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::{EphemeralLifetime, 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    /// The copy-form status-projection primitive on the
1367    /// `status.phase_since` axis: returns the [`DateTime<Utc>`] the
1368    /// reconciler stamped when this Process last transitioned into its
1369    /// current [`ProcessPhase`], wrapped in an `Option` so BOTH the
1370    /// missing-`status` corner AND the empty-slot corner
1371    /// (`ProcessStatus.phase_since == None` — a freshly-forked Process
1372    /// whose reconciler has not yet stamped a first transition) collapse
1373    /// to `None` — the ONE-liner collapse of the paired
1374    /// `self.status.as_ref().and_then(|s| s.phase_since)` incantation
1375    /// the pool reconciler's per-owned-Process member-seed builder
1376    /// restated by hand pre-lift.
1377    ///
1378    /// Pre-lift the 5-line
1379    /// ```rust,ignore
1380    /// p.status
1381    ///     .as_ref()
1382    ///     .and_then(|s| s.phase_since)
1383    ///     .unwrap_or_else(Utc::now)
1384    /// ```
1385    /// chain was hand-authored at
1386    /// `tatara-pool-reconciler::controller_pool::reconcile_inner`'s
1387    /// per-owned-Process `PoolMember { entered_state_at: … }` seed —
1388    /// the row-builder that feeds `pool_phase_from_members` +
1389    /// `apply_pool_reconcile_decision` with each owned Process's
1390    /// last-observed transition instant. Post-lift the callsite reads
1391    /// `p.observed_phase_since().unwrap_or_else(Utc::now)`, a
1392    /// one-liner symmetric to the peer `p.created_at()
1393    /// .unwrap_or_else(Utc::now)` chain the sibling
1394    /// [`PoolMemberSnapshot`] `created_at` seed two branches below
1395    /// already routes through — closing the last raw
1396    /// `.status.as_ref()` chain on `Process` at that reconciler site.
1397    ///
1398    /// Return-form axis: `Option<DateTime<Utc>>` matches the copy-form
1399    /// discipline of the sibling metadata-projection primitive
1400    /// [`Self::created_at`] (both return `Option<DateTime<Utc>>` and
1401    /// hide the wire-format wrapper — `ProcessStatus` on the status
1402    /// side, `k8s_openapi::…::v1::Time` on the metadata side) so the
1403    /// two timestamp-projection primitives compose byte-uniformly at
1404    /// the pool reconciler's `PoolMember` / `PoolMemberSnapshot`
1405    /// seeds. Returning owned `DateTime<Utc>` with a
1406    /// substrate-injected `Utc::now()` fallback would fold an impure
1407    /// wall-clock read into the primitive, breaking the pure-
1408    /// projection discipline every peer `observed_*` accessor
1409    /// follows; the sink stays at the callsite where it composes with
1410    /// [`Self::created_at`]'s identical `.unwrap_or_else(Utc::now)`
1411    /// tail.
1412    ///
1413    /// Peer to the copy-form status-projection primitive
1414    /// [`Self::observed_phase`] on the (return-shape × status-slot)
1415    /// axis pair — both walk the paired `.status.as_ref().<map|and_then>
1416    /// (|s| s.<slot>)` chain and both project a `Copy` inner from a
1417    /// wire slot whose "not yet observed" corner collapses to `None`.
1418    /// [`Self::observed_phase`] projects the `phase` slot (a bare
1419    /// [`ProcessPhase`] with a `Default` sentinel — collapses only on
1420    /// missing `status`); this method projects the `phase_since` slot
1421    /// (an `Option<DateTime<Utc>>` with no sentinel — collapses on
1422    /// missing `status` OR on empty slot). The paired
1423    /// `.map` vs `.and_then` choice tracks the difference: the raw
1424    /// slot is `Option<DateTime<Utc>>` here so the closure returns an
1425    /// `Option` and the outer combinator flattens through `.and_then`,
1426    /// where `observed_phase`'s raw slot is a bare `ProcessPhase` so
1427    /// the closure returns a bare value and the outer combinator maps
1428    /// through `.map`. Future status-timestamp projections (an
1429    /// `observed_last_boundary_check` on
1430    /// [`crate::status::BoundaryStatus.last_check`], an
1431    /// `observed_last_export_receipt` on a future receipt-observation
1432    /// slot) land as peer methods on this same axis.
1433    ///
1434    /// A future normalization step (a per-cluster clock-skew guard
1435    /// that offsets the returned timestamp by the observing controller's
1436    /// measured skew, a canonicalization pass that maps a suspiciously-
1437    /// zero `phase_since` to `None` so consumers' `.unwrap_or_else
1438    /// (Utc::now)` tails synthesize a fresh anchor, a staleness gate
1439    /// that drops a `phase_since` predating a reconcile deadline) lands
1440    /// at ONE substrate method here and every downstream consumer
1441    /// picks up the upgrade mechanically — no per-callsite hand-edit
1442    /// at `reconcile_inner`'s member-seed builder.
1443    ///
1444    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1445    /// the paired `.status.as_ref().and_then(|s| s.phase_since)` chain
1446    /// closes the last raw `.status.as_ref()` chain in
1447    /// `tatara-pool-reconciler`'s production reconciler code on
1448    /// `Process`, and is lifted to ONE substrate owner here alongside
1449    /// the sibling `observed_phase` / `observed_phase_or_pending` /
1450    /// `observed_identity` / `observed_pid` / `observed_attestation` /
1451    /// `observed_flux_resources` primitives that closed their axes
1452    /// previously). THEORY.md §II.1 invariant 5 (composition preserves
1453    /// proofs — the pins bind the missing-`status` corner + the empty-
1454    /// slot corner + the populated-slot pass-through + the pure-
1455    /// projection discipline + the byte-identical parity with the pre-
1456    /// lift `.status.as_ref().and_then(|s| s.phase_since)` chain + the
1457    /// composition-shape agreement with [`Self::created_at`]'s
1458    /// identical `.unwrap_or_else(Utc::now)` tail at the peer
1459    /// pool-reconciler seed, so a regression that drifted any surface
1460    /// at `tests::observed_phase_since_*` rather than as silent
1461    /// operator-facing skew between the `PoolMember` row's observed-
1462    /// transition anchor and the `PoolMemberSnapshot`'s creation-
1463    /// timestamp anchor on the SAME owned `Process` within one
1464    /// reconcile pass).
1465    #[must_use]
1466    pub fn observed_phase_since(&self) -> Option<DateTime<Utc>> {
1467        self.status.as_ref().and_then(|s| s.phase_since)
1468    }
1469
1470    /// Pure composer over [`Self::observed_phase_since`] that folds the
1471    /// paired `.unwrap_or(fallback)` sink into ONE substrate owner — the
1472    /// ONE-liner collapse of the paired
1473    /// `p.observed_phase_since().unwrap_or_else(Utc::now)` incantation
1474    /// the pool-reconciler consumer restated by hand pre-lift, and the
1475    /// status-slot peer of the sibling [`Self::created_at_or`] composer
1476    /// on the metadata-timestamp axis. The wall-clock read stays at the
1477    /// callsite (as `Utc::now()` passed in positionally) so the composer
1478    /// itself stays pure — matching the discipline every peer `observed_*`
1479    /// / `created_at` copy-form projection follows and the explicit
1480    /// warning against a substrate-injected `Utc::now()` fallback that
1481    /// [`Self::observed_phase_since`]'s doc already spelled out.
1482    ///
1483    /// Pre-lift the paired 2-step
1484    /// `.observed_phase_since().unwrap_or_else(Utc::now)` chain was hand-
1485    /// authored at THREE workspace-wide sites past the ★★ PRIME-DIRECTIVE
1486    /// ≥ 2 duplication threshold, all stamping the SAME wall-clock
1487    /// fallback on the same missing-`phase_since` corner:
1488    /// * `tatara-pool-reconciler::controller_pool::reconcile_inner` —
1489    ///   the per-owned-Process `PoolMember { entered_state_at, .. }`
1490    ///   seed feeding `pool_phase_from_members` +
1491    ///   `apply_pool_reconcile_decision`. A freshly-forked pool member
1492    ///   whose reconciler has not yet stamped a first phase-transition
1493    ///   gets `Utc::now()` synthesized so the observed-transition
1494    ///   anchor sorts as "just entered" rather than short-circuiting
1495    ///   on the missing slot.
1496    /// * `tatara-process::crd::tests::
1497    ///   observed_phase_since_composes_with_unwrap_or_else_utc_now_tail_at_pool_seed`
1498    ///   — the call-site-shape pin that binds the composed tail's
1499    ///   behavior on both the populated corner (fallback silent) and
1500    ///   the empty corner (fallback fires). Two hand-authored
1501    ///   restatements inside the single test pin the same 2-step chain
1502    ///   at fail-before-pass-after granularity.
1503    ///
1504    /// All THREE sites walked the SAME `.unwrap_or_else(Utc::now)` tail
1505    /// on the SAME [`Self::observed_phase_since`] pure projection and
1506    /// all THREE wanted the resolved `DateTime<Utc>` the composer
1507    /// returns. Post-lift each production callsite reads
1508    /// `p.observed_phase_since_or(Utc::now())` and the produced value
1509    /// feeds the same downstream slot unchanged; the test pin retains
1510    /// the pre-lift `.unwrap_or_else(Utc::now)` composition to bind the
1511    /// pure-projection primitive's own byte-identical behavior while a
1512    /// peer test pin binds this composer's byte-identical parity.
1513    ///
1514    /// The `fallback: DateTime<Utc>` parameter (rather than a
1515    /// substrate-injected `Utc::now()`) keeps the composer pure — a
1516    /// test with a fixed-clock harness passes its own frozen anchor, a
1517    /// production consumer passes `Utc::now()`, both go through the
1518    /// same primitive without the composer itself reaching for the
1519    /// wall clock. This resolves exactly the tension
1520    /// [`Self::observed_phase_since`]'s doc spelled out (a buried
1521    /// `Utc::now()` fallback "would fold an impure wall-clock read
1522    /// into the primitive, breaking the pure-projection discipline
1523    /// every peer `observed_*` accessor follows") by lifting the
1524    /// composition shape, not the wall-clock read.
1525    ///
1526    /// Return-form axis: `DateTime<Utc>` matches the `unwrap_or`-style
1527    /// composer discipline of `Option::unwrap_or` in std — takes the
1528    /// pure projection, an owned fallback, returns the resolved owned
1529    /// value. Peer to the substrate composer [`Self::created_at_or`]
1530    /// on the metadata-timestamp axis — both lift a
1531    /// `.unwrap_or(<fallback>)` tail into ONE substrate site so the
1532    /// fallback-shape decision lives at ONE owner per axis; the two
1533    /// timestamp-projection composers on `Process` (metadata-timestamp
1534    /// [`Self::created_at_or`] + status-timestamp [`Self`]) now
1535    /// compose byte-uniformly at the pool reconciler's per-member row
1536    /// builder, closing the last hand-authored `.unwrap_or_else(Utc::
1537    /// now)` tail on `Process` in that reconciler's production code.
1538    ///
1539    /// A future normalization step (a per-cluster clock-skew guard
1540    /// that offsets the returned timestamp by the observing
1541    /// controller's measured skew before applying the fallback, a
1542    /// canonicalization pass that folds a suspiciously-zero
1543    /// `phase_since` to the fallback rather than accepting it, a
1544    /// staleness gate that treats a `phase_since` predating a
1545    /// reconcile deadline as unobserved and falls through to the
1546    /// fallback) lands at ONE substrate method here and every
1547    /// downstream consumer picks up the upgrade mechanically — no
1548    /// per-callsite hand-edit at
1549    /// `controller_pool::reconcile_inner`'s member-seed builder or at
1550    /// any future observed-transition consumer (a stable-name claim-
1551    /// arbiter age tie-break on the status-transition anchor, a
1552    /// per-pool dwell-time reap probe on the same slot).
1553    ///
1554    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1555    /// the paired `.observed_phase_since().unwrap_or_else(Utc::now)`
1556    /// chain recurred at three hand-authored sites past the ★★
1557    /// PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
1558    /// owner here alongside the sibling [`Self::created_at_or`] on
1559    /// the metadata-timestamp axis). THEORY.md §II.1 invariant 5
1560    /// (composition preserves proofs — the pins bind the missing-slot
1561    /// fallback corner + the populated-slot pass-through + the pure-
1562    /// composer discipline + the byte-identical parity with the
1563    /// pre-lift `.unwrap_or(fallback)` chain, so a regression that
1564    /// drifted any surface at `tests::observed_phase_since_or_*`
1565    /// rather than as silent operator-facing skew between the
1566    /// `PoolMember` row's observed-transition anchor and any future
1567    /// observed-transition consumer on the SAME `Process` within one
1568    /// reconcile pass).
1569    #[must_use]
1570    pub fn observed_phase_since_or(&self, fallback: DateTime<Utc>) -> DateTime<Utc> {
1571        self.observed_phase_since().unwrap_or(fallback)
1572    }
1573
1574    /// Copy-form metadata-projection primitive on the deletion-tombstone
1575    /// axis: returns `true` iff the K8s API server has stamped a
1576    /// `metadata.deletionTimestamp` on this Process (the moment the
1577    /// object entered the "being deleted" corner of its lifecycle,
1578    /// after which further mutating writes are refused and finalizers
1579    /// are drained before the object is actually removed) — the ONE-
1580    /// liner collapse of the paired `self.metadata.deletion_timestamp
1581    /// .is_some()` incantation every consumer restated by hand
1582    /// pre-lift.
1583    ///
1584    /// Pre-lift the `.metadata.deletion_timestamp.is_some()` chain
1585    /// was hand-authored at TWO sites past the ★★ PRIME-DIRECTIVE
1586    /// ≥ 2 duplication threshold in `tatara-reconciler`, both
1587    /// projecting the SAME tombstone-presence predicate on a
1588    /// `Process` value:
1589    /// * `controller::reconcile` — the top-level dispatcher's
1590    ///   deletion-preempt gate that forces the SIGTERM cascade
1591    ///   (`→ Exiting`) as soon as the API server stamps the
1592    ///   tombstone, before the phase handler for the current
1593    ///   [`ProcessPhase`] gets a chance to run. Composed with
1594    ///   [`ProcessPhase::is_alive`] so the preempt only fires on a
1595    ///   Process still in an alive phase — a Process already in
1596    ///   `Zombie` / `Reaped` / `Failed` runs its normal handler.
1597    /// * `phase_machine::handle_exiting` — the SIGTERM cascade's
1598    ///   child-fan-out loop that enumerates every child Process and
1599    ///   skips ones the API server has already tombstoned (so the
1600    ///   reconciler does not re-issue a `DELETE` against a child
1601    ///   whose deletion the API server is already draining through
1602    ///   its own finalizer). The skip composes with
1603    ///   [`Self::coordinates_or_none`]'s name-required probe so a
1604    ///   child missing either its tombstone-absent gate or its
1605    ///   `metadata.name` slot is a clean `continue` rather than an
1606    ///   attempted `child_api.delete("")` no-op.
1607    ///
1608    /// Both sites walked the SAME `.metadata.deletion_timestamp
1609    /// .is_some()` chain and both wanted the `bool` form the
1610    /// primitive returns — the `controller::reconcile` site to gate
1611    /// the SIGTERM preempt with `&& current_phase.is_alive()` and
1612    /// the `handle_exiting` site to gate the DELETE-skip with a
1613    /// bare `if child.is_being_deleted() { continue; }`. Post-lift
1614    /// each callsite reads `process.is_being_deleted()` and the
1615    /// produced `bool` feeds the same downstream gate unchanged.
1616    ///
1617    /// Return-form axis: `bool` matches the copy-form discipline of
1618    /// [`Self::observed_phase`] (an `Option<Copy>` scalar) — the
1619    /// underlying slot is a wire-format `Option<Time>` that carries
1620    /// only presence information at this axis (the RFC-3339 timestamp
1621    /// payload itself is not what the two consumers read; both only
1622    /// probe presence to detect the tombstone-stamped state).
1623    /// Returning the raw `Option<&Time>` would push the `.is_some()`
1624    /// probe back to every callsite, restating the pre-lift chain
1625    /// one link shorter without collapsing the primitive.
1626    ///
1627    /// Peer to the metadata-fallback primitives
1628    /// [`Self::namespace_or_default`], [`Self::name_or_placeholder`],
1629    /// [`Self::uid_or_empty`], [`Self::coordinates_or_defaults`],
1630    /// [`Self::coordinates_or_none`], [`Self::owned_coordinates_or_err`],
1631    /// [`Self::annotation`] on the metadata axis; this method opens
1632    /// the copy-form peer for the presence-probe corner. Future
1633    /// metadata-presence projections (an `is_being_finalized`
1634    /// projection on `metadata.finalizers.is_empty()`'s negation,
1635    /// a `has_owner` projection on `metadata.owner_references.is_empty()`'s
1636    /// negation) land as peer methods on this same axis.
1637    ///
1638    /// A future normalization step (a per-tombstone staleness gate
1639    /// that returns `false` for a tombstone older than the reconciler's
1640    /// grace-period budget, a canonicalization pass that treats a
1641    /// tombstone from a paused controller as absent, a cross-cluster
1642    /// tombstone-observation clock skew guard) lands at ONE substrate
1643    /// method here and both downstream consumers pick up the upgrade
1644    /// mechanically — no per-callsite hand-edit at
1645    /// `controller::reconcile` / `phase_machine::handle_exiting`.
1646    ///
1647    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1648    /// the `.metadata.deletion_timestamp.is_some()` chain recurred at
1649    /// two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
1650    /// duplication trigger, and is lifted to ONE owner here).
1651    /// THEORY.md §II.1 invariant 5 (composition preserves proofs —
1652    /// the pins bind the missing-tombstone corner + the present-
1653    /// tombstone corner + the copy-form `bool` return + the byte-
1654    /// identical parity with the pre-lift `.is_some()` chain, so a
1655    /// regression that drifted any surface at
1656    /// `tests::is_being_deleted_*` rather than as silent operator-
1657    /// facing skew between the top-level dispatcher's SIGTERM
1658    /// preempt and the SIGTERM cascade's child-fan-out DELETE-skip
1659    /// on the SAME `Process` within one reconcile pass).
1660    pub fn is_being_deleted(&self) -> bool {
1661        self.metadata.deletion_timestamp.is_some()
1662    }
1663
1664    /// Copy-form metadata-projection primitive on the
1665    /// `metadata.creationTimestamp` axis: returns the K8s-API-server-
1666    /// assigned creation moment as a `DateTime<Utc>`, hiding the wire-
1667    /// format `k8s_openapi::apimachinery::pkg::apis::meta::v1::Time`
1668    /// newtype behind an inherent projection — the ONE-liner collapse
1669    /// of the paired `self.metadata.creation_timestamp.as_ref().map(|t|
1670    /// t.0)` incantation every timestamp-driven consumer restated by
1671    /// hand pre-lift.
1672    ///
1673    /// Pre-lift the paired `.metadata.creation_timestamp.as_ref()` +
1674    /// `t.0` unwrap chain was hand-authored at THREE sites past the
1675    /// ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold across the
1676    /// workspace, all projecting the SAME creation-moment `DateTime<Utc>`
1677    /// on a `Process`:
1678    /// * `tatara-process::lifetime_clock::evaluate` — TTL-expiry gate
1679    ///   in the ephemeral-lifetime decision (`elapsed = now
1680    ///   .signed_duration_since(creation.0)`), inside the non-terminal-
1681    ///   phase guard that fires the `AutoTerminate::Now { TtlExpired }`
1682    ///   branch. Pre-lift the site read `if let Some(creation) = process
1683    ///   .metadata.creation_timestamp.as_ref() { ... creation.0 ... }`.
1684    /// * `tatara-process::lifetime_clock::requeue_with_ttl` — sleep-
1685    ///   budget picker for the reconciler's next requeue, choosing the
1686    ///   smaller of HEARTBEAT and TTL-remaining so the reconciler
1687    ///   doesn't oversleep past a TTL boundary. Pre-lift the site read
1688    ///   `let Some(creation) = process.metadata.creation_timestamp
1689    ///   .as_ref() else { return default; };` + `creation.0`.
1690    /// * `tatara-reconciler::table_controller::reconcile_process_table`
1691    ///   — stable-name claim-arbiter row builder, seeding each
1692    ///   candidate row's `created_at` for the tie-break ordering
1693    ///   (oldest wins). Pre-lift the site read `p.metadata
1694    ///   .creation_timestamp.as_ref().map(|t| t.0).unwrap_or_else(Utc
1695    ///   ::now)`.
1696    ///
1697    /// All THREE sites walked the SAME two-link chain — read the
1698    /// `Option<Time>` slot as a borrow, then unwrap the `Time` newtype
1699    /// to its inner `DateTime<Utc>` — differing only in the tail
1700    /// (`if-let-Some` guard, `let-else` short-circuit, `Utc::now`
1701    /// fallback). Post-lift each callsite reads
1702    /// `process.created_at()` and applies its own tail at its own site
1703    /// (`if let Some(creation) = ...`, `let Some(creation) = ... else`,
1704    /// `.unwrap_or_else(Utc::now)`).
1705    ///
1706    /// Return-form axis: `Option<DateTime<Utc>>` matches the copy-form
1707    /// discipline of the sibling status-projection primitive
1708    /// [`Self::observed_phase`] — both return `Option<T>` where `T:
1709    /// Copy` and hide the wire-format wrapper (`ProcessStatus` on the
1710    /// status side; `Time` on the metadata side). Returning the raw
1711    /// `Option<&Time>` would push the `.0` unwrap back to every
1712    /// callsite, restating the pre-lift chain one link shorter without
1713    /// collapsing the primitive; returning owned `Option<Time>` would
1714    /// force a `Time` import at every consumer for a projection every
1715    /// consumer immediately discards past `.0`.
1716    ///
1717    /// Peer to the metadata-fallback + presence-probe primitives
1718    /// [`Self::namespace_or_default`], [`Self::name_or_placeholder`],
1719    /// [`Self::uid_or_empty`], [`Self::coordinates_or_defaults`],
1720    /// [`Self::coordinates_or_none`], [`Self::owned_coordinates_or_err`],
1721    /// [`Self::annotation`], [`Self::is_being_deleted`] on the metadata
1722    /// axis; this method opens the copy-form timestamp corner. Future
1723    /// metadata-timestamp projections (a
1724    /// `deletion_at() -> Option<DateTime<Utc>>` peer on the
1725    /// tombstone-payload axis for staleness gates that need the
1726    /// timestamp value alongside the presence bit) land as peer
1727    /// methods on this same axis.
1728    ///
1729    /// A future normalization step (a per-cluster clock-skew guard
1730    /// that offsets the returned timestamp by the observing controller's
1731    /// measured skew, a canonicalization pass that maps a suspiciously-
1732    /// zero creation moment to `None`, a per-namespace override that
1733    /// substitutes a `spec.identity`-declared creation anchor for the
1734    /// metadata slot on adopted resources) lands at ONE substrate
1735    /// method here and all three downstream consumers pick up the
1736    /// upgrade mechanically — no per-callsite hand-edit at `evaluate`
1737    /// / `requeue_with_ttl` / `reconcile_process_table`.
1738    ///
1739    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1740    /// the `.metadata.creation_timestamp.as_ref().map(|t| t.0)` chain
1741    /// recurred at three hand-authored sites past the ★★
1742    /// PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
1743    /// owner here). THEORY.md §II.1 invariant 5 (composition preserves
1744    /// proofs — the pins bind the missing-timestamp corner + the
1745    /// present-timestamp corner + the copy-form `DateTime<Utc>` return
1746    /// + the byte-identical parity with the pre-lift `.as_ref().map(|t|
1747    /// t.0)` chain, so a regression that drifted any surface at
1748    /// `tests::created_at_*` rather than as silent operator-facing
1749    /// skew between the TTL-expiry gate, the requeue-budget picker,
1750    /// and the stable-name claim-arbiter tie-break on the SAME
1751    /// `Process` within one reconcile pass).
1752    pub fn created_at(&self) -> Option<DateTime<Utc>> {
1753        self.metadata.creation_timestamp.as_ref().map(|t| t.0)
1754    }
1755
1756    /// Pure composer over [`Self::created_at`] that folds the paired
1757    /// `.unwrap_or(fallback)` sink into ONE substrate owner — the
1758    /// ONE-liner collapse of the paired
1759    /// `p.created_at().unwrap_or_else(Utc::now)` incantation the two
1760    /// production consumers restated by hand pre-lift, with the
1761    /// wall-clock read kept at the callsite (as `Utc::now()` passed in
1762    /// positionally) so the primitive itself stays pure — matching the
1763    /// discipline every peer `observed_*` / `created_at` copy-form
1764    /// projection follows and the explicit warning against a
1765    /// substrate-injected `Utc::now()` fallback that
1766    /// [`Self::observed_phase_since`]'s doc already spelled out.
1767    ///
1768    /// Pre-lift the paired 2-step
1769    /// `.created_at().unwrap_or_else(Utc::now)` chain was hand-authored
1770    /// at TWO production sites past the ★★ PRIME-DIRECTIVE ≥ 2
1771    /// duplication threshold, both stamping the SAME wall-clock
1772    /// fallback on the same missing-timestamp corner:
1773    /// * `tatara-reconciler::table_controller::reconcile_process_table` —
1774    ///   the per-Process claim-row's `created_at` anchor that feeds
1775    ///   the stable-name group's tie-break comparator; a freshly-forked
1776    ///   Process whose API server has not yet stamped
1777    ///   `metadata.creationTimestamp` gets `Utc::now()` synthesized so
1778    ///   the tie-break sorts by "just-created" order rather than
1779    ///   short-circuiting on the missing slot.
1780    /// * `tatara-pool-reconciler::controller_pool::reconcile_inner`'s
1781    ///   desired-count `PoolMemberSnapshot { created_at, .. }` seed —
1782    ///   the per-owned-Process snapshot fed to
1783    ///   `decide_pool_convergence`, whose stability arithmetic
1784    ///   subtracts the anchor from `now` to compute the observed dwell
1785    ///   time; the same "just-created" fallback keeps a freshly-spawned
1786    ///   pool member from being reaped as if it were a stale zombie.
1787    ///
1788    /// Both sites walked the SAME `.unwrap_or_else(Utc::now)` tail on
1789    /// the SAME [`Self::created_at`] pure projection and both wanted
1790    /// the resolved `DateTime<Utc>` the composer returns. Post-lift
1791    /// each callsite reads `p.created_at_or(Utc::now())` and the
1792    /// produced value feeds the same downstream slot unchanged.
1793    ///
1794    /// The `fallback: DateTime<Utc>` parameter (rather than a
1795    /// substrate-injected `Utc::now()`) keeps the composer pure — a
1796    /// test with a fixed-clock harness passes its own frozen anchor, a
1797    /// production consumer passes `Utc::now()`, both go through the
1798    /// same primitive without the composer itself reaching for the
1799    /// wall clock. This resolves the tension the sibling
1800    /// [`Self::observed_phase_since`]'s doc spelled out (a buried
1801    /// `Utc::now()` fallback "would fold an impure wall-clock read
1802    /// into the primitive, breaking the pure-projection discipline
1803    /// every peer `observed_*` accessor follows") by lifting the
1804    /// composition shape, not the wall-clock read.
1805    ///
1806    /// Return-form axis: `DateTime<Utc>` matches the `unwrap_or`-style
1807    /// composer discipline of `Option::unwrap_or` in std — takes the
1808    /// pure projection, an owned fallback, returns the resolved owned
1809    /// value. Peer to the substrate composers
1810    /// [`Self::observed_phase_or_pending`] on the status-phase axis and
1811    /// [`Self::coordinates_or_defaults`] on the metadata-coordinate
1812    /// axis; all three lift a `.unwrap_or(<fallback>)` tail into ONE
1813    /// substrate site so the fallback-shape decision lives at ONE
1814    /// owner per axis.
1815    ///
1816    /// A future normalization step (a per-cluster clock-skew guard
1817    /// that offsets the returned timestamp by the observing
1818    /// controller's measured skew before applying the fallback, a
1819    /// canonicalization pass that folds a suspiciously-zero
1820    /// `creationTimestamp` to the fallback rather than accepting it,
1821    /// a per-namespace override that substitutes a `spec.identity`-
1822    /// declared creation anchor for the metadata slot on adopted
1823    /// resources) lands at ONE substrate method here and both
1824    /// downstream consumers pick up the upgrade mechanically — no
1825    /// per-callsite hand-edit at `reconcile_process_table` /
1826    /// `reconcile_inner`.
1827    ///
1828    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1829    /// the paired `.created_at().unwrap_or_else(Utc::now)` chain
1830    /// recurred at two hand-authored sites past the ★★
1831    /// PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
1832    /// owner here). THEORY.md §II.1 invariant 5 (composition
1833    /// preserves proofs — the pins bind the missing-slot fallback
1834    /// corner + the populated-slot pass-through + the pure-composer
1835    /// discipline + the byte-identical parity with the pre-lift
1836    /// `.unwrap_or(fallback)` chain, so a regression that drifted
1837    /// any surface at `tests::created_at_or_*` rather than as
1838    /// silent operator-facing skew between the claim-arbiter's
1839    /// tie-break anchor and the pool convergence snapshot's dwell-time
1840    /// anchor on the SAME `Process` within one reconcile pass).
1841    #[must_use]
1842    pub fn created_at_or(&self, fallback: DateTime<Utc>) -> DateTime<Utc> {
1843        self.created_at().unwrap_or(fallback)
1844    }
1845
1846    /// Wall-clock-anchored peer of [`Self::created_at_or`] — reads
1847    /// `Utc::now()` at call time and forwards it into the pure composer's
1848    /// `fallback` slot so the wall-clock projection lives at ONE
1849    /// substrate site rather than at each production callsite.
1850    ///
1851    /// # Why it exists
1852    ///
1853    /// Pre-lift the 2-arg `p.created_at_or(Utc::now())` chain was
1854    /// hand-authored at TWO production sites past the ★★ PRIME-DIRECTIVE
1855    /// ≥ 2 duplication threshold, each pairing the pure
1856    /// [`Self::created_at_or`] composer with a `Utc::now()` fallback
1857    /// argument at a per-Process anchor seed:
1858    ///
1859    /// * `tatara-reconciler::table_controller::reconcile_process_table`
1860    ///   — the per-Process claim-row `created_at` anchor feeding the
1861    ///   stable-name group's tie-break comparator; a freshly-forked
1862    ///   Process whose API server has not yet stamped
1863    ///   `metadata.creationTimestamp` gets the wall-clock read
1864    ///   synthesized so the tie-break sorts by "just-created" order
1865    ///   rather than short-circuiting on the missing slot.
1866    /// * `tatara-pool-reconciler::controller_pool::reconcile_inner`'s
1867    ///   desired-count `PoolMemberSnapshot { created_at, .. }` seed —
1868    ///   the per-owned-Process snapshot fed to
1869    ///   `decide_pool_convergence`, whose stability arithmetic
1870    ///   subtracts the anchor from `now` to compute observed dwell
1871    ///   time; the same "just-created" wall-clock fallback keeps a
1872    ///   freshly-spawned pool member from being reaped as a stale
1873    ///   zombie.
1874    ///
1875    /// Both sites walked the SAME 2-arg call with the SAME `Utc::now()`
1876    /// fallback — the wall-clock projection had no per-callsite
1877    /// variation. Post-lift both consumers share ONE substrate owner
1878    /// for the wall-clock-at-tick projection; a future clock swap (a
1879    /// monotonic clock cross-check, a per-reconciler injected time
1880    /// source, a test-only override at the production callsite via
1881    /// feature flag) lands at ONE substrate function and both anchor
1882    /// seeds inherit the upgrade mechanically.
1883    ///
1884    /// The 2-arg [`Self::created_at_or`] peer stays load-bearing for
1885    /// this crate's own test suite — the injected-`fallback` shape is
1886    /// what unit tests use to drive the fallback anchor deterministically
1887    /// (every `p.created_at_or(seeded_anchor)` in the pin family below
1888    /// reads that surface). This peer is production-only: pinning the
1889    /// wall-clock at the substrate site means no test can accidentally
1890    /// consume `created_at_or_now` without the deterministic-clock
1891    /// injection that makes the test meaningful.
1892    ///
1893    /// Sibling of the wall-clock-anchored peer family across the
1894    /// workspace's timed-decision axes:
1895    /// [`crate::pool::PoolStatus::observed_now`] on the
1896    /// `PoolStatus`-observation axis,
1897    /// [`crate::allocation::AllocationStatus::transition_now`] on the
1898    /// `AllocationStatus`-transition axis, and
1899    /// [`crate::lifetime_clock::evaluate_now`] on the
1900    /// `AutoTerminate` timed-decision axis. All four primitives own the
1901    /// "read the wall clock at tick-time" projection on a peer
1902    /// clock-injectable pure composer so the workspace's
1903    /// wall-clock-anchored peer family stays uniform across every
1904    /// production callsite.
1905    ///
1906    /// # Invariants
1907    ///
1908    /// - **Same shape:** returns the SAME `DateTime<Utc>` the 2-arg
1909    ///   [`Self::created_at_or`] returns when passed `Utc::now()` as
1910    ///   the fallback argument. This is a delegation, not a
1911    ///   re-implementation.
1912    /// - **Wall-clock read once:** `Utc::now()` is called exactly ONCE
1913    ///   per invocation, at the primitive's body, so a future consumer
1914    ///   that chains two `created_at_or_now` calls back-to-back still
1915    ///   sees monotonic `now` reads (each call reads a fresh instant,
1916    ///   not a cached one) — matches the pre-lift shape where each of
1917    ///   the two anchor sites computed its own `Utc::now()` at its own
1918    ///   line.
1919    ///
1920    /// # `#[must_use]`
1921    ///
1922    /// Every consumer feeds the returned `DateTime<Utc>` into a
1923    /// downstream slot (`ClaimRecord.created_at`, `PoolMemberSnapshot
1924    /// .created_at`). Dropping the return means the anchor was
1925    /// computed for no observable reason — the attribute surfaces that
1926    /// as a warning at every call site.
1927    ///
1928    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
1929    /// the 2-arg call with `Utc::now()` as the fallback argument
1930    /// recurred at 2 hand-authored sites past the ★★ PRIME-DIRECTIVE
1931    /// ≥ 2 duplication trigger, lifted onto the ONE workspace-wide
1932    /// substrate owner here). THEORY.md §II.1 invariant 5 (composition
1933    /// preserves proofs — the wall-clock projection lives at ONE site
1934    /// so a future clock swap reaches both consumers through one
1935    /// edit).
1936    #[must_use]
1937    pub fn created_at_or_now(&self) -> DateTime<Utc> {
1938        self.created_at_or(Utc::now())
1939    }
1940
1941    /// Compound spec-projection primitive on the `spec.lifetime` axis:
1942    /// returns `Some(&e)` iff the resolver unambiguously picks the
1943    /// `Ephemeral` slot, `None` otherwise — the ONE-liner collapse of
1944    /// the 4-step `self.spec.lifetime.resolved_ephemeral()` chain the
1945    /// two `lifetime_clock` consumers previously reached through and
1946    /// the coherence-tightening lift of the naked
1947    /// `self.spec.lifetime.ephemeral.as_ref()` raw-field access
1948    /// `tatara_reconciler::render::render_export_jobs` previously
1949    /// walked past.
1950    ///
1951    /// Pre-lift THREE consumer sites past the ★★ PRIME-DIRECTIVE ≥ 2
1952    /// duplication threshold reached the ephemeral inner through TWO
1953    /// different chains that disagreed on the ambiguous corner:
1954    /// * `tatara_process::lifetime_clock::evaluate` — ambiguity-aware:
1955    ///   `process.spec.lifetime.resolved_ephemeral()` collapses BOTH-
1956    ///   slots-set to `None`, matching the "no ephemeral action"
1957    ///   outcome (`AutoTerminate::Skip`) the ambiguous case must yield.
1958    /// * `tatara_process::lifetime_clock::requeue_with_ttl` —
1959    ///   ambiguity-aware peer of `evaluate`; both share the SAME
1960    ///   `resolved_ephemeral()` gate and MUST agree on the ambiguous
1961    ///   corner or the reconciler's teardown decision and requeue-
1962    ///   budget picker drift apart on the SAME `Process` within one
1963    ///   reconcile pass.
1964    /// * `tatara_reconciler::render::render_export_jobs` — RAW field
1965    ///   access: `process.spec.lifetime.ephemeral.as_ref()` returned
1966    ///   `Some(&e)` on the ambiguous corner, so an operator-authored
1967    ///   `Process` with BOTH `permanent:` AND `ephemeral:` slots
1968    ///   populated would emit export Jobs whose teardown-triggered
1969    ///   fire semantics `lifetime_clock` refused to honor. The two
1970    ///   consumers drifted at the mis-configuration corner.
1971    ///
1972    /// Post-lift ALL THREE consumers reach through ONE `Process` method
1973    /// that composes `self.spec.lifetime.resolved_ephemeral()` — the
1974    /// ambiguity-aware `variant().ok() + as_ephemeral` chain
1975    /// [`crate::lifetime::Lifetime::resolved_ephemeral`] owns — and
1976    /// the drift between the reconciler's export-render arm and the
1977    /// lifetime clock's teardown/TTL arm CLOSES at ONE substrate site.
1978    ///
1979    /// Return-form axis: `Option<&EphemeralLifetime>` matches the
1980    /// borrow-form discipline of the underlying
1981    /// [`crate::lifetime::Lifetime::resolved_ephemeral`] projection so
1982    /// the borrow carries the `'_self` lifetime through directly
1983    /// without a temporary `LifetimeVariant` binding. Peer to the
1984    /// borrow-form status-projection primitives
1985    /// [`Self::observed_attestation`], [`Self::observed_identity`] and
1986    /// the borrow-form metadata-projection primitive
1987    /// [`Self::uid_or_empty`] — all four hide a wrapping `Option`-
1988    /// carrying wire slot behind an inherent projection.
1989    ///
1990    /// A future normalization step (a canonicalization pass that maps
1991    /// a suspiciously-zero `ttl` to a per-cluster default, a per-
1992    /// namespace override that substitutes an operator-declared
1993    /// teardown policy on adopted resources, a wire-schema migration
1994    /// that renames `spec.lifetime.ephemeral` to `spec.lifetime.timed`
1995    /// with a bridging `From` shim) lands at ONE substrate method here
1996    /// and all three downstream consumers pick up the upgrade
1997    /// mechanically — no per-callsite hand-edit at `evaluate` /
1998    /// `requeue_with_ttl` / `render_export_jobs`.
1999    ///
2000    /// Theory anchor: THEORY.md §II.1 invariant 5 (composition
2001    /// preserves proofs — the pins bind the Permanent-only corner, the
2002    /// Ephemeral-only corner, the Both-set-ambiguous corner, the
2003    /// empty-default corner, and the byte-identity parity with the
2004    /// underlying `self.spec.lifetime.resolved_ephemeral()` delegate,
2005    /// so a regression that silently swapped the projection back to
2006    /// the raw `.ephemeral.as_ref()` field would surface here rather
2007    /// than as operator-facing drift between the export-render arm
2008    /// and the teardown/TTL arm on the SAME `Process`). THEORY.md
2009    /// §VI.1 (generation over composition — the ambiguity-aware
2010    /// projection recurred at three hand-authored sites past the ★★
2011    /// PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
2012    /// owner here).
2013    pub fn resolved_ephemeral(&self) -> Option<&EphemeralLifetime> {
2014        self.spec.lifetime.resolved_ephemeral()
2015    }
2016}
2017
2018impl ProcessSpec {
2019    /// Canonical minimum [`ProcessSpec`] — a [`Classification::gate_compute`]
2020    /// classification with every other field parked at its [`Default`] —
2021    /// the workspace-baseline spec every consumer that needed "a
2022    /// `ProcessSpec` that just exists, with no domain-specific claim on
2023    /// intent / boundary / lifetime / routing / encapsulates" hand-authored
2024    /// as a 12-line struct-literal at scattered sites across the workspace.
2025    ///
2026    /// The composition is the two-primitive product of
2027    /// [`Classification::gate_compute`] (the two axes with no `Default` — a
2028    /// `Gate` point on the `Compute` substrate) with the `Default` impl on
2029    /// every other slot: [`IdentitySpec`], [`Intent`], [`Boundary`],
2030    /// [`ComplianceSpec`], `Vec<DependsOn>`, [`SignalPolicy`], [`Lifetime`],
2031    /// `Option<RoutingSpec>`, `Option<EncapsulatesSpec>`, `bool`. The 11
2032    /// defaulted axes ride at the sibling closed-set + `#[serde(default)]`
2033    /// defaults the CRD already owns; the two `_or_default` /
2034    /// `_or_placeholder` corners on the metadata axis stay closed at the
2035    /// substrate ([`Process::coordinates_or_defaults`],
2036    /// [`Process::name_or_placeholder`]) since this primitive builds the
2037    /// `spec` half, not the `metadata` half.
2038    ///
2039    /// Pre-lift the 12-line `ProcessSpec { identity: <Default>,
2040    /// classification: Classification::gate_compute(), intent: <Default>,
2041    /// boundary: Default::default(), compliance: Default::default(),
2042    /// depends_on: vec![], signals: Default::default(), lifetime:
2043    /// Default::default(), routing: None, encapsulates: None, suspended:
2044    /// false }` struct-literal recurred at EIGHT hand-authored sites past
2045    /// the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold across four
2046    /// crates, each restating the SAME 12-slot verbatim:
2047    /// * `tatara-process::crd::tests::empty_spec` — the substrate test
2048    ///   fixture that pins every `Process::*_or_*` metadata-projection
2049    ///   primitive on the (return-form × fallback-shape) axis;
2050    /// * `tatara-process::lib::tests::empty_process_spec` (×2) — the
2051    ///   sibling fixture inside the `qualified_process_ref` +
2052    ///   `DeletionTombstoned` / `Annotated` trait pin modules;
2053    /// * `tatara-process::lib::tests` (one inline site in the
2054    ///   `qualified_process_ref_composes_from_process_coordinates_or_defaults`
2055    ///   pin) — restated the SAME 12-line block inside the test body;
2056    /// * `tatara-reconciler::claim::tests::empty_process` — the claim-
2057    ///   arbiter row-builder pin fixture;
2058    /// * `tatara-pool-reconciler::controller_pool::tests` (×3) — the
2059    ///   `empty_spec` fixture + two inline `process_to_member_state_*` pin
2060    ///   sites that hand-composed the same 12-slot spec inline.
2061    ///
2062    /// Five more sites walked the SAME 12-slot shape but overrode ONE
2063    /// field (intent, lifetime, or routing) inline and are lifted onto
2064    /// the primitive via struct-update syntax
2065    /// (`..ProcessSpec::gate_compute_defaults()`): the three
2066    /// `tatara-reconciler::render` test-fixture helpers
2067    /// (`render_through_top_level_intent_dispatch`, `process_with`,
2068    /// `demo_process`) and the two `tatara-process::lifetime_clock`
2069    /// helpers (`ephemeral_process`, `permanent_process`).
2070    ///
2071    /// Post-lift each callsite reads `ProcessSpec::gate_compute_defaults()`
2072    /// (or `ProcessSpec { <slot>: <value>,
2073    /// ..ProcessSpec::gate_compute_defaults() }` for the override sites);
2074    /// a future workspace-wide baseline shift (a new `#[serde(default)]`
2075    /// on a promoted [`Intent`] variant, a rename of a defaulted slot, a
2076    /// per-baseline compliance overlay stamping through the spec) lands
2077    /// at ONE substrate function here and every downstream consumer
2078    /// inherits the upgrade mechanically. The current pin ties the
2079    /// classification axis to the sibling [`Classification::gate_compute`]
2080    /// primitive so a future change to that baseline surfaces at this
2081    /// primitive's tests rather than as silent drift across thirteen
2082    /// independent callsites.
2083    ///
2084    /// Sibling to [`Classification::gate_compute`] on the composition-
2085    /// depth axis — that primitive owns the ONE-axis-slice construction
2086    /// (the 5-slot [`Classification`] value); this primitive owns the
2087    /// FULL-spec construction (the 11-slot [`ProcessSpec`] value that
2088    /// wraps the classification-slice plus every other slot at
2089    /// `Default`). A future peer `ProcessSpec::observability_stack()` or
2090    /// similar named variant lands as a sibling method here when a
2091    /// second unremarkable-baseline shape opens.
2092    ///
2093    /// Theory anchor: THEORY.md §VI.1 (generation over composition — the
2094    /// 12-line struct-literal shape recurred at EIGHT hand-authored sites
2095    /// past the ★★ PRIME-DIRECTIVE ≥ 2 duplication trigger and is lifted
2096    /// onto ONE workspace-wide owner here). THEORY.md §II.1 invariant 5
2097    /// (composition preserves proofs — a regression that drifted the
2098    /// baseline axis choice at only one consumer, or that broke the
2099    /// sibling-default correspondence with [`Classification::gate_compute`],
2100    /// surfaces at this primitive's tests rather than as silent operator-
2101    /// visible skew between the eight exact-match test-fixtures + the
2102    /// five override sites whose struct-update composition depends on the
2103    /// shape).
2104    #[must_use]
2105    pub fn gate_compute_defaults() -> Self {
2106        Self {
2107            identity: IdentitySpec::default(),
2108            classification: Classification::gate_compute(),
2109            intent: Intent::default(),
2110            boundary: Boundary::default(),
2111            compliance: ComplianceSpec::default(),
2112            depends_on: Vec::new(),
2113            signals: SignalPolicy::default(),
2114            lifetime: Lifetime::default(),
2115            routing: None,
2116            encapsulates: None,
2117            suspended: false,
2118        }
2119    }
2120}
2121
2122/// Process status — every field optional until the reconciler writes it.
2123#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)]
2124#[serde(rename_all = "camelCase")]
2125pub struct ProcessStatus {
2126    /// Hierarchical PID path — e.g., `"seph.1.7"`.
2127    #[serde(default, skip_serializing_if = "Option::is_none")]
2128    pub pid: Option<String>,
2129
2130    /// Parent PID path (mirror of `spec.identity.parent`, resolved at fork).
2131    #[serde(default, skip_serializing_if = "Option::is_none")]
2132    pub parent: Option<String>,
2133
2134    /// Direct children's PID paths.
2135    #[serde(default)]
2136    pub children: Vec<String>,
2137
2138    /// Resolved identity (name + content hash).
2139    #[serde(default, skip_serializing_if = "Option::is_none")]
2140    pub identity: Option<Identity>,
2141
2142    /// Current phase.
2143    #[serde(default)]
2144    pub phase: ProcessPhase,
2145
2146    /// When the process entered the current phase.
2147    #[serde(default, skip_serializing_if = "Option::is_none")]
2148    pub phase_since: Option<DateTime<Utc>>,
2149
2150    /// Three-pillar attestation (written at end of every successful cycle).
2151    #[serde(default, skip_serializing_if = "Option::is_none")]
2152    pub attestation: Option<ProcessAttestation>,
2153
2154    /// FluxCD resources currently owned by this Process.
2155    #[serde(default)]
2156    pub flux_resources: Vec<FluxResourceRef>,
2157
2158    /// Boundary verification state.
2159    #[serde(default)]
2160    pub boundary: BoundaryStatus,
2161
2162    /// Compliance summary at the latest attestation.
2163    #[serde(default)]
2164    pub compliance: ComplianceStatus,
2165
2166    /// Pending signals (delivered, not yet handled).
2167    #[serde(default)]
2168    pub signal_queue: Vec<ProcessSignal>,
2169
2170    /// Standard K8s Conditions.
2171    #[serde(default)]
2172    pub conditions: Vec<ProcessCondition>,
2173
2174    /// Human-readable last status message.
2175    #[serde(default, skip_serializing_if = "Option::is_none")]
2176    pub message: Option<String>,
2177
2178    /// Exit code (only set on Failed / Reaped).
2179    #[serde(default, skip_serializing_if = "Option::is_none")]
2180    pub exit_code: Option<i32>,
2181}
2182
2183impl ProcessStatus {
2184    /// Canonical phase-slot-only [`ProcessStatus`] fixture — a
2185    /// [`ProcessPhase`] pinned at the caller-supplied variant with every
2186    /// other slot parked at its [`Default`] — the workspace-baseline
2187    /// status shape every pool-reconciler phase-decision fixture and
2188    /// every below-controller test that "just wants a Process whose
2189    /// status carries a specific `phase`, nothing else observed" hand-
2190    /// authored as a 3-line `Some(ProcessStatus { phase, ..Default })`
2191    /// struct-literal at scattered pin sites.
2192    ///
2193    /// Pre-lift the 3-line `ProcessStatus { phase: <ProcessPhase::…>,
2194    /// ..Default::default() }` shape recurred at TWO hand-authored
2195    /// sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold,
2196    /// both inside `tatara-pool-reconciler::controller_pool::tests`:
2197    /// * `process_to_member_state_attested_permanent_is_free` — the
2198    ///   Free-arm pin that binds "a Process whose observed phase is
2199    ///   Attested + whose declared `lifetime` is Permanent maps to
2200    ///   `MemberState::Free`".
2201    /// * `process_to_member_state_attested_ephemeral_is_allocated` —
2202    ///   the Allocated-arm pin that binds the peer transition on the
2203    ///   `Lifetime::Ephemeral` corner.
2204    ///
2205    /// Both pin sites walked the SAME 3-line shape stamping
2206    /// `ProcessPhase::Attested`; the composer serves both directly and
2207    /// stays parameterized on `phase` so a future pin on a peer variant
2208    /// (`Running`, `Reconverging`, `Reaped`) rides the same primitive
2209    /// without a new shape opening.
2210    ///
2211    /// Post-lift each callsite reads
2212    /// `p.status = Some(ProcessStatus::at_phase(ProcessPhase::Attested));`
2213    /// and the phase-slot-only status fixture lives at ONE substrate
2214    /// owner. Sibling to [`ProcessSpec::gate_compute_defaults`] on the
2215    /// (spec × status) construction-shape pair: that primitive owns the
2216    /// FULL-spec baseline builder for every downstream `Process::new`
2217    /// consumer; this primitive owns the phase-slot-observation status
2218    /// builder for every downstream `p.status = Some(...)` fixture.
2219    ///
2220    /// A future normalization of the phase-only status shape (a
2221    /// call-time `phase_since` stamp mirroring the phase-transition
2222    /// writer's discipline, a `boundary` slot default overlay pinning
2223    /// the phase to a matching BoundaryStatus corner, a wired-in
2224    /// `identity` fixture for the phase-decision fixtures that today
2225    /// leave the slot at `None`) lands at THIS ONE function and every
2226    /// downstream phase-decision pin inherits the upgrade mechanically.
2227    /// Directly benefits the P5 shigoto Dag refactor (any RecordingJob
2228    /// test fixture stamping "a Process whose observed phase is X" rides
2229    /// the same composer rather than restating the 3-line shape a third
2230    /// time) and the P3 kenshi-runner library lift (any test-Job
2231    /// controller that binds a phase-observation fixture on its owning
2232    /// Process rides through the same composer as the pool-reconciler's
2233    /// two phase-decision pins).
2234    ///
2235    /// Theory anchor: THEORY.md §VI.1 (generation over composition —
2236    /// the 3-line `ProcessStatus { phase, ..Default::default() }`
2237    /// struct-literal recurred at 2 hand-authored sites past the ★★
2238    /// PRIME-DIRECTIVE ≥ 2 duplication trigger inside one workspace
2239    /// crate, and is lifted onto ONE substrate owner here). THEORY.md
2240    /// §II.1 invariant 5 (composition preserves proofs — the pin block
2241    /// binds the primitive at fail-before-pass-after granularity so a
2242    /// regression that drifted the phase slot pass-through, leaked a
2243    /// sibling slot away from `Default`, or hijacked the composer to
2244    /// stamp a static `phase_since` on the `phase` transition surfaces
2245    /// at THESE pins rather than as silent phase-decision skew across
2246    /// the two pool-reconciler callsites).
2247    #[must_use]
2248    pub fn at_phase(phase: ProcessPhase) -> Self {
2249        Self {
2250            phase,
2251            ..Self::default()
2252        }
2253    }
2254}
2255
2256#[cfg(test)]
2257mod tests {
2258    use super::*;
2259    use crate::classification::{ConvergencePointType, SubstrateType};
2260    use crate::intent::NixIntent;
2261
2262    #[test]
2263    fn minimal_spec_serializes() {
2264        let spec = ProcessSpec {
2265            identity: IdentitySpec::default(),
2266            classification: Classification {
2267                point_type: ConvergencePointType::Gate,
2268                substrate: SubstrateType::Observability,
2269                horizon: Default::default(),
2270                calm: Default::default(),
2271                data_classification: Default::default(),
2272            },
2273            intent: Intent {
2274                nix: Some(NixIntent {
2275                    flake_ref: "github:pleme-io/k8s".into(),
2276                    attribute: "obs".into(),
2277                    system: None,
2278                    attic_cache: None,
2279                    extra_args: vec![],
2280                    delegate_to_nix_build: false,
2281                }),
2282                ..Intent::default()
2283            },
2284            boundary: Default::default(),
2285            compliance: Default::default(),
2286            depends_on: vec![],
2287            signals: Default::default(),
2288            lifetime: Default::default(),
2289            routing: None,
2290            encapsulates: None,
2291            suspended: false,
2292        };
2293        let yaml = serde_yaml::to_string(&spec).unwrap();
2294        assert!(yaml.contains("pointType: Gate"));
2295        assert!(yaml.contains("substrate: Observability"));
2296        assert!(yaml.contains("flakeRef: github:pleme-io/k8s"));
2297    }
2298
2299    // ─── Process::coordinates_or_defaults substrate pins ────────────────
2300    //
2301    // Pins the (namespace, name) coordinate-primitive family on the
2302    // (metadata slot × fallback shape) axis. Fail-before-pass-after
2303    // granularity: a regression that flipped either fallback string,
2304    // swapped the return-tuple axis order, or dropped the
2305    // `Option::as_deref` unwrap surfaces here rather than as silent
2306    // drift at every downstream annotation writer / claim-arbiter row
2307    // builder / render owner-metadata seed.
2308
2309    fn empty_spec() -> ProcessSpec {
2310        // Routes through the ONE substrate composer
2311        // `ProcessSpec::gate_compute_defaults` — pre-lift this was the
2312        // 12-line struct-literal restated verbatim at every fixture in
2313        // this pin family, one of EIGHT hand-authored exact-match sites
2314        // past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold across
2315        // four crates.
2316        ProcessSpec::gate_compute_defaults()
2317    }
2318
2319    #[test]
2320    fn default_namespace_constant_is_k8s_canonical_default() {
2321        // Pins the load-bearing convention that this primitive's
2322        // namespace fallback matches K8s's own implicit-namespace
2323        // spelling. A regression that renamed this to "kube-system"
2324        // or any other K8s-reserved name would silently misroute
2325        // every downstream namespaced-Api call on a Process without
2326        // a metadata.namespace.
2327        assert_eq!(Process::DEFAULT_NAMESPACE, "default");
2328    }
2329
2330    #[test]
2331    fn unnamed_placeholder_constant_matches_prior_annotation_writer_fallback() {
2332        // Pins the load-bearing convention that this primitive's name
2333        // fallback matches the exact spelling every annotation writer
2334        // (tatara-reconciler::ssapply::inject_annotations,
2335        // tatara-reconciler::render::render, and
2336        // tatara-reconciler::table_controller's claim-row builder)
2337        // was hand-authoring pre-lift ("unnamed", NOT "<unnamed>" or
2338        // ""). A regression that renamed this would break the
2339        // annotation-writer / claim-arbiter grep contract silently.
2340        assert_eq!(Process::UNNAMED_PLACEHOLDER, "unnamed");
2341    }
2342
2343    #[test]
2344    fn namespace_or_default_falls_back_when_metadata_namespace_is_none() {
2345        let mut p = Process::new("some-proc", empty_spec());
2346        p.metadata.namespace = None;
2347        assert_eq!(p.namespace_or_default(), Process::DEFAULT_NAMESPACE);
2348    }
2349
2350    #[test]
2351    fn namespace_or_default_returns_metadata_slice_when_some() {
2352        let mut p = Process::new("some-proc", empty_spec());
2353        p.metadata.namespace = Some("prod-app".into());
2354        assert_eq!(p.namespace_or_default(), "prod-app");
2355    }
2356
2357    #[test]
2358    fn name_or_placeholder_falls_back_when_metadata_name_is_none() {
2359        let mut p = Process::new("real-name", empty_spec());
2360        p.metadata.name = None;
2361        assert_eq!(p.name_or_placeholder(), Process::UNNAMED_PLACEHOLDER);
2362    }
2363
2364    #[test]
2365    fn name_or_placeholder_returns_metadata_slice_when_some() {
2366        let p = Process::new("api-gateway", empty_spec());
2367        assert_eq!(p.name_or_placeholder(), "api-gateway");
2368    }
2369
2370    #[test]
2371    fn coordinates_or_defaults_composes_both_halves() {
2372        // Both slots present — returns metadata slices in
2373        // (namespace, name) axis order.
2374        let mut p = Process::new("api", empty_spec());
2375        p.metadata.namespace = Some("staging".into());
2376        assert_eq!(p.coordinates_or_defaults(), ("staging", "api"));
2377    }
2378
2379    #[test]
2380    fn coordinates_or_defaults_falls_back_on_both_slots() {
2381        // Both slots None — returns (DEFAULT_NAMESPACE,
2382        // UNNAMED_PLACEHOLDER) in axis order.
2383        let mut p = Process::new("scratch", empty_spec());
2384        p.metadata.name = None;
2385        p.metadata.namespace = None;
2386        assert_eq!(
2387            p.coordinates_or_defaults(),
2388            (Process::DEFAULT_NAMESPACE, Process::UNNAMED_PLACEHOLDER)
2389        );
2390    }
2391
2392    #[test]
2393    fn coordinates_or_defaults_mixes_slotted_and_fallback_halves() {
2394        // Namespace set, name missing — the (namespace, name) tuple
2395        // pins each half independently. A regression that returned
2396        // BOTH fallbacks when EITHER metadata slot was None would
2397        // surface here rather than at every downstream reader.
2398        let mut p = Process::new("kept-name", empty_spec());
2399        p.metadata.namespace = Some("prod".into());
2400        assert_eq!(p.coordinates_or_defaults(), ("prod", "kept-name"));
2401
2402        // Name set, namespace missing — the peer corner.
2403        let mut q = Process::new("api", empty_spec());
2404        q.metadata.namespace = None;
2405        assert_eq!(
2406            q.coordinates_or_defaults(),
2407            (Process::DEFAULT_NAMESPACE, "api")
2408        );
2409    }
2410
2411    // ─── Process::qualified_ref substrate pins ─────────────────────────
2412    //
2413    // Pins the paired-projection + shape-composer chain
2414    // `coordinates_or_defaults() → qualified_process_ref(ns, name)` on
2415    // the (return-form × composition-depth) axis pair. Fail-before-
2416    // pass-after granularity: a regression that swapped the `<ns>/<name>`
2417    // axis order, dropped either half, drifted the fallback strings
2418    // between the paired-projection primitive and the shape composer, or
2419    // inserted a normalization step at only the composed site and not
2420    // the pair-returning primitive (or vice versa) surfaces here rather
2421    // than as silent operator-visible skew across the three pre-lift
2422    // `tatara-reconciler` sites (`render::render_routing`,
2423    // `render::render_export_jobs`, `table_controller::reconcile`)
2424    // whose downstream greps the reference shape verbatim (the
2425    // `PROCESS=<ref>` annotation seed on every emitted Ingress /
2426    // DNSEndpoint / export Job, the `ClaimRecord.holder` slot on the
2427    // stable-name claim registry).
2428
2429    #[test]
2430    fn qualified_ref_composes_ns_and_name_with_slash_when_both_slots_present() {
2431        // Happy path — both metadata slots populated. The composed
2432        // reference is EXACTLY `<ns>/<name>`, in that order, joined by
2433        // a single `/`. A regression that swapped the two axes at
2434        // this primitive would silently break every downstream
2435        // `PROCESS=<ref>` annotation grep + claim-registry lookup.
2436        let mut p = Process::new("api-gateway", empty_spec());
2437        p.metadata.namespace = Some("prod-app".into());
2438        assert_eq!(p.qualified_ref(), "prod-app/api-gateway");
2439    }
2440
2441    #[test]
2442    fn qualified_ref_falls_back_to_default_namespace_when_metadata_namespace_is_none() {
2443        // Namespace-fallback pin: an absent `metadata.namespace` rides
2444        // through `namespace_or_default()` → `DEFAULT_NAMESPACE`, so
2445        // the composed reference lands as `default/<name>`. Matches
2446        // what a pre-lift `qualified_process_ref(process.
2447        // coordinates_or_defaults())` composition produced.
2448        let mut p = Process::new("api-gateway", empty_spec());
2449        p.metadata.namespace = None;
2450        assert_eq!(p.qualified_ref(), "default/api-gateway");
2451    }
2452
2453    #[test]
2454    fn qualified_ref_falls_back_to_unnamed_placeholder_when_metadata_name_is_none() {
2455        // Name-fallback pin: an absent `metadata.name` rides through
2456        // `name_or_placeholder()` → `UNNAMED_PLACEHOLDER`, so the
2457        // composed reference lands as `<ns>/unnamed`. A pre-lift
2458        // consumer whose paired projection returned the placeholder
2459        // (annotation writer, render owner-metadata seed) sees the
2460        // exact same `<ns>/unnamed` shape post-lift, so downstream
2461        // greps keyed on the pre-metadata Process's reference match
2462        // bytewise.
2463        let mut p = Process::new("ignored", empty_spec());
2464        p.metadata.namespace = Some("staging".into());
2465        p.metadata.name = None;
2466        assert_eq!(p.qualified_ref(), "staging/unnamed");
2467    }
2468
2469    #[test]
2470    fn qualified_ref_falls_back_on_both_slots_when_both_metadata_are_none() {
2471        // Both slots absent → both fallbacks land in the composed
2472        // reference. The `default/unnamed` shape is what every pre-
2473        // lift caller produced when a Process fixture (test or
2474        // dynamic API response) surfaced without populated metadata;
2475        // pinning it here holds the primitive's contract against a
2476        // regression that dropped either fallback at only the
2477        // composed site.
2478        let mut p = Process::new("ignored", empty_spec());
2479        p.metadata.namespace = None;
2480        p.metadata.name = None;
2481        assert_eq!(
2482            p.qualified_ref(),
2483            format!(
2484                "{}/{}",
2485                Process::DEFAULT_NAMESPACE,
2486                Process::UNNAMED_PLACEHOLDER
2487            )
2488        );
2489    }
2490
2491    #[test]
2492    fn qualified_ref_matches_pre_lift_paired_composition_bytewise() {
2493        // Byte-identical parity with the exact pre-lift 2-step
2494        // composition every `tatara-reconciler` site hand-authored:
2495        // `let (ns, name) = process.coordinates_or_defaults(); let r
2496        // = qualified_process_ref(ns, name);`. Sweeps every metadata-
2497        // slot combination the three pre-lift consumers plausibly
2498        // encountered — both slots populated (steady state), one
2499        // slot absent (Process mid-fork before API-server metadata
2500        // stamp), both slots absent (dynamic API response / test
2501        // fixture) — so a regression that reshaped the composition at
2502        // the substrate primitive would surface here rather than as
2503        // silent drift at the three consumer sites.
2504        let fixtures: [(Option<&str>, Option<&str>); 4] = [
2505            (Some("prod-app"), Some("api-gateway")),
2506            (None, Some("api-gateway")),
2507            (Some("staging"), None),
2508            (None, None),
2509        ];
2510        for (ns_slot, name_slot) in fixtures {
2511            let mut p = Process::new(name_slot.unwrap_or("seed"), empty_spec());
2512            p.metadata.namespace = ns_slot.map(str::to_string);
2513            p.metadata.name = name_slot.map(str::to_string);
2514            let via_primitive = p.qualified_ref();
2515            let (ns, name) = p.coordinates_or_defaults();
2516            let via_paired = crate::qualified_process_ref(ns, name);
2517            assert_eq!(
2518                via_primitive, via_paired,
2519                "qualified_ref must be byte-identical to the pre-lift \
2520                 paired composition on (ns={ns_slot:?}, name={name_slot:?})"
2521            );
2522        }
2523    }
2524
2525    #[test]
2526    fn qualified_ref_composes_from_the_shared_coordinates_or_defaults_owner() {
2527        // Composition invariant: the composed reference decomposes at
2528        // the single `/` separator into EXACTLY the (ns, name) pair
2529        // `coordinates_or_defaults` returns. A regression that
2530        // introduced a per-callsite normalization at the shape
2531        // composer (URL-escape, case-fold, path-normalize) or that
2532        // pulled the pair from a different metadata source than the
2533        // paired-projection primitive would surface here rather than
2534        // at every downstream reference-shape grep.
2535        let mut p = Process::new("api-gateway", empty_spec());
2536        p.metadata.namespace = Some("prod-app".into());
2537        let composed = p.qualified_ref();
2538        let (ns, name) = p.coordinates_or_defaults();
2539        let (composed_ns, composed_name) = composed.split_once('/').unwrap();
2540        assert_eq!(composed_ns, ns);
2541        assert_eq!(composed_name, name);
2542    }
2543
2544    // ─── Process::owned_coordinates_or_err substrate pins ──────────────
2545    //
2546    // Pins the owned + name-required peer of the coordinate-primitive
2547    // family on the (return-form × name gate) axis pair. Fail-before-
2548    // pass-after granularity: a regression that flipped the namespace
2549    // fallback string, dropped the `Option::clone` unwrap, changed the
2550    // return-tuple axis order, or altered the "Process has no
2551    // metadata.name" error wording surfaces here rather than as silent
2552    // drift at every pre-lift caller (10 sites in
2553    // `tatara-reconciler::phase_machine` + 2 sites in
2554    // `tatara-reconciler::signals` pre-lift).
2555
2556    #[test]
2557    fn owned_coordinates_or_err_returns_owned_strings_when_both_slots_present() {
2558        // Happy path — both slots populated, method returns owned
2559        // Strings in (namespace, name) axis order.
2560        let mut p = Process::new("api-gateway", empty_spec());
2561        p.metadata.namespace = Some("prod-app".into());
2562        let (ns, name) = p.owned_coordinates_or_err().unwrap();
2563        assert_eq!(ns, "prod-app");
2564        assert_eq!(name, "api-gateway");
2565        // Ownership pin: type inference above binds ns/name as
2566        // owned Strings — a regression that returned &str would
2567        // fail to compile at the following .push() call. This
2568        // holds the "owned" half of the primitive's contract.
2569        let mut owned_ns = ns;
2570        owned_ns.push_str("-mutated");
2571        assert_eq!(owned_ns, "prod-app-mutated");
2572    }
2573
2574    #[test]
2575    fn owned_coordinates_or_err_falls_back_on_namespace_but_returns_owned_name() {
2576        // Namespace absent → DEFAULT_NAMESPACE. Name present → owned.
2577        let p = Process::new("api", empty_spec());
2578        // Process::new leaves metadata.namespace = None by default.
2579        let (ns, name) = p.owned_coordinates_or_err().unwrap();
2580        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
2581        assert_eq!(name, "api");
2582    }
2583
2584    #[test]
2585    fn owned_coordinates_or_err_errors_when_metadata_name_absent_regardless_of_namespace() {
2586        // Name absent → Err, REGARDLESS of whether the namespace is
2587        // populated. The name gate is strictly on `metadata.name` and
2588        // does NOT fall back to `Self::UNNAMED_PLACEHOLDER` (that
2589        // fallback is on the peer `coordinates_or_defaults`, which
2590        // exists precisely for consumers that can tolerate a
2591        // display placeholder).
2592        for ns_slot in [None, Some("prod".to_string())] {
2593            let mut p = Process::new("scratch", empty_spec());
2594            p.metadata.name = None;
2595            p.metadata.namespace = ns_slot.clone();
2596            let err = p.owned_coordinates_or_err().unwrap_err();
2597            assert!(
2598                err.to_string().contains("metadata.name"),
2599                "err on missing name (ns={ns_slot:?}) should mention metadata.name; got {err}"
2600            );
2601        }
2602    }
2603
2604    #[test]
2605    fn owned_coordinates_or_err_error_message_matches_pre_lift_reconciler_wording() {
2606        // Load-bearing wording pin — every pre-lift `tatara-reconciler`
2607        // helper (`phase_machine::namespace_and_name`,
2608        // `signals::ingest`, `signals::consume_effect`) errored with
2609        // EXACTLY this wording. Post-lift the substrate owner produces
2610        // the same wording so log-line / test greps that anchored on
2611        // it keep matching, and no operator-visible message drift
2612        // lands as a side effect of the substrate move.
2613        let mut p = Process::new("scratch", empty_spec());
2614        p.metadata.name = None;
2615        let err = p.owned_coordinates_or_err().unwrap_err();
2616        assert_eq!(err.to_string(), "Process has no metadata.name");
2617    }
2618
2619    #[test]
2620    fn owned_coordinates_or_err_namespace_fallback_matches_default_namespace_const() {
2621        // Byte-identity pin between the owned form's namespace
2622        // fallback and the workspace-wide `DEFAULT_NAMESPACE` const.
2623        // A regression that spelled this fallback as any other
2624        // string ("kube-system", "", "default-ns") would silently
2625        // misroute every downstream namespaced-Api call on a
2626        // Process without a metadata.namespace — surfaces here
2627        // rather than at every kube-rs API caller.
2628        let mut p = Process::new("api", empty_spec());
2629        p.metadata.namespace = None;
2630        let (ns, _) = p.owned_coordinates_or_err().unwrap();
2631        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
2632    }
2633
2634    #[test]
2635    fn owned_coordinates_or_err_matches_pre_lift_reconciler_helper_shape() {
2636        // Byte-identical parity pin between the owned + name-required
2637        // primitive here and the pre-lift `tatara-reconciler` helper
2638        // shape — the exact 2-slot unwrap chain each pre-lift caller
2639        // spelled by hand:
2640        //
2641        //   let ns = p.metadata.namespace.clone().unwrap_or_else(|| "default".into());
2642        //   let name = p.metadata.name.clone().ok_or_else(|| anyhow!(...))?;
2643        //   Ok((ns, name))
2644        //
2645        // Sweeps every corner every callsite plausibly encounters
2646        // (both slots present, namespace absent, name absent, both
2647        // absent). A regression that inserted a normalization step
2648        // at the primitive that the pre-lift chain does NOT apply —
2649        // or vice versa — surfaces here rather than as silent drift
2650        // between the 12 pre-lift consumer callsites and the ONE
2651        // substrate owner they now route through.
2652        fn pre_lift(p: &Process) -> anyhow::Result<(String, String)> {
2653            let ns = p
2654                .metadata
2655                .namespace
2656                .clone()
2657                .unwrap_or_else(|| "default".into());
2658            let name = p
2659                .metadata
2660                .name
2661                .clone()
2662                .ok_or_else(|| anyhow::anyhow!("Process has no metadata.name"))?;
2663            Ok((ns, name))
2664        }
2665        // Both present.
2666        let mut p = Process::new("api", empty_spec());
2667        p.metadata.namespace = Some("prod".into());
2668        assert_eq!(p.owned_coordinates_or_err().unwrap(), pre_lift(&p).unwrap());
2669        // Namespace absent.
2670        let p = Process::new("api", empty_spec());
2671        assert_eq!(p.owned_coordinates_or_err().unwrap(), pre_lift(&p).unwrap());
2672        // Name absent → both variants error with the same wording.
2673        let mut p = Process::new("api", empty_spec());
2674        p.metadata.name = None;
2675        p.metadata.namespace = Some("prod".into());
2676        assert_eq!(
2677            p.owned_coordinates_or_err().unwrap_err().to_string(),
2678            pre_lift(&p).unwrap_err().to_string(),
2679        );
2680        // Both absent → still errors on the name gate.
2681        let mut p = Process::new("api", empty_spec());
2682        p.metadata.name = None;
2683        p.metadata.namespace = None;
2684        assert_eq!(
2685            p.owned_coordinates_or_err().unwrap_err().to_string(),
2686            pre_lift(&p).unwrap_err().to_string(),
2687        );
2688    }
2689
2690    #[test]
2691    fn owned_coordinates_or_err_axis_order_matches_coordinates_or_defaults() {
2692        // Cross-primitive coherence pin between the owned + name-
2693        // required form and the borrow + name-defaulted peer:
2694        // (namespace, name) axis order is IDENTICAL across both
2695        // return-forms. A regression that swapped the tuple slots on
2696        // only ONE of the two primitives would silently misroute
2697        // every consumer that picked between the two forms based on
2698        // its callsite's ownership needs. The pin re-reads both
2699        // primitives at test time so the equality holds iff both
2700        // live paths are the current implementation.
2701        let mut p = Process::new("app", empty_spec());
2702        p.metadata.namespace = Some("infra".into());
2703        let (borrow_ns, borrow_name) = p.coordinates_or_defaults();
2704        let (owned_ns, owned_name) = p.owned_coordinates_or_err().unwrap();
2705        assert_eq!(owned_ns, borrow_ns);
2706        assert_eq!(owned_name, borrow_name);
2707        // Explicit slot labels — pins the (namespace, name) axis
2708        // order as opposed to (name, namespace).
2709        assert_eq!(owned_ns, "infra"); // NOT "app"
2710        assert_eq!(owned_name, "app"); // NOT "infra"
2711    }
2712
2713    // ─── Process::coordinates_or_none substrate pins ──────────────────
2714    //
2715    // Pins the borrow + name-required peer of the coordinate-primitive
2716    // family on the (return-form × name-gate) axis pair. Closes the
2717    // corner previously left open (borrow + name-required) so the
2718    // three consumer shapes (child-Process delete-fan-out at
2719    // `phase_machine::handle_exiting`, claim-arbiter probe at
2720    // `phase_machine::process_holds_any_claim`, any future non-fatal
2721    // skip site) route through ONE primitive rather than three hand-
2722    // authored empty-string / `unwrap_or_default()` sentinel chains.
2723    // Fail-before-pass-after granularity: a regression that flipped
2724    // the namespace fallback, swapped the return-tuple axis order,
2725    // returned an owned form, or promoted a missing name to an error
2726    // rather than `None` surfaces here rather than as silent drift at
2727    // every borrow + name-required consumer.
2728
2729    #[test]
2730    fn coordinates_or_none_returns_slices_when_both_slots_present() {
2731        // Happy path — both slots populated, method returns borrowed
2732        // (&str, &str) in (namespace, name) axis order wrapped in
2733        // `Some`.
2734        let mut p = Process::new("api-gateway", empty_spec());
2735        p.metadata.namespace = Some("prod-app".into());
2736        let (ns, name) = p.coordinates_or_none().expect("Some when name set");
2737        assert_eq!(ns, "prod-app");
2738        assert_eq!(name, "api-gateway");
2739    }
2740
2741    #[test]
2742    fn coordinates_or_none_falls_back_on_namespace_but_returns_name_slice() {
2743        // Namespace absent → DEFAULT_NAMESPACE (shared with the peer
2744        // `coordinates_or_defaults` + `namespace_or_default`). Name
2745        // present → the metadata slice, wrapped in `Some`.
2746        let mut p = Process::new("api", empty_spec());
2747        p.metadata.namespace = None;
2748        let (ns, name) = p.coordinates_or_none().expect("Some when name set");
2749        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
2750        assert_eq!(name, "api");
2751    }
2752
2753    #[test]
2754    fn coordinates_or_none_returns_none_when_metadata_name_absent_regardless_of_namespace() {
2755        // Name absent → `None`, REGARDLESS of whether the namespace
2756        // slot is populated. The name gate is strictly on
2757        // `metadata.name` and does NOT fall back to
2758        // `Self::UNNAMED_PLACEHOLDER` (that fallback is on the peer
2759        // `coordinates_or_defaults`, which exists precisely for
2760        // consumers that tolerate a display placeholder). Peer to
2761        // `owned_coordinates_or_err_errors_when_metadata_name_absent_regardless_of_namespace`
2762        // on the sibling primitive; a regression that widened THIS
2763        // form to substitute the placeholder while leaving the owned
2764        // form strict would silently drift the two borrow-form
2765        // primitives out of the coherence the family carries.
2766        for ns_slot in [None, Some("prod".to_string())] {
2767            let mut p = Process::new("scratch", empty_spec());
2768            p.metadata.name = None;
2769            p.metadata.namespace = ns_slot.clone();
2770            assert!(
2771                p.coordinates_or_none().is_none(),
2772                "coordinates_or_none must be None on missing name (ns={ns_slot:?})",
2773            );
2774        }
2775    }
2776
2777    #[test]
2778    fn coordinates_or_none_namespace_fallback_matches_default_namespace_const() {
2779        // Byte-identity pin between the borrow + name-required form's
2780        // namespace fallback and the workspace-wide `DEFAULT_NAMESPACE`
2781        // const. Sibling to
2782        // `owned_coordinates_or_err_namespace_fallback_matches_default_namespace_const`
2783        // on the peer primitive — the two forms MUST substitute the
2784        // same fallback string, else a consumer that switches between
2785        // them based on its ownership need silently observes a
2786        // different namespace-fallback shape as a side effect.
2787        let mut p = Process::new("api", empty_spec());
2788        p.metadata.namespace = None;
2789        let (ns, _) = p.coordinates_or_none().unwrap();
2790        assert_eq!(ns, Process::DEFAULT_NAMESPACE);
2791    }
2792
2793    #[test]
2794    fn coordinates_or_none_axis_order_matches_coordinates_or_defaults_when_name_present() {
2795        // Cross-primitive coherence pin between the two borrow-form
2796        // primitives: when the name is present, the (namespace, name)
2797        // return-tuple axis order is IDENTICAL across the two forms,
2798        // and the returned slices are the SAME `&str` view onto the
2799        // same metadata slots. A regression that swapped the tuple
2800        // slots on ONE form would silently misroute every consumer
2801        // that picked between the two forms based on its name-gate
2802        // need. The pin re-reads both primitives at test time so the
2803        // equality holds iff both live paths are the current
2804        // implementation.
2805        let mut p = Process::new("app", empty_spec());
2806        p.metadata.namespace = Some("infra".into());
2807        let (defaulted_ns, defaulted_name) = p.coordinates_or_defaults();
2808        let (required_ns, required_name) = p.coordinates_or_none().unwrap();
2809        assert_eq!(defaulted_ns, required_ns);
2810        assert_eq!(defaulted_name, required_name);
2811        // Explicit slot labels — pins the (namespace, name) axis order
2812        // as opposed to (name, namespace).
2813        assert_eq!(required_ns, "infra"); // NOT "app"
2814        assert_eq!(required_name, "app"); // NOT "infra"
2815    }
2816
2817    #[test]
2818    fn coordinates_or_none_axis_pair_diverges_from_coordinates_or_defaults_on_missing_name() {
2819        // Divergence pin between the two borrow-form primitives when
2820        // the name gate fires: `coordinates_or_defaults` substitutes
2821        // the display placeholder AND still returns a tuple;
2822        // `coordinates_or_none` returns `None`. A regression that
2823        // collapsed the two behaviors (either by dropping the gate
2824        // from the required form or by adding a `None` corner to the
2825        // defaulted form) would blur the axis pair's whole reason to
2826        // exist as two peer primitives.
2827        let mut p = Process::new("scratch", empty_spec());
2828        p.metadata.name = None;
2829        p.metadata.namespace = Some("prod".into());
2830        // Defaulted form: substitutes placeholder, no gate.
2831        assert_eq!(
2832            p.coordinates_or_defaults(),
2833            ("prod", Process::UNNAMED_PLACEHOLDER)
2834        );
2835        // Required form: gate fires, `None`.
2836        assert!(p.coordinates_or_none().is_none());
2837    }
2838
2839    #[test]
2840    fn coordinates_or_none_matches_pre_lift_reconciler_helper_shape() {
2841        // Byte-identical parity pin between the borrow + name-required
2842        // primitive here and the pre-lift `tatara-reconciler` helper
2843        // shapes — the exact 2-slot unwrap + gate chains each pre-lift
2844        // caller spelled by hand (`phase_machine::process_holds_any_claim`
2845        // spelled it as `unwrap_or("")` + `is_empty` early-return;
2846        // `phase_machine::handle_exiting`'s child-fan-out spelled it
2847        // as `unwrap_or_default()` + implicit no-op delete on the
2848        // empty API-path). Sweeps every corner every callsite plausibly
2849        // encounters (both slots present, namespace absent, name
2850        // absent + ns present, both absent). A regression that
2851        // inserted a normalization step at the primitive the pre-lift
2852        // chain does NOT apply — or vice versa — surfaces here rather
2853        // than as silent drift between the pre-lift consumer sites
2854        // and the ONE substrate owner they now route through.
2855        fn pre_lift_holds_any_claim(p: &Process) -> Option<(&str, &str)> {
2856            let ns = p.metadata.namespace.as_deref().unwrap_or("default");
2857            let name = p.metadata.name.as_deref().unwrap_or("");
2858            if name.is_empty() {
2859                return None;
2860            }
2861            Some((ns, name))
2862        }
2863        // Both present.
2864        let mut p = Process::new("api", empty_spec());
2865        p.metadata.namespace = Some("prod".into());
2866        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2867        // Namespace absent.
2868        let p = Process::new("api", empty_spec());
2869        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2870        // Name absent → both variants return `None` regardless of ns.
2871        let mut p = Process::new("api", empty_spec());
2872        p.metadata.name = None;
2873        p.metadata.namespace = Some("prod".into());
2874        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2875        // Both absent → still `None` on the name gate.
2876        let mut p = Process::new("api", empty_spec());
2877        p.metadata.name = None;
2878        p.metadata.namespace = None;
2879        assert_eq!(p.coordinates_or_none(), pre_lift_holds_any_claim(&p));
2880    }
2881
2882    #[test]
2883    fn coordinates_or_none_axis_order_matches_owned_coordinates_or_err_on_happy_path() {
2884        // Cross-primitive coherence pin at the sibling corner: when
2885        // BOTH slots are present, the borrow + name-required form
2886        // (this method) and the owned + name-required peer
2887        // (`owned_coordinates_or_err`) return the SAME `(ns, name)`
2888        // pair — the axis order is IDENTICAL and neither primitive
2889        // silently applies a normalization the other omits. A
2890        // regression that skewed one form's normalization would
2891        // surface here rather than as silent drift between the two
2892        // name-required corners of the primitive family.
2893        let mut p = Process::new("app", empty_spec());
2894        p.metadata.namespace = Some("infra".into());
2895        let (borrow_ns, borrow_name) = p.coordinates_or_none().unwrap();
2896        let (owned_ns, owned_name) = p.owned_coordinates_or_err().unwrap();
2897        assert_eq!(borrow_ns, owned_ns.as_str());
2898        assert_eq!(borrow_name, owned_name.as_str());
2899    }
2900
2901    #[test]
2902    fn coordinates_or_defaults_axis_order_matches_qualified_process_ref() {
2903        // Pins the load-bearing convention that the return-tuple
2904        // axis order is (namespace, name) — the exact positional
2905        // argument order the substrate's paired-composer primitive
2906        // `tatara_reconciler::ssapply::qualified_process_ref(ns,
2907        // name)` consumes. A regression that swapped the tuple
2908        // slots would silently misroute every annotation writer /
2909        // claim-arbiter row / owner-metadata seed built by feeding
2910        // this pair into the composer — every downstream `<ns>/
2911        // <name>` grep would suddenly see `<name>/<ns>`. The test
2912        // verifies the tuple's first slot is what a hand-authored
2913        // `.metadata.namespace.as_deref()...` produced pre-lift, and
2914        // the second slot is what `.metadata.name.as_deref()...`
2915        // produced.
2916        let mut p = Process::new("app", empty_spec());
2917        p.metadata.namespace = Some("infra".into());
2918        let (ns, name) = p.coordinates_or_defaults();
2919        assert_eq!(ns, "infra"); // NOT "app"
2920        assert_eq!(name, "app"); // NOT "infra"
2921    }
2922
2923    // ─── Process::annotation substrate pins ────────────────────────────
2924    //
2925    // Pins the borrow-form annotation-lookup primitive that owns the
2926    // 3-line `.metadata.annotations.as_ref().and_then(|m| m.get(KEY))`
2927    // chain three hand-authored sites restated by hand pre-lift:
2928    // `tatara-reconciler::signals::ingest` (SIGNAL),
2929    // `tatara-reconciler::phase_machine::released_from_annotation`
2930    // (RELEASED_FROM), and
2931    // `tatara-pool-reconciler::controller_pool::process_belongs_to_pool`
2932    // (POOL). Fail-before-pass-after granularity: a regression that
2933    // widened the missing-`annotations` corner (returning `Some("")`
2934    // instead of `None`), promoted a missing key to an error, dropped
2935    // the borrow-form return, or changed the two swallowed corners'
2936    // shared collapse to `None` surfaces here rather than as silent
2937    // drift at the three consumer sites.
2938    fn process_with_annotation(key: &str, value: &str) -> Process {
2939        let mut p = Process::new("some-proc", empty_spec());
2940        let mut anns = std::collections::BTreeMap::new();
2941        anns.insert(key.to_string(), value.to_string());
2942        p.metadata.annotations = Some(anns);
2943        p
2944    }
2945
2946    #[test]
2947    fn annotation_returns_none_when_metadata_annotations_is_none() {
2948        // Missing-`annotations` corner: a Process with no annotations
2949        // block at all returns `None` for every key. Peer to
2950        // `observed_flux_resources_returns_empty_slice_when_status_is_none`
2951        // on the status-projection axis; both primitives collapse the
2952        // outer `Option` corner rather than requiring each consumer
2953        // to spell the guard by hand.
2954        let mut p = Process::new("scratch", empty_spec());
2955        p.metadata.annotations = None;
2956        assert!(p.annotation("tatara.pleme.io/signal").is_none());
2957        assert!(p.annotation("tatara.pleme.io/pool").is_none());
2958        assert!(p.annotation("").is_none());
2959    }
2960
2961    #[test]
2962    fn annotation_returns_none_when_key_absent_from_populated_map() {
2963        // Missing-key corner: annotations block populated with OTHER
2964        // keys returns `None` for the queried key. Symmetric with the
2965        // missing-`annotations` corner — both corners collapse to the
2966        // same `None`, matching the pre-lift `.and_then(...)`
2967        // behavior every consumer relied on.
2968        let p = process_with_annotation("tatara.pleme.io/other", "value");
2969        assert!(p.annotation("tatara.pleme.io/signal").is_none());
2970        assert!(p.annotation("").is_none());
2971    }
2972
2973    #[test]
2974    fn annotation_returns_borrowed_slice_when_key_present() {
2975        // Happy path: annotations block populated + key present →
2976        // `Some(&str)` borrowed from the underlying `String` in the
2977        // map. A regression that returned an owned `String` (defeating
2978        // the primitive's role as a zero-copy projection) would
2979        // surface at the lifetime of the returned reference — the
2980        // `&str` outlives the borrow of `&p` here.
2981        let p = process_with_annotation("tatara.pleme.io/signal", "SIGHUP");
2982        assert_eq!(p.annotation("tatara.pleme.io/signal"), Some("SIGHUP"));
2983    }
2984
2985    #[test]
2986    fn annotation_returns_borrowed_empty_string_slice_when_value_is_empty() {
2987        // Edge corner between the missing-key `None` and the present-
2988        // key `Some("")` — a Process whose annotation is EXPLICITLY
2989        // set to an empty string returns `Some("")`, NOT `None`. A
2990        // regression that normalized the empty-string value to `None`
2991        // (a plausible "defensive" simplification) would silently
2992        // reshape the corner every callsite pre-lift kept distinct via
2993        // `.cloned().unwrap_or_default()` (which collapses BOTH to
2994        // `""`) or `.map(String::as_str)` (which keeps them distinct
2995        // as `None` vs `Some("")`).
2996        let p = process_with_annotation("tatara.pleme.io/signal", "");
2997        assert_eq!(p.annotation("tatara.pleme.io/signal"), Some(""));
2998    }
2999
3000    #[test]
3001    fn annotation_is_a_pure_projection() {
3002        // Purity pin — repeated calls return equal results and the
3003        // primitive does not mutate `self`. Peer to
3004        // `observed_flux_resources_is_a_pure_projection` on the
3005        // status-projection axis.
3006        let p = process_with_annotation("tatara.pleme.io/released-from", "Attested");
3007        let a = p.annotation("tatara.pleme.io/released-from");
3008        let b = p.annotation("tatara.pleme.io/released-from");
3009        assert_eq!(a, b);
3010        assert_eq!(a, Some("Attested"));
3011    }
3012
3013    #[test]
3014    fn annotation_matches_pre_lift_reconciler_chain_shape() {
3015        // Byte-identical parity pin between the borrow-form primitive
3016        // here and the pre-lift `tatara-reconciler` / `tatara-pool-
3017        // reconciler` chain shape — the exact 3-line
3018        // `.metadata.annotations.as_ref().and_then(|m| m.get(KEY))
3019        // .map(String::as_str)` incantation each pre-lift caller
3020        // spelled by hand (three variants of tail collapsed onto ONE
3021        // borrow-form primitive here; each caller reapplies its own
3022        // tail at its own site). Sweeps every corner (missing
3023        // annotations map, missing key, present key with value,
3024        // present key with empty value) so a regression that inserted
3025        // a normalization at the primitive the pre-lift chain does
3026        // NOT apply — or vice versa — surfaces here rather than as
3027        // silent drift between the ONE substrate owner and the three
3028        // consumer sites.
3029        fn pre_lift<'a>(p: &'a Process, key: &str) -> Option<&'a str> {
3030            p.metadata
3031                .annotations
3032                .as_ref()
3033                .and_then(|m| m.get(key))
3034                .map(String::as_str)
3035        }
3036        // Missing annotations map.
3037        let mut p = Process::new("x", empty_spec());
3038        p.metadata.annotations = None;
3039        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
3040        // Missing key in populated map.
3041        let p = process_with_annotation("other", "v");
3042        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
3043        // Present key with non-empty value.
3044        let p = process_with_annotation("k", "v");
3045        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
3046        // Present key with explicitly-empty value — the corner
3047        // `.cloned().unwrap_or_default()` collapses to `""` post-tail
3048        // but the primitive-level shape stays `Some("")`.
3049        let p = process_with_annotation("k", "");
3050        assert_eq!(p.annotation("k"), pre_lift(&p, "k"));
3051    }
3052
3053    #[test]
3054    fn annotation_composes_owned_tail_matching_pre_lift_signals_ingest() {
3055        // Pins the exact tail shape `tatara-reconciler::signals::
3056        // ingest` composed pre-lift: an `Option<String>` for the
3057        // downstream `let Some(raw) = raw else { ... }` guard.
3058        // Post-lift the callsite composes `.map(str::to_string)` at
3059        // its own site; this test pins the composition matches the
3060        // pre-lift `.cloned()` tail byte-for-byte on both corners the
3061        // consumer's downstream distinguishes (annotation present →
3062        // `Some(String)`; absent → `None`).
3063        let p = process_with_annotation("tatara.pleme.io/signal", "SIGUSR1");
3064        assert_eq!(
3065            p.annotation("tatara.pleme.io/signal").map(str::to_string),
3066            Some("SIGUSR1".to_string())
3067        );
3068        let mut q = Process::new("y", empty_spec());
3069        q.metadata.annotations = None;
3070        assert_eq!(
3071            q.annotation("tatara.pleme.io/signal").map(str::to_string),
3072            None
3073        );
3074    }
3075
3076    #[test]
3077    fn annotation_composes_default_tail_matching_pre_lift_released_from() {
3078        // Pins the exact tail shape
3079        // `tatara-reconciler::phase_machine::released_from_annotation`
3080        // composed pre-lift: a bare `String` via `.cloned()
3081        // .unwrap_or_default()` for the downstream
3082        // `match v.as_str()` dispatch. Post-lift the callsite matches
3083        // directly on `Option<&str>` (Some("Failed") vs _); this test
3084        // pins that the borrow-form primitive plus the `.unwrap_or("")`
3085        // fallback reproduces the pre-lift bare-string shape on both
3086        // corners.
3087        let p = process_with_annotation("tatara.pleme.io/released-from", "Failed");
3088        assert_eq!(
3089            p.annotation("tatara.pleme.io/released-from").unwrap_or(""),
3090            "Failed"
3091        );
3092        let mut q = Process::new("y", empty_spec());
3093        q.metadata.annotations = None;
3094        assert_eq!(
3095            q.annotation("tatara.pleme.io/released-from").unwrap_or(""),
3096            ""
3097        );
3098    }
3099
3100    #[test]
3101    fn annotation_composes_borrow_equality_tail_matching_pre_lift_pool() {
3102        // Pins the exact tail shape `tatara-pool-reconciler::
3103        // controller_pool::process_belongs_to_pool` composed pre-lift:
3104        // an `Option<&str>` compared with `== Some(pool_name)` for the
3105        // membership gate. Post-lift the callsite composes
3106        // `p.annotation(POOL) == Some(pool_name)` verbatim; this test
3107        // pins that the borrow-form primitive returns exactly the
3108        // shape the equality gate expects.
3109        let p = process_with_annotation("tatara.pleme.io/pool", "demo-pool");
3110        assert_eq!(
3111            p.annotation("tatara.pleme.io/pool") == Some("demo-pool"),
3112            true
3113        );
3114        assert_eq!(p.annotation("tatara.pleme.io/pool") == Some("other"), false);
3115    }
3116
3117    // ─── Process::uid_or_empty substrate pins ──────────────────────────
3118    //
3119    // Pins the borrow-form metadata-projection primitive on the
3120    // `metadata.uid` axis that owns the `.metadata.uid.as_deref()
3121    // .unwrap_or("")` chain the two hand-authored
3122    // `tatara-reconciler::render` sites (`render_routing` +
3123    // `render_export_jobs`) restated by hand pre-lift. Peer to the
3124    // sibling `namespace_or_default_*` + `name_or_placeholder_*` pin
3125    // families on the metadata-slot × fallback-shape axis; all three
3126    // primitives return borrows of an owned-metadata slot with a slot-
3127    // specific fallback baked in (`"default"` for namespace, `"unnamed"`
3128    // for name, `""` for uid — the load-bearing gate value for
3129    // `owner_references_json`'s `is_empty` check). Fail-before-pass-
3130    // after granularity: `uid_or_empty` did not exist pre-lift, so any
3131    // test invoking it fails to compile pre-lift and passes post-lift.
3132
3133    #[test]
3134    fn uid_or_empty_returns_empty_string_when_metadata_uid_is_none() {
3135        // Empty-slot corner pin: the primitive collapses the no-uid
3136        // case to `""`, matching the pre-lift `.as_deref().unwrap_or("")`
3137        // chain's `""` byte-identically at both render consumer sites.
3138        // Semantically corresponds to a Process pre-metadata (fixtured
3139        // in tests, or caught mid-Forking before the API server has
3140        // stamped a `uid`); the downstream `owner_references_json`
3141        // composer gates on this exact `""` sentinel to stamp
3142        // `metadata.ownerReferences: []` rather than emit an owner-ref
3143        // pointing at a placeholder uid.
3144        let mut p = Process::new("scratch", empty_spec());
3145        p.metadata.uid = None;
3146        assert_eq!(p.uid_or_empty(), "");
3147    }
3148
3149    #[test]
3150    fn uid_or_empty_returns_borrowed_str_when_slot_is_populated() {
3151        // Happy-path pin: with a populated `metadata.uid` slot, the
3152        // primitive returns a borrowed `&str` whose contents match the
3153        // persisted `String`. A regression that reshaped / normalized
3154        // / cross-cluster-stripped the uid without touching this pin
3155        // would surface here rather than as silent skew at the two
3156        // `owner_references_json(name, uid)` emitters on the SAME
3157        // Process.
3158        let mut p = Process::new("owned-proc", empty_spec());
3159        p.metadata.uid = Some("uid-abc-123".into());
3160        assert_eq!(p.uid_or_empty(), "uid-abc-123");
3161    }
3162
3163    #[test]
3164    fn uid_or_empty_returns_empty_string_when_slot_is_explicitly_empty_string() {
3165        // Corner between the missing-slot `None` and the explicitly-
3166        // empty-string `Some("")` — both collapse to `""` at the
3167        // primitive because the downstream gate at
3168        // `owner_references_json` treats `.is_empty()` uniformly (the
3169        // empty-slot posture is what the whole primitive family
3170        // encodes: "no admissible owner reference, stamp `[]`"). A
3171        // regression that discriminated the two corners (returning a
3172        // sentinel `"<none>"` for the missing slot but `""` for the
3173        // explicit slot) would break the composition with
3174        // `owner_references_json` at the exactly-two-corner gate.
3175        let mut p = Process::new("owned-proc", empty_spec());
3176        p.metadata.uid = Some(String::new());
3177        assert_eq!(p.uid_or_empty(), "");
3178    }
3179
3180    #[test]
3181    fn uid_or_empty_is_a_zero_copy_borrow_projection() {
3182        // Borrow-discipline pin: the returned `&str` borrows the
3183        // persisted `String`'s underlying byte buffer in place — NOT
3184        // a fresh allocation or a clone. A regression that switched
3185        // the projection to an owned `String` (via `.clone()` or a
3186        // `format!` wrap) would defeat the zero-copy contract the
3187        // lift's primary strict-widening delivers, and would surface
3188        // here via pointer-identity comparison.
3189        let mut p = Process::new("owned-proc", empty_spec());
3190        p.metadata.uid = Some("uid-borrow-pin".into());
3191        let slice = p.uid_or_empty();
3192        assert!(std::ptr::eq(
3193            slice.as_ptr(),
3194            p.metadata.uid.as_ref().unwrap().as_ptr()
3195        ));
3196    }
3197
3198    #[test]
3199    fn uid_or_empty_is_a_pure_projection() {
3200        // Purity pin — repeated calls return byte-identical slices
3201        // (same pointer, same length). A regression that introduced
3202        // state (a lazy-cached normalized slot, a first-call
3203        // canonicalization pass) would surface here rather than as
3204        // silent drift between the two render consumer sites on the
3205        // SAME Process within one render pass.
3206        let mut p = Process::new("owned-proc", empty_spec());
3207        p.metadata.uid = Some("uid-pure".into());
3208        let a = p.uid_or_empty();
3209        let b = p.uid_or_empty();
3210        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3211        assert_eq!(a.len(), b.len());
3212    }
3213
3214    #[test]
3215    fn uid_or_empty_matches_pre_lift_render_chain_shape() {
3216        // Byte-identical parity pin between the borrow-form primitive
3217        // here and the pre-lift `tatara-reconciler::render` chain shape
3218        // — the exact `.metadata.uid.as_deref().unwrap_or("")`
3219        // incantation both `render_routing` (line 514) and
3220        // `render_export_jobs` (line 653) spelled by hand pre-lift.
3221        // Sweeps every corner (missing uid slot, populated uid slot,
3222        // explicitly-empty uid slot) so a regression that inserted a
3223        // normalization the pre-lift chain does NOT apply — or vice
3224        // versa — surfaces here rather than as silent drift between
3225        // the ONE substrate owner and the two consumer sites.
3226        fn pre_lift(p: &Process) -> &str {
3227            p.metadata.uid.as_deref().unwrap_or("")
3228        }
3229        // Missing slot.
3230        let mut p = Process::new("x", empty_spec());
3231        p.metadata.uid = None;
3232        assert_eq!(p.uid_or_empty(), pre_lift(&p));
3233        // Populated slot.
3234        let mut p = Process::new("x", empty_spec());
3235        p.metadata.uid = Some("uid-42".into());
3236        assert_eq!(p.uid_or_empty(), pre_lift(&p));
3237        // Explicitly-empty slot.
3238        let mut p = Process::new("x", empty_spec());
3239        p.metadata.uid = Some(String::new());
3240        assert_eq!(p.uid_or_empty(), pre_lift(&p));
3241    }
3242
3243    #[test]
3244    fn uid_or_empty_composes_with_owner_references_json_empty_gate() {
3245        // Cross-primitive composition pin — the empty-string sentinel
3246        // this primitive returns for the missing-uid corner is EXACTLY
3247        // the sentinel the sibling substrate composer
3248        // `owner_references_json(name, uid)` gates on to stamp
3249        // `metadata.ownerReferences: []`. A regression that changed
3250        // the sentinel at either end (this primitive returning
3251        // `"<none>"`, `owner_references_json` gating on `uid == "0"`
3252        // instead of `uid.is_empty()`) would break the composition
3253        // and surface here rather than as an operator-observed
3254        // orphan resource after apply.
3255        let mut p = Process::new("x", empty_spec());
3256        p.metadata.uid = None;
3257        let refs = crate::owner_references_json("some-name", p.uid_or_empty());
3258        assert!(
3259            refs.is_empty(),
3260            "empty-uid corner must produce empty owner-refs array"
3261        );
3262
3263        p.metadata.uid = Some("real-uid".into());
3264        let refs = crate::owner_references_json("some-name", p.uid_or_empty());
3265        assert_eq!(
3266            refs.len(),
3267            1,
3268            "populated-uid corner must produce one owner-ref entry"
3269        );
3270    }
3271
3272    // ─── Process::owned_name_or_empty substrate pins ─────────────────
3273    //
3274    // Pins the owned-form metadata-projection primitive on the
3275    // `metadata.name` axis that owns the
3276    // `.metadata.name.clone().unwrap_or_default()` chain the two hand-
3277    // authored `tatara-pool-reconciler::controller_pool` sites (the
3278    // `PoolMember` seed at line 68 + the `PoolMemberSnapshot` desired-
3279    // count seed at line 108) restated by hand pre-lift. Peer to the
3280    // sibling `uid_or_empty` pin family on the (return-form × fallback-
3281    // value) axis pair — `uid_or_empty` owns the BORROW + empty-sentinel
3282    // corner (`&str` for owner-ref emitters gating on `.is_empty()`);
3283    // this method owns the OWNED + empty-sentinel corner (`String` for
3284    // struct-literal / HashMap-key row-builder consumers whose
3285    // downstream fills a `String` field with the load-bearing `""`
3286    // sentinel). Fail-before-pass-after granularity: `owned_name_or_empty`
3287    // did not exist pre-lift, so any test invoking it fails to compile
3288    // pre-lift and passes post-lift.
3289
3290    #[test]
3291    fn owned_name_or_empty_returns_empty_string_when_metadata_name_is_none() {
3292        // Empty-slot corner pin: the primitive collapses the no-name
3293        // case to `String::new()`, matching the pre-lift
3294        // `.clone().unwrap_or_default()` chain's empty `String` byte-
3295        // identically at both pool-reconciler consumer sites.
3296        // Semantically corresponds to a Process pre-metadata-name (test
3297        // fixture, dynamic API response pre-name-resolution); the
3298        // downstream `PoolMember { process_name, .. }` slot then holds
3299        // `""` as a stable "no name to key by" signal rather than a
3300        // display placeholder that would silently alias distinct rows.
3301        let mut p = Process::new("scratch", empty_spec());
3302        p.metadata.name = None;
3303        assert_eq!(p.owned_name_or_empty(), String::new());
3304    }
3305
3306    #[test]
3307    fn owned_name_or_empty_returns_owned_string_when_slot_is_populated() {
3308        // Happy-path pin: with a populated `metadata.name` slot, the
3309        // primitive returns an owned `String` whose contents match the
3310        // persisted `String`. A regression that reshaped / normalized
3311        // / case-folded the name without touching this pin would surface
3312        // here rather than as silent skew between the two pool-member
3313        // seeds keying on the SAME Process's name.
3314        let p = Process::new("api", empty_spec());
3315        assert_eq!(p.owned_name_or_empty(), "api");
3316    }
3317
3318    #[test]
3319    fn owned_name_or_empty_returns_empty_string_when_slot_is_explicitly_empty_string() {
3320        // Corner between the missing-slot `None` and the explicitly-
3321        // empty-string `Some(String::new())` — both collapse to `""` at
3322        // the primitive because the downstream pool-member consumers
3323        // treat both corners uniformly (no name, no key). A regression
3324        // that discriminated the two corners (returning a sentinel
3325        // `"<none>"` for the missing slot but `""` for the explicit
3326        // slot) would break `String::is_empty` gating at the row-builder
3327        // callsites without moving this pin.
3328        let mut p = Process::new("scratch", empty_spec());
3329        p.metadata.name = Some(String::new());
3330        assert_eq!(p.owned_name_or_empty(), String::new());
3331        assert!(p.owned_name_or_empty().is_empty());
3332    }
3333
3334    #[test]
3335    fn owned_name_or_empty_is_a_pure_projection() {
3336        // Purity pin — repeated calls return byte-identical `String`
3337        // values. A regression that introduced state (a lazy-cached
3338        // normalized slot, a first-call canonicalization pass) would
3339        // surface here rather than as silent drift between the pool-
3340        // member seed and the desired-count snapshot seed on the SAME
3341        // Process within one reconcile pass.
3342        let p = Process::new("stable-name", empty_spec());
3343        assert_eq!(p.owned_name_or_empty(), p.owned_name_or_empty());
3344    }
3345
3346    #[test]
3347    fn owned_name_or_empty_returns_independent_owned_string() {
3348        // Owned-discipline pin: the returned `String` is an independent
3349        // allocation the caller may consume, `.push_str` into, or move
3350        // into a struct-literal `process_name: String` slot — NOT a
3351        // shared reference into `metadata.name`. A regression that
3352        // switched the projection to a `Cow`-shaped variant or a slice-
3353        // form projection would defeat the owned-form contract the two
3354        // pool-reconciler struct-literal consumers depend on (a slice
3355        // cannot land in a `process_name: String` slot without a re-
3356        // clone), and would surface here at compile time via the mutate-
3357        // in-place test below.
3358        let p = Process::new("owned-proc", empty_spec());
3359        let mut owned = p.owned_name_or_empty();
3360        owned.push_str("-mutated");
3361        assert_eq!(owned, "owned-proc-mutated");
3362        // The Process's own slot is unchanged — the returned String
3363        // owns its own byte buffer, disjoint from `metadata.name`.
3364        assert_eq!(p.metadata.name.as_deref(), Some("owned-proc"));
3365    }
3366
3367    #[test]
3368    fn owned_name_or_empty_matches_pre_lift_controller_pool_chain_shape() {
3369        // Byte-identical parity pin between the owned-form primitive
3370        // here and the pre-lift `tatara-pool-reconciler::controller_pool`
3371        // chain shape — the exact `.metadata.name.clone().unwrap_or_default()`
3372        // incantation both `PoolMember` seed (line 68) and
3373        // `PoolMemberSnapshot` seed (line 108) spelled by hand pre-lift.
3374        // Sweeps every corner (missing name slot, populated name slot,
3375        // explicitly-empty name slot) so a regression that inserted a
3376        // normalization the pre-lift chain does NOT apply — or vice
3377        // versa — surfaces here rather than as silent drift between
3378        // the ONE substrate owner and the two consumer sites.
3379        fn pre_lift(p: &Process) -> String {
3380            p.metadata.name.clone().unwrap_or_default()
3381        }
3382        // Missing slot.
3383        let mut p = Process::new("x", empty_spec());
3384        p.metadata.name = None;
3385        assert_eq!(p.owned_name_or_empty(), pre_lift(&p));
3386        // Populated slot.
3387        let p = Process::new("real-name", empty_spec());
3388        assert_eq!(p.owned_name_or_empty(), pre_lift(&p));
3389        // Explicitly-empty slot.
3390        let mut p = Process::new("x", empty_spec());
3391        p.metadata.name = Some(String::new());
3392        assert_eq!(p.owned_name_or_empty(), pre_lift(&p));
3393    }
3394
3395    #[test]
3396    fn owned_name_or_empty_shares_empty_sentinel_with_uid_or_empty() {
3397        // Cross-primitive coherence pin — the empty-string fallback this
3398        // primitive returns for the missing-name corner is the SAME
3399        // sentinel the sibling borrow-form primitive `uid_or_empty`
3400        // returns for the missing-uid corner. Both partition the OWNED
3401        // × BORROW corner of the metadata-slot family on identical
3402        // fallback semantics ("the slot is unset"), so a consumer that
3403        // switches between them based on downstream ownership
3404        // requirements never sees a different missing-slot spelling as
3405        // a side effect. A regression that drifted either sentinel
3406        // (this primitive returning `"<unnamed>"`, `uid_or_empty`
3407        // returning `"<none>"`) would break the partition and surface
3408        // here rather than as silent shape drift across the family.
3409        let mut p = Process::new("scratch", empty_spec());
3410        p.metadata.name = None;
3411        p.metadata.uid = None;
3412        assert_eq!(p.owned_name_or_empty(), p.uid_or_empty());
3413        assert!(p.owned_name_or_empty().is_empty());
3414        assert!(p.uid_or_empty().is_empty());
3415    }
3416
3417    #[test]
3418    fn owned_name_or_empty_returns_distinct_fallback_from_name_or_placeholder() {
3419        // Axis-partition pin — the owned + empty-sentinel primitive here
3420        // and the borrow + display-placeholder primitive
3421        // [`Self::name_or_placeholder`] MUST return distinct fallback
3422        // values on the missing-name corner. The distinction is load-
3423        // bearing: `owned_name_or_empty` is for HashMap-key / row-builder
3424        // consumers that need distinct keys for missing-name Processes
3425        // (empty string collides only with other missing-name rows,
3426        // never with a real "unnamed" Process); `name_or_placeholder`
3427        // is for log-line / display consumers that render the
3428        // `"unnamed"` word to operators. A regression that unified the
3429        // two fallbacks (either primitive returning the other's
3430        // sentinel) would silently collapse missing-name pool members
3431        // into a display-string key or expose the empty sentinel to
3432        // operator log lines. This pin catches either drift.
3433        let mut p = Process::new("scratch", empty_spec());
3434        p.metadata.name = None;
3435        assert_eq!(p.owned_name_or_empty(), "");
3436        assert_eq!(p.name_or_placeholder(), Process::UNNAMED_PLACEHOLDER);
3437        assert_ne!(p.owned_name_or_empty(), p.name_or_placeholder());
3438    }
3439
3440    // ─── Process::declared_parent_pid substrate pins ─────────────────
3441    //
3442    // Pins the borrow-form spec-projection primitive on the declared
3443    // parent-PID axis that owns the `.spec.identity.parent.as_deref()`
3444    // chain the two hand-authored `tatara-reconciler::phase_machine`
3445    // sites (`handle_forking` ALLOCATE-PID composer + `handle_exiting`
3446    // SIGTERM-cascade child-fan-out filter) restated by hand pre-lift.
3447    // Peer to the sibling `observed_pid_*` pin family on the (spec-
3448    // declared × status-observed) axis pair; both compose the same
3449    // borrow-form `Option<&str>` return-shape skeleton on distinct
3450    // slots (`spec.identity.parent` vs. `status.pid`). Fail-before-
3451    // pass-after granularity: `declared_parent_pid` did not exist
3452    // pre-lift, so any test invoking it fails to compile pre-lift and
3453    // passes post-lift.
3454    fn process_with_declared_parent(parent: Option<&str>) -> Process {
3455        let mut spec = empty_spec();
3456        spec.identity.parent = parent.map(str::to_string);
3457        Process::new("child-proc", spec)
3458    }
3459
3460    #[test]
3461    fn declared_parent_pid_returns_none_when_slot_is_none() {
3462        // Empty-slot corner pin: the primitive collapses the no-
3463        // parent case to `None`, matching the pre-lift `.as_deref()`
3464        // chain's `None` byte-identically at both reconciler consumer
3465        // sites. Semantically corresponds to a Process authored at
3466        // cluster init (PID 1) with no upstream parent — the
3467        // ALLOCATE-PID composer feeds `None` into `pid::allocate_pid`
3468        // to signal "no prefix", and the SIGTERM cascade's filter
3469        // never matches such a Process because a child's declared
3470        // parent can never equal `Some(pid)` when the slot is `None`.
3471        let p = process_with_declared_parent(None);
3472        assert!(p.declared_parent_pid().is_none());
3473    }
3474
3475    #[test]
3476    fn declared_parent_pid_returns_borrowed_str_when_slot_is_populated() {
3477        // Happy-path pin: with a populated `spec.identity.parent`
3478        // slot, the primitive returns a borrowed `&str` whose
3479        // contents match the persisted `String`. A regression that
3480        // filtered / reshaped / canonicalized the string would
3481        // surface here rather than as silent skew at the child-fan-
3482        // out filter's `.declared_parent_pid() == Some(pid)`
3483        // equality check on the SAME parent-child pair.
3484        let p = process_with_declared_parent(Some("seph.1"));
3485        assert_eq!(p.declared_parent_pid(), Some("seph.1"));
3486    }
3487
3488    #[test]
3489    fn declared_parent_pid_is_a_zero_copy_borrow_projection() {
3490        // Borrow-discipline pin: the returned `&str` borrows the
3491        // persisted `String`'s underlying byte buffer in place —
3492        // NOT a fresh allocation or a clone. A regression that
3493        // switched the projection to an owned `String` (via
3494        // `.clone()` or `.to_owned()`) would defeat the zero-copy
3495        // contract the lift's primary strict-widening delivers.
3496        // The `handle_exiting` cascade filter runs per candidate
3497        // child across the cluster-wide Process list; a per-row
3498        // `String::clone` would allocate one heap block per non-
3499        // matching row, so the borrow-form primitive is load-
3500        // bearing for large clusters. Peer to the sibling
3501        // `observed_pid_is_a_zero_copy_borrow_projection` pin on
3502        // the status-observed side of the axis pair.
3503        let p = process_with_declared_parent(Some("seph.1"));
3504        let borrowed = p.declared_parent_pid().expect("populated slot");
3505        let persisted = p.spec.identity.parent.as_ref().unwrap();
3506        assert!(std::ptr::eq(borrowed.as_ptr(), persisted.as_ptr()));
3507    }
3508
3509    #[test]
3510    fn declared_parent_pid_is_a_pure_projection() {
3511        // Purity pin: calling the projection twice on the same
3512        // `Process` returns byte-identical `&str`s (same pointer,
3513        // same length). A regression that introduced state — a
3514        // lazy-cached slice materialized on first call, a
3515        // normalization step that ran once and cached — would
3516        // surface here rather than as silent drift between the
3517        // ALLOCATE-PID composer and the SIGTERM cascade's child-
3518        // fan-out filter within one reconcile pass.
3519        let p = process_with_declared_parent(Some("seph.1.3"));
3520        let a = p.declared_parent_pid().expect("populated slot");
3521        let b = p.declared_parent_pid().expect("populated slot");
3522        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3523        assert_eq!(a.len(), b.len());
3524    }
3525
3526    #[test]
3527    fn declared_parent_pid_matches_pre_lift_reconciler_chain_shape() {
3528        // Byte-identical parity pin between the borrow-form primitive
3529        // here and the pre-lift `tatara-reconciler::phase_machine`
3530        // `.spec.identity.parent.as_deref()` chain shape. Sweeps
3531        // every corner every callsite plausibly encounters (empty
3532        // slot, populated with a hierarchical PID). A regression
3533        // that inserted a normalization step at the primitive the
3534        // pre-lift chain does NOT apply — or vice versa — surfaces
3535        // here rather than as silent drift between the pre-lift
3536        // consumer sites and the ONE substrate owner they now route
3537        // through. Peer to
3538        // `observed_pid_matches_pre_lift_reconciler_chain_shape` on
3539        // the sibling axis's borrow-form primitive.
3540        fn pre_lift(p: &Process) -> Option<&str> {
3541            p.spec.identity.parent.as_deref()
3542        }
3543        // Empty slot.
3544        let p = process_with_declared_parent(None);
3545        assert_eq!(p.declared_parent_pid(), pre_lift(&p));
3546        // Populated with a hierarchical PID.
3547        let p = process_with_declared_parent(Some("seph.1"));
3548        assert_eq!(p.declared_parent_pid(), pre_lift(&p));
3549        // Populated with a deeper hierarchical PID.
3550        let p = process_with_declared_parent(Some("seph.1.7.42"));
3551        assert_eq!(p.declared_parent_pid(), pre_lift(&p));
3552    }
3553
3554    #[test]
3555    fn declared_parent_pid_preserves_hierarchical_pid_format() {
3556        // Format-preservation pin: the hierarchical PID path
3557        // (dotted-segment form `seph.1.7`, matching the ported
3558        // `convergence-controller/src/identity.rs` scheme) reaches
3559        // the caller with segments and separators byte-identical
3560        // to the persisted `String`. A regression that inserted a
3561        // canonicalization pass (a segment-count validator, a
3562        // separator swap `.` → `/`, a leading/trailing whitespace
3563        // trim) would silently misroute the SIGTERM cascade's
3564        // `declared_parent_pid() == Some(pid)` comparator against
3565        // children whose `parent` field was authored in the ported
3566        // scheme's exact form — the SAME children the observed_pid
3567        // primitive is pinned to match on the other side of the
3568        // axis pair.
3569        for parent in ["seph", "seph.1", "seph.1.7", "seph.1.7.42"] {
3570            let p = process_with_declared_parent(Some(parent));
3571            assert_eq!(p.declared_parent_pid(), Some(parent));
3572        }
3573    }
3574
3575    #[test]
3576    fn declared_parent_pid_composes_with_observed_pid_for_child_fanout_filter() {
3577        // Cross-axis coherence pin against the sibling
3578        // [`Self::observed_pid`] on the (spec-declared × status-
3579        // observed) axis pair: a child's `.declared_parent_pid()`
3580        // and its parent's `.observed_pid()` compose through the
3581        // SAME borrow-form `Option<&str>` skeleton so the
3582        // `handle_exiting` cascade filter's equality gate holds
3583        // structurally. A regression that skewed EITHER primitive's
3584        // return-form (return-shape, borrow discipline, empty-slot
3585        // collapse) would silently misroute every SIGTERM cascade
3586        // on the parent-child pair. This pin re-reads both primitives
3587        // at test time so the composition holds iff both live paths
3588        // are the current implementation.
3589        // Parent Process: has an observed PID.
3590        let mut parent = Process::new("parent-proc", empty_spec());
3591        parent.status = Some(ProcessStatus {
3592            pid: Some("seph.1".to_string()),
3593            ..Default::default()
3594        });
3595        // Child Process: declared parent matches parent's observed PID.
3596        let child = process_with_declared_parent(Some("seph.1"));
3597        // The `handle_exiting` filter's equality gate:
3598        // `child.declared_parent_pid() == Some(parent.observed_pid()?)`.
3599        let parent_pid = parent.observed_pid().expect("parent has PID");
3600        assert_eq!(child.declared_parent_pid(), Some(parent_pid));
3601        // Sibling Process with an unrelated declared parent must NOT
3602        // match the same parent — pins that the filter's SKIP branch
3603        // holds on the other side of the axis pair.
3604        let sibling = process_with_declared_parent(Some("seph.2"));
3605        assert_ne!(sibling.declared_parent_pid(), Some(parent_pid));
3606    }
3607
3608    // ─── Process::declared_name_override substrate pins ──────────────
3609    //
3610    // Pins the borrow-form spec-projection primitive on the declared
3611    // name-override sub-axis of the declared-identity axis that owns
3612    // the `.spec.identity.name_override.as_deref()` chain the two
3613    // hand-authored `tatara-reconciler::phase_machine` sites
3614    // (`handle_pending` DECLARE composer + `handle_forking` ALLOCATE-
3615    // PID rehydration branch) restated by hand pre-lift. Peer to the
3616    // sibling `declared_parent_pid_*` pin family on the (parent ×
3617    // name-override) sub-axis pair; both compose the same borrow-form
3618    // `Option<&str>` return-shape skeleton on distinct slots
3619    // (`spec.identity.name_override` vs `spec.identity.parent`).
3620    // Fail-before-pass-after granularity: `declared_name_override`
3621    // did not exist pre-lift, so any test invoking it fails to
3622    // compile pre-lift and passes post-lift.
3623    fn process_with_declared_name_override(name_override: Option<&str>) -> Process {
3624        let mut spec = empty_spec();
3625        spec.identity.name_override = name_override.map(str::to_string);
3626        Process::new("some-proc", spec)
3627    }
3628
3629    #[test]
3630    fn declared_name_override_returns_none_when_slot_is_none() {
3631        // Empty-slot corner pin: the primitive collapses the no-
3632        // override case to `None`, matching the pre-lift `.as_deref()`
3633        // chain's `None` byte-identically at both reconciler consumer
3634        // sites. Semantically corresponds to a Process authored
3635        // WITHOUT the human-name-override escape hatch — the default;
3636        // `derive_identity` then computes the name from the content
3637        // hash and stamps `name_override: false` on the resulting
3638        // [`Identity`].
3639        let p = process_with_declared_name_override(None);
3640        assert!(p.declared_name_override().is_none());
3641    }
3642
3643    #[test]
3644    fn declared_name_override_returns_borrowed_str_when_slot_is_populated() {
3645        // Happy-path pin: with a populated `spec.identity
3646        // .name_override` slot, the primitive returns a borrowed
3647        // `&str` whose contents match the persisted `String`. A
3648        // regression that filtered / reshaped / canonicalized the
3649        // string at the primitive (as opposed to inside
3650        // `derive_identity`, where the trim/empty-filter lives today)
3651        // would surface here rather than as silent skew between the
3652        // DECLARE composer and the ALLOCATE-PID rehydration branch on
3653        // the SAME Process spec.
3654        let p = process_with_declared_name_override(Some("observability-stack"));
3655        assert_eq!(p.declared_name_override(), Some("observability-stack"));
3656    }
3657
3658    #[test]
3659    fn declared_name_override_is_a_zero_copy_borrow_projection() {
3660        // Borrow-discipline pin: the returned `&str` borrows the
3661        // persisted `String`'s underlying byte buffer in place —
3662        // NOT a fresh allocation or a clone. Peer to the sibling
3663        // `declared_parent_pid_is_a_zero_copy_borrow_projection` pin
3664        // on the other side of the (parent × name-override) sub-axis
3665        // pair; the borrow discipline holds structurally on BOTH
3666        // sub-axes so a future `declared_identity` composite that
3667        // returns both halves together can compose them without
3668        // dropping into an owning form.
3669        let p = process_with_declared_name_override(Some("observability-stack"));
3670        let borrowed = p.declared_name_override().expect("populated slot");
3671        let persisted = p.spec.identity.name_override.as_ref().unwrap();
3672        assert!(std::ptr::eq(borrowed.as_ptr(), persisted.as_ptr()));
3673    }
3674
3675    #[test]
3676    fn declared_name_override_is_a_pure_projection() {
3677        // Purity pin: calling the projection twice on the same
3678        // `Process` returns byte-identical `&str`s (same pointer,
3679        // same length). A regression that introduced state — a
3680        // lazy-cached slice materialized on first call, a
3681        // normalization step that ran once and cached — would
3682        // surface here rather than as silent drift between the
3683        // DECLARE composer and the ALLOCATE-PID rehydration branch
3684        // within one reconcile pass.
3685        let p = process_with_declared_name_override(Some("gateway-primary"));
3686        let a = p.declared_name_override().expect("populated slot");
3687        let b = p.declared_name_override().expect("populated slot");
3688        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3689        assert_eq!(a.len(), b.len());
3690    }
3691
3692    #[test]
3693    fn declared_name_override_matches_pre_lift_reconciler_chain_shape() {
3694        // Byte-identical parity pin between the borrow-form primitive
3695        // here and the pre-lift `tatara-reconciler::phase_machine`
3696        // `.spec.identity.name_override.as_deref()` chain shape.
3697        // Sweeps every corner every callsite plausibly encounters
3698        // (empty slot, populated with a bare name, populated with a
3699        // whitespace-containing name that `derive_identity`'s
3700        // internal trim would collapse, populated with an explicitly
3701        // empty string that `derive_identity`'s internal
3702        // `!s.is_empty()` filter would reject). A regression that
3703        // inserted a normalization step at the primitive the pre-
3704        // lift chain does NOT apply — or vice versa — surfaces here
3705        // rather than as silent drift between the pre-lift consumer
3706        // sites and the ONE substrate owner they now route through.
3707        // Peer to
3708        // `declared_parent_pid_matches_pre_lift_reconciler_chain_shape`
3709        // on the sibling sub-axis's borrow-form primitive.
3710        fn pre_lift(p: &Process) -> Option<&str> {
3711            p.spec.identity.name_override.as_deref()
3712        }
3713        // Empty slot.
3714        let p = process_with_declared_name_override(None);
3715        assert_eq!(p.declared_name_override(), pre_lift(&p));
3716        // Populated with a bare name.
3717        let p = process_with_declared_name_override(Some("observability-stack"));
3718        assert_eq!(p.declared_name_override(), pre_lift(&p));
3719        // Populated with a whitespace-containing name.
3720        let p = process_with_declared_name_override(Some("  observability-stack  "));
3721        assert_eq!(p.declared_name_override(), pre_lift(&p));
3722        // Populated with an explicitly empty string. Distinct from
3723        // the missing-slot `None` corner both at the primitive here
3724        // and at the pre-lift chain (the trim/filter that collapses
3725        // these two into the same `false`-branched
3726        // `Identity { name_override: false, .. }` lives INSIDE
3727        // `derive_identity`, NOT at the borrow site) — the primitive
3728        // MUST preserve the distinction so a future lift of the trim/
3729        // filter OUT of `derive_identity` INTO the primitive is a
3730        // conscious substrate change, not a silent one.
3731        let p = process_with_declared_name_override(Some(""));
3732        assert_eq!(p.declared_name_override(), pre_lift(&p));
3733    }
3734
3735    #[test]
3736    fn declared_name_override_preserves_raw_slot_verbatim() {
3737        // Invariance-under-`derive_identity`-normalization pin: the
3738        // primitive returns the slot's raw byte contents verbatim —
3739        // no trim, no empty-string filter, no case fold, no
3740        // normalization of any kind. `derive_identity` internally
3741        // applies `.map(str::trim).filter(|s| !s.is_empty())` before
3742        // dispatching on `Some(non_empty)` vs `None | Some(empty |
3743        // whitespace)`, but that transform lives IN `derive_identity`,
3744        // NOT at the borrow site. A regression that pulled the trim/
3745        // filter forward INTO the primitive would silently collapse
3746        // three currently-distinct corners at the borrow site (bare
3747        // populated → `Some(name)`; whitespace-only → `Some("   ")`;
3748        // empty → `Some("")`) into two (bare → `Some(name)`; the
3749        // other two → `None`). That collapse might be an intentional
3750        // substrate change some future run wants to make; if so, it
3751        // lands as a conscious edit here (with this pin updated in
3752        // the same commit) rather than as silent behavior drift.
3753        for value in ["bare", "  padded  ", "\ttabs\t", "   ", ""] {
3754            let p = process_with_declared_name_override(Some(value));
3755            assert_eq!(
3756                p.declared_name_override(),
3757                Some(value),
3758                "declared_name_override must preserve raw slot verbatim for value {value:?}"
3759            );
3760        }
3761    }
3762
3763    #[test]
3764    fn declared_name_override_composes_with_derive_identity_call_shape() {
3765        // Cross-primitive coherence pin against the [`derive_identity`]
3766        // consumer: the two live `tatara-reconciler::phase_machine`
3767        // callsites feed `p.declared_name_override()` as the second
3768        // positional argument to `derive_identity(&p.spec, …)`. This
3769        // pin exercises that exact call shape at test time so a
3770        // regression that skewed the primitive's return-form (return-
3771        // shape, borrow discipline, empty-slot collapse) surfaces
3772        // here as a shape mismatch at the [`derive_identity`] call
3773        // site rather than as silent operator-facing skew between the
3774        // DECLARE composer and the ALLOCATE-PID rehydration branch.
3775        // Populated with a bare non-empty name: `derive_identity`
3776        // dispatches on `Some(non_empty)` and stamps
3777        // `name_override: true` on the resulting [`Identity`], with
3778        // the resulting `.name` equal to the raw slot value.
3779        let p = process_with_declared_name_override(Some("gateway-primary"));
3780        let id = crate::identity::derive_identity(&p.spec, p.declared_name_override());
3781        assert!(id.name_override);
3782        assert_eq!(id.name, "gateway-primary");
3783        // Empty slot: `derive_identity` dispatches on `None` and
3784        // stamps `name_override: false` on the resulting [`Identity`],
3785        // with the resulting `.name` derived from the content hash
3786        // (NOT equal to any operator-authored slot value).
3787        let p = process_with_declared_name_override(None);
3788        let id = crate::identity::derive_identity(&p.spec, p.declared_name_override());
3789        assert!(!id.name_override);
3790    }
3791
3792    // ─── Process::observed_flux_resources substrate pins ───────────────
3793    //
3794    // Pins the borrow-form status-projection primitive that owns the
3795    // 5-line `.status.as_ref().map(|s| s.flux_resources.clone())
3796    // .unwrap_or_default()` chain the two hand-authored
3797    // `tatara-reconciler::phase_machine` sites (`handle_running` +
3798    // `handle_attested`) restated by hand pre-lift. Fail-before-pass-
3799    // after granularity: a regression that widened the missing-`status`
3800    // corner, dropped the slot, or drifted the borrow discipline
3801    // surfaces here rather than as silent operator-facing skew between
3802    // the VERIFY-phase readiness probe and the ATTEST-heartbeat drift
3803    // detector.
3804
3805    fn sample_flux_ref(name: &str) -> FluxResourceRef {
3806        // Distinct slot values so a swap between adjacent tuple
3807        // positions surfaces as an equality failure at the assertion
3808        // site — a slot-inversion regression cannot masquerade as
3809        // identity by accident. Peer to the sibling
3810        // `tatara_process::status::tests::sample_flux_ref` discipline
3811        // on the fetch-coords axis. Routes through the ONE substrate
3812        // composer [`FluxResourceRef::pending`] — the 4-slot pre-
3813        // observation-shape composer that owns the workspace-wide
3814        // `FluxResourceRef { …, ready: false, message: None,
3815        // last_check: None }` fixture literal.
3816        FluxResourceRef::pending(
3817            "kustomize.toolkit.fluxcd.io/v1",
3818            "Kustomization",
3819            name,
3820            "flux-system",
3821        )
3822    }
3823
3824    fn process_with_flux_resources(refs: Vec<FluxResourceRef>) -> Process {
3825        let mut p = Process::new("api-gateway", empty_spec());
3826        p.metadata.namespace = Some("prod".into());
3827        let mut status = ProcessStatus::default();
3828        status.flux_resources = refs;
3829        p.status = Some(status);
3830        p
3831    }
3832
3833    #[test]
3834    fn observed_flux_resources_returns_empty_slice_when_status_is_none() {
3835        // Missing-`status` corner pin: the primitive collapses the
3836        // no-status case to `&[]` so downstream `.is_empty()` /
3837        // `.len()` / iteration behave identically on a `Process`
3838        // whose status field is `None` and on one whose status
3839        // carries an empty `flux_resources` slot. Matches the
3840        // pre-lift `.unwrap_or_default()`'s empty-`Vec` corner
3841        // byte-identically at every reconciler consumer's downstream
3842        // shape.
3843        let mut p = Process::new("api", empty_spec());
3844        p.status = None;
3845        assert!(p.observed_flux_resources().is_empty());
3846        assert_eq!(p.observed_flux_resources().len(), 0);
3847    }
3848
3849    #[test]
3850    fn observed_flux_resources_returns_empty_slice_when_flux_resources_is_empty() {
3851        // Zero-refs-under-populated-status corner pin: the primitive
3852        // returns an empty slice, matching the missing-`status`
3853        // corner byte-identically. A regression that treated the two
3854        // corners differently (a `None`-vs-empty signal that
3855        // downstream consumers could grep on) would silently promote
3856        // an internal representation detail (whether the reconciler
3857        // has ever written a status subresource) into observable
3858        // behavior.
3859        let p = process_with_flux_resources(vec![]);
3860        assert!(p.observed_flux_resources().is_empty());
3861        assert_eq!(p.observed_flux_resources().len(), 0);
3862    }
3863
3864    #[test]
3865    fn observed_flux_resources_returns_slice_of_persisted_vec() {
3866        // Happy-path pin: with a populated `status.flux_resources`
3867        // slot, the primitive returns a borrowed slice whose length
3868        // and per-element identity match the persisted vector. A
3869        // regression that filtered / reshaped / deduplicated the
3870        // slice would surface here rather than as silent skew at the
3871        // downstream fetch consumers.
3872        let refs = vec![
3873            sample_flux_ref("observability-stack"),
3874            sample_flux_ref("gateway"),
3875        ];
3876        let p = process_with_flux_resources(refs.clone());
3877        let observed = p.observed_flux_resources();
3878        assert_eq!(observed.len(), 2);
3879        assert_eq!(observed[0].name, "observability-stack");
3880        assert_eq!(observed[1].name, "gateway");
3881    }
3882
3883    #[test]
3884    fn observed_flux_resources_is_a_zero_copy_borrow_projection() {
3885        // Borrow-discipline pin: the returned slice borrows the
3886        // persisted `Vec<FluxResourceRef>` in place — NOT a fresh
3887        // allocation or a clone. A regression that switched the
3888        // projection to owned refs (via `.clone()` or `.to_vec()`)
3889        // would defeat the zero-copy contract the lift's primary
3890        // strict-widening delivers (the pre-lift 5-line chain
3891        // eagerly cloned the whole vector per reconcile pass; the
3892        // post-lift primitive borrows). Peer to the sibling
3893        // `flux_resource_ref_fetch_coords_returns_borrows_of_owned_slots`
3894        // pin on the per-ref borrow-projection axis.
3895        let refs = vec![sample_flux_ref("observability-stack")];
3896        let p = process_with_flux_resources(refs);
3897        let observed = p.observed_flux_resources();
3898        let persisted = &p.status.as_ref().unwrap().flux_resources;
3899        assert!(std::ptr::eq(observed.as_ptr(), persisted.as_ptr()));
3900    }
3901
3902    #[test]
3903    fn observed_flux_resources_is_a_pure_projection() {
3904        // Purity pin: calling the projection twice on the same
3905        // `Process` returns byte-identical slices (same pointer,
3906        // same length). A regression that introduced state — a
3907        // lazy-cached slice materialized on first call, a
3908        // normalization step that ran once and cached — would
3909        // surface here rather than as silent drift between the
3910        // VERIFY-phase and ATTEST-heartbeat consumers on the SAME
3911        // `Process` within one reconcile pass.
3912        let refs = vec![sample_flux_ref("observability-stack")];
3913        let p = process_with_flux_resources(refs);
3914        let a = p.observed_flux_resources();
3915        let b = p.observed_flux_resources();
3916        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
3917        assert_eq!(a.len(), b.len());
3918    }
3919
3920    #[test]
3921    fn observed_flux_resources_matches_pre_lift_reconciler_chain_shape() {
3922        // Byte-identical parity pin between the borrow-form primitive
3923        // here and the pre-lift `tatara-reconciler::phase_machine`
3924        // 5-line chain shape. Sweeps every corner every callsite
3925        // plausibly encounters (missing status, empty flux_resources,
3926        // populated flux_resources with one ref, populated with
3927        // multiple refs). A regression that inserted a normalization
3928        // step at the primitive the pre-lift chain does NOT apply —
3929        // or vice versa — surfaces here rather than as silent drift
3930        // between the pre-lift consumer sites and the ONE substrate
3931        // owner they now route through. Peer to
3932        // `coordinates_or_none_matches_pre_lift_reconciler_helper_shape`
3933        // on the metadata axis's borrow-form primitive.
3934        // `FluxResourceRef` does not derive `PartialEq` — the parity
3935        // check walks the per-ref fetch-coords tuple (the same 4-slot
3936        // borrow projection every downstream fetch consumer routes
3937        // through) so a regression that reshaped ANY slot at ANY
3938        // index surfaces here through the sibling
3939        // `FluxResourceRef::fetch_coords` typed projection.
3940        fn pre_lift(p: &Process) -> Vec<FluxResourceRef> {
3941            p.status
3942                .as_ref()
3943                .map(|s| s.flux_resources.clone())
3944                .unwrap_or_default()
3945        }
3946        fn coord_shape(refs: &[FluxResourceRef]) -> Vec<(String, String, String, String)> {
3947            refs.iter()
3948                .map(|r| {
3949                    let (ns, av, kind, name) = r.fetch_coords();
3950                    (
3951                        ns.to_string(),
3952                        av.to_string(),
3953                        kind.to_string(),
3954                        name.to_string(),
3955                    )
3956                })
3957                .collect()
3958        }
3959        // Missing status.
3960        let mut p = Process::new("api", empty_spec());
3961        p.status = None;
3962        assert_eq!(
3963            coord_shape(p.observed_flux_resources()),
3964            coord_shape(&pre_lift(&p))
3965        );
3966        // Populated status, empty slot.
3967        let p = process_with_flux_resources(vec![]);
3968        assert_eq!(
3969            coord_shape(p.observed_flux_resources()),
3970            coord_shape(&pre_lift(&p))
3971        );
3972        // Populated status, one ref.
3973        let p = process_with_flux_resources(vec![sample_flux_ref("obs")]);
3974        assert_eq!(
3975            coord_shape(p.observed_flux_resources()),
3976            coord_shape(&pre_lift(&p))
3977        );
3978        // Populated status, multiple refs.
3979        let p = process_with_flux_resources(vec![
3980            sample_flux_ref("obs"),
3981            sample_flux_ref("gw"),
3982            sample_flux_ref("api"),
3983        ]);
3984        assert_eq!(
3985            coord_shape(p.observed_flux_resources()),
3986            coord_shape(&pre_lift(&p))
3987        );
3988    }
3989
3990    #[test]
3991    fn observed_flux_resources_missing_status_and_empty_slot_collapse_to_the_same_slice_shape() {
3992        // Cross-corner coherence pin: the missing-`status` corner and
3993        // the populated-empty-slot corner return slices whose
3994        // `.is_empty()` / `.len()` observations are IDENTICAL. A
3995        // regression that promoted the missing-`status` corner to
3996        // returning `None` (via a signature change) — or that widened
3997        // the empty-slot corner to a synthetic single-element slice
3998        // — would surface here rather than as silent operator-facing
3999        // divergence between a never-status-written Process and a
4000        // status-emptied Process.
4001        let mut p_no_status = Process::new("api", empty_spec());
4002        p_no_status.status = None;
4003        let p_empty_status = process_with_flux_resources(vec![]);
4004        assert_eq!(
4005            p_no_status.observed_flux_resources().len(),
4006            p_empty_status.observed_flux_resources().len()
4007        );
4008        assert_eq!(
4009            p_no_status.observed_flux_resources().is_empty(),
4010            p_empty_status.observed_flux_resources().is_empty()
4011        );
4012    }
4013
4014    #[test]
4015    fn observed_flux_resources_slice_preserves_persisted_ordering() {
4016        // Ordering-preservation pin: the borrowed slice preserves
4017        // the exact insertion order of the persisted vector — no
4018        // sort, no dedup, no reshape. A regression that inserted a
4019        // sort or reordering would silently misroute per-ref
4020        // observations at the downstream VERIFY-phase / ATTEST-
4021        // heartbeat consumers, both of which walk the slice
4022        // positionally and correlate the position to the observed
4023        // readiness.
4024        let refs = vec![
4025            sample_flux_ref("z-last"),
4026            sample_flux_ref("a-first"),
4027            sample_flux_ref("m-middle"),
4028        ];
4029        let p = process_with_flux_resources(refs);
4030        let observed = p.observed_flux_resources();
4031        assert_eq!(observed[0].name, "z-last");
4032        assert_eq!(observed[1].name, "a-first");
4033        assert_eq!(observed[2].name, "m-middle");
4034    }
4035
4036    // ─── Process::observed_pid substrate pins ─────────────────────────
4037    //
4038    // Pins the borrow-form status-projection primitive on the PID axis
4039    // that owns the 3-line `.status.as_ref().and_then(|s| s.pid.clone())`
4040    // chain the two hand-authored `tatara-reconciler::phase_machine`
4041    // sites (`handle_forking` ALLOCATE-PID gate + `handle_exiting`
4042    // SIGTERM cascade) restated by hand pre-lift. Peer to the sibling
4043    // `observed_flux_resources_*` pin family on the flux-resources
4044    // axis; both compose the missing-`status` fallback + borrow-form
4045    // return-shape skeleton on distinct `ProcessStatus` slots. Fail-
4046    // before-pass-after granularity: `observed_pid` did not exist
4047    // pre-lift, so any test invoking it fails to compile pre-lift and
4048    // passes post-lift.
4049
4050    fn process_with_pid(pid: Option<&str>) -> Process {
4051        let mut p = Process::new("api-gateway", empty_spec());
4052        p.metadata.namespace = Some("prod".into());
4053        let mut status = ProcessStatus::default();
4054        status.pid = pid.map(str::to_string);
4055        p.status = Some(status);
4056        p
4057    }
4058
4059    #[test]
4060    fn observed_pid_returns_none_when_status_is_none() {
4061        // Missing-`status` corner pin: the primitive collapses the
4062        // no-status case to `None` so downstream `.is_some()` /
4063        // `if let Some(_)` / `.map(...)` behave identically on a
4064        // `Process` whose status field is `None` and on one whose
4065        // status carries an unpopulated `pid` slot. Matches the
4066        // pre-lift `.and_then(...)` chain's `None` byte-identically
4067        // at every reconciler consumer's downstream shape.
4068        let mut p = Process::new("api", empty_spec());
4069        p.status = None;
4070        assert!(p.observed_pid().is_none());
4071    }
4072
4073    #[test]
4074    fn observed_pid_returns_none_when_pid_slot_is_none() {
4075        // Empty-slot-under-populated-status corner pin: the
4076        // primitive returns `None`, matching the missing-`status`
4077        // corner byte-identically. A regression that treated the
4078        // two corners differently (a `None`-vs-`Some("")` signal
4079        // that downstream consumers could grep on) would silently
4080        // promote an internal representation detail (whether the
4081        // reconciler has ever written a status subresource) into
4082        // observable behavior at the ALLOCATE-PID gate.
4083        let p = process_with_pid(None);
4084        assert!(p.observed_pid().is_none());
4085    }
4086
4087    #[test]
4088    fn observed_pid_returns_borrowed_str_when_pid_slot_is_populated() {
4089        // Happy-path pin: with a populated `status.pid` slot, the
4090        // primitive returns a borrowed `&str` whose contents match
4091        // the persisted `String`. A regression that filtered /
4092        // reshaped / canonicalized the string would surface here
4093        // rather than as silent skew at the downstream cascade
4094        // comparator's `.as_deref() == Some(...)` equality check.
4095        let p = process_with_pid(Some("seph.1.7"));
4096        assert_eq!(p.observed_pid(), Some("seph.1.7"));
4097    }
4098
4099    #[test]
4100    fn observed_pid_is_a_zero_copy_borrow_projection() {
4101        // Borrow-discipline pin: the returned `&str` borrows the
4102        // persisted `String`'s underlying byte buffer in place —
4103        // NOT a fresh allocation or a clone. A regression that
4104        // switched the projection to an owned `String` (via
4105        // `.clone()` or `.to_owned()`) would defeat the zero-copy
4106        // contract the lift's primary strict-widening delivers
4107        // (the pre-lift 3-line chain eagerly cloned the `String`
4108        // per reconcile pass at BOTH call sites even though the
4109        // ALLOCATE-PID gate immediately dropped the clone and the
4110        // SIGTERM cascade only re-borrowed it via `.as_str()`; the
4111        // post-lift primitive borrows). Peer to the sibling
4112        // `observed_flux_resources_is_a_zero_copy_borrow_projection`
4113        // pin on the flux-resources borrow-projection axis.
4114        let p = process_with_pid(Some("seph.1.7"));
4115        let observed = p.observed_pid().expect("populated slot");
4116        let persisted = p.status.as_ref().unwrap().pid.as_ref().unwrap();
4117        assert!(std::ptr::eq(observed.as_ptr(), persisted.as_ptr()));
4118    }
4119
4120    #[test]
4121    fn observed_pid_is_a_pure_projection() {
4122        // Purity pin: calling the projection twice on the same
4123        // `Process` returns byte-identical `&str`s (same pointer,
4124        // same length). A regression that introduced state — a
4125        // lazy-cached slice materialized on first call, a
4126        // normalization step that ran once and cached — would
4127        // surface here rather than as silent drift between the
4128        // ALLOCATE-PID gate and the SIGTERM cascade on the SAME
4129        // `Process` within one reconcile pass.
4130        let p = process_with_pid(Some("seph.1.7"));
4131        let a = p.observed_pid().expect("populated slot");
4132        let b = p.observed_pid().expect("populated slot");
4133        assert!(std::ptr::eq(a.as_ptr(), b.as_ptr()));
4134        assert_eq!(a.len(), b.len());
4135    }
4136
4137    #[test]
4138    fn observed_pid_matches_pre_lift_reconciler_chain_shape() {
4139        // Byte-identical parity pin between the borrow-form
4140        // primitive here and the pre-lift `tatara-reconciler
4141        // ::phase_machine` 3-line chain shape. Sweeps every corner
4142        // every callsite plausibly encounters (missing status,
4143        // empty pid slot, populated pid slot). A regression that
4144        // inserted a normalization step at the primitive the pre-
4145        // lift chain does NOT apply — or vice versa — surfaces
4146        // here rather than as silent drift between the pre-lift
4147        // consumer sites and the ONE substrate owner they now
4148        // route through. Peer to
4149        // `observed_flux_resources_matches_pre_lift_reconciler_chain_shape`
4150        // on the flux-resources axis's borrow-form primitive.
4151        fn pre_lift(p: &Process) -> Option<String> {
4152            p.status.as_ref().and_then(|s| s.pid.clone())
4153        }
4154        // Missing status.
4155        let mut p = Process::new("api", empty_spec());
4156        p.status = None;
4157        assert_eq!(p.observed_pid().map(str::to_string), pre_lift(&p));
4158        // Populated status, empty pid slot.
4159        let p = process_with_pid(None);
4160        assert_eq!(p.observed_pid().map(str::to_string), pre_lift(&p));
4161        // Populated status, populated pid slot.
4162        let p = process_with_pid(Some("seph.1.7"));
4163        assert_eq!(p.observed_pid().map(str::to_string), pre_lift(&p));
4164    }
4165
4166    #[test]
4167    fn observed_pid_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
4168        // Cross-corner coherence pin: the missing-`status` corner
4169        // and the populated-empty-slot corner return `Option`s whose
4170        // `.is_none()` observations are IDENTICAL. A regression
4171        // that promoted the missing-`status` corner to returning a
4172        // typed error (via a signature change to `Result<_, _>`) —
4173        // or that widened the empty-slot corner to a synthetic
4174        // `Some("")` — would surface here rather than as silent
4175        // operator-facing divergence between a never-status-
4176        // written Process and a status-emptied Process on the
4177        // ALLOCATE-PID gate.
4178        let mut p_no_status = Process::new("api", empty_spec());
4179        p_no_status.status = None;
4180        let p_empty_slot = process_with_pid(None);
4181        assert_eq!(
4182            p_no_status.observed_pid().is_none(),
4183            p_empty_slot.observed_pid().is_none()
4184        );
4185        assert_eq!(
4186            p_no_status.observed_pid().is_some(),
4187            p_empty_slot.observed_pid().is_some()
4188        );
4189    }
4190
4191    #[test]
4192    fn observed_pid_preserves_hierarchical_pid_format() {
4193        // Format-preservation pin: the hierarchical PID path
4194        // (dotted-segment form `seph.1.7`, matching the ported
4195        // `convergence-controller/src/identity.rs` scheme) reaches
4196        // the caller with segments and separators byte-identical
4197        // to the persisted `String`. A regression that inserted a
4198        // canonicalization pass (a segment-count validator, a
4199        // separator swap `.` → `/`, a leading/trailing whitespace
4200        // trim) would silently misroute the SIGTERM cascade's
4201        // `spec.identity.parent == Some(pid)` comparator against
4202        // children whose `parent` field was authored in the ported
4203        // scheme's exact form.
4204        for pid in ["seph", "seph.1", "seph.1.7", "seph.1.7.42"] {
4205            let p = process_with_pid(Some(pid));
4206            assert_eq!(p.observed_pid(), Some(pid));
4207        }
4208    }
4209
4210    // ─── Process::observed_attestation substrate pins ─────────────────
4211    //
4212    // Pins the borrow-form status-projection primitive on the
4213    // attestation-chain axis that owns the 3-line
4214    // `.status.as_ref().and_then(|s| s.attestation.as_ref())` chain
4215    // the two hand-authored `tatara-reconciler` sites
4216    // (`phase_machine::advance_to_attested` ATTEST composer +
4217    // `render::render_export_jobs` export-Job builder) restated by
4218    // hand pre-lift. Peer to the sibling `observed_pid_*` +
4219    // `observed_flux_resources_*` pin families; all three compose
4220    // the missing-`status` fallback + borrow-form return-shape
4221    // skeleton on distinct `ProcessStatus` slots. Fail-before-pass-
4222    // after granularity: `observed_attestation` did not exist
4223    // pre-lift, so any test invoking it fails to compile pre-lift
4224    // and passes post-lift.
4225
4226    fn sample_attestation(artifact: &str, intent: &str) -> ProcessAttestation {
4227        // Distinct pillar strings so a regression that swapped the
4228        // artifact / intent pillars silently surfaces as an
4229        // equality failure at the composed-root parity pin.
4230        ProcessAttestation::initial(artifact.to_string(), None, intent.to_string())
4231    }
4232
4233    fn process_with_attestation(attestation: Option<ProcessAttestation>) -> Process {
4234        let mut p = Process::new("api-gateway", empty_spec());
4235        p.metadata.namespace = Some("prod".into());
4236        let mut status = ProcessStatus::default();
4237        status.attestation = attestation;
4238        p.status = Some(status);
4239        p
4240    }
4241
4242    #[test]
4243    fn observed_attestation_returns_none_when_status_is_none() {
4244        // Missing-`status` corner pin: the primitive collapses the
4245        // no-status case to `None` so downstream `.is_some()` /
4246        // `if let Some(_)` / `.map(...)` behave identically on a
4247        // `Process` whose status field is `None` and on one whose
4248        // status carries an unpopulated `attestation` slot.
4249        // Matches the pre-lift `.and_then(...)` chain's `None`
4250        // byte-identically at every reconciler consumer's
4251        // downstream shape.
4252        let mut p = Process::new("api", empty_spec());
4253        p.status = None;
4254        assert!(p.observed_attestation().is_none());
4255    }
4256
4257    #[test]
4258    fn observed_attestation_returns_none_when_attestation_slot_is_none() {
4259        // Empty-slot-under-populated-status corner pin: the
4260        // primitive returns `None`, matching the missing-`status`
4261        // corner byte-identically. A regression that treated the
4262        // two corners differently (a `None`-vs-`Some(_)` signal
4263        // that downstream consumers could grep on) would silently
4264        // promote an internal representation detail (whether the
4265        // reconciler has ever written a status subresource) into
4266        // observable behavior at the ATTEST composer's
4267        // seed-vs-chain branch.
4268        let p = process_with_attestation(None);
4269        assert!(p.observed_attestation().is_none());
4270    }
4271
4272    #[test]
4273    fn observed_attestation_returns_borrow_when_slot_is_populated() {
4274        // Happy-path pin: with a populated `status.attestation`
4275        // slot, the primitive returns a borrowed
4276        // `&ProcessAttestation` whose fields match the persisted
4277        // record. A regression that filtered / reshaped /
4278        // canonicalized the record would surface here rather than
4279        // as silent skew at the downstream `prior.next(pillars)`
4280        // chain composer + the ephemeral-export receipt's
4281        // `previous_root` linker.
4282        let att = sample_attestation("art-1", "int-1");
4283        let composed_root = att.composed_root.clone();
4284        let p = process_with_attestation(Some(att));
4285        let observed = p.observed_attestation().expect("populated slot");
4286        assert_eq!(observed.artifact_hash, "art-1");
4287        assert_eq!(observed.intent_hash, "int-1");
4288        assert_eq!(observed.composed_root, composed_root);
4289        assert_eq!(observed.generation, 0);
4290        assert!(observed.previous_root.is_none());
4291    }
4292
4293    #[test]
4294    fn observed_attestation_is_a_zero_copy_borrow_projection() {
4295        // Borrow-discipline pin: the returned reference points at
4296        // the persisted `ProcessAttestation` in place — NOT a fresh
4297        // allocation or a clone. A regression that switched the
4298        // projection to an owned `ProcessAttestation` (via
4299        // `.clone()`) would defeat the zero-copy contract the
4300        // lift's primary strict-widening delivers (the pre-lift
4301        // 3-line chain returned a borrow, but the export-Job
4302        // builder then cloned `composed_root` off it; the post-
4303        // lift primitive preserves the borrow all the way to the
4304        // consumer's own cloning choice). Peer to the sibling
4305        // `observed_pid_is_a_zero_copy_borrow_projection` +
4306        // `observed_flux_resources_is_a_zero_copy_borrow_projection`
4307        // pins on the PID + flux-resources borrow-projection axes.
4308        let att = sample_attestation("art-1", "int-1");
4309        let p = process_with_attestation(Some(att));
4310        let observed = p.observed_attestation().expect("populated slot") as *const _;
4311        let persisted = p.status.as_ref().unwrap().attestation.as_ref().unwrap() as *const _;
4312        assert!(std::ptr::eq(observed, persisted));
4313    }
4314
4315    #[test]
4316    fn observed_attestation_is_a_pure_projection() {
4317        // Purity pin: calling the projection twice on the same
4318        // `Process` returns byte-identical borrows (same pointer).
4319        // A regression that introduced state — a lazy-cached
4320        // reference materialized on first call, a normalization
4321        // step that ran once and cached — would surface here
4322        // rather than as silent drift between the ATTEST composer
4323        // and the ephemeral-export receipt chain on the SAME
4324        // `Process` within one reconcile pass.
4325        let att = sample_attestation("art-1", "int-1");
4326        let p = process_with_attestation(Some(att));
4327        let a = p.observed_attestation().expect("populated slot") as *const _;
4328        let b = p.observed_attestation().expect("populated slot") as *const _;
4329        assert!(std::ptr::eq(a, b));
4330    }
4331
4332    #[test]
4333    fn observed_attestation_matches_pre_lift_reconciler_chain_shape() {
4334        // Byte-identical parity pin between the borrow-form
4335        // primitive here and the pre-lift `tatara-reconciler`
4336        // 3-line chain shape. Sweeps every corner every callsite
4337        // plausibly encounters (missing status, empty attestation
4338        // slot, populated attestation slot). A regression that
4339        // inserted a normalization step at the primitive the pre-
4340        // lift chain does NOT apply — or vice versa — surfaces
4341        // here rather than as silent drift between the pre-lift
4342        // consumer sites and the ONE substrate owner they now
4343        // route through. Peer to
4344        // `observed_pid_matches_pre_lift_reconciler_chain_shape` +
4345        // `observed_flux_resources_matches_pre_lift_reconciler_chain_shape`
4346        // on the PID + flux-resources axes.
4347        // `ProcessAttestation` does not derive `PartialEq` — the
4348        // parity check walks the `composed_root` field (the
4349        // byte-string every downstream consumer keys off) so a
4350        // regression that reshaped the record without touching
4351        // the composed-root observation surfaces here through
4352        // the receipt-chain projection.
4353        fn pre_lift(p: &Process) -> Option<String> {
4354            p.status
4355                .as_ref()
4356                .and_then(|s| s.attestation.as_ref())
4357                .map(|a| a.composed_root.clone())
4358        }
4359        // Missing status.
4360        let mut p = Process::new("api", empty_spec());
4361        p.status = None;
4362        assert_eq!(
4363            p.observed_attestation().map(|a| a.composed_root.clone()),
4364            pre_lift(&p)
4365        );
4366        // Populated status, empty attestation slot.
4367        let p = process_with_attestation(None);
4368        assert_eq!(
4369            p.observed_attestation().map(|a| a.composed_root.clone()),
4370            pre_lift(&p)
4371        );
4372        // Populated status, populated attestation slot.
4373        let p = process_with_attestation(Some(sample_attestation("art-1", "int-1")));
4374        assert_eq!(
4375            p.observed_attestation().map(|a| a.composed_root.clone()),
4376            pre_lift(&p)
4377        );
4378    }
4379
4380    #[test]
4381    fn observed_attestation_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
4382        // Cross-corner coherence pin: the missing-`status` corner
4383        // and the populated-empty-slot corner return `Option`s
4384        // whose `.is_none()` observations are IDENTICAL. A
4385        // regression that promoted the missing-`status` corner to
4386        // returning a typed error (via a signature change to
4387        // `Result<_, _>`) — or that widened the empty-slot corner
4388        // to a synthetic `Some(default_attestation)` — would
4389        // surface here rather than as silent operator-facing
4390        // divergence between a never-status-written Process and
4391        // an attestation-emptied Process on the ATTEST composer's
4392        // seed-vs-chain branch.
4393        let mut p_no_status = Process::new("api", empty_spec());
4394        p_no_status.status = None;
4395        let p_empty_slot = process_with_attestation(None);
4396        assert_eq!(
4397            p_no_status.observed_attestation().is_none(),
4398            p_empty_slot.observed_attestation().is_none()
4399        );
4400        assert_eq!(
4401            p_no_status.observed_attestation().is_some(),
4402            p_empty_slot.observed_attestation().is_some()
4403        );
4404    }
4405
4406    #[test]
4407    fn observed_attestation_preserves_chain_generation_field() {
4408        // Generation-preservation pin: a chained attestation
4409        // (`prior.next(...)` at generation N ≥ 1 with a
4410        // `previous_root` linked to `prior.composed_root`) reaches
4411        // the caller with its `generation` counter + `previous_root`
4412        // link byte-identical to the persisted record. The pre-lift
4413        // ATTEST composer discriminated exactly on this borrow's
4414        // `Some(prior)` vs `None` arm; a regression that dropped
4415        // the chain's `generation` counter (say, by folding
4416        // `next(...)` into a fresh `initial(...)` on every
4417        // reconcile pass) would silently reset every chain and
4418        // orphan every downstream `previous_root` link, but that
4419        // drift is invisible to a Process CRD reader who only
4420        // observes the LATEST composed_root.
4421        let prior = sample_attestation("art-0", "int-0");
4422        let chained = prior.next("art-1".to_string(), None, "int-1".to_string());
4423        let expected_generation = chained.generation;
4424        let expected_previous = chained.previous_root.clone();
4425        let p = process_with_attestation(Some(chained));
4426        let observed = p.observed_attestation().expect("populated slot");
4427        assert_eq!(observed.generation, expected_generation);
4428        assert_eq!(observed.generation, 1);
4429        assert_eq!(observed.previous_root, expected_previous);
4430        assert_eq!(
4431            observed.previous_root.as_deref(),
4432            Some(prior.composed_root.as_str())
4433        );
4434    }
4435
4436    // ─── Process::observed_identity substrate pins ────────────────────
4437    //
4438    // The borrow-form status-projection primitive on the resolved-
4439    // identity axis. Collapses the paired 3-line `.status.as_ref()
4440    // .and_then(|s| s.identity.<clone|as_ref>())` chain every
4441    // consumer in `tatara-reconciler` restated by hand pre-lift at
4442    // TWO sites (`phase_machine::handle_forking` seed +
4443    // `ssapply::inject_annotations` content-hash annotation
4444    // composer). Peer to the sibling `observed_pid_*` +
4445    // `observed_attestation_*` + `observed_flux_resources_*` pin
4446    // families; all four compose the same missing-`status` fallback
4447    // + borrow-form return-shape skeleton on distinct
4448    // `ProcessStatus` slots. Each pin fails-before-pass-after
4449    // granularity: `observed_identity` did not exist pre-lift, so
4450    // any test invoking it fails to compile pre-lift and passes
4451    // post-lift.
4452
4453    fn sample_identity(name: &str) -> Identity {
4454        // Distinct name + content_hash + override flag so a
4455        // regression that reshaped one slot surfaces at the
4456        // populated-slot pin's field-equality check without
4457        // aliasing the sibling slots.
4458        Identity {
4459            name: name.to_string(),
4460            content_hash: "a".repeat(26),
4461            name_override: true,
4462        }
4463    }
4464
4465    fn process_with_identity(identity: Option<Identity>) -> Process {
4466        let mut p = Process::new("api-gateway", empty_spec());
4467        p.metadata.namespace = Some("prod".into());
4468        let mut status = ProcessStatus::default();
4469        status.identity = identity;
4470        p.status = Some(status);
4471        p
4472    }
4473
4474    #[test]
4475    fn observed_identity_returns_none_when_status_is_none() {
4476        // Missing-`status` corner pin: the primitive collapses the
4477        // no-status case to `None` so downstream `.is_some()` /
4478        // `if let Some(_)` / `.cloned().unwrap_or_else(...)` behave
4479        // identically on a `Process` whose status field is `None`
4480        // and on one whose status carries an unpopulated `identity`
4481        // slot. Matches the pre-lift `.and_then(...)` chain's `None`
4482        // byte-identically at every reconciler consumer's
4483        // downstream shape.
4484        let mut p = Process::new("api", empty_spec());
4485        p.status = None;
4486        assert!(p.observed_identity().is_none());
4487    }
4488
4489    #[test]
4490    fn observed_identity_returns_none_when_identity_slot_is_none() {
4491        // Empty-slot-under-populated-status corner pin: the
4492        // primitive returns `None`, matching the missing-`status`
4493        // corner byte-identically. A regression that treated the
4494        // two corners differently (a `None`-vs-`Some(_)` signal
4495        // that downstream consumers could grep on) would silently
4496        // promote an internal representation detail (whether the
4497        // reconciler has ever written a status subresource) into
4498        // observable behavior at the FORK-time `derive_identity`
4499        // fallback branch.
4500        let p = process_with_identity(None);
4501        assert!(p.observed_identity().is_none());
4502    }
4503
4504    #[test]
4505    fn observed_identity_returns_borrow_when_slot_is_populated() {
4506        // Happy-path pin: with a populated `status.identity` slot,
4507        // the primitive returns a borrowed `&Identity` whose fields
4508        // match the persisted record. A regression that filtered /
4509        // reshaped / canonicalized the record would surface here
4510        // rather than as silent skew at the FORK-time seed's
4511        // `.cloned().unwrap_or_else(derive_identity)` composition
4512        // + the SSA-time content-hash annotation stamp on the SAME
4513        // Process.
4514        let id = sample_identity("seph");
4515        let expected = id.clone();
4516        let p = process_with_identity(Some(id));
4517        let observed = p.observed_identity().expect("populated slot");
4518        assert_eq!(observed, &expected);
4519        assert_eq!(observed.name, "seph");
4520        assert_eq!(observed.content_hash, "a".repeat(26));
4521        assert!(observed.name_override);
4522    }
4523
4524    #[test]
4525    fn observed_identity_is_a_zero_copy_borrow_projection() {
4526        // Borrow-discipline pin: the returned reference points at
4527        // the persisted `Identity` in place — NOT a fresh
4528        // allocation or a clone. A regression that switched the
4529        // projection to an owned `Identity` (via `.clone()`) would
4530        // defeat the zero-copy contract the lift's primary strict-
4531        // widening delivers (the SSA-time consumer never clones the
4532        // whole `Identity`, only the `content_hash` field it stamps
4533        // onto the annotation map, so the borrow-form return
4534        // shape's happy-path allocation count is exactly ZERO).
4535        // Peer to the sibling
4536        // `observed_attestation_is_a_zero_copy_borrow_projection`
4537        // + `observed_pid_is_a_zero_copy_borrow_projection` +
4538        // `observed_flux_resources_is_a_zero_copy_borrow_projection`
4539        // pins on the attestation-chain + PID + flux-resources
4540        // borrow-projection axes.
4541        let id = sample_identity("seph");
4542        let p = process_with_identity(Some(id));
4543        let observed = p.observed_identity().expect("populated slot") as *const _;
4544        let persisted = p.status.as_ref().unwrap().identity.as_ref().unwrap() as *const _;
4545        assert!(std::ptr::eq(observed, persisted));
4546    }
4547
4548    #[test]
4549    fn observed_identity_is_a_pure_projection() {
4550        // Purity pin: calling the projection twice on the same
4551        // `Process` returns byte-identical borrows (same pointer).
4552        // A regression that introduced state — a lazy-cached
4553        // reference materialized on first call, a normalization
4554        // step that ran once and cached — would surface here
4555        // rather than as silent drift between the FORK-time
4556        // identity seed and the SSA-time content-hash annotation
4557        // stamp on the SAME `Process` within one reconcile pass.
4558        let p = process_with_identity(Some(sample_identity("seph")));
4559        let a = p.observed_identity().expect("populated slot") as *const _;
4560        let b = p.observed_identity().expect("populated slot") as *const _;
4561        assert!(std::ptr::eq(a, b));
4562    }
4563
4564    #[test]
4565    fn observed_identity_matches_pre_lift_reconciler_chain_shape() {
4566        // Byte-identical parity pin between the borrow-form
4567        // primitive here and the pre-lift `tatara-reconciler`
4568        // 3-line chain shape. Sweeps every corner every callsite
4569        // plausibly encounters (missing status, empty identity
4570        // slot, populated identity slot). A regression that
4571        // inserted a normalization step at the primitive the pre-
4572        // lift chain does NOT apply — or vice versa — surfaces
4573        // here rather than as silent drift between the pre-lift
4574        // consumer sites and the ONE substrate owner they now
4575        // route through. Peer to
4576        // `observed_attestation_matches_pre_lift_reconciler_chain_shape`
4577        // + `observed_pid_matches_pre_lift_reconciler_chain_shape`
4578        // + `observed_flux_resources_matches_pre_lift_reconciler_chain_shape`
4579        // on the attestation-chain + PID + flux-resources axes.
4580        fn pre_lift(p: &Process) -> Option<Identity> {
4581            p.status.as_ref().and_then(|s| s.identity.clone())
4582        }
4583        // Missing status.
4584        let mut p = Process::new("api", empty_spec());
4585        p.status = None;
4586        assert_eq!(p.observed_identity().cloned(), pre_lift(&p));
4587        // Populated status, empty identity slot.
4588        let p = process_with_identity(None);
4589        assert_eq!(p.observed_identity().cloned(), pre_lift(&p));
4590        // Populated status, populated identity slot.
4591        let p = process_with_identity(Some(sample_identity("seph")));
4592        assert_eq!(p.observed_identity().cloned(), pre_lift(&p));
4593    }
4594
4595    #[test]
4596    fn observed_identity_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
4597        // Cross-corner coherence pin: the missing-`status` corner
4598        // and the populated-empty-slot corner return `Option`s
4599        // whose `.is_none()` observations are IDENTICAL. A
4600        // regression that promoted the missing-`status` corner to
4601        // returning a typed error (via a signature change to
4602        // `Result<_, _>`) — or that widened the empty-slot corner
4603        // to a synthetic `Some(derive_identity(default_spec))` —
4604        // would surface here rather than as silent operator-facing
4605        // divergence between a never-status-written Process and an
4606        // identity-cleared Process on the FORK-time seed branch.
4607        let mut p_no_status = Process::new("api", empty_spec());
4608        p_no_status.status = None;
4609        let p_empty_slot = process_with_identity(None);
4610        assert_eq!(
4611            p_no_status.observed_identity().is_none(),
4612            p_empty_slot.observed_identity().is_none()
4613        );
4614        assert_eq!(
4615            p_no_status.observed_identity().is_some(),
4616            p_empty_slot.observed_identity().is_some()
4617        );
4618    }
4619
4620    #[test]
4621    fn observed_identity_cloned_composes_with_derive_identity_fallback() {
4622        // Cross-primitive composition pin: the borrow-form
4623        // primitive threaded through `.cloned().unwrap_or_else(||
4624        // derive_identity(...))` reproduces the pre-lift FORK-time
4625        // seed's owned-`Identity` shape at every corner. Binds the
4626        // exact composition the `phase_machine::handle_forking`
4627        // consumer performs: on the populated-slot corner the
4628        // reconciler-persisted `Identity` is returned verbatim (the
4629        // fallback never fires), and on both empty corners
4630        // (missing-status + empty-slot) the fallback fires
4631        // producing a fresh `derive_identity(&spec,
4632        // name_override)`. A regression that (a) swapped the
4633        // fallback direction, (b) made `.cloned()` re-derive
4634        // instead of clone, or (c) made the empty-slot corner
4635        // return a synthetic `Some(default_identity)` collides
4636        // with the fallback surfaces here rather than as silent
4637        // FORK-time PID allocator skew.
4638        let spec = empty_spec();
4639        let fallback_expected = crate::identity::derive_identity(&spec, None);
4640        // Populated-slot corner: the seed returns the persisted
4641        // identity, NOT the derive fallback.
4642        let persisted = sample_identity("seph");
4643        let p = process_with_identity(Some(persisted.clone()));
4644        let seed = p.observed_identity().cloned().unwrap_or_else(|| {
4645            crate::identity::derive_identity(&p.spec, p.declared_name_override())
4646        });
4647        assert_eq!(seed, persisted);
4648        assert_ne!(seed, fallback_expected);
4649        // Empty-slot corner: the seed fires the derive fallback.
4650        let p = process_with_identity(None);
4651        let seed = p.observed_identity().cloned().unwrap_or_else(|| {
4652            crate::identity::derive_identity(&p.spec, p.declared_name_override())
4653        });
4654        assert_eq!(seed, fallback_expected);
4655        // Missing-status corner: the seed fires the derive
4656        // fallback, byte-identical to the empty-slot corner.
4657        let mut p = Process::new("api-gateway", empty_spec());
4658        p.metadata.namespace = Some("prod".into());
4659        p.status = None;
4660        let seed = p.observed_identity().cloned().unwrap_or_else(|| {
4661            crate::identity::derive_identity(&p.spec, p.declared_name_override())
4662        });
4663        assert_eq!(seed, fallback_expected);
4664    }
4665
4666    // ─── Process::observed_phase substrate pins ───────────────────────
4667    //
4668    // The copy-form status-projection primitive on the phase axis.
4669    // Collapses the paired 3-line `.status.as_ref().map(|s| s.phase)`
4670    // chain every consumer in `tatara-reconciler` restated by hand
4671    // pre-lift at FIVE sites. Peer to the borrow-form
4672    // `observed_pid_*` + `observed_flux_resources_*` +
4673    // `observed_attestation_*` pin families; all four compose the
4674    // same missing-`status` fallback skeleton on distinct
4675    // `ProcessStatus` slots, with the phase-axis form returning
4676    // `Option<ProcessPhase>` (copy of a `Copy` scalar) rather than
4677    // `Option<&T>` (borrow) because the underlying slot is a bare
4678    // `ProcessPhase` — no allocation to borrow past, and the enum
4679    // is one byte on the wire. Each pin fails-before-pass-after
4680    // granularity: `observed_phase` did not exist pre-lift, so any
4681    // test invoking it fails to compile pre-lift and passes
4682    // post-lift.
4683
4684    fn process_with_phase(phase: Option<ProcessPhase>) -> Process {
4685        let mut p = Process::new("api-gateway", empty_spec());
4686        p.metadata.namespace = Some("prod".into());
4687        if let Some(ph) = phase {
4688            let mut status = ProcessStatus::default();
4689            status.phase = ph;
4690            p.status = Some(status);
4691        }
4692        p
4693    }
4694
4695    #[test]
4696    fn observed_phase_returns_none_when_status_is_none() {
4697        // Missing-`status` corner pin: the primitive collapses the
4698        // no-status case to `None` so downstream `.unwrap_or(...)`
4699        // at every reconciler consumer chooses the default
4700        // deliberately (`Pending` for the top-level dispatch seed
4701        // + boundary evaluator + routing groupby; `Attested` for
4702        // the released-from annotation composer). Matches the
4703        // pre-lift `.map(|s| s.phase)` chain's `None`
4704        // byte-identically at every consumer's downstream shape.
4705        let mut p = Process::new("api", empty_spec());
4706        p.status = None;
4707        assert!(p.observed_phase().is_none());
4708    }
4709
4710    #[test]
4711    fn observed_phase_returns_some_default_when_status_is_populated_with_default_phase() {
4712        // Populated-status corner pin: the primitive returns
4713        // `Some(ProcessPhase::default())` — a `ProcessStatus`
4714        // constructed via `default()` carries `phase: Pending`
4715        // because the phase field is a bare `ProcessPhase` (not
4716        // `Option<ProcessPhase>`), so there is NO "empty slot"
4717        // corner peer to the borrow-form projections' empty-slot
4718        // pins. A regression that reshaped the return type to
4719        // filter out `Pending` (treating it as "unset") would
4720        // surface here and silently break the top-level
4721        // dispatcher's Pending → Forking transition on a Process
4722        // freshly written by the reconciler.
4723        let p = process_with_phase(Some(ProcessPhase::default()));
4724        assert_eq!(p.observed_phase(), Some(ProcessPhase::Pending));
4725        assert_eq!(p.observed_phase(), Some(ProcessPhase::default()));
4726    }
4727
4728    #[test]
4729    fn observed_phase_returns_persisted_phase_when_status_is_populated() {
4730        // Happy-path pin: with a populated `status.phase` slot,
4731        // the primitive returns the persisted `ProcessPhase`.
4732        // A regression that filtered / reshaped / canonicalized
4733        // the phase would surface here rather than as silent
4734        // skew at the top-level dispatcher's phase handler
4735        // dispatch on the SAME Process.
4736        let p = process_with_phase(Some(ProcessPhase::Running));
4737        assert_eq!(p.observed_phase(), Some(ProcessPhase::Running));
4738    }
4739
4740    #[test]
4741    fn observed_phase_is_a_pure_projection() {
4742        // Purity pin: two consecutive calls return byte-identical
4743        // `Option<ProcessPhase>` values (no lazy materialization,
4744        // no interior mutation of `self`). Peer to the sibling
4745        // `observed_pid_is_a_pure_projection` +
4746        // `observed_flux_resources_is_a_pure_projection` +
4747        // `observed_attestation_is_a_pure_projection` pins; all
4748        // four bind the pure-projection discipline on the ONE
4749        // substrate accessor per status slot.
4750        let p = process_with_phase(Some(ProcessPhase::Attested));
4751        let a = p.observed_phase();
4752        let b = p.observed_phase();
4753        assert_eq!(a, b);
4754        assert_eq!(a, Some(ProcessPhase::Attested));
4755    }
4756
4757    #[test]
4758    fn observed_phase_matches_pre_lift_reconciler_chain_shape() {
4759        // Parity pin: sweeps the two corners every pre-lift
4760        // consumer plausibly encountered (missing status,
4761        // populated status with a particular phase) and compares
4762        // the substrate call against a hand-authored pre-lift
4763        // chain byte-identically. A regression that reshaped ANY
4764        // of the two corners would surface here rather than as
4765        // silent operator-facing skew between the top-level
4766        // dispatcher and any of the four other reconciler
4767        // consumers on the SAME `Process`.
4768        fn pre_lift(p: &Process) -> Option<ProcessPhase> {
4769            p.status.as_ref().map(|s| s.phase)
4770        }
4771        let mut p = Process::new("api", empty_spec());
4772        p.status = None;
4773        assert_eq!(p.observed_phase(), pre_lift(&p));
4774        let p = process_with_phase(Some(ProcessPhase::Running));
4775        assert_eq!(p.observed_phase(), pre_lift(&p));
4776        let p = process_with_phase(Some(ProcessPhase::Attested));
4777        assert_eq!(p.observed_phase(), pre_lift(&p));
4778        let p = process_with_phase(Some(ProcessPhase::Failed));
4779        assert_eq!(p.observed_phase(), pre_lift(&p));
4780    }
4781
4782    #[test]
4783    fn observed_phase_default_unwrap_matches_pre_lift_pending_default() {
4784        // Callsite-shape pin: three of the FIVE pre-lift consumers
4785        // (`controller::reconcile`, `boundary::evaluate_process_phase`,
4786        // `table_controller::stable_name_group_key`) closed the
4787        // 3-line chain with `.unwrap_or(ProcessPhase::Pending)`
4788        // (identical to `.unwrap_or_default()`). This pin binds
4789        // that call-site shape: `observed_phase().unwrap_or
4790        // (Pending)` returns `Pending` on missing status and the
4791        // persisted phase otherwise. A regression that swapped
4792        // the `None` sentinel's downstream default would surface
4793        // here rather than as silent skew at three of the five
4794        // consumer sites.
4795        let mut p = Process::new("api", empty_spec());
4796        p.status = None;
4797        assert_eq!(
4798            p.observed_phase().unwrap_or(ProcessPhase::Pending),
4799            ProcessPhase::Pending
4800        );
4801        let p = process_with_phase(Some(ProcessPhase::Running));
4802        assert_eq!(
4803            p.observed_phase().unwrap_or(ProcessPhase::Pending),
4804            ProcessPhase::Running
4805        );
4806    }
4807
4808    #[test]
4809    fn observed_phase_attested_unwrap_matches_pre_lift_released_from_default() {
4810        // Callsite-shape pin: the ONE pre-lift consumer
4811        // (`phase_machine::p_current_phase_str` — the
4812        // released-from annotation composer) closed the 3-line
4813        // chain with `.unwrap_or(ProcessPhase::Attested)` rather
4814        // than the `Default` (`Pending`). This pin binds that
4815        // call-site shape: `observed_phase().unwrap_or(Attested)`
4816        // returns `Attested` on missing status and the persisted
4817        // phase otherwise. A regression that folded the
4818        // `Attested`-default consumer into the `Pending`-default
4819        // majority would break the SIGSTOP/SIGCONT release gate's
4820        // "which annotation label to emit" branch — the pin binds
4821        // the primitive at the raw `Option<ProcessPhase>` form so
4822        // this default choice stays local at the callsite.
4823        let mut p = Process::new("api", empty_spec());
4824        p.status = None;
4825        assert_eq!(
4826            p.observed_phase().unwrap_or(ProcessPhase::Attested),
4827            ProcessPhase::Attested
4828        );
4829        let p = process_with_phase(Some(ProcessPhase::Failed));
4830        assert_eq!(
4831            p.observed_phase().unwrap_or(ProcessPhase::Attested),
4832            ProcessPhase::Failed
4833        );
4834    }
4835
4836    #[test]
4837    fn observed_phase_preserves_every_process_phase_variant() {
4838        // Round-trip pin: every `ProcessPhase` variant round-
4839        // trips through the primitive unchanged. Peer to the
4840        // sibling `observed_pid_preserves_hierarchical_pid_format`
4841        // pin's dotted-segment sweep; this pin sweeps the closed
4842        // set of `ProcessPhase` variants directly so a
4843        // canonicalization pass that dropped or reshaped one
4844        // (e.g. folded `Reconverging` back into `Execing`, or
4845        // remapped `Zombie` to `Reaped`) surfaces here rather
4846        // than as silent skew at the SIGSTOP/SIGCONT release
4847        // gate's phase-name annotation branch. Covers every
4848        // variant the `ProcessPhase::DeriveClosedSet` enumerates
4849        // so a future variant addition surfaces via the closed-
4850        // set macro rather than at a silent partial sweep.
4851        for phase in [
4852            ProcessPhase::Pending,
4853            ProcessPhase::Forking,
4854            ProcessPhase::Execing,
4855            ProcessPhase::Running,
4856            ProcessPhase::Attested,
4857            ProcessPhase::Reconverging,
4858            ProcessPhase::Releasing,
4859            ProcessPhase::Exiting,
4860            ProcessPhase::Failed,
4861            ProcessPhase::Zombie,
4862            ProcessPhase::Reaped,
4863        ] {
4864            let p = process_with_phase(Some(phase));
4865            assert_eq!(
4866                p.observed_phase(),
4867                Some(phase),
4868                "phase variant {phase:?} did not round-trip"
4869            );
4870        }
4871    }
4872
4873    // ─── Process::observed_phase_or_pending substrate pins ─────────────
4874    //
4875    // Pins the copy-form status-projection primitive on the phase
4876    // axis with the `Pending` sink applied. Sibling to the raw
4877    // `observed_phase_*` pin family on the (return-form × fallback
4878    // shape) axis pair — the raw-`Option` corner stays with the
4879    // sibling family; this pin family opens the `Pending`-defaulted
4880    // corner that four of the five pre-lift `observed_phase`
4881    // consumers wrote by hand. Fail-before-pass-after granularity:
4882    // `observed_phase_or_pending` did not exist pre-lift, so any
4883    // test invoking it fails to compile pre-lift and passes
4884    // post-lift.
4885
4886    #[test]
4887    fn observed_phase_or_pending_returns_pending_when_status_is_none() {
4888        // Missing-`status` corner pin: the primitive collapses the
4889        // no-status case to `Pending` — the sink four of the five
4890        // pre-lift `observed_phase` consumers wrote by hand
4891        // (`controller::reconcile` / `boundary::
4892        // evaluate_process_phase` / `table_controller::
4893        // stable_name_group_key` / `controller_pool::reconcile_pool`)
4894        // and the sentinel `ProcessPhase::default()` returns. A
4895        // regression that folded the `None` sink to any other phase
4896        // (e.g. `Forking` — treating "not yet observed" as "already
4897        // dispatched") would silently mis-seed the top-level
4898        // dispatcher's `Pending → Forking` transition and surface as
4899        // operator-visible reconcile-cycle skew on a freshly-forked
4900        // Process rather than at this pin.
4901        let mut p = Process::new("api", empty_spec());
4902        p.status = None;
4903        assert_eq!(p.observed_phase_or_pending(), ProcessPhase::Pending);
4904    }
4905
4906    #[test]
4907    fn observed_phase_or_pending_returns_persisted_phase_when_status_is_populated() {
4908        // Populated-status corner pin: the primitive passes through
4909        // the persisted `ProcessPhase` unchanged — the sink only
4910        // fires on missing `status`, not on a populated one carrying
4911        // a `Pending`-adjacent variant. Two variants pinned to
4912        // separate the "pass through the persisted phase" arm from
4913        // the "sink fires" arm: `Running` (mid-lifecycle) and
4914        // `Attested` (post-verify) both round-trip unchanged where
4915        // a regression that always returned `Pending` (dropped the
4916        // pass-through arm entirely) would surface here rather than
4917        // as silent skew at every reconciler's per-phase branch.
4918        let p = process_with_phase(Some(ProcessPhase::Running));
4919        assert_eq!(p.observed_phase_or_pending(), ProcessPhase::Running);
4920        let p = process_with_phase(Some(ProcessPhase::Attested));
4921        assert_eq!(p.observed_phase_or_pending(), ProcessPhase::Attested);
4922    }
4923
4924    #[test]
4925    fn observed_phase_or_pending_matches_pre_lift_unwrap_or_pending_chain_shape() {
4926        // Byte-identical parity pin: the primitive's return equals
4927        // the pre-lift two-link `.observed_phase().unwrap_or
4928        // (ProcessPhase::Pending)` chain at every one of the four
4929        // corner values (missing `status` → `Pending`, populated
4930        // with `Pending` → `Pending`, populated with a mid-lifecycle
4931        // variant → pass-through, populated with a terminal variant
4932        // → pass-through). A regression that swapped the sink to
4933        // `ProcessPhase::default()` (currently equivalent to
4934        // `Pending`) would keep this pin green until the enum's
4935        // `Default` impl drifted — the explicit `Pending` spelling
4936        // in the pin binds the operator-visible label rather than
4937        // the derived `Default`, so a future rename or reordering
4938        // of `ProcessPhase` variants that shifted `Default` off
4939        // `Pending` would surface here rather than as silent skew
4940        // at the four downstream consumer sites.
4941        let pre_lift = |p: &Process| p.observed_phase().unwrap_or(ProcessPhase::Pending);
4942        let mut p = Process::new("api", empty_spec());
4943        p.status = None;
4944        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4945        let p = process_with_phase(Some(ProcessPhase::Pending));
4946        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4947        let p = process_with_phase(Some(ProcessPhase::Running));
4948        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4949        let p = process_with_phase(Some(ProcessPhase::Reaped));
4950        assert_eq!(p.observed_phase_or_pending(), pre_lift(&p));
4951    }
4952
4953    #[test]
4954    fn observed_phase_or_pending_is_a_pure_projection() {
4955        // Purity pin: two back-to-back calls on the same `Process`
4956        // return the same `ProcessPhase` — the primitive stamps no
4957        // side effect (no clock read, no metadata write, no
4958        // `status` mutation) despite the sibling `observed_phase`
4959        // taking `&self` too. Peer to the sibling `observed_phase`
4960        // purity pin; a regression that folded a clock read (e.g.
4961        // "if the sink fired, stamp `phase_since = Utc::now()`")
4962        // into the primitive would surface here rather than at the
4963        // consumer sites' downstream reconcile-cycle behavior.
4964        let p = process_with_phase(Some(ProcessPhase::Running));
4965        let a = p.observed_phase_or_pending();
4966        let b = p.observed_phase_or_pending();
4967        assert_eq!(a, b);
4968    }
4969
4970    #[test]
4971    fn observed_phase_or_pending_preserves_every_process_phase_variant() {
4972        // Round-trip pin: every `ProcessPhase` variant round-trips
4973        // through the primitive unchanged when the `status` slot is
4974        // populated. Peer to the sibling `observed_phase_preserves
4975        // _every_process_phase_variant` sweep; this pin sweeps the
4976        // closed set through the `Pending`-sinked accessor rather
4977        // than the raw-`Option` accessor so a canonicalization pass
4978        // that dropped or reshaped one variant (e.g. folded
4979        // `Reconverging` back into `Execing`, remapped `Zombie` to
4980        // `Reaped`) surfaces at BOTH primitives' pin sets rather
4981        // than as silent skew at a subset of the reconciler
4982        // consumers. Covers every variant the
4983        // `ProcessPhase::DeriveClosedSet` enumerates so a future
4984        // variant addition surfaces via the closed-set macro rather
4985        // than at a silent partial sweep.
4986        for phase in [
4987            ProcessPhase::Pending,
4988            ProcessPhase::Forking,
4989            ProcessPhase::Execing,
4990            ProcessPhase::Running,
4991            ProcessPhase::Attested,
4992            ProcessPhase::Reconverging,
4993            ProcessPhase::Releasing,
4994            ProcessPhase::Exiting,
4995            ProcessPhase::Failed,
4996            ProcessPhase::Zombie,
4997            ProcessPhase::Reaped,
4998        ] {
4999            let p = process_with_phase(Some(phase));
5000            assert_eq!(
5001                p.observed_phase_or_pending(),
5002                phase,
5003                "phase variant {phase:?} did not round-trip through observed_phase_or_pending"
5004            );
5005        }
5006    }
5007
5008    // ─── Process::observed_phase_since substrate pins ──────────────────
5009    //
5010    // Pins the copy-form status-projection primitive on the
5011    // `status.phase_since` axis that owns the paired 5-line
5012    // `.status.as_ref().and_then(|s| s.phase_since).unwrap_or_else
5013    // (Utc::now)` chain the pool reconciler's per-owned-Process
5014    // `PoolMember { entered_state_at: … }` seed restated by hand pre-
5015    // lift. Peer to the sibling `observed_phase_*` +
5016    // `observed_identity_*` + `observed_attestation_*` +
5017    // `observed_flux_resources_*` + `observed_pid_*` + `created_at_*`
5018    // pin families — all six / seven primitives project a wire-format
5019    // `Option<T>` slot into a `Copy`-or-borrow inner value at ONE
5020    // owner. Fail-before-pass-after granularity: `observed_phase_since`
5021    // did not exist pre-lift, so any test invoking it fails to
5022    // compile pre-lift and passes post-lift.
5023
5024    fn process_with_phase_since(phase_since: Option<DateTime<Utc>>) -> Process {
5025        let mut p = Process::new("api-gateway", empty_spec());
5026        p.metadata.namespace = Some("prod".into());
5027        let mut status = ProcessStatus::default();
5028        status.phase_since = phase_since;
5029        p.status = Some(status);
5030        p
5031    }
5032
5033    #[test]
5034    fn observed_phase_since_returns_none_when_status_is_none() {
5035        // Missing-`status` corner pin: the primitive collapses the
5036        // no-status case to `None` so the pool reconciler's `PoolMember
5037        // { entered_state_at: p.observed_phase_since().unwrap_or_else
5038        // (Utc::now), .. }` seed synthesizes a "just entered" anchor
5039        // at its own tail rather than materializing a stale timestamp
5040        // at the substrate. Matches the pre-lift `.and_then(|s| s
5041        // .phase_since)` chain's `None` byte-identically at the
5042        // consumer's downstream tail.
5043        let mut p = Process::new("api", empty_spec());
5044        p.status = None;
5045        assert!(p.observed_phase_since().is_none());
5046    }
5047
5048    #[test]
5049    fn observed_phase_since_returns_none_when_slot_is_empty() {
5050        // Populated-status + empty-slot corner pin: a `ProcessStatus`
5051        // whose `phase_since` slot is `None` (a freshly-forked
5052        // Process whose reconciler has not yet stamped a first
5053        // transition) collapses to `None` at the primitive. The
5054        // paired-corner collapse with the missing-`status` corner
5055        // (both → `None`) matches what `.and_then` produces
5056        // structurally — one `None` cannot recover into a `Some` at
5057        // the flat outer wrapper. A regression that swapped the outer
5058        // combinator to `.map(|s| s.phase_since)` would flatten to
5059        // `Option<Option<_>>` and the compiler would reject the
5060        // signature, but a regression that "synthesized" a default
5061        // anchor at the substrate (e.g. `Utc::now()` on the empty
5062        // slot) would silently break the callsite's own
5063        // `.unwrap_or_else(Utc::now)` tail's semantics — the sink
5064        // fires ONCE at the callsite, not twice.
5065        let p = process_with_phase_since(None);
5066        assert!(p.observed_phase_since().is_none());
5067    }
5068
5069    #[test]
5070    fn observed_phase_since_returns_populated_timestamp_verbatim() {
5071        // Populated-slot corner pin: with a populated `status
5072        // .phase_since` slot, the primitive returns the persisted
5073        // `DateTime<Utc>` verbatim — no rounding, no timezone
5074        // stripping, no `Time` wrapper leaked. A regression that
5075        // canonicalized the timestamp (e.g. truncated to the second,
5076        // stripped the timezone marker) would surface here rather
5077        // than as silent skew at the pool reconciler's per-member
5078        // entered-state-at seed comparison against `Utc::now()`
5079        // downstream at `pool_phase_from_members`.
5080        let anchor = crate::time::seconds_ago(720);
5081        let p = process_with_phase_since(Some(anchor));
5082        assert_eq!(p.observed_phase_since(), Some(anchor));
5083    }
5084
5085    #[test]
5086    fn observed_phase_since_is_a_pure_projection() {
5087        // Purity pin: two consecutive calls return byte-identical
5088        // `Option<DateTime<Utc>>` values (no lazy materialization,
5089        // no interior mutation of `self`, no wall-clock read on the
5090        // empty corner). Peer to the sibling
5091        // `is_being_deleted_is_a_pure_projection` +
5092        // `created_at_is_a_pure_projection` +
5093        // `observed_phase_is_a_pure_projection` +
5094        // `observed_phase_or_pending_is_a_pure_projection` pins; all
5095        // five bind the pure-projection discipline on the ONE
5096        // substrate accessor per metadata / status slot. A
5097        // regression that folded the impure `Utc::now()` sink into
5098        // this primitive (rather than keeping it at the callsite's
5099        // `.unwrap_or_else(Utc::now)` tail alongside the sibling
5100        // `created_at` seed) would surface here as two consecutive
5101        // calls that returned distinct `Some(now_1)` /
5102        // `Some(now_2)` values.
5103        let anchor = crate::time::seconds_ago(5);
5104        let p = process_with_phase_since(Some(anchor));
5105        let a = p.observed_phase_since();
5106        let b = p.observed_phase_since();
5107        assert_eq!(a, b);
5108        assert_eq!(a, Some(anchor));
5109        // Empty-slot corner: pure `None`, not a fresh `Utc::now()`.
5110        let p_empty = process_with_phase_since(None);
5111        let a = p_empty.observed_phase_since();
5112        let b = p_empty.observed_phase_since();
5113        assert_eq!(a, b);
5114        assert!(a.is_none());
5115    }
5116
5117    #[test]
5118    fn observed_phase_since_matches_pre_lift_pool_reconciler_chain_shape() {
5119        // Byte-identical parity pin between the copy-form primitive
5120        // here and the pre-lift `tatara-pool-reconciler::
5121        // controller_pool::reconcile_inner` 5-line chain shape
5122        // (without the callsite's `.unwrap_or_else(Utc::now)` tail —
5123        // that tail stays at the callsite). Sweeps every corner
5124        // every pre-lift callsite plausibly encountered: missing
5125        // `status`, populated `status` + empty `phase_since` slot,
5126        // populated `status` + populated `phase_since` slot. A
5127        // regression that inserted a normalization step at the
5128        // primitive the pre-lift chain does NOT apply — or vice
5129        // versa — surfaces here rather than as silent drift between
5130        // the pre-lift consumer site and the ONE substrate owner it
5131        // now routes through.
5132        fn pre_lift(p: &Process) -> Option<DateTime<Utc>> {
5133            p.status.as_ref().and_then(|s| s.phase_since)
5134        }
5135        // Missing status.
5136        let mut p = Process::new("x", empty_spec());
5137        p.status = None;
5138        assert_eq!(p.observed_phase_since(), pre_lift(&p));
5139        // Populated status, empty slot.
5140        let p = process_with_phase_since(None);
5141        assert_eq!(p.observed_phase_since(), pre_lift(&p));
5142        // Populated status, populated slot.
5143        let anchor = crate::time::seconds_ago(90);
5144        let p = process_with_phase_since(Some(anchor));
5145        assert_eq!(p.observed_phase_since(), pre_lift(&p));
5146    }
5147
5148    #[test]
5149    fn observed_phase_since_missing_status_and_empty_slot_collapse_to_the_same_option_shape() {
5150        // Cross-corner coherence pin: the missing-`status` corner
5151        // AND the populated-empty-slot corner return `Option`s
5152        // whose `.is_none()` observations are IDENTICAL — a
5153        // shape peer to `observed_identity_missing_status_and_empty
5154        // _slot_collapse_to_the_same_option_shape`. A regression
5155        // that promoted the missing-`status` corner to returning a
5156        // typed error (via a signature change to `Result<_, _>`) —
5157        // or that widened the empty-slot corner to a synthetic
5158        // `Some(Utc::now())` at the substrate — would surface here
5159        // rather than as silent operator-facing divergence between
5160        // a never-status-written Process and a phase-since-cleared
5161        // Process at the pool reconciler's per-member row builder.
5162        let mut p_no_status = Process::new("api", empty_spec());
5163        p_no_status.status = None;
5164        let p_empty_slot = process_with_phase_since(None);
5165        assert_eq!(
5166            p_no_status.observed_phase_since().is_none(),
5167            p_empty_slot.observed_phase_since().is_none()
5168        );
5169        assert_eq!(
5170            p_no_status.observed_phase_since().is_some(),
5171            p_empty_slot.observed_phase_since().is_some()
5172        );
5173    }
5174
5175    #[test]
5176    fn observed_phase_since_composes_with_unwrap_or_else_utc_now_tail_at_pool_seed() {
5177        // Call-site-shape pin: the `tatara-pool-reconciler::
5178        // controller_pool::reconcile_inner` per-owned-Process
5179        // `PoolMember { entered_state_at: … }` seed composes
5180        // `p.observed_phase_since().unwrap_or_else(Utc::now)`. A
5181        // regression that returned `Some(Utc::now())` on the empty
5182        // corner (folding the sink into the primitive) would break
5183        // the observable contract that a caller with a distinct
5184        // now-source (e.g. an injected `time_source: impl Fn() ->
5185        // DateTime<Utc>`, or a test-time frozen clock) could
5186        // substitute at the tail — this pin binds the empty-corner
5187        // shape by observing that the substrate returns `None` (so
5188        // the `.unwrap_or_else` runs at the callsite) and that the
5189        // populated-corner shape is byte-identical between the
5190        // substrate `Some(anchor)` and the composed
5191        // `Some(anchor).unwrap_or_else(...)` (the fallback never
5192        // fires when the corner is populated). Peer to
5193        // `created_at_composes_with_signed_duration_since_at_ttl_gate`
5194        // on the metadata-timestamp side — both bind the
5195        // composition shape at the callsite so a substrate-side
5196        // refactor cannot silently break the tail semantics.
5197        let anchor = crate::time::seconds_ago(30);
5198        // Populated corner: substrate returns `Some(anchor)` and
5199        // the composed tail returns `anchor` (fallback silent).
5200        let p = process_with_phase_since(Some(anchor));
5201        let composed = p.observed_phase_since().unwrap_or_else(Utc::now);
5202        assert_eq!(composed, anchor);
5203        // Empty corner: substrate returns `None` and the composed
5204        // tail fires `Utc::now()` at the callsite (observed as a
5205        // timestamp >= a `before` sample AND close to now).
5206        let before = Utc::now();
5207        let p = process_with_phase_since(None);
5208        assert!(p.observed_phase_since().is_none());
5209        let composed = p.observed_phase_since().unwrap_or_else(Utc::now);
5210        assert!(composed >= before);
5211        assert!(composed <= Utc::now() + chrono::Duration::seconds(1));
5212    }
5213
5214    // ─── Process::observed_phase_since_or substrate pins ────────────────
5215    //
5216    // Pins the pure composer over `Process::observed_phase_since` that
5217    // owns the paired `.observed_phase_since().unwrap_or_else(Utc::now)`
5218    // chain the pool-reconciler consumer restated by hand pre-lift
5219    // (`tatara-pool-reconciler::controller_pool::reconcile_inner`) and
5220    // that the sibling `observed_phase_since_composes_with_unwrap_or_
5221    // else_utc_now_tail_at_pool_seed` call-site-shape pin binds at
5222    // fail-before-pass-after granularity above. Peer to the sibling
5223    // `created_at_or_*` pin family — both bind the pure-composer
5224    // discipline (fallback owned by the caller, wall-clock read stays
5225    // at the callsite) at one substrate accessor per axis. Fail-before-
5226    // pass-after granularity: `observed_phase_since_or` did not exist
5227    // pre-lift, so any test invoking it fails to compile pre-lift and
5228    // passes post-lift.
5229
5230    #[test]
5231    fn observed_phase_since_or_returns_fallback_when_status_is_none() {
5232        // Missing-`status` corner pin: the composer collapses the
5233        // no-status case to the caller's fallback anchor byte-
5234        // identically to the pre-lift `.unwrap_or(fallback)` tail on
5235        // the `.and_then(|s| s.phase_since)` pure projection. A
5236        // freshly-forked Process whose reconciler has not yet stamped
5237        // a first phase-transition gets the caller's wall-clock read
5238        // (or a test's frozen anchor) synthesized so downstream
5239        // dwell-time / tie-break arithmetic proceeds without a
5240        // special-case branch at each consumer.
5241        let mut p = Process::new("api", empty_spec());
5242        p.status = None;
5243        let fallback = crate::time::seconds_ago(42);
5244        assert_eq!(p.observed_phase_since_or(fallback), fallback);
5245    }
5246
5247    #[test]
5248    fn observed_phase_since_or_returns_fallback_when_slot_is_empty() {
5249        // Populated-`status` + empty-slot corner pin: a
5250        // `ProcessStatus` whose `phase_since` slot is `None`
5251        // collapses to the caller's fallback at the composer. Peer
5252        // to the missing-`status` corner above — both compose the
5253        // `None` output of the pure projection through the same
5254        // `.unwrap_or(fallback)` tail. A regression that returned
5255        // the fallback ONLY on the missing-`status` corner (and
5256        // panicked / returned a stale sentinel on the empty-slot
5257        // corner) would silently break the pool-reconciler's
5258        // per-member row builder on freshly-forked members whose
5259        // reconciler HAD stamped an empty status but not yet a
5260        // first transition.
5261        let p = process_with_phase_since(None);
5262        let fallback = crate::time::seconds_ago(7);
5263        assert_eq!(p.observed_phase_since_or(fallback), fallback);
5264    }
5265
5266    #[test]
5267    fn observed_phase_since_or_returns_anchor_when_slot_is_populated() {
5268        // Populated-slot corner pin: with a populated
5269        // `phase_since` slot, the composer ignores the caller's
5270        // fallback and returns the observed anchor byte-identically
5271        // to the pre-lift `.unwrap_or(fallback)` pass-through.
5272        // Sibling to `observed_phase_since_returns_anchor_when_slot_
5273        // is_populated` — that pin binds the pure projection, this
5274        // pin binds the composer's pass-through on the same
5275        // populated corner.
5276        let anchor = crate::time::seconds_ago(300);
5277        let p = process_with_phase_since(Some(anchor));
5278        let unrelated_fallback = Utc::now() + chrono::Duration::seconds(9_999);
5279        assert_eq!(p.observed_phase_since_or(unrelated_fallback), anchor);
5280    }
5281
5282    #[test]
5283    fn observed_phase_since_or_is_pure_over_the_fallback_argument() {
5284        // Purity pin: the composer itself never reads the wall clock
5285        // — two consecutive calls with the SAME fallback return
5286        // byte-identical `DateTime<Utc>` values on both the missing-
5287        // slot corner (both calls return the caller's fallback) and
5288        // the populated-slot corner (both calls return the observed
5289        // anchor). Peer to the sibling `created_at_or_is_pure_over_
5290        // the_fallback_argument` pin; both bind the pure-composer
5291        // discipline on the ONE substrate accessor per timestamp
5292        // axis.
5293        let fallback = crate::time::seconds_ago(7);
5294        // Missing status.
5295        let mut p = Process::new("x", empty_spec());
5296        p.status = None;
5297        assert_eq!(
5298            p.observed_phase_since_or(fallback),
5299            p.observed_phase_since_or(fallback),
5300        );
5301        // Populated slot.
5302        let anchor = crate::time::seconds_ago(120);
5303        let p = process_with_phase_since(Some(anchor));
5304        assert_eq!(
5305            p.observed_phase_since_or(fallback),
5306            p.observed_phase_since_or(fallback),
5307        );
5308    }
5309
5310    #[test]
5311    fn observed_phase_since_or_matches_pre_lift_unwrap_or_chain_shape() {
5312        // Parity pin: sweeps the three corners every pre-lift
5313        // consumer encountered (missing status, empty slot, populated
5314        // slot) and compares the substrate call against the hand-
5315        // authored pre-lift `.observed_phase_since().unwrap_or(
5316        // fallback)` chain byte-identically. A regression that
5317        // reshaped either corner (returning the fallback on a
5318        // populated slot, returning a sentinel like `DateTime::MIN`
5319        // on the missing corner regardless of the caller's fallback)
5320        // would surface here rather than as silent operator-facing
5321        // skew between the pool convergence snapshot's observed-
5322        // transition anchor and any future observed-transition
5323        // consumer on the SAME `Process` within one reconcile pass.
5324        fn pre_lift(p: &Process, fallback: DateTime<Utc>) -> DateTime<Utc> {
5325            p.observed_phase_since().unwrap_or(fallback)
5326        }
5327        let fallback = crate::time::seconds_ago(13);
5328        // Missing status.
5329        let mut p = Process::new("x", empty_spec());
5330        p.status = None;
5331        assert_eq!(p.observed_phase_since_or(fallback), pre_lift(&p, fallback),);
5332        // Empty slot.
5333        let p = process_with_phase_since(None);
5334        assert_eq!(p.observed_phase_since_or(fallback), pre_lift(&p, fallback),);
5335        // Populated slot.
5336        let anchor = crate::time::seconds_ago(42);
5337        let p = process_with_phase_since(Some(anchor));
5338        assert_eq!(p.observed_phase_since_or(fallback), pre_lift(&p, fallback),);
5339    }
5340
5341    #[test]
5342    fn observed_phase_since_or_composes_with_utc_now_at_reconciler_callsite() {
5343        // Call-site-shape pin: the production consumer
5344        // (`controller_pool::reconcile_inner`'s per-owned-Process
5345        // `PoolMember { entered_state_at, .. }` seed) calls
5346        // `p.observed_phase_since_or(Utc::now())`. On the populated
5347        // corner the wall-clock fallback is irrelevant (the observed
5348        // anchor wins); on the missing/empty corner the fallback
5349        // becomes the resolved value within the sub-second window
5350        // between the caller's `Utc::now()` read and the assertion
5351        // below. This pin binds that the callsite composition
5352        // returns the observed anchor exactly on the populated
5353        // corner (the stable, drift-free assertion) and a "recent"
5354        // wall-clock read on the empty corner (bounded within a
5355        // two-second window to absorb scheduler jitter). A
5356        // regression that silently substituted a different fallback
5357        // (`DateTime::MIN`, a per-cluster prefix offset, a
5358        // hardcoded epoch) would surface at the second half of this
5359        // pin.
5360        // Populated corner: byte-identical to the observed anchor.
5361        let anchor = crate::time::seconds_ago(600);
5362        let p = process_with_phase_since(Some(anchor));
5363        assert_eq!(p.observed_phase_since_or(Utc::now()), anchor);
5364        // Missing status corner: within a two-second wall-clock window.
5365        let mut p = Process::new("x", empty_spec());
5366        p.status = None;
5367        let before = Utc::now();
5368        let resolved = p.observed_phase_since_or(Utc::now());
5369        let after = Utc::now();
5370        assert!(
5371            resolved >= before - chrono::Duration::seconds(2),
5372            "resolved {resolved} is before window start {before}"
5373        );
5374        assert!(
5375            resolved <= after + chrono::Duration::seconds(2),
5376            "resolved {resolved} is after window end {after}"
5377        );
5378    }
5379
5380    // ─── Process::is_being_deleted substrate pins ───────────────────────
5381    //
5382    // Pins the copy-form metadata-projection primitive on the
5383    // deletion-tombstone axis. Peer to the borrow-form + copy-form
5384    // metadata-fallback family (`namespace_or_default`,
5385    // `name_or_placeholder`, `uid_or_empty`, `coordinates_or_defaults`,
5386    // `coordinates_or_none`, `owned_coordinates_or_err`, `annotation`);
5387    // this one opens the presence-probe corner for the tombstone slot.
5388    // Fail-before-pass-after granularity: `is_being_deleted` did not
5389    // exist pre-lift, so any test invoking it fails to compile pre-
5390    // lift and passes post-lift.
5391
5392    fn tombstoned_process() -> Process {
5393        let mut p = Process::new("api-gateway", empty_spec());
5394        p.metadata.namespace = Some("prod".into());
5395        // Routes through the ONE substrate composer
5396        // `tatara_process::time::tombstone_now` — one of 12 pre-lift
5397        // exact-match sites past the ★★ PRIME-DIRECTIVE ≥ 2 threshold
5398        // for the `Some(Time(Utc::now()))` wire shape.
5399        p.metadata.deletion_timestamp = crate::time::tombstone_now();
5400        p
5401    }
5402
5403    #[test]
5404    fn is_being_deleted_returns_false_when_deletion_timestamp_is_absent() {
5405        // Missing-tombstone corner pin: the primitive collapses the
5406        // no-tombstone case to `false` so the SIGTERM preempt at
5407        // `controller::reconcile` skips the `→ Exiting` forcing
5408        // branch and the DELETE-skip at `handle_exiting`'s child
5409        // fan-out does NOT `continue` past a child that is still
5410        // healthy. Matches the pre-lift `.is_some()` chain's `false`
5411        // byte-identically at every consumer's downstream gate.
5412        let mut p = Process::new("api", empty_spec());
5413        p.metadata.deletion_timestamp = None;
5414        assert!(!p.is_being_deleted());
5415    }
5416
5417    #[test]
5418    fn is_being_deleted_returns_true_when_deletion_timestamp_is_present() {
5419        // Present-tombstone corner pin: the primitive returns
5420        // `true` on any populated `metadata.deletionTimestamp`
5421        // slot regardless of the timestamp payload — the two
5422        // consumers only read the tombstone's PRESENCE, never
5423        // its RFC-3339 timestamp value. A regression that gated
5424        // the `true` return on the timestamp being non-epoch, or
5425        // parsed the timestamp before returning, would surface
5426        // here rather than as silent skew at the SIGTERM preempt
5427        // or child-fan-out DELETE-skip on the SAME `Process`.
5428        let p = tombstoned_process();
5429        assert!(p.is_being_deleted());
5430    }
5431
5432    #[test]
5433    fn is_being_deleted_is_a_pure_projection() {
5434        // Purity pin: two consecutive calls return byte-identical
5435        // `bool` values (no lazy materialization, no interior
5436        // mutation of `self`). Peer to the sibling
5437        // `observed_phase_is_a_pure_projection` +
5438        // `observed_pid_is_a_pure_projection` +
5439        // `observed_flux_resources_is_a_pure_projection` +
5440        // `observed_attestation_is_a_pure_projection` pins; all
5441        // five bind the pure-projection discipline on the ONE
5442        // substrate accessor per metadata / status slot.
5443        let p = tombstoned_process();
5444        let a = p.is_being_deleted();
5445        let b = p.is_being_deleted();
5446        assert_eq!(a, b);
5447        assert!(a);
5448    }
5449
5450    #[test]
5451    fn is_being_deleted_matches_pre_lift_reconciler_chain_shape() {
5452        // Parity pin: sweeps the two corners every pre-lift
5453        // consumer plausibly encountered (missing tombstone,
5454        // present tombstone) and compares the substrate call
5455        // against a hand-authored pre-lift chain byte-identically.
5456        // A regression that reshaped either corner would surface
5457        // here rather than as silent operator-facing skew between
5458        // the top-level dispatcher's SIGTERM preempt and the
5459        // SIGTERM cascade's child-fan-out DELETE-skip on the
5460        // SAME `Process` within one reconcile pass.
5461        fn pre_lift(p: &Process) -> bool {
5462            p.metadata.deletion_timestamp.is_some()
5463        }
5464        let mut p = Process::new("api", empty_spec());
5465        p.metadata.deletion_timestamp = None;
5466        assert_eq!(p.is_being_deleted(), pre_lift(&p));
5467        let p = tombstoned_process();
5468        assert_eq!(p.is_being_deleted(), pre_lift(&p));
5469    }
5470
5471    #[test]
5472    fn is_being_deleted_composes_with_process_phase_is_alive_at_reconcile_preempt() {
5473        // Call-site-shape pin: the `controller::reconcile` SIGTERM
5474        // preempt composes `is_being_deleted() && current_phase
5475        // .is_alive()` — the tombstone-presence probe AND the
5476        // alive-phase gate must BOTH hold to force `→ Exiting`.
5477        // A dead-phase (`Zombie` / `Reaped` / `Failed`) Process
5478        // that carries a tombstone still runs its normal handler,
5479        // not the preempt. This pin binds that composition shape
5480        // at the primitive so a regression that flipped either
5481        // half of the `&&` (or that broadened the tombstone probe
5482        // to include the `is_alive` half implicitly) surfaces
5483        // here rather than as silent skew at the top-level
5484        // dispatch on the SAME `Process`.
5485        let mut p = tombstoned_process();
5486        // Alive + tombstoned → preempt fires.
5487        let mut alive = ProcessStatus::default();
5488        alive.phase = ProcessPhase::Running;
5489        p.status = Some(alive);
5490        assert!(p.is_being_deleted());
5491        assert!(p.observed_phase().unwrap_or_default().is_alive());
5492        // Dead + tombstoned → preempt does NOT fire (composition
5493        // with `is_alive` returns false).
5494        let mut dead = ProcessStatus::default();
5495        dead.phase = ProcessPhase::Reaped;
5496        p.status = Some(dead);
5497        assert!(p.is_being_deleted());
5498        assert!(!p.observed_phase().unwrap_or_default().is_alive());
5499    }
5500
5501    // ─── Process::created_at substrate pins ─────────────────────────
5502    //
5503    // Pins the copy-form metadata-projection primitive on the
5504    // `metadata.creationTimestamp` axis that owns the
5505    // `.metadata.creation_timestamp.as_ref().map(|t| t.0)` chain the
5506    // three hand-authored sites (`lifetime_clock::evaluate`,
5507    // `lifetime_clock::requeue_with_ttl`,
5508    // `tatara-reconciler::table_controller`) restated by hand pre-lift.
5509    // Peer to the sibling `is_being_deleted_*` +
5510    // `observed_phase_*` pin families — all three primitives project a
5511    // wire-format `Option<T>` slot into a `Copy` inner value at ONE
5512    // owner. Fail-before-pass-after granularity: `created_at` did not
5513    // exist pre-lift, so any test invoking it fails to compile pre-lift
5514    // and passes post-lift.
5515
5516    fn creation_stamped_process(t: DateTime<Utc>) -> Process {
5517        let mut p = Process::new("age-anchor", empty_spec());
5518        p.metadata.namespace = Some("prod".into());
5519        p.metadata.creation_timestamp =
5520            Some(k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(t));
5521        p
5522    }
5523
5524    #[test]
5525    fn created_at_returns_none_when_creation_timestamp_is_absent() {
5526        // Missing-slot corner pin: the primitive collapses the
5527        // no-creation-timestamp case to `None` so the TTL-expiry gate
5528        // at `lifetime_clock::evaluate` short-circuits its inner
5529        // `if let Some(...)` branch (no elapsed computation), the
5530        // requeue-budget picker returns its default sleep, and the
5531        // stable-name arbiter's `.unwrap_or_else(Utc::now)` tail
5532        // synthesizes a "just created" anchor at its own site. Matches
5533        // the pre-lift `.as_ref().map(|t| t.0)` chain's `None`
5534        // byte-identically at every consumer's downstream tail.
5535        let mut p = Process::new("api", empty_spec());
5536        p.metadata.creation_timestamp = None;
5537        assert!(p.created_at().is_none());
5538    }
5539
5540    #[test]
5541    fn created_at_returns_some_datetime_when_slot_is_populated() {
5542        // Populated-slot corner pin: with a populated
5543        // `metadata.creationTimestamp` slot, the primitive unwraps the
5544        // wire-format `Time` newtype to its inner `DateTime<Utc>` and
5545        // returns it as `Some(datetime)` — hiding the `.0` field-access
5546        // every pre-lift consumer restated to reach the underlying
5547        // instant.
5548        let anchor = crate::time::seconds_ago(300);
5549        let p = creation_stamped_process(anchor);
5550        assert_eq!(p.created_at(), Some(anchor));
5551    }
5552
5553    #[test]
5554    fn created_at_is_a_pure_projection() {
5555        // Purity pin: two consecutive calls return byte-identical
5556        // `Option<DateTime<Utc>>` values (no lazy materialization, no
5557        // interior mutation of `self`). Peer to the sibling
5558        // `is_being_deleted_is_a_pure_projection` +
5559        // `observed_phase_is_a_pure_projection` pins; all three bind
5560        // the pure-projection discipline on the ONE substrate accessor
5561        // per metadata / status slot.
5562        let anchor = Utc::now();
5563        let p = creation_stamped_process(anchor);
5564        let a = p.created_at();
5565        let b = p.created_at();
5566        assert_eq!(a, b);
5567        assert_eq!(a, Some(anchor));
5568    }
5569
5570    #[test]
5571    fn created_at_matches_pre_lift_creation_timestamp_chain_shape() {
5572        // Parity pin: sweeps the two corners every pre-lift consumer
5573        // plausibly encountered (missing slot, populated slot) and
5574        // compares the substrate call against a hand-authored pre-lift
5575        // chain byte-identically. A regression that reshaped either
5576        // corner (returning `Some(Utc::now())` on the missing slot,
5577        // returning a rounded / truncated timestamp on the populated
5578        // slot) would surface here rather than as silent operator-
5579        // facing skew between the TTL-expiry gate, the requeue-budget
5580        // picker, and the stable-name claim-arbiter tie-break on the
5581        // SAME `Process` within one reconcile pass.
5582        fn pre_lift(p: &Process) -> Option<DateTime<Utc>> {
5583            p.metadata.creation_timestamp.as_ref().map(|t| t.0)
5584        }
5585        // Missing slot.
5586        let mut p = Process::new("x", empty_spec());
5587        p.metadata.creation_timestamp = None;
5588        assert_eq!(p.created_at(), pre_lift(&p));
5589        // Populated slot.
5590        let anchor = crate::time::seconds_ago(42);
5591        let p = creation_stamped_process(anchor);
5592        assert_eq!(p.created_at(), pre_lift(&p));
5593    }
5594
5595    #[test]
5596    fn created_at_composes_with_signed_duration_since_at_ttl_gate() {
5597        // Call-site-shape pin: the `lifetime_clock::evaluate` TTL-
5598        // expiry gate composes `now.signed_duration_since(creation)`
5599        // where `creation` is the `DateTime<Utc>` returned by this
5600        // primitive's `Some` corner. A regression that returned a
5601        // per-callsite `Local` timezone (or that stripped the timezone
5602        // marker) would break the arithmetic silently. This pin
5603        // computes the elapsed duration byte-identically against the
5604        // pre-lift `.map(|t| t.0)` chain so a timezone drift surfaces
5605        // here rather than as silent skew at the TTL-expiry decision
5606        // on the SAME `Process` within one reconcile pass.
5607        let now = Utc::now();
5608        let anchor = now - chrono::Duration::seconds(120);
5609        let p = creation_stamped_process(anchor);
5610        let via_primitive = p.created_at().expect("populated slot");
5611        let via_pre_lift = p
5612            .metadata
5613            .creation_timestamp
5614            .as_ref()
5615            .map(|t| t.0)
5616            .expect("populated slot");
5617        assert_eq!(
5618            now.signed_duration_since(via_primitive),
5619            now.signed_duration_since(via_pre_lift)
5620        );
5621    }
5622
5623    // ─── Process::created_at_or substrate pins ──────────────────────
5624    //
5625    // Pins the pure composer over `Process::created_at` that owns the
5626    // paired `.created_at().unwrap_or_else(Utc::now)` chain the two
5627    // production consumers restated by hand pre-lift
5628    // (`tatara-reconciler::table_controller::reconcile_process_table`
5629    // + `tatara-pool-reconciler::controller_pool::reconcile_inner`).
5630    // Fail-before-pass-after granularity: `created_at_or` did not
5631    // exist pre-lift, so any test invoking it fails to compile
5632    // pre-lift and passes post-lift.
5633
5634    #[test]
5635    fn created_at_or_returns_fallback_when_creation_timestamp_is_absent() {
5636        // Missing-slot corner pin: the composer collapses the
5637        // no-creation-timestamp case to the caller's fallback anchor
5638        // byte-identically to the pre-lift `.unwrap_or(fallback)`
5639        // tail. A freshly-forked Process whose API server has not yet
5640        // stamped `metadata.creationTimestamp` gets the caller's
5641        // wall-clock read (or a test's frozen anchor) synthesized so
5642        // downstream dwell-time / tie-break arithmetic proceeds
5643        // without a special-case branch at each consumer.
5644        let mut p = Process::new("api", empty_spec());
5645        p.metadata.creation_timestamp = None;
5646        let fallback = crate::time::seconds_ago(42);
5647        assert_eq!(p.created_at_or(fallback), fallback);
5648    }
5649
5650    #[test]
5651    fn created_at_or_returns_anchor_when_slot_is_populated() {
5652        // Populated-slot corner pin: with a populated
5653        // `metadata.creationTimestamp` slot, the composer ignores the
5654        // caller's fallback and returns the observed anchor
5655        // byte-identically to the pre-lift `.unwrap_or(fallback)`
5656        // pass-through. Sibling to `created_at_returns_some_datetime_
5657        // when_slot_is_populated` — that pin binds the pure projection,
5658        // this pin binds the composer's pass-through on the same
5659        // populated corner.
5660        let anchor = crate::time::seconds_ago(300);
5661        let p = creation_stamped_process(anchor);
5662        let unrelated_fallback = Utc::now() + chrono::Duration::seconds(9_999);
5663        assert_eq!(p.created_at_or(unrelated_fallback), anchor);
5664    }
5665
5666    #[test]
5667    fn created_at_or_is_pure_over_the_fallback_argument() {
5668        // Purity pin: the composer itself never reads the wall clock —
5669        // two consecutive calls with the SAME fallback return
5670        // byte-identical `DateTime<Utc>` values on both the missing-
5671        // slot corner (both calls return the caller's fallback) and
5672        // the populated-slot corner (both calls return the observed
5673        // anchor). Peer to the sibling
5674        // `created_at_is_a_pure_projection` pin; both bind the pure-
5675        // projection / pure-composer discipline on the ONE substrate
5676        // accessor per axis.
5677        let fallback = crate::time::seconds_ago(7);
5678        // Missing slot.
5679        let mut p = Process::new("x", empty_spec());
5680        p.metadata.creation_timestamp = None;
5681        assert_eq!(p.created_at_or(fallback), p.created_at_or(fallback));
5682        // Populated slot.
5683        let anchor = crate::time::seconds_ago(120);
5684        let p = creation_stamped_process(anchor);
5685        assert_eq!(p.created_at_or(fallback), p.created_at_or(fallback));
5686    }
5687
5688    #[test]
5689    fn created_at_or_matches_pre_lift_unwrap_or_chain_shape() {
5690        // Parity pin: sweeps the two corners every pre-lift consumer
5691        // encountered (missing slot, populated slot) and compares the
5692        // substrate call against the hand-authored pre-lift
5693        // `.created_at().unwrap_or(fallback)` chain byte-identically.
5694        // A regression that reshaped either corner (returning the
5695        // fallback on a populated slot, returning `Utc::now()` on the
5696        // missing slot regardless of the caller's fallback) would
5697        // surface here rather than as silent operator-facing skew
5698        // between the claim-arbiter's tie-break anchor and the pool
5699        // convergence snapshot's dwell-time anchor on the SAME
5700        // `Process` within one reconcile pass.
5701        fn pre_lift(p: &Process, fallback: DateTime<Utc>) -> DateTime<Utc> {
5702            p.created_at().unwrap_or(fallback)
5703        }
5704        let fallback = crate::time::seconds_ago(13);
5705        // Missing slot.
5706        let mut p = Process::new("x", empty_spec());
5707        p.metadata.creation_timestamp = None;
5708        assert_eq!(p.created_at_or(fallback), pre_lift(&p, fallback));
5709        // Populated slot.
5710        let anchor = crate::time::seconds_ago(42);
5711        let p = creation_stamped_process(anchor);
5712        assert_eq!(p.created_at_or(fallback), pre_lift(&p, fallback));
5713    }
5714
5715    #[test]
5716    fn created_at_or_composes_with_utc_now_at_reconciler_callsites() {
5717        // Call-site-shape pin: the two production consumers
5718        // (`table_controller::reconcile_process_table` +
5719        // `controller_pool::reconcile_inner`) both call
5720        // `p.created_at_or(Utc::now())`. On the populated corner the
5721        // wall-clock fallback is irrelevant (the observed anchor
5722        // wins); on the missing corner the fallback becomes the
5723        // resolved value within the sub-second window between the
5724        // caller's `Utc::now()` read and the assertion below. This
5725        // pin binds that the callsite composition returns the
5726        // observed anchor exactly on the populated corner (the
5727        // stable, drift-free assertion) and a "recent" wall-clock
5728        // read on the missing corner (bounded within a two-second
5729        // window to absorb scheduler jitter). A regression that
5730        // silently substituted a different fallback (`DateTime::MIN`,
5731        // a per-cluster prefix offset, a hardcoded epoch) would
5732        // surface at the second half of this pin.
5733        // Populated corner: byte-identical to the observed anchor.
5734        let anchor = crate::time::seconds_ago(600);
5735        let p = creation_stamped_process(anchor);
5736        assert_eq!(p.created_at_or(Utc::now()), anchor);
5737        // Missing corner: within a two-second wall-clock window.
5738        let mut p = Process::new("x", empty_spec());
5739        p.metadata.creation_timestamp = None;
5740        let before = Utc::now();
5741        let resolved = p.created_at_or(Utc::now());
5742        let after = Utc::now();
5743        assert!(
5744            resolved >= before - chrono::Duration::seconds(2),
5745            "resolved {resolved} is before window start {before}"
5746        );
5747        assert!(
5748            resolved <= after + chrono::Duration::seconds(2),
5749            "resolved {resolved} is after window end {after}"
5750        );
5751    }
5752
5753    // ─── Process::created_at_or_now substrate pins ──────────────────
5754    //
5755    // Pins the wall-clock-anchored peer of `Process::created_at_or` —
5756    // the ONE substrate owner of the 2-arg `p.created_at_or(Utc::now())`
5757    // chain the two production consumers hand-authored pre-lift
5758    // (`tatara-reconciler::table_controller::reconcile_process_table`
5759    // + `tatara-pool-reconciler::controller_pool::reconcile_inner`).
5760    // Fail-before-pass-after granularity: `created_at_or_now` did not
5761    // exist pre-lift, so any test invoking it fails to compile pre-lift
5762    // and passes post-lift.
5763
5764    #[test]
5765    fn created_at_or_now_returns_wall_clock_when_creation_timestamp_is_absent() {
5766        // Missing-slot corner pin: the peer stamps the wall-clock read
5767        // as the resolved anchor byte-identically to
5768        // `p.created_at_or(Utc::now())` — bounded within a two-second
5769        // window to absorb scheduler jitter between the pin's own
5770        // `Utc::now()` reads and the peer's internal read. A regression
5771        // that silently substituted a different fallback source
5772        // (`DateTime::MIN`, a cached-at-module-load constant, a
5773        // per-namespace override) would surface at this window rather
5774        // than as silent tie-break skew at the claim-arbiter row seed
5775        // or dwell-time skew at the pool convergence snapshot.
5776        let mut p = Process::new("x", empty_spec());
5777        p.metadata.creation_timestamp = None;
5778        let before = Utc::now();
5779        let resolved = p.created_at_or_now();
5780        let after = Utc::now();
5781        assert!(
5782            resolved >= before - chrono::Duration::seconds(2),
5783            "resolved {resolved} is before window start {before}"
5784        );
5785        assert!(
5786            resolved <= after + chrono::Duration::seconds(2),
5787            "resolved {resolved} is after window end {after}"
5788        );
5789    }
5790
5791    #[test]
5792    fn created_at_or_now_returns_anchor_when_slot_is_populated() {
5793        // Populated-slot corner pin: with a populated
5794        // `metadata.creationTimestamp` slot, the peer's internal
5795        // `Utc::now()` fallback is irrelevant and the observed anchor
5796        // wins byte-identically to the 2-arg
5797        // `p.created_at_or(<any-fallback>)` pass-through. Sibling to
5798        // the peer `created_at_or_returns_anchor_when_slot_is_populated`
5799        // pin — both bind the pass-through discipline on the same
5800        // populated corner, one on the pure composer and one on the
5801        // wall-clock-anchored peer.
5802        let anchor = crate::time::seconds_ago(300);
5803        let p = creation_stamped_process(anchor);
5804        assert_eq!(p.created_at_or_now(), anchor);
5805    }
5806
5807    #[test]
5808    fn created_at_or_now_reads_wall_clock_at_call_time_not_module_load() {
5809        // Per-invocation wall-clock-read pin: two consecutive calls on
5810        // a missing-slot Process must return DISTINCT (or at least
5811        // monotonically-non-decreasing) `DateTime<Utc>` values, since
5812        // each call reads a fresh `Utc::now()`. A regression that
5813        // hoisted the wall-clock read to a stale module-load constant
5814        // (or cached the first-invocation value inside `Self`) would
5815        // return the SAME value on the second call — this pin surfaces
5816        // that regression directly, matching the peer-family discipline
5817        // on `PoolStatus::observed_now` / `AllocationStatus::transition_now`
5818        // / `lifetime_clock::evaluate_now` where each invocation reads
5819        // its own `Utc::now()` at the primitive's body.
5820        let mut p = Process::new("x", empty_spec());
5821        p.metadata.creation_timestamp = None;
5822        let first = p.created_at_or_now();
5823        // A `std::thread::sleep(...)` here would be flaky under CI clock
5824        // jitter; the monotonicity check (each call is >= previous)
5825        // suffices to catch the module-load-constant regression class
5826        // because two module-load-constant reads would return identical
5827        // values on a `chrono::DateTime<Utc>` field (equality, not
5828        // ordering, is what the regression breaks).
5829        let second = p.created_at_or_now();
5830        assert!(
5831            second >= first,
5832            "second `created_at_or_now` read {second} must be >= first {first}; \
5833             a regression that cached the wall-clock read at module load \
5834             would return byte-identical values"
5835        );
5836    }
5837
5838    #[test]
5839    fn created_at_or_now_matches_created_at_or_with_utc_now_bytewise() {
5840        // Delegation pin: the peer's body is `self.created_at_or(Utc::now())`
5841        // — a pure delegation, not a re-implementation. On the
5842        // populated corner both surfaces return the observed anchor
5843        // byte-identically (wall-clock fallback is irrelevant). A
5844        // regression that re-implemented the peer with different
5845        // semantics (a different fallback source, a per-slot override
5846        // that only applied to one surface) would surface at the
5847        // populated-corner half of this pin.
5848        let anchor = crate::time::seconds_ago(600);
5849        let p = creation_stamped_process(anchor);
5850        assert_eq!(p.created_at_or_now(), p.created_at_or(Utc::now()));
5851        assert_eq!(p.created_at_or_now(), anchor);
5852    }
5853
5854    #[test]
5855    fn created_at_or_now_composes_at_reconciler_callsites_verbatim() {
5856        // Cross-callsite parity pin: both production consumers
5857        // (`table_controller::reconcile_process_table` +
5858        // `controller_pool::reconcile_inner`) pre-lift called
5859        // `p.created_at_or(Utc::now())` inline; post-lift both call
5860        // `p.created_at_or_now()`. This pin sweeps both the populated
5861        // and missing corners on the SAME `Process` fixture and asserts
5862        // that both surfaces (pre-lift chain, post-lift peer) resolve
5863        // to the same anchor on the populated corner. The missing
5864        // corner is elided from this specific pin because the pre-lift
5865        // and post-lift `Utc::now()` reads happen at different call
5866        // sites (across the `p.created_at_or(Utc::now())` argument
5867        // evaluation vs. the peer's body), so an exact-equality
5868        // assertion between the two reads would race the wall clock —
5869        // the `_reads_wall_clock_at_call_time_not_module_load` pin
5870        // above already binds the per-invocation freshness invariant
5871        // on the missing corner without needing the cross-shape
5872        // equality here.
5873        let anchor = crate::time::seconds_ago(120);
5874        let p = creation_stamped_process(anchor);
5875        let pre_lift_shape = p.created_at_or(Utc::now());
5876        let post_lift_shape = p.created_at_or_now();
5877        assert_eq!(pre_lift_shape, anchor);
5878        assert_eq!(post_lift_shape, anchor);
5879        assert_eq!(pre_lift_shape, post_lift_shape);
5880    }
5881
5882    // ─── Process::resolved_ephemeral substrate pins ─────────────────
5883    //
5884    // Pins the compound spec-projection primitive on the
5885    // `spec.lifetime` axis that owns the ambiguity-aware
5886    // `resolved_ephemeral` chain the three hand-authored sites
5887    // (`lifetime_clock::evaluate`, `lifetime_clock::requeue_with_ttl`,
5888    // `tatara-reconciler::render::render_export_jobs`) restated by
5889    // hand pre-lift through TWO different chains that disagreed on
5890    // the ambiguous corner. Fail-before-pass-after granularity:
5891    // `resolved_ephemeral` did not exist pre-lift on `impl Process`,
5892    // so any test invoking it fails to compile pre-lift and passes
5893    // post-lift.
5894
5895    fn permanent_only_process() -> Process {
5896        let mut spec = empty_spec();
5897        // Routes through the ONE substrate composer
5898        // [`crate::lifetime::Lifetime::permanent`] — one of FOUR
5899        // pre-lift exact-match sites past the ★★ PRIME-DIRECTIVE ≥ 2
5900        // threshold; see the composer's doc-comment for the full
5901        // migration rationale.
5902        spec.lifetime = crate::lifetime::Lifetime::permanent();
5903        Process::new("perm", spec)
5904    }
5905
5906    fn ephemeral_only_process(ttl: &str) -> Process {
5907        let mut spec = empty_spec();
5908        // Routes through the ONE substrate composer
5909        // [`crate::lifetime::Lifetime::ephemeral`] — one of ELEVEN+
5910        // pre-lift exact-match sites past the ★★ PRIME-DIRECTIVE ≥ 2
5911        // threshold; see the composer's doc-comment for the full
5912        // migration rationale.
5913        spec.lifetime = crate::lifetime::Lifetime::ephemeral(EphemeralLifetime {
5914            ttl: ttl.into(),
5915            teardown_policy: crate::lifetime::TeardownPolicy::OnAttested,
5916            max_concurrent: 3,
5917            exports: vec![],
5918        });
5919        Process::new("eph", spec)
5920    }
5921
5922    fn ambiguous_lifetime_process() -> Process {
5923        let mut spec = empty_spec();
5924        spec.lifetime = crate::lifetime::Lifetime {
5925            permanent: Some(crate::lifetime::PermanentLifetime {}),
5926            ephemeral: Some(EphemeralLifetime::default()),
5927        };
5928        Process::new("both", spec)
5929    }
5930
5931    #[test]
5932    fn resolved_ephemeral_returns_none_when_lifetime_is_default_empty() {
5933        // Empty-default corner pin: neither slot populated. The
5934        // resolver collapses to `Permanent(&DEFAULT_PERMANENT)` and
5935        // the compound projection sees no ephemeral inner. Matches
5936        // the pre-lift `lifetime_clock::evaluate` early-return to
5937        // `AutoTerminate::Skip` byte-identically.
5938        let p = Process::new("empty-lifetime", empty_spec());
5939        assert!(p.resolved_ephemeral().is_none());
5940    }
5941
5942    #[test]
5943    fn resolved_ephemeral_returns_none_for_permanent_only_process() {
5944        // Permanent-only corner pin: the `permanent:` slot is
5945        // populated, `ephemeral:` is not. Matches the pre-lift
5946        // `lifetime_clock::evaluate` outcome — the teardown/TTL
5947        // branch is never reached on a Permanent Process, and the
5948        // export-render arm now agrees at this call site (was
5949        // previously reached through the raw `.ephemeral.as_ref()`
5950        // that also returned `None` on this same corner — no drift
5951        // here; the drift is at the ambiguous corner below).
5952        let p = permanent_only_process();
5953        assert!(p.resolved_ephemeral().is_none());
5954    }
5955
5956    #[test]
5957    fn resolved_ephemeral_returns_some_for_ephemeral_only_process() {
5958        // Ephemeral-only corner pin: the ONE arm that projects. The
5959        // returned borrow carries the operator-authored `ttl` /
5960        // `teardown_policy` / `max_concurrent` verbatim. A
5961        // regression that swapped the projection to the sibling
5962        // `permanent:` slot would surface here as a type mismatch on
5963        // the `EphemeralLifetime` fields rather than as silent
5964        // operator-facing no-op teardown at the reconciler.
5965        let p = ephemeral_only_process("42m");
5966        let e = p
5967            .resolved_ephemeral()
5968            .expect("ephemeral-only Process must project");
5969        assert_eq!(e.ttl, "42m");
5970        assert_eq!(
5971            e.teardown_policy,
5972            crate::lifetime::TeardownPolicy::OnAttested
5973        );
5974        assert_eq!(e.max_concurrent, 3);
5975    }
5976
5977    #[test]
5978    fn resolved_ephemeral_returns_none_for_ambiguous_lifetime() {
5979        // DRIFT-CLOSING CONTRACT: BOTH `permanent:` AND `ephemeral:`
5980        // slots populated is an operator-authored mis-configuration.
5981        // Pre-lift, `lifetime_clock::evaluate` (via
5982        // `resolved_ephemeral()` on `Lifetime`) collapsed this
5983        // corner to `None` and yielded `AutoTerminate::Skip`, while
5984        // `tatara-reconciler::render::render_export_jobs` walked
5985        // the naked `.spec.lifetime.ephemeral.as_ref()` chain and
5986        // returned `Some(&e)` — so the reconciler would emit export
5987        // Jobs on a Process whose teardown-triggered fire semantics
5988        // the lifetime clock refused to honor. Post-lift this
5989        // primitive collapses ambiguity to `None` at ONE site so
5990        // BOTH consumers agree. A regression that broadened the
5991        // projection back to the raw field (or that silently
5992        // "preferred ephemeral" in the ambiguous case) surfaces
5993        // here rather than as export-Job noise on a mis-configured
5994        // ephemeral.
5995        let p = ambiguous_lifetime_process();
5996        assert!(p.resolved_ephemeral().is_none());
5997        // The raw field IS populated at this corner — pins the
5998        // pre-lift `.spec.lifetime.ephemeral.as_ref()` shape that
5999        // returned `Some` here.
6000        assert!(p.spec.lifetime.ephemeral.is_some());
6001    }
6002
6003    #[test]
6004    fn resolved_ephemeral_matches_spec_lifetime_forwarder() {
6005        // Byte-identity pin: the `Process` projection delegates
6006        // through the underlying `Lifetime::resolved_ephemeral`
6007        // primitive at every corner (empty, permanent-only,
6008        // ephemeral-only, ambiguous). A regression that silently
6009        // reintroduced the raw `.ephemeral.as_ref()` shortcut, or
6010        // that decided the ambiguous case by "prefer ephemeral"
6011        // at the Process layer instead of delegating, surfaces
6012        // here.
6013        for p in [
6014            Process::new("empty", empty_spec()),
6015            permanent_only_process(),
6016            ephemeral_only_process("1h"),
6017            ambiguous_lifetime_process(),
6018        ] {
6019            let via_process = p.resolved_ephemeral();
6020            let via_lifetime = p.spec.lifetime.resolved_ephemeral();
6021            // Both borrows point into the SAME `EphemeralLifetime`
6022            // slot when present — a regression that materialized a
6023            // per-call clone at the Process layer would fail the
6024            // pointer-equality gate.
6025            match (via_process, via_lifetime) {
6026                (Some(a), Some(b)) => assert!(
6027                    std::ptr::eq(a, b),
6028                    "Process::resolved_ephemeral must borrow the same slot as Lifetime::resolved_ephemeral"
6029                ),
6030                (None, None) => {}
6031                (a, b) => panic!(
6032                    "resolved_ephemeral shape drift: process={:?}, lifetime={:?}",
6033                    a.is_some(),
6034                    b.is_some()
6035                ),
6036            }
6037        }
6038    }
6039
6040    #[test]
6041    fn resolved_ephemeral_is_a_pure_projection() {
6042        // Purity pin: two consecutive calls return borrows into the
6043        // same underlying slot (no lazy materialization, no interior
6044        // mutation of `self`). Peer to the sibling
6045        // `is_being_deleted_is_a_pure_projection` +
6046        // `observed_attestation_is_a_pure_projection` pins; all
6047        // three bind the pure-projection discipline on the ONE
6048        // substrate accessor per spec / metadata / status slot.
6049        let p = ephemeral_only_process("5m");
6050        let a = p.resolved_ephemeral();
6051        let b = p.resolved_ephemeral();
6052        match (a, b) {
6053            (Some(x), Some(y)) => assert!(std::ptr::eq(x, y)),
6054            other => panic!("expected two Some borrows into the same slot, got {other:?}"),
6055        }
6056    }
6057
6058    // ── ProcessSpec::gate_compute_defaults substrate pins ───────────────
6059    //
6060    // The 12-line `ProcessSpec { identity: <Default>, classification:
6061    // Classification::gate_compute(), intent: <Default>, boundary:
6062    // Default::default(), compliance: Default::default(), depends_on:
6063    // vec![], signals: Default::default(), lifetime: Default::default(),
6064    // routing: None, encapsulates: None, suspended: false }` struct-
6065    // literal was open-coded verbatim at eight hand-authored callsites
6066    // before this primitive closed it. These pins bind the composed
6067    // shape at fail-before-pass-after granularity so a regression that
6068    // drifted the classification baseline, promoted a defaulted slot to
6069    // a non-default, or leaked a non-baseline slot into the substrate
6070    // composer surfaces HERE rather than as silent operator-visible
6071    // drift across every test fixture that keys assertions on the
6072    // shape.
6073    fn hand_authored_pre_lift() -> ProcessSpec {
6074        ProcessSpec {
6075            identity: IdentitySpec::default(),
6076            classification: Classification::gate_compute(),
6077            intent: Intent::default(),
6078            boundary: Default::default(),
6079            compliance: Default::default(),
6080            depends_on: vec![],
6081            signals: Default::default(),
6082            lifetime: Default::default(),
6083            routing: None,
6084            encapsulates: None,
6085            suspended: false,
6086        }
6087    }
6088
6089    #[test]
6090    fn gate_compute_defaults_composes_the_classification_baseline() {
6091        // Primary shape: the classification axis rides the sibling
6092        // `Classification::gate_compute` primitive verbatim. A
6093        // regression that flipped the classification baseline (a new
6094        // `#[default]` on the sibling closed-set, a re-import through a
6095        // different composer) surfaces HERE rather than at every
6096        // downstream fixture whose assertions key on
6097        // `spec.classification`.
6098        let s = ProcessSpec::gate_compute_defaults();
6099        assert_eq!(s.classification, Classification::gate_compute());
6100    }
6101
6102    #[test]
6103    fn gate_compute_defaults_defaulted_slots_ride_sibling_defaults() {
6104        // Pins the sibling-default correspondence the doc comment
6105        // names — a regression that promoted any defaulted slot to a
6106        // non-default (a new `#[default]` on `Intent`, a `Lifetime`
6107        // baseline shift, a per-field overlay stamping through the
6108        // primitive) would move the baseline HERE rather than at every
6109        // downstream consumer.
6110        let s = ProcessSpec::gate_compute_defaults();
6111        assert_eq!(
6112            serde_json::to_value(&s.identity).unwrap(),
6113            serde_json::to_value(IdentitySpec::default()).unwrap()
6114        );
6115        assert_eq!(
6116            serde_json::to_value(&s.intent).unwrap(),
6117            serde_json::to_value(Intent::default()).unwrap()
6118        );
6119        assert_eq!(
6120            serde_json::to_value(&s.boundary).unwrap(),
6121            serde_json::to_value(Boundary::default()).unwrap()
6122        );
6123        assert_eq!(
6124            serde_json::to_value(&s.compliance).unwrap(),
6125            serde_json::to_value(ComplianceSpec::default()).unwrap()
6126        );
6127        assert!(s.depends_on.is_empty());
6128        assert_eq!(
6129            serde_json::to_value(&s.signals).unwrap(),
6130            serde_json::to_value(SignalPolicy::default()).unwrap()
6131        );
6132        assert_eq!(
6133            serde_json::to_value(&s.lifetime).unwrap(),
6134            serde_json::to_value(Lifetime::default()).unwrap()
6135        );
6136        assert!(s.routing.is_none());
6137        assert!(s.encapsulates.is_none());
6138        assert!(!s.suspended);
6139    }
6140
6141    #[test]
6142    fn gate_compute_defaults_matches_hand_authored_pre_lift_bytewise() {
6143        // Byte-identical parity pin between the substrate primitive
6144        // and the pre-lift 12-line struct-literal that recurred at
6145        // eight hand-authored sites. Compares via `serde_json` value
6146        // equality — `ProcessSpec` does not derive `PartialEq` (the
6147        // typed fields it composes over do not uniformly derive it),
6148        // so a serialize round-trip is the shape-equality currency the
6149        // pin family already uses for `ProcessSpec`-shaped assertions
6150        // elsewhere in this test module. A regression that reshaped
6151        // the primitive would diverge from the pre-lift block HERE
6152        // rather than at every downstream fixture that keys on the
6153        // shape.
6154        let composed = ProcessSpec::gate_compute_defaults();
6155        let hand_authored = hand_authored_pre_lift();
6156        assert_eq!(
6157            serde_json::to_value(&composed).unwrap(),
6158            serde_json::to_value(&hand_authored).unwrap(),
6159        );
6160    }
6161
6162    #[test]
6163    fn gate_compute_defaults_supports_struct_update_override() {
6164        // The five override sites (three `render.rs` fixtures + two
6165        // `lifetime_clock.rs` fixtures) rely on struct-update syntax
6166        // to override a single slot while the primitive supplies the
6167        // other eleven. Pin the composition here so a regression that
6168        // broke the struct-update path (e.g. a `#[non_exhaustive]`
6169        // attribute added to `ProcessSpec` that would refuse struct-
6170        // update syntax across crate boundaries) surfaces at compile
6171        // time HERE rather than as a five-site downstream break.
6172        let base = ProcessSpec::gate_compute_defaults();
6173        let overridden = ProcessSpec {
6174            suspended: true,
6175            ..ProcessSpec::gate_compute_defaults()
6176        };
6177        assert!(!base.suspended);
6178        assert!(overridden.suspended);
6179        // Every other slot rides the same default as the base.
6180        assert_eq!(
6181            serde_json::to_value(&overridden.classification).unwrap(),
6182            serde_json::to_value(&base.classification).unwrap(),
6183        );
6184        assert_eq!(
6185            serde_json::to_value(&overridden.lifetime).unwrap(),
6186            serde_json::to_value(&base.lifetime).unwrap(),
6187        );
6188    }
6189
6190    #[test]
6191    fn gate_compute_defaults_is_call_time_construction_not_a_shared_singleton() {
6192        // Two independent calls produce structurally-equal but
6193        // distinct values — pins that the primitive is a plain
6194        // constructor rather than a `lazy_static` clone whose in-
6195        // place mutation at one consumer would silently mutate the
6196        // shape at every other consumer. Mirrors the sibling
6197        // `gate_compute_is_call_time_construction_not_a_shared_singleton`
6198        // pin on `Classification::gate_compute`.
6199        let a = ProcessSpec::gate_compute_defaults();
6200        let b = ProcessSpec::gate_compute_defaults();
6201        assert_eq!(
6202            serde_json::to_value(&a).unwrap(),
6203            serde_json::to_value(&b).unwrap(),
6204        );
6205        assert!(!std::ptr::eq(&a, &b));
6206    }
6207
6208    // ─── ProcessStatus::at_phase substrate pins ─────────────────────
6209    //
6210    // The 3-line `ProcessStatus { phase: <ProcessPhase::…>, ..Default::
6211    // default() }` shape now rides through the ONE substrate composer
6212    // [`ProcessStatus::at_phase`] across the two pool-reconciler
6213    // phase-decision pin sites (`process_to_member_state_attested_
6214    // permanent_is_free`, `process_to_member_state_attested_ephemeral_
6215    // is_allocated`). These pins bind the primitive at fail-before-pass-
6216    // after granularity so a regression that drifted the phase slot
6217    // pass-through, leaked a sibling slot away from `Default`, or
6218    // hijacked the composer to stamp a static `phase_since` /
6219    // `attestation` on the `phase` transition surfaces HERE rather
6220    // than as silent phase-decision skew across the two pool-reconciler
6221    // callsites (or across any future consumer fixture that binds a
6222    // phase-observation shape).
6223
6224    #[test]
6225    fn at_phase_binds_caller_supplied_phase_verbatim_at_the_phase_slot() {
6226        // The composer's `phase` slot is the caller-supplied
6227        // `ProcessPhase` verbatim — no case-fold, no substitution, no
6228        // remapping to a peer variant. Sweep every variant so a
6229        // regression that hijacked one arm to stamp a different variant
6230        // silently would surface here (per-variant coverage matters
6231        // because the pool-reconciler's `process_to_member_state`
6232        // matcher already keys on `ProcessPhase::Attested` specifically,
6233        // and a peer variant lift would need the pass-through to
6234        // faithfully carry any of the eight variants without translation).
6235        for phase in [
6236            ProcessPhase::Pending,
6237            ProcessPhase::Forking,
6238            ProcessPhase::Execing,
6239            ProcessPhase::Running,
6240            ProcessPhase::Reconverging,
6241            ProcessPhase::Attested,
6242            ProcessPhase::Failed,
6243            ProcessPhase::Exiting,
6244        ] {
6245            let s = ProcessStatus::at_phase(phase);
6246            assert_eq!(
6247                s.phase, phase,
6248                "at_phase({phase:?}) must stamp the caller-supplied phase verbatim",
6249            );
6250        }
6251    }
6252
6253    #[test]
6254    fn at_phase_leaves_every_other_slot_at_default_no_sibling_leak() {
6255        // The composer stamps ONLY the `phase` slot — every other slot
6256        // (`pid`, `parent`, `children`, `identity`, `phase_since`,
6257        // `attestation`, `flux_resources`, `boundary`, `compliance`,
6258        // `signal_queue`, `conditions`, `message`, `exit_code`) parks at
6259        // `Default`. A regression that widened the composer's stamped
6260        // slot set (an auto-stamped `phase_since = Utc::now()` overlay
6261        // that would break byte-identical parity with the pre-lift
6262        // 3-line struct-literal, a defaulted-non-empty `flux_resources`
6263        // fixture that would silently reshape every pool-reconciler
6264        // phase-decision test's downstream `.flux_resources` observation)
6265        // surfaces HERE at the pin block rather than as silent skew
6266        // at every fixture consumer.
6267        let s = ProcessStatus::at_phase(ProcessPhase::Attested);
6268        assert!(s.pid.is_none(), "pid parks at Default (None)");
6269        assert!(s.parent.is_none(), "parent parks at Default (None)");
6270        assert!(
6271            s.children.is_empty(),
6272            "children parks at Default (Vec::new())"
6273        );
6274        assert!(s.identity.is_none(), "identity parks at Default (None)");
6275        assert!(
6276            s.phase_since.is_none(),
6277            "phase_since parks at Default (None) — a call-time Utc::now() stamp would break \
6278             byte-identical parity with the pre-lift `..Default::default()` struct-update shape",
6279        );
6280        assert!(
6281            s.attestation.is_none(),
6282            "attestation parks at Default (None)"
6283        );
6284        assert!(
6285            s.flux_resources.is_empty(),
6286            "flux_resources parks at Default (Vec::new())",
6287        );
6288        assert_eq!(
6289            serde_json::to_value(&s.boundary).unwrap(),
6290            serde_json::to_value(BoundaryStatus::default()).unwrap(),
6291            "boundary parks at Default",
6292        );
6293        assert_eq!(
6294            serde_json::to_value(&s.compliance).unwrap(),
6295            serde_json::to_value(ComplianceStatus::default()).unwrap(),
6296            "compliance parks at Default",
6297        );
6298        assert!(
6299            s.signal_queue.is_empty(),
6300            "signal_queue parks at Default (Vec::new())",
6301        );
6302        assert!(
6303            s.conditions.is_empty(),
6304            "conditions parks at Default (Vec::new())"
6305        );
6306        assert!(s.message.is_none(), "message parks at Default (None)");
6307        assert!(s.exit_code.is_none(), "exit_code parks at Default (None)");
6308    }
6309
6310    #[test]
6311    fn at_phase_matches_hand_authored_pre_lift_bytewise() {
6312        // Byte-identical parity pin between the substrate composer and
6313        // the pre-lift 3-line `ProcessStatus { phase: <p>, ..Default::
6314        // default() }` struct-literal that recurred at both pool-
6315        // reconciler pin sites. Compares via `serde_json` value
6316        // equality — `ProcessStatus` does not derive `PartialEq` (the
6317        // typed fields it composes over do not uniformly derive it),
6318        // so a serialize round-trip is the shape-equality currency the
6319        // pin family already uses for status-shaped assertions in this
6320        // module (see the sibling `gate_compute_defaults_matches_hand_
6321        // authored_pre_lift_bytewise` pin on the spec side). A
6322        // regression that reshaped the primitive would diverge from
6323        // the pre-lift struct-literal HERE rather than at every
6324        // downstream fixture that keys on the shape.
6325        for phase in [
6326            ProcessPhase::Attested,
6327            ProcessPhase::Running,
6328            ProcessPhase::Pending,
6329        ] {
6330            let composed = ProcessStatus::at_phase(phase);
6331            let hand_authored = ProcessStatus {
6332                phase,
6333                ..Default::default()
6334            };
6335            assert_eq!(
6336                serde_json::to_value(&composed).unwrap(),
6337                serde_json::to_value(&hand_authored).unwrap(),
6338                "primitive must be byte-identical to the pre-lift struct-literal for phase {phase:?}",
6339            );
6340        }
6341    }
6342
6343    #[test]
6344    fn at_phase_is_call_time_construction_not_a_shared_singleton() {
6345        // Two independent calls produce structurally-equal but distinct
6346        // values — pins that the primitive is a plain constructor
6347        // rather than a `lazy_static` clone whose in-place mutation at
6348        // one consumer would silently mutate the shape at every other
6349        // consumer. Mirrors the sibling
6350        // `gate_compute_defaults_is_call_time_construction_not_a_shared_singleton`
6351        // pin on `ProcessSpec::gate_compute_defaults`.
6352        let a = ProcessStatus::at_phase(ProcessPhase::Attested);
6353        let b = ProcessStatus::at_phase(ProcessPhase::Attested);
6354        assert_eq!(
6355            serde_json::to_value(&a).unwrap(),
6356            serde_json::to_value(&b).unwrap(),
6357        );
6358        assert!(!std::ptr::eq(&a, &b));
6359    }
6360
6361    #[test]
6362    fn at_phase_default_variant_equals_process_status_default() {
6363        // Handing the composer the `ProcessPhase::default()` variant
6364        // yields a value byte-identical to `ProcessStatus::default()`
6365        // itself — pins that the composer's ONLY divergence from
6366        // `Default` is the caller-supplied `phase` slot, and that when
6367        // the caller passes the same variant `phase` already defaults
6368        // to, the composer collapses cleanly to the plain default.
6369        // A regression that stamped a non-default value on any sibling
6370        // slot (a runtime timestamp on `phase_since`, a synthetic
6371        // `identity` seed) would break this collapse and surface HERE.
6372        let default_phase = ProcessPhase::default();
6373        let via_at_phase = ProcessStatus::at_phase(default_phase);
6374        let via_default = ProcessStatus::default();
6375        assert_eq!(
6376            serde_json::to_value(&via_at_phase).unwrap(),
6377            serde_json::to_value(&via_default).unwrap(),
6378        );
6379    }
6380}