pub trait HostnameResultExt<T>: Sized {
// Required method
fn hostname_ctx(self, context: &'static str) -> Result<T>;
}Expand description
Substrate extension trait over Result<T, HostnameError> — the ONE
substrate owner of the .map_err(|e| anyhow::anyhow!("<ctx>: {e}"))
wrap-shape every reconciler consumer restated by hand at the
hostname-formatter → anyhow error boundary. Peer of
crate::kube_error::KubeResultExt on the wrap-shape axis; the two
traits partition the flatten-wrap space by underlying error type
(kube::Error on that peer, HostnameError on this one).
Pre-lift the shape was hand-authored at THREE sites in
tatara-reconciler::render::render_routing — each of the three
HostnameError-returning hostname primitives (ephemeral_id_from_spec,
fmt_fqdn, fmt_fqdn_stable) had ITS consumer restate the
SAME closure at the R9 routing-edge render — capture the
HostnameError, prepend a static context slug identifying which
hostname primitive faulted, delegate the tail to HostnameError’s
Display impl via the {e} slot — differing only in the context
slug prefix each callsite stamped ("ephemeral_id_from_spec" /
"fmt_fqdn (per-instance)" / "fmt_fqdn_stable"). Three
hand-authored callsites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
threshold.
Post-lift each callsite reads
<hostname-primitive>().hostname_ctx("<slug>")? and the wrap-shape
lives at ONE substrate owner here. The composed anyhow::Error’s
Display is byte-identical to the pre-lift chain
(format!("{ctx}: {e}"), threading the HostnameError’s own
Display verbatim into the {e} slot), so operator-facing log
output and any error-chain greps still match bytewise. A regression
that drifts the separator, swaps the two slots, or wraps the
HostnameError with a chain-form source (which would change
Display output on the err slot) surfaces at
[tests::hostname_ctx_static_str_context_matches_pre_lift_format_bytewise]
rather than as silent operator-facing drift across the three
pre-lift consumers.
§Naming — hostname_ctx, not anyhow::Context::context
Same discipline as crate::kube_error::KubeResultExt::kube_ctx —
anyhow::Context::context wraps the source in a chain (so Display
emits only the context slug and callers reach the HostnameError
via std::error::Error::source traversal), while this trait’s
hostname_ctx FLATTENS to a display-prefix shape ("<ctx>: <HostnameError display>") — the pre-lift wire format every consumer’s log output
already encoded. Sharing the name would let a caller who has
anyhow::Context in scope resolve to the WRONG method (a chain-wrap
instead of the display-prefix flatten) and silently change every
operator log message.
§Static-slug only (no _with peer yet)
Every current callsite composes its slug at compile time
("ephemeral_id_from_spec", "fmt_fqdn (per-instance)",
"fmt_fqdn_stable"); no consumer needs a format!-composed
runtime slug. The static-&'static str binding keeps the substrate
contract minimal — a future dynamic-slug consumer would add a
hostname_ctx_with peer here matching the kube_ctx_with shape,
but until then this trait exposes only the static peer.
§#[must_use]
Every consumer threads the ? short-circuit onto its handler’s
Result<_, anyhow::Error> return — dropping the wrap swallows the
hostname-format failure entirely, which is never the intended
semantic (a rejected DNS label at emit time silently produces a
resource with a "" FQDN slot that the K8s API server accepts and
then no downstream Ingress / DNSEndpoint dispatcher can route to).
The attribute surfaces that as a warning at every call site.
Theory anchor: THEORY.md §VI.1 (generation over composition — the
HostnameError → anyhow-with-display-prefix wrap-shape recurred
at three hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
duplication trigger, and is lifted to ONE substrate owner here).
THEORY.md §II.1 invariant 5 (composition preserves proofs — a
regression that drifts the display-prefix separator or the byte-
shape at ONE site surfaces here at the substrate pin rather than
as silent operator-facing skew across every render_routing tick).
Required Methods§
Sourcefn hostname_ctx(self, context: &'static str) -> Result<T>
fn hostname_ctx(self, context: &'static str) -> Result<T>
Wrap the HostnameError (if any) with a static context
prefix, producing an anyhow::Result whose error Display
reads exactly "<context>: <HostnameError display>".
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".