pub struct PipelineConfig {Show 23 fields
pub version: u32,
pub name: Option<String>,
pub vars: Option<HashMap<String, Value>>,
pub params: ParamsSpec,
pub auth: Option<HashMap<String, Value>>,
pub pipeline: PipelineSpec,
pub matrix: Vec<MatrixRow>,
pub execution: Option<ExecutionSpec>,
pub selection: Option<SelectionSpec>,
pub observability: Option<ObservabilitySpec>,
pub delivery: DeliveryMode,
pub resilience: Option<ResilienceSpec>,
pub sla: Option<SlaSpec>,
pub reconcile: Option<ReconcileSpec>,
pub shard: Option<ShardingSpec>,
pub replication: Option<ReplicationSpec>,
pub backfill: Option<BackfillSpec>,
pub partition: Option<PartitionSpec>,
pub schedule: Option<ScheduleSpec>,
pub lineage: Option<LineageConfig>,
pub catalog: Option<CatalogSpec>,
pub notifications: Vec<NotificationSpec>,
pub metadata_columns: Option<MetadataColumnsSpec>,
}Expand description
Top-level pipeline definition.
Fields§
§version: u32Config-format version. Currently always 1.
name: Option<String>Optional human-readable name (used in logs and error messages).
vars: Option<HashMap<String, Value>>Optional shared constants. Resolvable as ${vars.key} anywhere in
the config (including inside named templates). Resolved at load time,
after env/file/secret substitution.
params: ParamsSpecOptional typed run parameters (#444) — the config’s trigger-time
override surface. Each entry declares a name, scalar type,
required/default, a secret flag, and a description; values are
referenced as ${param.NAME} and bound before parsing by
crate::params::bind (from --param, faucet template run, or
POST /v1/templates/{id}/runs). Because binding happens pre-parse, no
${param.*} token ever reaches a connector. See faucet schema params.
auth: Option<HashMap<String, Value>>Optional named auth providers. Each entry is a { type, config } spec
(the same shape as inline auth) built once and shared across every
connector that references it via auth: { ref: <name> }. Values are kept
as raw JSON so faucet-auth owns the per-type schema.
pipeline: PipelineSpecBase pipeline — every matrix row is deep-merged into this.
matrix: Vec<MatrixRow>Matrix of per-row overrides. Empty or omitted means “one anonymous row” (full pipeline runs once with no merge).
execution: Option<ExecutionSpec>Optional execution controls (concurrency, on-error policy).
selection: Option<SelectionSpec>Optional matrix-row selection policy (#377). Currently carries only
include_parents — how a selected row’s parent: / depends_on:
ancestors are resolved when they are not independently in the run set.
Absent = the built-in default (include_parents: off, strict).
observability: Option<ObservabilitySpec>Optional observability configuration (Prometheus + tracing).
delivery: DeliveryModeDelivery guarantee for every row (overridable per matrix row). Default
at_least_once — no behaviour change for existing configs. exactly_once
requires an idempotent sink, a deterministic-replay source, and a state
store (enforced at expand time).
resilience: Option<ResilienceSpec>Optional resilience policy (retry / backoff / circuit-breaker /
poison-pill). Top-level in v1 (not per-matrix-row). Absent = no behaviour
change. Consumed by faucet run/schedule/replicate.
sla: Option<SlaSpec>Optional data-freshness & volume SLA (#202). Top-level in v1 (not
per-matrix-row, like resilience:). Evaluated after every root
invocation by faucet run/schedule/serve/replicate; violations
emit metrics + warnings and never fail the run. Staleness/volume checks
require a state: block (enforced at expand time).
reconcile: Option<ReconcileSpec>Optional completeness reconciliation (#502): after a successful root run,
compare rows written against an authoritative count probe and fail the
run on a shortfall beyond tolerance — a silent-truncation guard,
especially for write_mode: overwrite.
shard: Option<ShardingSpec>Optional source-shard distribution for clustered (Mode B) execution.
Only consumed by faucet serve --cluster: a run whose source
is shardable is split into
shard.count shards processed concurrently across cluster workers.
Ignored by faucet run and by a non-cluster serve, so it is fully
backward compatible.
replication: Option<ReplicationSpec>Optional snapshot→CDC replication block. Consumed only by
faucet replicate; ignored by faucet run (like schedule:).
backfill: Option<BackfillSpec>Optional backfill defaults (window/concurrency/timezone, #282).
Consumed only by faucet backfill; ignored by faucet run (like
schedule: / replication:). See faucet schema backfill.
partition: Option<PartitionSpec>Default range partitioning applied to every root row that does not
declare its own (#479). Unlike backfill: / schedule:, this IS
consumed by faucet run — a partitioned row fans out on every run.
schedule: Option<ScheduleSpec>schedule only.Optional cron schedule. Only consumed by faucet schedule; ignored by
faucet run. Presence makes the config runnable on a schedule.
lineage: Option<LineageConfig>lineage only.Optional OpenLineage emission. Consumed by faucet run/schedule/serve.
catalog: Option<CatalogSpec>catalog only.Optional Data Movement Catalog store (#279): where faucet run /
schedule / replicate accumulate the cross-run dataset catalog
(identity, schema timeline, volume/freshness, lineage edges). faucet serve ignores this block and records into its --history backend.
Recording never fails a run. See faucet schema catalog.
notifications: Vec<NotificationSpec>notify only.Optional notification / incident-routing rules (#280). Fan pipeline
lifecycle and health events (run failure/success, SLA breach, circuit
open, contract abort, DLQ threshold, scheduler stuck) out to Slack /
PagerDuty / a signed webhook. Consumed by every runtime
(run/schedule/serve/replicate); delivery never fails a run.
metadata_columns: Option<MetadataColumnsSpec>Optional _faucet_* run/lineage metadata columns (#510) stamped onto
every row by a connector-agnostic sink decorator (works for any sink).
Off unless present.
Implementations§
Source§impl PipelineConfig
impl PipelineConfig
Sourcepub fn from_path(
path: impl AsRef<Path>,
profile: Option<&str>,
) -> CliResult<Self>
pub fn from_path( path: impl AsRef<Path>, profile: Option<&str>, ) -> CliResult<Self>
Load a pipeline config from disk. The file extension determines the
parser: .yaml / .yml → YAML, .json → JSON. Other extensions are
rejected.
Composition runs first via crate::compose::compose: extends (base
inheritance), profiles (the named overlay selected by profile), and
!include (YAML fragment substitution) are resolved into a single
merged document before ${...} interpolation and parsing.
Secret directives (${vault:…}, ${aws-sm:…}, etc.) are not
resolved by this path. If any are present the call returns
CliError::SecretsRequireAsyncLoad — use Self::from_path_async instead.
Sourcepub fn from_path_with(
path: impl AsRef<Path>,
profile: Option<&str>,
inputs: &RunInputs,
) -> CliResult<Self>
pub fn from_path_with( path: impl AsRef<Path>, profile: Option<&str>, inputs: &RunInputs, ) -> CliResult<Self>
Self::from_path with caller-supplied RunInputs (params: values
and an ${env:} overlay, #444).
Sourcepub fn from_path_tolerating_secrets(
path: impl AsRef<Path>,
profile: Option<&str>,
) -> CliResult<Self>
pub fn from_path_tolerating_secrets( path: impl AsRef<Path>, profile: Option<&str>, ) -> CliResult<Self>
Like Self::from_path but does not reject secret directives — they are
left unresolved. Used by validate --no-secrets. Composition
(extends/profiles/!include) runs first via crate::compose::compose.
Sourcepub fn from_path_tolerating_secrets_with(
path: impl AsRef<Path>,
profile: Option<&str>,
inputs: &RunInputs,
) -> CliResult<Self>
pub fn from_path_tolerating_secrets_with( path: impl AsRef<Path>, profile: Option<&str>, inputs: &RunInputs, ) -> CliResult<Self>
Self::from_path_tolerating_secrets with caller-supplied RunInputs.
Sourcepub async fn from_path_async(
path: impl AsRef<Path>,
profile: Option<&str>,
) -> CliResult<Self>
pub async fn from_path_async( path: impl AsRef<Path>, profile: Option<&str>, ) -> CliResult<Self>
Async load path: like Self::from_path but resolves secret-manager
directives (${vault:…}, ${aws-sm:…}, …) as a final stage. Composition
(extends/profiles/!include) runs first via crate::compose::compose.
Sourcepub async fn from_path_async_with(
path: impl AsRef<Path>,
profile: Option<&str>,
inputs: &RunInputs,
) -> CliResult<Self>
pub async fn from_path_async_with( path: impl AsRef<Path>, profile: Option<&str>, inputs: &RunInputs, ) -> CliResult<Self>
Self::from_path_async with caller-supplied RunInputs (params:
values and an ${env:} overlay, #444).
Sourcepub fn from_text(text: &str, path: &Path) -> CliResult<Self>
pub fn from_text(text: &str, path: &Path) -> CliResult<Self>
Parse an already-interpolated config string. path is only used for
error messages and to pick the parser by file extension.
Sourcepub fn from_value(value: Value) -> CliResult<Self>
pub fn from_value(value: Value) -> CliResult<Self>
Build a config from an already-parsed JSON value (used by faucet serve,
which merges a submitted body onto a --default-config base). Runs the
same version check + structural ${...} ref resolution as Self::from_text.
Note: load-time ${env:VAR} / ${file:PATH} / ${secret:VAR} directives
are not resolved here — the caller must pre-resolve them (e.g. by running
interpolate on the source text) before building the Value.
Trait Implementations§
Source§impl Clone for PipelineConfig
impl Clone for PipelineConfig
Source§fn clone(&self) -> PipelineConfig
fn clone(&self) -> PipelineConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PipelineConfig
impl Debug for PipelineConfig
Source§impl<'de> Deserialize<'de> for PipelineConfig
impl<'de> Deserialize<'de> for PipelineConfig
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for PipelineConfig
impl JsonSchema for PipelineConfig
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl Freeze for PipelineConfig
impl RefUnwindSafe for PipelineConfig
impl Send for PipelineConfig
impl Sync for PipelineConfig
impl Unpin for PipelineConfig
impl UnsafeUnpin for PipelineConfig
impl UnwindSafe for PipelineConfig
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> AsAny for T
impl<T> AsAny for T
Source§fn any_ref(&self) -> &(dyn Any + Sync + Send + 'static)
fn any_ref(&self) -> &(dyn Any + Sync + Send + 'static)
dyn Any reference to the object: Read moreSource§fn as_any(self: Arc<T>) -> Arc<dyn Any + Sync + Send> ⓘ
fn as_any(self: Arc<T>) -> Arc<dyn Any + Sync + Send> ⓘ
Arc<dyn Any> reference to the object: Read moreSource§fn into_any(self: Box<T>) -> Box<dyn Any + Sync + Send>
fn into_any(self: Box<T>) -> Box<dyn Any + Sync + Send>
Box<dyn Any>: Read moreSource§fn type_name(&self) -> &'static str
fn type_name(&self) -> &'static str
std::any::type_name, since Any does not provide it and
Any::type_id is useless as a debugging aid (its Debug is just a mess of hex digits).Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<D> DeserializeWith<JsonFormat> for Dwhere
D: DeserializeOwned,
impl<D> DeserializeWith<JsonFormat> for Dwhere
D: DeserializeOwned,
Source§fn deserialize_with(body: ResponseBody) -> Result<D, Error>
fn deserialize_with(body: ResponseBody) -> Result<D, Error>
Source§impl<T> Downcast for T
impl<T> Downcast for T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::RequestSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::RequestSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Serialize for T
impl<T> Serialize for T
fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>
fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>
Source§impl<T> ServiceExt for T
impl<T> ServiceExt for T
Source§fn decompression(self) -> Decompression<Self>where
Self: Sized,
fn decompression(self) -> Decompression<Self>where
Self: Sized,
decompression-br or decompression-deflate or decompression-gzip or decompression-zstd only.Source§fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
trace only.Source§fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
trace only.Source§fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
follow-redirect only.Source§fn set_request_id<M>(
self,
header_name: HeaderName,
make_request_id: M,
) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
fn set_request_id<M>(
self,
header_name: HeaderName,
make_request_id: M,
) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
request-id only.Source§fn set_x_request_id<M>(self, make_request_id: M) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
fn set_x_request_id<M>(self, make_request_id: M) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
request-id only.x-request-id as the header name. Read moreSource§fn propagate_request_id(
self,
header_name: HeaderName,
) -> PropagateRequestId<Self>where
Self: Sized,
fn propagate_request_id(
self,
header_name: HeaderName,
) -> PropagateRequestId<Self>where
Self: Sized,
request-id only.Source§fn propagate_x_request_id(self) -> PropagateRequestId<Self>where
Self: Sized,
fn propagate_x_request_id(self) -> PropagateRequestId<Self>where
Self: Sized,
request-id only.x-request-id as the header name. Read moreSource§fn request_body_limit(self, limit: usize) -> RequestBodyLimit<Self>where
Self: Sized,
fn request_body_limit(self, limit: usize) -> RequestBodyLimit<Self>where
Self: Sized,
limit only.413 Payload Too Large responses. Read moreSource§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.