Skip to main content

tatara_process/
crd.rs

1//! The `Process` CRD — `tatara.pleme.io/v1alpha1`.
2
3use chrono::{DateTime, Utc};
4use kube::CustomResource;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use tatara_lisp::DeriveTataraDomain;
8
9use crate::attestation::ProcessAttestation;
10use crate::boundary::Boundary;
11use crate::classification::Classification;
12use crate::compliance::ComplianceSpec;
13use crate::encapsulates::EncapsulatesSpec;
14use crate::identity::Identity;
15use crate::intent::Intent;
16use crate::lifetime::Lifetime;
17use crate::phase::ProcessPhase;
18use crate::routing::RoutingSpec;
19use crate::signal::ProcessSignal;
20use crate::spec::{DependsOn, IdentitySpec, SignalPolicy};
21use crate::status::{BoundaryStatus, ComplianceStatus, FluxResourceRef, ProcessCondition};
22
23/// Process — one element of the tatara convergence lattice, reconciled as a Unix process.
24///
25/// ```yaml
26/// apiVersion: tatara.pleme.io/v1alpha1
27/// kind: Process
28/// metadata:
29///   name: observability-stack
30///   namespace: seph
31/// spec:
32///   identity:
33///     parent: seph.1
34///   classification:
35///     pointType: Gate
36///     substrate: Observability
37///   intent:
38///     nix:
39///       flakeRef: github:pleme-io/k8s?dir=shared/infrastructure
40///       attribute: observability
41///   compliance:
42///     baseline: fedramp-moderate
43///     bindings:
44///       - framework: nist-800-53
45///         controlId: SC-7
46///         phase: AtBoundary
47///   dependsOn:
48///     - name: secret-injection
49/// ```
50#[derive(CustomResource, DeriveTataraDomain, Clone, Debug, Deserialize, Serialize, JsonSchema)]
51#[kube(
52    group = "tatara.pleme.io",
53    version = "v1alpha1",
54    kind = "Process",
55    plural = "processes",
56    shortname = "proc",
57    namespaced,
58    status = "ProcessStatus",
59    printcolumn = r#"{"name":"PID","type":"string","jsonPath":".status.pid"}"#,
60    printcolumn = r#"{"name":"Phase","type":"string","jsonPath":".status.phase"}"#,
61    printcolumn = r#"{"name":"Type","type":"string","jsonPath":".spec.classification.pointType"}"#,
62    printcolumn = r#"{"name":"Substrate","type":"string","jsonPath":".spec.classification.substrate"}"#,
63    printcolumn = r#"{"name":"Gen","type":"integer","jsonPath":".status.attestation.generation"}"#,
64    printcolumn = r#"{"name":"Age","type":"date","jsonPath":".metadata.creationTimestamp"}"#
65)]
66#[serde(rename_all = "camelCase")]
67#[tatara(keyword = "defpoint")]
68pub struct ProcessSpec {
69    /// Identity (parent, name override).
70    #[serde(default)]
71    pub identity: IdentitySpec,
72
73    /// Lattice position (6 dimensions).
74    pub classification: Classification,
75
76    /// Where rendered artifacts come from. Exactly one variant must be set.
77    pub intent: Intent,
78
79    /// Boundary predicates (preconditions / postconditions).
80    #[serde(default)]
81    pub boundary: Boundary,
82
83    /// Compliance bindings + baseline.
84    #[serde(default)]
85    pub compliance: ComplianceSpec,
86
87    /// Lattice dependencies — must reach phase before we proceed.
88    #[serde(default)]
89    pub depends_on: Vec<DependsOn>,
90
91    /// Signal policy (grace, SIGHUP strategy, start-suspended).
92    #[serde(default)]
93    pub signals: SignalPolicy,
94
95    /// Lifetime — `Permanent` (default, re-converging) or `Ephemeral`
96    /// (auto-SIGTERM per `teardown_policy` + TTL clock).
97    #[serde(default, skip_serializing_if = "Lifetime::is_default")]
98    pub lifetime: Lifetime,
99
100    /// External edges — DNS + Ingress. When `None`, the Process is
101    /// internal-only (matches today's default). See
102    /// [`crate::routing`] for the full shape.
103    #[serde(default, skip_serializing_if = "Option::is_none")]
104    pub routing: Option<RoutingSpec>,
105
106    /// Pre-existing in-cluster state this Process wraps. When `None`,
107    /// the Process is greenfield (Manage mode implicitly applied to
108    /// nothing pre-existing). See [`crate::encapsulates`] for the
109    /// three modes (Manage / Adopt / Observe).
110    #[serde(default, skip_serializing_if = "Option::is_none")]
111    pub encapsulates: Option<EncapsulatesSpec>,
112
113    /// Soft-suspend marker — reconciler treats as SIGSTOP.
114    /// Same effect as delivering SIGSTOP, but persistent across restarts.
115    #[serde(default)]
116    pub suspended: bool,
117}
118
119// Coordinate primitives — the `(namespace, name)` pair every downstream
120// composer (annotation writers, claim arbiter, boundary evaluator,
121// render owner-metadata seed) pulled by hand from `Process.metadata`
122// pre-lift, each restating the same two `Option<String>`-to-`&str`
123// unwrap incantations with the same two workspace-wide fallback
124// strings sprayed inline. Post-lift the pair lives at ONE substrate
125// primitive on `Process` — a future normalization (case-fold,
126// unicode-safe collation, cross-cluster prefix, a rename of either
127// fallback) lands here and every downstream composer inherits the
128// upgrade mechanically. Peer to `qualified_process_ref` in
129// `tatara-reconciler::ssapply`, whose two `&str` arguments are
130// exactly the pair `Process::coordinates_or_defaults` returns.
131impl Process {
132    /// The K8s canonical default namespace — the fallback every
133    /// consumer of a `Process` whose `metadata.namespace` is `None`
134    /// substitutes. Matches the string K8s itself substitutes on
135    /// namespaced resource writes with no explicit namespace.
136    pub const DEFAULT_NAMESPACE: &'static str = "default";
137
138    /// Workspace-wide fallback for a `Process`'s `metadata.name` when
139    /// it is `None` — the sentinel every annotation writer, claim
140    /// arbiter, and owner-metadata seed substitutes so downstream
141    /// grepping / label-selecting sees a stable spelling rather than
142    /// a per-callsite ad-hoc placeholder (`""`, `"<unnamed>"`, or the
143    /// empty `unwrap_or_default()` fallback). A Process authored
144    /// through the reconciler's fork path always has a name; this
145    /// constant covers the surface where an untyped `Process` value
146    /// (test fixture, dynamic API response, adopted resource pre-
147    /// name-resolution) surfaces without one.
148    pub const UNNAMED_PLACEHOLDER: &'static str = "unnamed";
149
150    /// Namespace slice with the [`Self::DEFAULT_NAMESPACE`] fallback
151    /// applied — the ONE-line collapse of the `metadata.namespace
152    /// .as_deref().unwrap_or("default")` incantation every consumer
153    /// spelled by hand pre-lift.
154    ///
155    /// Peer to [`Self::name_or_placeholder`] on the (metadata slot ×
156    /// fallback shape) axis; both compose through
157    /// [`Self::coordinates_or_defaults`] when a consumer needs the
158    /// pair together (annotation writers, claim-arbiter row builders,
159    /// render owner-metadata seed).
160    pub fn namespace_or_default(&self) -> &str {
161        self.metadata
162            .namespace
163            .as_deref()
164            .unwrap_or(Self::DEFAULT_NAMESPACE)
165    }
166
167    /// Name slice with the [`Self::UNNAMED_PLACEHOLDER`] fallback
168    /// applied — the ONE-line collapse of the `metadata.name.as_deref
169    /// ().unwrap_or("unnamed")` incantation every consumer spelled by
170    /// hand pre-lift.
171    ///
172    /// Peer to [`Self::namespace_or_default`] on the (metadata slot ×
173    /// fallback shape) axis; both compose through
174    /// [`Self::coordinates_or_defaults`] when a consumer needs the
175    /// pair together.
176    pub fn name_or_placeholder(&self) -> &str {
177        self.metadata
178            .name
179            .as_deref()
180            .unwrap_or(Self::UNNAMED_PLACEHOLDER)
181    }
182
183    /// `(namespace, name)` coordinates with the workspace-wide default
184    /// fallbacks applied — the ONE-line collapse of the paired
185    /// `metadata.namespace.as_deref().unwrap_or("default")` +
186    /// `metadata.name.as_deref().unwrap_or("unnamed")` extraction
187    /// every downstream composer restated by hand pre-lift.
188    ///
189    /// Return-tuple order matches the axis order of the substrate's
190    /// paired-composer primitive
191    /// `tatara_reconciler::ssapply::qualified_process_ref(ns, name)`:
192    /// the (namespace, name) pair this method returns feeds that
193    /// primitive positionally without an axis-swap step.
194    pub fn coordinates_or_defaults(&self) -> (&str, &str) {
195        (self.namespace_or_default(), self.name_or_placeholder())
196    }
197
198    /// `(namespace, name)` coordinates as owned `String`s, with the
199    /// namespace half fallback-defaulted to [`Self::DEFAULT_NAMESPACE`]
200    /// but the name half REQUIRED — an [`anyhow::Error`] is returned
201    /// when `metadata.name` is absent, because "unnamed" is a display
202    /// placeholder, not a valid K8s API path segment. Fed straight into
203    /// kube-rs API calls (`Api::patch`, `Api::delete`, `Api::get`) that
204    /// take owned `String` arguments; the [`Self::DEFAULT_NAMESPACE`]
205    /// fallback matches what K8s itself substitutes on namespaced
206    /// resource writes with no explicit namespace, so the surface is
207    /// safe against a `Process` whose `metadata.namespace` slot is
208    /// absent (test fixture, dynamic API response pre-defaulting) but
209    /// refuses to guess a name.
210    ///
211    /// Peer to [`Self::coordinates_or_defaults`] on the (return-form ×
212    /// name gate) axis pair:
213    /// * borrow + name-defaulted → `coordinates_or_defaults` (display,
214    ///   annotation writers, ownership-tag composers — every consumer
215    ///   whose downstream drops `"unnamed"` in place of a missing name
216    ///   without an operator-visible failure);
217    /// * owned + name-required → this method (kube-rs API calls —
218    ///   every consumer whose downstream must NOT silently substitute
219    ///   a placeholder for the API call target, because the caller is
220    ///   about to `patch`/`delete`/`get` at `metadata.name`).
221    ///
222    /// The error wording is pinned by
223    /// [`tests::owned_coordinates_or_err_error_message_matches_pre_lift_reconciler_wording`]
224    /// to match the exact spelling every pre-lift `tatara-reconciler`
225    /// helper produced (`"Process has no metadata.name"`) so log-line
226    /// / test greps that anchored on that wording keep matching post-
227    /// lift, and no operator-visible message drift lands as a side
228    /// effect of the substrate move.
229    pub fn owned_coordinates_or_err(&self) -> anyhow::Result<(String, String)> {
230        let ns = self
231            .metadata
232            .namespace
233            .clone()
234            .unwrap_or_else(|| Self::DEFAULT_NAMESPACE.into());
235        let name = self
236            .metadata
237            .name
238            .clone()
239            .ok_or_else(|| anyhow::anyhow!("Process has no metadata.name"))?;
240        Ok((ns, name))
241    }
242
243    /// `(namespace, name)` coordinates in the BORROW + NAME-REQUIRED
244    /// corner of the primitive family — namespace half falls back to
245    /// [`Self::DEFAULT_NAMESPACE`], but the name half is REQUIRED
246    /// (`None` on a `Process` whose `metadata.name` is absent, so the
247    /// caller stops with an `else { continue; }` / `else { return
248    /// …; }` guard rather than proceeding with the empty-string
249    /// sentinel every pre-lift consumer had to spell inline).
250    ///
251    /// Peer to [`Self::coordinates_or_defaults`] +
252    /// [`Self::owned_coordinates_or_err`] on the (return-form ×
253    /// name-gate) axis pair — closes the corner the family previously
254    /// left open:
255    ///
256    /// * borrow + name-defaulted → [`Self::coordinates_or_defaults`]
257    ///   (annotation writers, render owner-metadata seed — consumers
258    ///   whose downstream tolerates the `"unnamed"` display placeholder
259    ///   without operator-visible failure);
260    /// * borrow + name-required → **this method** (claim-arbiter
261    ///   probes, child-Process delete-fan-out — consumers that need a
262    ///   real API-path leaf and cleanly SKIP the row when the name is
263    ///   absent rather than issuing a K8s call with an empty-string
264    ///   name argument);
265    /// * owned + name-required → [`Self::owned_coordinates_or_err`]
266    ///   (kube-rs API-path calls — consumers whose downstream requires
267    ///   owned `String` arguments and rejects the missing-name corner
268    ///   with a load-bearing error message).
269    ///
270    /// The primitive family's `None`-on-missing-name semantics
271    /// intentionally differs from [`Self::owned_coordinates_or_err`]'s
272    /// error-on-missing-name semantics: the caller sites for this form
273    /// (child-Process fan-out, claim-arbiter row probes) are non-fatal
274    /// SKIPS rather than reportable failures — an `Option::None` at
275    /// the primitive lets the caller thread that "skip" through a
276    /// let-else without stringifying / logging an anyhow chain per
277    /// missing-name occurrence.
278    ///
279    /// The namespace fallback matches [`Self::coordinates_or_defaults`]
280    /// (via [`Self::namespace_or_default`]), so a consumer that
281    /// switches between the two borrow-form primitives based on its
282    /// name-gate need never sees a different namespace-fallback string
283    /// as a side effect.
284    pub fn coordinates_or_none(&self) -> Option<(&str, &str)> {
285        let name = self.metadata.name.as_deref()?;
286        Some((self.namespace_or_default(), name))
287    }
288
289    /// Canonical `<ns>/<name>` **namespace-qualified process reference**
290    /// composed straight off the live [`Process`] — the ONE-liner
291    /// collapse of the paired
292    /// `let (ns, name) = process.coordinates_or_defaults(); let r =
293    /// qualified_process_ref(ns, name);` incantation every consumer
294    /// whose downstream keys a Process by "which cluster location owns
295    /// it" hand-authored at scattered sites across `tatara-reconciler`.
296    ///
297    /// Pre-lift the 2-step `coordinates_or_defaults() →
298    /// qualified_process_ref(ns, name)` composition was hand-authored
299    /// at THREE sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
300    /// threshold in `tatara-reconciler`, each restating the SAME
301    /// paired projection + `<ns>/<name>` shape:
302    /// * `render::render_routing` — routing-graph `PROCESS=<ref>`
303    ///   annotation seed on every emitted Ingress / DNSEndpoint,
304    ///   feeding [`crate::status::FluxResourceRef`] downstream.
305    /// * `render::render_export_jobs` — export-Job `PROCESS=<ref>`
306    ///   annotation seed on every emitted export `batch/v1` Job.
307    /// * `table_controller::reconcile` — claim-arbiter row-key +
308    ///   `Candidate.process_ref` seed on the stable-name claim
309    ///   registry (the reference lands verbatim in
310    ///   [`crate::table::ClaimRecord.holder`], where every downstream
311    ///   claim query greps it).
312    ///
313    /// All THREE sites walked the SAME 2-step chain — pull the
314    /// `(ns, name)` pair through [`Self::coordinates_or_defaults`],
315    /// then feed the pair positionally into
316    /// [`crate::qualified_process_ref`]. Post-lift each caller reads
317    /// `process.qualified_ref()` — the paired projection + shape
318    /// composer now sit at ONE substrate owner, so a rename of either
319    /// workspace-wide fallback (`"default"` / `"unnamed"`), a swap of
320    /// the `<ns>/<name>` separator, a normalization pass inserted
321    /// between the paired projection and the shape composer, or a
322    /// future `<ns>/<name>@<gen>` / `<cluster>/<ns>/<name>` cross-
323    /// cluster extension lands here exactly once and every consumer
324    /// (annotation seed, claim-row key, holder-slot writer, export-
325    /// Job seed, `Candidate` composer) inherits the upgrade
326    /// mechanically.
327    ///
328    /// Peer to [`Self::coordinates_or_defaults`] on the (return-form ×
329    /// composition-depth) axis pair:
330    /// * pair + defaulted → [`Self::coordinates_or_defaults`]
331    ///   (consumers that thread each half into a separate positional
332    ///   slot — `Api::namespaced(client, &ns) + Api::patch(&name, …)`,
333    ///   `one_export_job(ns, name, …)`, `EdgeContext { process_name,
334    ///   process_namespace, … }`);
335    /// * shape + defaulted → **this method** (consumers that key on
336    ///   the composed `<ns>/<name>` reference directly — the
337    ///   `PROCESS=<ref>` annotation seed, the `ClaimRecord.holder`
338    ///   slot, the label-selector composer).
339    ///
340    /// The namespace-fallback discipline matches
341    /// [`Self::coordinates_or_defaults`] (via
342    /// [`Self::namespace_or_default`]) and the name-fallback discipline
343    /// matches [`Self::name_or_placeholder`], so a consumer that
344    /// switches between the pair-returning primitive and this shape-
345    /// composing primitive never sees a different fallback string as
346    /// a side effect. The composed reference is byte-identical to the
347    /// pre-lift hand-authored `format!("{ns}/{name}")` with `ns` /
348    /// `name` supplied by the pair-returning primitive, so downstream
349    /// greps keyed on the reference shape (`PROCESS=<ref>` on emitted
350    /// resources, `holder = <ref>` on claim-registry queries) match
351    /// bytewise post-lift.
352    ///
353    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
354    /// the 2-step paired-projection + shape-composer chain recurred at
355    /// three hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
356    /// duplication trigger, and is lifted onto ONE workspace-wide
357    /// owner here). THEORY.md §II.1 invariant 5 (composition preserves
358    /// proofs — a regression that inserted a normalization step at
359    /// only two of three sites, or that drifted the fallback strings
360    /// between the paired projection and the shape composer, surfaces
361    /// at [`tests::qualified_ref_*`] rather than as silent operator-
362    /// visible skew across the three annotation / claim-key /
363    /// export-Job seed writers).
364    #[must_use]
365    pub fn qualified_ref(&self) -> String {
366        let (ns, name) = self.coordinates_or_defaults();
367        crate::qualified_process_ref(ns, name)
368    }
369
370    /// Borrowed lookup of ONE key in `metadata.annotations`, with
371    /// BOTH the missing-`annotations` corner AND the missing-key
372    /// corner collapsed to `None` — the ONE-liner collapse of the
373    /// paired `self.metadata.annotations.as_ref().and_then(|m|
374    /// m.get(key)).map(String::as_str)` incantation every consumer
375    /// restated by hand pre-lift.
376    ///
377    /// Pre-lift the 3-line `.metadata.annotations.as_ref().and_then
378    /// (|m| m.get(KEY))` chain (in three tail variants — `.cloned()`,
379    /// `.cloned().unwrap_or_default()`, `.map(String::as_str)`) was
380    /// hand-authored at THREE sites past the ★★ PRIME-DIRECTIVE ≥ 2
381    /// duplication threshold across the workspace:
382    /// * `tatara-reconciler::signals::ingest` — SIGNAL annotation
383    ///   lookup (pre-lift `.cloned()` for owned parsing).
384    /// * `tatara-reconciler::phase_machine::released_from_annotation`
385    ///   — RELEASED_FROM annotation lookup (pre-lift `.cloned()
386    ///   .unwrap_or_default()` for `match v.as_str()`).
387    /// * `tatara-pool-reconciler::controller_pool::process_belongs_to_pool`
388    ///   — POOL annotation lookup (pre-lift `.map(String::as_str)`
389    ///   for `== Some(pool_name)`).
390    ///
391    /// All THREE sites walked the SAME 3-line chain — read the
392    /// annotations map, gate on presence, index by key — differing
393    /// only in the tail that shaped the result. Post-lift each
394    /// caller routes through the ONE substrate primitive here and
395    /// applies its own tail at its own site (`.map(str::to_string)`
396    /// / bare match / `==`).
397    ///
398    /// Return-form axis: `Option<&str>` mirrors the existing borrow-
399    /// first discipline of the peer metadata primitives
400    /// [`Self::namespace_or_default`], [`Self::name_or_placeholder`],
401    /// [`Self::coordinates_or_none`]. The two corners the chain
402    /// swallowed pre-lift (missing `metadata.annotations` map,
403    /// missing key inside the map) BOTH collapse to `None` so
404    /// `.is_some()` / `if let Some(_)` / `Option::map` behave
405    /// identically on a `Process` whose annotations block is `None`
406    /// and on one whose annotations block is populated but omits the
407    /// key — matching what the pre-lift `.and_then(...)` chain
408    /// produced.
409    ///
410    /// A future normalization step (a key-canonicalization pass,
411    /// a case-fold lookup, a per-key alias table for renamed
412    /// annotations across API versions, a per-namespace override
413    /// substrate) lands at ONE substrate method here and all three
414    /// downstream consumers pick up the upgrade mechanically — no
415    /// per-callsite hand-edit at `ingest` / `released_from_annotation`
416    /// / `process_belongs_to_pool`.
417    ///
418    /// Sibling to the peer metadata primitives
419    /// ([`Self::namespace_or_default`], [`Self::name_or_placeholder`],
420    /// [`Self::coordinates_or_defaults`], [`Self::coordinates_or_none`],
421    /// [`Self::owned_coordinates_or_err`]) on the metadata axis;
422    /// this method opens the borrow-form peer on the ANNOTATION
423    /// axis. Future annotation projections (a paired
424    /// `label(&str) -> Option<&str>` on `metadata.labels`, a
425    /// `has_annotation(&str) -> bool` boolean gate for presence-
426    /// only consumers) land as peer methods on this same axis.
427    ///
428    /// Theory anchor: THEORY.md §VI.1 (generation over composition
429    /// — the 3-line annotation-lookup chain recurred at three
430    /// hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
431    /// duplication trigger, and is lifted to ONE owner here).
432    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
433    /// the pins bind the missing-`annotations` corner + the
434    /// missing-key corner + the borrow-form `&str` lifetime + the
435    /// byte-identical parity with the pre-lift 3-line chain, so a
436    /// regression that drifted any surface at
437    /// `tests::annotation_*` rather than as silent operator-facing
438    /// skew between the SIGNAL / RELEASED_FROM / POOL annotation
439    /// readers).
440    pub fn annotation(&self, key: &str) -> Option<&str> {
441        self.metadata
442            .annotations
443            .as_ref()
444            .and_then(|m| m.get(key))
445            .map(String::as_str)
446    }
447
448    /// Borrow-form metadata-projection primitive on the `metadata.uid`
449    /// axis: returns the K8s-API-server-assigned uid as a `&str`, with
450    /// the missing-uid corner collapsed to the load-bearing empty-string
451    /// sentinel — the ONE-liner collapse of the paired
452    /// `self.metadata.uid.as_deref().unwrap_or("")` incantation every
453    /// owner-reference-emitting consumer restated by hand pre-lift.
454    ///
455    /// The empty-string fallback is NOT arbitrary — it is the exact
456    /// sentinel value the sibling substrate composer
457    /// [`crate::owner_references_json`] gates on (`if uid.is_empty()
458    /// { vec![] } else { vec![owner_reference_json(name, uid)] }`) to
459    /// stamp `metadata.ownerReferences: []` on a resource whose owning
460    /// Process pre-dates the API server's `metadata.uid` assignment
461    /// (test fixture, mid-Forking snapshot before the first `patch`
462    /// round-trip, dynamic API response pre-uid-resolution). Pre-lift
463    /// each consumer spelled the fallback as `.unwrap_or("")` at its
464    /// callsite; the two literals in two files could drift silently to
465    /// `.unwrap_or_default()`, `.unwrap_or("<unknown>")`, or an
466    /// `if let Some(u) = &process.metadata.uid` gate that returned a
467    /// different owner-refs shape for the missing-uid corner. Post-lift
468    /// the sentinel value is composed at ONE substrate site so the
469    /// empty-uid gate at `owner_references_json` and its per-callsite
470    /// producers share the SAME `""` byte-string, and a rename of the
471    /// sentinel would land at ONE substrate site rather than at every
472    /// downstream `owner_references_json(name, uid)` call.
473    ///
474    /// Peer to [`Self::namespace_or_default`] +
475    /// [`Self::name_or_placeholder`] on the metadata-slot × fallback-
476    /// shape axis: `namespace_or_default` returns the K8s-canonical
477    /// `"default"` fallback (matching what the API server substitutes
478    /// on namespaced writes with no explicit namespace);
479    /// `name_or_placeholder` returns the workspace-wide `"unnamed"`
480    /// sentinel (a display placeholder for downstream grepping /
481    /// label-selecting); this method returns the empty-string sentinel
482    /// (a load-bearing gate value that composes with
483    /// [`crate::owner_references_json`]'s `is_empty` check). The three
484    /// primitives partition the metadata-slot family by whether the
485    /// consumer wants a K8s-canonical fallback (namespace), a display
486    /// placeholder (name), or a gate sentinel (uid).
487    ///
488    /// Pre-lift the `.metadata.uid.as_deref().unwrap_or("")` chain was
489    /// hand-authored at TWO sites past the ★★ PRIME-DIRECTIVE ≥ 2
490    /// duplication threshold in `tatara-reconciler::render`, both
491    /// feeding a downstream owner-reference emitter:
492    /// * `render_routing` — the routing-edge seed that binds
493    ///   `process_uid` into every routing-form `EdgeContext` (Ingress +
494    ///   DNSEndpoint) built inside the fanout loop over
495    ///   `RoutingSpec::hostnames`; each `Edge::render` impl then walks
496    ///   its `EdgeContext` through `build_owner_refs` →
497    ///   [`crate::owner_references_json`] to stamp
498    ///   `metadata.ownerReferences` on the emitted resource.
499    /// * `render_export_jobs` — the ephemeral-export Job builder that
500    ///   passes the same uid slice to `tatara_process::
501    ///   owner_references_json(name, uid)` per rendered Job, stamping
502    ///   the export-Job's `metadata.ownerReferences` back at the
503    ///   owning Process.
504    ///
505    /// Both sites walked the SAME `.as_deref().unwrap_or("")` chain and
506    /// both wanted the `&str` form the primitive returns — as the
507    /// second positional argument to `owner_references_json(name, uid)`
508    /// on the ownership-tag axis. Post-lift each callsite reads
509    /// `let uid = process.uid_or_empty();` and the produced slice feeds
510    /// the same downstream composer unchanged.
511    ///
512    /// Return-form axis: `&str` mirrors the existing borrow-first
513    /// discipline of the peer metadata-fallback primitives
514    /// ([`Self::namespace_or_default`], [`Self::name_or_placeholder`]);
515    /// all three return owned-metadata borrows with a slot-specific
516    /// fallback baked in so downstream consumers compose the slice
517    /// directly into their next call without re-spelling the fallback.
518    ///
519    /// A future normalization step (a canonicalization pass that
520    /// rejects a malformed uid before the owner-ref stamp, a cross-
521    /// cluster uid rewrite for multi-tenant control planes, a stale-
522    /// uid warning annotation for a Process whose uid changed under
523    /// the reconciler mid-generation) lands at ONE substrate method
524    /// here and both downstream `owner_references_json` consumers
525    /// pick up the upgrade mechanically — no per-callsite hand-edit
526    /// at `render_routing` / `render_export_jobs`.
527    ///
528    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
529    /// the `.metadata.uid.as_deref().unwrap_or("")` chain recurred at
530    /// two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
531    /// duplication trigger, and is lifted to ONE owner here).
532    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
533    /// the pins bind the missing-uid corner + the empty-string
534    /// sentinel byte-shape + the borrow-form `&str` lifetime + the
535    /// byte-identical parity with the pre-lift chain + the composition
536    /// coherence with [`crate::owner_references_json`]'s `is_empty`
537    /// gate, so a regression that drifted any surface at
538    /// `tests::uid_or_empty_*` rather than as silent operator-facing
539    /// skew between the two owner-reference emitters on the SAME
540    /// Process).
541    pub fn uid_or_empty(&self) -> &str {
542        self.metadata.uid.as_deref().unwrap_or("")
543    }
544
545    /// Owned-form metadata-projection primitive on the `metadata.name`
546    /// axis: returns an owned `String` copy of the K8s object name, with
547    /// the missing-name corner collapsed to the load-bearing empty-string
548    /// sentinel — the ONE-liner collapse of the paired
549    /// `self.metadata.name.clone().unwrap_or_default()` incantation every
550    /// keying / row-builder consumer restated by hand pre-lift.
551    ///
552    /// Pre-lift the `.metadata.name.clone().unwrap_or_default()` chain
553    /// was hand-authored at TWO sites past the ★★ PRIME-DIRECTIVE ≥ 2
554    /// duplication threshold in `tatara-pool-reconciler::controller_pool`,
555    /// both stamping the `PoolMember` / `PoolMemberSnapshot`
556    /// `process_name: String` slot inside a struct-literal fanout over
557    /// pool-owned `Process`es:
558    /// * `reconcile_pool`'s pool-member seed (annotation-matched Process
559    ///   list → `PoolMember { process_name, state, entered_state_at, .. }`)
560    ///   — the row every operator sees on the pool's status page.
561    /// * `reconcile_pool`'s desired-count snapshot seed
562    ///   (`PoolMemberSnapshot { process_name, phase, created_at }`)
563    ///   — the row fed into `decide_pool_convergence`.
564    ///
565    /// Both sites walked the SAME `.clone().unwrap_or_default()` chain
566    /// and both wanted the `String` form the primitive returns — as the
567    /// owned-form `process_name: String` slot on a struct literal
568    /// composed inside a `.iter().map(...)` fanout over the same
569    /// pool-owned `Process` list. Post-lift each callsite reads
570    /// `process_name: p.owned_name_or_empty()` and the produced value
571    /// feeds the same struct-literal slot unchanged.
572    ///
573    /// The empty-string fallback is the SAME sentinel the sibling
574    /// borrow-form primitive [`Self::uid_or_empty`] returns — the two
575    /// primitives partition the owned-form × borrow-form corner of the
576    /// metadata-slot family on identical fallback semantics (empty
577    /// string means "the slot is unset"), so a consumer that switches
578    /// between them based on downstream ownership requirements never
579    /// sees a different missing-slot spelling as a side effect.
580    ///
581    /// Peer to [`Self::name_or_placeholder`] on the (return-form ×
582    /// fallback-value) axis pair — closes the corner the family
583    /// previously left open:
584    ///
585    /// * borrow + display placeholder → [`Self::name_or_placeholder`]
586    ///   (log lines, annotation writers, ownership-tag composers —
587    ///   consumers whose downstream drops `"unnamed"` in place of a
588    ///   missing name without operator-visible failure);
589    /// * owned + empty sentinel → **this method** (row-builder /
590    ///   HashMap-key / struct-literal fanout consumers whose downstream
591    ///   fills a `String` field with the load-bearing `""` sentinel to
592    ///   flag "no name to key by" rather than substituting a display
593    ///   placeholder that would misalign a downstream lookup);
594    /// * owned + name-required → [`Self::owned_coordinates_or_err`] (kube-rs
595    ///   API-path calls — consumers whose downstream must NOT silently
596    ///   substitute a placeholder for the API call target).
597    ///
598    /// The primitive family's `""`-on-missing-name semantics
599    /// intentionally differs from [`Self::name_or_placeholder`]'s
600    /// `"unnamed"` semantics: the caller sites for this form (pool
601    /// membership row seeds, HashMap keys) are load-bearing keys — a
602    /// display placeholder like `"unnamed"` would silently alias every
603    /// missing-name Process to the same key, collapsing distinct rows
604    /// in the pool's member list. The empty-string sentinel keeps the
605    /// pre-lift byte-shape and lets downstream consumers gate on
606    /// `String::is_empty` if they need to filter the missing-name
607    /// corner explicitly.
608    ///
609    /// A future normalization step (a name-canonicalization pass, a
610    /// case-fold key builder, a per-pool alias table for renamed
611    /// Processes across generations) lands at ONE substrate method
612    /// here and both downstream `PoolMember` / `PoolMemberSnapshot`
613    /// seeds pick up the upgrade mechanically — no per-callsite hand-
614    /// edit at `reconcile_pool`.
615    ///
616    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
617    /// the `.metadata.name.clone().unwrap_or_default()` chain recurred
618    /// at two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
619    /// duplication trigger, and is lifted to ONE owner here).
620    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
621    /// the pins bind the missing-name corner + the empty-string
622    /// sentinel byte-shape + the owned-form `String` return type +
623    /// the byte-identical parity with the pre-lift chain + the
624    /// fallback-value coherence with the sibling [`Self::uid_or_empty`]
625    /// on the metadata-slot × empty-sentinel axis, so a regression
626    /// that drifted any surface at `tests::owned_name_or_empty_*`
627    /// rather than as silent operator-facing skew between the pool-
628    /// member seed and the desired-count snapshot seed on the SAME
629    /// pool).
630    pub fn owned_name_or_empty(&self) -> String {
631        self.metadata.name.clone().unwrap_or_default()
632    }
633
634    /// Borrow-form spec-projection primitive on the declared parent-PID
635    /// axis: returns the hierarchical PID path (e.g. `"seph.1"`) the
636    /// author declared at `spec.identity.parent`, with the empty-slot
637    /// corner collapsed to `None` — the ONE-liner collapse of the
638    /// paired `self.spec.identity.parent.as_deref()` incantation every
639    /// consumer restated by hand pre-lift.
640    ///
641    /// Pre-lift the `.spec.identity.parent.as_deref()` chain was hand-
642    /// authored at TWO sites past the ★★ PRIME-DIRECTIVE ≥ 2
643    /// duplication threshold in `tatara-reconciler::phase_machine`:
644    /// * `handle_forking` — the ALLOCATE-PID composer that threads the
645    ///   declared parent PID into [`pid::allocate_pid`] and also into
646    ///   the status patch payload (`{ "pid": new_pid, "parent":
647    ///   parent_pid }`), so the reconciler-observed
648    ///   [`ProcessStatus::parent`] slot mirrors the author-declared
649    ///   [`IdentitySpec::parent`] at fork time. The `info!` tracing
650    ///   span also reads the same slice as the `parent` field on the
651    ///   PID-assigned log line.
652    /// * `handle_exiting` — the SIGTERM cascade's child-fan-out filter
653    ///   that enumerates every Process cluster-wide and picks children
654    ///   whose `spec.identity.parent` equals this Process's currently-
655    ///   observed PID (`.filter(|c| c.spec.identity.parent.as_deref()
656    ///   == Some(pid))`). The filter runs per candidate child, so the
657    ///   borrow-form projection avoids allocating one `String` clone
658    ///   per non-matching row in the cluster-wide list.
659    ///
660    /// Both sites walked the SAME `.as_deref()` chain and both wanted
661    /// the `Option<&str>` form the primitive returns — the
662    /// `handle_forking` site to feed positionally into
663    /// `pid::allocate_pid(&identity, parent_pid, next_seq)` and the
664    /// tracing span's `parent = ?parent_pid` debug print + the JSON
665    /// payload's `"parent": parent_pid` slot; the `handle_exiting`
666    /// filter to compare directly against `Some(pid)` where `pid:
667    /// &str` came off the borrow-form peer [`Self::observed_pid`].
668    ///
669    /// Return-form axis: `Option<&str>` mirrors the borrow-first
670    /// discipline of every peer primitive on the metadata / status
671    /// slot family ([`Self::namespace_or_default`],
672    /// [`Self::name_or_placeholder`], [`Self::observed_pid`],
673    /// [`Self::annotation`]). The empty-slot corner
674    /// (`spec.identity.parent = None`, matching `init` / PID 1 with
675    /// no parent) collapses to `None` so `.is_some()` / `if let
676    /// Some(_)` / `.map(...)` behave identically on a `Process`
677    /// authored at cluster init (PID 1, parent absent) and on any
678    /// PID-N child (parent present) — matching the pre-lift
679    /// `.as_deref()` chain's `None` byte-identically.
680    ///
681    /// Peer to [`Self::observed_pid`] on the (spec-declared ×
682    /// status-observed) axis pair: `observed_pid` returns the PID
683    /// path this Process currently OWNS (the reconciler-persisted
684    /// child position in the hierarchy), while `declared_parent_pid`
685    /// returns the PID path this Process's parent OWNS (the author-
686    /// declared upstream position). The SIGTERM cascade at
687    /// `handle_exiting` composes both: it reads its own
688    /// [`Self::observed_pid`] and matches each candidate child's
689    /// [`Self::declared_parent_pid`] against that value — the child-
690    /// fan-out relation IS the spec-declared × status-observed axis
691    /// pair collapsed to a single comparator, both sides routed
692    /// through the same borrow-form skeleton.
693    ///
694    /// A future normalization step (a per-slot canonicalization pass
695    /// that rejects malformed hierarchical PIDs, a case-fold lookup
696    /// against a table of renamed identities, a cross-cluster prefix
697    /// stripper, an alias-table lookup that maps a legacy PID to its
698    /// current spelling) lands at ONE substrate method here and both
699    /// downstream consumers pick up the upgrade mechanically — no
700    /// per-callsite hand-edit at `handle_forking` / `handle_exiting`.
701    ///
702    /// Sibling to the peer metadata-projection primitives
703    /// ([`Self::namespace_or_default`], [`Self::name_or_placeholder`],
704    /// [`Self::coordinates_or_defaults`], [`Self::coordinates_or_none`],
705    /// [`Self::owned_coordinates_or_err`], [`Self::annotation`]) on the
706    /// metadata axis; this method opens the borrow-form peer on the
707    /// declared-identity axis. Future identity projections
708    /// (`declared_name_override` on the `spec.identity.name_override`
709    /// axis, a paired `declared_identity` composite that returns both
710    /// halves) land as peer methods on this same axis.
711    ///
712    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
713    /// the `.spec.identity.parent.as_deref()` chain recurred at two
714    /// hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
715    /// trigger, and is lifted to ONE owner here). THEORY.md §II.1
716    /// invariant 5 (composition preserves proofs — the pins bind the
717    /// empty-slot corner + the borrow-form `&str` lifetime + the
718    /// byte-identical parity with the pre-lift `.as_deref()` chain,
719    /// so a regression that drifted any surface at
720    /// `tests::declared_parent_pid_*` rather than as silent operator-
721    /// facing skew between the ALLOCATE-PID composer and the SIGTERM
722    /// cascade's child-fan-out filter on the SAME parent-child pair).
723    pub fn declared_parent_pid(&self) -> Option<&str> {
724        self.spec.identity.parent.as_deref()
725    }
726
727    /// Borrow-form spec-projection primitive on the declared
728    /// name-override axis: returns the human name the author declared
729    /// at `spec.identity.name_override` (used verbatim instead of the
730    /// content-hash-derived name in [`derive_identity`]), with the
731    /// empty-slot corner collapsed to `None` — the ONE-liner collapse
732    /// of the paired `self.spec.identity.name_override.as_deref()`
733    /// incantation every consumer restated by hand pre-lift.
734    ///
735    /// Pre-lift the `.spec.identity.name_override.as_deref()` chain
736    /// was hand-authored at TWO sites past the ★★ PRIME-DIRECTIVE ≥ 2
737    /// duplication threshold in `tatara-reconciler::phase_machine`,
738    /// both feeding the second positional argument of
739    /// [`derive_identity`]:
740    /// * `handle_pending` — the DECLARE composer that computes the
741    ///   Process's [`Identity`] on entry to the state machine (before
742    ///   `patch::phase_status` writes it into `status.identity`).
743    /// * `handle_forking` — the ALLOCATE-PID composer that recomputes
744    ///   the same [`Identity`] on a rehydration path (status may
745    ///   already carry an identity from a prior reconcile, in which
746    ///   case the `.and_then(|s| s.identity.clone())` short-circuit
747    ///   takes it; otherwise this `.unwrap_or_else` branch fires and
748    ///   recomputes the identity fresh from the spec) so `pid::
749    ///   allocate_pid` sees the SAME [`Identity`] the DECLARE phase
750    ///   produced.
751    ///
752    /// Both sites walked the SAME `.as_deref()` chain and both wanted
753    /// the `Option<&str>` form the primitive returns — as the second
754    /// positional argument to `derive_identity(&self.spec, …)`, which
755    /// internally trims + filters empty strings + dispatches on
756    /// `Some(non_empty)` (verbatim name, `name_override: true`) vs
757    /// `None | Some(empty | whitespace)` (content-hash-derived name,
758    /// `name_override: false`). The primitive itself preserves the
759    /// raw slot byte-identically (the trim happens IN
760    /// `derive_identity`, not at the borrow site), so the two live
761    /// paths compose through the SAME borrow-form skeleton.
762    ///
763    /// Return-form axis: `Option<&str>` mirrors the borrow-first
764    /// discipline of every peer primitive on the metadata / status /
765    /// spec-identity slot family ([`Self::namespace_or_default`],
766    /// [`Self::name_or_placeholder`], [`Self::observed_pid`],
767    /// [`Self::annotation`], [`Self::declared_parent_pid`]). The
768    /// empty-slot corner (`spec.identity.name_override = None`,
769    /// matching a Process authored WITHOUT the human-name-override
770    /// escape hatch — the default; `derive_identity` then computes
771    /// the name from the content hash) collapses to `None` so
772    /// `.is_some()` / `if let Some(_)` / `.map(...)` behave
773    /// identically on the two Process shapes an operator can author.
774    ///
775    /// Peer to [`Self::declared_parent_pid`] on the (parent × name-
776    /// override) sub-axis of the declared-identity axis: both
777    /// primitives project a `Option<String>` slot on `IdentitySpec`
778    /// through the SAME borrow-form skeleton, so a future
779    /// `declared_identity` composite that returns both halves
780    /// together (e.g. as a `(Option<&str>, Option<&str>)` tuple or a
781    /// borrow-form `DeclaredIdentityView<'_>` newtype) lands as ONE
782    /// method that COMPOSES the two peer primitives, not as three
783    /// hand-authored `.as_deref()` chains restated at each callsite.
784    ///
785    /// A future normalization step (a per-slot canonicalization pass
786    /// that rejects malformed names, a case-fold lookup against a
787    /// table of renamed identities, an alias-table lookup that maps
788    /// a legacy name-override to its current spelling, a whitespace-
789    /// trim lift OUT of `derive_identity` INTO the primitive so both
790    /// consumers see the trimmed form) lands at ONE substrate method
791    /// here and both downstream consumers pick up the upgrade
792    /// mechanically — no per-callsite hand-edit at `handle_pending` /
793    /// `handle_forking`.
794    ///
795    /// Sibling to the peer spec-identity projection
796    /// [`Self::declared_parent_pid`] on the declared-identity axis;
797    /// this method opens the borrow-form peer on the name-override
798    /// sub-axis of the same closed set (`IdentitySpec { parent,
799    /// name_override }`). Future identity projections (a paired
800    /// `declared_identity` composite that returns both halves
801    /// together) land as peer methods on this same axis.
802    ///
803    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
804    /// the `.spec.identity.name_override.as_deref()` chain recurred
805    /// at two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
806    /// duplication trigger, and is lifted to ONE owner here).
807    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
808    /// the pins bind the empty-slot corner + the borrow-form `&str`
809    /// lifetime + the byte-identical parity with the pre-lift
810    /// `.as_deref()` chain + the invariance under
811    /// [`derive_identity`]'s internal trim/filter step, so a
812    /// regression that drifted any surface at
813    /// `tests::declared_name_override_*` rather than as silent
814    /// operator-facing skew between the DECLARE composer and the
815    /// ALLOCATE-PID rehydration branch on the SAME Process spec).
816    pub fn declared_name_override(&self) -> Option<&str> {
817        self.spec.identity.name_override.as_deref()
818    }
819
820    /// Borrowed slice of the FluxCD resources this Process's status
821    /// currently persists at `status.flux_resources`, with the
822    /// missing-`status` corner collapsed to an empty slice — the ONE-
823    /// line collapse of the paired `self.status.as_ref().map(|s|
824    /// s.flux_resources.clone()).unwrap_or_default()` incantation
825    /// every VERIFY-phase / ATTEST-heartbeat consumer restated by hand
826    /// pre-lift.
827    ///
828    /// Pre-lift the 5-line `.status.as_ref().map(|s| s.flux_resources
829    /// .clone()).unwrap_or_default()` chain was hand-authored at TWO
830    /// sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold in
831    /// `tatara-reconciler::phase_machine`:
832    /// * `handle_running` — the VERIFY-phase per-ref readiness probe
833    ///   seed that walks every ref through
834    ///   [`crate::status::FluxResourceRef::fetch_coords`] via
835    ///   `ssapply::fetch_flux_ref` and rebuilds an updated
836    ///   `Vec<FluxResourceRef>` with `ready` + `message` + `last_check`
837    ///   observed at reconcile time.
838    /// * `handle_attested` — the ATTEST-heartbeat drift detector that
839    ///   short-circuits on the first non-Ready ref via
840    ///   `ssapply::fetch_flux_ref` + `ssapply::ready_condition`.
841    ///
842    /// Both sites walked the SAME 5-line chain — clone the vector
843    /// eagerly for the length of the reconcile pass, then iterate it
844    /// by reference — even though neither site ever mutates the vector
845    /// nor keeps it alive past the enclosing async fn. Post-lift both
846    /// callers borrow the slice directly from `self.status`; the two
847    /// pre-lift `.clone()` calls disappear because the slice lives for
848    /// the borrow of `&self`, and both call sites' subsequent
849    /// downstream calls (`ssapply::fetch_flux_ref` / the
850    /// `patch::patch_process_status` write) do not touch the borrowed
851    /// `p: &Process`, so the borrow lifetime holds.
852    ///
853    /// Return-form axis: `&[FluxResourceRef]` mirrors the existing
854    /// borrow-first discipline every pre-lift consumer already
855    /// iterated by reference (`for r in &refs`), and the shape of
856    /// [`crate::status::FluxResourceRef::fetch_coords`]'s per-ref
857    /// borrow projection extends mechanically to the slice-level
858    /// projection here. The missing-`status` corner collapses to the
859    /// empty slice `&[]` so `.is_empty()` / `.len()` / iteration all
860    /// behave identically on a `Process` whose status is `None` and
861    /// on one whose status carries an empty `flux_resources` slot —
862    /// matching what the pre-lift `.unwrap_or_default()` produced
863    /// (an empty `Vec`).
864    ///
865    /// A future normalization step (a per-ref canonicalization pass
866    /// that skips duplicated refs, an owner-filter that returns only
867    /// refs stamped with the CURRENT `metadata.generation`, a
868    /// staleness gate that drops refs whose `last_check` predates a
869    /// reconcile deadline) lands at ONE substrate method here and
870    /// both downstream consumers pick up the upgrade mechanically —
871    /// no per-callsite hand-edit at `handle_running` /
872    /// `handle_attested`.
873    ///
874    /// Sibling to the [`Self::coordinates_or_none`] borrow-first
875    /// primitive on the metadata axis; this method opens the
876    /// analogous borrow-first primitive on the status-projection
877    /// axis. Future status projections (`observed_attestation` on
878    /// the attestation-chain axis, `observed_pid` on the PID axis,
879    /// `observed_children` on the child-fan-out axis) land as peer
880    /// methods on this same axis.
881    ///
882    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
883    /// the 5-line status-projection chain recurred at two hand-
884    /// authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
885    /// trigger, and is lifted to ONE owner here). THEORY.md §II.1
886    /// invariant 5 (composition preserves proofs — the pins bind the
887    /// missing-`status` corner + the slice-lifetime borrow discipline
888    /// + the byte-identical parity with the pre-lift 5-line chain, so
889    /// a regression that drifted any of the three surfaces at
890    /// `tests::observed_flux_resources_*` rather than as silent
891    /// operator-facing skew between the VERIFY-phase and ATTEST-
892    /// heartbeat consumers).
893    pub fn observed_flux_resources(&self) -> &[FluxResourceRef] {
894        self.status
895            .as_ref()
896            .map(|s| s.flux_resources.as_slice())
897            .unwrap_or(&[])
898    }
899
900    /// The borrow-form status-projection primitive on the PID axis:
901    /// returns the hierarchical PID path (e.g. `"seph.1.7"`) the
902    /// reconciler currently persists at `status.pid`, with BOTH the
903    /// missing-`status` corner AND the empty-slot corner collapsed
904    /// to `None` — the ONE-liner collapse of the paired
905    /// `self.status.as_ref().and_then(|s| s.pid.clone())` incantation
906    /// every consumer restated by hand pre-lift.
907    ///
908    /// Pre-lift the 3-line `.status.as_ref().and_then(|s| s.pid
909    /// .clone())` chain was hand-authored at TWO sites past the ★★
910    /// PRIME-DIRECTIVE ≥ 2 duplication threshold in
911    /// `tatara-reconciler::phase_machine`:
912    /// * `handle_forking` — the ALLOCATE-PID gate that short-
913    ///   circuits the PID allocator when the reconciler already
914    ///   assigned a PID on a prior reconcile pass (pre-lift the
915    ///   chain composed with `.is_some()` and threw the clone away
916    ///   without ever reading the string).
917    /// * `handle_exiting` — the SIGTERM cascade that enumerates
918    ///   child Processes and terminates them by matching each
919    ///   child's `spec.identity.parent` against the PID this Process
920    ///   currently owns (pre-lift the chain bound an owned
921    ///   `Option<String>` and threaded `pid.as_str()` into the
922    ///   downstream `.as_deref() == Some(...)` comparator).
923    ///
924    /// Both sites walked the SAME 3-line chain — clone the `String`
925    /// eagerly, then either drop it (the `handle_forking` gate) or
926    /// re-borrow it through `.as_str()` (the `handle_exiting`
927    /// comparator) — even though neither site ever mutates the PID
928    /// nor keeps it alive past the enclosing async fn. Post-lift
929    /// both callers borrow the PID directly from `self.status`; the
930    /// pre-lift `.clone()` at both sites disappears because the
931    /// `&str` lives for the borrow of `&self`, and both call sites'
932    /// subsequent downstream calls (the K8s API list/patch, the
933    /// child-Process comparator) do not touch the borrowed
934    /// `p: &Process`, so the borrow lifetime holds.
935    ///
936    /// Return-form axis: `Option<&str>` mirrors the existing
937    /// borrow-first discipline every pre-lift consumer already
938    /// re-borrowed through `.as_str()` before use, and the shape of
939    /// [`Self::coordinates_or_none`]'s `Option<(&str, &str)>`
940    /// projection extends mechanically to the single-slot
941    /// projection here. The missing-`status` corner AND the
942    /// populated-status-with-`pid=None` corner BOTH collapse to
943    /// `None` so `.is_some()` / `if let Some(_)` / `.map(...)`
944    /// behave identically on a `Process` whose status is `None`
945    /// and on one whose status carries an unpopulated `pid` slot —
946    /// matching what the pre-lift `.and_then(...)` chain produced.
947    ///
948    /// A future normalization step (a per-slot canonicalization
949    /// pass that rejects malformed hierarchical PIDs, a
950    /// generation-filter that returns `None` for a PID stamped
951    /// with a stale `metadata.generation`, a staleness gate that
952    /// drops a PID whose observing `phase_since` predates a
953    /// reconcile deadline) lands at ONE substrate method here and
954    /// both downstream consumers pick up the upgrade mechanically
955    /// — no per-callsite hand-edit at `handle_forking` /
956    /// `handle_exiting`.
957    ///
958    /// Sibling to the peer [`Self::observed_flux_resources`]
959    /// borrow-first primitive on the flux-resources axis; both
960    /// methods compose the same missing-`status` fallback +
961    /// borrow-form return-shape skeleton on distinct
962    /// `ProcessStatus` slots. Future status projections
963    /// (`observed_parent` on the parent-pointer axis,
964    /// `observed_message` on the human-readable-status axis,
965    /// `observed_attestation` on the attestation-chain axis) land
966    /// as peer methods on this same axis.
967    ///
968    /// Theory anchor: THEORY.md §VI.1 (generation over
969    /// composition — the 3-line status-projection chain recurred
970    /// at two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
971    /// duplication trigger, and is lifted to ONE owner here).
972    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
973    /// the pins bind the missing-`status` corner + the empty-slot
974    /// corner + the borrow-form `&str` lifetime + the
975    /// byte-identical parity with the pre-lift 3-line chain, so a
976    /// regression that drifted any surface at
977    /// `tests::observed_pid_*` rather than as silent operator-
978    /// facing skew between the ALLOCATE-PID gate and the SIGTERM
979    /// cascade on the SAME `Process`).
980    pub fn observed_pid(&self) -> Option<&str> {
981        self.status.as_ref().and_then(|s| s.pid.as_deref())
982    }
983
984    /// The borrow-form status-projection primitive on the
985    /// attestation-chain axis: returns the last
986    /// [`ProcessAttestation`] the reconciler persisted at
987    /// `status.attestation`, with the missing-`status` corner AND the
988    /// empty-slot corner BOTH collapsed to `None` — the ONE-liner
989    /// collapse of the paired `self.status.as_ref().and_then(|s|
990    /// s.attestation.as_ref())` incantation every consumer restated
991    /// by hand pre-lift.
992    ///
993    /// Pre-lift the 3-line `.status.as_ref().and_then(|s| s
994    /// .attestation.as_ref())` chain was hand-authored at TWO sites
995    /// past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold in
996    /// `tatara-reconciler`:
997    /// * `phase_machine::advance_to_attested` — the ATTEST composer
998    ///   that chains `prior.next(pillars)` when a prior attestation
999    ///   is persisted and seeds with `ProcessAttestation::initial`
1000    ///   otherwise.
1001    /// * `render::render_export_jobs` — the ephemeral-export Job
1002    ///   builder that pulls the prior `composed_root` off the last
1003    ///   persisted attestation and threads it into every rendered
1004    ///   Job's `previousRoot` env var, so the export receipt chains
1005    ///   into the Process's BLAKE3 attestation tree at the correct
1006    ///   generation boundary.
1007    ///
1008    /// Both sites walked the SAME 3-line chain — the borrow-form
1009    /// `Option<&ProcessAttestation>` shape both consumers wanted
1010    /// already — even though neither site ever mutated the
1011    /// attestation nor kept it alive past the enclosing async fn.
1012    /// Post-lift both callers borrow the attestation directly from
1013    /// `self.status`; the pre-lift 3-line chain shrinks to a single
1014    /// method call at both sites, and both consumers' subsequent
1015    /// downstream calls (`ProcessAttestation::next` for the ATTEST
1016    /// composer, `.composed_root.clone()` for the export Job builder)
1017    /// do not touch the borrowed `p: &Process`, so the borrow
1018    /// lifetime holds.
1019    ///
1020    /// Return-form axis: `Option<&ProcessAttestation>` mirrors the
1021    /// existing borrow-first discipline every pre-lift consumer
1022    /// already re-borrowed through `.as_ref()`, and the shape of the
1023    /// peer [`Self::observed_pid`] projection extends mechanically
1024    /// to the whole-attestation-record projection here. The missing-
1025    /// `status` corner AND the populated-status-with-`attestation
1026    /// =None` corner BOTH collapse to `None` so `.is_some()` / `if
1027    /// let Some(_)` / `.map(...)` behave identically on a `Process`
1028    /// whose status is `None` and on one whose status carries an
1029    /// unpopulated `attestation` slot — matching what the pre-lift
1030    /// `.and_then(...)` chain produced.
1031    ///
1032    /// A future normalization step (a per-slot canonicalization pass
1033    /// that rejects a persisted attestation whose `composed_root`
1034    /// fails `verify`, a generation-filter that returns `None` for
1035    /// an attestation stamped with a stale `metadata.generation`, a
1036    /// staleness gate that drops an attestation whose `attested_at`
1037    /// predates a reconcile deadline) lands at ONE substrate method
1038    /// here and both downstream consumers pick up the upgrade
1039    /// mechanically — no per-callsite hand-edit at
1040    /// `advance_to_attested` / `render_export_jobs`.
1041    ///
1042    /// Sibling to the peer [`Self::observed_pid`] +
1043    /// [`Self::observed_flux_resources`] borrow-first primitives on
1044    /// the PID + flux-resources axes; all three methods compose the
1045    /// same missing-`status` fallback + borrow-form return-shape
1046    /// skeleton on distinct `ProcessStatus` slots. Future status
1047    /// projections (`observed_parent` on the parent-pointer axis,
1048    /// `observed_message` on the human-readable-status axis) land
1049    /// as peer methods on this same axis.
1050    ///
1051    /// Theory anchor: THEORY.md §VI.1 (generation over composition
1052    /// — the 3-line status-projection chain recurred at two hand-
1053    /// authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
1054    /// trigger, and is lifted to ONE owner here). THEORY.md §II.1
1055    /// invariant 5 (composition preserves proofs — the pins bind
1056    /// the missing-`status` corner + the empty-slot corner + the
1057    /// borrow-form `&ProcessAttestation` lifetime + the byte-
1058    /// identical parity with the pre-lift 3-line chain, so a
1059    /// regression that drifted any surface at
1060    /// `tests::observed_attestation_*` rather than as silent
1061    /// operator-facing skew between the ATTEST composer and the
1062    /// ephemeral-export receipt chain on the SAME `Process`).
1063    pub fn observed_attestation(&self) -> Option<&ProcessAttestation> {
1064        self.status.as_ref().and_then(|s| s.attestation.as_ref())
1065    }
1066
1067    /// The borrow-form status-projection primitive on the resolved-
1068    /// identity axis: returns the [`Identity`] the reconciler
1069    /// currently persists at `status.identity` (name + content hash +
1070    /// override flag), with the missing-`status` corner AND the
1071    /// empty-slot corner BOTH collapsed to `None` — the ONE-liner
1072    /// collapse of the paired `self.status.as_ref().and_then(|s|
1073    /// s.identity.as_ref())` incantation every consumer restated by
1074    /// hand pre-lift.
1075    ///
1076    /// Pre-lift the paired `.status.as_ref().and_then(|s|
1077    /// s.identity.<clone|as_ref>())` chain was hand-authored at TWO
1078    /// sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold
1079    /// in `tatara-reconciler`:
1080    /// * `phase_machine::handle_forking` — the FORK-time identity
1081    ///   seed that reuses the reconciler-persisted `Identity` if
1082    ///   present and falls back to a fresh `derive_identity(&spec,
1083    ///   name_override)` otherwise. Pre-lift the site cloned the
1084    ///   whole `Identity` off the borrow before threading it through
1085    ///   `.unwrap_or_else(...)` even though the fallback path
1086    ///   allocates its own owned `Identity` — the pre-lift clone
1087    ///   allocated a fresh `Identity` on the happy path just so the
1088    ///   `Option`'s shape matched the fallback's `Identity` return
1089    ///   type.
1090    /// * `ssapply::inject_annotations` — the SSA-time annotation
1091    ///   composer that stamps the content-hash annotation onto every
1092    ///   owned resource. Pre-lift the site nested the identity
1093    ///   borrow-form check inside a manual `if let Some(status) =
1094    ///   &process.status { … }` guard alongside sibling `status.pid`
1095    ///   and `status.attestation` accesses — three siblings the peer
1096    ///   primitives [`Self::observed_pid`] and
1097    ///   [`Self::observed_attestation`] already own, so the outer
1098    ///   status guard was the last hand-authored `.status.as_ref()`
1099    ///   destructure at this composer.
1100    ///
1101    /// Both sites walked the SAME 3-line chain (one via `.clone()`,
1102    /// one via `.as_ref()`) — the borrow-form
1103    /// `Option<&Identity>` shape both consumers wanted already, even
1104    /// though the FORK-time seed then had to `.clone()` off the
1105    /// borrow to compose with the owned-`Identity` fallback. Post-
1106    /// lift the seed calls `.observed_identity().cloned()` at the
1107    /// exact composition point where the owned value is required
1108    /// (the empty-borrow corner clones nothing, since
1109    /// `Option::cloned` on `None` is `None`), and the SSA-time
1110    /// consumer drops the outer status guard entirely — the
1111    /// three-sibling primitive family (pid + identity + attestation)
1112    /// now peers through `observed_pid` +
1113    /// `observed_identity` + `observed_attestation` at ONE call each
1114    /// with no shared status destructure between them.
1115    ///
1116    /// Return-form axis: `Option<&Identity>` mirrors the
1117    /// existing borrow-first discipline every pre-lift consumer
1118    /// already re-borrowed through `.as_ref()` / re-cloned through
1119    /// `.clone()`, and the shape of the peer
1120    /// [`Self::observed_attestation`] projection extends
1121    /// mechanically to the whole-`Identity`-record projection here.
1122    /// The missing-`status` corner AND the populated-status-with-
1123    /// `identity=None` corner BOTH collapse to `None` so
1124    /// `.is_some()` / `if let Some(_)` / `.map(...)` behave
1125    /// identically on a `Process` whose status is `None` and on one
1126    /// whose status carries an unpopulated `identity` slot —
1127    /// matching what the pre-lift `.and_then(...)` chain produced.
1128    ///
1129    /// A future normalization step (a per-slot canonicalization
1130    /// pass that rejects an `Identity` whose `content_hash` fails
1131    /// re-derivation against the current spec, a generation-filter
1132    /// that returns `None` for an identity stamped with a stale
1133    /// `metadata.generation`, a staleness gate that drops an
1134    /// identity whose observing `phase_since` predates a reconcile
1135    /// deadline) lands at ONE substrate method here and both
1136    /// downstream consumers pick up the upgrade mechanically — no
1137    /// per-callsite hand-edit at `handle_forking` /
1138    /// `inject_annotations`.
1139    ///
1140    /// Sibling to the peer [`Self::observed_pid`] +
1141    /// [`Self::observed_attestation`] +
1142    /// [`Self::observed_flux_resources`] borrow-first primitives on
1143    /// the PID + attestation-chain + flux-resources axes; all four
1144    /// methods compose the same missing-`status` fallback +
1145    /// borrow-form return-shape skeleton on distinct `ProcessStatus`
1146    /// slots. Future status projections (`observed_parent` on the
1147    /// parent-pointer axis, `observed_message` on the human-
1148    /// readable-status axis) land as peer methods on this same
1149    /// axis.
1150    ///
1151    /// Theory anchor: THEORY.md §VI.1 (generation over composition
1152    /// — the 3-line status-projection chain recurred at two hand-
1153    /// authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
1154    /// trigger, and is lifted to ONE owner here). THEORY.md §II.1
1155    /// invariant 5 (composition preserves proofs — the pins bind
1156    /// the missing-`status` corner + the empty-slot corner + the
1157    /// borrow-form `&Identity` lifetime + the byte-identical parity
1158    /// with the pre-lift 3-line chain, so a regression that drifted
1159    /// any surface at `tests::observed_identity_*` rather than as
1160    /// silent operator-facing skew between the FORK-time identity
1161    /// seed and the SSA-time content-hash annotation stamp on the
1162    /// SAME `Process`).
1163    pub fn observed_identity(&self) -> Option<&Identity> {
1164        self.status.as_ref().and_then(|s| s.identity.as_ref())
1165    }
1166
1167    /// The copy-form status-projection primitive on the phase axis:
1168    /// returns the [`ProcessPhase`] the reconciler currently persists
1169    /// at `status.phase`, wrapped in an `Option` so the missing-
1170    /// `status` corner collapses to `None` — the ONE-liner collapse
1171    /// of the paired `self.status.as_ref().map(|s| s.phase)`
1172    /// incantation every consumer restated by hand pre-lift.
1173    ///
1174    /// Peer to the borrow-form projections
1175    /// [`Self::observed_pid`] (PID axis, `Option<&str>`),
1176    /// [`Self::observed_flux_resources`] (flux-resources axis,
1177    /// `&[FluxResourceRef]`), and [`Self::observed_attestation`]
1178    /// (attestation-chain axis, `Option<&ProcessAttestation>`); this
1179    /// method opens the copy-form peer for `ProcessPhase` — a
1180    /// `Copy` scalar with a `Default` impl (`Pending`), so the
1181    /// return is `Option<ProcessPhase>` rather than
1182    /// `Option<&ProcessPhase>` (borrow would give the caller
1183    /// nothing over the copy for a 1-byte enum) and neither the
1184    /// missing-`status` corner nor a "empty slot" corner is
1185    /// meaningful — the underlying slot is a bare `ProcessPhase`,
1186    /// not `Option<ProcessPhase>`, so the primitive returns `None`
1187    /// iff `status: None`.
1188    ///
1189    /// Pre-lift the 3-line `.status.as_ref().map(|s| s.phase)`
1190    /// chain was hand-authored at FIVE sites past the ★★
1191    /// PRIME-DIRECTIVE ≥ 2 duplication threshold in
1192    /// `tatara-reconciler`:
1193    /// * `controller::reconcile` — the top-level dispatcher's
1194    ///   `current_phase` seed that feeds the deletion-preempt +
1195    ///   signal-ingestion gates + the per-phase handler dispatch.
1196    ///   Pre-lift `.unwrap_or(ProcessPhase::Pending)`.
1197    /// * `boundary::evaluate_process_phase` — the boundary
1198    ///   evaluator's `ProcessPhase` condition (a peer-Process
1199    ///   `phase`-reached postcondition). Pre-lift
1200    ///   `.unwrap_or(ProcessPhase::Pending)`.
1201    /// * `boundary::check_depends_on` — the `depends_on`
1202    ///   pre-condition audit that stashes the observed phase into
1203    ///   the `UnmetDependency::actual: Option<ProcessPhase>` slot
1204    ///   (keeps the `Option` form). Pre-lift the raw
1205    ///   `.map(|s| s.phase)` shape.
1206    /// * `phase_machine::p_current_phase_str` — the released-from
1207    ///   annotation composer that emits `"Attested"` for every
1208    ///   non-`Failed` phase (SIGSTOP/SIGCONT release gate).
1209    ///   Pre-lift `.unwrap_or(ProcessPhase::Attested)` — the ONE
1210    ///   site whose default is not `Pending`; the primitive
1211    ///   returns the raw `Option` so the caller's `.unwrap_or`
1212    ///   default choice stays local rather than baked in.
1213    /// * `table_controller::stable_name_group_key` — the routing-
1214    ///   groupby seed that pairs the phase with the PID + creation
1215    ///   timestamp when partitioning Processes claiming the same
1216    ///   stable name. Pre-lift `.unwrap_or(ProcessPhase::Pending)`.
1217    ///
1218    /// All FIVE sites walked the SAME 3-line `.status.as_ref()
1219    /// .map(|s| s.phase)` chain — three closed with `unwrap_or
1220    /// (ProcessPhase::Pending)` (the `Default`), one closed with
1221    /// `unwrap_or(ProcessPhase::Attested)`, one kept the raw
1222    /// `Option<ProcessPhase>` — so the ONE substrate accessor
1223    /// returns the raw `Option<ProcessPhase>` and each consumer
1224    /// keeps its `.unwrap_or(...)` default choice at its own site.
1225    ///
1226    /// A future normalization step (a generation-filter that
1227    /// returns `None` for a phase stamped with a stale
1228    /// `metadata.generation`, a staleness gate that drops a phase
1229    /// whose observing `phase_since` predates a reconcile
1230    /// deadline, a canonicalization pass that maps a phase that
1231    /// no longer belongs to the CRD's closed set to `None`) lands
1232    /// at ONE substrate method here and all five consumers pick
1233    /// up the upgrade mechanically — no per-callsite hand-edit at
1234    /// `reconcile` / `evaluate_process_phase` / `check_depends_on`
1235    /// / `p_current_phase_str` / `stable_name_group_key`.
1236    ///
1237    /// Future status projections (`observed_parent` on the
1238    /// parent-pointer axis, `observed_message` on the human-
1239    /// readable-status axis, `observed_children` on the child
1240    /// fan-out axis, `observed_exit_code` on the terminal-exit
1241    /// axis) land as peer methods on this same axis.
1242    ///
1243    /// Theory anchor: THEORY.md §VI.1 (generation over
1244    /// composition — the 3-line status-projection chain recurred
1245    /// at FIVE hand-authored sites past the ★★ PRIME-DIRECTIVE
1246    /// ≥ 2 duplication trigger, and is lifted to ONE owner here).
1247    /// THEORY.md §II.1 invariant 5 (composition preserves proofs
1248    /// — the pins bind the missing-`status` corner + the
1249    /// per-variant enum round-trip + the byte-identical parity
1250    /// with the pre-lift 3-line chain, so a regression that
1251    /// drifted any surface at `tests::observed_phase_*` rather
1252    /// than as silent operator-facing skew between the
1253    /// controller's dispatch seed and the boundary evaluator's
1254    /// depends-on audit on the SAME `Process` within one
1255    /// reconcile pass).
1256    pub fn observed_phase(&self) -> Option<ProcessPhase> {
1257        self.status.as_ref().map(|s| s.phase)
1258    }
1259
1260    /// The copy-form status-projection primitive on the phase axis
1261    /// with the `Pending` sink applied — the ONE-liner collapse of
1262    /// the paired `self.observed_phase().unwrap_or(ProcessPhase::
1263    /// Pending)` incantation every reconciler consumer restated by
1264    /// hand at the `Option`-flattening tail of the `observed_phase`
1265    /// call. Sibling to [`Self::observed_phase`] on the (return-form
1266    /// × fallback shape) axis pair — the raw-`Option` corner stays
1267    /// as `observed_phase`, this method opens the `Pending`-defaulted
1268    /// corner that four of the five hand-authored `observed_phase`
1269    /// consumers chose (the fifth chose `Attested`; it keeps the raw
1270    /// `Option` accessor because a `Pending` sink would silently drop
1271    /// its released-from-annotation branch into the wrong label).
1272    ///
1273    /// The primitive returns [`ProcessPhase::Pending`] on any missing
1274    /// `status` slot — the same sentinel [`ProcessPhase::default`]
1275    /// returns, and the same fallback all four pre-lift consumers
1276    /// wrote by hand. `ProcessPhase::Pending` is load-bearing as the
1277    /// "not yet observed" default because the top-level dispatcher's
1278    /// `Pending → Forking` transition, the boundary evaluator's
1279    /// per-Process phase-reached postcondition, the routing groupby's
1280    /// stable-name claim-arbiter row seed, and the pool controller's
1281    /// desired-count snapshot all read a freshly-forked Process (no
1282    /// `status` yet stamped by the reconciler) as being at the
1283    /// entrypoint phase of the closed lifecycle. A caller with a
1284    /// different default choice (currently only the SIGSTOP/SIGCONT
1285    /// release gate's `Attested` fallback in
1286    /// `phase_machine::p_current_phase_str`) keeps the raw
1287    /// [`Self::observed_phase`] accessor at its own site.
1288    ///
1289    /// Pre-lift the two-link `.observed_phase().unwrap_or
1290    /// (ProcessPhase::Pending)` chain was hand-authored at FOUR
1291    /// sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold
1292    /// across the workspace:
1293    /// * `tatara-reconciler::controller::reconcile` — the top-level
1294    ///   dispatcher's `current_phase` seed that feeds the
1295    ///   deletion-preempt + signal-ingestion gates + the per-phase
1296    ///   handler dispatch.
1297    /// * `tatara-reconciler::boundary::evaluate_process_phase` — the
1298    ///   boundary evaluator's [`ConditionKind::ProcessPhase`]
1299    ///   evaluator that compares a peer-Process's observed phase
1300    ///   against the operator-declared `phase`-reached postcondition.
1301    /// * `tatara-reconciler::table_controller::stable_name_group_key`
1302    ///   — the routing-groupby seed that pairs the phase with the
1303    ///   PID + creation timestamp when partitioning Processes
1304    ///   claiming the same stable name.
1305    /// * `tatara-pool-reconciler::controller_pool::reconcile_pool` —
1306    ///   the desired-count loop's per-member snapshot seed that feeds
1307    ///   `decide_pool_convergence` with each owned Process's
1308    ///   `(phase, created_at)` pair.
1309    ///
1310    /// All FOUR sites walked the SAME two-link chain and all four
1311    /// closed with `ProcessPhase::Pending` as the sink; post-lift
1312    /// each callsite reads `process.observed_phase_or_pending()` and
1313    /// the produced `ProcessPhase` feeds the same downstream branch
1314    /// (dispatch on the `current_phase` value, comparison against a
1315    /// declared threshold, groupby-key composition, member-state
1316    /// snapshot construction) unchanged.
1317    ///
1318    /// Return-form axis: `ProcessPhase` matches the copy discipline
1319    /// of [`Self::observed_phase`] (a `Copy` scalar one byte wide),
1320    /// with the [`Option`] wrapper collapsed at the primitive rather
1321    /// than at every consumer. A caller that needs the missing-`status`
1322    /// corner as a distinguishable value keeps the raw
1323    /// [`Self::observed_phase`] accessor.
1324    ///
1325    /// A future normalization step (a generation-filter that
1326    /// treats a phase stamped with a stale `metadata.generation` as
1327    /// unobserved and therefore `Pending`, a staleness gate that
1328    /// drops a phase whose observing `phase_since` predates a
1329    /// reconcile deadline, a canonicalization pass that maps a phase
1330    /// that no longer belongs to the CRD's closed set to `Pending`)
1331    /// lands at ONE substrate method here — because this primitive
1332    /// composes on top of [`Self::observed_phase`], the normalization
1333    /// applies to both the raw-`Option` and the `Pending`-sinked
1334    /// return through the SAME upstream body — and all four
1335    /// downstream consumers pick up the upgrade mechanically.
1336    ///
1337    /// Peer to the sibling defaulted-fallback primitive family
1338    /// [`Self::namespace_or_default`] +
1339    /// [`Self::name_or_placeholder`] + [`Self::uid_or_empty`] on the
1340    /// (return-shape × fallback-value) axis — those three open the
1341    /// borrow-form defaulted corner for the metadata slots; this
1342    /// method opens the copy-form defaulted corner for the phase
1343    /// slot on `status`. Future defaulted-fallback status
1344    /// projections (an `observed_pid_or_empty` on the PID axis, an
1345    /// `observed_exit_code_or_zero` on the terminal-exit axis) land
1346    /// as peer methods on this same axis.
1347    ///
1348    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1349    /// the two-link `.observed_phase().unwrap_or(Pending)` chain
1350    /// recurred at four hand-authored sites past the ★★
1351    /// PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
1352    /// owner here). THEORY.md §II.1 invariant 5 (composition
1353    /// preserves proofs — the pins bind the missing-`status` sink to
1354    /// `Pending` + populated-status pass-through + every
1355    /// `ProcessPhase` variant round-trip + byte-identical parity
1356    /// with the pre-lift two-link chain, so a regression that
1357    /// drifted any surface at `tests::observed_phase_or_pending_*`
1358    /// rather than as silent operator-facing skew between the
1359    /// top-level dispatcher's `Pending → Forking` seed and the
1360    /// boundary evaluator's per-Process phase-reached postcondition
1361    /// on the SAME `Process` within one reconcile pass).
1362    pub fn observed_phase_or_pending(&self) -> ProcessPhase {
1363        self.observed_phase().unwrap_or(ProcessPhase::Pending)
1364    }
1365
1366    /// Copy-form metadata-projection primitive on the deletion-tombstone
1367    /// axis: returns `true` iff the K8s API server has stamped a
1368    /// `metadata.deletionTimestamp` on this Process (the moment the
1369    /// object entered the "being deleted" corner of its lifecycle,
1370    /// after which further mutating writes are refused and finalizers
1371    /// are drained before the object is actually removed) — the ONE-
1372    /// liner collapse of the paired `self.metadata.deletion_timestamp
1373    /// .is_some()` incantation every consumer restated by hand
1374    /// pre-lift.
1375    ///
1376    /// Pre-lift the `.metadata.deletion_timestamp.is_some()` chain
1377    /// was hand-authored at TWO sites past the ★★ PRIME-DIRECTIVE
1378    /// ≥ 2 duplication threshold in `tatara-reconciler`, both
1379    /// projecting the SAME tombstone-presence predicate on a
1380    /// `Process` value:
1381    /// * `controller::reconcile` — the top-level dispatcher's
1382    ///   deletion-preempt gate that forces the SIGTERM cascade
1383    ///   (`→ Exiting`) as soon as the API server stamps the
1384    ///   tombstone, before the phase handler for the current
1385    ///   [`ProcessPhase`] gets a chance to run. Composed with
1386    ///   [`ProcessPhase::is_alive`] so the preempt only fires on a
1387    ///   Process still in an alive phase — a Process already in
1388    ///   `Zombie` / `Reaped` / `Failed` runs its normal handler.
1389    /// * `phase_machine::handle_exiting` — the SIGTERM cascade's
1390    ///   child-fan-out loop that enumerates every child Process and
1391    ///   skips ones the API server has already tombstoned (so the
1392    ///   reconciler does not re-issue a `DELETE` against a child
1393    ///   whose deletion the API server is already draining through
1394    ///   its own finalizer). The skip composes with
1395    ///   [`Self::coordinates_or_none`]'s name-required probe so a
1396    ///   child missing either its tombstone-absent gate or its
1397    ///   `metadata.name` slot is a clean `continue` rather than an
1398    ///   attempted `child_api.delete("")` no-op.
1399    ///
1400    /// Both sites walked the SAME `.metadata.deletion_timestamp
1401    /// .is_some()` chain and both wanted the `bool` form the
1402    /// primitive returns — the `controller::reconcile` site to gate
1403    /// the SIGTERM preempt with `&& current_phase.is_alive()` and
1404    /// the `handle_exiting` site to gate the DELETE-skip with a
1405    /// bare `if child.is_being_deleted() { continue; }`. Post-lift
1406    /// each callsite reads `process.is_being_deleted()` and the
1407    /// produced `bool` feeds the same downstream gate unchanged.
1408    ///
1409    /// Return-form axis: `bool` matches the copy-form discipline of
1410    /// [`Self::observed_phase`] (an `Option<Copy>` scalar) — the
1411    /// underlying slot is a wire-format `Option<Time>` that carries
1412    /// only presence information at this axis (the RFC-3339 timestamp
1413    /// payload itself is not what the two consumers read; both only
1414    /// probe presence to detect the tombstone-stamped state).
1415    /// Returning the raw `Option<&Time>` would push the `.is_some()`
1416    /// probe back to every callsite, restating the pre-lift chain
1417    /// one link shorter without collapsing the primitive.
1418    ///
1419    /// Peer to the metadata-fallback primitives
1420    /// [`Self::namespace_or_default`], [`Self::name_or_placeholder`],
1421    /// [`Self::uid_or_empty`], [`Self::coordinates_or_defaults`],
1422    /// [`Self::coordinates_or_none`], [`Self::owned_coordinates_or_err`],
1423    /// [`Self::annotation`] on the metadata axis; this method opens
1424    /// the copy-form peer for the presence-probe corner. Future
1425    /// metadata-presence projections (an `is_being_finalized`
1426    /// projection on `metadata.finalizers.is_empty()`'s negation,
1427    /// a `has_owner` projection on `metadata.owner_references.is_empty()`'s
1428    /// negation) land as peer methods on this same axis.
1429    ///
1430    /// A future normalization step (a per-tombstone staleness gate
1431    /// that returns `false` for a tombstone older than the reconciler's
1432    /// grace-period budget, a canonicalization pass that treats a
1433    /// tombstone from a paused controller as absent, a cross-cluster
1434    /// tombstone-observation clock skew guard) lands at ONE substrate
1435    /// method here and both downstream consumers pick up the upgrade
1436    /// mechanically — no per-callsite hand-edit at
1437    /// `controller::reconcile` / `phase_machine::handle_exiting`.
1438    ///
1439    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1440    /// the `.metadata.deletion_timestamp.is_some()` chain recurred at
1441    /// two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
1442    /// duplication trigger, and is lifted to ONE owner here).
1443    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
1444    /// the pins bind the missing-tombstone corner + the present-
1445    /// tombstone corner + the copy-form `bool` return + the byte-
1446    /// identical parity with the pre-lift `.is_some()` chain, so a
1447    /// regression that drifted any surface at
1448    /// `tests::is_being_deleted_*` rather than as silent operator-
1449    /// facing skew between the top-level dispatcher's SIGTERM
1450    /// preempt and the SIGTERM cascade's child-fan-out DELETE-skip
1451    /// on the SAME `Process` within one reconcile pass).
1452    pub fn is_being_deleted(&self) -> bool {
1453        self.metadata.deletion_timestamp.is_some()
1454    }
1455
1456    /// Copy-form metadata-projection primitive on the
1457    /// `metadata.creationTimestamp` axis: returns the K8s-API-server-
1458    /// assigned creation moment as a `DateTime<Utc>`, hiding the wire-
1459    /// format `k8s_openapi::apimachinery::pkg::apis::meta::v1::Time`
1460    /// newtype behind an inherent projection — the ONE-liner collapse
1461    /// of the paired `self.metadata.creation_timestamp.as_ref().map(|t|
1462    /// t.0)` incantation every timestamp-driven consumer restated by
1463    /// hand pre-lift.
1464    ///
1465    /// Pre-lift the paired `.metadata.creation_timestamp.as_ref()` +
1466    /// `t.0` unwrap chain was hand-authored at THREE sites past the
1467    /// ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold across the
1468    /// workspace, all projecting the SAME creation-moment `DateTime<Utc>`
1469    /// on a `Process`:
1470    /// * `tatara-process::lifetime_clock::evaluate` — TTL-expiry gate
1471    ///   in the ephemeral-lifetime decision (`elapsed = now
1472    ///   .signed_duration_since(creation.0)`), inside the non-terminal-
1473    ///   phase guard that fires the `AutoTerminate::Now { TtlExpired }`
1474    ///   branch. Pre-lift the site read `if let Some(creation) = process
1475    ///   .metadata.creation_timestamp.as_ref() { ... creation.0 ... }`.
1476    /// * `tatara-process::lifetime_clock::requeue_with_ttl` — sleep-
1477    ///   budget picker for the reconciler's next requeue, choosing the
1478    ///   smaller of HEARTBEAT and TTL-remaining so the reconciler
1479    ///   doesn't oversleep past a TTL boundary. Pre-lift the site read
1480    ///   `let Some(creation) = process.metadata.creation_timestamp
1481    ///   .as_ref() else { return default; };` + `creation.0`.
1482    /// * `tatara-reconciler::table_controller::reconcile_process_table`
1483    ///   — stable-name claim-arbiter row builder, seeding each
1484    ///   candidate row's `created_at` for the tie-break ordering
1485    ///   (oldest wins). Pre-lift the site read `p.metadata
1486    ///   .creation_timestamp.as_ref().map(|t| t.0).unwrap_or_else(Utc
1487    ///   ::now)`.
1488    ///
1489    /// All THREE sites walked the SAME two-link chain — read the
1490    /// `Option<Time>` slot as a borrow, then unwrap the `Time` newtype
1491    /// to its inner `DateTime<Utc>` — differing only in the tail
1492    /// (`if-let-Some` guard, `let-else` short-circuit, `Utc::now`
1493    /// fallback). Post-lift each callsite reads
1494    /// `process.created_at()` and applies its own tail at its own site
1495    /// (`if let Some(creation) = ...`, `let Some(creation) = ... else`,
1496    /// `.unwrap_or_else(Utc::now)`).
1497    ///
1498    /// Return-form axis: `Option<DateTime<Utc>>` matches the copy-form
1499    /// discipline of the sibling status-projection primitive
1500    /// [`Self::observed_phase`] — both return `Option<T>` where `T:
1501    /// Copy` and hide the wire-format wrapper (`ProcessStatus` on the
1502    /// status side; `Time` on the metadata side). Returning the raw
1503    /// `Option<&Time>` would push the `.0` unwrap back to every
1504    /// callsite, restating the pre-lift chain one link shorter without
1505    /// collapsing the primitive; returning owned `Option<Time>` would
1506    /// force a `Time` import at every consumer for a projection every
1507    /// consumer immediately discards past `.0`.
1508    ///
1509    /// Peer to the metadata-fallback + presence-probe primitives
1510    /// [`Self::namespace_or_default`], [`Self::name_or_placeholder`],
1511    /// [`Self::uid_or_empty`], [`Self::coordinates_or_defaults`],
1512    /// [`Self::coordinates_or_none`], [`Self::owned_coordinates_or_err`],
1513    /// [`Self::annotation`], [`Self::is_being_deleted`] on the metadata
1514    /// axis; this method opens the copy-form timestamp corner. Future
1515    /// metadata-timestamp projections (a
1516    /// `deletion_at() -> Option<DateTime<Utc>>` peer on the
1517    /// tombstone-payload axis for staleness gates that need the
1518    /// timestamp value alongside the presence bit) land as peer
1519    /// methods on this same axis.
1520    ///
1521    /// A future normalization step (a per-cluster clock-skew guard
1522    /// that offsets the returned timestamp by the observing controller's
1523    /// measured skew, a canonicalization pass that maps a suspiciously-
1524    /// zero creation moment to `None`, a per-namespace override that
1525    /// substitutes a `spec.identity`-declared creation anchor for the
1526    /// metadata slot on adopted resources) lands at ONE substrate
1527    /// method here and all three downstream consumers pick up the
1528    /// upgrade mechanically — no per-callsite hand-edit at `evaluate`
1529    /// / `requeue_with_ttl` / `reconcile_process_table`.
1530    ///
1531    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1532    /// the `.metadata.creation_timestamp.as_ref().map(|t| t.0)` chain
1533    /// recurred at three hand-authored sites past the ★★
1534    /// PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
1535    /// owner here). THEORY.md §II.1 invariant 5 (composition preserves
1536    /// proofs — the pins bind the missing-timestamp corner + the
1537    /// present-timestamp corner + the copy-form `DateTime<Utc>` return
1538    /// + the byte-identical parity with the pre-lift `.as_ref().map(|t|
1539    /// t.0)` chain, so a regression that drifted any surface at
1540    /// `tests::created_at_*` rather than as silent operator-facing
1541    /// skew between the TTL-expiry gate, the requeue-budget picker,
1542    /// and the stable-name claim-arbiter tie-break on the SAME
1543    /// `Process` within one reconcile pass).
1544    pub fn created_at(&self) -> Option<DateTime<Utc>> {
1545        self.metadata.creation_timestamp.as_ref().map(|t| t.0)
1546    }
1547}
1548
1549/// Process status — every field optional until the reconciler writes it.
1550#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)]
1551#[serde(rename_all = "camelCase")]
1552pub struct ProcessStatus {
1553    /// Hierarchical PID path — e.g., `"seph.1.7"`.
1554    #[serde(default, skip_serializing_if = "Option::is_none")]
1555    pub pid: Option<String>,
1556
1557    /// Parent PID path (mirror of `spec.identity.parent`, resolved at fork).
1558    #[serde(default, skip_serializing_if = "Option::is_none")]
1559    pub parent: Option<String>,
1560
1561    /// Direct children's PID paths.
1562    #[serde(default)]
1563    pub children: Vec<String>,
1564
1565    /// Resolved identity (name + content hash).
1566    #[serde(default, skip_serializing_if = "Option::is_none")]
1567    pub identity: Option<Identity>,
1568
1569    /// Current phase.
1570    #[serde(default)]
1571    pub phase: ProcessPhase,
1572
1573    /// When the process entered the current phase.
1574    #[serde(default, skip_serializing_if = "Option::is_none")]
1575    pub phase_since: Option<DateTime<Utc>>,
1576
1577    /// Three-pillar attestation (written at end of every successful cycle).
1578    #[serde(default, skip_serializing_if = "Option::is_none")]
1579    pub attestation: Option<ProcessAttestation>,
1580
1581    /// FluxCD resources currently owned by this Process.
1582    #[serde(default)]
1583    pub flux_resources: Vec<FluxResourceRef>,
1584
1585    /// Boundary verification state.
1586    #[serde(default)]
1587    pub boundary: BoundaryStatus,
1588
1589    /// Compliance summary at the latest attestation.
1590    #[serde(default)]
1591    pub compliance: ComplianceStatus,
1592
1593    /// Pending signals (delivered, not yet handled).
1594    #[serde(default)]
1595    pub signal_queue: Vec<ProcessSignal>,
1596
1597    /// Standard K8s Conditions.
1598    #[serde(default)]
1599    pub conditions: Vec<ProcessCondition>,
1600
1601    /// Human-readable last status message.
1602    #[serde(default, skip_serializing_if = "Option::is_none")]
1603    pub message: Option<String>,
1604
1605    /// Exit code (only set on Failed / Reaped).
1606    #[serde(default, skip_serializing_if = "Option::is_none")]
1607    pub exit_code: Option<i32>,
1608}
1609
1610#[cfg(test)]
1611mod tests {
1612    use super::*;
1613    use crate::classification::{ConvergencePointType, SubstrateType};
1614    use crate::intent::NixIntent;
1615
1616    #[test]
1617    fn minimal_spec_serializes() {
1618        let spec = ProcessSpec {
1619            identity: IdentitySpec::default(),
1620            classification: Classification {
1621                point_type: ConvergencePointType::Gate,
1622                substrate: SubstrateType::Observability,
1623                horizon: Default::default(),
1624                calm: Default::default(),
1625                data_classification: Default::default(),
1626            },
1627            intent: Intent {
1628                nix: Some(NixIntent {
1629                    flake_ref: "github:pleme-io/k8s".into(),
1630                    attribute: "obs".into(),
1631                    system: None,
1632                    attic_cache: None,
1633                    extra_args: vec![],
1634                    delegate_to_nix_build: false,
1635                }),
1636                ..Intent::default()
1637            },
1638            boundary: Default::default(),
1639            compliance: Default::default(),
1640            depends_on: vec![],
1641            signals: Default::default(),
1642            lifetime: Default::default(),
1643            routing: None,
1644            encapsulates: None,
1645            suspended: false,
1646        };
1647        let yaml = serde_yaml::to_string(&spec).unwrap();
1648        assert!(yaml.contains("pointType: Gate"));
1649        assert!(yaml.contains("substrate: Observability"));
1650        assert!(yaml.contains("flakeRef: github:pleme-io/k8s"));
1651    }
1652
1653    // ─── Process::coordinates_or_defaults substrate pins ────────────────
1654    //
1655    // Pins the (namespace, name) coordinate-primitive family on the
1656    // (metadata slot × fallback shape) axis. Fail-before-pass-after
1657    // granularity: a regression that flipped either fallback string,
1658    // swapped the return-tuple axis order, or dropped the
1659    // `Option::as_deref` unwrap surfaces here rather than as silent
1660    // drift at every downstream annotation writer / claim-arbiter row
1661    // builder / render owner-metadata seed.
1662
1663    fn empty_spec() -> ProcessSpec {
1664        ProcessSpec {
1665            identity: IdentitySpec::default(),
1666            classification: Classification {
1667                point_type: ConvergencePointType::Gate,
1668                substrate: SubstrateType::Compute,
1669                horizon: Default::default(),
1670                calm: Default::default(),
1671                data_classification: Default::default(),
1672            },
1673            intent: Intent::default(),
1674            boundary: Default::default(),
1675            compliance: Default::default(),
1676            depends_on: vec![],
1677            signals: Default::default(),
1678            lifetime: Default::default(),
1679            routing: None,
1680            encapsulates: None,
1681            suspended: false,
1682        }
1683    }
1684
1685    #[test]
1686    fn default_namespace_constant_is_k8s_canonical_default() {
1687        // Pins the load-bearing convention that this primitive's
1688        // namespace fallback matches K8s's own implicit-namespace
1689        // spelling. A regression that renamed this to "kube-system"
1690        // or any other K8s-reserved name would silently misroute
1691        // every downstream namespaced-Api call on a Process without
1692        // a metadata.namespace.
1693        assert_eq!(Process::DEFAULT_NAMESPACE, "default");
1694    }
1695
1696    #[test]
1697    fn unnamed_placeholder_constant_matches_prior_annotation_writer_fallback() {
1698        // Pins the load-bearing convention that this primitive's name
1699        // fallback matches the exact spelling every annotation writer
1700        // (tatara-reconciler::ssapply::inject_annotations,
1701        // tatara-reconciler::render::render, and
1702        // tatara-reconciler::table_controller's claim-row builder)
1703        // was hand-authoring pre-lift ("unnamed", NOT "<unnamed>" or
1704        // ""). A regression that renamed this would break the
1705        // annotation-writer / claim-arbiter grep contract silently.
1706        assert_eq!(Process::UNNAMED_PLACEHOLDER, "unnamed");
1707    }
1708
1709    #[test]
1710    fn namespace_or_default_falls_back_when_metadata_namespace_is_none() {
1711        let mut p = Process::new("some-proc", empty_spec());
1712        p.metadata.namespace = None;
1713        assert_eq!(p.namespace_or_default(), Process::DEFAULT_NAMESPACE);
1714    }
1715
1716    #[test]
1717    fn namespace_or_default_returns_metadata_slice_when_some() {
1718        let mut p = Process::new("some-proc", empty_spec());
1719        p.metadata.namespace = Some("prod-app".into());
1720        assert_eq!(p.namespace_or_default(), "prod-app");
1721    }
1722
1723    #[test]
1724    fn name_or_placeholder_falls_back_when_metadata_name_is_none() {
1725        let mut p = Process::new("real-name", empty_spec());
1726        p.metadata.name = None;
1727        assert_eq!(p.name_or_placeholder(), Process::UNNAMED_PLACEHOLDER);
1728    }
1729
1730    #[test]
1731    fn name_or_placeholder_returns_metadata_slice_when_some() {
1732        let p = Process::new("api-gateway", empty_spec());
1733        assert_eq!(p.name_or_placeholder(), "api-gateway");
1734    }
1735
1736    #[test]
1737    fn coordinates_or_defaults_composes_both_halves() {
1738        // Both slots present — returns metadata slices in
1739        // (namespace, name) axis order.
1740        let mut p = Process::new("api", empty_spec());
1741        p.metadata.namespace = Some("staging".into());
1742        assert_eq!(p.coordinates_or_defaults(), ("staging", "api"));
1743    }
1744
1745    #[test]
1746    fn coordinates_or_defaults_falls_back_on_both_slots() {
1747        // Both slots None — returns (DEFAULT_NAMESPACE,
1748        // UNNAMED_PLACEHOLDER) in axis order.
1749        let mut p = Process::new("scratch", empty_spec());
1750        p.metadata.name = None;
1751        p.metadata.namespace = None;
1752        assert_eq!(
1753            p.coordinates_or_defaults(),
1754            (Process::DEFAULT_NAMESPACE, Process::UNNAMED_PLACEHOLDER)
1755        );
1756    }
1757
1758    #[test]
1759    fn coordinates_or_defaults_mixes_slotted_and_fallback_halves() {
1760        // Namespace set, name missing — the (namespace, name) tuple
1761        // pins each half independently. A regression that returned
1762        // BOTH fallbacks when EITHER metadata slot was None would
1763        // surface here rather than at every downstream reader.
1764        let mut p = Process::new("kept-name", empty_spec());
1765        p.metadata.namespace = Some("prod".into());
1766        assert_eq!(p.coordinates_or_defaults(), ("prod", "kept-name"));
1767
1768        // Name set, namespace missing — the peer corner.
1769        let mut q = Process::new("api", empty_spec());
1770        q.metadata.namespace = None;
1771        assert_eq!(
1772            q.coordinates_or_defaults(),
1773            (Process::DEFAULT_NAMESPACE, "api")
1774        );
1775    }
1776
1777    // ─── Process::qualified_ref substrate pins ─────────────────────────
1778    //
1779    // Pins the paired-projection + shape-composer chain
1780    // `coordinates_or_defaults() → qualified_process_ref(ns, name)` on
1781    // the (return-form × composition-depth) axis pair. Fail-before-
1782    // pass-after granularity: a regression that swapped the `<ns>/<name>`
1783    // axis order, dropped either half, drifted the fallback strings
1784    // between the paired-projection primitive and the shape composer, or
1785    // inserted a normalization step at only the composed site and not
1786    // the pair-returning primitive (or vice versa) surfaces here rather
1787    // than as silent operator-visible skew across the three pre-lift
1788    // `tatara-reconciler` sites (`render::render_routing`,
1789    // `render::render_export_jobs`, `table_controller::reconcile`)
1790    // whose downstream greps the reference shape verbatim (the
1791    // `PROCESS=<ref>` annotation seed on every emitted Ingress /
1792    // DNSEndpoint / export Job, the `ClaimRecord.holder` slot on the
1793    // stable-name claim registry).
1794
1795    #[test]
1796    fn qualified_ref_composes_ns_and_name_with_slash_when_both_slots_present() {
1797        // Happy path — both metadata slots populated. The composed
1798        // reference is EXACTLY `<ns>/<name>`, in that order, joined by
1799        // a single `/`. A regression that swapped the two axes at
1800        // this primitive would silently break every downstream
1801        // `PROCESS=<ref>` annotation grep + claim-registry lookup.
1802        let mut p = Process::new("api-gateway", empty_spec());
1803        p.metadata.namespace = Some("prod-app".into());
1804        assert_eq!(p.qualified_ref(), "prod-app/api-gateway");
1805    }
1806
1807    #[test]
1808    fn qualified_ref_falls_back_to_default_namespace_when_metadata_namespace_is_none() {
1809        // Namespace-fallback pin: an absent `metadata.namespace` rides
1810        // through `namespace_or_default()` → `DEFAULT_NAMESPACE`, so
1811        // the composed reference lands as `default/<name>`. Matches
1812        // what a pre-lift `qualified_process_ref(process.
1813        // coordinates_or_defaults())` composition produced.
1814        let mut p = Process::new("api-gateway", empty_spec());
1815        p.metadata.namespace = None;
1816        assert_eq!(p.qualified_ref(), "default/api-gateway");
1817    }
1818
1819    #[test]
1820    fn qualified_ref_falls_back_to_unnamed_placeholder_when_metadata_name_is_none() {
1821        // Name-fallback pin: an absent `metadata.name` rides through
1822        // `name_or_placeholder()` → `UNNAMED_PLACEHOLDER`, so the
1823        // composed reference lands as `<ns>/unnamed`. A pre-lift
1824        // consumer whose paired projection returned the placeholder
1825        // (annotation writer, render owner-metadata seed) sees the
1826        // exact same `<ns>/unnamed` shape post-lift, so downstream
1827        // greps keyed on the pre-metadata Process's reference match
1828        // bytewise.
1829        let mut p = Process::new("ignored", empty_spec());
1830        p.metadata.namespace = Some("staging".into());
1831        p.metadata.name = None;
1832        assert_eq!(p.qualified_ref(), "staging/unnamed");
1833    }
1834
1835    #[test]
1836    fn qualified_ref_falls_back_on_both_slots_when_both_metadata_are_none() {
1837        // Both slots absent → both fallbacks land in the composed
1838        // reference. The `default/unnamed` shape is what every pre-
1839        // lift caller produced when a Process fixture (test or
1840        // dynamic API response) surfaced without populated metadata;
1841        // pinning it here holds the primitive's contract against a
1842        // regression that dropped either fallback at only the
1843        // composed site.
1844        let mut p = Process::new("ignored", empty_spec());
1845        p.metadata.namespace = None;
1846        p.metadata.name = None;
1847        assert_eq!(
1848            p.qualified_ref(),
1849            format!(
1850                "{}/{}",
1851                Process::DEFAULT_NAMESPACE,
1852                Process::UNNAMED_PLACEHOLDER
1853            )
1854        );
1855    }
1856
1857    #[test]
1858    fn qualified_ref_matches_pre_lift_paired_composition_bytewise() {
1859        // Byte-identical parity with the exact pre-lift 2-step
1860        // composition every `tatara-reconciler` site hand-authored:
1861        // `let (ns, name) = process.coordinates_or_defaults(); let r
1862        // = qualified_process_ref(ns, name);`. Sweeps every metadata-
1863        // slot combination the three pre-lift consumers plausibly
1864        // encountered — both slots populated (steady state), one
1865        // slot absent (Process mid-fork before API-server metadata
1866        // stamp), both slots absent (dynamic API response / test
1867        // fixture) — so a regression that reshaped the composition at
1868        // the substrate primitive would surface here rather than as
1869        // silent drift at the three consumer sites.
1870        let fixtures: [(Option<&str>, Option<&str>); 4] = [
1871            (Some("prod-app"), Some("api-gateway")),
1872            (None, Some("api-gateway")),
1873            (Some("staging"), None),
1874            (None, None),
1875        ];
1876        for (ns_slot, name_slot) in fixtures {
1877            let mut p = Process::new(name_slot.unwrap_or("seed"), empty_spec());
1878            p.metadata.namespace = ns_slot.map(str::to_string);
1879            p.metadata.name = name_slot.map(str::to_string);
1880            let via_primitive = p.qualified_ref();
1881            let (ns, name) = p.coordinates_or_defaults();
1882            let via_paired = crate::qualified_process_ref(ns, name);
1883            assert_eq!(
1884                via_primitive, via_paired,
1885                "qualified_ref must be byte-identical to the pre-lift \
1886                 paired composition on (ns={ns_slot:?}, name={name_slot:?})"
1887            );
1888        }
1889    }
1890
1891    #[test]
1892    fn qualified_ref_composes_from_the_shared_coordinates_or_defaults_owner() {
1893        // Composition invariant: the composed reference decomposes at
1894        // the single `/` separator into EXACTLY the (ns, name) pair
1895        // `coordinates_or_defaults` returns. A regression that
1896        // introduced a per-callsite normalization at the shape
1897        // composer (URL-escape, case-fold, path-normalize) or that
1898        // pulled the pair from a different metadata source than the
1899        // paired-projection primitive would surface here rather than
1900        // at every downstream reference-shape grep.
1901        let mut p = Process::new("api-gateway", empty_spec());
1902        p.metadata.namespace = Some("prod-app".into());
1903        let composed = p.qualified_ref();
1904        let (ns, name) = p.coordinates_or_defaults();
1905        let (composed_ns, composed_name) = composed.split_once('/').unwrap();
1906        assert_eq!(composed_ns, ns);
1907        assert_eq!(composed_name, name);
1908    }
1909
1910    // ─── Process::owned_coordinates_or_err substrate pins ──────────────
1911    //
1912    // Pins the owned + name-required peer of the coordinate-primitive
1913    // family on the (return-form × name gate) axis pair. Fail-before-
1914    // pass-after granularity: a regression that flipped the namespace
1915    // fallback string, dropped the `Option::clone` unwrap, changed the
1916    // return-tuple axis order, or altered the "Process has no
1917    // metadata.name" error wording surfaces here rather than as silent
1918    // drift at every pre-lift caller (10 sites in
1919    // `tatara-reconciler::phase_machine` + 2 sites in
1920    // `tatara-reconciler::signals` pre-lift).
1921
1922    #[test]
1923    fn owned_coordinates_or_err_returns_owned_strings_when_both_slots_present() {
1924        // Happy path — both slots populated, method returns owned
1925        // Strings in (namespace, name) axis order.
1926        let mut p = Process::new("api-gateway", empty_spec());
1927        p.metadata.namespace = Some("prod-app".into());
1928        let (ns, name) = p.owned_coordinates_or_err().unwrap();
1929        assert_eq!(ns, "prod-app");
1930        assert_eq!(name, "api-gateway");
1931        // Ownership pin: type inference above binds ns/name as
1932        // owned Strings — a regression that returned &str would
1933        // fail to compile at the following .push() call. This
1934        // holds the "owned" half of the primitive's contract.
1935        let mut owned_ns = ns;
1936        owned_ns.push_str("-mutated");
1937        assert_eq!(owned_ns, "prod-app-mutated");
1938    }
1939
1940    #[test]
1941    fn owned_coordinates_or_err_falls_back_on_namespace_but_returns_owned_name() {
1942        // Namespace absent → DEFAULT_NAMESPACE. Name present → owned.
1943        let p = Process::new("api", empty_spec());
1944        // Process::new leaves metadata.namespace = None by default.
1945        let (ns, name) = p.owned_coordinates_or_err().unwrap();
1946        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
1947        assert_eq!(name, "api");
1948    }
1949
1950    #[test]
1951    fn owned_coordinates_or_err_errors_when_metadata_name_absent_regardless_of_namespace() {
1952        // Name absent → Err, REGARDLESS of whether the namespace is
1953        // populated. The name gate is strictly on `metadata.name` and
1954        // does NOT fall back to `Self::UNNAMED_PLACEHOLDER` (that
1955        // fallback is on the peer `coordinates_or_defaults`, which
1956        // exists precisely for consumers that can tolerate a
1957        // display placeholder).
1958        for ns_slot in [None, Some("prod".to_string())] {
1959            let mut p = Process::new("scratch", empty_spec());
1960            p.metadata.name = None;
1961            p.metadata.namespace = ns_slot.clone();
1962            let err = p.owned_coordinates_or_err().unwrap_err();
1963            assert!(
1964                err.to_string().contains("metadata.name"),
1965                "err on missing name (ns={ns_slot:?}) should mention metadata.name; got {err}"
1966            );
1967        }
1968    }
1969
1970    #[test]
1971    fn owned_coordinates_or_err_error_message_matches_pre_lift_reconciler_wording() {
1972        // Load-bearing wording pin — every pre-lift `tatara-reconciler`
1973        // helper (`phase_machine::namespace_and_name`,
1974        // `signals::ingest`, `signals::consume_effect`) errored with
1975        // EXACTLY this wording. Post-lift the substrate owner produces
1976        // the same wording so log-line / test greps that anchored on
1977        // it keep matching, and no operator-visible message drift
1978        // lands as a side effect of the substrate move.
1979        let mut p = Process::new("scratch", empty_spec());
1980        p.metadata.name = None;
1981        let err = p.owned_coordinates_or_err().unwrap_err();
1982        assert_eq!(err.to_string(), "Process has no metadata.name");
1983    }
1984
1985    #[test]
1986    fn owned_coordinates_or_err_namespace_fallback_matches_default_namespace_const() {
1987        // Byte-identity pin between the owned form's namespace
1988        // fallback and the workspace-wide `DEFAULT_NAMESPACE` const.
1989        // A regression that spelled this fallback as any other
1990        // string ("kube-system", "", "default-ns") would silently
1991        // misroute every downstream namespaced-Api call on a
1992        // Process without a metadata.namespace — surfaces here
1993        // rather than at every kube-rs API caller.
1994        let mut p = Process::new("api", empty_spec());
1995        p.metadata.namespace = None;
1996        let (ns, _) = p.owned_coordinates_or_err().unwrap();
1997        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
1998    }
1999
2000    #[test]
2001    fn owned_coordinates_or_err_matches_pre_lift_reconciler_helper_shape() {
2002        // Byte-identical parity pin between the owned + name-required
2003        // primitive here and the pre-lift `tatara-reconciler` helper
2004        // shape — the exact 2-slot unwrap chain each pre-lift caller
2005        // spelled by hand:
2006        //
2007        //   let ns = p.metadata.namespace.clone().unwrap_or_else(|| "default".into());
2008        //   let name = p.metadata.name.clone().ok_or_else(|| anyhow!(...))?;
2009        //   Ok((ns, name))
2010        //
2011        // Sweeps every corner every callsite plausibly encounters
2012        // (both slots present, namespace absent, name absent, both
2013        // absent). A regression that inserted a normalization step
2014        // at the primitive that the pre-lift chain does NOT apply —
2015        // or vice versa — surfaces here rather than as silent drift
2016        // between the 12 pre-lift consumer callsites and the ONE
2017        // substrate owner they now route through.
2018        fn pre_lift(p: &Process) -> anyhow::Result<(String, String)> {
2019            let ns = p
2020                .metadata
2021                .namespace
2022                .clone()
2023                .unwrap_or_else(|| "default".into());
2024            let name = p
2025                .metadata
2026                .name
2027                .clone()
2028                .ok_or_else(|| anyhow::anyhow!("Process has no metadata.name"))?;
2029            Ok((ns, name))
2030        }
2031        // Both present.
2032        let mut p = Process::new("api", empty_spec());
2033        p.metadata.namespace = Some("prod".into());
2034        assert_eq!(p.owned_coordinates_or_err().unwrap(), pre_lift(&p).unwrap());
2035        // Namespace absent.
2036        let p = Process::new("api", empty_spec());
2037        assert_eq!(p.owned_coordinates_or_err().unwrap(), pre_lift(&p).unwrap());
2038        // Name absent → both variants error with the same wording.
2039        let mut p = Process::new("api", empty_spec());
2040        p.metadata.name = None;
2041        p.metadata.namespace = Some("prod".into());
2042        assert_eq!(
2043            p.owned_coordinates_or_err().unwrap_err().to_string(),
2044            pre_lift(&p).unwrap_err().to_string(),
2045        );
2046        // Both absent → still errors on the name gate.
2047        let mut p = Process::new("api", empty_spec());
2048        p.metadata.name = None;
2049        p.metadata.namespace = None;
2050        assert_eq!(
2051            p.owned_coordinates_or_err().unwrap_err().to_string(),
2052            pre_lift(&p).unwrap_err().to_string(),
2053        );
2054    }
2055
2056    #[test]
2057    fn owned_coordinates_or_err_axis_order_matches_coordinates_or_defaults() {
2058        // Cross-primitive coherence pin between the owned + name-
2059        // required form and the borrow + name-defaulted peer:
2060        // (namespace, name) axis order is IDENTICAL across both
2061        // return-forms. A regression that swapped the tuple slots on
2062        // only ONE of the two primitives would silently misroute
2063        // every consumer that picked between the two forms based on
2064        // its callsite's ownership needs. The pin re-reads both
2065        // primitives at test time so the equality holds iff both
2066        // live paths are the current implementation.
2067        let mut p = Process::new("app", empty_spec());
2068        p.metadata.namespace = Some("infra".into());
2069        let (borrow_ns, borrow_name) = p.coordinates_or_defaults();
2070        let (owned_ns, owned_name) = p.owned_coordinates_or_err().unwrap();
2071        assert_eq!(owned_ns, borrow_ns);
2072        assert_eq!(owned_name, borrow_name);
2073        // Explicit slot labels — pins the (namespace, name) axis
2074        // order as opposed to (name, namespace).
2075        assert_eq!(owned_ns, "infra"); // NOT "app"
2076        assert_eq!(owned_name, "app"); // NOT "infra"
2077    }
2078
2079    // ─── Process::coordinates_or_none substrate pins ──────────────────
2080    //
2081    // Pins the borrow + name-required peer of the coordinate-primitive
2082    // family on the (return-form × name-gate) axis pair. Closes the
2083    // corner previously left open (borrow + name-required) so the
2084    // three consumer shapes (child-Process delete-fan-out at
2085    // `phase_machine::handle_exiting`, claim-arbiter probe at
2086    // `phase_machine::process_holds_any_claim`, any future non-fatal
2087    // skip site) route through ONE primitive rather than three hand-
2088    // authored empty-string / `unwrap_or_default()` sentinel chains.
2089    // Fail-before-pass-after granularity: a regression that flipped
2090    // the namespace fallback, swapped the return-tuple axis order,
2091    // returned an owned form, or promoted a missing name to an error
2092    // rather than `None` surfaces here rather than as silent drift at
2093    // every borrow + name-required consumer.
2094
2095    #[test]
2096    fn coordinates_or_none_returns_slices_when_both_slots_present() {
2097        // Happy path — both slots populated, method returns borrowed
2098        // (&str, &str) in (namespace, name) axis order wrapped in
2099        // `Some`.
2100        let mut p = Process::new("api-gateway", empty_spec());
2101        p.metadata.namespace = Some("prod-app".into());
2102        let (ns, name) = p.coordinates_or_none().expect("Some when name set");
2103        assert_eq!(ns, "prod-app");
2104        assert_eq!(name, "api-gateway");
2105    }
2106
2107    #[test]
2108    fn coordinates_or_none_falls_back_on_namespace_but_returns_name_slice() {
2109        // Namespace absent → DEFAULT_NAMESPACE (shared with the peer
2110        // `coordinates_or_defaults` + `namespace_or_default`). Name
2111        // present → the metadata slice, wrapped in `Some`.
2112        let mut p = Process::new("api", empty_spec());
2113        p.metadata.namespace = None;
2114        let (ns, name) = p.coordinates_or_none().expect("Some when name set");
2115        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
2116        assert_eq!(name, "api");
2117    }
2118
2119    #[test]
2120    fn coordinates_or_none_returns_none_when_metadata_name_absent_regardless_of_namespace() {
2121        // Name absent → `None`, REGARDLESS of whether the namespace
2122        // slot is populated. The name gate is strictly on
2123        // `metadata.name` and does NOT fall back to
2124        // `Self::UNNAMED_PLACEHOLDER` (that fallback is on the peer
2125        // `coordinates_or_defaults`, which exists precisely for
2126        // consumers that tolerate a display placeholder). Peer to
2127        // `owned_coordinates_or_err_errors_when_metadata_name_absent_regardless_of_namespace`
2128        // on the sibling primitive; a regression that widened THIS
2129        // form to substitute the placeholder while leaving the owned
2130        // form strict would silently drift the two borrow-form
2131        // primitives out of the coherence the family carries.
2132        for ns_slot in [None, Some("prod".to_string())] {
2133            let mut p = Process::new("scratch", empty_spec());
2134            p.metadata.name = None;
2135            p.metadata.namespace = ns_slot.clone();
2136            assert!(
2137                p.coordinates_or_none().is_none(),
2138                "coordinates_or_none must be None on missing name (ns={ns_slot:?})",
2139            );
2140        }
2141    }
2142
2143    #[test]
2144    fn coordinates_or_none_namespace_fallback_matches_default_namespace_const() {
2145        // Byte-identity pin between the borrow + name-required form's
2146        // namespace fallback and the workspace-wide `DEFAULT_NAMESPACE`
2147        // const. Sibling to
2148        // `owned_coordinates_or_err_namespace_fallback_matches_default_namespace_const`
2149        // on the peer primitive — the two forms MUST substitute the
2150        // same fallback string, else a consumer that switches between
2151        // them based on its ownership need silently observes a
2152        // different namespace-fallback shape as a side effect.
2153        let mut p = Process::new("api", empty_spec());
2154        p.metadata.namespace = None;
2155        let (ns, _) = p.coordinates_or_none().unwrap();
2156        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
2157    }
2158
2159    #[test]
2160    fn coordinates_or_none_axis_order_matches_coordinates_or_defaults_when_name_present() {
2161        // Cross-primitive coherence pin between the two borrow-form
2162        // primitives: when the name is present, the (namespace, name)
2163        // return-tuple axis order is IDENTICAL across the two forms,
2164        // and the returned slices are the SAME `&str` view onto the
2165        // same metadata slots. A regression that swapped the tuple
2166        // slots on ONE form would silently misroute every consumer
2167        // that picked between the two forms based on its name-gate
2168        // need. The pin re-reads both primitives at test time so the
2169        // equality holds iff both live paths are the current
2170        // implementation.
2171        let mut p = Process::new("app", empty_spec());
2172        p.metadata.namespace = Some("infra".into());
2173        let (defaulted_ns, defaulted_name) = p.coordinates_or_defaults();
2174        let (required_ns, required_name) = p.coordinates_or_none().unwrap();
2175        assert_eq!(defaulted_ns, required_ns);
2176        assert_eq!(defaulted_name, required_name);
2177        // Explicit slot labels — pins the (namespace, name) axis order
2178        // as opposed to (name, namespace).
2179        assert_eq!(required_ns, "infra"); // NOT "app"
2180        assert_eq!(required_name, "app"); // NOT "infra"
2181    }
2182
2183    #[test]
2184    fn coordinates_or_none_axis_pair_diverges_from_coordinates_or_defaults_on_missing_name() {
2185        // Divergence pin between the two borrow-form primitives when
2186        // the name gate fires: `coordinates_or_defaults` substitutes
2187        // the display placeholder AND still returns a tuple;
2188        // `coordinates_or_none` returns `None`. A regression that
2189        // collapsed the two behaviors (either by dropping the gate
2190        // from the required form or by adding a `None` corner to the
2191        // defaulted form) would blur the axis pair's whole reason to
2192        // exist as two peer primitives.
2193        let mut p = Process::new("scratch", empty_spec());
2194        p.metadata.name = None;
2195        p.metadata.namespace = Some("prod".into());
2196        // Defaulted form: substitutes placeholder, no gate.
2197        assert_eq!(
2198            p.coordinates_or_defaults(),
2199            ("prod", Process::UNNAMED_PLACEHOLDER)
2200        );
2201        // Required form: gate fires, `None`.
2202        assert!(p.coordinates_or_none().is_none());
2203    }
2204
2205    #[test]
2206    fn coordinates_or_none_matches_pre_lift_reconciler_helper_shape() {
2207        // Byte-identical parity pin between the borrow + name-required
2208        // primitive here and the pre-lift `tatara-reconciler` helper
2209        // shapes — the exact 2-slot unwrap + gate chains each pre-lift
2210        // caller spelled by hand (`phase_machine::process_holds_any_claim`
2211        // spelled it as `unwrap_or("")` + `is_empty` early-return;
2212        // `phase_machine::handle_exiting`'s child-fan-out spelled it
2213        // as `unwrap_or_default()` + implicit no-op delete on the
2214        // empty API-path). Sweeps every corner every callsite plausibly
2215        // encounters (both slots present, namespace absent, name
2216        // absent + ns present, both absent). A regression that
2217        // inserted a normalization step at the primitive the pre-lift
2218        // chain does NOT apply — or vice versa — surfaces here rather
2219        // than as silent drift between the pre-lift consumer sites
2220        // and the ONE substrate owner they now route through.
2221        fn pre_lift_holds_any_claim(p: &Process) -> Option<(&str, &str)> {
2222            let ns = p.metadata.namespace.as_deref().unwrap_or("default");
2223            let name = p.metadata.name.as_deref().unwrap_or("");
2224            if name.is_empty() {
2225                return None;
2226            }
2227            Some((ns, name))
2228        }
2229        // Both present.
2230        let mut p = Process::new("api", empty_spec());
2231        p.metadata.namespace = Some("prod".into());
2232        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2233        // Namespace absent.
2234        let p = Process::new("api", empty_spec());
2235        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2236        // Name absent → both variants return `None` regardless of ns.
2237        let mut p = Process::new("api", empty_spec());
2238        p.metadata.name = None;
2239        p.metadata.namespace = Some("prod".into());
2240        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2241        // Both absent → still `None` on the name gate.
2242        let mut p = Process::new("api", empty_spec());
2243        p.metadata.name = None;
2244        p.metadata.namespace = None;
2245        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2246    }
2247
2248    #[test]
2249    fn coordinates_or_none_axis_order_matches_owned_coordinates_or_err_on_happy_path() {
2250        // Cross-primitive coherence pin at the sibling corner: when
2251        // BOTH slots are present, the borrow + name-required form
2252        // (this method) and the owned + name-required peer
2253        // (`owned_coordinates_or_err`) return the SAME `(ns, name)`
2254        // pair — the axis order is IDENTICAL and neither primitive
2255        // silently applies a normalization the other omits. A
2256        // regression that skewed one form's normalization would
2257        // surface here rather than as silent drift between the two
2258        // name-required corners of the primitive family.
2259        let mut p = Process::new("app", empty_spec());
2260        p.metadata.namespace = Some("infra".into());
2261        let (borrow_ns, borrow_name) = p.coordinates_or_none().unwrap();
2262        let (owned_ns, owned_name) = p.owned_coordinates_or_err().unwrap();
2263        assert_eq!(borrow_ns, owned_ns.as_str());
2264        assert_eq!(borrow_name, owned_name.as_str());
2265    }
2266
2267    #[test]
2268    fn coordinates_or_defaults_axis_order_matches_qualified_process_ref() {
2269        // Pins the load-bearing convention that the return-tuple
2270        // axis order is (namespace, name) — the exact positional
2271        // argument order the substrate's paired-composer primitive
2272        // `tatara_reconciler::ssapply::qualified_process_ref(ns,
2273        // name)` consumes. A regression that swapped the tuple
2274        // slots would silently misroute every annotation writer /
2275        // claim-arbiter row / owner-metadata seed built by feeding
2276        // this pair into the composer — every downstream `<ns>/
2277        // <name>` grep would suddenly see `<name>/<ns>`. The test
2278        // verifies the tuple's first slot is what a hand-authored
2279        // `.metadata.namespace.as_deref()...` produced pre-lift, and
2280        // the second slot is what `.metadata.name.as_deref()...`
2281        // produced.
2282        let mut p = Process::new("app", empty_spec());
2283        p.metadata.namespace = Some("infra".into());
2284        let (ns, name) = p.coordinates_or_defaults();
2285        assert_eq!(ns, "infra"); // NOT "app"
2286        assert_eq!(name, "app"); // NOT "infra"
2287    }
2288
2289    // ─── Process::annotation substrate pins ────────────────────────────
2290    //
2291    // Pins the borrow-form annotation-lookup primitive that owns the
2292    // 3-line `.metadata.annotations.as_ref().and_then(|m| m.get(KEY))`
2293    // chain three hand-authored sites restated by hand pre-lift:
2294    // `tatara-reconciler::signals::ingest` (SIGNAL),
2295    // `tatara-reconciler::phase_machine::released_from_annotation`
2296    // (RELEASED_FROM), and
2297    // `tatara-pool-reconciler::controller_pool::process_belongs_to_pool`
2298    // (POOL). Fail-before-pass-after granularity: a regression that
2299    // widened the missing-`annotations` corner (returning `Some("")`
2300    // instead of `None`), promoted a missing key to an error, dropped
2301    // the borrow-form return, or changed the two swallowed corners'
2302    // shared collapse to `None` surfaces here rather than as silent
2303    // drift at the three consumer sites.
2304    fn process_with_annotation(key: &str, value: &str) -> Process {
2305        let mut p = Process::new("some-proc", empty_spec());
2306        let mut anns = std::collections::BTreeMap::new();
2307        anns.insert(key.to_string(), value.to_string());
2308        p.metadata.annotations = Some(anns);
2309        p
2310    }
2311
2312    #[test]
2313    fn annotation_returns_none_when_metadata_annotations_is_none() {
2314        // Missing-`annotations` corner: a Process with no annotations
2315        // block at all returns `None` for every key. Peer to
2316        // `observed_flux_resources_returns_empty_slice_when_status_is_none`
2317        // on the status-projection axis; both primitives collapse the
2318        // outer `Option` corner rather than requiring each consumer
2319        // to spell the guard by hand.
2320        let mut p = Process::new("scratch", empty_spec());
2321        p.metadata.annotations = None;
2322        assert!(p.annotation("tatara.pleme.io/signal").is_none());
2323        assert!(p.annotation("tatara.pleme.io/pool").is_none());
2324        assert!(p.annotation("").is_none());
2325    }
2326
2327    #[test]
2328    fn annotation_returns_none_when_key_absent_from_populated_map() {
2329        // Missing-key corner: annotations block populated with OTHER
2330        // keys returns `None` for the queried key. Symmetric with the
2331        // missing-`annotations` corner — both corners collapse to the
2332        // same `None`, matching the pre-lift `.and_then(...)`
2333        // behavior every consumer relied on.
2334        let p = process_with_annotation("tatara.pleme.io/other", "value");
2335        assert!(p.annotation("tatara.pleme.io/signal").is_none());
2336        assert!(p.annotation("").is_none());
2337    }
2338
2339    #[test]
2340    fn annotation_returns_borrowed_slice_when_key_present() {
2341        // Happy path: annotations block populated + key present →
2342        // `Some(&str)` borrowed from the underlying `String` in the
2343        // map. A regression that returned an owned `String` (defeating
2344        // the primitive's role as a zero-copy projection) would
2345        // surface at the lifetime of the returned reference — the
2346        // `&str` outlives the borrow of `&p` here.
2347        let p = process_with_annotation("tatara.pleme.io/signal", "SIGHUP");
2348        assert_eq!(p.annotation("tatara.pleme.io/signal"), Some("SIGHUP"));
2349    }
2350
2351    #[test]
2352    fn annotation_returns_borrowed_empty_string_slice_when_value_is_empty() {
2353        // Edge corner between the missing-key `None` and the present-
2354        // key `Some("")` — a Process whose annotation is EXPLICITLY
2355        // set to an empty string returns `Some("")`, NOT `None`. A
2356        // regression that normalized the empty-string value to `None`
2357        // (a plausible "defensive" simplification) would silently
2358        // reshape the corner every callsite pre-lift kept distinct via
2359        // `.cloned().unwrap_or_default()` (which collapses BOTH to
2360        // `""`) or `.map(String::as_str)` (which keeps them distinct
2361        // as `None` vs `Some("")`).
2362        let p = process_with_annotation("tatara.pleme.io/signal", "");
2363        assert_eq!(p.annotation("tatara.pleme.io/signal"), Some(""));
2364    }
2365
2366    #[test]
2367    fn annotation_is_a_pure_projection() {
2368        // Purity pin — repeated calls return equal results and the
2369        // primitive does not mutate `self`. Peer to
2370        // `observed_flux_resources_is_a_pure_projection` on the
2371        // status-projection axis.
2372        let p = process_with_annotation("tatara.pleme.io/released-from", "Attested");
2373        let a = p.annotation("tatara.pleme.io/released-from");
2374        let b = p.annotation("tatara.pleme.io/released-from");
2375        assert_eq!(a, b);
2376        assert_eq!(a, Some("Attested"));
2377    }
2378
2379    #[test]
2380    fn annotation_matches_pre_lift_reconciler_chain_shape() {
2381        // Byte-identical parity pin between the borrow-form primitive
2382        // here and the pre-lift `tatara-reconciler` / `tatara-pool-
2383        // reconciler` chain shape — the exact 3-line
2384        // `.metadata.annotations.as_ref().and_then(|m| m.get(KEY))
2385        // .map(String::as_str)` incantation each pre-lift caller
2386        // spelled by hand (three variants of tail collapsed onto ONE
2387        // borrow-form primitive here; each caller reapplies its own
2388        // tail at its own site). Sweeps every corner (missing
2389        // annotations map, missing key, present key with value,
2390        // present key with empty value) so a regression that inserted
2391        // a normalization at the primitive the pre-lift chain does
2392        // NOT apply — or vice versa — surfaces here rather than as
2393        // silent drift between the ONE substrate owner and the three
2394        // consumer sites.
2395        fn pre_lift<'a>(p: &'a Process, key: &str) -> Option<&'a str> {
2396            p.metadata
2397                .annotations
2398                .as_ref()
2399                .and_then(|m| m.get(key))
2400                .map(String::as_str)
2401        }
2402        // Missing annotations map.
2403        let mut p = Process::new("x", empty_spec());
2404        p.metadata.annotations = None;
2405        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
2406        // Missing key in populated map.
2407        let p = process_with_annotation("other", "v");
2408        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
2409        // Present key with non-empty value.
2410        let p = process_with_annotation("k", "v");
2411        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
2412        // Present key with explicitly-empty value — the corner
2413        // `.cloned().unwrap_or_default()` collapses to `""` post-tail
2414        // but the primitive-level shape stays `Some("")`.
2415        let p = process_with_annotation("k", "");
2416        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
2417    }
2418
2419    #[test]
2420    fn annotation_composes_owned_tail_matching_pre_lift_signals_ingest() {
2421        // Pins the exact tail shape `tatara-reconciler::signals::
2422        // ingest` composed pre-lift: an `Option<String>` for the
2423        // downstream `let Some(raw) = raw else { ... }` guard.
2424        // Post-lift the callsite composes `.map(str::to_string)` at
2425        // its own site; this test pins the composition matches the
2426        // pre-lift `.cloned()` tail byte-for-byte on both corners the
2427        // consumer's downstream distinguishes (annotation present →
2428        // `Some(String)`; absent → `None`).
2429        let p = process_with_annotation("tatara.pleme.io/signal", "SIGUSR1");
2430        assert_eq!(
2431            p.annotation("tatara.pleme.io/signal").map(str::to_string),
2432            Some("SIGUSR1".to_string())
2433        );
2434        let mut q = Process::new("y", empty_spec());
2435        q.metadata.annotations = None;
2436        assert_eq!(
2437            q.annotation("tatara.pleme.io/signal").map(str::to_string),
2438            None
2439        );
2440    }
2441
2442    #[test]
2443    fn annotation_composes_default_tail_matching_pre_lift_released_from() {
2444        // Pins the exact tail shape
2445        // `tatara-reconciler::phase_machine::released_from_annotation`
2446        // composed pre-lift: a bare `String` via `.cloned()
2447        // .unwrap_or_default()` for the downstream
2448        // `match v.as_str()` dispatch. Post-lift the callsite matches
2449        // directly on `Option<&str>` (Some("Failed") vs _); this test
2450        // pins that the borrow-form primitive plus the `.unwrap_or("")`
2451        // fallback reproduces the pre-lift bare-string shape on both
2452        // corners.
2453        let p = process_with_annotation("tatara.pleme.io/released-from", "Failed");
2454        assert_eq!(
2455            p.annotation("tatara.pleme.io/released-from").unwrap_or(""),
2456            "Failed"
2457        );
2458        let mut q = Process::new("y", empty_spec());
2459        q.metadata.annotations = None;
2460        assert_eq!(
2461            q.annotation("tatara.pleme.io/released-from").unwrap_or(""),
2462            ""
2463        );
2464    }
2465
2466    #[test]
2467    fn annotation_composes_borrow_equality_tail_matching_pre_lift_pool() {
2468        // Pins the exact tail shape `tatara-pool-reconciler::
2469        // controller_pool::process_belongs_to_pool` composed pre-lift:
2470        // an `Option<&str>` compared with `== Some(pool_name)` for the
2471        // membership gate. Post-lift the callsite composes
2472        // `p.annotation(POOL) == Some(pool_name)` verbatim; this test
2473        // pins that the borrow-form primitive returns exactly the
2474        // shape the equality gate expects.
2475        let p = process_with_annotation("tatara.pleme.io/pool", "demo-pool");
2476        assert_eq!(
2477            p.annotation("tatara.pleme.io/pool") == Some("demo-pool"),
2478            true
2479        );
2480        assert_eq!(p.annotation("tatara.pleme.io/pool") == Some("other"), false);
2481    }
2482
2483    // ─── Process::uid_or_empty substrate pins ──────────────────────────
2484    //
2485    // Pins the borrow-form metadata-projection primitive on the
2486    // `metadata.uid` axis that owns the `.metadata.uid.as_deref()
2487    // .unwrap_or("")` chain the two hand-authored
2488    // `tatara-reconciler::render` sites (`render_routing` +
2489    // `render_export_jobs`) restated by hand pre-lift. Peer to the
2490    // sibling `namespace_or_default_*` + `name_or_placeholder_*` pin
2491    // families on the metadata-slot × fallback-shape axis; all three
2492    // primitives return borrows of an owned-metadata slot with a slot-
2493    // specific fallback baked in (`"default"` for namespace, `"unnamed"`
2494    // for name, `""` for uid — the load-bearing gate value for
2495    // `owner_references_json`'s `is_empty` check). Fail-before-pass-
2496    // after granularity: `uid_or_empty` did not exist pre-lift, so any
2497    // test invoking it fails to compile pre-lift and passes post-lift.
2498
2499    #[test]
2500    fn uid_or_empty_returns_empty_string_when_metadata_uid_is_none() {
2501        // Empty-slot corner pin: the primitive collapses the no-uid
2502        // case to `""`, matching the pre-lift `.as_deref().unwrap_or("")`
2503        // chain's `""` byte-identically at both render consumer sites.
2504        // Semantically corresponds to a Process pre-metadata (fixtured
2505        // in tests, or caught mid-Forking before the API server has
2506        // stamped a `uid`); the downstream `owner_references_json`
2507        // composer gates on this exact `""` sentinel to stamp
2508        // `metadata.ownerReferences: []` rather than emit an owner-ref
2509        // pointing at a placeholder uid.
2510        let mut p = Process::new("scratch", empty_spec());
2511        p.metadata.uid = None;
2512        assert_eq!(p.uid_or_empty(), "");
2513    }
2514
2515    #[test]
2516    fn uid_or_empty_returns_borrowed_str_when_slot_is_populated() {
2517        // Happy-path pin: with a populated `metadata.uid` slot, the
2518        // primitive returns a borrowed `&str` whose contents match the
2519        // persisted `String`. A regression that reshaped / normalized
2520        // / cross-cluster-stripped the uid without touching this pin
2521        // would surface here rather than as silent skew at the two
2522        // `owner_references_json(name, uid)` emitters on the SAME
2523        // Process.
2524        let mut p = Process::new("owned-proc", empty_spec());
2525        p.metadata.uid = Some("uid-abc-123".into());
2526        assert_eq!(p.uid_or_empty(), "uid-abc-123");
2527    }
2528
2529    #[test]
2530    fn uid_or_empty_returns_empty_string_when_slot_is_explicitly_empty_string() {
2531        // Corner between the missing-slot `None` and the explicitly-
2532        // empty-string `Some("")` — both collapse to `""` at the
2533        // primitive because the downstream gate at
2534        // `owner_references_json` treats `.is_empty()` uniformly (the
2535        // empty-slot posture is what the whole primitive family
2536        // encodes: "no admissible owner reference, stamp `[]`"). A
2537        // regression that discriminated the two corners (returning a
2538        // sentinel `"<none>"` for the missing slot but `""` for the
2539        // explicit slot) would break the composition with
2540        // `owner_references_json` at the exactly-two-corner gate.
2541        let mut p = Process::new("owned-proc", empty_spec());
2542        p.metadata.uid = Some(String::new());
2543        assert_eq!(p.uid_or_empty(), "");
2544    }
2545
2546    #[test]
2547    fn uid_or_empty_is_a_zero_copy_borrow_projection() {
2548        // Borrow-discipline pin: the returned `&str` borrows the
2549        // persisted `String`'s underlying byte buffer in place — NOT
2550        // a fresh allocation or a clone. A regression that switched
2551        // the projection to an owned `String` (via `.clone()` or a
2552        // `format!` wrap) would defeat the zero-copy contract the
2553        // lift's primary strict-widening delivers, and would surface
2554        // here via pointer-identity comparison.
2555        let mut p = Process::new("owned-proc", empty_spec());
2556        p.metadata.uid = Some("uid-borrow-pin".into());
2557        let slice = p.uid_or_empty();
2558        assert!(std::ptr::eq(
2559            slice.as_ptr(),
2560            p.metadata.uid.as_ref().unwrap().as_ptr()
2561        ));
2562    }
2563
2564    #[test]
2565    fn uid_or_empty_is_a_pure_projection() {
2566        // Purity pin — repeated calls return byte-identical slices
2567        // (same pointer, same length). A regression that introduced
2568        // state (a lazy-cached normalized slot, a first-call
2569        // canonicalization pass) would surface here rather than as
2570        // silent drift between the two render consumer sites on the
2571        // SAME Process within one render pass.
2572        let mut p = Process::new("owned-proc", empty_spec());
2573        p.metadata.uid = Some("uid-pure".into());
2574        let a = p.uid_or_empty();
2575        let b = p.uid_or_empty();
2576        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
2577        assert_eq!(a.len(), b.len());
2578    }
2579
2580    #[test]
2581    fn uid_or_empty_matches_pre_lift_render_chain_shape() {
2582        // Byte-identical parity pin between the borrow-form primitive
2583        // here and the pre-lift `tatara-reconciler::render` chain shape
2584        // — the exact `.metadata.uid.as_deref().unwrap_or("")`
2585        // incantation both `render_routing` (line 514) and
2586        // `render_export_jobs` (line 653) spelled by hand pre-lift.
2587        // Sweeps every corner (missing uid slot, populated uid slot,
2588        // explicitly-empty uid slot) so a regression that inserted a
2589        // normalization the pre-lift chain does NOT apply — or vice
2590        // versa — surfaces here rather than as silent drift between
2591        // the ONE substrate owner and the two consumer sites.
2592        fn pre_lift(p: &Process) -> &str {
2593            p.metadata.uid.as_deref().unwrap_or("")
2594        }
2595        // Missing slot.
2596        let mut p = Process::new("x", empty_spec());
2597        p.metadata.uid = None;
2598        assert_eq!(p.uid_or_empty(), pre_lift(&p));
2599        // Populated slot.
2600        let mut p = Process::new("x", empty_spec());
2601        p.metadata.uid = Some("uid-42".into());
2602        assert_eq!(p.uid_or_empty(), pre_lift(&p));
2603        // Explicitly-empty slot.
2604        let mut p = Process::new("x", empty_spec());
2605        p.metadata.uid = Some(String::new());
2606        assert_eq!(p.uid_or_empty(), pre_lift(&p));
2607    }
2608
2609    #[test]
2610    fn uid_or_empty_composes_with_owner_references_json_empty_gate() {
2611        // Cross-primitive composition pin — the empty-string sentinel
2612        // this primitive returns for the missing-uid corner is EXACTLY
2613        // the sentinel the sibling substrate composer
2614        // `owner_references_json(name, uid)` gates on to stamp
2615        // `metadata.ownerReferences: []`. A regression that changed
2616        // the sentinel at either end (this primitive returning
2617        // `"<none>"`, `owner_references_json` gating on `uid == "0"`
2618        // instead of `uid.is_empty()`) would break the composition
2619        // and surface here rather than as an operator-observed
2620        // orphan resource after apply.
2621        let mut p = Process::new("x", empty_spec());
2622        p.metadata.uid = None;
2623        let refs = crate::owner_references_json("some-name", p.uid_or_empty());
2624        assert!(
2625            refs.is_empty(),
2626            "empty-uid corner must produce empty owner-refs array"
2627        );
2628
2629        p.metadata.uid = Some("real-uid".into());
2630        let refs = crate::owner_references_json("some-name", p.uid_or_empty());
2631        assert_eq!(
2632            refs.len(),
2633            1,
2634            "populated-uid corner must produce one owner-ref entry"
2635        );
2636    }
2637
2638    // ─── Process::owned_name_or_empty substrate pins ─────────────────
2639    //
2640    // Pins the owned-form metadata-projection primitive on the
2641    // `metadata.name` axis that owns the
2642    // `.metadata.name.clone().unwrap_or_default()` chain the two hand-
2643    // authored `tatara-pool-reconciler::controller_pool` sites (the
2644    // `PoolMember` seed at line 68 + the `PoolMemberSnapshot` desired-
2645    // count seed at line 108) restated by hand pre-lift. Peer to the
2646    // sibling `uid_or_empty` pin family on the (return-form × fallback-
2647    // value) axis pair — `uid_or_empty` owns the BORROW + empty-sentinel
2648    // corner (`&str` for owner-ref emitters gating on `.is_empty()`);
2649    // this method owns the OWNED + empty-sentinel corner (`String` for
2650    // struct-literal / HashMap-key row-builder consumers whose
2651    // downstream fills a `String` field with the load-bearing `""`
2652    // sentinel). Fail-before-pass-after granularity: `owned_name_or_empty`
2653    // did not exist pre-lift, so any test invoking it fails to compile
2654    // pre-lift and passes post-lift.
2655
2656    #[test]
2657    fn owned_name_or_empty_returns_empty_string_when_metadata_name_is_none() {
2658        // Empty-slot corner pin: the primitive collapses the no-name
2659        // case to `String::new()`, matching the pre-lift
2660        // `.clone().unwrap_or_default()` chain's empty `String` byte-
2661        // identically at both pool-reconciler consumer sites.
2662        // Semantically corresponds to a Process pre-metadata-name (test
2663        // fixture, dynamic API response pre-name-resolution); the
2664        // downstream `PoolMember { process_name, .. }` slot then holds
2665        // `""` as a stable "no name to key by" signal rather than a
2666        // display placeholder that would silently alias distinct rows.
2667        let mut p = Process::new("scratch", empty_spec());
2668        p.metadata.name = None;
2669        assert_eq!(p.owned_name_or_empty(), String::new());
2670    }
2671
2672    #[test]
2673    fn owned_name_or_empty_returns_owned_string_when_slot_is_populated() {
2674        // Happy-path pin: with a populated `metadata.name` slot, the
2675        // primitive returns an owned `String` whose contents match the
2676        // persisted `String`. A regression that reshaped / normalized
2677        // / case-folded the name without touching this pin would surface
2678        // here rather than as silent skew between the two pool-member
2679        // seeds keying on the SAME Process's name.
2680        let p = Process::new("api", empty_spec());
2681        assert_eq!(p.owned_name_or_empty(), "api");
2682    }
2683
2684    #[test]
2685    fn owned_name_or_empty_returns_empty_string_when_slot_is_explicitly_empty_string() {
2686        // Corner between the missing-slot `None` and the explicitly-
2687        // empty-string `Some(String::new())` — both collapse to `""` at
2688        // the primitive because the downstream pool-member consumers
2689        // treat both corners uniformly (no name, no key). A regression
2690        // that discriminated the two corners (returning a sentinel
2691        // `"<none>"` for the missing slot but `""` for the explicit
2692        // slot) would break `String::is_empty` gating at the row-builder
2693        // callsites without moving this pin.
2694        let mut p = Process::new("scratch", empty_spec());
2695        p.metadata.name = Some(String::new());
2696        assert_eq!(p.owned_name_or_empty(), String::new());
2697        assert!(p.owned_name_or_empty().is_empty());
2698    }
2699
2700    #[test]
2701    fn owned_name_or_empty_is_a_pure_projection() {
2702        // Purity pin — repeated calls return byte-identical `String`
2703        // values. A regression that introduced state (a lazy-cached
2704        // normalized slot, a first-call canonicalization pass) would
2705        // surface here rather than as silent drift between the pool-
2706        // member seed and the desired-count snapshot seed on the SAME
2707        // Process within one reconcile pass.
2708        let p = Process::new("stable-name", empty_spec());
2709        assert_eq!(p.owned_name_or_empty(), p.owned_name_or_empty());
2710    }
2711
2712    #[test]
2713    fn owned_name_or_empty_returns_independent_owned_string() {
2714        // Owned-discipline pin: the returned `String` is an independent
2715        // allocation the caller may consume, `.push_str` into, or move
2716        // into a struct-literal `process_name: String` slot — NOT a
2717        // shared reference into `metadata.name`. A regression that
2718        // switched the projection to a `Cow`-shaped variant or a slice-
2719        // form projection would defeat the owned-form contract the two
2720        // pool-reconciler struct-literal consumers depend on (a slice
2721        // cannot land in a `process_name: String` slot without a re-
2722        // clone), and would surface here at compile time via the mutate-
2723        // in-place test below.
2724        let p = Process::new("owned-proc", empty_spec());
2725        let mut owned = p.owned_name_or_empty();
2726        owned.push_str("-mutated");
2727        assert_eq!(owned, "owned-proc-mutated");
2728        // The Process's own slot is unchanged — the returned String
2729        // owns its own byte buffer, disjoint from `metadata.name`.
2730        assert_eq!(p.metadata.name.as_deref(), Some("owned-proc"));
2731    }
2732
2733    #[test]
2734    fn owned_name_or_empty_matches_pre_lift_controller_pool_chain_shape() {
2735        // Byte-identical parity pin between the owned-form primitive
2736        // here and the pre-lift `tatara-pool-reconciler::controller_pool`
2737        // chain shape — the exact `.metadata.name.clone().unwrap_or_default()`
2738        // incantation both `PoolMember` seed (line 68) and
2739        // `PoolMemberSnapshot` seed (line 108) spelled by hand pre-lift.
2740        // Sweeps every corner (missing name slot, populated name slot,
2741        // explicitly-empty name slot) so a regression that inserted a
2742        // normalization the pre-lift chain does NOT apply — or vice
2743        // versa — surfaces here rather than as silent drift between
2744        // the ONE substrate owner and the two consumer sites.
2745        fn pre_lift(p: &Process) -> String {
2746            p.metadata.name.clone().unwrap_or_default()
2747        }
2748        // Missing slot.
2749        let mut p = Process::new("x", empty_spec());
2750        p.metadata.name = None;
2751        assert_eq!(p.owned_name_or_empty(), pre_lift(&p));
2752        // Populated slot.
2753        let p = Process::new("real-name", empty_spec());
2754        assert_eq!(p.owned_name_or_empty(), pre_lift(&p));
2755        // Explicitly-empty slot.
2756        let mut p = Process::new("x", empty_spec());
2757        p.metadata.name = Some(String::new());
2758        assert_eq!(p.owned_name_or_empty(), pre_lift(&p));
2759    }
2760
2761    #[test]
2762    fn owned_name_or_empty_shares_empty_sentinel_with_uid_or_empty() {
2763        // Cross-primitive coherence pin — the empty-string fallback this
2764        // primitive returns for the missing-name corner is the SAME
2765        // sentinel the sibling borrow-form primitive `uid_or_empty`
2766        // returns for the missing-uid corner. Both partition the OWNED
2767        // × BORROW corner of the metadata-slot family on identical
2768        // fallback semantics ("the slot is unset"), so a consumer that
2769        // switches between them based on downstream ownership
2770        // requirements never sees a different missing-slot spelling as
2771        // a side effect. A regression that drifted either sentinel
2772        // (this primitive returning `"<unnamed>"`, `uid_or_empty`
2773        // returning `"<none>"`) would break the partition and surface
2774        // here rather than as silent shape drift across the family.
2775        let mut p = Process::new("scratch", empty_spec());
2776        p.metadata.name = None;
2777        p.metadata.uid = None;
2778        assert_eq!(p.owned_name_or_empty(), p.uid_or_empty());
2779        assert!(p.owned_name_or_empty().is_empty());
2780        assert!(p.uid_or_empty().is_empty());
2781    }
2782
2783    #[test]
2784    fn owned_name_or_empty_returns_distinct_fallback_from_name_or_placeholder() {
2785        // Axis-partition pin — the owned + empty-sentinel primitive here
2786        // and the borrow + display-placeholder primitive
2787        // [`Self::name_or_placeholder`] MUST return distinct fallback
2788        // values on the missing-name corner. The distinction is load-
2789        // bearing: `owned_name_or_empty` is for HashMap-key / row-builder
2790        // consumers that need distinct keys for missing-name Processes
2791        // (empty string collides only with other missing-name rows,
2792        // never with a real "unnamed" Process); `name_or_placeholder`
2793        // is for log-line / display consumers that render the
2794        // `"unnamed"` word to operators. A regression that unified the
2795        // two fallbacks (either primitive returning the other's
2796        // sentinel) would silently collapse missing-name pool members
2797        // into a display-string key or expose the empty sentinel to
2798        // operator log lines. This pin catches either drift.
2799        let mut p = Process::new("scratch", empty_spec());
2800        p.metadata.name = None;
2801        assert_eq!(p.owned_name_or_empty(), "");
2802        assert_eq!(p.name_or_placeholder(), Process::UNNAMED_PLACEHOLDER);
2803        assert_ne!(p.owned_name_or_empty(), p.name_or_placeholder());
2804    }
2805
2806    // ─── Process::declared_parent_pid substrate pins ─────────────────
2807    //
2808    // Pins the borrow-form spec-projection primitive on the declared
2809    // parent-PID axis that owns the `.spec.identity.parent.as_deref()`
2810    // chain the two hand-authored `tatara-reconciler::phase_machine`
2811    // sites (`handle_forking` ALLOCATE-PID composer + `handle_exiting`
2812    // SIGTERM-cascade child-fan-out filter) restated by hand pre-lift.
2813    // Peer to the sibling `observed_pid_*` pin family on the (spec-
2814    // declared × status-observed) axis pair; both compose the same
2815    // borrow-form `Option<&str>` return-shape skeleton on distinct
2816    // slots (`spec.identity.parent` vs. `status.pid`). Fail-before-
2817    // pass-after granularity: `declared_parent_pid` did not exist
2818    // pre-lift, so any test invoking it fails to compile pre-lift and
2819    // passes post-lift.
2820    fn process_with_declared_parent(parent: Option<&str>) -> Process {
2821        let mut spec = empty_spec();
2822        spec.identity.parent = parent.map(str::to_string);
2823        Process::new("child-proc", spec)
2824    }
2825
2826    #[test]
2827    fn declared_parent_pid_returns_none_when_slot_is_none() {
2828        // Empty-slot corner pin: the primitive collapses the no-
2829        // parent case to `None`, matching the pre-lift `.as_deref()`
2830        // chain's `None` byte-identically at both reconciler consumer
2831        // sites. Semantically corresponds to a Process authored at
2832        // cluster init (PID 1) with no upstream parent — the
2833        // ALLOCATE-PID composer feeds `None` into `pid::allocate_pid`
2834        // to signal "no prefix", and the SIGTERM cascade's filter
2835        // never matches such a Process because a child's declared
2836        // parent can never equal `Some(pid)` when the slot is `None`.
2837        let p = process_with_declared_parent(None);
2838        assert!(p.declared_parent_pid().is_none());
2839    }
2840
2841    #[test]
2842    fn declared_parent_pid_returns_borrowed_str_when_slot_is_populated() {
2843        // Happy-path pin: with a populated `spec.identity.parent`
2844        // slot, the primitive returns a borrowed `&str` whose
2845        // contents match the persisted `String`. A regression that
2846        // filtered / reshaped / canonicalized the string would
2847        // surface here rather than as silent skew at the child-fan-
2848        // out filter's `.declared_parent_pid() == Some(pid)`
2849        // equality check on the SAME parent-child pair.
2850        let p = process_with_declared_parent(Some("seph.1"));
2851        assert_eq!(p.declared_parent_pid(), Some("seph.1"));
2852    }
2853
2854    #[test]
2855    fn declared_parent_pid_is_a_zero_copy_borrow_projection() {
2856        // Borrow-discipline pin: the returned `&str` borrows the
2857        // persisted `String`'s underlying byte buffer in place —
2858        // NOT a fresh allocation or a clone. A regression that
2859        // switched the projection to an owned `String` (via
2860        // `.clone()` or `.to_owned()`) would defeat the zero-copy
2861        // contract the lift's primary strict-widening delivers.
2862        // The `handle_exiting` cascade filter runs per candidate
2863        // child across the cluster-wide Process list; a per-row
2864        // `String::clone` would allocate one heap block per non-
2865        // matching row, so the borrow-form primitive is load-
2866        // bearing for large clusters. Peer to the sibling
2867        // `observed_pid_is_a_zero_copy_borrow_projection` pin on
2868        // the status-observed side of the axis pair.
2869        let p = process_with_declared_parent(Some("seph.1"));
2870        let borrowed = p.declared_parent_pid().expect("populated slot");
2871        let persisted = p.spec.identity.parent.as_ref().unwrap();
2872        assert!(std::ptr::eq(borrowed.as_ptr(), persisted.as_ptr()));
2873    }
2874
2875    #[test]
2876    fn declared_parent_pid_is_a_pure_projection() {
2877        // Purity pin: calling the projection twice on the same
2878        // `Process` returns byte-identical `&str`s (same pointer,
2879        // same length). A regression that introduced state — a
2880        // lazy-cached slice materialized on first call, a
2881        // normalization step that ran once and cached — would
2882        // surface here rather than as silent drift between the
2883        // ALLOCATE-PID composer and the SIGTERM cascade's child-
2884        // fan-out filter within one reconcile pass.
2885        let p = process_with_declared_parent(Some("seph.1.3"));
2886        let a = p.declared_parent_pid().expect("populated slot");
2887        let b = p.declared_parent_pid().expect("populated slot");
2888        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
2889        assert_eq!(a.len(), b.len());
2890    }
2891
2892    #[test]
2893    fn declared_parent_pid_matches_pre_lift_reconciler_chain_shape() {
2894        // Byte-identical parity pin between the borrow-form primitive
2895        // here and the pre-lift `tatara-reconciler::phase_machine`
2896        // `.spec.identity.parent.as_deref()` chain shape. Sweeps
2897        // every corner every callsite plausibly encounters (empty
2898        // slot, populated with a hierarchical PID). A regression
2899        // that inserted a normalization step at the primitive the
2900        // pre-lift chain does NOT apply — or vice versa — surfaces
2901        // here rather than as silent drift between the pre-lift
2902        // consumer sites and the ONE substrate owner they now route
2903        // through. Peer to
2904        // `observed_pid_matches_pre_lift_reconciler_chain_shape` on
2905        // the sibling axis's borrow-form primitive.
2906        fn pre_lift(p: &Process) -> Option<&str> {
2907            p.spec.identity.parent.as_deref()
2908        }
2909        // Empty slot.
2910        let p = process_with_declared_parent(None);
2911        assert_eq!(p.declared_parent_pid(), pre_lift(&p));
2912        // Populated with a hierarchical PID.
2913        let p = process_with_declared_parent(Some("seph.1"));
2914        assert_eq!(p.declared_parent_pid(), pre_lift(&p));
2915        // Populated with a deeper hierarchical PID.
2916        let p = process_with_declared_parent(Some("seph.1.7.42"));
2917        assert_eq!(p.declared_parent_pid(), pre_lift(&p));
2918    }
2919
2920    #[test]
2921    fn declared_parent_pid_preserves_hierarchical_pid_format() {
2922        // Format-preservation pin: the hierarchical PID path
2923        // (dotted-segment form `seph.1.7`, matching the ported
2924        // `convergence-controller/src/identity.rs` scheme) reaches
2925        // the caller with segments and separators byte-identical
2926        // to the persisted `String`. A regression that inserted a
2927        // canonicalization pass (a segment-count validator, a
2928        // separator swap `.` → `/`, a leading/trailing whitespace
2929        // trim) would silently misroute the SIGTERM cascade's
2930        // `declared_parent_pid() == Some(pid)` comparator against
2931        // children whose `parent` field was authored in the ported
2932        // scheme's exact form — the SAME children the observed_pid
2933        // primitive is pinned to match on the other side of the
2934        // axis pair.
2935        for parent in ["seph", "seph.1", "seph.1.7", "seph.1.7.42"] {
2936            let p = process_with_declared_parent(Some(parent));
2937            assert_eq!(p.declared_parent_pid(), Some(parent));
2938        }
2939    }
2940
2941    #[test]
2942    fn declared_parent_pid_composes_with_observed_pid_for_child_fanout_filter() {
2943        // Cross-axis coherence pin against the sibling
2944        // [`Self::observed_pid`] on the (spec-declared × status-
2945        // observed) axis pair: a child's `.declared_parent_pid()`
2946        // and its parent's `.observed_pid()` compose through the
2947        // SAME borrow-form `Option<&str>` skeleton so the
2948        // `handle_exiting` cascade filter's equality gate holds
2949        // structurally. A regression that skewed EITHER primitive's
2950        // return-form (return-shape, borrow discipline, empty-slot
2951        // collapse) would silently misroute every SIGTERM cascade
2952        // on the parent-child pair. This pin re-reads both primitives
2953        // at test time so the composition holds iff both live paths
2954        // are the current implementation.
2955        // Parent Process: has an observed PID.
2956        let mut parent = Process::new("parent-proc", empty_spec());
2957        parent.status = Some(ProcessStatus {
2958            pid: Some("seph.1".to_string()),
2959            ..Default::default()
2960        });
2961        // Child Process: declared parent matches parent's observed PID.
2962        let child = process_with_declared_parent(Some("seph.1"));
2963        // The `handle_exiting` filter's equality gate:
2964        // `child.declared_parent_pid() == Some(parent.observed_pid()?)`.
2965        let parent_pid = parent.observed_pid().expect("parent has PID");
2966        assert_eq!(child.declared_parent_pid(), Some(parent_pid));
2967        // Sibling Process with an unrelated declared parent must NOT
2968        // match the same parent — pins that the filter's SKIP branch
2969        // holds on the other side of the axis pair.
2970        let sibling = process_with_declared_parent(Some("seph.2"));
2971        assert_ne!(sibling.declared_parent_pid(), Some(parent_pid));
2972    }
2973
2974    // ─── Process::declared_name_override substrate pins ──────────────
2975    //
2976    // Pins the borrow-form spec-projection primitive on the declared
2977    // name-override sub-axis of the declared-identity axis that owns
2978    // the `.spec.identity.name_override.as_deref()` chain the two
2979    // hand-authored `tatara-reconciler::phase_machine` sites
2980    // (`handle_pending` DECLARE composer + `handle_forking` ALLOCATE-
2981    // PID rehydration branch) restated by hand pre-lift. Peer to the
2982    // sibling `declared_parent_pid_*` pin family on the (parent ×
2983    // name-override) sub-axis pair; both compose the same borrow-form
2984    // `Option<&str>` return-shape skeleton on distinct slots
2985    // (`spec.identity.name_override` vs `spec.identity.parent`).
2986    // Fail-before-pass-after granularity: `declared_name_override`
2987    // did not exist pre-lift, so any test invoking it fails to
2988    // compile pre-lift and passes post-lift.
2989    fn process_with_declared_name_override(name_override: Option<&str>) -> Process {
2990        let mut spec = empty_spec();
2991        spec.identity.name_override = name_override.map(str::to_string);
2992        Process::new("some-proc", spec)
2993    }
2994
2995    #[test]
2996    fn declared_name_override_returns_none_when_slot_is_none() {
2997        // Empty-slot corner pin: the primitive collapses the no-
2998        // override case to `None`, matching the pre-lift `.as_deref()`
2999        // chain's `None` byte-identically at both reconciler consumer
3000        // sites. Semantically corresponds to a Process authored
3001        // WITHOUT the human-name-override escape hatch — the default;
3002        // `derive_identity` then computes the name from the content
3003        // hash and stamps `name_override: false` on the resulting
3004        // [`Identity`].
3005        let p = process_with_declared_name_override(None);
3006        assert!(p.declared_name_override().is_none());
3007    }
3008
3009    #[test]
3010    fn declared_name_override_returns_borrowed_str_when_slot_is_populated() {
3011        // Happy-path pin: with a populated `spec.identity
3012        // .name_override` slot, the primitive returns a borrowed
3013        // `&str` whose contents match the persisted `String`. A
3014        // regression that filtered / reshaped / canonicalized the
3015        // string at the primitive (as opposed to inside
3016        // `derive_identity`, where the trim/empty-filter lives today)
3017        // would surface here rather than as silent skew between the
3018        // DECLARE composer and the ALLOCATE-PID rehydration branch on
3019        // the SAME Process spec.
3020        let p = process_with_declared_name_override(Some("observability-stack"));
3021        assert_eq!(p.declared_name_override(), Some("observability-stack"));
3022    }
3023
3024    #[test]
3025    fn declared_name_override_is_a_zero_copy_borrow_projection() {
3026        // Borrow-discipline pin: the returned `&str` borrows the
3027        // persisted `String`'s underlying byte buffer in place —
3028        // NOT a fresh allocation or a clone. Peer to the sibling
3029        // `declared_parent_pid_is_a_zero_copy_borrow_projection` pin
3030        // on the other side of the (parent × name-override) sub-axis
3031        // pair; the borrow discipline holds structurally on BOTH
3032        // sub-axes so a future `declared_identity` composite that
3033        // returns both halves together can compose them without
3034        // dropping into an owning form.
3035        let p = process_with_declared_name_override(Some("observability-stack"));
3036        let borrowed = p.declared_name_override().expect("populated slot");
3037        let persisted = p.spec.identity.name_override.as_ref().unwrap();
3038        assert!(std::ptr::eq(borrowed.as_ptr(), persisted.as_ptr()));
3039    }
3040
3041    #[test]
3042    fn declared_name_override_is_a_pure_projection() {
3043        // Purity pin: calling the projection twice on the same
3044        // `Process` returns byte-identical `&str`s (same pointer,
3045        // same length). A regression that introduced state — a
3046        // lazy-cached slice materialized on first call, a
3047        // normalization step that ran once and cached — would
3048        // surface here rather than as silent drift between the
3049        // DECLARE composer and the ALLOCATE-PID rehydration branch
3050        // within one reconcile pass.
3051        let p = process_with_declared_name_override(Some("gateway-primary"));
3052        let a = p.declared_name_override().expect("populated slot");
3053        let b = p.declared_name_override().expect("populated slot");
3054        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3055        assert_eq!(a.len(), b.len());
3056    }
3057
3058    #[test]
3059    fn declared_name_override_matches_pre_lift_reconciler_chain_shape() {
3060        // Byte-identical parity pin between the borrow-form primitive
3061        // here and the pre-lift `tatara-reconciler::phase_machine`
3062        // `.spec.identity.name_override.as_deref()` chain shape.
3063        // Sweeps every corner every callsite plausibly encounters
3064        // (empty slot, populated with a bare name, populated with a
3065        // whitespace-containing name that `derive_identity`'s
3066        // internal trim would collapse, populated with an explicitly
3067        // empty string that `derive_identity`'s internal
3068        // `!s.is_empty()` filter would reject). A regression that
3069        // inserted a normalization step at the primitive the pre-
3070        // lift chain does NOT apply — or vice versa — surfaces here
3071        // rather than as silent drift between the pre-lift consumer
3072        // sites and the ONE substrate owner they now route through.
3073        // Peer to
3074        // `declared_parent_pid_matches_pre_lift_reconciler_chain_shape`
3075        // on the sibling sub-axis's borrow-form primitive.
3076        fn pre_lift(p: &Process) -> Option<&str> {
3077            p.spec.identity.name_override.as_deref()
3078        }
3079        // Empty slot.
3080        let p = process_with_declared_name_override(None);
3081        assert_eq!(p.declared_name_override(), pre_lift(&p));
3082        // Populated with a bare name.
3083        let p = process_with_declared_name_override(Some("observability-stack"));
3084        assert_eq!(p.declared_name_override(), pre_lift(&p));
3085        // Populated with a whitespace-containing name.
3086        let p = process_with_declared_name_override(Some("  observability-stack  "));
3087        assert_eq!(p.declared_name_override(), pre_lift(&p));
3088        // Populated with an explicitly empty string. Distinct from
3089        // the missing-slot `None` corner both at the primitive here
3090        // and at the pre-lift chain (the trim/filter that collapses
3091        // these two into the same `false`-branched
3092        // `Identity { name_override: false, .. }` lives INSIDE
3093        // `derive_identity`, NOT at the borrow site) — the primitive
3094        // MUST preserve the distinction so a future lift of the trim/
3095        // filter OUT of `derive_identity` INTO the primitive is a
3096        // conscious substrate change, not a silent one.
3097        let p = process_with_declared_name_override(Some(""));
3098        assert_eq!(p.declared_name_override(), pre_lift(&p));
3099    }
3100
3101    #[test]
3102    fn declared_name_override_preserves_raw_slot_verbatim() {
3103        // Invariance-under-`derive_identity`-normalization pin: the
3104        // primitive returns the slot's raw byte contents verbatim —
3105        // no trim, no empty-string filter, no case fold, no
3106        // normalization of any kind. `derive_identity` internally
3107        // applies `.map(str::trim).filter(|s| !s.is_empty())` before
3108        // dispatching on `Some(non_empty)` vs `None | Some(empty |
3109        // whitespace)`, but that transform lives IN `derive_identity`,
3110        // NOT at the borrow site. A regression that pulled the trim/
3111        // filter forward INTO the primitive would silently collapse
3112        // three currently-distinct corners at the borrow site (bare
3113        // populated → `Some(name)`; whitespace-only → `Some("   ")`;
3114        // empty → `Some("")`) into two (bare → `Some(name)`; the
3115        // other two → `None`). That collapse might be an intentional
3116        // substrate change some future run wants to make; if so, it
3117        // lands as a conscious edit here (with this pin updated in
3118        // the same commit) rather than as silent behavior drift.
3119        for value in ["bare", "  padded  ", "\ttabs\t", "   ", ""] {
3120            let p = process_with_declared_name_override(Some(value));
3121            assert_eq!(
3122                p.declared_name_override(),
3123                Some(value),
3124                "declared_name_override must preserve raw slot verbatim for value {value:?}"
3125            );
3126        }
3127    }
3128
3129    #[test]
3130    fn declared_name_override_composes_with_derive_identity_call_shape() {
3131        // Cross-primitive coherence pin against the [`derive_identity`]
3132        // consumer: the two live `tatara-reconciler::phase_machine`
3133        // callsites feed `p.declared_name_override()` as the second
3134        // positional argument to `derive_identity(&p.spec, …)`. This
3135        // pin exercises that exact call shape at test time so a
3136        // regression that skewed the primitive's return-form (return-
3137        // shape, borrow discipline, empty-slot collapse) surfaces
3138        // here as a shape mismatch at the [`derive_identity`] call
3139        // site rather than as silent operator-facing skew between the
3140        // DECLARE composer and the ALLOCATE-PID rehydration branch.
3141        // Populated with a bare non-empty name: `derive_identity`
3142        // dispatches on `Some(non_empty)` and stamps
3143        // `name_override: true` on the resulting [`Identity`], with
3144        // the resulting `.name` equal to the raw slot value.
3145        let p = process_with_declared_name_override(Some("gateway-primary"));
3146        let id = crate::identity::derive_identity(&p.spec, p.declared_name_override());
3147        assert!(id.name_override);
3148        assert_eq!(id.name, "gateway-primary");
3149        // Empty slot: `derive_identity` dispatches on `None` and
3150        // stamps `name_override: false` on the resulting [`Identity`],
3151        // with the resulting `.name` derived from the content hash
3152        // (NOT equal to any operator-authored slot value).
3153        let p = process_with_declared_name_override(None);
3154        let id = crate::identity::derive_identity(&p.spec, p.declared_name_override());
3155        assert!(!id.name_override);
3156    }
3157
3158    // ─── Process::observed_flux_resources substrate pins ───────────────
3159    //
3160    // Pins the borrow-form status-projection primitive that owns the
3161    // 5-line `.status.as_ref().map(|s| s.flux_resources.clone())
3162    // .unwrap_or_default()` chain the two hand-authored
3163    // `tatara-reconciler::phase_machine` sites (`handle_running` +
3164    // `handle_attested`) restated by hand pre-lift. Fail-before-pass-
3165    // after granularity: a regression that widened the missing-`status`
3166    // corner, dropped the slot, or drifted the borrow discipline
3167    // surfaces here rather than as silent operator-facing skew between
3168    // the VERIFY-phase readiness probe and the ATTEST-heartbeat drift
3169    // detector.
3170
3171    fn sample_flux_ref(name: &str) -> FluxResourceRef {
3172        // Distinct slot values so a swap between adjacent tuple
3173        // positions surfaces as an equality failure at the assertion
3174        // site — a slot-inversion regression cannot masquerade as
3175        // identity by accident. Peer to the sibling
3176        // `tatara_process::status::tests::sample_flux_ref` discipline
3177        // on the fetch-coords axis.
3178        FluxResourceRef {
3179            api_version: "kustomize.toolkit.fluxcd.io/v1".to_string(),
3180            kind: "Kustomization".to_string(),
3181            name: name.to_string(),
3182            namespace: "flux-system".to_string(),
3183            ready: false,
3184            message: None,
3185            last_check: None,
3186        }
3187    }
3188
3189    fn process_with_flux_resources(refs: Vec<FluxResourceRef>) -> Process {
3190        let mut p = Process::new("api-gateway", empty_spec());
3191        p.metadata.namespace = Some("prod".into());
3192        let mut status = ProcessStatus::default();
3193        status.flux_resources = refs;
3194        p.status = Some(status);
3195        p
3196    }
3197
3198    #[test]
3199    fn observed_flux_resources_returns_empty_slice_when_status_is_none() {
3200        // Missing-`status` corner pin: the primitive collapses the
3201        // no-status case to `&[]` so downstream `.is_empty()` /
3202        // `.len()` / iteration behave identically on a `Process`
3203        // whose status field is `None` and on one whose status
3204        // carries an empty `flux_resources` slot. Matches the
3205        // pre-lift `.unwrap_or_default()`'s empty-`Vec` corner
3206        // byte-identically at every reconciler consumer's downstream
3207        // shape.
3208        let mut p = Process::new("api", empty_spec());
3209        p.status = None;
3210        assert!(p.observed_flux_resources().is_empty());
3211        assert_eq!(p.observed_flux_resources().len(), 0);
3212    }
3213
3214    #[test]
3215    fn observed_flux_resources_returns_empty_slice_when_flux_resources_is_empty() {
3216        // Zero-refs-under-populated-status corner pin: the primitive
3217        // returns an empty slice, matching the missing-`status`
3218        // corner byte-identically. A regression that treated the two
3219        // corners differently (a `None`-vs-empty signal that
3220        // downstream consumers could grep on) would silently promote
3221        // an internal representation detail (whether the reconciler
3222        // has ever written a status subresource) into observable
3223        // behavior.
3224        let p = process_with_flux_resources(vec![]);
3225        assert!(p.observed_flux_resources().is_empty());
3226        assert_eq!(p.observed_flux_resources().len(), 0);
3227    }
3228
3229    #[test]
3230    fn observed_flux_resources_returns_slice_of_persisted_vec() {
3231        // Happy-path pin: with a populated `status.flux_resources`
3232        // slot, the primitive returns a borrowed slice whose length
3233        // and per-element identity match the persisted vector. A
3234        // regression that filtered / reshaped / deduplicated the
3235        // slice would surface here rather than as silent skew at the
3236        // downstream fetch consumers.
3237        let refs = vec![
3238            sample_flux_ref("observability-stack"),
3239            sample_flux_ref("gateway"),
3240        ];
3241        let p = process_with_flux_resources(refs.clone());
3242        let observed = p.observed_flux_resources();
3243        assert_eq!(observed.len(), 2);
3244        assert_eq!(observed[0].name, "observability-stack");
3245        assert_eq!(observed[1].name, "gateway");
3246    }
3247
3248    #[test]
3249    fn observed_flux_resources_is_a_zero_copy_borrow_projection() {
3250        // Borrow-discipline pin: the returned slice borrows the
3251        // persisted `Vec<FluxResourceRef>` in place — NOT a fresh
3252        // allocation or a clone. A regression that switched the
3253        // projection to owned refs (via `.clone()` or `.to_vec()`)
3254        // would defeat the zero-copy contract the lift's primary
3255        // strict-widening delivers (the pre-lift 5-line chain
3256        // eagerly cloned the whole vector per reconcile pass; the
3257        // post-lift primitive borrows). Peer to the sibling
3258        // `flux_resource_ref_fetch_coords_returns_borrows_of_owned_slots`
3259        // pin on the per-ref borrow-projection axis.
3260        let refs = vec![sample_flux_ref("observability-stack")];
3261        let p = process_with_flux_resources(refs);
3262        let observed = p.observed_flux_resources();
3263        let persisted = &p.status.as_ref().unwrap().flux_resources;
3264        assert!(std::ptr::eq(observed.as_ptr(), persisted.as_ptr()));
3265    }
3266
3267    #[test]
3268    fn observed_flux_resources_is_a_pure_projection() {
3269        // Purity pin: calling the projection twice on the same
3270        // `Process` returns byte-identical slices (same pointer,
3271        // same length). A regression that introduced state — a
3272        // lazy-cached slice materialized on first call, a
3273        // normalization step that ran once and cached — would
3274        // surface here rather than as silent drift between the
3275        // VERIFY-phase and ATTEST-heartbeat consumers on the SAME
3276        // `Process` within one reconcile pass.
3277        let refs = vec![sample_flux_ref("observability-stack")];
3278        let p = process_with_flux_resources(refs);
3279        let a = p.observed_flux_resources();
3280        let b = p.observed_flux_resources();
3281        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3282        assert_eq!(a.len(), b.len());
3283    }
3284
3285    #[test]
3286    fn observed_flux_resources_matches_pre_lift_reconciler_chain_shape() {
3287        // Byte-identical parity pin between the borrow-form primitive
3288        // here and the pre-lift `tatara-reconciler::phase_machine`
3289        // 5-line chain shape. Sweeps every corner every callsite
3290        // plausibly encounters (missing status, empty flux_resources,
3291        // populated flux_resources with one ref, populated with
3292        // multiple refs). A regression that inserted a normalization
3293        // step at the primitive the pre-lift chain does NOT apply —
3294        // or vice versa — surfaces here rather than as silent drift
3295        // between the pre-lift consumer sites and the ONE substrate
3296        // owner they now route through. Peer to
3297        // `coordinates_or_none_matches_pre_lift_reconciler_helper_shape`
3298        // on the metadata axis's borrow-form primitive.
3299        // `FluxResourceRef` does not derive `PartialEq` — the parity
3300        // check walks the per-ref fetch-coords tuple (the same 4-slot
3301        // borrow projection every downstream fetch consumer routes
3302        // through) so a regression that reshaped ANY slot at ANY
3303        // index surfaces here through the sibling
3304        // `FluxResourceRef::fetch_coords` typed projection.
3305        fn pre_lift(p: &Process) -> Vec<FluxResourceRef> {
3306            p.status
3307                .as_ref()
3308                .map(|s| s.flux_resources.clone())
3309                .unwrap_or_default()
3310        }
3311        fn coord_shape(refs: &[FluxResourceRef]) -> Vec<(String, String, String, String)> {
3312            refs.iter()
3313                .map(|r| {
3314                    let (ns, av, kind, name) = r.fetch_coords();
3315                    (
3316                        ns.to_string(),
3317                        av.to_string(),
3318                        kind.to_string(),
3319                        name.to_string(),
3320                    )
3321                })
3322                .collect()
3323        }
3324        // Missing status.
3325        let mut p = Process::new("api", empty_spec());
3326        p.status = None;
3327        assert_eq!(
3328            coord_shape(p.observed_flux_resources()),
3329            coord_shape(&pre_lift(&p))
3330        );
3331        // Populated status, empty slot.
3332        let p = process_with_flux_resources(vec![]);
3333        assert_eq!(
3334            coord_shape(p.observed_flux_resources()),
3335            coord_shape(&pre_lift(&p))
3336        );
3337        // Populated status, one ref.
3338        let p = process_with_flux_resources(vec![sample_flux_ref("obs")]);
3339        assert_eq!(
3340            coord_shape(p.observed_flux_resources()),
3341            coord_shape(&pre_lift(&p))
3342        );
3343        // Populated status, multiple refs.
3344        let p = process_with_flux_resources(vec![
3345            sample_flux_ref("obs"),
3346            sample_flux_ref("gw"),
3347            sample_flux_ref("api"),
3348        ]);
3349        assert_eq!(
3350            coord_shape(p.observed_flux_resources()),
3351            coord_shape(&pre_lift(&p))
3352        );
3353    }
3354
3355    #[test]
3356    fn observed_flux_resources_missing_status_and_empty_slot_collapse_to_the_same_slice_shape() {
3357        // Cross-corner coherence pin: the missing-`status` corner and
3358        // the populated-empty-slot corner return slices whose
3359        // `.is_empty()` / `.len()` observations are IDENTICAL. A
3360        // regression that promoted the missing-`status` corner to
3361        // returning `None` (via a signature change) — or that widened
3362        // the empty-slot corner to a synthetic single-element slice
3363        // — would surface here rather than as silent operator-facing
3364        // divergence between a never-status-written Process and a
3365        // status-emptied Process.
3366        let mut p_no_status = Process::new("api", empty_spec());
3367        p_no_status.status = None;
3368        let p_empty_status = process_with_flux_resources(vec![]);
3369        assert_eq!(
3370            p_no_status.observed_flux_resources().len(),
3371            p_empty_status.observed_flux_resources().len()
3372        );
3373        assert_eq!(
3374            p_no_status.observed_flux_resources().is_empty(),
3375            p_empty_status.observed_flux_resources().is_empty()
3376        );
3377    }
3378
3379    #[test]
3380    fn observed_flux_resources_slice_preserves_persisted_ordering() {
3381        // Ordering-preservation pin: the borrowed slice preserves
3382        // the exact insertion order of the persisted vector — no
3383        // sort, no dedup, no reshape. A regression that inserted a
3384        // sort or reordering would silently misroute per-ref
3385        // observations at the downstream VERIFY-phase / ATTEST-
3386        // heartbeat consumers, both of which walk the slice
3387        // positionally and correlate the position to the observed
3388        // readiness.
3389        let refs = vec![
3390            sample_flux_ref("z-last"),
3391            sample_flux_ref("a-first"),
3392            sample_flux_ref("m-middle"),
3393        ];
3394        let p = process_with_flux_resources(refs);
3395        let observed = p.observed_flux_resources();
3396        assert_eq!(observed[0].name, "z-last");
3397        assert_eq!(observed[1].name, "a-first");
3398        assert_eq!(observed[2].name, "m-middle");
3399    }
3400
3401    // ─── Process::observed_pid substrate pins ─────────────────────────
3402    //
3403    // Pins the borrow-form status-projection primitive on the PID axis
3404    // that owns the 3-line `.status.as_ref().and_then(|s| s.pid.clone())`
3405    // chain the two hand-authored `tatara-reconciler::phase_machine`
3406    // sites (`handle_forking` ALLOCATE-PID gate + `handle_exiting`
3407    // SIGTERM cascade) restated by hand pre-lift. Peer to the sibling
3408    // `observed_flux_resources_*` pin family on the flux-resources
3409    // axis; both compose the missing-`status` fallback + borrow-form
3410    // return-shape skeleton on distinct `ProcessStatus` slots. Fail-
3411    // before-pass-after granularity: `observed_pid` did not exist
3412    // pre-lift, so any test invoking it fails to compile pre-lift and
3413    // passes post-lift.
3414
3415    fn process_with_pid(pid: Option<&str>) -> Process {
3416        let mut p = Process::new("api-gateway", empty_spec());
3417        p.metadata.namespace = Some("prod".into());
3418        let mut status = ProcessStatus::default();
3419        status.pid = pid.map(str::to_string);
3420        p.status = Some(status);
3421        p
3422    }
3423
3424    #[test]
3425    fn observed_pid_returns_none_when_status_is_none() {
3426        // Missing-`status` corner pin: the primitive collapses the
3427        // no-status case to `None` so downstream `.is_some()` /
3428        // `if let Some(_)` / `.map(...)` behave identically on a
3429        // `Process` whose status field is `None` and on one whose
3430        // status carries an unpopulated `pid` slot. Matches the
3431        // pre-lift `.and_then(...)` chain's `None` byte-identically
3432        // at every reconciler consumer's downstream shape.
3433        let mut p = Process::new("api", empty_spec());
3434        p.status = None;
3435        assert!(p.observed_pid().is_none());
3436    }
3437
3438    #[test]
3439    fn observed_pid_returns_none_when_pid_slot_is_none() {
3440        // Empty-slot-under-populated-status corner pin: the
3441        // primitive returns `None`, matching the missing-`status`
3442        // corner byte-identically. A regression that treated the
3443        // two corners differently (a `None`-vs-`Some("")` signal
3444        // that downstream consumers could grep on) would silently
3445        // promote an internal representation detail (whether the
3446        // reconciler has ever written a status subresource) into
3447        // observable behavior at the ALLOCATE-PID gate.
3448        let p = process_with_pid(None);
3449        assert!(p.observed_pid().is_none());
3450    }
3451
3452    #[test]
3453    fn observed_pid_returns_borrowed_str_when_pid_slot_is_populated() {
3454        // Happy-path pin: with a populated `status.pid` slot, the
3455        // primitive returns a borrowed `&str` whose contents match
3456        // the persisted `String`. A regression that filtered /
3457        // reshaped / canonicalized the string would surface here
3458        // rather than as silent skew at the downstream cascade
3459        // comparator's `.as_deref() == Some(...)` equality check.
3460        let p = process_with_pid(Some("seph.1.7"));
3461        assert_eq!(p.observed_pid(), Some("seph.1.7"));
3462    }
3463
3464    #[test]
3465    fn observed_pid_is_a_zero_copy_borrow_projection() {
3466        // Borrow-discipline pin: the returned `&str` borrows the
3467        // persisted `String`'s underlying byte buffer in place —
3468        // NOT a fresh allocation or a clone. A regression that
3469        // switched the projection to an owned `String` (via
3470        // `.clone()` or `.to_owned()`) would defeat the zero-copy
3471        // contract the lift's primary strict-widening delivers
3472        // (the pre-lift 3-line chain eagerly cloned the `String`
3473        // per reconcile pass at BOTH call sites even though the
3474        // ALLOCATE-PID gate immediately dropped the clone and the
3475        // SIGTERM cascade only re-borrowed it via `.as_str()`; the
3476        // post-lift primitive borrows). Peer to the sibling
3477        // `observed_flux_resources_is_a_zero_copy_borrow_projection`
3478        // pin on the flux-resources borrow-projection axis.
3479        let p = process_with_pid(Some("seph.1.7"));
3480        let observed = p.observed_pid().expect("populated slot");
3481        let persisted = p.status.as_ref().unwrap().pid.as_ref().unwrap();
3482        assert!(std::ptr::eq(observed.as_ptr(), persisted.as_ptr()));
3483    }
3484
3485    #[test]
3486    fn observed_pid_is_a_pure_projection() {
3487        // Purity pin: calling the projection twice on the same
3488        // `Process` returns byte-identical `&str`s (same pointer,
3489        // same length). A regression that introduced state — a
3490        // lazy-cached slice materialized on first call, a
3491        // normalization step that ran once and cached — would
3492        // surface here rather than as silent drift between the
3493        // ALLOCATE-PID gate and the SIGTERM cascade on the SAME
3494        // `Process` within one reconcile pass.
3495        let p = process_with_pid(Some("seph.1.7"));
3496        let a = p.observed_pid().expect("populated slot");
3497        let b = p.observed_pid().expect("populated slot");
3498        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3499        assert_eq!(a.len(), b.len());
3500    }
3501
3502    #[test]
3503    fn observed_pid_matches_pre_lift_reconciler_chain_shape() {
3504        // Byte-identical parity pin between the borrow-form
3505        // primitive here and the pre-lift `tatara-reconciler
3506        // ::phase_machine` 3-line chain shape. Sweeps every corner
3507        // every callsite plausibly encounters (missing status,
3508        // empty pid slot, populated pid slot). A regression that
3509        // inserted a normalization step at the primitive the pre-
3510        // lift chain does NOT apply — or vice versa — surfaces
3511        // here rather than as silent drift between the pre-lift
3512        // consumer sites and the ONE substrate owner they now
3513        // route through. Peer to
3514        // `observed_flux_resources_matches_pre_lift_reconciler_chain_shape`
3515        // on the flux-resources axis's borrow-form primitive.
3516        fn pre_lift(p: &Process) -> Option<String> {
3517            p.status.as_ref().and_then(|s| s.pid.clone())
3518        }
3519        // Missing status.
3520        let mut p = Process::new("api", empty_spec());
3521        p.status = None;
3522        assert_eq!(p.observed_pid().map(str::to_string), pre_lift(&p));
3523        // Populated status, empty pid slot.
3524        let p = process_with_pid(None);
3525        assert_eq!(p.observed_pid().map(str::to_string), pre_lift(&p));
3526        // Populated status, populated pid slot.
3527        let p = process_with_pid(Some("seph.1.7"));
3528        assert_eq!(p.observed_pid().map(str::to_string), pre_lift(&p));
3529    }
3530
3531    #[test]
3532    fn observed_pid_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
3533        // Cross-corner coherence pin: the missing-`status` corner
3534        // and the populated-empty-slot corner return `Option`s whose
3535        // `.is_none()` observations are IDENTICAL. A regression
3536        // that promoted the missing-`status` corner to returning a
3537        // typed error (via a signature change to `Result<_, _>`) —
3538        // or that widened the empty-slot corner to a synthetic
3539        // `Some("")` — would surface here rather than as silent
3540        // operator-facing divergence between a never-status-
3541        // written Process and a status-emptied Process on the
3542        // ALLOCATE-PID gate.
3543        let mut p_no_status = Process::new("api", empty_spec());
3544        p_no_status.status = None;
3545        let p_empty_slot = process_with_pid(None);
3546        assert_eq!(
3547            p_no_status.observed_pid().is_none(),
3548            p_empty_slot.observed_pid().is_none()
3549        );
3550        assert_eq!(
3551            p_no_status.observed_pid().is_some(),
3552            p_empty_slot.observed_pid().is_some()
3553        );
3554    }
3555
3556    #[test]
3557    fn observed_pid_preserves_hierarchical_pid_format() {
3558        // Format-preservation pin: the hierarchical PID path
3559        // (dotted-segment form `seph.1.7`, matching the ported
3560        // `convergence-controller/src/identity.rs` scheme) reaches
3561        // the caller with segments and separators byte-identical
3562        // to the persisted `String`. A regression that inserted a
3563        // canonicalization pass (a segment-count validator, a
3564        // separator swap `.` → `/`, a leading/trailing whitespace
3565        // trim) would silently misroute the SIGTERM cascade's
3566        // `spec.identity.parent == Some(pid)` comparator against
3567        // children whose `parent` field was authored in the ported
3568        // scheme's exact form.
3569        for pid in ["seph", "seph.1", "seph.1.7", "seph.1.7.42"] {
3570            let p = process_with_pid(Some(pid));
3571            assert_eq!(p.observed_pid(), Some(pid));
3572        }
3573    }
3574
3575    // ─── Process::observed_attestation substrate pins ─────────────────
3576    //
3577    // Pins the borrow-form status-projection primitive on the
3578    // attestation-chain axis that owns the 3-line
3579    // `.status.as_ref().and_then(|s| s.attestation.as_ref())` chain
3580    // the two hand-authored `tatara-reconciler` sites
3581    // (`phase_machine::advance_to_attested` ATTEST composer +
3582    // `render::render_export_jobs` export-Job builder) restated by
3583    // hand pre-lift. Peer to the sibling `observed_pid_*` +
3584    // `observed_flux_resources_*` pin families; all three compose
3585    // the missing-`status` fallback + borrow-form return-shape
3586    // skeleton on distinct `ProcessStatus` slots. Fail-before-pass-
3587    // after granularity: `observed_attestation` did not exist
3588    // pre-lift, so any test invoking it fails to compile pre-lift
3589    // and passes post-lift.
3590
3591    fn sample_attestation(artifact: &str, intent: &str) -> ProcessAttestation {
3592        // Distinct pillar strings so a regression that swapped the
3593        // artifact / intent pillars silently surfaces as an
3594        // equality failure at the composed-root parity pin.
3595        ProcessAttestation::initial(artifact.to_string(), None, intent.to_string())
3596    }
3597
3598    fn process_with_attestation(attestation: Option<ProcessAttestation>) -> Process {
3599        let mut p = Process::new("api-gateway", empty_spec());
3600        p.metadata.namespace = Some("prod".into());
3601        let mut status = ProcessStatus::default();
3602        status.attestation = attestation;
3603        p.status = Some(status);
3604        p
3605    }
3606
3607    #[test]
3608    fn observed_attestation_returns_none_when_status_is_none() {
3609        // Missing-`status` corner pin: the primitive collapses the
3610        // no-status case to `None` so downstream `.is_some()` /
3611        // `if let Some(_)` / `.map(...)` behave identically on a
3612        // `Process` whose status field is `None` and on one whose
3613        // status carries an unpopulated `attestation` slot.
3614        // Matches the pre-lift `.and_then(...)` chain's `None`
3615        // byte-identically at every reconciler consumer's
3616        // downstream shape.
3617        let mut p = Process::new("api", empty_spec());
3618        p.status = None;
3619        assert!(p.observed_attestation().is_none());
3620    }
3621
3622    #[test]
3623    fn observed_attestation_returns_none_when_attestation_slot_is_none() {
3624        // Empty-slot-under-populated-status corner pin: the
3625        // primitive returns `None`, matching the missing-`status`
3626        // corner byte-identically. A regression that treated the
3627        // two corners differently (a `None`-vs-`Some(_)` signal
3628        // that downstream consumers could grep on) would silently
3629        // promote an internal representation detail (whether the
3630        // reconciler has ever written a status subresource) into
3631        // observable behavior at the ATTEST composer's
3632        // seed-vs-chain branch.
3633        let p = process_with_attestation(None);
3634        assert!(p.observed_attestation().is_none());
3635    }
3636
3637    #[test]
3638    fn observed_attestation_returns_borrow_when_slot_is_populated() {
3639        // Happy-path pin: with a populated `status.attestation`
3640        // slot, the primitive returns a borrowed
3641        // `&ProcessAttestation` whose fields match the persisted
3642        // record. A regression that filtered / reshaped /
3643        // canonicalized the record would surface here rather than
3644        // as silent skew at the downstream `prior.next(pillars)`
3645        // chain composer + the ephemeral-export receipt's
3646        // `previous_root` linker.
3647        let att = sample_attestation("art-1", "int-1");
3648        let composed_root = att.composed_root.clone();
3649        let p = process_with_attestation(Some(att));
3650        let observed = p.observed_attestation().expect("populated slot");
3651        assert_eq!(observed.artifact_hash, "art-1");
3652        assert_eq!(observed.intent_hash, "int-1");
3653        assert_eq!(observed.composed_root, composed_root);
3654        assert_eq!(observed.generation, 0);
3655        assert!(observed.previous_root.is_none());
3656    }
3657
3658    #[test]
3659    fn observed_attestation_is_a_zero_copy_borrow_projection() {
3660        // Borrow-discipline pin: the returned reference points at
3661        // the persisted `ProcessAttestation` in place — NOT a fresh
3662        // allocation or a clone. A regression that switched the
3663        // projection to an owned `ProcessAttestation` (via
3664        // `.clone()`) would defeat the zero-copy contract the
3665        // lift's primary strict-widening delivers (the pre-lift
3666        // 3-line chain returned a borrow, but the export-Job
3667        // builder then cloned `composed_root` off it; the post-
3668        // lift primitive preserves the borrow all the way to the
3669        // consumer's own cloning choice). Peer to the sibling
3670        // `observed_pid_is_a_zero_copy_borrow_projection` +
3671        // `observed_flux_resources_is_a_zero_copy_borrow_projection`
3672        // pins on the PID + flux-resources borrow-projection axes.
3673        let att = sample_attestation("art-1", "int-1");
3674        let p = process_with_attestation(Some(att));
3675        let observed = p.observed_attestation().expect("populated slot") as *const _;
3676        let persisted = p.status.as_ref().unwrap().attestation.as_ref().unwrap() as *const _;
3677        assert!(std::ptr::eq(observed, persisted));
3678    }
3679
3680    #[test]
3681    fn observed_attestation_is_a_pure_projection() {
3682        // Purity pin: calling the projection twice on the same
3683        // `Process` returns byte-identical borrows (same pointer).
3684        // A regression that introduced state — a lazy-cached
3685        // reference materialized on first call, a normalization
3686        // step that ran once and cached — would surface here
3687        // rather than as silent drift between the ATTEST composer
3688        // and the ephemeral-export receipt chain on the SAME
3689        // `Process` within one reconcile pass.
3690        let att = sample_attestation("art-1", "int-1");
3691        let p = process_with_attestation(Some(att));
3692        let a = p.observed_attestation().expect("populated slot") as *const _;
3693        let b = p.observed_attestation().expect("populated slot") as *const _;
3694        assert!(std::ptr::eq(a, b));
3695    }
3696
3697    #[test]
3698    fn observed_attestation_matches_pre_lift_reconciler_chain_shape() {
3699        // Byte-identical parity pin between the borrow-form
3700        // primitive here and the pre-lift `tatara-reconciler`
3701        // 3-line chain shape. Sweeps every corner every callsite
3702        // plausibly encounters (missing status, empty attestation
3703        // slot, populated attestation slot). A regression that
3704        // inserted a normalization step at the primitive the pre-
3705        // lift chain does NOT apply — or vice versa — surfaces
3706        // here rather than as silent drift between the pre-lift
3707        // consumer sites and the ONE substrate owner they now
3708        // route through. Peer to
3709        // `observed_pid_matches_pre_lift_reconciler_chain_shape` +
3710        // `observed_flux_resources_matches_pre_lift_reconciler_chain_shape`
3711        // on the PID + flux-resources axes.
3712        // `ProcessAttestation` does not derive `PartialEq` — the
3713        // parity check walks the `composed_root` field (the
3714        // byte-string every downstream consumer keys off) so a
3715        // regression that reshaped the record without touching
3716        // the composed-root observation surfaces here through
3717        // the receipt-chain projection.
3718        fn pre_lift(p: &Process) -> Option<String> {
3719            p.status
3720                .as_ref()
3721                .and_then(|s| s.attestation.as_ref())
3722                .map(|a| a.composed_root.clone())
3723        }
3724        // Missing status.
3725        let mut p = Process::new("api", empty_spec());
3726        p.status = None;
3727        assert_eq!(
3728            p.observed_attestation().map(|a| a.composed_root.clone()),
3729            pre_lift(&p)
3730        );
3731        // Populated status, empty attestation slot.
3732        let p = process_with_attestation(None);
3733        assert_eq!(
3734            p.observed_attestation().map(|a| a.composed_root.clone()),
3735            pre_lift(&p)
3736        );
3737        // Populated status, populated attestation slot.
3738        let p = process_with_attestation(Some(sample_attestation("art-1", "int-1")));
3739        assert_eq!(
3740            p.observed_attestation().map(|a| a.composed_root.clone()),
3741            pre_lift(&p)
3742        );
3743    }
3744
3745    #[test]
3746    fn observed_attestation_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
3747        // Cross-corner coherence pin: the missing-`status` corner
3748        // and the populated-empty-slot corner return `Option`s
3749        // whose `.is_none()` observations are IDENTICAL. A
3750        // regression that promoted the missing-`status` corner to
3751        // returning a typed error (via a signature change to
3752        // `Result<_, _>`) — or that widened the empty-slot corner
3753        // to a synthetic `Some(default_attestation)` — would
3754        // surface here rather than as silent operator-facing
3755        // divergence between a never-status-written Process and
3756        // an attestation-emptied Process on the ATTEST composer's
3757        // seed-vs-chain branch.
3758        let mut p_no_status = Process::new("api", empty_spec());
3759        p_no_status.status = None;
3760        let p_empty_slot = process_with_attestation(None);
3761        assert_eq!(
3762            p_no_status.observed_attestation().is_none(),
3763            p_empty_slot.observed_attestation().is_none()
3764        );
3765        assert_eq!(
3766            p_no_status.observed_attestation().is_some(),
3767            p_empty_slot.observed_attestation().is_some()
3768        );
3769    }
3770
3771    #[test]
3772    fn observed_attestation_preserves_chain_generation_field() {
3773        // Generation-preservation pin: a chained attestation
3774        // (`prior.next(...)` at generation N ≥ 1 with a
3775        // `previous_root` linked to `prior.composed_root`) reaches
3776        // the caller with its `generation` counter + `previous_root`
3777        // link byte-identical to the persisted record. The pre-lift
3778        // ATTEST composer discriminated exactly on this borrow's
3779        // `Some(prior)` vs `None` arm; a regression that dropped
3780        // the chain's `generation` counter (say, by folding
3781        // `next(...)` into a fresh `initial(...)` on every
3782        // reconcile pass) would silently reset every chain and
3783        // orphan every downstream `previous_root` link, but that
3784        // drift is invisible to a Process CRD reader who only
3785        // observes the LATEST composed_root.
3786        let prior = sample_attestation("art-0", "int-0");
3787        let chained = prior.next("art-1".to_string(), None, "int-1".to_string());
3788        let expected_generation = chained.generation;
3789        let expected_previous = chained.previous_root.clone();
3790        let p = process_with_attestation(Some(chained));
3791        let observed = p.observed_attestation().expect("populated slot");
3792        assert_eq!(observed.generation, expected_generation);
3793        assert_eq!(observed.generation, 1);
3794        assert_eq!(observed.previous_root, expected_previous);
3795        assert_eq!(
3796            observed.previous_root.as_deref(),
3797            Some(prior.composed_root.as_str())
3798        );
3799    }
3800
3801    // ─── Process::observed_identity substrate pins ────────────────────
3802    //
3803    // The borrow-form status-projection primitive on the resolved-
3804    // identity axis. Collapses the paired 3-line `.status.as_ref()
3805    // .and_then(|s| s.identity.<clone|as_ref>())` chain every
3806    // consumer in `tatara-reconciler` restated by hand pre-lift at
3807    // TWO sites (`phase_machine::handle_forking` seed +
3808    // `ssapply::inject_annotations` content-hash annotation
3809    // composer). Peer to the sibling `observed_pid_*` +
3810    // `observed_attestation_*` + `observed_flux_resources_*` pin
3811    // families; all four compose the same missing-`status` fallback
3812    // + borrow-form return-shape skeleton on distinct
3813    // `ProcessStatus` slots. Each pin fails-before-pass-after
3814    // granularity: `observed_identity` did not exist pre-lift, so
3815    // any test invoking it fails to compile pre-lift and passes
3816    // post-lift.
3817
3818    fn sample_identity(name: &str) -> Identity {
3819        // Distinct name + content_hash + override flag so a
3820        // regression that reshaped one slot surfaces at the
3821        // populated-slot pin's field-equality check without
3822        // aliasing the sibling slots.
3823        Identity {
3824            name: name.to_string(),
3825            content_hash: "a".repeat(26),
3826            name_override: true,
3827        }
3828    }
3829
3830    fn process_with_identity(identity: Option<Identity>) -> Process {
3831        let mut p = Process::new("api-gateway", empty_spec());
3832        p.metadata.namespace = Some("prod".into());
3833        let mut status = ProcessStatus::default();
3834        status.identity = identity;
3835        p.status = Some(status);
3836        p
3837    }
3838
3839    #[test]
3840    fn observed_identity_returns_none_when_status_is_none() {
3841        // Missing-`status` corner pin: the primitive collapses the
3842        // no-status case to `None` so downstream `.is_some()` /
3843        // `if let Some(_)` / `.cloned().unwrap_or_else(...)` behave
3844        // identically on a `Process` whose status field is `None`
3845        // and on one whose status carries an unpopulated `identity`
3846        // slot. Matches the pre-lift `.and_then(...)` chain's `None`
3847        // byte-identically at every reconciler consumer's
3848        // downstream shape.
3849        let mut p = Process::new("api", empty_spec());
3850        p.status = None;
3851        assert!(p.observed_identity().is_none());
3852    }
3853
3854    #[test]
3855    fn observed_identity_returns_none_when_identity_slot_is_none() {
3856        // Empty-slot-under-populated-status corner pin: the
3857        // primitive returns `None`, matching the missing-`status`
3858        // corner byte-identically. A regression that treated the
3859        // two corners differently (a `None`-vs-`Some(_)` signal
3860        // that downstream consumers could grep on) would silently
3861        // promote an internal representation detail (whether the
3862        // reconciler has ever written a status subresource) into
3863        // observable behavior at the FORK-time `derive_identity`
3864        // fallback branch.
3865        let p = process_with_identity(None);
3866        assert!(p.observed_identity().is_none());
3867    }
3868
3869    #[test]
3870    fn observed_identity_returns_borrow_when_slot_is_populated() {
3871        // Happy-path pin: with a populated `status.identity` slot,
3872        // the primitive returns a borrowed `&Identity` whose fields
3873        // match the persisted record. A regression that filtered /
3874        // reshaped / canonicalized the record would surface here
3875        // rather than as silent skew at the FORK-time seed's
3876        // `.cloned().unwrap_or_else(derive_identity)` composition
3877        // + the SSA-time content-hash annotation stamp on the SAME
3878        // Process.
3879        let id = sample_identity("seph");
3880        let expected = id.clone();
3881        let p = process_with_identity(Some(id));
3882        let observed = p.observed_identity().expect("populated slot");
3883        assert_eq!(observed, &expected);
3884        assert_eq!(observed.name, "seph");
3885        assert_eq!(observed.content_hash, "a".repeat(26));
3886        assert!(observed.name_override);
3887    }
3888
3889    #[test]
3890    fn observed_identity_is_a_zero_copy_borrow_projection() {
3891        // Borrow-discipline pin: the returned reference points at
3892        // the persisted `Identity` in place — NOT a fresh
3893        // allocation or a clone. A regression that switched the
3894        // projection to an owned `Identity` (via `.clone()`) would
3895        // defeat the zero-copy contract the lift's primary strict-
3896        // widening delivers (the SSA-time consumer never clones the
3897        // whole `Identity`, only the `content_hash` field it stamps
3898        // onto the annotation map, so the borrow-form return
3899        // shape's happy-path allocation count is exactly ZERO).
3900        // Peer to the sibling
3901        // `observed_attestation_is_a_zero_copy_borrow_projection`
3902        // + `observed_pid_is_a_zero_copy_borrow_projection` +
3903        // `observed_flux_resources_is_a_zero_copy_borrow_projection`
3904        // pins on the attestation-chain + PID + flux-resources
3905        // borrow-projection axes.
3906        let id = sample_identity("seph");
3907        let p = process_with_identity(Some(id));
3908        let observed = p.observed_identity().expect("populated slot") as *const _;
3909        let persisted = p.status.as_ref().unwrap().identity.as_ref().unwrap() as *const _;
3910        assert!(std::ptr::eq(observed, persisted));
3911    }
3912
3913    #[test]
3914    fn observed_identity_is_a_pure_projection() {
3915        // Purity pin: calling the projection twice on the same
3916        // `Process` returns byte-identical borrows (same pointer).
3917        // A regression that introduced state — a lazy-cached
3918        // reference materialized on first call, a normalization
3919        // step that ran once and cached — would surface here
3920        // rather than as silent drift between the FORK-time
3921        // identity seed and the SSA-time content-hash annotation
3922        // stamp on the SAME `Process` within one reconcile pass.
3923        let p = process_with_identity(Some(sample_identity("seph")));
3924        let a = p.observed_identity().expect("populated slot") as *const _;
3925        let b = p.observed_identity().expect("populated slot") as *const _;
3926        assert!(std::ptr::eq(a, b));
3927    }
3928
3929    #[test]
3930    fn observed_identity_matches_pre_lift_reconciler_chain_shape() {
3931        // Byte-identical parity pin between the borrow-form
3932        // primitive here and the pre-lift `tatara-reconciler`
3933        // 3-line chain shape. Sweeps every corner every callsite
3934        // plausibly encounters (missing status, empty identity
3935        // slot, populated identity slot). A regression that
3936        // inserted a normalization step at the primitive the pre-
3937        // lift chain does NOT apply — or vice versa — surfaces
3938        // here rather than as silent drift between the pre-lift
3939        // consumer sites and the ONE substrate owner they now
3940        // route through. Peer to
3941        // `observed_attestation_matches_pre_lift_reconciler_chain_shape`
3942        // + `observed_pid_matches_pre_lift_reconciler_chain_shape`
3943        // + `observed_flux_resources_matches_pre_lift_reconciler_chain_shape`
3944        // on the attestation-chain + PID + flux-resources axes.
3945        fn pre_lift(p: &Process) -> Option<Identity> {
3946            p.status.as_ref().and_then(|s| s.identity.clone())
3947        }
3948        // Missing status.
3949        let mut p = Process::new("api", empty_spec());
3950        p.status = None;
3951        assert_eq!(p.observed_identity().cloned(), pre_lift(&p));
3952        // Populated status, empty identity slot.
3953        let p = process_with_identity(None);
3954        assert_eq!(p.observed_identity().cloned(), pre_lift(&p));
3955        // Populated status, populated identity slot.
3956        let p = process_with_identity(Some(sample_identity("seph")));
3957        assert_eq!(p.observed_identity().cloned(), pre_lift(&p));
3958    }
3959
3960    #[test]
3961    fn observed_identity_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
3962        // Cross-corner coherence pin: the missing-`status` corner
3963        // and the populated-empty-slot corner return `Option`s
3964        // whose `.is_none()` observations are IDENTICAL. A
3965        // regression that promoted the missing-`status` corner to
3966        // returning a typed error (via a signature change to
3967        // `Result<_, _>`) — or that widened the empty-slot corner
3968        // to a synthetic `Some(derive_identity(default_spec))` —
3969        // would surface here rather than as silent operator-facing
3970        // divergence between a never-status-written Process and an
3971        // identity-cleared Process on the FORK-time seed branch.
3972        let mut p_no_status = Process::new("api", empty_spec());
3973        p_no_status.status = None;
3974        let p_empty_slot = process_with_identity(None);
3975        assert_eq!(
3976            p_no_status.observed_identity().is_none(),
3977            p_empty_slot.observed_identity().is_none()
3978        );
3979        assert_eq!(
3980            p_no_status.observed_identity().is_some(),
3981            p_empty_slot.observed_identity().is_some()
3982        );
3983    }
3984
3985    #[test]
3986    fn observed_identity_cloned_composes_with_derive_identity_fallback() {
3987        // Cross-primitive composition pin: the borrow-form
3988        // primitive threaded through `.cloned().unwrap_or_else(||
3989        // derive_identity(...))` reproduces the pre-lift FORK-time
3990        // seed's owned-`Identity` shape at every corner. Binds the
3991        // exact composition the `phase_machine::handle_forking`
3992        // consumer performs: on the populated-slot corner the
3993        // reconciler-persisted `Identity` is returned verbatim (the
3994        // fallback never fires), and on both empty corners
3995        // (missing-status + empty-slot) the fallback fires
3996        // producing a fresh `derive_identity(&spec,
3997        // name_override)`. A regression that (a) swapped the
3998        // fallback direction, (b) made `.cloned()` re-derive
3999        // instead of clone, or (c) made the empty-slot corner
4000        // return a synthetic `Some(default_identity)` collides
4001        // with the fallback surfaces here rather than as silent
4002        // FORK-time PID allocator skew.
4003        let spec = empty_spec();
4004        let fallback_expected = crate::identity::derive_identity(&spec, None);
4005        // Populated-slot corner: the seed returns the persisted
4006        // identity, NOT the derive fallback.
4007        let persisted = sample_identity("seph");
4008        let p = process_with_identity(Some(persisted.clone()));
4009        let seed = p.observed_identity().cloned().unwrap_or_else(|| {
4010            crate::identity::derive_identity(&p.spec, p.declared_name_override())
4011        });
4012        assert_eq!(seed, persisted);
4013        assert_ne!(seed, fallback_expected);
4014        // Empty-slot corner: the seed fires the derive fallback.
4015        let p = process_with_identity(None);
4016        let seed = p.observed_identity().cloned().unwrap_or_else(|| {
4017            crate::identity::derive_identity(&p.spec, p.declared_name_override())
4018        });
4019        assert_eq!(seed, fallback_expected);
4020        // Missing-status corner: the seed fires the derive
4021        // fallback, byte-identical to the empty-slot corner.
4022        let mut p = Process::new("api-gateway", empty_spec());
4023        p.metadata.namespace = Some("prod".into());
4024        p.status = None;
4025        let seed = p.observed_identity().cloned().unwrap_or_else(|| {
4026            crate::identity::derive_identity(&p.spec, p.declared_name_override())
4027        });
4028        assert_eq!(seed, fallback_expected);
4029    }
4030
4031    // ─── Process::observed_phase substrate pins ───────────────────────
4032    //
4033    // The copy-form status-projection primitive on the phase axis.
4034    // Collapses the paired 3-line `.status.as_ref().map(|s| s.phase)`
4035    // chain every consumer in `tatara-reconciler` restated by hand
4036    // pre-lift at FIVE sites. Peer to the borrow-form
4037    // `observed_pid_*` + `observed_flux_resources_*` +
4038    // `observed_attestation_*` pin families; all four compose the
4039    // same missing-`status` fallback skeleton on distinct
4040    // `ProcessStatus` slots, with the phase-axis form returning
4041    // `Option<ProcessPhase>` (copy of a `Copy` scalar) rather than
4042    // `Option<&T>` (borrow) because the underlying slot is a bare
4043    // `ProcessPhase` — no allocation to borrow past, and the enum
4044    // is one byte on the wire. Each pin fails-before-pass-after
4045    // granularity: `observed_phase` did not exist pre-lift, so any
4046    // test invoking it fails to compile pre-lift and passes
4047    // post-lift.
4048
4049    fn process_with_phase(phase: Option<ProcessPhase>) -> Process {
4050        let mut p = Process::new("api-gateway", empty_spec());
4051        p.metadata.namespace = Some("prod".into());
4052        if let Some(ph) = phase {
4053            let mut status = ProcessStatus::default();
4054            status.phase = ph;
4055            p.status = Some(status);
4056        }
4057        p
4058    }
4059
4060    #[test]
4061    fn observed_phase_returns_none_when_status_is_none() {
4062        // Missing-`status` corner pin: the primitive collapses the
4063        // no-status case to `None` so downstream `.unwrap_or(...)`
4064        // at every reconciler consumer chooses the default
4065        // deliberately (`Pending` for the top-level dispatch seed
4066        // + boundary evaluator + routing groupby; `Attested` for
4067        // the released-from annotation composer). Matches the
4068        // pre-lift `.map(|s| s.phase)` chain's `None`
4069        // byte-identically at every consumer's downstream shape.
4070        let mut p = Process::new("api", empty_spec());
4071        p.status = None;
4072        assert!(p.observed_phase().is_none());
4073    }
4074
4075    #[test]
4076    fn observed_phase_returns_some_default_when_status_is_populated_with_default_phase() {
4077        // Populated-status corner pin: the primitive returns
4078        // `Some(ProcessPhase::default())` — a `ProcessStatus`
4079        // constructed via `default()` carries `phase: Pending`
4080        // because the phase field is a bare `ProcessPhase` (not
4081        // `Option<ProcessPhase>`), so there is NO "empty slot"
4082        // corner peer to the borrow-form projections' empty-slot
4083        // pins. A regression that reshaped the return type to
4084        // filter out `Pending` (treating it as "unset") would
4085        // surface here and silently break the top-level
4086        // dispatcher's Pending → Forking transition on a Process
4087        // freshly written by the reconciler.
4088        let p = process_with_phase(Some(ProcessPhase::default()));
4089        assert_eq!(p.observed_phase(), Some(ProcessPhase::Pending));
4090        assert_eq!(p.observed_phase(), Some(ProcessPhase::default()));
4091    }
4092
4093    #[test]
4094    fn observed_phase_returns_persisted_phase_when_status_is_populated() {
4095        // Happy-path pin: with a populated `status.phase` slot,
4096        // the primitive returns the persisted `ProcessPhase`.
4097        // A regression that filtered / reshaped / canonicalized
4098        // the phase would surface here rather than as silent
4099        // skew at the top-level dispatcher's phase handler
4100        // dispatch on the SAME Process.
4101        let p = process_with_phase(Some(ProcessPhase::Running));
4102        assert_eq!(p.observed_phase(), Some(ProcessPhase::Running));
4103    }
4104
4105    #[test]
4106    fn observed_phase_is_a_pure_projection() {
4107        // Purity pin: two consecutive calls return byte-identical
4108        // `Option<ProcessPhase>` values (no lazy materialization,
4109        // no interior mutation of `self`). Peer to the sibling
4110        // `observed_pid_is_a_pure_projection` +
4111        // `observed_flux_resources_is_a_pure_projection` +
4112        // `observed_attestation_is_a_pure_projection` pins; all
4113        // four bind the pure-projection discipline on the ONE
4114        // substrate accessor per status slot.
4115        let p = process_with_phase(Some(ProcessPhase::Attested));
4116        let a = p.observed_phase();
4117        let b = p.observed_phase();
4118        assert_eq!(a, b);
4119        assert_eq!(a, Some(ProcessPhase::Attested));
4120    }
4121
4122    #[test]
4123    fn observed_phase_matches_pre_lift_reconciler_chain_shape() {
4124        // Parity pin: sweeps the two corners every pre-lift
4125        // consumer plausibly encountered (missing status,
4126        // populated status with a particular phase) and compares
4127        // the substrate call against a hand-authored pre-lift
4128        // chain byte-identically. A regression that reshaped ANY
4129        // of the two corners would surface here rather than as
4130        // silent operator-facing skew between the top-level
4131        // dispatcher and any of the four other reconciler
4132        // consumers on the SAME `Process`.
4133        fn pre_lift(p: &Process) -> Option<ProcessPhase> {
4134            p.status.as_ref().map(|s| s.phase)
4135        }
4136        let mut p = Process::new("api", empty_spec());
4137        p.status = None;
4138        assert_eq!(p.observed_phase(), pre_lift(&p));
4139        let p = process_with_phase(Some(ProcessPhase::Running));
4140        assert_eq!(p.observed_phase(), pre_lift(&p));
4141        let p = process_with_phase(Some(ProcessPhase::Attested));
4142        assert_eq!(p.observed_phase(), pre_lift(&p));
4143        let p = process_with_phase(Some(ProcessPhase::Failed));
4144        assert_eq!(p.observed_phase(), pre_lift(&p));
4145    }
4146
4147    #[test]
4148    fn observed_phase_default_unwrap_matches_pre_lift_pending_default() {
4149        // Callsite-shape pin: three of the FIVE pre-lift consumers
4150        // (`controller::reconcile`, `boundary::evaluate_process_phase`,
4151        // `table_controller::stable_name_group_key`) closed the
4152        // 3-line chain with `.unwrap_or(ProcessPhase::Pending)`
4153        // (identical to `.unwrap_or_default()`). This pin binds
4154        // that call-site shape: `observed_phase().unwrap_or
4155        // (Pending)` returns `Pending` on missing status and the
4156        // persisted phase otherwise. A regression that swapped
4157        // the `None` sentinel's downstream default would surface
4158        // here rather than as silent skew at three of the five
4159        // consumer sites.
4160        let mut p = Process::new("api", empty_spec());
4161        p.status = None;
4162        assert_eq!(
4163            p.observed_phase().unwrap_or(ProcessPhase::Pending),
4164            ProcessPhase::Pending
4165        );
4166        let p = process_with_phase(Some(ProcessPhase::Running));
4167        assert_eq!(
4168            p.observed_phase().unwrap_or(ProcessPhase::Pending),
4169            ProcessPhase::Running
4170        );
4171    }
4172
4173    #[test]
4174    fn observed_phase_attested_unwrap_matches_pre_lift_released_from_default() {
4175        // Callsite-shape pin: the ONE pre-lift consumer
4176        // (`phase_machine::p_current_phase_str` — the
4177        // released-from annotation composer) closed the 3-line
4178        // chain with `.unwrap_or(ProcessPhase::Attested)` rather
4179        // than the `Default` (`Pending`). This pin binds that
4180        // call-site shape: `observed_phase().unwrap_or(Attested)`
4181        // returns `Attested` on missing status and the persisted
4182        // phase otherwise. A regression that folded the
4183        // `Attested`-default consumer into the `Pending`-default
4184        // majority would break the SIGSTOP/SIGCONT release gate's
4185        // "which annotation label to emit" branch — the pin binds
4186        // the primitive at the raw `Option<ProcessPhase>` form so
4187        // this default choice stays local at the callsite.
4188        let mut p = Process::new("api", empty_spec());
4189        p.status = None;
4190        assert_eq!(
4191            p.observed_phase().unwrap_or(ProcessPhase::Attested),
4192            ProcessPhase::Attested
4193        );
4194        let p = process_with_phase(Some(ProcessPhase::Failed));
4195        assert_eq!(
4196            p.observed_phase().unwrap_or(ProcessPhase::Attested),
4197            ProcessPhase::Failed
4198        );
4199    }
4200
4201    #[test]
4202    fn observed_phase_preserves_every_process_phase_variant() {
4203        // Round-trip pin: every `ProcessPhase` variant round-
4204        // trips through the primitive unchanged. Peer to the
4205        // sibling `observed_pid_preserves_hierarchical_pid_format`
4206        // pin's dotted-segment sweep; this pin sweeps the closed
4207        // set of `ProcessPhase` variants directly so a
4208        // canonicalization pass that dropped or reshaped one
4209        // (e.g. folded `Reconverging` back into `Execing`, or
4210        // remapped `Zombie` to `Reaped`) surfaces here rather
4211        // than as silent skew at the SIGSTOP/SIGCONT release
4212        // gate's phase-name annotation branch. Covers every
4213        // variant the `ProcessPhase::DeriveClosedSet` enumerates
4214        // so a future variant addition surfaces via the closed-
4215        // set macro rather than at a silent partial sweep.
4216        for phase in [
4217            ProcessPhase::Pending,
4218            ProcessPhase::Forking,
4219            ProcessPhase::Execing,
4220            ProcessPhase::Running,
4221            ProcessPhase::Attested,
4222            ProcessPhase::Reconverging,
4223            ProcessPhase::Releasing,
4224            ProcessPhase::Exiting,
4225            ProcessPhase::Failed,
4226            ProcessPhase::Zombie,
4227            ProcessPhase::Reaped,
4228        ] {
4229            let p = process_with_phase(Some(phase));
4230            assert_eq!(
4231                p.observed_phase(),
4232                Some(phase),
4233                "phase variant {phase:?} did not round-trip"
4234            );
4235        }
4236    }
4237
4238    // ─── Process::observed_phase_or_pending substrate pins ─────────────
4239    //
4240    // Pins the copy-form status-projection primitive on the phase
4241    // axis with the `Pending` sink applied. Sibling to the raw
4242    // `observed_phase_*` pin family on the (return-form × fallback
4243    // shape) axis pair — the raw-`Option` corner stays with the
4244    // sibling family; this pin family opens the `Pending`-defaulted
4245    // corner that four of the five pre-lift `observed_phase`
4246    // consumers wrote by hand. Fail-before-pass-after granularity:
4247    // `observed_phase_or_pending` did not exist pre-lift, so any
4248    // test invoking it fails to compile pre-lift and passes
4249    // post-lift.
4250
4251    #[test]
4252    fn observed_phase_or_pending_returns_pending_when_status_is_none() {
4253        // Missing-`status` corner pin: the primitive collapses the
4254        // no-status case to `Pending` — the sink four of the five
4255        // pre-lift `observed_phase` consumers wrote by hand
4256        // (`controller::reconcile` / `boundary::
4257        // evaluate_process_phase` / `table_controller::
4258        // stable_name_group_key` / `controller_pool::reconcile_pool`)
4259        // and the sentinel `ProcessPhase::default()` returns. A
4260        // regression that folded the `None` sink to any other phase
4261        // (e.g. `Forking` — treating "not yet observed" as "already
4262        // dispatched") would silently mis-seed the top-level
4263        // dispatcher's `Pending → Forking` transition and surface as
4264        // operator-visible reconcile-cycle skew on a freshly-forked
4265        // Process rather than at this pin.
4266        let mut p = Process::new("api", empty_spec());
4267        p.status = None;
4268        assert_eq!(p.observed_phase_or_pending(), ProcessPhase::Pending);
4269    }
4270
4271    #[test]
4272    fn observed_phase_or_pending_returns_persisted_phase_when_status_is_populated() {
4273        // Populated-status corner pin: the primitive passes through
4274        // the persisted `ProcessPhase` unchanged — the sink only
4275        // fires on missing `status`, not on a populated one carrying
4276        // a `Pending`-adjacent variant. Two variants pinned to
4277        // separate the "pass through the persisted phase" arm from
4278        // the "sink fires" arm: `Running` (mid-lifecycle) and
4279        // `Attested` (post-verify) both round-trip unchanged where
4280        // a regression that always returned `Pending` (dropped the
4281        // pass-through arm entirely) would surface here rather than
4282        // as silent skew at every reconciler's per-phase branch.
4283        let p = process_with_phase(Some(ProcessPhase::Running));
4284        assert_eq!(p.observed_phase_or_pending(), ProcessPhase::Running);
4285        let p = process_with_phase(Some(ProcessPhase::Attested));
4286        assert_eq!(p.observed_phase_or_pending(), ProcessPhase::Attested);
4287    }
4288
4289    #[test]
4290    fn observed_phase_or_pending_matches_pre_lift_unwrap_or_pending_chain_shape() {
4291        // Byte-identical parity pin: the primitive's return equals
4292        // the pre-lift two-link `.observed_phase().unwrap_or
4293        // (ProcessPhase::Pending)` chain at every one of the four
4294        // corner values (missing `status` → `Pending`, populated
4295        // with `Pending` → `Pending`, populated with a mid-lifecycle
4296        // variant → pass-through, populated with a terminal variant
4297        // → pass-through). A regression that swapped the sink to
4298        // `ProcessPhase::default()` (currently equivalent to
4299        // `Pending`) would keep this pin green until the enum's
4300        // `Default` impl drifted — the explicit `Pending` spelling
4301        // in the pin binds the operator-visible label rather than
4302        // the derived `Default`, so a future rename or reordering
4303        // of `ProcessPhase` variants that shifted `Default` off
4304        // `Pending` would surface here rather than as silent skew
4305        // at the four downstream consumer sites.
4306        let pre_lift = |p: &Process| p.observed_phase().unwrap_or(ProcessPhase::Pending);
4307        let mut p = Process::new("api", empty_spec());
4308        p.status = None;
4309        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4310        let p = process_with_phase(Some(ProcessPhase::Pending));
4311        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4312        let p = process_with_phase(Some(ProcessPhase::Running));
4313        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4314        let p = process_with_phase(Some(ProcessPhase::Reaped));
4315        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4316    }
4317
4318    #[test]
4319    fn observed_phase_or_pending_is_a_pure_projection() {
4320        // Purity pin: two back-to-back calls on the same `Process`
4321        // return the same `ProcessPhase` — the primitive stamps no
4322        // side effect (no clock read, no metadata write, no
4323        // `status` mutation) despite the sibling `observed_phase`
4324        // taking `&self` too. Peer to the sibling `observed_phase`
4325        // purity pin; a regression that folded a clock read (e.g.
4326        // "if the sink fired, stamp `phase_since = Utc::now()`")
4327        // into the primitive would surface here rather than at the
4328        // consumer sites' downstream reconcile-cycle behavior.
4329        let p = process_with_phase(Some(ProcessPhase::Running));
4330        let a = p.observed_phase_or_pending();
4331        let b = p.observed_phase_or_pending();
4332        assert_eq!(a, b);
4333    }
4334
4335    #[test]
4336    fn observed_phase_or_pending_preserves_every_process_phase_variant() {
4337        // Round-trip pin: every `ProcessPhase` variant round-trips
4338        // through the primitive unchanged when the `status` slot is
4339        // populated. Peer to the sibling `observed_phase_preserves
4340        // _every_process_phase_variant` sweep; this pin sweeps the
4341        // closed set through the `Pending`-sinked accessor rather
4342        // than the raw-`Option` accessor so a canonicalization pass
4343        // that dropped or reshaped one variant (e.g. folded
4344        // `Reconverging` back into `Execing`, remapped `Zombie` to
4345        // `Reaped`) surfaces at BOTH primitives' pin sets rather
4346        // than as silent skew at a subset of the reconciler
4347        // consumers. Covers every variant the
4348        // `ProcessPhase::DeriveClosedSet` enumerates so a future
4349        // variant addition surfaces via the closed-set macro rather
4350        // than at a silent partial sweep.
4351        for phase in [
4352            ProcessPhase::Pending,
4353            ProcessPhase::Forking,
4354            ProcessPhase::Execing,
4355            ProcessPhase::Running,
4356            ProcessPhase::Attested,
4357            ProcessPhase::Reconverging,
4358            ProcessPhase::Releasing,
4359            ProcessPhase::Exiting,
4360            ProcessPhase::Failed,
4361            ProcessPhase::Zombie,
4362            ProcessPhase::Reaped,
4363        ] {
4364            let p = process_with_phase(Some(phase));
4365            assert_eq!(
4366                p.observed_phase_or_pending(),
4367                phase,
4368                "phase variant {phase:?} did not round-trip through observed_phase_or_pending"
4369            );
4370        }
4371    }
4372
4373    // ─── Process::is_being_deleted substrate pins ───────────────────────
4374    //
4375    // Pins the copy-form metadata-projection primitive on the
4376    // deletion-tombstone axis. Peer to the borrow-form + copy-form
4377    // metadata-fallback family (`namespace_or_default`,
4378    // `name_or_placeholder`, `uid_or_empty`, `coordinates_or_defaults`,
4379    // `coordinates_or_none`, `owned_coordinates_or_err`, `annotation`);
4380    // this one opens the presence-probe corner for the tombstone slot.
4381    // Fail-before-pass-after granularity: `is_being_deleted` did not
4382    // exist pre-lift, so any test invoking it fails to compile pre-
4383    // lift and passes post-lift.
4384
4385    fn tombstoned_process() -> Process {
4386        let mut p = Process::new("api-gateway", empty_spec());
4387        p.metadata.namespace = Some("prod".into());
4388        p.metadata.deletion_timestamp = Some(k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(
4389            Utc::now(),
4390        ));
4391        p
4392    }
4393
4394    #[test]
4395    fn is_being_deleted_returns_false_when_deletion_timestamp_is_absent() {
4396        // Missing-tombstone corner pin: the primitive collapses the
4397        // no-tombstone case to `false` so the SIGTERM preempt at
4398        // `controller::reconcile` skips the `→ Exiting` forcing
4399        // branch and the DELETE-skip at `handle_exiting`'s child
4400        // fan-out does NOT `continue` past a child that is still
4401        // healthy. Matches the pre-lift `.is_some()` chain's `false`
4402        // byte-identically at every consumer's downstream gate.
4403        let mut p = Process::new("api", empty_spec());
4404        p.metadata.deletion_timestamp = None;
4405        assert!(!p.is_being_deleted());
4406    }
4407
4408    #[test]
4409    fn is_being_deleted_returns_true_when_deletion_timestamp_is_present() {
4410        // Present-tombstone corner pin: the primitive returns
4411        // `true` on any populated `metadata.deletionTimestamp`
4412        // slot regardless of the timestamp payload — the two
4413        // consumers only read the tombstone's PRESENCE, never
4414        // its RFC-3339 timestamp value. A regression that gated
4415        // the `true` return on the timestamp being non-epoch, or
4416        // parsed the timestamp before returning, would surface
4417        // here rather than as silent skew at the SIGTERM preempt
4418        // or child-fan-out DELETE-skip on the SAME `Process`.
4419        let p = tombstoned_process();
4420        assert!(p.is_being_deleted());
4421    }
4422
4423    #[test]
4424    fn is_being_deleted_is_a_pure_projection() {
4425        // Purity pin: two consecutive calls return byte-identical
4426        // `bool` values (no lazy materialization, no interior
4427        // mutation of `self`). Peer to the sibling
4428        // `observed_phase_is_a_pure_projection` +
4429        // `observed_pid_is_a_pure_projection` +
4430        // `observed_flux_resources_is_a_pure_projection` +
4431        // `observed_attestation_is_a_pure_projection` pins; all
4432        // five bind the pure-projection discipline on the ONE
4433        // substrate accessor per metadata / status slot.
4434        let p = tombstoned_process();
4435        let a = p.is_being_deleted();
4436        let b = p.is_being_deleted();
4437        assert_eq!(a, b);
4438        assert!(a);
4439    }
4440
4441    #[test]
4442    fn is_being_deleted_matches_pre_lift_reconciler_chain_shape() {
4443        // Parity pin: sweeps the two corners every pre-lift
4444        // consumer plausibly encountered (missing tombstone,
4445        // present tombstone) and compares the substrate call
4446        // against a hand-authored pre-lift chain byte-identically.
4447        // A regression that reshaped either corner would surface
4448        // here rather than as silent operator-facing skew between
4449        // the top-level dispatcher's SIGTERM preempt and the
4450        // SIGTERM cascade's child-fan-out DELETE-skip on the
4451        // SAME `Process` within one reconcile pass.
4452        fn pre_lift(p: &Process) -> bool {
4453            p.metadata.deletion_timestamp.is_some()
4454        }
4455        let mut p = Process::new("api", empty_spec());
4456        p.metadata.deletion_timestamp = None;
4457        assert_eq!(p.is_being_deleted(), pre_lift(&p));
4458        let p = tombstoned_process();
4459        assert_eq!(p.is_being_deleted(), pre_lift(&p));
4460    }
4461
4462    #[test]
4463    fn is_being_deleted_composes_with_process_phase_is_alive_at_reconcile_preempt() {
4464        // Call-site-shape pin: the `controller::reconcile` SIGTERM
4465        // preempt composes `is_being_deleted() && current_phase
4466        // .is_alive()` — the tombstone-presence probe AND the
4467        // alive-phase gate must BOTH hold to force `→ Exiting`.
4468        // A dead-phase (`Zombie` / `Reaped` / `Failed`) Process
4469        // that carries a tombstone still runs its normal handler,
4470        // not the preempt. This pin binds that composition shape
4471        // at the primitive so a regression that flipped either
4472        // half of the `&&` (or that broadened the tombstone probe
4473        // to include the `is_alive` half implicitly) surfaces
4474        // here rather than as silent skew at the top-level
4475        // dispatch on the SAME `Process`.
4476        let mut p = tombstoned_process();
4477        // Alive + tombstoned → preempt fires.
4478        let mut alive = ProcessStatus::default();
4479        alive.phase = ProcessPhase::Running;
4480        p.status = Some(alive);
4481        assert!(p.is_being_deleted());
4482        assert!(p.observed_phase().unwrap_or_default().is_alive());
4483        // Dead + tombstoned → preempt does NOT fire (composition
4484        // with `is_alive` returns false).
4485        let mut dead = ProcessStatus::default();
4486        dead.phase = ProcessPhase::Reaped;
4487        p.status = Some(dead);
4488        assert!(p.is_being_deleted());
4489        assert!(!p.observed_phase().unwrap_or_default().is_alive());
4490    }
4491
4492    // ─── Process::created_at substrate pins ─────────────────────────
4493    //
4494    // Pins the copy-form metadata-projection primitive on the
4495    // `metadata.creationTimestamp` axis that owns the
4496    // `.metadata.creation_timestamp.as_ref().map(|t| t.0)` chain the
4497    // three hand-authored sites (`lifetime_clock::evaluate`,
4498    // `lifetime_clock::requeue_with_ttl`,
4499    // `tatara-reconciler::table_controller`) restated by hand pre-lift.
4500    // Peer to the sibling `is_being_deleted_*` +
4501    // `observed_phase_*` pin families — all three primitives project a
4502    // wire-format `Option<T>` slot into a `Copy` inner value at ONE
4503    // owner. Fail-before-pass-after granularity: `created_at` did not
4504    // exist pre-lift, so any test invoking it fails to compile pre-lift
4505    // and passes post-lift.
4506
4507    fn creation_stamped_process(t: DateTime<Utc>) -> Process {
4508        let mut p = Process::new("age-anchor", empty_spec());
4509        p.metadata.namespace = Some("prod".into());
4510        p.metadata.creation_timestamp =
4511            Some(k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(t));
4512        p
4513    }
4514
4515    #[test]
4516    fn created_at_returns_none_when_creation_timestamp_is_absent() {
4517        // Missing-slot corner pin: the primitive collapses the
4518        // no-creation-timestamp case to `None` so the TTL-expiry gate
4519        // at `lifetime_clock::evaluate` short-circuits its inner
4520        // `if let Some(...)` branch (no elapsed computation), the
4521        // requeue-budget picker returns its default sleep, and the
4522        // stable-name arbiter's `.unwrap_or_else(Utc::now)` tail
4523        // synthesizes a "just created" anchor at its own site. Matches
4524        // the pre-lift `.as_ref().map(|t| t.0)` chain's `None`
4525        // byte-identically at every consumer's downstream tail.
4526        let mut p = Process::new("api", empty_spec());
4527        p.metadata.creation_timestamp = None;
4528        assert!(p.created_at().is_none());
4529    }
4530
4531    #[test]
4532    fn created_at_returns_some_datetime_when_slot_is_populated() {
4533        // Populated-slot corner pin: with a populated
4534        // `metadata.creationTimestamp` slot, the primitive unwraps the
4535        // wire-format `Time` newtype to its inner `DateTime<Utc>` and
4536        // returns it as `Some(datetime)` — hiding the `.0` field-access
4537        // every pre-lift consumer restated to reach the underlying
4538        // instant.
4539        let anchor = Utc::now() - chrono::Duration::seconds(300);
4540        let p = creation_stamped_process(anchor);
4541        assert_eq!(p.created_at(), Some(anchor));
4542    }
4543
4544    #[test]
4545    fn created_at_is_a_pure_projection() {
4546        // Purity pin: two consecutive calls return byte-identical
4547        // `Option<DateTime<Utc>>` values (no lazy materialization, no
4548        // interior mutation of `self`). Peer to the sibling
4549        // `is_being_deleted_is_a_pure_projection` +
4550        // `observed_phase_is_a_pure_projection` pins; all three bind
4551        // the pure-projection discipline on the ONE substrate accessor
4552        // per metadata / status slot.
4553        let anchor = Utc::now();
4554        let p = creation_stamped_process(anchor);
4555        let a = p.created_at();
4556        let b = p.created_at();
4557        assert_eq!(a, b);
4558        assert_eq!(a, Some(anchor));
4559    }
4560
4561    #[test]
4562    fn created_at_matches_pre_lift_creation_timestamp_chain_shape() {
4563        // Parity pin: sweeps the two corners every pre-lift consumer
4564        // plausibly encountered (missing slot, populated slot) and
4565        // compares the substrate call against a hand-authored pre-lift
4566        // chain byte-identically. A regression that reshaped either
4567        // corner (returning `Some(Utc::now())` on the missing slot,
4568        // returning a rounded / truncated timestamp on the populated
4569        // slot) would surface here rather than as silent operator-
4570        // facing skew between the TTL-expiry gate, the requeue-budget
4571        // picker, and the stable-name claim-arbiter tie-break on the
4572        // SAME `Process` within one reconcile pass.
4573        fn pre_lift(p: &Process) -> Option<DateTime<Utc>> {
4574            p.metadata.creation_timestamp.as_ref().map(|t| t.0)
4575        }
4576        // Missing slot.
4577        let mut p = Process::new("x", empty_spec());
4578        p.metadata.creation_timestamp = None;
4579        assert_eq!(p.created_at(), pre_lift(&p));
4580        // Populated slot.
4581        let anchor = Utc::now() - chrono::Duration::seconds(42);
4582        let p = creation_stamped_process(anchor);
4583        assert_eq!(p.created_at(), pre_lift(&p));
4584    }
4585
4586    #[test]
4587    fn created_at_composes_with_signed_duration_since_at_ttl_gate() {
4588        // Call-site-shape pin: the `lifetime_clock::evaluate` TTL-
4589        // expiry gate composes `now.signed_duration_since(creation)`
4590        // where `creation` is the `DateTime<Utc>` returned by this
4591        // primitive's `Some` corner. A regression that returned a
4592        // per-callsite `Local` timezone (or that stripped the timezone
4593        // marker) would break the arithmetic silently. This pin
4594        // computes the elapsed duration byte-identically against the
4595        // pre-lift `.map(|t| t.0)` chain so a timezone drift surfaces
4596        // here rather than as silent skew at the TTL-expiry decision
4597        // on the SAME `Process` within one reconcile pass.
4598        let now = Utc::now();
4599        let anchor = now - chrono::Duration::seconds(120);
4600        let p = creation_stamped_process(anchor);
4601        let via_primitive = p.created_at().expect("populated slot");
4602        let via_pre_lift = p
4603            .metadata
4604            .creation_timestamp
4605            .as_ref()
4606            .map(|t| t.0)
4607            .expect("populated slot");
4608        assert_eq!(
4609            now.signed_duration_since(via_primitive),
4610            now.signed_duration_since(via_pre_lift)
4611        );
4612    }
4613}