tatara_process/classification.rs
1//! The six classification dimensions — CRD-facing with `JsonSchema`,
2//! `From`/`Into` bridges to `tatara_core::domain::classification`.
3
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7use tatara_core::domain::classification as core;
8use tatara_core::domain::compliance_binding as core_compl;
9
10/// Lattice position of a Process — six orthogonal axes.
11#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
12#[serde(rename_all = "camelCase")]
13pub struct Classification {
14 pub point_type: ConvergencePointType,
15 pub substrate: SubstrateType,
16 #[serde(default)]
17 pub horizon: Horizon,
18 #[serde(default)]
19 pub calm: CalmClassification,
20 #[serde(default)]
21 pub data_classification: DataClassification,
22}
23
24impl Classification {
25 /// The workspace-baseline classification — a [`ConvergencePointType::Gate`]
26 /// point on the [`SubstrateType::Compute`] substrate with every other axis
27 /// at its [`Default`]. The `(Gate, Compute)` pair names an unremarkable
28 /// barrier point in the Compute plane: no domain-specific structural
29 /// claim (no fan-out / fan-in / broadcast / observation semantics beyond
30 /// the barrier gate) and no domain-specific substrate claim (no
31 /// `Financial` / `Network` / `Storage` / `Security` / `Identity` /
32 /// `Observability` / `Regulatory` plane bringing in its own compliance
33 /// baselines). The three defaulted axes ride at the intentional
34 /// workspace baseline the sibling closed-set primitives already own:
35 /// [`Horizon`] at [`HorizonKind::Bounded`] (terminates naturally, no
36 /// asymptotic metric axes required), [`CalmClassification::Monotone`]
37 /// (no coordination required per CALM), and
38 /// [`DataClassification::Internal`] (access-controlled but not
39 /// externally regulated).
40 ///
41 /// Pre-lift the six-line `Classification { point_type: Gate, substrate:
42 /// Compute, horizon: Default::default(), calm: Default::default(),
43 /// data_classification: Default::default() }` struct-literal recurred
44 /// at TEN sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold
45 /// — one production consumer plus nine test-fixture callsites spread
46 /// across four crates, each restating the SAME `(Gate, Compute)`
47 /// baseline verbatim:
48 /// * `crate::ephemeral::default_ephemeral_class` — the substitute
49 /// [`EphemeralSpec::into::<crate::crd::ProcessSpec>`] fills into
50 /// [`crate::crd::ProcessSpec::classification`] when the operator
51 /// omits an explicit `:classification` slot on `(defephemeral …)`.
52 /// The one PRODUCTION consumer of the shape — a regression that
53 /// drifted its point-type or substrate axis silently retargets every
54 /// unadorned ephemeral to a different plane.
55 /// * `crate::crd`'s + `crate::lib`'s + `crate::lifetime_clock`'s +
56 /// `tatara_reconciler::{claim,render}`'s + `tatara_pool_reconciler::
57 /// controller_pool`'s `empty_spec` / `empty_process_spec` /
58 /// `ephemeral_process` / `permanent_process` test-fixture helpers +
59 /// inline `ProcessSpec` literals — nine test-fixture callsites
60 /// restating the SAME six-line struct-literal at the same shape.
61 ///
62 /// Post-lift every callsite reads `Classification::gate_compute()`;
63 /// a future workspace-wide baseline shift (a new [`Horizon`] default,
64 /// a promotion of `Compute` to a compound baseline that pre-fills a
65 /// canonical [`CalmClassification`], a per-baseline compliance overlay
66 /// stamping through the classification, or a rename of either axis
67 /// enum) lands at ONE substrate function here and every downstream
68 /// consumer inherits the upgrade mechanically. The current pin ties
69 /// the three defaulted axes to the sibling closed-set defaults
70 /// ([`HorizonKind::Bounded`], [`CalmClassification::Monotone`],
71 /// [`DataClassification::Internal`]) so a future change to any sibling
72 /// default surfaces at this primitive's tests rather than as silent
73 /// drift across ten independent callsites.
74 ///
75 /// Sibling to the `_or_default` / `_or_placeholder` primitive family on
76 /// [`crate::prelude::Process`] on the (return-form × axis) axis — those
77 /// primitives own the borrow-form projections off a live `Process`;
78 /// this one owns the construction shape for a fresh
79 /// [`crate::crd::ProcessSpec`] whose classification axis is
80 /// unremarkable. A future peer `Classification::observe_observability()`
81 /// or similar named variant lands as a sibling method here when a
82 /// second unremarkable-baseline shape opens.
83 ///
84 /// Theory anchor: THEORY.md §VI.1 (generation over composition — the
85 /// six-line struct-literal shape recurred at TEN hand-authored sites
86 /// past the ★★ PRIME-DIRECTIVE ≥ 2 duplication trigger and is lifted
87 /// onto ONE workspace-wide owner here). THEORY.md §II.1 invariant 5
88 /// (composition preserves proofs — a regression that drifted the
89 /// baseline axis choice at only one consumer, or that broke the
90 /// sibling-default correspondence, surfaces at this primitive's tests
91 /// rather than as silent operator-visible skew between the ephemeral
92 /// sugar substitute and the ten downstream test-fixtures whose
93 /// assertions depend on the shape).
94 #[must_use]
95 pub fn gate_compute() -> Self {
96 Self {
97 point_type: ConvergencePointType::Gate,
98 substrate: SubstrateType::Compute,
99 horizon: Horizon::default(),
100 calm: CalmClassification::default(),
101 data_classification: DataClassification::default(),
102 }
103 }
104
105 /// Closed-set-driven presence probe — does this [`Classification`]
106 /// carry the given [`ConvergencePointType`] discriminator on its
107 /// [`Self::point_type`] slot? The ONE substrate primitive that owns
108 /// the `(Classification, ConvergencePointType) -> bool`
109 /// scalar-carrier walk shape.
110 ///
111 /// # Third scalar-carrier peer on the presence-probe axis
112 ///
113 /// Peer of [`crate::spec::SignalPolicy::has_sighup_strategy`] and
114 /// [`crate::encapsulates::EncapsulatesSpec::has_mode`] — all three
115 /// probe a scalar closed-set-discriminator field on an inner
116 /// [`crate::crd::ProcessSpec`] struct via a one-line
117 /// `self.<field> == kind` body. Together they compose the
118 /// SCALAR-CARRIER stratum of the workspace-wide closed-set-driven
119 /// presence-probe algebra (the workspace-wide algebra spans three
120 /// underlying representation kinds — Option-slot, slice, scalar —
121 /// see the [`crate::spec::SignalPolicy::has_sighup_strategy`]
122 /// docstring for the full-shape rundown; this method is the third
123 /// scalar-carrier instance).
124 ///
125 /// # Semantics — VARIANT match, not POPULATED slot
126 ///
127 /// `has_point_type(kind)` returns `true` iff `self.point_type ==
128 /// kind`. Distinct from BOTH prior scalar-carrier peers on the
129 /// (parent-shape × child-shape) axis:
130 ///
131 /// * [`crate::spec::SignalPolicy::has_sighup_strategy`] lives on a
132 /// non-Option, DEFAULTED parent (`SignalPolicy: Default`) with a
133 /// defaulted scalar child (`SighupStrategy: Default =
134 /// Reconverge`) — a default carrier reads `true` for the default
135 /// variant only.
136 /// * [`crate::encapsulates::EncapsulatesSpec::has_mode`] lives on
137 /// an OPTION parent (`spec.encapsulates:
138 /// Option<EncapsulatesSpec>`) with a defaulted scalar child
139 /// (`EncapsulationMode: Default = Manage`) — a bare `None`
140 /// parent reads `false` for every variant.
141 /// * `has_point_type` lives on a REQUIRED, non-Option, NON-DEFAULT
142 /// parent ([`Classification`] has no `impl Default`) with a
143 /// NON-DEFAULT scalar child ([`ConvergencePointType`] has no
144 /// `impl Default`) — every well-formed [`crate::crd::ProcessSpec`]
145 /// carries a `Classification` whose `point_type` slot is
146 /// deliberately chosen by the operator, so the probe returns
147 /// `true` on exactly ONE variant per spec and `false` on the
148 /// other seven, with no default-arm short-circuit shortcut.
149 ///
150 /// This closes the (required-parent × required-scalar-child) corner
151 /// of the workspace-wide closed-set-driven presence-probe algebra
152 /// at its first substrate primitive.
153 ///
154 /// # Compounding
155 ///
156 /// A future closed-set-discriminator scalar field on
157 /// [`Classification`] (a peer `has_substrate`, `has_calm`,
158 /// `has_data_classification` — the four remaining
159 /// classification-axis closed sets) lands as ONE peer inherent
160 /// method with the same one-line `self.<field> == kind` body and
161 /// routes through the same `strip_and_classify_prefixed_kind::<K,
162 /// _>` shape in `tatara-check`. A future
163 /// [`ConvergencePointType`] variant (a hypothetical `Demux` /
164 /// `Mux` / `Pipeline` for finer topology carving) reaches every
165 /// downstream through ONE `ALL` entry on the closed set with the
166 /// probe body untouched.
167 ///
168 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition preserves
169 /// proofs; the scalar-carrier presence-probe body lives at ONE
170 /// substrate site so every downstream (`point-type-<kind>`
171 /// require-tag family in `tatara-check`, closed-set audit
172 /// dispatchers, future variant additions on
173 /// [`ConvergencePointType`]) binds through the SAME shape rather
174 /// than restating the `classification.point_type == kind` closure
175 /// body at each callsite. THEORY.md §VI.1 — generation over
176 /// composition; a future [`ConvergencePointType`] variant lands at
177 /// ONE `ALL` entry + ONE `as_str` arm on the closed set and the
178 /// probe picks it up mechanically without further per-consumer
179 /// edits.
180 #[must_use]
181 pub fn has_point_type(&self, kind: ConvergencePointType) -> bool {
182 self.point_type == kind
183 }
184
185 /// Closed-set-driven presence probe — does this [`Classification`]
186 /// carry the given [`SubstrateType`] discriminator on its
187 /// [`Self::substrate`] slot? The ONE substrate primitive that
188 /// owns the `(Classification, SubstrateType) -> bool`
189 /// scalar-carrier walk shape.
190 ///
191 /// # Fourth scalar-carrier peer on the presence-probe axis
192 ///
193 /// Peer of [`crate::spec::SignalPolicy::has_sighup_strategy`],
194 /// [`crate::encapsulates::EncapsulatesSpec::has_mode`], and
195 /// [`Self::has_point_type`] — all four probe a scalar closed-set-
196 /// discriminator field on an inner [`crate::crd::ProcessSpec`]
197 /// struct via a one-line `self.<field> == kind` body. Together
198 /// they compose the SCALAR-CARRIER stratum of the workspace-wide
199 /// closed-set-driven presence-probe algebra (the workspace-wide
200 /// algebra spans three underlying representation kinds — Option-
201 /// slot, slice, scalar — see the
202 /// [`crate::spec::SignalPolicy::has_sighup_strategy`] docstring
203 /// for the full-shape rundown; this method is the fourth scalar-
204 /// carrier instance).
205 ///
206 /// # Semantics — VARIANT match, not POPULATED slot
207 ///
208 /// `has_substrate(kind)` returns `true` iff `self.substrate ==
209 /// kind`. FIRST co-tenant on the (required-parent × required-
210 /// scalar-child) corner of the algebra with [`Self::has_point_type`]
211 /// — both probe REQUIRED, non-Option, NON-DEFAULT slots on the
212 /// same [`Classification`] parent whose two required axes carry
213 /// no [`Default`] impl, so exactly ONE of the eight [`SubstrateType`]
214 /// variants and exactly ONE of the eight [`ConvergencePointType`]
215 /// variants answer `true` per well-formed [`crate::crd::ProcessSpec`],
216 /// with no default-arm short-circuit shortcut. Distinct from the
217 /// two prior scalar-carrier peers on the (parent-shape × child-
218 /// shape) axis: `has_sighup_strategy` lives on a non-Option,
219 /// DEFAULTED parent ([`crate::spec::SignalPolicy`] carries
220 /// `#[derive(Default)]`) with a defaulted scalar child
221 /// ([`crate::signal::SighupStrategy`] defaults to
222 /// [`crate::signal::SighupStrategy::Reconverge`]); `has_mode`
223 /// lives on an OPTION parent (`spec.encapsulates:
224 /// Option<EncapsulatesSpec>`) with a defaulted scalar child
225 /// ([`crate::encapsulates::EncapsulationMode`] defaults to
226 /// [`crate::encapsulates::EncapsulationMode::Manage`]).
227 ///
228 /// This POPULATES the (required-parent × required-scalar-child)
229 /// corner of the workspace-wide closed-set-driven presence-probe
230 /// algebra at its SECOND substrate primitive after
231 /// [`Self::has_point_type`] opened the corner, pinning the corner
232 /// as a proven-repeatable primitive shape rather than a single-
233 /// example curiosity.
234 ///
235 /// # Compounding
236 ///
237 /// A future closed-set-discriminator scalar field on
238 /// [`Classification`] (a peer `has_calm` on [`CalmClassification`],
239 /// `has_data_classification` on [`DataClassification`] — the two
240 /// remaining defaulted-scalar-child classification-axis closed
241 /// sets) lands as ONE peer inherent method with the same one-line
242 /// `self.<field> == kind` body and routes through the same
243 /// `strip_and_classify_prefixed_kind::<K, _>` shape in
244 /// `tatara-check`. A future [`SubstrateType`] variant (a
245 /// hypothetical `Consensus` for governance substrates, `Physical`
246 /// for hardware substrates, `Cache` for ephemeral memoization
247 /// substrates) reaches every downstream through ONE `ALL` entry
248 /// on the closed set with the probe body untouched.
249 ///
250 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition preserves
251 /// proofs; the scalar-carrier presence-probe body lives at ONE
252 /// substrate site so every downstream (`substrate-<kind>`
253 /// require-tag family in `tatara-check`, closed-set audit
254 /// dispatchers, future variant additions on [`SubstrateType`])
255 /// binds through the SAME shape rather than restating the
256 /// `classification.substrate == kind` closure body at each
257 /// callsite. THEORY.md §VI.1 — generation over composition; a
258 /// future [`SubstrateType`] variant lands at ONE `ALL` entry +
259 /// ONE `as_str` arm on the closed set and the probe picks it up
260 /// mechanically without further per-consumer edits.
261 #[must_use]
262 pub fn has_substrate(&self, kind: SubstrateType) -> bool {
263 self.substrate == kind
264 }
265
266 /// Closed-set-driven presence probe — does this [`Classification`]
267 /// carry the given [`CalmClassification`] discriminator on its
268 /// [`Self::calm`] slot? The ONE substrate primitive that owns the
269 /// `(Classification, CalmClassification) -> bool` scalar-carrier
270 /// walk shape.
271 ///
272 /// # Fifth scalar-carrier peer on the presence-probe axis
273 ///
274 /// Peer of [`crate::spec::SignalPolicy::has_sighup_strategy`],
275 /// [`crate::encapsulates::EncapsulatesSpec::has_mode`],
276 /// [`Self::has_point_type`], and [`Self::has_substrate`] — all
277 /// five probe a scalar closed-set-discriminator field on an inner
278 /// [`crate::crd::ProcessSpec`] struct via a one-line
279 /// `self.<field> == kind` body. Together they compose the
280 /// SCALAR-CARRIER stratum of the workspace-wide closed-set-driven
281 /// presence-probe algebra (the workspace-wide algebra spans three
282 /// underlying representation kinds — Option-slot, slice, scalar
283 /// — see the [`crate::spec::SignalPolicy::has_sighup_strategy`]
284 /// docstring for the full-shape rundown; this method is the
285 /// fifth scalar-carrier instance).
286 ///
287 /// # Semantics — VARIANT match, not POPULATED slot
288 ///
289 /// `has_calm(kind)` returns `true` iff `self.calm == kind`. FIRST
290 /// occupant on a FRESH corner of the (parent-shape × child-shape)
291 /// axis: a REQUIRED, non-Option, NON-DEFAULT parent
292 /// ([`Classification`] has no `impl Default` because its two
293 /// required axes `point_type`/`substrate` carry no default)
294 /// combined with a DEFAULTED scalar child
295 /// ([`CalmClassification`] defaults to
296 /// [`CalmClassification::Monotone`] via `#[default]`). Distinct
297 /// from every prior scalar-carrier peer on the (parent-shape ×
298 /// child-shape) axis:
299 ///
300 /// * [`crate::spec::SignalPolicy::has_sighup_strategy`] lives on
301 /// a non-Option, DEFAULTED parent
302 /// ([`crate::spec::SignalPolicy`] carries `#[derive(Default)]`)
303 /// with a defaulted scalar child
304 /// ([`crate::signal::SighupStrategy`] defaults to
305 /// [`crate::signal::SighupStrategy::Reconverge`]) — a bare
306 /// `SignalPolicy` reads `true` on the default variant only.
307 /// * [`crate::encapsulates::EncapsulatesSpec::has_mode`] lives on
308 /// an OPTION parent (`spec.encapsulates:
309 /// Option<EncapsulatesSpec>`) with a defaulted scalar child
310 /// ([`crate::encapsulates::EncapsulationMode`] defaults to
311 /// [`crate::encapsulates::EncapsulationMode::Manage`]) — a
312 /// bare `None` parent reads `false` for every variant.
313 /// * [`Self::has_point_type`] + [`Self::has_substrate`] both live
314 /// on the REQUIRED, non-Option, NON-DEFAULT [`Classification`]
315 /// parent with a NON-DEFAULT scalar child — every well-formed
316 /// [`crate::crd::ProcessSpec`] carries a `Classification` whose
317 /// corresponding slot was deliberately chosen by the operator,
318 /// so exactly ONE of the eight variants answers `true` per
319 /// spec.
320 /// * `has_calm` lives on the REQUIRED, non-Option, NON-DEFAULT
321 /// [`Classification`] parent with a DEFAULTED scalar child
322 /// ([`CalmClassification::Monotone`] is the [`Default`] via
323 /// `#[default]`) — a bare `Classification` filled via
324 /// `..Default::default()` on the defaulted axes reads `true`
325 /// for the default variant ([`CalmClassification::Monotone`])
326 /// and `false` for every other. Exactly ONE of the two variants
327 /// answers `true` per spec, and the default-arm short-circuit
328 /// is present (the operator can DECLINE to name the CALM axis
329 /// and the spec still answers `true` on the default variant).
330 ///
331 /// This OPENS the (required-parent × defaulted-scalar-child)
332 /// corner of the workspace-wide closed-set-driven presence-probe
333 /// algebra at its first substrate primitive — a corner distinct
334 /// from all four prior scalar-carrier peers (which sit on the
335 /// three prior corners: defaulted-parent × defaulted-child,
336 /// Option-parent × defaulted-child, required-parent ×
337 /// required-child).
338 ///
339 /// # Compounding
340 ///
341 /// A future closed-set-discriminator scalar field on
342 /// [`Classification`] whose child carries `#[derive(Default)]`
343 /// (a peer `has_data_classification` on [`DataClassification`],
344 /// whose default is [`DataClassification::Internal`] via
345 /// `#[default]` — the remaining classification-axis closed set
346 /// on a defaulted-scalar-child slot) lands as ONE peer inherent
347 /// method with the same one-line `self.<field> == kind` body and
348 /// routes through the same `strip_and_classify_prefixed_kind::<K,
349 /// _>` shape in `tatara-check`. A future [`CalmClassification`]
350 /// variant (a hypothetical `ConditionallyMonotone` for ops that
351 /// are monotone under a witness, like CRDT joins under a fixed
352 /// schema) reaches every downstream through ONE `ALL` entry on
353 /// the closed set with the probe body untouched.
354 ///
355 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
356 /// preserves proofs; the scalar-carrier presence-probe body
357 /// lives at ONE substrate site so every downstream
358 /// (`calm-<kind>` require-tag family in `tatara-check`,
359 /// closed-set audit dispatchers, future variant additions on
360 /// [`CalmClassification`]) binds through the SAME shape rather
361 /// than restating the `classification.calm == kind` closure body
362 /// at each callsite. THEORY.md §VI.1 — generation over
363 /// composition; a future [`CalmClassification`] variant lands at
364 /// ONE `ALL` entry + ONE `as_str` arm on the closed set and the
365 /// probe picks it up mechanically without further per-consumer
366 /// edits.
367 #[must_use]
368 pub fn has_calm(&self, kind: CalmClassification) -> bool {
369 self.calm == kind
370 }
371
372 /// Closed-set-driven presence probe — does this [`Classification`]
373 /// carry the given [`DataClassification`] discriminator on its
374 /// [`Self::data_classification`] slot? The ONE substrate primitive
375 /// that owns the `(Classification, DataClassification) -> bool`
376 /// scalar-carrier walk shape.
377 ///
378 /// # Sixth scalar-carrier peer on the presence-probe axis
379 ///
380 /// Peer of [`crate::spec::SignalPolicy::has_sighup_strategy`],
381 /// [`crate::encapsulates::EncapsulatesSpec::has_mode`],
382 /// [`Self::has_point_type`], [`Self::has_substrate`], and
383 /// [`Self::has_calm`] — all six probe a scalar closed-set-
384 /// discriminator field on an inner [`crate::crd::ProcessSpec`]
385 /// struct via a one-line `self.<field> == kind` body. Together
386 /// they compose the SCALAR-CARRIER stratum of the workspace-wide
387 /// closed-set-driven presence-probe algebra (the workspace-wide
388 /// algebra spans three underlying representation kinds — Option-
389 /// slot, slice, scalar — see the
390 /// [`crate::spec::SignalPolicy::has_sighup_strategy`] docstring
391 /// for the full-shape rundown; this method is the sixth scalar-
392 /// carrier instance).
393 ///
394 /// # Semantics — VARIANT match, not POPULATED slot
395 ///
396 /// `has_data_classification(kind)` returns `true` iff
397 /// `self.data_classification == kind`. SECOND co-tenant on the
398 /// (required-parent × defaulted-scalar-child) corner of the
399 /// algebra alongside [`Self::has_calm`] — both probe REQUIRED,
400 /// non-Option, NON-DEFAULT [`Classification`] parent slots with
401 /// a DEFAULTED scalar child ([`DataClassification`] defaults to
402 /// [`DataClassification::Internal`] via `#[default]`, sibling to
403 /// [`CalmClassification::Monotone`]'s `#[default]`), so exactly
404 /// ONE of the six [`DataClassification`] variants answers `true`
405 /// per spec AND the default-arm short-circuit is present (a
406 /// `Classification` filled via `..Default::default()` on the
407 /// `data_classification` axis reads `true` on the default
408 /// variant [`DataClassification::Internal`] and `false` on every
409 /// other).
410 ///
411 /// This POPULATES the (required-parent × defaulted-scalar-child)
412 /// corner of the workspace-wide closed-set-driven presence-probe
413 /// algebra at its SECOND substrate primitive after
414 /// [`Self::has_calm`] opened the corner, pinning the corner as a
415 /// proven-repeatable primitive shape rather than a single-example
416 /// curiosity. The corner-property contract ("bare
417 /// [`Classification`] reads `true` on the default variant")
418 /// now walks TWO independent defaulted-scalar-child slots on the
419 /// SAME [`Classification`] parent — a regression that promoted
420 /// a different [`DataClassification`] variant to `#[default]`
421 /// (or wired the arm to a fixed variant answer) fails HERE at
422 /// ONE narrow substrate site before drifting through every
423 /// unadorned Process's baseline data-classification answer.
424 ///
425 /// # Compounding
426 ///
427 /// This method exhausts the four scalar closed-set-discriminator
428 /// axes on [`Classification`] ([`Self::has_point_type`],
429 /// [`Self::has_substrate`], [`Self::has_calm`], and
430 /// [`Self::has_data_classification`]) — the six-axis classification
431 /// lattice publishes ALL FOUR of its scalar-carrier presence
432 /// probes at ONE substrate site each. The remaining two axes
433 /// (`horizon` — a nested struct threading [`HorizonKind`] through
434 /// `horizon.kind`; the sixth axis is variant-dependent on the
435 /// [`HorizonKind::Asymptotic`] arm) live on nested-struct-scalar
436 /// slots rather than the direct-scalar corner the four current
437 /// peers span — the [`Self::has_horizon_kind`] peer opens that
438 /// fresh (required-parent × nested-struct-scalar-child) corner
439 /// with the same `has(kind)` shape composed through one struct
440 /// hop. A future [`DataClassification`] variant (a
441 /// hypothetical seventh variant beyond `Public / Internal /
442 /// Confidential / Pii / Phi / Pci` — say a `TradeSecret` bucket
443 /// for competitive-sensitive data, or an `Anonymized` bucket for
444 /// pseudonymized-PII whose regulatory posture differs) reaches
445 /// every downstream through ONE `ALL` entry on the closed set +
446 /// ONE `as_str` arm + ONE `sensitivity_rank` arm + one arm per
447 /// predicate with the probe body untouched.
448 ///
449 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
450 /// preserves proofs; the scalar-carrier presence-probe body
451 /// lives at ONE substrate site so every downstream
452 /// (`data-classification-<kind>` require-tag family in
453 /// `tatara-check`, closed-set audit dispatchers, future variant
454 /// additions on [`DataClassification`]) binds through the SAME
455 /// shape rather than restating the
456 /// `classification.data_classification == kind` closure body at
457 /// each callsite. THEORY.md §VI.1 — generation over composition;
458 /// a future [`DataClassification`] variant lands at ONE `ALL`
459 /// entry + ONE `as_str` arm on the closed set and the probe
460 /// picks it up mechanically without further per-consumer edits.
461 #[must_use]
462 pub fn has_data_classification(&self, kind: DataClassification) -> bool {
463 self.data_classification == kind
464 }
465
466 /// Closed-set-driven presence probe — does this [`Classification`]
467 /// carry the given [`HorizonKind`] discriminator on its
468 /// [`Self::horizon`]`.kind` slot? The ONE substrate primitive that
469 /// owns the `(Classification, HorizonKind) -> bool` nested-struct-
470 /// scalar-carrier walk shape.
471 ///
472 /// # Seventh peer on the presence-probe axis — first on a fresh corner
473 ///
474 /// Peer of [`crate::spec::SignalPolicy::has_sighup_strategy`],
475 /// [`crate::encapsulates::EncapsulatesSpec::has_mode`],
476 /// [`Self::has_point_type`], [`Self::has_substrate`],
477 /// [`Self::has_calm`], and [`Self::has_data_classification`] on the
478 /// workspace-wide closed-set-driven presence-probe algebra — the
479 /// four scalar-carrier peers on [`Classification`] all read a
480 /// closed-set discriminator DIRECTLY off a scalar `Classification`
481 /// slot (`point_type`, `substrate`, `calm`, `data_classification`).
482 /// `has_horizon_kind` instead threads through a NESTED-STRUCT
483 /// intermediary ([`Horizon`], the defaulted nested struct owning
484 /// the `horizon` axis on the six-axis classification lattice) to
485 /// reach a scalar [`HorizonKind`] discriminator on
486 /// `horizon.kind`. This OPENS the (required-parent × nested-
487 /// struct-scalar-child) corner of the algebra at its FIRST
488 /// substrate primitive — a fresh corner distinct from all four
489 /// corner-property-exhaustive scalar-carrier peers on
490 /// [`Classification`].
491 ///
492 /// # Semantics — VARIANT match on the nested scalar, not POPULATED nested struct
493 ///
494 /// `has_horizon_kind(kind)` returns `true` iff
495 /// `self.horizon.kind == kind`. The nested [`Horizon`] struct
496 /// carries [`Default`] via `#[derive(Default)]` and its `kind`
497 /// field defaults to [`HorizonKind::Bounded`] via `#[default]`, so
498 /// a [`Classification`] filled via `..Default::default()` on the
499 /// `horizon` axis reads `true` on the default kind
500 /// [`HorizonKind::Bounded`] and `false` on
501 /// [`HorizonKind::Asymptotic`]. The default-arm short-circuit is
502 /// therefore present at this corner too — but through the extra
503 /// struct hop the peer scalar-carrier peers on the defaulted-
504 /// child corner (`has_calm`, `has_data_classification`) walk
505 /// directly. A regression that dropped `#[default]` on
506 /// [`HorizonKind`], or that replaced `Horizon::default()` in
507 /// [`Classification::gate_compute`] with an explicit non-`Bounded`
508 /// kind, surfaces at this primitive's tests before drifting
509 /// through every unadorned Process's baseline horizon answer.
510 ///
511 /// # Compounding
512 ///
513 /// This method OPENS the (required-parent × nested-struct-scalar-
514 /// child) corner of the workspace-wide closed-set-driven
515 /// presence-probe algebra, distinct from the four corner-property-
516 /// exhaustive scalar-carrier peers on [`Classification`]
517 /// ([`Self::has_point_type`], [`Self::has_substrate`],
518 /// [`Self::has_calm`], [`Self::has_data_classification`]) whose
519 /// bodies read a closed-set discriminator directly off a scalar
520 /// slot. A future co-tenant on this fresh corner (a peer probe on
521 /// another nested-struct's scalar discriminator, e.g. a
522 /// hypothetical `has_optimization_direction` reaching
523 /// `spec.classification.horizon.direction.unwrap_or_default()`, or
524 /// a nested-struct-scalar discriminator on a different `ProcessSpec`
525 /// field's inner struct) lands as ONE peer inherent method with
526 /// the same two-hop `self.<outer>.<inner> == kind` body and routes
527 /// through the same `strip_and_classify_prefixed_kind::<K, _>`
528 /// shape in `tatara-check`. A future [`HorizonKind`] variant (a
529 /// hypothetical `Periodic` sentinel for "terminates on each
530 /// window boundary then re-arms", pre-flagged on the closed set's
531 /// `ALL` docstring) reaches every downstream through ONE `ALL`
532 /// entry + one `as_str` arm + one `terminates` arm + one
533 /// `requires_metric_axes` arm on the closed set with the probe
534 /// body untouched.
535 ///
536 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
537 /// preserves proofs; the nested-struct-scalar-carrier presence-
538 /// probe body lives at ONE substrate site so every downstream
539 /// (`horizon-<kind>` require-tag family in `tatara-check`, future
540 /// audit dispatchers walking [`HorizonKind::ALL`], future variant
541 /// additions on [`HorizonKind`]) binds through the SAME
542 /// `has(kind)` shape rather than restating the
543 /// `classification.horizon.kind == kind` closure body at each
544 /// callsite. THEORY.md §VI.1 — generation over composition; a
545 /// future [`HorizonKind`] variant lands at ONE `ALL` entry + ONE
546 /// `as_str` arm on the closed set and the probe picks it up
547 /// mechanically without further per-consumer edits.
548 #[must_use]
549 pub fn has_horizon_kind(&self, kind: HorizonKind) -> bool {
550 self.horizon.kind == kind
551 }
552
553 /// Closed-set-driven presence probe — does this [`Classification`]
554 /// carry the given [`OptimizationDirection`] discriminator on its
555 /// [`Self::horizon`]`.direction` slot (with the substrate
556 /// `Option::unwrap_or_default` treating `None` as the closed set's
557 /// `#[default] Minimize`)? The ONE substrate primitive that owns
558 /// the `(Classification, OptimizationDirection) -> bool` nested-
559 /// struct-Option-scalar-carrier walk shape.
560 ///
561 /// # Second occupant on the nested-struct-scalar-child corner —
562 /// the Option-hop co-tenant
563 ///
564 /// Peer of [`Self::has_horizon_kind`] on the (required-parent ×
565 /// nested-struct-scalar-child) corner opened by that method — same
566 /// two-hop composition through the nested defaulted [`Horizon`]
567 /// intermediary, but the inner scalar slot is `direction:
568 /// Option<OptimizationDirection>` (an `Option`-hop past the same
569 /// nested [`Horizon`]) rather than a bare scalar. The corner
570 /// therefore admits BOTH direct nested-scalar shapes ([`Horizon`]
571 /// carries `kind: HorizonKind` directly, [`Self::has_horizon_kind`]
572 /// walks it) AND Option-nested-scalar shapes ([`Horizon`] carries
573 /// `direction: Option<OptimizationDirection>`, this method walks
574 /// it through `Option::unwrap_or_default`), pinning the corner as
575 /// a proven-repeatable primitive shape rather than a single-
576 /// example curiosity. Every prior scalar-carrier peer on
577 /// [`Classification`] (`has_point_type`, `has_substrate`,
578 /// `has_calm`, `has_data_classification`) reads a closed-set
579 /// discriminator DIRECTLY off a scalar `Classification` slot; this
580 /// method (like [`Self::has_horizon_kind`]) threads through the
581 /// nested [`Horizon`] intermediary, and additionally traverses the
582 /// `Option`-slot with `unwrap_or_default` so the operator's
583 /// `:requires (optimization-direction-Minimize)` on an unadorned
584 /// baseline still answers `true` on the closed set's default arm.
585 ///
586 /// # Semantics — VARIANT match on the Option-defaulted nested
587 /// scalar, not POPULATED Option
588 ///
589 /// `has_optimization_direction(kind)` returns `true` iff
590 /// `self.horizon.direction.unwrap_or_default() == kind`.
591 /// [`OptimizationDirection`] carries `#[default] Minimize` via
592 /// the derived [`Default`] impl, so a Process filled through
593 /// [`Horizon::bounded`] (which leaves `direction: None`) or
594 /// through `Horizon::default()` (same shape, `direction: None`)
595 /// answers `true` on [`OptimizationDirection::Minimize`] and
596 /// `false` on [`OptimizationDirection::Maximize`]. This mirrors
597 /// the default-arm short-circuit contract every other closed-set-
598 /// defaulted-child probe on [`Classification`] publishes
599 /// (`has_calm`, `has_data_classification`, `has_horizon_kind`) —
600 /// the `Option`-hop is soft-mapped to the closed set's default
601 /// arm rather than surfaced as a distinct presence axis. A
602 /// regression that flipped [`OptimizationDirection`]'s
603 /// `#[default]` off `Minimize` (which would silently invert every
604 /// unadorned `Asymptotic` Process's rate-window evaluator
605 /// polarity — see the [`OptimizationDirection::Minimize`] variant
606 /// docstring) fails at this probe's default-arm tests before
607 /// drifting through every downstream consumer.
608 ///
609 /// # Semantics rationale — Option-hop as default vs presence
610 ///
611 /// The `direction: Option<OptimizationDirection>` slot on
612 /// [`Horizon`] is documented as "Asymptotic only" — a `Bounded`
613 /// horizon has no meaningful direction so the operator leaves
614 /// it `None`. Yet the closed set carries `#[default] Minimize`,
615 /// so a bare `Bounded` Process's optimization direction reads
616 /// as `Minimize` at every consumer downstream via
617 /// [`Option::unwrap_or_default`]. That default IS the substrate's
618 /// operator-facing answer for "what direction would this Process
619 /// optimize toward if it became Asymptotic without further
620 /// annotation?", and a `:requires (optimization-direction-
621 /// Minimize)` audit at the checks.lisp surface correctly matches
622 /// every unadorned Process — matching the corner-property contract
623 /// every other defaulted-child probe publishes. An operator who
624 /// wants a strict presence axis (`is direction *actually* set?`)
625 /// gets that answer through a distinct future primitive
626 /// (`has_optimization_direction_set`) that would read the
627 /// `is_some` bit alone — orthogonal to this variant-equality
628 /// probe. This method commits to the variant-equality
629 /// interpretation so the corner-property contract stays uniform
630 /// with the four scalar-carrier peers.
631 ///
632 /// # Compounding
633 ///
634 /// This method POPULATES the (required-parent × nested-struct-
635 /// scalar-child) corner at its SECOND substrate primitive after
636 /// [`Self::has_horizon_kind`] opened it — pinning the corner as
637 /// a proven-repeatable primitive shape rather than a single-
638 /// example curiosity, and DEMONSTRATING that the corner admits
639 /// both direct-scalar and Option-scalar traversals through the
640 /// same nested-struct intermediary via the closed set's default.
641 /// A future co-tenant on this corner (a peer probe on another
642 /// nested-struct's scalar or Option-scalar discriminator, e.g.
643 /// a hypothetical `has_backend_port_family` reaching
644 /// `spec.routing.as_ref().and_then(|r| r.backend.tls_issuer.as_ref()).is_some()`
645 /// or a nested-struct-scalar discriminator on
646 /// `spec.encapsulates.<some-inner>.kind`) lands as ONE peer
647 /// inherent method with the same two-hop `self.<outer>.<inner>`
648 /// walk (with or without an Option-hop threading through the
649 /// closed set's `Default`) and routes through the same
650 /// `strip_and_classify_prefixed_kind::<K, _>` shape in
651 /// `tatara-check`. A future [`OptimizationDirection`] variant
652 /// (a hypothetical `Stabilize` sentinel for "drive toward a
653 /// target value", pre-flagged on the closed set's `ALL`
654 /// docstring) reaches every downstream through ONE `ALL` entry
655 /// + one `as_str` arm + one `prefers_lower` arm + one
656 /// `is_improvement` arm on the closed set with the probe body
657 /// untouched.
658 ///
659 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
660 /// preserves proofs; the nested-struct-Option-scalar-carrier
661 /// presence-probe body lives at ONE substrate site so every
662 /// downstream (`optimization-direction-<kind>` require-tag family
663 /// in `tatara-check`, future audit dispatchers walking
664 /// [`OptimizationDirection::ALL`], future variant additions on
665 /// [`OptimizationDirection`]) binds through the SAME
666 /// `has(kind)` shape rather than restating the
667 /// `classification.horizon.direction.unwrap_or_default() == kind`
668 /// closure body at each callsite. THEORY.md §VI.1 — generation
669 /// over composition; a future [`OptimizationDirection`] variant
670 /// lands at ONE `ALL` entry + ONE `as_str` arm on the closed set
671 /// and the probe picks it up mechanically without further
672 /// per-consumer edits.
673 #[must_use]
674 pub fn has_optimization_direction(&self, kind: OptimizationDirection) -> bool {
675 self.horizon.direction.unwrap_or_default() == kind
676 }
677
678 /// Closed-set-driven presence probe — does this [`Classification`]
679 /// carry a [`ConvergencePointType`] whose typed input-edge
680 /// cardinality projection ([`ConvergencePointType::input_arity`])
681 /// matches the given [`Arity`] discriminator? The ONE substrate
682 /// primitive that owns the `(Classification, Arity) -> bool`
683 /// derived-typed-projection walk shape.
684 ///
685 /// # Third occupant on the (required-parent × nested-struct-scalar-child) corner — first via a derived-typed-projection
686 ///
687 /// Peer of [`Self::has_horizon_kind`] and
688 /// [`Self::has_optimization_direction`] on the (required-parent ×
689 /// nested-struct-scalar-child) corner. Distinct from the two on
690 /// ONE dimension: those two read a raw discriminator directly off
691 /// the nested [`Horizon`] slot (`self.horizon.kind` /
692 /// `self.horizon.direction.unwrap_or_default()`) so the child's
693 /// closed set IS the field's type; this probe threads through the
694 /// closed-set typed projection [`ConvergencePointType::input_arity`]
695 /// (a `const fn` many-to-one collapse `Transform | Fork |
696 /// Broadcast | Observe → One`, `Join | Gate | Select | Reduce →
697 /// Many`) so the child's closed set is REACHED THROUGH a typed
698 /// projection layer, not read raw off a scalar. Byte-for-byte
699 /// symmetric with the derived-typed-projection precedent set by
700 /// [`crate::export::ExportSpecSliceExt::has_report_payload_shape`]
701 /// on the (Option-parent × Vec-child × nested-Option-carrier ×
702 /// derived-typed-projection) corner — that peer routes through
703 /// [`crate::export::ReportFormat::payload_shape`] the same way
704 /// this method routes through [`ConvergencePointType::input_arity`].
705 /// FIRST occupant of the derived-typed-projection variant on the
706 /// (required-parent × nested-struct-scalar-child) corner —
707 /// widening the corner from "raw discriminator only" to "raw
708 /// discriminator OR typed projection over the child" and pinning
709 /// the corner as a proven-repeatable primitive shape rather than a
710 /// direct-field-equality curiosity.
711 ///
712 /// # Semantics — VARIANT match on the projected image, not on the source
713 ///
714 /// `has_input_arity(kind)` returns `true` iff
715 /// `self.point_type.input_arity() == kind`. [`Arity`] carries no
716 /// `Default` impl (the `Arity::ALL` closed set is a bare 2-arm
717 /// enum with no `#[default]`), so exactly ONE of the two arms
718 /// answers `true` per well-formed [`crate::crd::ProcessSpec`],
719 /// with no default-arm short-circuit shortcut. The many-to-one
720 /// projection shape means the answer is invariant under intra-
721 /// bucket point-type swaps (`Transform ↔ Fork ↔ Broadcast ↔
722 /// Observe` all keep `input-arity-One = true`) and flips at
723 /// bucket boundaries (`Transform ↔ Join` flips `input-arity-One`
724 /// from `true` to `false`). A regression that (a) probed
725 /// [`ConvergencePointType`] directly (dropping the
726 /// `.input_arity()` call), (b) inverted the projection (`One ↔
727 /// Many`), or (c) crossed the wires with the sibling
728 /// [`ConvergencePointType::output_arity`] projection (which
729 /// disagrees on the fan-out arms `Fork | Broadcast → Many` vs.
730 /// `input_arity`'s `Fork | Broadcast → One`) fails at this probe's
731 /// substrate site before drifting through every downstream
732 /// consumer.
733 ///
734 /// # Compounding
735 ///
736 /// This method POPULATES the (required-parent × nested-struct-
737 /// scalar-child) corner at its THIRD substrate primitive after
738 /// [`Self::has_horizon_kind`] opened it (direct-nested-scalar) and
739 /// [`Self::has_optimization_direction`] populated it
740 /// (Option-nested-scalar). Together the three demonstrate the
741 /// corner admits three traversal shapes through the SAME
742 /// two-hop `self.<field>.<projection>` walk: direct-scalar,
743 /// Option-scalar-with-default, and derived-typed-projection. A
744 /// future co-tenant reading a projected value off the same
745 /// [`ConvergencePointType`] (a peer `has_output_arity` reading
746 /// `self.point_type.output_arity() == kind` — the natural fourth
747 /// occupant, opening the pair for DAG-composition axis coverage;
748 /// a hypothetical `has_topology_bucket` reading `.is_preserving()`
749 /// / `.is_diffusive()` / `.is_convergent()`) lands as ONE peer
750 /// inherent method with the same one-line
751 /// `self.point_type.<projection>() == kind` body and routes
752 /// through the same `strip_and_classify_prefixed_kind::<K, _>`
753 /// shape in `tatara-check`. A future [`ConvergencePointType`]
754 /// variant (a hypothetical `Demux` for `One → Many` or `Mux` for
755 /// `Many → One`) reaches every downstream through ONE `ALL`
756 /// entry + one `as_str` arm + one `input_arity` arm + one
757 /// `output_arity` arm on the closed set with THIS probe body
758 /// untouched — the many-to-one projection means the bucket
759 /// membership shift lands exactly at the projection's own site.
760 ///
761 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
762 /// preserves proofs; the derived-typed-projection presence-probe
763 /// body lives at ONE substrate site so every downstream
764 /// (`input-arity-<kind>` require-tag family in `tatara-check`,
765 /// future DAG-composition validators, future variant additions
766 /// on [`ConvergencePointType`]) binds through the SAME
767 /// `has(kind)` shape rather than restating the
768 /// `classification.point_type.input_arity() == kind` closure body
769 /// at each callsite. THEORY.md §VI.1 — generation over
770 /// composition; a future [`Arity`] variant (a hypothetical `Zero`
771 /// for sinks) lands at ONE `ALL` entry + ONE `as_str` arm on the
772 /// closed set + ONE arm on each `input_arity`/`output_arity`
773 /// projection and the probe picks it up mechanically without
774 /// further per-consumer edits.
775 #[must_use]
776 pub fn has_input_arity(&self, kind: Arity) -> bool {
777 self.point_type.input_arity() == kind
778 }
779
780 /// Closed-set-driven presence probe — does this [`Classification`]
781 /// carry a [`ConvergencePointType`] whose typed output-edge
782 /// cardinality projection ([`ConvergencePointType::output_arity`])
783 /// matches the given [`Arity`] discriminator? The ONE substrate
784 /// primitive that owns the `(Classification, Arity) -> bool`
785 /// output-side derived-typed-projection walk shape.
786 ///
787 /// # Fourth occupant on the (required-parent × nested-struct-scalar-child) corner — second via a derived-typed-projection; closes the DAG-composition arity pair
788 ///
789 /// Peer of [`Self::has_horizon_kind`],
790 /// [`Self::has_optimization_direction`], and
791 /// [`Self::has_input_arity`] on the (required-parent ×
792 /// nested-struct-scalar-child) corner. Byte-for-byte symmetric with
793 /// [`Self::has_input_arity`]: this method walks the SAME
794 /// `self.point_type` scalar carrier through the SAME `Arity`
795 /// closed set — the sole distinction is the typed projection
796 /// composed on the walk. `has_input_arity` composes
797 /// [`ConvergencePointType::input_arity`] (`Transform | Fork |
798 /// Broadcast | Observe → One`, `Join | Gate | Select | Reduce →
799 /// Many`); this method composes
800 /// [`ConvergencePointType::output_arity`] (`Fork | Broadcast →
801 /// Many`, everything else → `One`). Together the two probes close
802 /// the DAG-composition arity pair — the `(input_arity,
803 /// output_arity)` typed projection that pins each variant to
804 /// exactly one cell of the `Arity × Arity` topology table
805 /// (endomorphic `(One, One)`, diffusive `(One, Many)`, convergent
806 /// `(Many, One)`) so future DAG-composition validators dispatch on
807 /// a typed projection rather than re-deriving from variant names.
808 /// SECOND derived-typed-projection occupant on the
809 /// (required-parent × nested-struct-scalar-child) corner — pinning
810 /// the corner's "one carrier, N typed-projection probes" property
811 /// with a second projection over the same source closed set.
812 ///
813 /// # Semantics — VARIANT match on the OUTPUT-projected image
814 ///
815 /// `has_output_arity(kind)` returns `true` iff
816 /// `self.point_type.output_arity() == kind`. [`Arity`] carries no
817 /// `Default` impl, so exactly ONE of the two arms answers `true`
818 /// per well-formed [`crate::crd::ProcessSpec`], with no default-
819 /// arm short-circuit. The many-to-one projection shape means the
820 /// answer is invariant under intra-bucket swaps (`Fork ↔
821 /// Broadcast` both keep `output-arity-Many = true`; `Transform ↔
822 /// Join ↔ Gate ↔ Select ↔ Reduce ↔ Observe` all keep
823 /// `output-arity-One = true`) and flips at bucket boundaries
824 /// (`Fork ↔ Transform` flips `output-arity-Many` from `true` to
825 /// `false`). CROSS-PROJECTION DIAGONAL: `Fork | Broadcast` have
826 /// `(input_arity, output_arity) = (One, Many)` so `has_input_arity`
827 /// and `has_output_arity` DISAGREE on those two variants (the
828 /// diffusive bucket is the unique cell where the two projections
829 /// answer opposite `Arity` values); `Join | Gate | Select |
830 /// Reduce` have `(Many, One)` so the two probes disagree there too
831 /// (the convergent bucket is the mirror cell); `Transform |
832 /// Observe` have `(One, One)` so the two probes AGREE (the
833 /// endomorphic bucket). A regression that (a) probed
834 /// [`ConvergencePointType`] directly (dropping the
835 /// `.output_arity()` call), (b) inverted the projection (`One ↔
836 /// Many`), or (c) crossed the wires with
837 /// [`ConvergencePointType::input_arity`] (which disagrees on the
838 /// four arms in the diffusive + convergent cells) fails at this
839 /// probe's substrate site before drifting through every downstream
840 /// consumer.
841 ///
842 /// # Compounding
843 ///
844 /// This method POPULATES the DAG-composition arity pair for full
845 /// axis coverage — the natural fourth occupant the
846 /// [`Self::has_input_arity`] docstring names as the next
847 /// derived-typed-projection co-tenant on the same
848 /// `self.point_type` carrier. Operators authoring `(defpoint …
849 /// :requires (output-arity-Many))` in `checks.lisp` now get typed
850 /// access to the fan-out axis (edge-cardinality checks: "every
851 /// diffusive topology point emits fan-out" — the exact fleet-wide
852 /// property the (`Fork | Broadcast`, `Many`) projection composition
853 /// is designed to name) as the mirror of the input-side family,
854 /// and the two conjoined (`input-arity-One AND
855 /// output-arity-Many`) names the diffusive bucket exactly through
856 /// the two typed projections rather than through the OR of raw
857 /// `point-type-<Fork | Broadcast>` conjuncts. A future
858 /// [`ConvergencePointType`] variant (a hypothetical `Demux` for
859 /// `One → Many` or `Mux` for `Many → One`) reaches every downstream
860 /// through ONE `ALL` entry + one `as_str` arm + one `input_arity`
861 /// arm + one `output_arity` arm on the closed set with THIS probe
862 /// body untouched — the many-to-one projection means the bucket
863 /// membership shift lands exactly at each projection's own site,
864 /// not at every consumer that previously restated the bucket in
865 /// code.
866 ///
867 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
868 /// preserves proofs; the second derived-typed-projection presence-
869 /// probe body over the SAME `self.point_type` carrier lives at ONE
870 /// substrate site so every downstream (`output-arity-<kind>`
871 /// require-tag family in `tatara-check`, future DAG-composition
872 /// validators, future variant additions on
873 /// [`ConvergencePointType`]) binds through the SAME `has(kind)`
874 /// shape. THEORY.md §VI.1 — generation over composition; a future
875 /// [`Arity`] variant lands at ONE `ALL` entry + ONE `as_str` arm
876 /// on the closed set + ONE arm on each `input_arity`/`output_arity`
877 /// projection and both probes pick it up mechanically.
878 #[must_use]
879 pub fn has_output_arity(&self, kind: Arity) -> bool {
880 self.point_type.output_arity() == kind
881 }
882
883 /// Derived-boolean predicate — does this [`Classification`] carry a
884 /// [`Horizon`] whose kind projects to `true` under
885 /// [`HorizonKind::terminates`]? The ONE substrate primitive that
886 /// owns the `(Classification) -> bool` derived-nullary-predicate
887 /// walk shape on the `horizon.kind` slot.
888 ///
889 /// # First occupant on the (required-parent × nested-struct-derived-nullary-bool) corner
890 ///
891 /// Distinct from every prior presence-probe method on
892 /// [`Classification`] — those all admit a closed-set `kind`
893 /// argument that the probe compares against the stored /
894 /// projected discriminator ([`Self::has_horizon_kind`] walks
895 /// `horizon.kind == kind`, [`Self::has_optimization_direction`]
896 /// walks `horizon.direction.unwrap_or_default() == kind`,
897 /// [`Self::has_input_arity`] / [`Self::has_output_arity`] walk
898 /// `point_type.<projection>() == kind`). This probe has NO
899 /// argument at all: it collapses [`HorizonKind::ALL`] onto a
900 /// single boolean question ("does this horizon terminate?") via
901 /// the closed set's own [`HorizonKind::terminates`] predicate,
902 /// so callers asking the workspace-wide scheduler-facing
903 /// question "will this Process ever reach [`crate::phase::ProcessPhase::Reaped`]
904 /// via natural termination" reach the answer through a nullary
905 /// substrate call rather than restating
906 /// `classification.horizon.kind.terminates()` at every consumer.
907 ///
908 /// # Semantics — derived nullary boolean, not variant equality
909 ///
910 /// `horizon_terminates()` returns `true` iff
911 /// `self.horizon.kind.terminates()`. The two-variant
912 /// [`HorizonKind`] closed set publishes the truth table:
913 /// [`HorizonKind::Bounded`] → `true` (has a fixed point,
914 /// distance reaches 0, terminates naturally);
915 /// [`HorizonKind::Asymptotic`] → `false` (runs in perpetuity,
916 /// rate is the health signal, never terminates on its own). A
917 /// [`Classification::gate_compute`] baseline (which uses
918 /// [`Horizon::default`] with `kind = HorizonKind::Bounded` via
919 /// `#[default]`) answers `true` — the substrate's default-arm
920 /// short-circuit propagates through the nested [`Horizon`]
921 /// struct's own [`Default`] impl to this predicate's answer
922 /// the same way it propagates through
923 /// [`Self::has_horizon_kind`]'s `HorizonKind::Bounded` arm.
924 ///
925 /// A future third [`HorizonKind`] variant (a hypothetical
926 /// `Periodic` sentinel for "terminates on each window boundary
927 /// then re-arms" — pre-flagged on the closed set's `ALL`
928 /// docstring) reaches this probe through ONE `terminates` arm
929 /// on the closed set with the probe body untouched — the
930 /// nullary-predicate shape defers every per-variant policy
931 /// decision to the closed set's own truth table
932 /// ([`HorizonKind::terminates`]) rather than duplicating the
933 /// discriminator sweep here.
934 ///
935 /// # Compounding
936 ///
937 /// This method OPENS the (required-parent ×
938 /// nested-struct-derived-nullary-bool) corner of the workspace-
939 /// wide closed-set-driven presence-probe algebra at its FIRST
940 /// substrate primitive — distinct from every prior corner
941 /// occupant on [`Classification`] (which all take a closed-set
942 /// `kind` argument). A future co-tenant on this fresh corner (a
943 /// peer nullary predicate on another nested-struct's derived
944 /// boolean projection — a hypothetical `horizon_requires_metric_axes`
945 /// composing [`HorizonKind::requires_metric_axes`] as the
946 /// antisymmetric partner of `horizon_terminates`; a hypothetical
947 /// `intent_is_helm_driven` composing over the tagged-union
948 /// intent variants; a peer collapsing a routing form's
949 /// [`crate::routing::RoutingForm::ALL`] → bool) lands as ONE
950 /// peer inherent method with the same nullary derived body and
951 /// routes through the same fixed-tag substrate in
952 /// [`tatara-check`]'s classifier — no per-consumer restatement
953 /// of the `classification.<field>.<projection>()` chain.
954 ///
955 /// The point-domain require-tag surface in
956 /// `tatara-reconciler::bin::tatara-check` composes this primitive
957 /// as a fixed tag `terminating-horizon` on
958 /// [`POINT_FIXED_TAG_ARMS`] — byte-for-byte peer of the fixed
959 /// tags [`FixedTagArm`] already publishes (`depends-on`,
960 /// `boundary-pre`, `boundary-post`, `compliance`, `signals`).
961 /// The ephemeral surface publishes the same tag via
962 /// [`crate::ephemeral::EphemeralSpec::horizon_terminates`], which
963 /// composes THIS method through
964 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
965 /// so the two-surface parity contract holds — the operator's
966 /// `:requires (terminating-horizon)` audit answers the same
967 /// question on both surfaces.
968 ///
969 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
970 /// preserves proofs; the derived-nullary-bool predicate body
971 /// lives at ONE substrate site so every downstream (the
972 /// `terminating-horizon` fixed tag in [`tatara-check`], future
973 /// scheduler / termination-shape validators, future variant
974 /// additions on [`HorizonKind`]) binds through the SAME
975 /// `horizon_terminates()` shape rather than restating the
976 /// `classification.horizon.kind.terminates()` chain at each
977 /// callsite. THEORY.md §VI.1 — generation over composition; a
978 /// future [`HorizonKind`] variant lands at ONE `ALL` entry +
979 /// ONE `terminates` arm on the closed set and this probe picks
980 /// it up mechanically.
981 #[must_use]
982 pub fn horizon_terminates(&self) -> bool {
983 self.horizon.kind.terminates()
984 }
985
986 /// Derived-boolean predicate — does this [`Classification`] carry a
987 /// [`Horizon`] whose kind projects to `true` under
988 /// [`HorizonKind::requires_metric_axes`]? The ONE substrate
989 /// primitive that owns the `(Classification) -> bool` derived-
990 /// nullary-predicate walk shape on the `horizon.kind` slot for
991 /// the metric-axes-required question.
992 ///
993 /// # Second occupant on the (required-parent × nested-struct-derived-nullary-bool) corner
994 ///
995 /// Byte-for-byte peer of [`Self::horizon_terminates`] via the SAME
996 /// closed set [`HorizonKind`] reached through the SAME nested
997 /// [`Horizon`] struct: [`Self::horizon_terminates`] composes
998 /// [`HorizonKind::terminates`] as `self.horizon.kind.terminates()`;
999 /// this method composes the ANTISYMMETRIC partner
1000 /// [`HorizonKind::requires_metric_axes`] as
1001 /// `self.horizon.kind.requires_metric_axes()`. The closed set
1002 /// pins the XOR contract
1003 /// `terminates() ^ requires_metric_axes()` on every variant (see
1004 /// `horizon_kind_terminate_xor_requires_metric_axes` on the closed
1005 /// set itself), so exactly ONE of the two derived-nullary probes
1006 /// answers `true` per [`Classification`] and the two probes
1007 /// together partition [`HorizonKind::ALL`] into two disjoint
1008 /// buckets. This POPULATES the (required-parent × nested-struct-
1009 /// derived-nullary-bool) corner of the workspace-wide closed-set-
1010 /// driven presence-probe algebra at its SECOND substrate primitive
1011 /// after [`Self::horizon_terminates`] opened the corner, pinning
1012 /// the corner as a proven-repeatable primitive shape rather than
1013 /// a single-example curiosity.
1014 ///
1015 /// # Semantics — derived nullary boolean, not variant equality
1016 ///
1017 /// `horizon_requires_metric_axes()` returns `true` iff
1018 /// `self.horizon.kind.requires_metric_axes()`. The two-variant
1019 /// [`HorizonKind`] closed set publishes the truth table:
1020 /// [`HorizonKind::Bounded`] → `false` (has a fixed point, no
1021 /// asymptotic metric axes required); [`HorizonKind::Asymptotic`]
1022 /// → `true` (runs in perpetuity, `rate` and `oscillation` are the
1023 /// health signal and must be measured). A
1024 /// [`Classification::gate_compute`] baseline (which uses
1025 /// [`Horizon::default`] with `kind = HorizonKind::Bounded` via
1026 /// `#[default]`) answers `false` — the substrate's default-arm
1027 /// short-circuit propagates through the nested [`Horizon`]
1028 /// struct's own [`Default`] impl to this predicate's answer, the
1029 /// mirror image of [`Self::horizon_terminates`]'s default-arm
1030 /// answer.
1031 ///
1032 /// A future third [`HorizonKind`] variant (a hypothetical
1033 /// `Periodic` sentinel for "terminates on each window boundary
1034 /// then re-arms" — pre-flagged on the closed set's `ALL`
1035 /// docstring) reaches this probe through ONE `requires_metric_axes`
1036 /// arm on the closed set with the probe body untouched — the
1037 /// nullary-predicate shape defers every per-variant policy
1038 /// decision to the closed set's own truth table
1039 /// ([`HorizonKind::requires_metric_axes`]) rather than duplicating
1040 /// the discriminator sweep here.
1041 ///
1042 /// # Compounding
1043 ///
1044 /// The point-domain require-tag surface in
1045 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1046 /// as a fixed tag `metric-axes-required` on
1047 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte antisymmetric peer of
1048 /// the sibling `terminating-horizon` fixed tag. The ephemeral
1049 /// surface publishes the same tag via
1050 /// [`crate::ephemeral::EphemeralSpec::horizon_requires_metric_axes`],
1051 /// which composes THIS method through
1052 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1053 /// so the two-surface parity contract holds — the operator's
1054 /// `:requires (metric-axes-required)` audit answers the same
1055 /// question on both surfaces.
1056 ///
1057 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1058 /// preserves proofs; the derived-nullary-bool predicate body
1059 /// lives at ONE substrate site so every downstream (the
1060 /// `metric-axes-required` fixed tag in `tatara-check`, future
1061 /// scheduler / metric-provisioning validators, future variant
1062 /// additions on [`HorizonKind`]) binds through the SAME
1063 /// `horizon_requires_metric_axes()` shape rather than restating
1064 /// the `classification.horizon.kind.requires_metric_axes()` chain
1065 /// at each callsite. THEORY.md §VI.1 — generation over
1066 /// composition; a future [`HorizonKind`] variant lands at ONE
1067 /// `ALL` entry + ONE `requires_metric_axes` arm on the closed set
1068 /// and this probe picks it up mechanically.
1069 #[must_use]
1070 pub fn horizon_requires_metric_axes(&self) -> bool {
1071 self.horizon.kind.requires_metric_axes()
1072 }
1073
1074 /// Derived-boolean predicate — does this [`Classification`] carry a
1075 /// [`CalmClassification`] whose variant projects to `true` under
1076 /// [`CalmClassification::requires_coordination`]? The ONE substrate
1077 /// primitive that owns the `(Classification) -> bool` derived-
1078 /// nullary-predicate walk shape on the `calm` slot.
1079 ///
1080 /// # Third occupant on the (parent × derived-nullary-bool) corner
1081 ///
1082 /// Peer of [`Self::horizon_terminates`] and
1083 /// [`Self::horizon_requires_metric_axes`] on the workspace-wide
1084 /// (parent × derived-nullary-bool) corner of the closed-set-driven
1085 /// presence-probe algebra — the FIRST occupant threading the
1086 /// `calm` axis rather than the `horizon.kind` sub-axis. Distinct
1087 /// from the two `horizon.*` peers by ONE structural degree: this
1088 /// probe reads a DIRECT scalar closed-set field
1089 /// ([`Self::calm`]) rather than the NESTED-STRUCT projection
1090 /// (`self.horizon.kind`) both `horizon_*` peers walk; the derived-
1091 /// nullary shape and the truth-table composition style match
1092 /// exactly. Populates the corner as a proven-repeatable primitive
1093 /// shape across TWO distinct closed-set axes (`HorizonKind`,
1094 /// `CalmClassification`) rather than an axis-local curiosity.
1095 ///
1096 /// # Semantics — derived nullary boolean, not variant equality
1097 ///
1098 /// `calm_requires_coordination()` returns `true` iff
1099 /// `self.calm.requires_coordination()`. The two-variant
1100 /// [`CalmClassification`] closed set publishes the truth table
1101 /// (the CALM theorem's typed image, Hellerstein 2010):
1102 /// [`CalmClassification::Monotone`] → `false` (can be distributed
1103 /// without coordination); [`CalmClassification::NonMonotone`] →
1104 /// `true` (requires coordination). A
1105 /// [`Classification::gate_compute`] baseline (which uses
1106 /// [`CalmClassification::default = Monotone`] via `#[default]`)
1107 /// answers `false` — the substrate's default-arm short-circuit
1108 /// propagates through the scalar closed-set field's own
1109 /// [`Default`] impl to this predicate's answer. The mirror-image
1110 /// distinguishing feature vs the two `horizon_*` peers: those
1111 /// short-circuit through TWO layers of `Default`
1112 /// ([`Horizon::default`] → [`HorizonKind::default`]); this probe
1113 /// short-circuits through ONE layer of `Default`
1114 /// ([`CalmClassification::default`]) because `Self::calm` is a
1115 /// direct scalar rather than a nested struct wrapper.
1116 ///
1117 /// A future third [`CalmClassification`] variant (a hypothetical
1118 /// `ConditionallyMonotone` sentinel — pre-flagged on the closed
1119 /// set's `ALL` docstring) reaches this probe through ONE
1120 /// `requires_coordination` arm on the closed set with the probe
1121 /// body untouched — the nullary-predicate shape defers every
1122 /// per-variant policy decision to the closed set's own truth
1123 /// table ([`CalmClassification::requires_coordination`]) rather
1124 /// than duplicating the discriminator sweep here.
1125 ///
1126 /// # Compounding
1127 ///
1128 /// The point-domain require-tag surface in
1129 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1130 /// as a fixed tag `coordination-required` on
1131 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte peer of the sibling
1132 /// `terminating-horizon` and `metric-axes-required` fixed tags on
1133 /// the (parent × derived-nullary-bool) corner. The ephemeral
1134 /// surface publishes the same tag via
1135 /// [`crate::ephemeral::EphemeralSpec::calm_requires_coordination`],
1136 /// which composes THIS method through
1137 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1138 /// so the two-surface parity contract holds — the operator's
1139 /// `:requires (coordination-required)` audit answers the same
1140 /// question on both surfaces.
1141 ///
1142 /// Future scheduler dispatch between Raft writes and gossip
1143 /// propagation (documented on
1144 /// [`CalmClassification::requires_coordination`] itself) reads
1145 /// THIS predicate rather than re-deriving from the variant name
1146 /// at each callsite — the classification-axis lattice-typed
1147 /// image of the CALM theorem lives at ONE substrate site and
1148 /// every scheduler / coordination-mode chooser downstream binds
1149 /// through the SAME `calm_requires_coordination()` shape.
1150 ///
1151 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1152 /// preserves proofs; the derived-nullary-bool predicate body
1153 /// lives at ONE substrate site so every downstream (the
1154 /// `coordination-required` fixed tag in `tatara-check`, future
1155 /// scheduler / coordination-mode validators, future variant
1156 /// additions on [`CalmClassification`]) binds through the SAME
1157 /// `calm_requires_coordination()` shape rather than restating the
1158 /// `classification.calm.requires_coordination()` chain at each
1159 /// callsite. THEORY.md §VI.1 — generation over composition; a
1160 /// future [`CalmClassification`] variant lands at ONE `ALL` entry +
1161 /// ONE `requires_coordination` arm on the closed set and this probe
1162 /// picks it up mechanically.
1163 #[must_use]
1164 pub fn calm_requires_coordination(&self) -> bool {
1165 self.calm.requires_coordination()
1166 }
1167
1168 /// Derived-boolean predicate — does this [`Classification`] carry a
1169 /// [`DataClassification`] whose variant projects to `true` under
1170 /// [`DataClassification::is_regulated`]? The ONE substrate primitive
1171 /// that owns the `(Classification) -> bool` derived-nullary-
1172 /// predicate walk shape on the `data_classification` slot for the
1173 /// regulated-data question.
1174 ///
1175 /// # Fourth occupant on the (parent × derived-nullary-bool) corner
1176 ///
1177 /// Peer of [`Self::horizon_terminates`],
1178 /// [`Self::horizon_requires_metric_axes`], and
1179 /// [`Self::calm_requires_coordination`] on the workspace-wide
1180 /// (parent × derived-nullary-bool) corner of the closed-set-driven
1181 /// presence-probe algebra — the FIRST occupant threading the
1182 /// classification-data axis rather than the horizon or calm
1183 /// sub-axes. Populates the corner across THREE distinct closed-set
1184 /// axes (`HorizonKind`, `CalmClassification`, `DataClassification`)
1185 /// rather than two — pinning the corner as a proven-repeatable
1186 /// primitive shape across the substrate's three classification-
1187 /// axis closed sets that publish a `#[default]` variant, not a
1188 /// single-axis or two-axis curiosity. Byte-for-byte structural
1189 /// peer of [`Self::calm_requires_coordination`]: both walk a
1190 /// DIRECT scalar closed-set field (`self.calm` /
1191 /// `self.data_classification`) on the [`Classification`] parent —
1192 /// TWO layers of `Default` short-circuit (`Classification::gate_compute`
1193 /// → the direct scalar child's `#[default]`) — distinct from the
1194 /// two `horizon_*` peers which walk a NESTED-STRUCT projection
1195 /// (`self.horizon.kind`) with THREE layers of `Default`
1196 /// (`Classification::gate_compute` → `Horizon::default` →
1197 /// `HorizonKind::default`). SECOND direct-scalar peer on the
1198 /// corner: `calm_requires_coordination` opened the direct-scalar
1199 /// variant, this method populates it, pinning "direct-scalar
1200 /// derived-nullary-bool" as a proven-repeatable structural
1201 /// sub-corner rather than a single-example curiosity.
1202 ///
1203 /// # Semantics — derived nullary boolean, not variant equality
1204 ///
1205 /// `data_is_regulated()` returns `true` iff
1206 /// `self.data_classification.is_regulated()`. The six-variant
1207 /// [`DataClassification`] closed set publishes the truth table:
1208 /// [`DataClassification::Public`] / [`DataClassification::Internal`]
1209 /// / [`DataClassification::Confidential`] → `false` (not subject
1210 /// to external regulatory regime); [`DataClassification::Pii`] /
1211 /// [`DataClassification::Phi`] / [`DataClassification::Pci`] →
1212 /// `true` (HIPAA / PCI-DSS / GDPR-style data-subject controls
1213 /// apply). A [`Classification::gate_compute`] baseline (which
1214 /// uses [`DataClassification::default = Internal`] via
1215 /// `#[default]`) answers `false` — the substrate's default-arm
1216 /// short-circuit propagates through the scalar closed-set field's
1217 /// own [`Default`] impl to this predicate's answer, mirror image
1218 /// of [`Self::calm_requires_coordination`]'s Monotone-default
1219 /// short-circuit through the same structural depth.
1220 ///
1221 /// The closed-set-internal pin
1222 /// `data_classification_regulated_implies_restricted` seals the
1223 /// implication `is_regulated() ⇒ is_restricted()` on every
1224 /// variant, so a `true` answer here implies the sibling
1225 /// (`data_is_restricted`, when it lands) also answers `true`;
1226 /// the reverse does not hold (`Internal | Confidential` are
1227 /// restricted but not regulated).
1228 ///
1229 /// A future seventh [`DataClassification`] variant (a hypothetical
1230 /// `TradeSecret` bucket for competitive-sensitive data, or an
1231 /// `Anonymized` bucket for pseudonymized-PII whose regulatory
1232 /// posture differs from raw PII) reaches this probe through ONE
1233 /// `is_regulated` arm on the closed set with the probe body
1234 /// untouched — the nullary-predicate shape defers every per-
1235 /// variant policy decision to the closed set's own truth table
1236 /// ([`DataClassification::is_regulated`]) rather than duplicating
1237 /// the discriminator sweep here.
1238 ///
1239 /// # Compounding
1240 ///
1241 /// The point-domain require-tag surface in
1242 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1243 /// as a fixed tag `data-regulated` on `POINT_FIXED_TAG_ARMS` —
1244 /// byte-for-byte peer of the sibling `terminating-horizon`,
1245 /// `metric-axes-required`, and `coordination-required` fixed tags
1246 /// on the (parent × derived-nullary-bool) corner. The ephemeral
1247 /// surface publishes the same tag via
1248 /// [`crate::ephemeral::EphemeralSpec::data_is_regulated`], which
1249 /// composes THIS method through
1250 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1251 /// so the two-surface parity contract holds — the operator's
1252 /// `:requires (data-regulated)` audit answers the same question
1253 /// on both surfaces.
1254 ///
1255 /// Future compliance-baseline auto-selectors dispatching on the
1256 /// `(is_regulated, is_restricted)` two-axis projection
1257 /// (documented on [`DataClassification::is_regulated`] itself)
1258 /// read THIS predicate rather than re-deriving from the variant
1259 /// name at each callsite — the classification-data-axis lattice-
1260 /// typed image of the regulated-data question lives at ONE
1261 /// substrate site and every compliance-mode chooser downstream
1262 /// binds through the SAME `data_is_regulated()` shape.
1263 ///
1264 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1265 /// preserves proofs; the derived-nullary-bool predicate body
1266 /// lives at ONE substrate site so every downstream (the
1267 /// `data-regulated` fixed tag in `tatara-check`, future
1268 /// compliance-baseline / regulatory-regime validators, future
1269 /// variant additions on [`DataClassification`]) binds through
1270 /// the SAME `data_is_regulated()` shape rather than restating the
1271 /// `classification.data_classification.is_regulated()` chain at
1272 /// each callsite. THEORY.md §VI.1 — generation over composition;
1273 /// a future [`DataClassification`] variant lands at ONE `ALL`
1274 /// entry + ONE `is_regulated` arm on the closed set and this
1275 /// probe picks it up mechanically.
1276 #[must_use]
1277 pub fn data_is_regulated(&self) -> bool {
1278 self.data_classification.is_regulated()
1279 }
1280
1281 /// Derived-boolean predicate — does this [`Classification`] carry a
1282 /// [`DataClassification`] whose variant projects to `true` under
1283 /// [`DataClassification::is_restricted`]? The ONE substrate primitive
1284 /// that owns the `(Classification) -> bool` derived-nullary-
1285 /// predicate walk shape on the `data_classification` slot for the
1286 /// restricted-data question.
1287 ///
1288 /// # Fifth occupant on the (parent × derived-nullary-bool) corner
1289 ///
1290 /// Peer of [`Self::horizon_terminates`],
1291 /// [`Self::horizon_requires_metric_axes`],
1292 /// [`Self::calm_requires_coordination`], and
1293 /// [`Self::data_is_regulated`] on the workspace-wide (parent ×
1294 /// derived-nullary-bool) corner of the closed-set-driven presence-
1295 /// probe algebra — the SECOND peer threading the classification-
1296 /// data axis after [`Self::data_is_regulated`] opened it, pinning
1297 /// the classification-data axis as a proven-repeatable structural
1298 /// sub-corner across TWO sibling closed-set projections
1299 /// (`DataClassification::is_regulated` / `is_restricted`) rather
1300 /// than a single-projection curiosity. Byte-for-byte structural
1301 /// peer of [`Self::data_is_regulated`]: both walk the SAME
1302 /// direct scalar closed-set field (`self.data_classification`) on
1303 /// the [`Classification`] parent through TWO layers of `Default`
1304 /// short-circuit (`Classification::gate_compute` →
1305 /// [`DataClassification::default = Internal`]) — distinct from the
1306 /// two `horizon_*` peers by ONE structural degree (they walk a
1307 /// NESTED-STRUCT projection with THREE layers of `Default`). THIRD
1308 /// direct-scalar peer on the corner after
1309 /// [`Self::calm_requires_coordination`] opened +
1310 /// [`Self::data_is_regulated`] populated the sub-corner: seals
1311 /// "direct-scalar derived-nullary-bool" as the substrate's third
1312 /// occupant on the sub-corner and the FIRST corner peer whose
1313 /// gate-compute baseline projects to `true` rather than `false`,
1314 /// mirror-image of the `Bounded`-default `terminating-horizon`
1315 /// baseline on the horizon-axis nested sub-corner.
1316 ///
1317 /// # Semantics — derived nullary boolean, not variant equality
1318 ///
1319 /// `data_is_restricted()` returns `true` iff
1320 /// `self.data_classification.is_restricted()`. The six-variant
1321 /// [`DataClassification`] closed set publishes the truth table:
1322 /// [`DataClassification::Public`] → `false` (freely distributable);
1323 /// [`DataClassification::Internal`] / [`DataClassification::Confidential`]
1324 /// / [`DataClassification::Pii`] / [`DataClassification::Phi`] /
1325 /// [`DataClassification::Pci`] → `true` (access controls beyond
1326 /// freely-distributable apply). A [`Classification::gate_compute`]
1327 /// baseline (which uses [`DataClassification::default = Internal`]
1328 /// via `#[default]`) answers `true` — the substrate's default-arm
1329 /// short-circuit propagates through the scalar closed-set field's
1330 /// own [`Default`] impl to this predicate's answer, distinct from
1331 /// [`Self::data_is_regulated`]'s `false` baseline (which projects
1332 /// the SAME `Internal` default through the antisymmetric arm of
1333 /// the closed set's predicate pair). This baseline-flip is the
1334 /// FIRST direct-scalar corner peer where the gate-compute baseline
1335 /// answers `true`, not `false`.
1336 ///
1337 /// The closed-set-internal pin
1338 /// `data_classification_regulated_implies_restricted` seals the
1339 /// implication `is_regulated() ⇒ is_restricted()` on every
1340 /// variant, so `data_is_regulated()` returning `true` implies THIS
1341 /// predicate also returns `true`; the reverse does not hold
1342 /// (`Internal | Confidential` are restricted but not regulated).
1343 /// This is the FIRST substrate-primitive pair on the (parent ×
1344 /// derived-nullary-bool) corner whose two predicates carry a non-
1345 /// trivial closed-set-internal implication relationship — a
1346 /// future compliance-baseline auto-selector can rely on
1347 /// `data_is_regulated() ⇒ data_is_restricted()` by construction
1348 /// rather than restating the implication at every callsite.
1349 ///
1350 /// A future seventh [`DataClassification`] variant (a hypothetical
1351 /// `TradeSecret` bucket for competitive-sensitive data, or an
1352 /// `Anonymized` bucket for pseudonymized-PII whose access posture
1353 /// differs from raw PII) reaches this probe through ONE
1354 /// `is_restricted` arm on the closed set with the probe body
1355 /// untouched — the nullary-predicate shape defers every per-
1356 /// variant policy decision to the closed set's own truth table
1357 /// ([`DataClassification::is_restricted`]) rather than duplicating
1358 /// the discriminator sweep here.
1359 ///
1360 /// # Compounding
1361 ///
1362 /// The point-domain require-tag surface in
1363 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1364 /// as a fixed tag `data-restricted` on `POINT_FIXED_TAG_ARMS` —
1365 /// byte-for-byte peer of the sibling `terminating-horizon`,
1366 /// `metric-axes-required`, `coordination-required`, and
1367 /// `data-regulated` fixed tags on the (parent × derived-nullary-
1368 /// bool) corner. The ephemeral surface publishes the same tag via
1369 /// [`crate::ephemeral::EphemeralSpec::data_is_restricted`], which
1370 /// composes THIS method through
1371 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1372 /// so the two-surface parity contract holds — the operator's
1373 /// `:requires (data-restricted)` audit answers the same question
1374 /// on both surfaces.
1375 ///
1376 /// Future compliance-baseline auto-selectors dispatching on the
1377 /// `(is_regulated, is_restricted)` two-axis projection
1378 /// (documented on [`DataClassification::is_regulated`] itself)
1379 /// read THIS predicate rather than re-deriving from the variant
1380 /// name at each callsite — the classification-data-axis lattice-
1381 /// typed image of the restricted-data question lives at ONE
1382 /// substrate site and every compliance-mode chooser downstream
1383 /// binds through the SAME `data_is_restricted()` shape.
1384 ///
1385 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1386 /// preserves proofs; the derived-nullary-bool predicate body
1387 /// lives at ONE substrate site so every downstream (the
1388 /// `data-restricted` fixed tag in `tatara-check`, future
1389 /// compliance-baseline / access-control-mandatory validators,
1390 /// future variant additions on [`DataClassification`]) binds
1391 /// through the SAME `data_is_restricted()` shape rather than
1392 /// restating the
1393 /// `classification.data_classification.is_restricted()` chain at
1394 /// each callsite. THEORY.md §VI.1 — generation over composition;
1395 /// a future [`DataClassification`] variant lands at ONE `ALL`
1396 /// entry + ONE `is_restricted` arm on the closed set and this
1397 /// probe picks it up mechanically.
1398 #[must_use]
1399 pub fn data_is_restricted(&self) -> bool {
1400 self.data_classification.is_restricted()
1401 }
1402
1403 /// Derived-boolean predicate — does this [`Classification`]'s
1404 /// [`ConvergencePointType`] project to `true` under
1405 /// [`ConvergencePointType::is_endomorphic`]? The ONE substrate
1406 /// primitive that owns the `(Classification) -> bool` derived-
1407 /// nullary-predicate walk shape on the `point_type` slot for the
1408 /// 1→1 topology-bucket question.
1409 ///
1410 /// # Sixth occupant on the (parent × derived-nullary-bool) corner
1411 ///
1412 /// Peer of [`Self::horizon_terminates`],
1413 /// [`Self::horizon_requires_metric_axes`],
1414 /// [`Self::calm_requires_coordination`],
1415 /// [`Self::data_is_regulated`], and [`Self::data_is_restricted`]
1416 /// on the workspace-wide (parent × derived-nullary-bool) corner of
1417 /// the closed-set-driven presence-probe algebra — the SIXTH
1418 /// occupant on the corner and the FIRST peer threading the
1419 /// classification-`point_type` axis rather than the horizon,
1420 /// calm, or data axes. Direct-scalar peer of
1421 /// [`Self::calm_requires_coordination`] /
1422 /// [`Self::data_is_regulated`] / [`Self::data_is_restricted`]:
1423 /// walks a DIRECT scalar closed-set field's derived projection on
1424 /// the [`Classification`] parent (no nested-struct hop like the
1425 /// two `horizon_*` peers), but distinct from all three by ONE
1426 /// structural degree — [`ConvergencePointType`] has NO
1427 /// [`Default`] impl, so the derived-nullary answer here does NOT
1428 /// carry a substrate default-arm short-circuit through the
1429 /// parent's `#[default]` chain. The [`Self::gate_compute`]
1430 /// baseline still fixes an answer (`Gate.is_endomorphic() =
1431 /// false`), pinned by
1432 /// `classification_gate_compute_point_is_endomorphic_is_false`,
1433 /// but that answer is chosen deliberately by the baseline's
1434 /// `point_type: Gate` field rather than reached through a
1435 /// closed-set-side `#[default]`. Populates the corner as a
1436 /// proven-repeatable primitive shape across FOUR distinct
1437 /// classification-axis closed sets ([`HorizonKind`],
1438 /// [`CalmClassification`], [`DataClassification`],
1439 /// [`ConvergencePointType`]) rather than a three-axis curiosity.
1440 ///
1441 /// # Semantics — derived nullary boolean, not variant equality
1442 ///
1443 /// `point_is_endomorphic()` returns `true` iff
1444 /// `self.point_type.is_endomorphic()`. The eight-variant
1445 /// [`ConvergencePointType`] closed set publishes the truth table
1446 /// (via the shape-preserving-topology (1,1) arity partition):
1447 /// [`ConvergencePointType::Transform`] /
1448 /// [`ConvergencePointType::Observe`] → `true` (1→1 shape);
1449 /// [`ConvergencePointType::Fork`] /
1450 /// [`ConvergencePointType::Broadcast`] → `false` (1→N diffusive);
1451 /// [`ConvergencePointType::Join`] / [`ConvergencePointType::Gate`]
1452 /// / [`ConvergencePointType::Select`] /
1453 /// [`ConvergencePointType::Reduce`] → `false` (N→1 convergent).
1454 /// A [`Classification::gate_compute`] baseline (which uses
1455 /// [`ConvergencePointType::Gate`] deliberately as the baseline
1456 /// convergent barrier point) answers `false` — this is NOT a
1457 /// [`Default`]-arm short-circuit (unlike the four earlier
1458 /// direct-scalar / nested-struct corner peers), because
1459 /// [`ConvergencePointType`] has no `impl Default`; the baseline
1460 /// is a chosen field value, not a defaulted one.
1461 ///
1462 /// A future ninth [`ConvergencePointType`] variant lands at ONE
1463 /// `ALL` entry + ONE `is_endomorphic` arm on the closed set with
1464 /// the probe body untouched — the nullary-predicate shape defers
1465 /// every per-variant policy decision to the closed set's own
1466 /// truth table ([`ConvergencePointType::is_endomorphic`]) rather
1467 /// than duplicating the discriminator sweep here.
1468 ///
1469 /// # Compounding
1470 ///
1471 /// The point-domain require-tag surface in
1472 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1473 /// as a fixed tag `endomorphic-point` on
1474 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte peer of the sibling
1475 /// `terminating-horizon` / `metric-axes-required` /
1476 /// `coordination-required` / `data-regulated` / `data-restricted`
1477 /// fixed tags on the (parent × derived-nullary-bool) corner. The
1478 /// ephemeral surface publishes the same tag via
1479 /// [`crate::ephemeral::EphemeralSpec::point_is_endomorphic`],
1480 /// which composes THIS method through
1481 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1482 /// so the two-surface parity contract holds — the operator's
1483 /// `:requires (endomorphic-point)` audit answers the same
1484 /// question on both surfaces. Sibling projections
1485 /// [`ConvergencePointType::is_diffusive`] and
1486 /// [`ConvergencePointType::is_convergent`] compose byte-
1487 /// identically as future seventh + eighth corner occupants; when
1488 /// all three land the three-way partition contract
1489 /// `is_endomorphic ⊕ is_diffusive ⊕ is_convergent` sealed on the
1490 /// closed set by `convergence_point_type_buckets_cover_every_variant`
1491 /// composes through the parent-composed layer as a substrate-
1492 /// wide theorem exactly as the closed-set XOR pair
1493 /// `terminates ^ requires_metric_axes` composes through this
1494 /// corner today.
1495 ///
1496 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1497 /// preserves proofs; the derived-nullary-bool predicate body
1498 /// lives at ONE substrate site so every downstream (the
1499 /// `endomorphic-point` fixed tag in `tatara-check`, future DAG
1500 /// composition / edge-cardinality validators, future variant
1501 /// additions on [`ConvergencePointType`]) binds through the SAME
1502 /// `point_is_endomorphic()` shape rather than restating the
1503 /// `classification.point_type.is_endomorphic()` chain at each
1504 /// callsite. THEORY.md §VI.1 — generation over composition; a
1505 /// future [`ConvergencePointType`] variant lands at ONE `ALL`
1506 /// entry + ONE `is_endomorphic` arm on the closed set and this
1507 /// probe picks it up mechanically.
1508 #[must_use]
1509 pub fn point_is_endomorphic(&self) -> bool {
1510 self.point_type.is_endomorphic()
1511 }
1512
1513 /// Derived-boolean predicate — does this [`Classification`]'s
1514 /// [`ConvergencePointType`] project to `true` under
1515 /// [`ConvergencePointType::is_diffusive`]? The ONE substrate
1516 /// primitive that owns the `(Classification) -> bool` derived-
1517 /// nullary-predicate walk shape on the `point_type` slot for the
1518 /// 1→N fan-out topology-bucket question.
1519 ///
1520 /// # Seventh occupant on the (parent × derived-nullary-bool) corner
1521 ///
1522 /// Peer of [`Self::horizon_terminates`],
1523 /// [`Self::horizon_requires_metric_axes`],
1524 /// [`Self::calm_requires_coordination`],
1525 /// [`Self::data_is_regulated`], [`Self::data_is_restricted`], and
1526 /// [`Self::point_is_endomorphic`] on the workspace-wide (parent ×
1527 /// derived-nullary-bool) corner of the closed-set-driven presence-
1528 /// probe algebra — the SEVENTH occupant on the corner and the
1529 /// SECOND peer threading the classification-`point_type` axis,
1530 /// pinning that axis as a proven-repeatable structural sub-corner
1531 /// across TWO sibling projections rather than a one-off. Direct-
1532 /// scalar peer of [`Self::point_is_endomorphic`]: the two share
1533 /// the SAME parent slot (`self.point_type`), the SAME closed-set
1534 /// carrier ([`ConvergencePointType`]), and the SAME chosen-field
1535 /// baseline discipline ([`ConvergencePointType`] has no
1536 /// [`Default`] impl, so the derived-nullary answer here does NOT
1537 /// carry a substrate default-arm short-circuit through the
1538 /// parent's `#[default]` chain — [`Self::gate_compute`] fixes
1539 /// `point_type: Gate` deliberately, and `Gate.is_diffusive() =
1540 /// false`).
1541 ///
1542 /// # Semantics — derived nullary boolean, disjoint from endomorphic
1543 ///
1544 /// `point_is_diffusive()` returns `true` iff
1545 /// `self.point_type.is_diffusive()`. The eight-variant
1546 /// [`ConvergencePointType`] closed set publishes the truth table
1547 /// (via the (One, Many) arity cell): [`ConvergencePointType::Fork`]
1548 /// / [`ConvergencePointType::Broadcast`] → `true` (1→N fan-out);
1549 /// every other variant → `false` (endomorphic or convergent).
1550 /// A [`Classification::gate_compute`] baseline answers `false`
1551 /// deliberately (Gate is a convergent barrier, not a diffusive
1552 /// fan-out).
1553 ///
1554 /// A future ninth [`ConvergencePointType`] variant lands at ONE
1555 /// `ALL` entry + ONE `is_diffusive` arm on the closed set with the
1556 /// probe body untouched — the nullary-predicate shape defers every
1557 /// per-variant policy decision to the closed set's own truth
1558 /// table ([`ConvergencePointType::is_diffusive`]) rather than
1559 /// duplicating the discriminator sweep here.
1560 ///
1561 /// # Compounding — first corner-peer mutex on the `point_type` axis
1562 ///
1563 /// This is the FIRST corner-peer pair on the `point_type` axis
1564 /// (with [`Self::point_is_endomorphic`]) whose two projections
1565 /// carry a non-trivial closed-set-internal MUTEX relationship
1566 /// (`point_is_endomorphic ⇒ ¬point_is_diffusive` — no variant
1567 /// lands in both buckets, sealed on the closed set by
1568 /// `convergence_point_type_buckets_cover_every_variant`). Distinct
1569 /// from the FIRST corner-peer implication pair on the `data`
1570 /// axis (`data_is_regulated ⇒ data_is_restricted`) by the
1571 /// implication direction — regulated-⇒-restricted has one bucket
1572 /// contained in the other, while endomorphic-vs-diffusive has
1573 /// two disjoint buckets partitioning a common universe. When the
1574 /// third sibling [`Self::point_is_convergent`] lands, the mutex
1575 /// closes into the three-way XOR partition contract
1576 /// `point_is_endomorphic ⊕ point_is_diffusive ⊕
1577 /// point_is_convergent` sealed on the closed set by
1578 /// `convergence_point_type_buckets_cover_every_variant` — a
1579 /// substrate-wide theorem that composes through this corner
1580 /// exactly as the closed-set XOR pair `terminates ^
1581 /// requires_metric_axes` composes today.
1582 ///
1583 /// The point-domain require-tag surface in
1584 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1585 /// as a fixed tag `diffusive-point` on `POINT_FIXED_TAG_ARMS` —
1586 /// byte-for-byte peer of the sibling `endomorphic-point` fixed
1587 /// tag. The ephemeral surface publishes the same tag via
1588 /// [`crate::ephemeral::EphemeralSpec::point_is_diffusive`], which
1589 /// composes THIS method through
1590 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`] so
1591 /// the two-surface parity contract holds — the operator's
1592 /// `:requires (diffusive-point)` audit answers the same question
1593 /// on both surfaces.
1594 ///
1595 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1596 /// preserves proofs; the derived-nullary-bool predicate body
1597 /// lives at ONE substrate site so every downstream (the
1598 /// `diffusive-point` fixed tag in `tatara-check`, future DAG
1599 /// composition / edge-cardinality validators, future variant
1600 /// additions on [`ConvergencePointType`]) binds through the SAME
1601 /// `point_is_diffusive()` shape rather than restating the
1602 /// `classification.point_type.is_diffusive()` chain at each
1603 /// callsite. THEORY.md §VI.1 — generation over composition; a
1604 /// future [`ConvergencePointType`] variant lands at ONE `ALL`
1605 /// entry + ONE `is_diffusive` arm on the closed set and this
1606 /// probe picks it up mechanically.
1607 #[must_use]
1608 pub fn point_is_diffusive(&self) -> bool {
1609 self.point_type.is_diffusive()
1610 }
1611
1612 /// Derived-boolean predicate — does this [`Classification`]'s
1613 /// [`ConvergencePointType`] project to `true` under
1614 /// [`ConvergencePointType::is_convergent`]? The ONE substrate
1615 /// primitive that owns the `(Classification) -> bool` derived-
1616 /// nullary-predicate walk shape on the `point_type` slot for the
1617 /// N→1 fan-in topology-bucket question.
1618 ///
1619 /// # Eighth occupant on the (parent × derived-nullary-bool) corner
1620 ///
1621 /// Peer of [`Self::horizon_terminates`],
1622 /// [`Self::horizon_requires_metric_axes`],
1623 /// [`Self::calm_requires_coordination`],
1624 /// [`Self::data_is_regulated`], [`Self::data_is_restricted`],
1625 /// [`Self::point_is_endomorphic`], and [`Self::point_is_diffusive`]
1626 /// on the workspace-wide (parent × derived-nullary-bool) corner of
1627 /// the closed-set-driven presence-probe algebra — the EIGHTH
1628 /// occupant on the corner and the THIRD peer threading the
1629 /// classification-`point_type` axis. Direct-scalar peer of
1630 /// [`Self::point_is_endomorphic`] / [`Self::point_is_diffusive`]:
1631 /// the three share the SAME parent slot (`self.point_type`), the
1632 /// SAME closed-set carrier ([`ConvergencePointType`]), and the
1633 /// SAME chosen-field baseline discipline
1634 /// ([`ConvergencePointType`] has no [`Default`] impl, so the
1635 /// derived-nullary answer here does NOT carry a substrate default-
1636 /// arm short-circuit through the parent's `#[default]` chain).
1637 /// Distinct from the two sibling probes on ONE structural degree
1638 /// — the [`Self::gate_compute`] baseline's `point_type: Gate`
1639 /// answer projects to `true` HERE (`Gate.is_convergent() = true`),
1640 /// mirror-inverted from the two siblings' `false` answers, so
1641 /// this is the FIRST direct-scalar corner peer whose parent-
1642 /// composed gate-compute baseline projects `true` through a
1643 /// chosen-field (rather than defaulted) answer.
1644 ///
1645 /// # Semantics — derived nullary boolean, closes the three-way carving
1646 ///
1647 /// `point_is_convergent()` returns `true` iff
1648 /// `self.point_type.is_convergent()`. The eight-variant
1649 /// [`ConvergencePointType`] closed set publishes the truth table
1650 /// (via the (Many, One) arity cell): [`ConvergencePointType::Join`]
1651 /// / [`ConvergencePointType::Gate`] /
1652 /// [`ConvergencePointType::Select`] / [`ConvergencePointType::Reduce`]
1653 /// → `true` (N→1 fan-in); every other variant → `false`
1654 /// (endomorphic or diffusive). A [`Classification::gate_compute`]
1655 /// baseline answers `true` deliberately (Gate is the canonical
1656 /// convergent barrier point of the workspace baseline).
1657 ///
1658 /// A future ninth [`ConvergencePointType`] variant lands at ONE
1659 /// `ALL` entry + ONE `is_convergent` arm on the closed set with
1660 /// the probe body untouched — the nullary-predicate shape defers
1661 /// every per-variant policy decision to the closed set's own truth
1662 /// table ([`ConvergencePointType::is_convergent`]) rather than
1663 /// duplicating the discriminator sweep here.
1664 ///
1665 /// # Compounding — closes the three-way XOR partition on the `point_type` axis
1666 ///
1667 /// This is the THIRD sibling on the `point_type` axis closing the
1668 /// mutex pair [`Self::point_is_endomorphic`] /
1669 /// [`Self::point_is_diffusive`] (which sealed
1670 /// `point_is_endomorphic ⇒ ¬point_is_diffusive`) into the FULL
1671 /// three-way XOR partition contract
1672 /// `point_is_endomorphic ⊕ point_is_diffusive ⊕
1673 /// point_is_convergent = true` for every
1674 /// [`ConvergencePointType`] variant. Sealed on the closed set by
1675 /// `convergence_point_type_buckets_cover_every_variant` (which
1676 /// pins each variant lands in EXACTLY ONE bucket) and now
1677 /// composed through the parent-composed layer as a substrate-wide
1678 /// theorem. THREE-way XOR is a stricter contract than the closed-
1679 /// set XOR pair `terminates ^ requires_metric_axes` that composes
1680 /// through this corner today via the two `horizon_*` peers — this
1681 /// axis carries a partition of THREE non-empty buckets rather
1682 /// than TWO, so the ternary XOR is the natural generalization
1683 /// composed through the corner.
1684 ///
1685 /// The point-domain require-tag surface in
1686 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1687 /// as a fixed tag `convergent-point` on `POINT_FIXED_TAG_ARMS` —
1688 /// byte-for-byte peer of the sibling `endomorphic-point` /
1689 /// `diffusive-point` fixed tags. The ephemeral surface publishes
1690 /// the same tag via
1691 /// [`crate::ephemeral::EphemeralSpec::point_is_convergent`], which
1692 /// composes THIS method through
1693 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`] so
1694 /// the two-surface parity contract holds — the operator's
1695 /// `:requires (convergent-point)` audit answers the same question
1696 /// on both surfaces.
1697 ///
1698 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1699 /// preserves proofs; the derived-nullary-bool predicate body
1700 /// lives at ONE substrate site so every downstream (the
1701 /// `convergent-point` fixed tag in `tatara-check`, future DAG
1702 /// composition / edge-cardinality validators, future variant
1703 /// additions on [`ConvergencePointType`]) binds through the SAME
1704 /// `point_is_convergent()` shape rather than restating the
1705 /// `classification.point_type.is_convergent()` chain at each
1706 /// callsite. THEORY.md §VI.1 — generation over composition; a
1707 /// future [`ConvergencePointType`] variant lands at ONE `ALL`
1708 /// entry + ONE `is_convergent` arm on the closed set and this
1709 /// probe picks it up mechanically.
1710 #[must_use]
1711 pub fn point_is_convergent(&self) -> bool {
1712 self.point_type.is_convergent()
1713 }
1714
1715 /// Derived-boolean predicate — does this [`Classification`]'s
1716 /// [`SubstrateType`] project to `true` under
1717 /// [`SubstrateType::is_resource`]? The ONE substrate primitive
1718 /// that owns the `(Classification) -> bool` derived-nullary-
1719 /// predicate walk shape on the `substrate` slot for the
1720 /// resource-plane bucket question.
1721 ///
1722 /// # Ninth occupant on the (parent × derived-nullary-bool) corner
1723 ///
1724 /// Peer of [`Self::horizon_terminates`],
1725 /// [`Self::horizon_requires_metric_axes`],
1726 /// [`Self::calm_requires_coordination`],
1727 /// [`Self::data_is_regulated`], [`Self::data_is_restricted`],
1728 /// [`Self::point_is_endomorphic`], [`Self::point_is_diffusive`],
1729 /// and [`Self::point_is_convergent`] on the workspace-wide
1730 /// (parent × derived-nullary-bool) corner of the closed-set-
1731 /// driven presence-probe algebra — the NINTH occupant on the
1732 /// corner and the FIRST peer threading the classification-
1733 /// `substrate` axis (the fourth of six classification axes,
1734 /// after `horizon`, `calm`, `data_classification`, and
1735 /// `point_type`). Direct-scalar peer of
1736 /// [`Self::point_is_endomorphic`] /
1737 /// [`Self::point_is_diffusive`] /
1738 /// [`Self::point_is_convergent`]: all four share the shape
1739 /// (direct scalar closed-set field with no [`Default`] impl on
1740 /// the child, so no default-arm short-circuit through the
1741 /// child's `#[default]` chain). Distinct from the three
1742 /// `point_type`-axis siblings on the parent slot walked
1743 /// (`self.substrate` vs `self.point_type`) and on the closed set
1744 /// carried ([`SubstrateType`] vs [`ConvergencePointType`]) — the
1745 /// [`Classification::gate_compute`] baseline's chosen field
1746 /// (`substrate: Compute`) projects `true` HERE
1747 /// (`Compute.is_resource() = true`), mirror-aligned with the
1748 /// [`Self::point_is_convergent`] sibling's `true`-on-baseline
1749 /// answer and mirror-inverted from the two other `point_type`
1750 /// peers.
1751 ///
1752 /// # Semantics — derived nullary boolean over the closed-set plane
1753 ///
1754 /// `substrate_is_resource()` returns `true` iff
1755 /// `self.substrate.is_resource()`. The eight-variant
1756 /// [`SubstrateType`] closed set publishes the truth table (via
1757 /// the plane partition):
1758 /// [`SubstrateType::Financial`] / [`SubstrateType::Compute`] /
1759 /// [`SubstrateType::Network`] / [`SubstrateType::Storage`] →
1760 /// `true` (resource plane — you allocate budgets from it);
1761 /// [`SubstrateType::Security`] / [`SubstrateType::Identity`] /
1762 /// [`SubstrateType::Observability`] /
1763 /// [`SubstrateType::Regulatory`] → `false` (policy or telemetry
1764 /// plane). A [`Classification::gate_compute`] baseline answers
1765 /// `true` because its `substrate: Compute` field is deliberately
1766 /// resource-plane.
1767 ///
1768 /// A future ninth [`SubstrateType`] variant lands at ONE `ALL`
1769 /// entry + ONE `is_resource` arm on the closed set with the
1770 /// probe body untouched — the nullary-predicate shape defers
1771 /// every per-variant policy decision to the closed set's own
1772 /// truth table ([`SubstrateType::is_resource`]) rather than
1773 /// duplicating the discriminator sweep here.
1774 ///
1775 /// # Compounding — first substrate-axis peer, opens the three-way plane partition
1776 ///
1777 /// The point-domain require-tag surface in
1778 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1779 /// as a fixed tag `resource-substrate` on
1780 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte structural peer of the
1781 /// sibling `terminating-horizon` / `metric-axes-required` /
1782 /// `coordination-required` / `data-regulated` / `data-restricted`
1783 /// / `endomorphic-point` / `diffusive-point` / `convergent-point`
1784 /// fixed tags on the (parent × derived-nullary-bool) corner. The
1785 /// ephemeral surface publishes the same tag via
1786 /// [`crate::ephemeral::EphemeralSpec::substrate_is_resource`],
1787 /// which composes THIS method through
1788 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1789 /// so the two-surface parity contract holds — the operator's
1790 /// `:requires (resource-substrate)` audit answers the same
1791 /// question on both surfaces. Sibling projections
1792 /// [`SubstrateType::is_policy`] and
1793 /// [`SubstrateType::is_telemetry`] compose byte-identically as
1794 /// future tenth + eleventh corner occupants; when all three land
1795 /// the three-way partition contract
1796 /// `is_resource ⊕ is_policy ⊕ is_telemetry` sealed on the closed
1797 /// set by `substrate_type_buckets_cover_every_variant` composes
1798 /// through the parent-composed layer as a substrate-wide theorem
1799 /// — the exact ternary lift already sealed on the sibling
1800 /// `point_type` axis by
1801 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`.
1802 ///
1803 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1804 /// preserves proofs; the derived-nullary-bool predicate body
1805 /// lives at ONE substrate site so every downstream (the
1806 /// `resource-substrate` fixed tag in `tatara-check`, future
1807 /// plane-baseline / compliance-baseline selectors, future
1808 /// variant additions on [`SubstrateType`]) binds through the
1809 /// SAME `substrate_is_resource()` shape rather than restating
1810 /// the `classification.substrate.is_resource()` chain at each
1811 /// callsite. THEORY.md §VI.1 — generation over composition; a
1812 /// future [`SubstrateType`] variant lands at ONE `ALL` entry +
1813 /// ONE `is_resource` arm on the closed set and this probe picks
1814 /// it up mechanically.
1815 #[must_use]
1816 pub fn substrate_is_resource(&self) -> bool {
1817 self.substrate.is_resource()
1818 }
1819
1820 /// Derived-boolean predicate — does this [`Classification`]'s
1821 /// [`SubstrateType`] project to `true` under
1822 /// [`SubstrateType::is_policy`]? The ONE substrate primitive
1823 /// that owns the `(Classification) -> bool` derived-nullary-
1824 /// predicate walk shape on the `substrate` slot for the
1825 /// policy-plane bucket question.
1826 ///
1827 /// # Tenth occupant on the (parent × derived-nullary-bool) corner
1828 ///
1829 /// Peer of [`Self::horizon_terminates`],
1830 /// [`Self::horizon_requires_metric_axes`],
1831 /// [`Self::calm_requires_coordination`],
1832 /// [`Self::data_is_regulated`], [`Self::data_is_restricted`],
1833 /// [`Self::point_is_endomorphic`], [`Self::point_is_diffusive`],
1834 /// [`Self::point_is_convergent`], and
1835 /// [`Self::substrate_is_resource`] on the workspace-wide
1836 /// (parent × derived-nullary-bool) corner of the closed-set-
1837 /// driven presence-probe algebra — the TENTH occupant on the
1838 /// corner and the SECOND peer threading the classification-
1839 /// `substrate` axis, promoting that axis from a proven-repeatable
1840 /// one-off (`substrate_is_resource` alone) to a proven-repeatable
1841 /// pair. FIRST corner-peer pair on the `substrate` axis whose
1842 /// two projections carry a non-trivial closed-set-internal
1843 /// MUTEX relationship (`substrate_is_resource ⇒ ¬substrate_is_policy`
1844 /// — the eight-variant [`SubstrateType`] closed set carves its
1845 /// variants into THREE disjoint buckets sealed by
1846 /// `substrate_type_buckets_cover_every_variant`), structural
1847 /// twin of the sibling `point_type`-axis MUTEX pair sealed by
1848 /// `classification_point_is_endomorphic_and_point_is_diffusive_are_mutex_over_all`.
1849 /// Direct-scalar peer of [`Self::substrate_is_resource`] and the
1850 /// three sibling `point_type`-axis arms: all five share the
1851 /// shape (direct scalar closed-set field with no [`Default`]
1852 /// impl on the child, so no default-arm short-circuit through
1853 /// the child's `#[default]` chain). The
1854 /// [`Classification::gate_compute`] baseline's chosen field
1855 /// (`substrate: Compute`) projects `false` HERE
1856 /// (`Compute.is_policy() = false`), mirror-inverted from the
1857 /// sibling `substrate_is_resource` baseline's `true`.
1858 ///
1859 /// # Semantics — derived nullary boolean over the closed-set plane
1860 ///
1861 /// `substrate_is_policy()` returns `true` iff
1862 /// `self.substrate.is_policy()`. The eight-variant
1863 /// [`SubstrateType`] closed set publishes the truth table (via
1864 /// the plane partition):
1865 /// [`SubstrateType::Security`] / [`SubstrateType::Identity`] /
1866 /// [`SubstrateType::Regulatory`] → `true` (policy plane — you
1867 /// enforce constraints on it); [`SubstrateType::Financial`] /
1868 /// [`SubstrateType::Compute`] / [`SubstrateType::Network`] /
1869 /// [`SubstrateType::Storage`] / [`SubstrateType::Observability`]
1870 /// → `false` (resource or telemetry plane). A
1871 /// [`Classification::gate_compute`] baseline answers `false`
1872 /// because its `substrate: Compute` field is deliberately
1873 /// resource-plane, not policy-plane.
1874 ///
1875 /// A future ninth [`SubstrateType`] variant lands at ONE `ALL`
1876 /// entry + ONE `is_policy` arm on the closed set with the
1877 /// probe body untouched — the nullary-predicate shape defers
1878 /// every per-variant policy decision to the closed set's own
1879 /// truth table ([`SubstrateType::is_policy`]) rather than
1880 /// duplicating the discriminator sweep here.
1881 ///
1882 /// # Compounding — second substrate-axis peer, opens the substrate MUTEX pair
1883 ///
1884 /// The point-domain require-tag surface in
1885 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1886 /// as a fixed tag `policy-substrate` on
1887 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte structural peer of the
1888 /// sibling `resource-substrate` / `terminating-horizon` /
1889 /// `metric-axes-required` / `coordination-required` /
1890 /// `data-regulated` / `data-restricted` / `endomorphic-point` /
1891 /// `diffusive-point` / `convergent-point` fixed tags on the
1892 /// (parent × derived-nullary-bool) corner. The ephemeral surface
1893 /// publishes the same tag via
1894 /// [`crate::ephemeral::EphemeralSpec::substrate_is_policy`],
1895 /// which composes THIS method through
1896 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
1897 /// so the two-surface parity contract holds — the operator's
1898 /// `:requires (policy-substrate)` audit answers the same
1899 /// question on both surfaces. Sibling projection
1900 /// [`SubstrateType::is_telemetry`] composes byte-identically as
1901 /// a future eleventh corner occupant; when it lands the
1902 /// three-way partition contract
1903 /// `is_resource ⊕ is_policy ⊕ is_telemetry` sealed on the closed
1904 /// set by `substrate_type_buckets_cover_every_variant` composes
1905 /// through the parent-composed layer as a substrate-wide theorem
1906 /// — the exact ternary lift already sealed on the sibling
1907 /// `point_type` axis by
1908 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`.
1909 ///
1910 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
1911 /// preserves proofs; the derived-nullary-bool predicate body
1912 /// lives at ONE substrate site so every downstream (the
1913 /// `policy-substrate` fixed tag in `tatara-check`, future
1914 /// plane-baseline / compliance-baseline selectors, future
1915 /// variant additions on [`SubstrateType`]) binds through the
1916 /// SAME `substrate_is_policy()` shape rather than restating
1917 /// the `classification.substrate.is_policy()` chain at each
1918 /// callsite. THEORY.md §VI.1 — generation over composition; a
1919 /// future [`SubstrateType`] variant lands at ONE `ALL` entry +
1920 /// ONE `is_policy` arm on the closed set and this probe picks
1921 /// it up mechanically.
1922 #[must_use]
1923 pub fn substrate_is_policy(&self) -> bool {
1924 self.substrate.is_policy()
1925 }
1926
1927 /// Derived-boolean predicate — does this [`Classification`]'s
1928 /// [`SubstrateType`] project to `true` under
1929 /// [`SubstrateType::is_telemetry`]? The ONE substrate primitive
1930 /// that owns the `(Classification) -> bool` derived-nullary-
1931 /// predicate walk shape on the `substrate` slot for the
1932 /// telemetry-plane bucket question.
1933 ///
1934 /// # Eleventh occupant on the (parent × derived-nullary-bool) corner — CLOSES the substrate axis
1935 ///
1936 /// Peer of [`Self::horizon_terminates`],
1937 /// [`Self::horizon_requires_metric_axes`],
1938 /// [`Self::calm_requires_coordination`],
1939 /// [`Self::data_is_regulated`], [`Self::data_is_restricted`],
1940 /// [`Self::point_is_endomorphic`], [`Self::point_is_diffusive`],
1941 /// [`Self::point_is_convergent`], [`Self::substrate_is_resource`],
1942 /// and [`Self::substrate_is_policy`] on the workspace-wide
1943 /// (parent × derived-nullary-bool) corner of the closed-set-
1944 /// driven presence-probe algebra — the ELEVENTH occupant on the
1945 /// corner and the THIRD peer threading the classification-
1946 /// `substrate` axis. This peer CLOSES the substrate axis on the
1947 /// corner into the FULL three-way XOR partition contract
1948 /// `substrate_is_resource ⊕ substrate_is_policy ⊕
1949 /// substrate_is_telemetry` — the closed-set partition already
1950 /// sealed on [`SubstrateType`] by
1951 /// `substrate_type_buckets_cover_every_variant` now composes
1952 /// through the parent-composed layer as a substrate-wide theorem
1953 /// pinned by
1954 /// `classification_substrate_probes_form_three_way_xor_partition_over_all`.
1955 /// The ternary lift on the substrate axis is the structural
1956 /// twin of the sibling `point_type`-axis ternary lift sealed by
1957 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`.
1958 /// Direct-scalar peer of [`Self::substrate_is_resource`],
1959 /// [`Self::substrate_is_policy`], and the three sibling
1960 /// `point_type`-axis arms: all six share the shape (direct scalar
1961 /// closed-set field with no [`Default`] impl on the child, so no
1962 /// default-arm short-circuit through the child's `#[default]`
1963 /// chain). The [`Classification::gate_compute`] baseline's chosen
1964 /// field (`substrate: Compute`) projects `false` HERE
1965 /// (`Compute.is_telemetry() = false`), mirror-inverted from the
1966 /// sibling `substrate_is_resource` baseline's `true` and aligned
1967 /// with the sibling `substrate_is_policy` baseline's `false`.
1968 ///
1969 /// # Semantics — derived nullary boolean over the closed-set plane
1970 ///
1971 /// `substrate_is_telemetry()` returns `true` iff
1972 /// `self.substrate.is_telemetry()`. The eight-variant
1973 /// [`SubstrateType`] closed set publishes the truth table (via
1974 /// the plane partition): [`SubstrateType::Observability`] →
1975 /// `true` (telemetry plane — the singleton bucket that passively
1976 /// observes other workloads without carrying their payload or
1977 /// gating their access); every other variant → `false`
1978 /// (resource or policy plane). A [`Classification::gate_compute`]
1979 /// baseline answers `false` because its `substrate: Compute`
1980 /// field is deliberately resource-plane, not telemetry-plane.
1981 ///
1982 /// A future ninth [`SubstrateType`] variant lands at ONE `ALL`
1983 /// entry + ONE `is_telemetry` arm on the closed set with the
1984 /// probe body untouched — the nullary-predicate shape defers
1985 /// every per-variant telemetry decision to the closed set's own
1986 /// truth table ([`SubstrateType::is_telemetry`]) rather than
1987 /// duplicating the discriminator sweep here.
1988 ///
1989 /// # Compounding — CLOSES the substrate axis into a three-way XOR partition
1990 ///
1991 /// The point-domain require-tag surface in
1992 /// `tatara-reconciler::bin::tatara-check` composes this primitive
1993 /// as a fixed tag `telemetry-substrate` on
1994 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte structural peer of the
1995 /// sibling `resource-substrate` / `policy-substrate` /
1996 /// `terminating-horizon` / `metric-axes-required` /
1997 /// `coordination-required` / `data-regulated` / `data-restricted`
1998 /// / `endomorphic-point` / `diffusive-point` / `convergent-point`
1999 /// fixed tags on the (parent × derived-nullary-bool) corner. The
2000 /// ephemeral surface publishes the same tag via
2001 /// [`crate::ephemeral::EphemeralSpec::substrate_is_telemetry`],
2002 /// which composes THIS method through
2003 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
2004 /// so the two-surface parity contract holds — the operator's
2005 /// `:requires (telemetry-substrate)` audit answers the same
2006 /// question on both surfaces. THIRD substrate-axis peer CLOSES
2007 /// the three-way XOR partition contract
2008 /// `is_resource ⊕ is_policy ⊕ is_telemetry` sealed on the closed
2009 /// set by `substrate_type_buckets_cover_every_variant` through
2010 /// the parent-composed layer as a substrate-wide theorem — the
2011 /// exact ternary lift already sealed on the sibling `point_type`
2012 /// axis by
2013 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`.
2014 ///
2015 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2016 /// preserves proofs; the derived-nullary-bool predicate body
2017 /// lives at ONE substrate site so every downstream (the
2018 /// `telemetry-substrate` fixed tag in `tatara-check`, future
2019 /// plane-baseline / compliance-baseline selectors, future
2020 /// variant additions on [`SubstrateType`]) binds through the
2021 /// SAME `substrate_is_telemetry()` shape rather than restating
2022 /// the `classification.substrate.is_telemetry()` chain at each
2023 /// callsite. THEORY.md §VI.1 — generation over composition; a
2024 /// future [`SubstrateType`] variant lands at ONE `ALL` entry +
2025 /// ONE `is_telemetry` arm on the closed set and this probe picks
2026 /// it up mechanically.
2027 #[must_use]
2028 pub fn substrate_is_telemetry(&self) -> bool {
2029 self.substrate.is_telemetry()
2030 }
2031
2032 /// Derived-boolean predicate — does this [`Classification`]'s
2033 /// [`CalmClassification`] project to `true` under
2034 /// [`CalmClassification::is_monotone`]? The ONE substrate
2035 /// primitive that owns the `(Classification) -> bool` derived-
2036 /// nullary-predicate walk shape on the `calm` slot for the
2037 /// CALM-monotone-plane question — the positive framing peer of
2038 /// [`Self::calm_requires_coordination`].
2039 ///
2040 /// # Twelfth occupant on the (parent × derived-nullary-bool) corner — CLOSES the calm axis
2041 ///
2042 /// Peer of [`Self::horizon_terminates`],
2043 /// [`Self::horizon_requires_metric_axes`],
2044 /// [`Self::calm_requires_coordination`], [`Self::data_is_regulated`],
2045 /// [`Self::data_is_restricted`], [`Self::point_is_endomorphic`],
2046 /// [`Self::point_is_diffusive`], [`Self::point_is_convergent`],
2047 /// [`Self::substrate_is_resource`], [`Self::substrate_is_policy`],
2048 /// and [`Self::substrate_is_telemetry`] on the workspace-wide
2049 /// (parent × derived-nullary-bool) corner of the closed-set-driven
2050 /// presence-probe algebra — the TWELFTH occupant on the corner and
2051 /// the SECOND peer threading the classification-`calm` axis. This
2052 /// peer CLOSES the calm axis on the corner into the FULL binary
2053 /// XOR partition contract `calm_is_monotone ⊕
2054 /// calm_requires_coordination` — the closed-set partition sealed
2055 /// on [`CalmClassification`] by
2056 /// `calm_classification_monotone_xor_requires_coordination` now
2057 /// composes through the parent-composed layer as a substrate-wide
2058 /// theorem pinned by
2059 /// `classification_calm_probes_form_binary_xor_partition_over_all`.
2060 /// Structural twin of the sibling horizon-axis binary XOR
2061 /// partition sealed on the closed set by
2062 /// `horizon_kind_terminate_xor_requires_metric_axes` (which
2063 /// composes at the closed-set layer today — the parent-composed
2064 /// lift lands here as the calm axis's counterpart). The calm axis
2065 /// becomes the THIRD classification axis (after `point_type`,
2066 /// `substrate`) to reach the closed XOR partition landmark on
2067 /// this corner, promoting the axis-closure milestone from a
2068 /// twin (ternary on `point_type` + `substrate`) to a triple
2069 /// (adding binary on `calm`). Direct-scalar peer of
2070 /// [`Self::calm_requires_coordination`]: both walk the same
2071 /// scalar `calm` slot on the parent — TWO layers of `Default`
2072 /// short-circuit reaching the derived-nullary predicate
2073 /// ([`Classification::gate_compute`] → [`CalmClassification::default`]).
2074 /// The [`Classification::gate_compute`] baseline's default-arm
2075 /// answer projects `true` HERE (Monotone default →
2076 /// `is_monotone() = true`), mirror-inverted from
2077 /// [`Self::calm_requires_coordination`]'s Monotone-default `false`.
2078 ///
2079 /// # Semantics — derived nullary boolean over the closed-set plane
2080 ///
2081 /// `calm_is_monotone()` returns `true` iff
2082 /// `self.calm.is_monotone()`. The two-variant
2083 /// [`CalmClassification`] closed set publishes the truth table:
2084 /// [`CalmClassification::Monotone`] → `true` (CALM ⇒ can be
2085 /// distributed without coordination); [`CalmClassification::NonMonotone`]
2086 /// → `false` (CALM ⇒ requires coordination). A
2087 /// [`Classification::gate_compute`] baseline answers `true`
2088 /// because its `calm: CalmClassification::default() = Monotone`
2089 /// field defaults via [`CalmClassification`]'s `#[default]`, so
2090 /// every unadorned Process reads as gossip-eligible (safe under
2091 /// the CALM theorem: monotone operations distribute without
2092 /// coordination).
2093 ///
2094 /// A future third [`CalmClassification`] variant (a hypothetical
2095 /// `ConditionallyMonotone` sentinel for CRDT joins under a fixed
2096 /// schema) lands at ONE `ALL` entry + ONE `is_monotone` arm on
2097 /// the closed set with the probe body untouched — the nullary-
2098 /// predicate shape defers every per-variant monotonicity decision
2099 /// to the closed set's own truth table
2100 /// ([`CalmClassification::is_monotone`]) rather than duplicating
2101 /// the discriminator sweep here.
2102 ///
2103 /// # Compounding — CLOSES the calm axis into a binary XOR partition
2104 ///
2105 /// The point-domain require-tag surface in
2106 /// `tatara-reconciler::bin::tatara-check` composes this primitive
2107 /// as a fixed tag `monotone-calm` on `POINT_FIXED_TAG_ARMS` —
2108 /// byte-for-byte structural peer of the sibling
2109 /// `coordination-required` fixed tag (the antisymmetric partner
2110 /// on the same axis) and of every other `(parent × derived-
2111 /// nullary-bool)` corner arm. The ephemeral surface publishes the
2112 /// same tag via
2113 /// [`crate::ephemeral::EphemeralSpec::calm_is_monotone`], which
2114 /// composes THIS method through
2115 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
2116 /// so the two-surface parity contract holds — the operator's
2117 /// `:requires (monotone-calm)` audit answers the same question on
2118 /// both surfaces. SECOND calm-axis peer CLOSES the binary XOR
2119 /// partition contract `is_monotone ⊕ requires_coordination`
2120 /// sealed on the closed set by
2121 /// `calm_classification_monotone_xor_requires_coordination`
2122 /// through the parent-composed layer as a substrate-wide theorem
2123 /// — the exact binary lift already sealed on the sibling
2124 /// `horizon` axis at the closed-set layer by
2125 /// `horizon_kind_terminate_xor_requires_metric_axes`, now with
2126 /// the parent-composed layer's own XOR partition test on the
2127 /// calm axis.
2128 ///
2129 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2130 /// preserves proofs; the derived-nullary-bool predicate body
2131 /// lives at ONE substrate site so every downstream (the
2132 /// `monotone-calm` fixed tag in `tatara-check`, future scheduler
2133 /// / coordination-mode validators reading the positive CALM
2134 /// framing, future variant additions on [`CalmClassification`])
2135 /// binds through the SAME `calm_is_monotone()` shape rather than
2136 /// restating either `!self.calm_requires_coordination()` or
2137 /// `self.calm.is_monotone()` at the callsite. THEORY.md §VI.1 —
2138 /// generation over composition; a future [`CalmClassification`]
2139 /// variant lands at ONE `ALL` entry + ONE `is_monotone` arm on
2140 /// the closed set and this probe picks it up mechanically.
2141 #[must_use]
2142 pub fn calm_is_monotone(&self) -> bool {
2143 self.calm.is_monotone()
2144 }
2145
2146 /// Derived-boolean predicate — does this [`Classification`]'s
2147 /// [`DataClassification`] project to `true` under
2148 /// [`DataClassification::is_public`]? The ONE substrate primitive
2149 /// that owns the `(Classification) -> bool` derived-nullary-
2150 /// predicate walk shape on the `data_classification` slot for the
2151 /// freely-distributable-data question — the positive framing peer
2152 /// of [`Self::data_is_restricted`].
2153 ///
2154 /// # Thirteenth occupant on the (parent × derived-nullary-bool) corner — CLOSES the data axis
2155 ///
2156 /// Peer of [`Self::horizon_terminates`],
2157 /// [`Self::horizon_requires_metric_axes`],
2158 /// [`Self::calm_requires_coordination`], [`Self::data_is_regulated`],
2159 /// [`Self::data_is_restricted`], [`Self::point_is_endomorphic`],
2160 /// [`Self::point_is_diffusive`], [`Self::point_is_convergent`],
2161 /// [`Self::substrate_is_resource`], [`Self::substrate_is_policy`],
2162 /// [`Self::substrate_is_telemetry`], and [`Self::calm_is_monotone`]
2163 /// on the workspace-wide (parent × derived-nullary-bool) corner of
2164 /// the closed-set-driven presence-probe algebra — the THIRTEENTH
2165 /// occupant on the corner and the THIRD peer threading the
2166 /// classification-`data_classification` axis. This peer CLOSES
2167 /// the data axis on the corner into the FULL binary XOR partition
2168 /// contract `data_is_public ⊕ data_is_restricted` — the closed-set
2169 /// partition sealed on [`DataClassification`] by
2170 /// `data_classification_public_xor_restricted` now composes
2171 /// through the parent-composed layer as a substrate-wide theorem
2172 /// pinned by
2173 /// `classification_data_probes_form_binary_xor_partition_over_all`.
2174 /// Structural twin of the calm-axis binary XOR partition sealed at
2175 /// the parent-composed layer by
2176 /// `classification_calm_probes_form_binary_xor_partition_over_all`
2177 /// on the sibling `calm` axis — both axes carve into a `is_X /
2178 /// requires_X` (positive/negative-framing) complementary bucket
2179 /// pair whose union covers every closed-set variant. The data axis
2180 /// becomes the FOURTH classification axis (after `point_type`,
2181 /// `substrate`, `calm`) to reach the closed XOR partition landmark
2182 /// on this corner, promoting the axis-closure milestone from a
2183 /// proven-repeatable triple (ternary on `point_type` + `substrate`
2184 /// plus binary on `calm`) to a proven-repeatable quadruple (adding
2185 /// a SECOND binary on `data_classification`). Direct-scalar peer
2186 /// of [`Self::data_is_regulated`] and [`Self::data_is_restricted`]:
2187 /// all three walk the same scalar `data_classification` slot on the
2188 /// parent — TWO layers of `Default` short-circuit reaching the
2189 /// derived-nullary predicate ([`Classification::gate_compute`] →
2190 /// [`DataClassification::default`]). The
2191 /// [`Classification::gate_compute`] baseline's default-arm answer
2192 /// projects `false` HERE (Internal default →
2193 /// `is_public() = false`), mirror-inverted from
2194 /// [`Self::data_is_restricted`]'s Internal-default `true` on the
2195 /// SAME defaulted `data_classification` slot.
2196 ///
2197 /// # Semantics — derived nullary boolean over the closed-set plane
2198 ///
2199 /// `data_is_public()` returns `true` iff
2200 /// `self.data_classification.is_public()`. The six-variant
2201 /// [`DataClassification`] closed set publishes the truth table:
2202 /// [`DataClassification::Public`] → `true` (freely distributable —
2203 /// no access control required); [`DataClassification::Internal`] /
2204 /// [`DataClassification::Confidential`] / [`DataClassification::Pii`]
2205 /// / [`DataClassification::Phi`] / [`DataClassification::Pci`] →
2206 /// `false` (some access-control regime applies). A
2207 /// [`Classification::gate_compute`] baseline answers `false`
2208 /// because its `data_classification:
2209 /// DataClassification::default() = Internal` field defaults via
2210 /// [`DataClassification`]'s `#[default]`, so every unadorned
2211 /// Process reads as access-controlled (safe under the compliance
2212 /// baseline: an operator must deliberately opt into public
2213 /// distribution).
2214 ///
2215 /// The closed-set-internal pin
2216 /// `data_classification_regulated_implies_not_public` seals the
2217 /// implication `is_regulated() ⇒ ¬is_public()` on every variant, so
2218 /// [`Self::data_is_regulated`] returning `true` implies THIS
2219 /// predicate returns `false`; this is the ANTISYMMETRIC pair to
2220 /// the sibling `data_classification_regulated_implies_restricted`
2221 /// on the same closed set, and the FIRST substrate-primitive pair
2222 /// on the (parent × derived-nullary-bool) corner whose two
2223 /// predicates project ONE closed set into the pair of
2224 /// complementary buckets whose union is a full binary XOR
2225 /// partition AND whose intersection is empty on every variant.
2226 ///
2227 /// A future seventh [`DataClassification`] variant (a hypothetical
2228 /// `TradeSecret` bucket for competitive-sensitive data, or an
2229 /// `Anonymized` bucket for pseudonymized-PII whose regulatory
2230 /// posture differs from raw PII) reaches this probe through ONE
2231 /// `is_public` arm on the closed set with the probe body untouched
2232 /// — the nullary-predicate shape defers every per-variant policy
2233 /// decision to the closed set's own truth table
2234 /// ([`DataClassification::is_public`]) rather than duplicating the
2235 /// discriminator sweep here.
2236 ///
2237 /// # Compounding — CLOSES the data axis into a binary XOR partition
2238 ///
2239 /// The point-domain require-tag surface in
2240 /// `tatara-reconciler::bin::tatara-check` composes this primitive
2241 /// as a fixed tag `public-data` on `POINT_FIXED_TAG_ARMS` —
2242 /// byte-for-byte structural peer of the sibling `data-restricted`
2243 /// fixed tag (the antisymmetric partner on the same axis) and of
2244 /// every other `(parent × derived-nullary-bool)` corner arm. The
2245 /// ephemeral surface publishes the same tag via
2246 /// [`crate::ephemeral::EphemeralSpec::data_is_public`], which
2247 /// composes THIS method through
2248 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
2249 /// so the two-surface parity contract holds — the operator's
2250 /// `:requires (public-data)` audit answers the same question on
2251 /// both surfaces. THIRD data-axis peer CLOSES the binary XOR
2252 /// partition contract `is_public ⊕ is_restricted` sealed on the
2253 /// closed set by `data_classification_public_xor_restricted`
2254 /// through the parent-composed layer as a substrate-wide theorem
2255 /// — mirror of the calm axis's parent-composed binary XOR closure
2256 /// `classification_calm_probes_form_binary_xor_partition_over_all`.
2257 ///
2258 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2259 /// preserves proofs; the derived-nullary-bool predicate body
2260 /// lives at ONE substrate site so every downstream (the
2261 /// `public-data` fixed tag in `tatara-check`, future compliance-
2262 /// baseline / audit-log-optional validators reading the positive
2263 /// distribution framing, future variant additions on
2264 /// [`DataClassification`]) binds through the SAME
2265 /// `data_is_public()` shape rather than restating either
2266 /// `!self.data_is_restricted()` or `self.data_classification.is_public()`
2267 /// at the callsite. THEORY.md §VI.1 — generation over composition;
2268 /// a future [`DataClassification`] variant lands at ONE `ALL`
2269 /// entry + ONE `is_public` arm on the closed set and this probe
2270 /// picks it up mechanically.
2271 #[must_use]
2272 pub fn data_is_public(&self) -> bool {
2273 self.data_classification.is_public()
2274 }
2275
2276 /// Derived-boolean predicate — does this [`Classification`]'s
2277 /// [`Horizon::direction`] slot (defaulted through
2278 /// [`OptimizationDirection::default = Minimize`] on absence) project
2279 /// to `true` under [`OptimizationDirection::prefers_lower`]? The ONE
2280 /// substrate primitive that owns the `(Classification) -> bool`
2281 /// derived-nullary-predicate walk on the `horizon.direction` slot
2282 /// for the lower-is-better optimization-polarity question.
2283 ///
2284 /// # Fourteenth occupant on the (parent × derived-nullary-bool) corner — first via the optimization-direction axis
2285 ///
2286 /// Peer of the thirteen prior nullary-bool substrate primitives on
2287 /// [`Classification`] ([`Self::horizon_terminates`],
2288 /// [`Self::horizon_requires_metric_axes`],
2289 /// [`Self::calm_requires_coordination`], [`Self::data_is_regulated`],
2290 /// [`Self::data_is_restricted`], [`Self::point_is_endomorphic`],
2291 /// [`Self::point_is_diffusive`], [`Self::point_is_convergent`],
2292 /// [`Self::substrate_is_resource`], [`Self::substrate_is_policy`],
2293 /// [`Self::substrate_is_telemetry`], [`Self::calm_is_monotone`],
2294 /// [`Self::data_is_public`]) on the workspace-wide (parent ×
2295 /// derived-nullary-bool) corner of the closed-set-driven presence-
2296 /// probe algebra. FIRST occupant threading the classification-
2297 /// `horizon.direction` axis — opens the SIXTH classification axis
2298 /// into the fixed-tag algebra after the horizon, calm, data, point,
2299 /// and substrate axes; distinct from every prior corner peer on ONE
2300 /// structural degree: the source carrier is `Option<OptimizationDirection>`
2301 /// nested inside the [`Horizon`] struct rather than a direct scalar
2302 /// or a nested direct-scalar. Byte-for-byte peer of the sibling
2303 /// [`Self::has_optimization_direction`] on the Option-carrier hop
2304 /// (both unwrap the [`Horizon::direction`] slot through
2305 /// [`Option::unwrap_or_default`] against the closed-set-level
2306 /// [`OptimizationDirection::default = Minimize`]); this method is
2307 /// the derived-nullary-bool projection over the same defaulted
2308 /// scalar, mirroring the (has-variant, is-projection) pair on the
2309 /// sibling `point_type` axis.
2310 ///
2311 /// # Semantics — derived nullary boolean, defaulted through Option
2312 ///
2313 /// `direction_prefers_lower()` returns `true` iff
2314 /// `self.horizon.direction.unwrap_or_default().prefers_lower()`. The
2315 /// two-variant [`OptimizationDirection`] closed set publishes the
2316 /// truth table: [`OptimizationDirection::Minimize`] → `true` (cost /
2317 /// latency / error rate — lower is better);
2318 /// [`OptimizationDirection::Maximize`] → `false` (throughput /
2319 /// coverage / revenue — higher is better). A
2320 /// [`Classification::gate_compute`] baseline (which carries
2321 /// `horizon: Horizon::default()` whose `direction` field is `None`)
2322 /// answers `true` deliberately — an unadorned Process's polarity
2323 /// reads as lower-is-better, matching the substrate
2324 /// [`OptimizationDirection::default = Minimize`] chosen precisely so
2325 /// an under-specified `Asymptotic` horizon can't silently flip the
2326 /// rate-window evaluator's polarity onto the Maximize path (a
2327 /// future `Maximize`-default-via-rename would silently invert every
2328 /// existing alert that treats decreasing rate as healthy).
2329 ///
2330 /// A future third [`OptimizationDirection`] variant (a hypothetical
2331 /// `Stabilize` sentinel for "drive toward a target value", which
2332 /// neither minimization nor maximization names) reaches this probe
2333 /// through ONE `prefers_lower` arm on the closed set with the probe
2334 /// body untouched — the nullary-predicate shape defers every
2335 /// per-variant policy decision to the closed set's own truth table
2336 /// ([`OptimizationDirection::prefers_lower`]) rather than
2337 /// duplicating the discriminator sweep here.
2338 ///
2339 /// # Compounding — opens the optimization-direction axis on the corner
2340 ///
2341 /// The point-domain require-tag surface in
2342 /// `tatara-reconciler::bin::tatara-check` composes this primitive
2343 /// as a fixed tag `prefers-lower-direction` on `POINT_FIXED_TAG_ARMS`
2344 /// — the SIXTH classification axis to reach the fixed-tag corner.
2345 /// The ephemeral surface publishes the same tag via
2346 /// [`crate::ephemeral::EphemeralSpec::direction_prefers_lower`],
2347 /// which composes THIS method through
2348 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`] so
2349 /// the two-surface parity contract holds — the operator's
2350 /// `:requires (prefers-lower-direction)` audit answers the same
2351 /// question on both surfaces. A future antisymmetric peer
2352 /// (`direction_prefers_higher` reading
2353 /// `!self.horizon.direction.unwrap_or_default().prefers_lower()`,
2354 /// or a projection through a peer `OptimizationDirection::prefers_higher`
2355 /// closed-set arm) closes the binary XOR partition on this axis —
2356 /// mirror of the calm-axis (`monotone-calm ⊕ coordination-required`)
2357 /// and data-axis (`public-data ⊕ data-restricted`) closures — as
2358 /// the SECOND occupant on the axis.
2359 ///
2360 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2361 /// preserves proofs; the derived-nullary-bool predicate body lives
2362 /// at ONE substrate site so every downstream (the
2363 /// `prefers-lower-direction` fixed tag in `tatara-check`, future
2364 /// asymptotic-health rate-window / regression-detector evaluators
2365 /// keying on the optimization-polarity, future variant additions on
2366 /// [`OptimizationDirection`]) binds through the SAME
2367 /// `direction_prefers_lower()` shape rather than restating the
2368 /// `classification.horizon.direction.unwrap_or_default().prefers_lower()`
2369 /// chain at each callsite. THEORY.md §VI.1 — generation over
2370 /// composition; a future [`OptimizationDirection`] variant lands at
2371 /// ONE `ALL` entry + ONE `prefers_lower` arm on the closed set and
2372 /// this probe picks it up mechanically.
2373 #[must_use]
2374 pub fn direction_prefers_lower(&self) -> bool {
2375 self.horizon.direction.unwrap_or_default().prefers_lower()
2376 }
2377
2378 /// POSITIVE-FRAMING PEER of [`Self::direction_prefers_lower`] —
2379 /// does this [`Classification`]'s [`Horizon::direction`] slot
2380 /// (defaulted through [`OptimizationDirection::default = Minimize`]
2381 /// on absence) project to `true` under
2382 /// [`OptimizationDirection::prefers_higher`]? The ONE substrate
2383 /// primitive that owns the `(Classification) -> bool` derived-
2384 /// nullary-predicate walk on the `horizon.direction` slot for the
2385 /// higher-is-better optimization-polarity question.
2386 ///
2387 /// # Fifteenth occupant on the (parent × derived-nullary-bool) corner — CLOSES the optimization-direction axis
2388 ///
2389 /// Peer of the fourteen prior nullary-bool substrate primitives on
2390 /// [`Classification`] ([`Self::horizon_terminates`],
2391 /// [`Self::horizon_requires_metric_axes`],
2392 /// [`Self::calm_requires_coordination`], [`Self::data_is_regulated`],
2393 /// [`Self::data_is_restricted`], [`Self::point_is_endomorphic`],
2394 /// [`Self::point_is_diffusive`], [`Self::point_is_convergent`],
2395 /// [`Self::substrate_is_resource`], [`Self::substrate_is_policy`],
2396 /// [`Self::substrate_is_telemetry`], [`Self::calm_is_monotone`],
2397 /// [`Self::data_is_public`], [`Self::direction_prefers_lower`]) on
2398 /// the workspace-wide (parent × derived-nullary-bool) corner of
2399 /// the closed-set-driven presence-probe algebra. FIFTEENTH
2400 /// occupant on the corner and SECOND peer threading the
2401 /// classification-`horizon.direction` axis — CLOSES the axis into
2402 /// the FULL binary XOR partition contract `direction_prefers_lower
2403 /// ⊕ direction_prefers_higher` sealed on the closed set by
2404 /// `optimization_direction_prefers_lower_xor_prefers_higher` and
2405 /// composed through the parent-composed layer by
2406 /// `classification_direction_probes_form_binary_xor_partition_over_all`.
2407 /// ALL SIX classification axes (horizon, calm, data, point,
2408 /// substrate, optimization-direction) now have their partitions
2409 /// closed at the corner — the fixed-tag algebra reaches full
2410 /// axis-coverage on the classification lattice.
2411 ///
2412 /// Direct byte-for-byte structural peer of
2413 /// [`Self::direction_prefers_lower`]: both walk the SAME
2414 /// [`Horizon::direction`] slot through TWO layers of `Default`
2415 /// (`Horizon::default` → `direction: None`; then
2416 /// [`OptimizationDirection::default = Minimize`]) to reach the
2417 /// closed-set-level projection. The [`Classification::gate_compute`]
2418 /// baseline's default-arm answer projects `false` HERE (Minimize
2419 /// default → `prefers_higher() = false`), mirror-inverted from
2420 /// [`Self::direction_prefers_lower`]'s Minimize-default `true` on
2421 /// the SAME defaulted `horizon.direction` slot — the antisymmetric
2422 /// twin on the substrate polarity default.
2423 ///
2424 /// # Semantics — derived nullary boolean over the closed-set plane
2425 ///
2426 /// `direction_prefers_higher()` returns `true` iff
2427 /// `self.horizon.direction.unwrap_or_default().prefers_higher()`.
2428 /// The two-variant [`OptimizationDirection`] closed set publishes
2429 /// the truth table: [`OptimizationDirection::Minimize`] → `false`
2430 /// (cost / latency / error rate — decreasing values improve);
2431 /// [`OptimizationDirection::Maximize`] → `true` (throughput /
2432 /// coverage / revenue — increasing values improve). A
2433 /// [`Classification::gate_compute`] baseline (which carries
2434 /// `horizon: Horizon::default()` whose `direction` field is `None`)
2435 /// answers `false` because [`OptimizationDirection::default =
2436 /// Minimize`] projects `prefers_higher = false`, so every
2437 /// unadorned Process reads under the lower-is-better polarity —
2438 /// matching the substrate polarity default (safe under the
2439 /// asymptotic-health rate-window evaluator's convention: an
2440 /// operator must deliberately opt into Maximize polarity rather
2441 /// than the substrate silently flipping every unadorned Process
2442 /// onto the higher-is-better path).
2443 ///
2444 /// A future third [`OptimizationDirection`] variant (a hypothetical
2445 /// `Stabilize` sentinel for "drive toward a target value", which
2446 /// neither minimization nor maximization names) reaches this probe
2447 /// through ONE `prefers_higher` arm on the closed set with the
2448 /// probe body untouched — the nullary-predicate shape defers every
2449 /// per-variant policy decision to the closed set's own truth table
2450 /// ([`OptimizationDirection::prefers_higher`]) rather than
2451 /// duplicating the discriminator sweep here. The XOR pin on the
2452 /// closed set forces such a variant to answer `false` on BOTH
2453 /// `prefers_lower` AND `prefers_higher` unless a deliberate
2454 /// extension carves the closed set into a ternary partition.
2455 ///
2456 /// # Compounding — CLOSES the optimization-direction axis into a binary XOR partition
2457 ///
2458 /// The point-domain require-tag surface in
2459 /// `tatara-reconciler::bin::tatara-check` composes this primitive
2460 /// as a fixed tag `prefers-higher-direction` on `POINT_FIXED_TAG_ARMS`
2461 /// — byte-for-byte structural peer of the sibling
2462 /// `prefers-lower-direction` fixed tag (the antisymmetric partner
2463 /// on the same axis) and of every other `(parent × derived-
2464 /// nullary-bool)` corner arm. The ephemeral surface publishes the
2465 /// same tag via
2466 /// [`crate::ephemeral::EphemeralSpec::direction_prefers_higher`],
2467 /// which composes THIS method through
2468 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`] so
2469 /// the two-surface parity contract holds — the operator's
2470 /// `:requires (prefers-higher-direction)` audit answers the same
2471 /// question on both surfaces. SECOND optimization-direction-axis
2472 /// peer CLOSES the binary XOR partition contract
2473 /// `direction_prefers_lower ⊕ direction_prefers_higher` sealed on
2474 /// the closed set by
2475 /// `optimization_direction_prefers_lower_xor_prefers_higher`
2476 /// through the parent-composed layer as a substrate-wide theorem
2477 /// — mirror of the calm-axis (`monotone-calm ⊕ coordination-required`)
2478 /// and data-axis (`public-data ⊕ data-restricted`) closures
2479 /// already landed on the corner, and the SIXTH (and final)
2480 /// classification axis to reach the closed XOR partition landmark
2481 /// at this corner.
2482 ///
2483 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2484 /// preserves proofs; the derived-nullary-bool predicate body
2485 /// lives at ONE substrate site so every downstream (the
2486 /// `prefers-higher-direction` fixed tag in `tatara-check`, future
2487 /// asymptotic-health rate-window / regression-detector evaluators
2488 /// keying on the positive higher-is-better polarity framing,
2489 /// future variant additions on [`OptimizationDirection`]) binds
2490 /// through the SAME `direction_prefers_higher()` shape rather
2491 /// than restating either `!self.direction_prefers_lower()` or
2492 /// `self.horizon.direction.unwrap_or_default().prefers_higher()`
2493 /// at the callsite. THEORY.md §VI.1 — generation over composition;
2494 /// a future [`OptimizationDirection`] variant lands at ONE `ALL`
2495 /// entry + ONE `prefers_higher` arm on the closed set and this
2496 /// probe picks it up mechanically.
2497 #[must_use]
2498 pub fn direction_prefers_higher(&self) -> bool {
2499 self.horizon.direction.unwrap_or_default().prefers_higher()
2500 }
2501
2502 /// Derived-boolean predicate — does this [`Classification`]'s
2503 /// `point_type` slot project to `Arity::One` under
2504 /// [`ConvergencePointType::input_arity`]? The ONE substrate
2505 /// primitive that owns the `(Classification) -> bool` derived-
2506 /// nullary-predicate walk on the DAG-composition input-arity
2507 /// projection.
2508 ///
2509 /// # First derived-nullary-bool corner occupant on the input-arity axis
2510 ///
2511 /// Peer of the fifteen prior nullary-bool substrate primitives on
2512 /// [`Classification`] ([`Self::horizon_terminates`],
2513 /// [`Self::horizon_requires_metric_axes`],
2514 /// [`Self::calm_requires_coordination`], [`Self::data_is_regulated`],
2515 /// [`Self::data_is_restricted`], [`Self::point_is_endomorphic`],
2516 /// [`Self::point_is_diffusive`], [`Self::point_is_convergent`],
2517 /// [`Self::substrate_is_resource`], [`Self::substrate_is_policy`],
2518 /// [`Self::substrate_is_telemetry`], [`Self::calm_is_monotone`],
2519 /// [`Self::data_is_public`], [`Self::direction_prefers_lower`],
2520 /// [`Self::direction_prefers_higher`]) on the workspace-wide
2521 /// (parent × derived-nullary-bool) corner of the closed-set-driven
2522 /// presence-probe algebra. SIXTEENTH occupant on the corner and
2523 /// FIRST occupant threading the classification-`point_type`-
2524 /// derived input-arity axis — opens the SEVENTH classification
2525 /// axis into the fixed-tag algebra after the six axes (horizon,
2526 /// calm, data, point-type, substrate, optimization-direction)
2527 /// already closed at the corner. The input-arity axis is a
2528 /// derived typed projection through
2529 /// [`ConvergencePointType::input_arity`] rather than a stored
2530 /// classification slot — so this predicate composes an extra
2531 /// closed-set-level projection hop compared to the sibling
2532 /// `point_is_*` triple that walks the raw `point_type` slot.
2533 ///
2534 /// # Semantics — derived nullary boolean over the input-arity projection
2535 ///
2536 /// `input_arity_is_one()` returns `true` iff
2537 /// `self.point_type.input_arity().is_one()`. The eight-variant
2538 /// [`ConvergencePointType`] closed set publishes the truth table
2539 /// through [`ConvergencePointType::input_arity`]: `Transform |
2540 /// Fork | Broadcast | Observe → One → true`; `Join | Gate |
2541 /// Select | Reduce → Many → false`. A
2542 /// [`Classification::gate_compute`] baseline (which carries
2543 /// `point_type: Gate`) answers `false` — `Gate.input_arity() =
2544 /// Many`, so the multi-input bucket carves the workspace-wide
2545 /// baseline into the multi-input cell.
2546 ///
2547 /// A future [`ConvergencePointType`] variant (a hypothetical
2548 /// `Demux` for `One → Many` or `Mux` for `Many → One`) reaches
2549 /// this probe through ONE `input_arity` arm on
2550 /// [`ConvergencePointType`] with the probe body untouched — the
2551 /// many-to-one projection means the bucket membership shift lands
2552 /// exactly at [`ConvergencePointType::input_arity`], not at every
2553 /// consumer that previously restated the bucket in code.
2554 ///
2555 /// # Compounding — opens the input-arity axis at the parent-composed corner
2556 ///
2557 /// The point-domain require-tag surface in
2558 /// `tatara-reconciler::bin::tatara-check` composes this primitive
2559 /// as a fixed tag `single-input-arity` on `POINT_FIXED_TAG_ARMS`
2560 /// — byte-for-byte structural peer of every other `(parent ×
2561 /// derived-nullary-bool)` corner arm. The antisymmetric partner
2562 /// [`Self::input_arity_is_many`] closes the input-arity axis into
2563 /// the FULL binary XOR partition contract sealed on the closed
2564 /// set by `arity_is_one_xor_is_many_over_all` — mirror of the
2565 /// binary XOR closures on the calm axis (`monotone-calm ⊕
2566 /// coordination-required`), the data axis (`public-data ⊕
2567 /// data-restricted`), and the optimization-direction axis
2568 /// (`prefers-lower-direction ⊕ prefers-higher-direction`). A
2569 /// future ephemeral-surface peer
2570 /// (`EphemeralSpec::input_arity_is_one`) will compose THIS method
2571 /// through [`crate::ephemeral::EphemeralSpec::resolved_classification`]
2572 /// so the two-surface parity contract holds — the operator's
2573 /// `:requires (single-input-arity)` audit answers the same
2574 /// question on both surfaces.
2575 ///
2576 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2577 /// preserves proofs; the derived-nullary-bool predicate body
2578 /// lives at ONE substrate site so every downstream (the future
2579 /// `single-input-arity` fixed tag in `tatara-check`, DAG
2580 /// composition validators keying on the single-input framing,
2581 /// future variant additions on [`ConvergencePointType`]) binds
2582 /// through the SAME `input_arity_is_one()` shape rather than
2583 /// restating the two-hop `self.point_type.input_arity().is_one()`
2584 /// chain at each callsite. THEORY.md §VI.1 — generation over
2585 /// composition; a future [`ConvergencePointType`] variant lands
2586 /// at ONE `ALL` entry + ONE `input_arity` arm on the closed set
2587 /// and this probe picks it up mechanically.
2588 #[must_use]
2589 pub fn input_arity_is_one(&self) -> bool {
2590 self.point_type.input_arity().is_one()
2591 }
2592
2593 /// ANTISYMMETRIC PEER of [`Self::input_arity_is_one`] — does
2594 /// this [`Classification`]'s `point_type` slot project to
2595 /// `Arity::Many` under [`ConvergencePointType::input_arity`]?
2596 /// The ONE substrate primitive that owns the `(Classification) ->
2597 /// bool` derived-nullary-predicate walk on the multi-input side
2598 /// of the DAG-composition input-arity projection.
2599 ///
2600 /// # Seventeenth corner occupant — CLOSES the input-arity axis into a binary XOR partition
2601 ///
2602 /// SEVENTEENTH occupant on the (parent × derived-nullary-bool)
2603 /// corner of the workspace-wide closed-set-driven presence-probe
2604 /// algebra and SECOND peer threading the classification-
2605 /// `point_type`-derived input-arity axis — CLOSES the SEVENTH
2606 /// classification axis into the FULL binary XOR partition
2607 /// contract `input_arity_is_one ⊕ input_arity_is_many` sealed on
2608 /// the closed set by `arity_is_one_xor_is_many_over_all` and
2609 /// composed through the parent-composed layer by
2610 /// `classification_input_arity_probes_form_binary_xor_partition_over_all`.
2611 /// Structural mirror of the calm-axis binary XOR partition
2612 /// (`monotone-calm ⊕ coordination-required`), the data-axis
2613 /// binary XOR partition (`public-data ⊕ data-restricted`), and
2614 /// the optimization-direction-axis binary XOR partition
2615 /// (`prefers-lower-direction ⊕ prefers-higher-direction`) — the
2616 /// FOURTH parent-composed binary XOR partition on the corner.
2617 ///
2618 /// # Semantics — derived nullary boolean over the multi-input projection
2619 ///
2620 /// `input_arity_is_many()` returns `true` iff
2621 /// `self.point_type.input_arity().is_many()`. The eight-variant
2622 /// [`ConvergencePointType`] closed set publishes the truth table
2623 /// through [`ConvergencePointType::input_arity`]: `Transform |
2624 /// Fork | Broadcast | Observe → One → false`; `Join | Gate |
2625 /// Select | Reduce → Many → true`. A
2626 /// [`Classification::gate_compute`] baseline (which carries
2627 /// `point_type: Gate`) answers `true` — `Gate.input_arity() =
2628 /// Many`, so the multi-input bucket carves the workspace-wide
2629 /// baseline. Direct antisymmetric mirror of
2630 /// [`Self::input_arity_is_one`] on the SAME projection through
2631 /// the SAME closed set.
2632 ///
2633 /// # Compounding — CLOSES the input-arity axis into a binary XOR partition
2634 ///
2635 /// The point-domain require-tag surface will compose this
2636 /// primitive as a fixed tag `multi-input-arity` on
2637 /// `POINT_FIXED_TAG_ARMS` — antisymmetric peer of the sibling
2638 /// `single-input-arity` fixed tag. Together with the sibling
2639 /// [`Self::input_arity_is_one`] the two predicates seal the
2640 /// input-arity axis into a binary XOR partition on the parent-
2641 /// composed layer as a substrate-wide theorem, closing the
2642 /// axis at the SEVENTH-classification-axis landmark.
2643 ///
2644 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2645 /// preserves proofs; the derived-nullary-bool predicate body
2646 /// lives at ONE substrate site so every downstream (the future
2647 /// `multi-input-arity` fixed tag, DAG composition validators
2648 /// keying on multi-input fan-in semantics, future variant
2649 /// additions on [`ConvergencePointType`]) binds through the SAME
2650 /// `input_arity_is_many()` shape rather than restating either
2651 /// `!self.input_arity_is_one()` or
2652 /// `self.point_type.input_arity().is_many()` at each callsite.
2653 /// THEORY.md §VI.1 — generation over composition; a future
2654 /// [`ConvergencePointType`] variant lands at ONE `ALL` entry +
2655 /// ONE `input_arity` arm on the closed set and this probe picks
2656 /// it up mechanically.
2657 #[must_use]
2658 pub fn input_arity_is_many(&self) -> bool {
2659 self.point_type.input_arity().is_many()
2660 }
2661
2662 /// Derived-boolean predicate — does this [`Classification`]'s
2663 /// `point_type` slot project to `Arity::One` under
2664 /// [`ConvergencePointType::output_arity`]? The ONE substrate
2665 /// primitive that owns the `(Classification) -> bool` derived-
2666 /// nullary-predicate walk on the DAG-composition OUTPUT-arity
2667 /// projection — antisymmetric partner (on the DAG-composition
2668 /// arity PAIR) of the sibling [`Self::input_arity_is_one`] that
2669 /// walks the SAME `point_type` slot through the SAME `Arity`
2670 /// closed set but composes a DIFFERENT typed projection
2671 /// ([`ConvergencePointType::output_arity`] rather than
2672 /// [`ConvergencePointType::input_arity`]).
2673 ///
2674 /// # Eighteenth (parent × derived-nullary-bool) corner occupant — opens the EIGHTH classification axis
2675 ///
2676 /// Peer of the seventeen prior nullary-bool substrate primitives
2677 /// on [`Classification`] ([`Self::horizon_terminates`],
2678 /// [`Self::horizon_requires_metric_axes`],
2679 /// [`Self::calm_requires_coordination`], [`Self::data_is_regulated`],
2680 /// [`Self::data_is_restricted`], [`Self::point_is_endomorphic`],
2681 /// [`Self::point_is_diffusive`], [`Self::point_is_convergent`],
2682 /// [`Self::substrate_is_resource`], [`Self::substrate_is_policy`],
2683 /// [`Self::substrate_is_telemetry`], [`Self::calm_is_monotone`],
2684 /// [`Self::data_is_public`], [`Self::direction_prefers_lower`],
2685 /// [`Self::direction_prefers_higher`],
2686 /// [`Self::input_arity_is_one`], [`Self::input_arity_is_many`]) on
2687 /// the workspace-wide (parent × derived-nullary-bool) corner of
2688 /// the closed-set-driven presence-probe algebra. EIGHTEENTH
2689 /// occupant on the corner and FIRST occupant threading the
2690 /// classification-`point_type`-derived output-arity axis — opens
2691 /// the EIGHTH classification axis into the fixed-tag algebra
2692 /// after the seven axes (horizon, calm, data, point-type,
2693 /// substrate, optimization-direction, input-arity) already opened
2694 /// at the corner. The output-arity axis is the SECOND derived
2695 /// typed projection ([`ConvergencePointType::output_arity`],
2696 /// after the input-arity axis's [`ConvergencePointType::input_arity`])
2697 /// rather than a stored classification slot — so this predicate
2698 /// composes an extra closed-set-level projection hop compared to
2699 /// the sibling `point_is_*` triple that walks the raw `point_type`
2700 /// slot.
2701 ///
2702 /// # Distinctness from the input-arity axis
2703 ///
2704 /// The input-arity and output-arity axes carve the eight-variant
2705 /// [`ConvergencePointType`] closed set into DISTINCT partitions —
2706 /// six of the eight variants (`Fork | Broadcast | Join | Gate |
2707 /// Select | Reduce`) DISAGREE between the two projections, and
2708 /// only the two endomorphic variants (`Transform | Observe` —
2709 /// both `(One, One)`) agree. So `output_arity_is_one` is NOT a
2710 /// redundant restatement of `input_arity_is_one`; the two together
2711 /// name the `(input_arity, output_arity)` typed pair contract
2712 /// canonically already carried on [`ConvergencePointType`] by the
2713 /// `is_endomorphic | is_diffusive | is_convergent` triple — but
2714 /// as SEPARATE nullary predicates on the parent-composed layer
2715 /// rather than as a bucket dispatcher.
2716 ///
2717 /// # Semantics — derived nullary boolean over the output-arity projection
2718 ///
2719 /// `output_arity_is_one()` returns `true` iff
2720 /// `self.point_type.output_arity().is_one()`. The eight-variant
2721 /// [`ConvergencePointType`] closed set publishes the truth table
2722 /// through [`ConvergencePointType::output_arity`]: `Transform |
2723 /// Join | Gate | Select | Reduce | Observe → One → true`; `Fork |
2724 /// Broadcast → Many → false`. A [`Classification::gate_compute`]
2725 /// baseline (which carries `point_type: Gate`) answers `true` —
2726 /// `Gate.output_arity() = One`, so the single-output bucket
2727 /// carves the workspace-wide baseline into the single-output
2728 /// cell. Note the workspace-baseline answer FLIPS between the
2729 /// input-arity and output-arity axes on the exact same baseline:
2730 /// `input_arity_is_one` is `false` on `gate_compute`, but
2731 /// `output_arity_is_one` is `true` — direct evidence that the two
2732 /// axes carve the closed set into structurally different
2733 /// partitions.
2734 ///
2735 /// A future [`ConvergencePointType`] variant (a hypothetical
2736 /// `Demux` for `One → Many` or `Mux` for `Many → One`) reaches
2737 /// this probe through ONE `output_arity` arm on
2738 /// [`ConvergencePointType`] with the probe body untouched — the
2739 /// many-to-one projection means the bucket membership shift lands
2740 /// exactly at [`ConvergencePointType::output_arity`], not at
2741 /// every consumer that previously restated the bucket in code.
2742 ///
2743 /// # Compounding — opens the output-arity axis at the parent-composed corner
2744 ///
2745 /// The point-domain require-tag surface in
2746 /// `tatara-reconciler::bin::tatara-check` will compose this
2747 /// primitive as a fixed tag `single-output-arity` on
2748 /// `POINT_FIXED_TAG_ARMS` — byte-for-byte structural peer of
2749 /// every other `(parent × derived-nullary-bool)` corner arm. The
2750 /// antisymmetric partner [`Self::output_arity_is_many`] closes
2751 /// the output-arity axis into the FULL binary XOR partition
2752 /// contract sealed on the closed set by
2753 /// `arity_is_one_xor_is_many_over_all` — mirror of the binary
2754 /// XOR closures on the calm axis (`monotone-calm ⊕
2755 /// coordination-required`), the data axis (`public-data ⊕
2756 /// data-restricted`), the optimization-direction axis
2757 /// (`prefers-lower-direction ⊕ prefers-higher-direction`), and
2758 /// the input-arity axis (`input_arity_is_one ⊕
2759 /// input_arity_is_many`). A future ephemeral-surface peer
2760 /// (`EphemeralSpec::output_arity_is_one`) will compose THIS
2761 /// method through
2762 /// [`crate::ephemeral::EphemeralSpec::resolved_classification`]
2763 /// so the two-surface parity contract holds — the operator's
2764 /// `:requires (single-output-arity)` audit answers the same
2765 /// question on both surfaces.
2766 ///
2767 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2768 /// preserves proofs; the derived-nullary-bool predicate body
2769 /// lives at ONE substrate site so every downstream (the future
2770 /// `single-output-arity` fixed tag in `tatara-check`, DAG
2771 /// composition validators keying on the single-output framing,
2772 /// future variant additions on [`ConvergencePointType`]) binds
2773 /// through the SAME `output_arity_is_one()` shape rather than
2774 /// restating the two-hop `self.point_type.output_arity().is_one()`
2775 /// chain at each callsite. THEORY.md §VI.1 — generation over
2776 /// composition; a future [`ConvergencePointType`] variant lands
2777 /// at ONE `ALL` entry + ONE `output_arity` arm on the closed set
2778 /// and this probe picks it up mechanically.
2779 #[must_use]
2780 pub fn output_arity_is_one(&self) -> bool {
2781 self.point_type.output_arity().is_one()
2782 }
2783
2784 /// ANTISYMMETRIC PEER of [`Self::output_arity_is_one`] — does
2785 /// this [`Classification`]'s `point_type` slot project to
2786 /// `Arity::Many` under [`ConvergencePointType::output_arity`]?
2787 /// The ONE substrate primitive that owns the `(Classification) ->
2788 /// bool` derived-nullary-predicate walk on the multi-output side
2789 /// of the DAG-composition output-arity projection.
2790 ///
2791 /// # Nineteenth corner occupant — CLOSES the output-arity axis into a binary XOR partition
2792 ///
2793 /// NINETEENTH occupant on the (parent × derived-nullary-bool)
2794 /// corner of the workspace-wide closed-set-driven presence-probe
2795 /// algebra and SECOND peer threading the classification-
2796 /// `point_type`-derived output-arity axis — CLOSES the EIGHTH
2797 /// classification axis into the FULL binary XOR partition
2798 /// contract `output_arity_is_one ⊕ output_arity_is_many` sealed
2799 /// on the closed set by `arity_is_one_xor_is_many_over_all` and
2800 /// composed through the parent-composed layer by
2801 /// `classification_output_arity_probes_form_binary_xor_partition_over_all`.
2802 /// Structural mirror of the input-arity-axis binary XOR partition
2803 /// (`input_arity_is_one ⊕ input_arity_is_many`), the calm-axis
2804 /// binary XOR partition (`monotone-calm ⊕ coordination-required`),
2805 /// the data-axis binary XOR partition
2806 /// (`public-data ⊕ data-restricted`), and the optimization-
2807 /// direction-axis binary XOR partition (`prefers-lower-direction
2808 /// ⊕ prefers-higher-direction`) — the FIFTH parent-composed
2809 /// binary XOR partition on the corner and the SECOND on the
2810 /// derived-typed-projection stratum (after the input-arity
2811 /// closure).
2812 ///
2813 /// # Semantics — derived nullary boolean over the multi-output projection
2814 ///
2815 /// `output_arity_is_many()` returns `true` iff
2816 /// `self.point_type.output_arity().is_many()`. The eight-variant
2817 /// [`ConvergencePointType`] closed set publishes the truth table
2818 /// through [`ConvergencePointType::output_arity`]: `Transform |
2819 /// Join | Gate | Select | Reduce | Observe → One → false`; `Fork
2820 /// | Broadcast → Many → true`. A [`Classification::gate_compute`]
2821 /// baseline (which carries `point_type: Gate`) answers `false` —
2822 /// `Gate.output_arity() = One`, so the single-output bucket
2823 /// carves the workspace-wide baseline. Direct antisymmetric
2824 /// mirror of [`Self::output_arity_is_one`] on the SAME projection
2825 /// through the SAME closed set.
2826 ///
2827 /// # Compounding — CLOSES the output-arity axis into a binary XOR partition
2828 ///
2829 /// The point-domain require-tag surface will compose this
2830 /// primitive as a fixed tag `multi-output-arity` on
2831 /// `POINT_FIXED_TAG_ARMS` — antisymmetric peer of the sibling
2832 /// `single-output-arity` fixed tag. Together with the sibling
2833 /// [`Self::output_arity_is_one`] the two predicates seal the
2834 /// output-arity axis into a binary XOR partition on the parent-
2835 /// composed layer as a substrate-wide theorem, closing the axis
2836 /// at the EIGHTH-classification-axis landmark. Together with the
2837 /// four sibling closed binary XOR partitions (input-arity, calm,
2838 /// data, optimization-direction) the (parent × derived-nullary-
2839 /// bool) corner now carries FIVE closed binary XOR partitions —
2840 /// the derived-typed-projection stratum grows the corner from
2841 /// stored-slot walks into DAG-composition typed projections
2842 /// systematically.
2843 ///
2844 /// Theory anchor: THEORY.md §II.1 invariant 5 — composition
2845 /// preserves proofs; the derived-nullary-bool predicate body
2846 /// lives at ONE substrate site so every downstream (the future
2847 /// `multi-output-arity` fixed tag, DAG composition validators
2848 /// keying on multi-output fan-out semantics, future variant
2849 /// additions on [`ConvergencePointType`]) binds through the SAME
2850 /// `output_arity_is_many()` shape rather than restating either
2851 /// `!self.output_arity_is_one()` or
2852 /// `self.point_type.output_arity().is_many()` at each callsite.
2853 /// THEORY.md §VI.1 — generation over composition; a future
2854 /// [`ConvergencePointType`] variant lands at ONE `ALL` entry +
2855 /// ONE `output_arity` arm on the closed set and this probe picks
2856 /// it up mechanically.
2857 #[must_use]
2858 pub fn output_arity_is_many(&self) -> bool {
2859 self.point_type.output_arity().is_many()
2860 }
2861
2862 /// Compose the workspace-baseline [`Self::gate_compute`] with a
2863 /// single-axis mutation — return `Self::gate_compute()` with the
2864 /// axis slot carrying `axis`'s classification-axis type overwritten
2865 /// by `axis`. The ONE substrate primitive that owns the
2866 /// (Classification, single-axis variant) → Classification
2867 /// baseline-with-axis-mutated composition shape.
2868 ///
2869 /// # Substrate ergonomics
2870 ///
2871 /// Pre-lift the shape `Classification::gate_compute()` with a
2872 /// single axis slot overwritten by a per-test swept variant
2873 /// recurred at ≥ 40 hand-authored test-fixture callsites past the
2874 /// ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold, each restating the
2875 /// SAME six-line struct-literal that names FOUR baseline slots
2876 /// verbatim and mutates ONE. Post-lift every callsite reads
2877 /// `Classification::gate_compute_with_axis(populated)` — one line,
2878 /// ONE substrate primitive owns the four-baseline-slot restatement,
2879 /// and a future workspace-wide baseline shift lands at ONE site
2880 /// via [`Self::gate_compute`] rather than at every downstream
2881 /// test fixture that names the four unmutated slots explicitly.
2882 ///
2883 /// # Compounding
2884 ///
2885 /// A future SIXTH classification axis (foreshadowed by the
2886 /// six-axis lattice language on the CRD-facing prose) lands as
2887 /// ONE peer `impl ClassificationAxis` on the new axis's closed
2888 /// set + ONE new slot on [`Classification`] itself — every test
2889 /// fixture using `gate_compute_with_axis` picks up the sixth axis
2890 /// mechanically without touching the callsite. A future audit
2891 /// dispatcher walking every classification axis (the "walk every
2892 /// classification axis through its XOR partition landmark" shape
2893 /// the FIFTH-axis-closure commit `2c74fab` explicitly named as
2894 /// the next-lift target) binds through the SAME trait rather than
2895 /// a five-arm dispatch on axis identity.
2896 ///
2897 /// Theory anchor: THEORY.md §II.1 invariant 5 (composition
2898 /// preserves proofs — the four-baseline-slot restatement is the
2899 /// composition proof `gate_compute` already carries at ONE site;
2900 /// this primitive extends the ONE-site composition guarantee
2901 /// through the per-axis mutation shape). THEORY.md §VI.1
2902 /// (generation over composition — a future sixth axis lands as
2903 /// ONE ClassificationAxis impl and every test fixture picks it
2904 /// up mechanically).
2905 #[must_use]
2906 pub fn gate_compute_with_axis<A: ClassificationAxis>(axis: A) -> Self {
2907 let mut c = Self::gate_compute();
2908 axis.overlay(&mut c);
2909 c
2910 }
2911
2912 /// Fluent per-axis overlay — post-composes ONE additional
2913 /// [`ClassificationAxis`] variant on top of `self`, returning
2914 /// the mutated [`Classification`] by value. Sibling to
2915 /// [`Self::gate_compute_with_axis`] on the (baseline-composer ×
2916 /// per-axis-overlay) axis: `gate_compute_with_axis(a)` is the
2917 /// (start-from-baseline, overlay-one-axis) shape; `with_axis(a)`
2918 /// is the (start-from-arbitrary-classification, overlay-one-more-
2919 /// axis) shape. Together they compose the workspace-wide
2920 /// (Classification, N-axis-conjunction) construction algebra:
2921 /// `Classification::gate_compute_with_axis(a).with_axis(b).with_axis(c)`
2922 /// chains an arbitrary N-axis conjunction onto the [`Self::gate_compute`]
2923 /// baseline through ONE substrate primitive per axis rather than
2924 /// restating the FIVE-field struct-literal (`point_type`,
2925 /// `substrate`, `horizon`, `calm`, `data_classification`) verbatim
2926 /// at every N-axis-conjunction test-fixture callsite.
2927 ///
2928 /// # Substrate ergonomics
2929 ///
2930 /// Pre-lift the shape `Classification { <mutated-axes>,
2931 /// ..(remaining-baselines) }` recurred at ≥ 5 hand-authored
2932 /// multi-axis-conjunction test-fixture callsites in this file
2933 /// past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold,
2934 /// each restating the FIVE-field struct-literal with distinct
2935 /// (Fork+Storage), (Fork+Storage+NonMonotone),
2936 /// (Fork+Storage+NonMonotone+Pii),
2937 /// (Fork+Storage+NonMonotone+Pii+HorizonKind::Asymptotic), and
2938 /// (Fork+Storage+NonMonotone+Pii+HorizonKind::Asymptotic+
2939 /// direction=Maximize) conjunctions. Post-lift each callsite
2940 /// reads
2941 /// `Classification::gate_compute_with_axis(Fork).with_axis(Storage)`
2942 /// … (chained per axis), and the four/three/two/one-baseline-slot
2943 /// restatement binds through the ONE substrate composer at every
2944 /// callsite. The prior lift onto [`Self::gate_compute_with_axis`]
2945 /// (`76d469c` + `08714f6` + `7f14656`) closed the SINGLE-axis-
2946 /// overlay shape; this primitive extends the same trait dispatch
2947 /// through arbitrary N-axis conjunctions without introducing a
2948 /// variadic-tuple-overlay dispatch path.
2949 ///
2950 /// # Compounding
2951 ///
2952 /// A future SIXTH classification axis (foreshadowed by the
2953 /// six-axis lattice language on the CRD-facing prose) lands as
2954 /// ONE peer `impl ClassificationAxis` on the new axis's closed
2955 /// set — every multi-axis-conjunction test fixture using
2956 /// `.with_axis(...)` picks up the sixth axis mechanically by
2957 /// appending ONE more `.with_axis(new_variant)` call rather than
2958 /// growing an N-field struct-literal to N+1 fields at every
2959 /// site. A future audit dispatcher walking a fixed N-axis
2960 /// conjunction on every classification axis binds through the
2961 /// SAME chained-overlay shape rather than a per-N-arity
2962 /// composer family (`gate_compute_with_axes2`,
2963 /// `gate_compute_with_axes3`, …).
2964 ///
2965 /// Theory anchor: THEORY.md §II.1 invariant 5 (composition
2966 /// preserves proofs — the per-axis overlay is the axis-local
2967 /// composition proof [`ClassificationAxis::overlay`] owns at ONE
2968 /// site; this primitive lifts the ONE-axis composition guarantee
2969 /// through arbitrary chaining without a per-arity dispatch
2970 /// path). THEORY.md §VI.1 (generation over composition — a
2971 /// future N-axis-conjunction test lands as ONE chained
2972 /// `.with_axis(...)` sequence versus a fresh N+1-field struct-
2973 /// literal per callsite).
2974 #[must_use]
2975 pub fn with_axis<A: ClassificationAxis>(mut self, axis: A) -> Self {
2976 axis.overlay(&mut self);
2977 self
2978 }
2979}
2980
2981/// Test/audit helper — a closed-set variant that can overlay its
2982/// classification-axis slot onto a base [`Classification`]. Unifies
2983/// the five per-axis assignments (`horizon = Horizon { kind: self, ..
2984/// default() }`, `calm = self`, `data_classification = self`,
2985/// `point_type = self`, `substrate = self`) under ONE substrate
2986/// shape so [`Classification::gate_compute_with_axis`] can compose
2987/// the workspace baseline with a single-axis mutation generically
2988/// over any of the five classification axes.
2989///
2990/// # Compounding
2991///
2992/// A future SIXTH classification axis lands as ONE peer `impl
2993/// ClassificationAxis` on the new axis's closed set — every
2994/// downstream test fixture and audit dispatcher that binds through
2995/// [`Classification::gate_compute_with_axis`] picks up the sixth
2996/// axis mechanically without a five-arm-becomes-six-arm dispatch
2997/// edit. A future workspace-wide "walk every classification axis"
2998/// audit primitive binds through the SAME trait rather than
2999/// restating the five-per-axis assignment shape at its own body.
3000///
3001/// Theory anchor: THEORY.md §II.1 invariant 5 — composition
3002/// preserves proofs. The five per-axis assignments each carry an
3003/// axis-local composition proof (nested-struct `horizon.kind` gets
3004/// a fresh `Horizon::default()` around the mutation; direct-scalar
3005/// axes get a bare `self` assignment); this trait promotes the
3006/// five proofs to ONE shape so a downstream composer binds through
3007/// the same primitive regardless of which axis it targets.
3008pub trait ClassificationAxis {
3009 /// Overlay this axis-variant onto `c`, replacing the corresponding
3010 /// classification-axis slot with `self`. Leaves every other slot
3011 /// on `c` untouched.
3012 fn overlay(self, c: &mut Classification);
3013}
3014
3015impl ClassificationAxis for HorizonKind {
3016 fn overlay(self, c: &mut Classification) {
3017 // Sub-slot overlay — set ONLY the `kind` field on the nested
3018 // `Horizon` struct, preserving any `direction` / `metric` /
3019 // `healthy_rate_threshold` a prior [`Classification::with_axis`]
3020 // overlay may have populated. Byte-symmetric with the previous
3021 // whole-`Horizon` reset shape (`c.horizon = Horizon { kind: self,
3022 // ..Horizon::default() }`) when the base carrier is
3023 // [`Classification::gate_compute`] (whose `horizon` is
3024 // `Horizon::default()` — every sub-slot already `None`), but
3025 // order-independent under chaining: a downstream
3026 // `.with_axis(OptimizationDirection::Maximize).with_axis(HorizonKind::Asymptotic)`
3027 // no longer stomps the prior `direction: Some(Maximize)` overlay.
3028 c.horizon.kind = self;
3029 }
3030}
3031
3032impl ClassificationAxis for OptimizationDirection {
3033 fn overlay(self, c: &mut Classification) {
3034 // Nested-struct-Option sub-slot overlay — set ONLY the
3035 // `direction` field on the nested `Horizon` struct as
3036 // `Some(self)`, preserving `kind` / `metric` /
3037 // `healthy_rate_threshold`. Peer to the direct-nested-scalar
3038 // [`ClassificationAxis for HorizonKind`] overlay: both hop into
3039 // the nested `Horizon` struct, but this overlay wraps its assign
3040 // in `Some(...)` per the `Horizon::direction: Option<OptimizationDirection>`
3041 // typed slot. Chain
3042 // `.with_axis(HorizonKind::Asymptotic).with_axis(OptimizationDirection::Maximize)`
3043 // to compose the (kind, direction) pair the
3044 // [`crate::export`]-facing rate-window Asymptotic-horizon
3045 // fixtures otherwise restate as `Horizon { kind: Asymptotic,
3046 // direction: Some(Maximize), ..Horizon::default() }` inline.
3047 c.horizon.direction = Some(self);
3048 }
3049}
3050
3051impl ClassificationAxis for CalmClassification {
3052 fn overlay(self, c: &mut Classification) {
3053 c.calm = self;
3054 }
3055}
3056
3057impl ClassificationAxis for DataClassification {
3058 fn overlay(self, c: &mut Classification) {
3059 c.data_classification = self;
3060 }
3061}
3062
3063impl ClassificationAxis for ConvergencePointType {
3064 fn overlay(self, c: &mut Classification) {
3065 c.point_type = self;
3066 }
3067}
3068
3069impl ClassificationAxis for SubstrateType {
3070 fn overlay(self, c: &mut Classification) {
3071 c.substrate = self;
3072 }
3073}
3074
3075/// Structural type — how data flows through the point.
3076///
3077/// Closed-set sibling on the classification axis algebra; the `ALL` /
3078/// `as_str` / Display / `FromStr` triad mirrors
3079/// [`DataClassification::ALL`], [`crate::pool::PoolPhase::ALL`],
3080/// [`crate::pool::MemberState::ALL`], [`crate::pool::ReplacementPolicy::ALL`],
3081/// [`crate::pool::ReturnPolicy::ALL`],
3082/// [`crate::boundary::ConditionKind::ALL`],
3083/// [`crate::lifetime::TeardownPolicy::ALL`],
3084/// [`crate::lifetime::LifetimeKind::ALL`],
3085/// [`crate::intent::IntentKind::ALL`],
3086/// [`crate::phase::ProcessPhase::ALL`],
3087/// [`crate::signal::ProcessSignal::ALL`]. The
3088/// `(input_arity, output_arity)` projection (via [`Arity`]) closes the
3089/// graph-topology contract: each variant lands in exactly one of the
3090/// three structural buckets — endomorphic (1→1), diffusive (1→N), or
3091/// convergent (N→1) — so future DAG composition / edge-cardinality
3092/// validators dispatch on a typed projection rather than re-deriving
3093/// from variant names.
3094#[derive(
3095 Clone,
3096 Copy,
3097 Debug,
3098 PartialEq,
3099 Eq,
3100 Hash,
3101 Serialize,
3102 Deserialize,
3103 JsonSchema,
3104 tatara_closed_set::DeriveClosedSet,
3105)]
3106#[serde(rename_all = "PascalCase")]
3107#[closed_set(via = "as_str", generate_unknown, display)]
3108pub enum ConvergencePointType {
3109 /// 1 input → 1 output (linear conversion).
3110 Transform,
3111 /// 1 input → N outputs (fan-out, spawns downstream DAGs).
3112 Fork,
3113 /// N inputs → 1 output (fan-in, merges upstream results).
3114 Join,
3115 /// N inputs → 1 output (barrier, waits for all inputs).
3116 Gate,
3117 /// N inputs → 1 output (choice, picks best by policy).
3118 Select,
3119 /// 1 input → N outputs same type (replicate signal).
3120 Broadcast,
3121 /// N inputs → 1 output (fold/aggregate).
3122 Reduce,
3123 /// 1 input → 1 output + side-channel (tap for observation).
3124 Observe,
3125}
3126
3127impl ConvergencePointType {
3128 /// The closed set of point types — single source of truth that
3129 /// drives the `as_str` / Display / `FromStr` triad AND the
3130 /// `(input_arity, output_arity)` typed pair (via [`Arity`]) AND the
3131 /// `is_endomorphic` / `is_diffusive` / `is_convergent` predicate
3132 /// triple. Adding a ninth variant lands at one `ALL` entry + one
3133 /// `as_str` arm + one `input_arity` arm + one `output_arity` arm +
3134 /// one arm per predicate — exhaustively checked by the compiler
3135 /// (the `[Self; 8]` array literal forces the arity) AND by the
3136 /// per-variant truth-table contract test (a new variant must
3137 /// declare its own `(input, output)` arity pair or any future
3138 /// DAG composition validator that dispatches on
3139 /// `(input_arity, output_arity)` will silently mis-wire it).
3140 /// Closes the load-bearing classification-axis enum that
3141 /// `tatara_core::domain::compliance_binding::PointSelector::ByType`
3142 /// already dispatches against and that every `Process`'s
3143 /// `Classification.point_type` reads as the topological identity
3144 /// of the convergence point.
3145 pub const ALL: [Self; 8] = [
3146 Self::Transform,
3147 Self::Fork,
3148 Self::Join,
3149 Self::Gate,
3150 Self::Select,
3151 Self::Broadcast,
3152 Self::Reduce,
3153 Self::Observe,
3154 ];
3155
3156 /// Canonical PascalCase wire-format projection — matches the
3157 /// serde `rename_all = "PascalCase"` output verbatim AND the CRD
3158 /// `enum:` enumeration that the Process schema stamps on
3159 /// `spec.classification.pointType`. Pinned by
3160 /// `convergence_point_type_as_str_matches_serde` so a variant
3161 /// rename can't drift between the typed surface, the CRD enum,
3162 /// the YAML wire format AND any future operator-facing
3163 /// diagnostic that composes `pointType={kind}` via Display
3164 /// rather than a hard-coded literal that would silently rot.
3165 /// Display + FromStr triad over `ALL` mirrors `DataClassification`
3166 /// / `PoolPhase` / `MemberState` / `ReplacementPolicy` /
3167 /// `ReturnPolicy` / `TeardownPolicy` / `ConditionKind` /
3168 /// `ProcessPhase` / `ProcessSignal`.
3169 pub const fn as_str(self) -> &'static str {
3170 match self {
3171 Self::Transform => "Transform",
3172 Self::Fork => "Fork",
3173 Self::Join => "Join",
3174 Self::Gate => "Gate",
3175 Self::Select => "Select",
3176 Self::Broadcast => "Broadcast",
3177 Self::Reduce => "Reduce",
3178 Self::Observe => "Observe",
3179 }
3180 }
3181
3182 /// Cardinality of the input edge into this point — `One` for
3183 /// `Transform | Fork | Broadcast | Observe` (single-source
3184 /// projections), `Many` for `Join | Gate | Select | Reduce`
3185 /// (multi-source convergent reductions). Closed-set match (not
3186 /// `matches!`) so a future variant triggers the compiler's
3187 /// exhaustiveness check at this site rather than silently
3188 /// defaulting to `One`. Paired with [`Self::output_arity`] they
3189 /// form the typed `(input, output)` projection that future
3190 /// DAG composition validators (edge-cardinality checks: "you
3191 /// can't connect a Fork's output to a Transform's input
3192 /// without a Join in between") dispatch against — a single
3193 /// projection per variant means a future `Demux` / `Mux` /
3194 /// `Pipeline` point lands in exactly one cell of the
3195 /// `Arity × Arity` topology table rather than rotting against
3196 /// open-coded `== ConvergencePointType::Fork` checks.
3197 pub const fn input_arity(self) -> Arity {
3198 match self {
3199 Self::Transform | Self::Fork | Self::Broadcast | Self::Observe => Arity::One,
3200 Self::Join | Self::Gate | Self::Select | Self::Reduce => Arity::Many,
3201 }
3202 }
3203
3204 /// Cardinality of the output edge from this point — `Many` for
3205 /// `Fork | Broadcast` (fan-out), `One` for everything else.
3206 /// Closed-set match so a future variant triggers the compiler's
3207 /// exhaustiveness check. See [`Self::input_arity`] for the
3208 /// arity-pair contract + bucket definitions.
3209 pub const fn output_arity(self) -> Arity {
3210 match self {
3211 Self::Fork | Self::Broadcast => Arity::Many,
3212 Self::Transform
3213 | Self::Join
3214 | Self::Gate
3215 | Self::Select
3216 | Self::Reduce
3217 | Self::Observe => Arity::One,
3218 }
3219 }
3220
3221 /// Does this point preserve the single-input single-output
3222 /// shape? `(input, output) == (One, One)` — `Transform`
3223 /// (identity-shaped reshape) and `Observe` (passthrough +
3224 /// side-channel tap). Closed-set match so a future variant
3225 /// triggers the compiler's exhaustiveness check. Paired with
3226 /// `is_diffusive` and `is_convergent` they form the three-way
3227 /// disjoint bucket carving sealed by
3228 /// `convergence_point_type_buckets_cover_every_variant` AND
3229 /// `convergence_point_type_arity_pair_agrees_with_bucket` —
3230 /// the bridge that lets the bucket predicates and the arity
3231 /// pair name the same topology partition from two angles.
3232 pub const fn is_endomorphic(self) -> bool {
3233 match self {
3234 Self::Transform | Self::Observe => true,
3235 Self::Fork
3236 | Self::Join
3237 | Self::Gate
3238 | Self::Select
3239 | Self::Broadcast
3240 | Self::Reduce => false,
3241 }
3242 }
3243
3244 /// Does this point fan out — single input replicated/split
3245 /// across many outputs? `(input, output) == (One, Many)` —
3246 /// `Fork` and `Broadcast`. Closed-set match so a future variant
3247 /// triggers the compiler's exhaustiveness check. See
3248 /// `is_endomorphic` for the bucket-carving contract.
3249 pub const fn is_diffusive(self) -> bool {
3250 match self {
3251 Self::Fork | Self::Broadcast => true,
3252 Self::Transform
3253 | Self::Join
3254 | Self::Gate
3255 | Self::Select
3256 | Self::Reduce
3257 | Self::Observe => false,
3258 }
3259 }
3260
3261 /// Does this point reduce — many inputs collapsed to one
3262 /// output? `(input, output) == (Many, One)` — `Join`, `Gate`,
3263 /// `Select`, `Reduce`. Closed-set match so a future variant
3264 /// triggers the compiler's exhaustiveness check. See
3265 /// `is_endomorphic` for the bucket-carving contract. The
3266 /// impossible `(Many, Many)` topology bucket is pinned empty
3267 /// by `convergence_point_type_arity_pair_agrees_with_bucket`
3268 /// — a `(Many, Many)` point would mean "many independent
3269 /// inputs replicated across many independent outputs", which
3270 /// has no convergence semantics: every DAG-composition
3271 /// validator would have to special-case it. A future variant
3272 /// that wants `(Many, Many)` must first extend the bucket
3273 /// carving deliberately.
3274 pub const fn is_convergent(self) -> bool {
3275 match self {
3276 Self::Join | Self::Gate | Self::Select | Self::Reduce => true,
3277 Self::Transform | Self::Fork | Self::Broadcast | Self::Observe => false,
3278 }
3279 }
3280}
3281
3282// `impl FromStr for ConvergencePointType` +
3283// `impl tatara_lisp::ClosedSet for ConvergencePointType` +
3284// `impl std::fmt::Display for ConvergencePointType` +
3285// `pub struct UnknownConvergencePointType(pub String)` are all generated
3286// by `#[derive(tatara_closed_set::DeriveClosedSet)]` +
3287// `#[closed_set(via = "as_str", generate_unknown, display)]` on the
3288// enum declaration above. `label` delegates to the inherent
3289// `ConvergencePointType::as_str` — the inherent name (PascalCase
3290// `as_str`) stays the load-bearing wire-vocabulary projection that
3291// matches the serde `rename_all = "PascalCase"` output AND the CRD
3292// `enum:` enumeration the Process schema stamps on
3293// `spec.classification.pointType` verbatim, while generic
3294// `T: ClosedSet` consumers reach the STABLE workspace-wide name
3295// (`label`). The `display` flag emits the
3296// `f.write_str(self.as_str())` delegation block at the same
3297// proc-macro site rather than a hand-rolled `fmt::Display` block per
3298// implementor. The auto-derived carrier label "convergence point
3299// type" matches the prior hand-rolled `#[error("unknown convergence
3300// point type: {0}")]` annotation byte-for-byte. Symmetric to the
3301// other five classification-axis closed-sets in this file
3302// (`SubstrateType` / `HorizonKind` / `OptimizationDirection` /
3303// `CalmClassification` / `DataClassification`) AND every other
3304// `#[derive(DeriveClosedSet)]` implementor across the workspace
3305// (`crate::pool::{ReplacementPolicy,MemberState,PoolPhase,ReturnPolicy}`,
3306// `crate::export::{ArtifactKind,ReportFormat,ChannelKind,ExportTrigger}`,
3307// `crate::allocation::{RequestorKind,AllocationPhase}`).
3308
3309/// Edge cardinality of a [`ConvergencePointType`]'s input or output.
3310///
3311/// Typed projection used by [`ConvergencePointType::input_arity`] and
3312/// [`ConvergencePointType::output_arity`] so DAG composition validators
3313/// reach for a closed-set enum rather than re-deriving the in/out
3314/// cardinality from variant names. `Many` is the "≥1, could be N"
3315/// cardinality — it carries no upper bound because the convergence
3316/// point's variant tag is already the structural identity; the
3317/// number itself is a runtime property of the DAG, not the typescape.
3318#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, tatara_closed_set::DeriveClosedSet)]
3319#[closed_set(via = "as_str", display, generate_unknown)]
3320pub enum Arity {
3321 /// Single edge — exactly one input or one output.
3322 One,
3323 /// Multiple edges — any number ≥ 1.
3324 Many,
3325}
3326
3327impl Arity {
3328 /// The closed set of arities — single source of truth that
3329 /// drives `as_str` / Display AND the `is_one` predicate. Adding
3330 /// a third variant (e.g. `Arity::Zero` for sinks) lands at one
3331 /// `ALL` entry + one `as_str` arm + one predicate arm —
3332 /// exhaustively checked by the compiler.
3333 pub const ALL: [Self; 2] = [Self::One, Self::Many];
3334
3335 /// Canonical projection — `"One" | "Many"`. Pinned by
3336 /// `arity_display_matches_as_str` so a future Display impl
3337 /// can't drift from the canonical string.
3338 pub const fn as_str(self) -> &'static str {
3339 match self {
3340 Self::One => "One",
3341 Self::Many => "Many",
3342 }
3343 }
3344
3345 /// Is this the single-edge cardinality? Closed-set match (not
3346 /// `matches!`) so a future variant triggers the compiler's
3347 /// exhaustiveness check.
3348 pub const fn is_one(self) -> bool {
3349 match self {
3350 Self::One => true,
3351 Self::Many => false,
3352 }
3353 }
3354
3355 /// POSITIVE-FRAMING PEER of [`Self::is_one`] — is this the
3356 /// multi-edge cardinality? Closed-set match (not `matches!`) so a
3357 /// future variant triggers the compiler's exhaustiveness check at
3358 /// this site rather than silently defaulting to `false` (which
3359 /// would mis-bucket a `Zero`-style sink variant onto the multi-
3360 /// edge path). The boolean partition is the antisymmetric image
3361 /// of [`Self::is_one`]: `One ⇒ false`, `Many ⇒ true`. Exactly
3362 /// one of `(is_one, is_many)` is true per variant on the current
3363 /// two-variant closed set — pinned by
3364 /// `arity_is_one_xor_is_many_over_all` — exactly the binary XOR
3365 /// partition already sealed on the sibling optimization-direction
3366 /// axis by `optimization_direction_prefers_lower_xor_prefers_higher`,
3367 /// on the calm axis by
3368 /// `calm_classification_monotone_xor_requires_coordination`, and
3369 /// on the data axis by
3370 /// `data_classification_public_xor_restricted`. Structural mirror
3371 /// of [`OptimizationDirection::prefers_higher`] as the positive-
3372 /// framing peer that any future dispatch on the multi-edge
3373 /// cardinality (DAG fan-out validators, edge-cardinality checks:
3374 /// "every diffusive topology point emits fan-out") reads once
3375 /// rather than re-deriving from the variant name or the
3376 /// `!is_one()` inversion at each callsite.
3377 ///
3378 /// A future third variant (a hypothetical `Zero` sentinel for
3379 /// pure sinks with no edge, which neither single nor multi
3380 /// cardinality names) MUST answer `false` here — matching the
3381 /// antisymmetric complement on [`Self::is_one`] so the binary
3382 /// XOR partition either extends into a ternary partition
3383 /// deliberately (adding a third derived-nullary predicate on the
3384 /// closed set) OR the author flips one of the existing predicates
3385 /// to reclaim the XOR. The exhaustiveness check plus the XOR pin
3386 /// force the decision at the closed set rather than silently
3387 /// bucketing the new variant onto an existing cardinality.
3388 pub const fn is_many(self) -> bool {
3389 match self {
3390 Self::One => false,
3391 Self::Many => true,
3392 }
3393 }
3394}
3395
3396// `impl fmt::Display for Arity` + `impl std::str::FromStr for Arity` +
3397// `impl tatara_lisp::ClosedSet for Arity` + `pub struct UnknownArity(pub
3398// String)` are all generated by
3399// `#[derive(tatara_closed_set::DeriveClosedSet)]` +
3400// `#[closed_set(via = "as_str", display, generate_unknown)]` on the enum
3401// declaration above. The inherent `as_str` projection stays load-bearing
3402// — the canonical `"One" | "Many"` string every DAG composition
3403// validator reads; `via = "as_str"` binds `ClosedSet::label` to the same
3404// projection so the substrate-wide `assert_display_matches_label` /
3405// `assert_closed_set_well_formed` primitives dispatch through the same
3406// byte-identical shape every other closed-set implementor across the
3407// crate publishes. Aligns `Arity` with the substrate-wide
3408// `#[derive(DeriveClosedSet)]` idiom that every other closed-set enum on
3409// this classification axis (`ConvergencePointType`, `SubstrateType`,
3410// `HorizonKind`, `OptimizationDirection`, `CalmClassification`,
3411// `DataClassification`) already carries — the last hand-rolled
3412// `impl fmt::Display` on the axis is closed at ONE substrate site.
3413
3414/// Operational substrate.
3415///
3416/// Closed-set sibling on the classification axis algebra; the `ALL` /
3417/// `as_str` / Display / `FromStr` triad mirrors
3418/// [`ConvergencePointType::ALL`], [`DataClassification::ALL`],
3419/// [`crate::pool::PoolPhase::ALL`], [`crate::pool::MemberState::ALL`],
3420/// [`crate::pool::ReplacementPolicy::ALL`],
3421/// [`crate::pool::ReturnPolicy::ALL`],
3422/// [`crate::boundary::ConditionKind::ALL`],
3423/// [`crate::lifetime::TeardownPolicy::ALL`],
3424/// [`crate::lifetime::LifetimeKind::ALL`],
3425/// [`crate::intent::IntentKind::ALL`],
3426/// [`crate::phase::ProcessPhase::ALL`],
3427/// [`crate::signal::ProcessSignal::ALL`]. The
3428/// `is_resource` / `is_policy` / `is_telemetry` predicate triple
3429/// carves the eight variants into three structurally-disjoint
3430/// substrate planes — resource (you allocate from it), policy (it
3431/// gates access for other workloads), telemetry (it observes other
3432/// workloads) — so future compliance-baseline selectors that
3433/// dispatch on a substrate's plane (resource budgets only apply to
3434/// resource substrates; policy substrates inherit baselines from
3435/// what they govern; telemetry substrates inherit baselines from
3436/// what they observe) read a typed projection rather than
3437/// re-deriving from variant names.
3438#[derive(
3439 Clone,
3440 Copy,
3441 Debug,
3442 PartialEq,
3443 Eq,
3444 Hash,
3445 PartialOrd,
3446 Ord,
3447 Serialize,
3448 Deserialize,
3449 JsonSchema,
3450 tatara_closed_set::DeriveClosedSet,
3451)]
3452#[serde(rename_all = "PascalCase")]
3453#[closed_set(via = "as_str", generate_unknown, display)]
3454pub enum SubstrateType {
3455 Financial,
3456 Compute,
3457 Network,
3458 Storage,
3459 Security,
3460 Identity,
3461 Observability,
3462 Regulatory,
3463}
3464
3465impl SubstrateType {
3466 /// The closed set of substrates — single source of truth that
3467 /// drives the `as_str` / Display / `FromStr` triad AND the
3468 /// `is_resource` / `is_policy` / `is_telemetry` predicate triple.
3469 /// Adding a ninth variant lands at one `ALL` entry + one
3470 /// `as_str` arm + one arm per predicate — exhaustively checked
3471 /// by the compiler (the `[Self; 8]` array literal forces the
3472 /// arity) AND by the per-variant plane-bucket contract test (a
3473 /// new variant must declare its own plane or any future
3474 /// compliance-baseline selector that dispatches on
3475 /// `(is_resource, is_policy, is_telemetry)` will silently
3476 /// mis-classify it). Closes the load-bearing classification-axis
3477 /// enum that
3478 /// `tatara_core::domain::compliance_binding::PointSelector::BySubstrate`
3479 /// already dispatches against and that every `Process`'s
3480 /// `Classification.substrate` reads as the operational
3481 /// substrate the convergence point lives on.
3482 pub const ALL: [Self; 8] = [
3483 Self::Financial,
3484 Self::Compute,
3485 Self::Network,
3486 Self::Storage,
3487 Self::Security,
3488 Self::Identity,
3489 Self::Observability,
3490 Self::Regulatory,
3491 ];
3492
3493 /// Canonical PascalCase wire-format projection — matches the
3494 /// serde `rename_all = "PascalCase"` output verbatim AND the CRD
3495 /// `enum:` enumeration that the Process schema stamps on
3496 /// `spec.classification.substrate`. Pinned by
3497 /// `substrate_type_as_str_matches_serde` so a variant rename
3498 /// can't drift between the typed surface, the CRD enum, the YAML
3499 /// wire format AND any future operator-facing diagnostic that
3500 /// composes `substrate={kind}` via Display rather than a
3501 /// hard-coded literal that would silently rot. Display + FromStr
3502 /// triad over `ALL` mirrors `ConvergencePointType` /
3503 /// `DataClassification` / `PoolPhase` / `MemberState` /
3504 /// `ReplacementPolicy` / `ReturnPolicy` / `TeardownPolicy` /
3505 /// `ConditionKind` / `ProcessPhase` / `ProcessSignal`.
3506 pub const fn as_str(self) -> &'static str {
3507 match self {
3508 Self::Financial => "Financial",
3509 Self::Compute => "Compute",
3510 Self::Network => "Network",
3511 Self::Storage => "Storage",
3512 Self::Security => "Security",
3513 Self::Identity => "Identity",
3514 Self::Observability => "Observability",
3515 Self::Regulatory => "Regulatory",
3516 }
3517 }
3518
3519 /// Is this a resource substrate — one you allocate budgets from
3520 /// to run workloads? `Financial | Compute | Network | Storage`.
3521 /// Closed-set match (not `matches!`) so a future variant
3522 /// triggers the compiler's exhaustiveness check at this site
3523 /// rather than silently defaulting to `false`. Paired with
3524 /// `is_policy` and `is_telemetry` they form the three-way
3525 /// disjoint plane carving sealed by
3526 /// `substrate_type_buckets_cover_every_variant` — the bridge
3527 /// that lets future compliance-baseline selectors dispatch on
3528 /// plane without re-deriving from variant names.
3529 pub const fn is_resource(self) -> bool {
3530 match self {
3531 Self::Financial | Self::Compute | Self::Network | Self::Storage => true,
3532 Self::Security | Self::Identity | Self::Observability | Self::Regulatory => false,
3533 }
3534 }
3535
3536 /// Is this a policy substrate — one that gates access or
3537 /// compliance for other workloads rather than carrying their
3538 /// payload? `Security | Identity | Regulatory`. Closed-set match
3539 /// so a future variant triggers the compiler's exhaustiveness
3540 /// check. See `is_resource` for the bucket-carving contract.
3541 pub const fn is_policy(self) -> bool {
3542 match self {
3543 Self::Security | Self::Identity | Self::Regulatory => true,
3544 Self::Financial
3545 | Self::Compute
3546 | Self::Network
3547 | Self::Storage
3548 | Self::Observability => false,
3549 }
3550 }
3551
3552 /// Is this a telemetry substrate — one that passively observes
3553 /// other workloads (metrics, logs, traces) without carrying
3554 /// their payload or gating their access? `Observability` only.
3555 /// Closed-set match so a future variant triggers the compiler's
3556 /// exhaustiveness check. See `is_resource` for the
3557 /// bucket-carving contract. A telemetry substrate's compliance
3558 /// baseline is inherited from what it observes — the singleton
3559 /// bucket is intentional, not a placeholder.
3560 pub const fn is_telemetry(self) -> bool {
3561 match self {
3562 Self::Observability => true,
3563 Self::Financial
3564 | Self::Compute
3565 | Self::Network
3566 | Self::Storage
3567 | Self::Security
3568 | Self::Identity
3569 | Self::Regulatory => false,
3570 }
3571 }
3572}
3573
3574// `impl FromStr for SubstrateType` +
3575// `impl tatara_lisp::ClosedSet for SubstrateType` +
3576// `impl std::fmt::Display for SubstrateType` +
3577// `pub struct UnknownSubstrateType(pub String)` are all generated by
3578// `#[derive(tatara_closed_set::DeriveClosedSet)]` +
3579// `#[closed_set(via = "as_str", generate_unknown, display)]` on the
3580// enum declaration above. The auto-derived carrier label "substrate
3581// type" matches the prior hand-rolled `#[error("unknown substrate
3582// type: {0}")]` annotation byte-for-byte. See the retrofit comment
3583// block on [`ConvergencePointType`] for the canonical narrative.
3584
3585/// How long the point runs. Flattened struct-of-optionals so the OpenAPI
3586/// schema carries a single `kind` discriminator without per-variant merge.
3587#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
3588#[serde(rename_all = "camelCase")]
3589pub struct Horizon {
3590 #[serde(default)]
3591 pub kind: HorizonKind,
3592 /// Metric being optimized (Asymptotic only).
3593 #[serde(default, skip_serializing_if = "Option::is_none")]
3594 pub metric: Option<String>,
3595 /// Whether to minimize or maximize the metric (Asymptotic only).
3596 #[serde(default, skip_serializing_if = "Option::is_none")]
3597 pub direction: Option<OptimizationDirection>,
3598 /// Rate threshold considered healthy (Asymptotic only).
3599 #[serde(default, skip_serializing_if = "Option::is_none")]
3600 pub healthy_rate_threshold: Option<f64>,
3601}
3602
3603/// The shape of a convergence horizon's lifetime — does the point
3604/// run toward a fixed point and terminate, or run in perpetuity with
3605/// a rate signal?
3606///
3607/// Closed-set sibling on the classification axis algebra; the `ALL` /
3608/// `as_str` / Display / `FromStr` triad mirrors
3609/// [`ConvergencePointType::ALL`], [`SubstrateType::ALL`],
3610/// [`DataClassification::ALL`], [`CalmClassification::ALL`],
3611/// [`OptimizationDirection::ALL`], [`crate::pool::PoolPhase::ALL`],
3612/// [`crate::pool::MemberState::ALL`],
3613/// [`crate::pool::ReplacementPolicy::ALL`],
3614/// [`crate::pool::ReturnPolicy::ALL`],
3615/// [`crate::boundary::ConditionKind::ALL`],
3616/// [`crate::lifetime::TeardownPolicy::ALL`],
3617/// [`crate::lifetime::LifetimeKind::ALL`],
3618/// [`crate::intent::IntentKind::ALL`],
3619/// [`crate::phase::ProcessPhase::ALL`],
3620/// [`crate::signal::ProcessSignal::ALL`]. The [`Self::terminates`]
3621/// predicate is the load-bearing horizon-shape primitive — schedulers
3622/// asking "will this Process ever reach `Reaped` via natural
3623/// termination?" read it as the typed image of the lattice ordering
3624/// (`Bounded ≤ Asymptotic` because the bounded horizon strictly
3625/// refines the asymptotic one by also terminating) rather than
3626/// re-deriving from the variant name. The
3627/// [`Self::requires_metric_axes`] predicate is the typed validity
3628/// witness for the [`Horizon`] struct's three `Option<…>` fields
3629/// (`metric`, `direction`, `healthy_rate_threshold`) — they're
3630/// `Some(_)` iff the kind requires them, so the implicit invariant
3631/// the optionality encodes becomes a checkable per-kind predicate
3632/// instead of operator folklore.
3633#[derive(
3634 Clone,
3635 Copy,
3636 Debug,
3637 PartialEq,
3638 Eq,
3639 Hash,
3640 Serialize,
3641 Deserialize,
3642 JsonSchema,
3643 Default,
3644 tatara_closed_set::DeriveClosedSet,
3645)]
3646#[serde(rename_all = "PascalCase")]
3647#[closed_set(via = "as_str", generate_unknown, display)]
3648pub enum HorizonKind {
3649 /// Has a fixed point — distance reaches 0 and terminates.
3650 #[default]
3651 Bounded,
3652 /// Runs in perpetuity — rate is the health signal, not distance.
3653 Asymptotic,
3654}
3655
3656impl HorizonKind {
3657 /// The closed set of horizon kinds — single source of truth that
3658 /// drives the `as_str` / Display / `FromStr` triad AND the
3659 /// `terminates` predicate AND the `requires_metric_axes` shape-
3660 /// validity witness. Adding a third variant (e.g. a `Periodic`
3661 /// sentinel for "terminates on each window boundary then
3662 /// re-arms", which neither perpetually-running nor singularly-
3663 /// terminating names) lands at one `ALL` entry + one `as_str`
3664 /// arm + one `terminates` arm + one `requires_metric_axes` arm —
3665 /// exhaustively checked by the compiler (the `[Self; 2]` array
3666 /// literal forces the arity) AND by the per-variant truth-table
3667 /// tests (a new variant must declare its own termination AND
3668 /// metric-axes requirement, or every scheduler / horizon-shape
3669 /// validator will silently bucket it). Closes the load-bearing
3670 /// classification sub-axis that the `Horizon.kind` field threads
3671 /// through every `Classification.horizon` field on every
3672 /// Process — the last open sibling on the classification axis
3673 /// algebra after `OptimizationDirection` (980a318),
3674 /// `CalmClassification` (da3430c), `SubstrateType` (b9d7b3b),
3675 /// `ConvergencePointType` (7941527), `Arity`, and
3676 /// `DataClassification` (81bffa0).
3677 pub const ALL: [Self; 2] = [Self::Bounded, Self::Asymptotic];
3678
3679 /// Canonical PascalCase wire-format projection — matches the
3680 /// serde `rename_all = "PascalCase"` output verbatim AND the CRD
3681 /// `enum:` enumeration the Process schema stamps on
3682 /// `spec.classification.horizon.kind`. Pinned by
3683 /// `horizon_kind_as_str_matches_serde` so a variant rename
3684 /// can't drift between the typed surface, the CRD enum, the
3685 /// YAML wire format AND any future operator-facing diagnostic
3686 /// composing `horizon.kind={kind}` via Display rather than a
3687 /// hard-coded literal. Display + FromStr triad over `ALL`
3688 /// mirrors every sibling closed-set enum in this crate.
3689 pub const fn as_str(self) -> &'static str {
3690 match self {
3691 Self::Bounded => "Bounded",
3692 Self::Asymptotic => "Asymptotic",
3693 }
3694 }
3695
3696 /// LOAD-BEARING HORIZON-SHAPE PRIMITIVE: does this kind terminate
3697 /// naturally — i.e. does it have a fixed point that
3698 /// `ConvergenceDistance` can reach? Closed-set match (not
3699 /// `matches!`) so a future variant triggers the compiler's
3700 /// exhaustiveness check rather than silently defaulting to
3701 /// `false` (which would silently mis-route a terminating
3702 /// variant through the asymptotic rate-window evaluator) or
3703 /// `true` (which would silently invent a fixed point for a
3704 /// perpetual variant). `Bounded ⇒ true`, `Asymptotic ⇒ false`
3705 /// is the typed image of the documented lattice ordering
3706 /// `Bounded ≤ Asymptotic` — the bounded horizon strictly refines
3707 /// the asymptotic one BY ALSO TERMINATING. Future schedulers
3708 /// asking "will this Process reach `Reaped` via natural
3709 /// termination?" read this predicate, and the tatara-lattice
3710 /// `Lattice for Horizon` impl (which currently dispatches on
3711 /// `self.kind == HorizonKind::Bounded` at three sites) can be
3712 /// recast in a future run to read `self.kind.terminates()` so
3713 /// the lattice basis is the typed primitive rather than a
3714 /// variant-name comparison.
3715 pub const fn terminates(self) -> bool {
3716 match self {
3717 Self::Bounded => true,
3718 Self::Asymptotic => false,
3719 }
3720 }
3721
3722 /// LOAD-BEARING SHAPE-VALIDITY WITNESS: does this kind require
3723 /// the three asymptotic-only [`Horizon`] axes (`metric`,
3724 /// `direction`, `healthy_rate_threshold`) to be `Some(_)`?
3725 /// Closed-set match (not `matches!`) so a future variant
3726 /// triggers the compiler's exhaustiveness check rather than
3727 /// silently defaulting to `false` (which would silently let an
3728 /// asymptotic-shaped variant ship with missing metric axes and
3729 /// trip the rate-window evaluator at runtime). `Bounded ⇒
3730 /// false`, `Asymptotic ⇒ true` is the typed image of the
3731 /// optionality the [`Horizon`] struct encodes via three
3732 /// `Option<…>` fields — the implicit invariant ("Asymptotic
3733 /// only" in the field docs) is now a checkable per-kind
3734 /// predicate. Future horizon-shape validators (CRD admission,
3735 /// `tatara-check` form linter, Lisp authoring-time predicate)
3736 /// read this rather than re-deriving from variant names.
3737 /// Pinned as the antisymmetric partner of [`Self::terminates`]
3738 /// — exactly one of `(terminates, requires_metric_axes)` is
3739 /// true per variant — by
3740 /// `horizon_kind_terminate_xor_requires_metric_axes`.
3741 pub const fn requires_metric_axes(self) -> bool {
3742 match self {
3743 Self::Bounded => false,
3744 Self::Asymptotic => true,
3745 }
3746 }
3747}
3748
3749// `impl FromStr for HorizonKind` +
3750// `impl tatara_lisp::ClosedSet for HorizonKind` +
3751// `impl std::fmt::Display for HorizonKind` +
3752// `pub struct UnknownHorizonKind(pub String)` are all generated by
3753// `#[derive(tatara_closed_set::DeriveClosedSet)]` +
3754// `#[closed_set(via = "as_str", generate_unknown, display)]` on the
3755// enum declaration above. The auto-derived carrier label "horizon
3756// kind" matches the prior hand-rolled `#[error("unknown horizon
3757// kind: {0}")]` annotation byte-for-byte. See the retrofit comment
3758// block on [`ConvergencePointType`] for the canonical narrative.
3759
3760impl Horizon {
3761 pub fn bounded() -> Self {
3762 Self::default()
3763 }
3764
3765 pub fn asymptotic(
3766 metric: impl Into<String>,
3767 direction: OptimizationDirection,
3768 threshold: f64,
3769 ) -> Self {
3770 Self {
3771 kind: HorizonKind::Asymptotic,
3772 metric: Some(metric.into()),
3773 direction: Some(direction),
3774 healthy_rate_threshold: Some(threshold),
3775 }
3776 }
3777}
3778
3779/// Direction of asymptotic optimization — does the metric trend
3780/// downward (cost / latency / error rate) or upward
3781/// (throughput / coverage / revenue)?
3782///
3783/// Closed-set sibling on the classification axis algebra; the `ALL` /
3784/// `as_str` / Display / `FromStr` triad mirrors
3785/// [`ConvergencePointType::ALL`], [`SubstrateType::ALL`],
3786/// [`DataClassification::ALL`], [`CalmClassification::ALL`],
3787/// [`crate::pool::PoolPhase::ALL`], [`crate::pool::MemberState::ALL`],
3788/// [`crate::pool::ReplacementPolicy::ALL`],
3789/// [`crate::pool::ReturnPolicy::ALL`],
3790/// [`crate::boundary::ConditionKind::ALL`],
3791/// [`crate::lifetime::TeardownPolicy::ALL`],
3792/// [`crate::lifetime::LifetimeKind::ALL`],
3793/// [`crate::intent::IntentKind::ALL`],
3794/// [`crate::phase::ProcessPhase::ALL`],
3795/// [`crate::signal::ProcessSignal::ALL`]. The
3796/// [`Self::is_improvement`] predicate is the load-bearing
3797/// optimization primitive — `Asymptotic` horizons read it as the
3798/// typed image of "did this metric sample improve over the last
3799/// one?" rather than re-deriving `<` vs `>` from the variant name
3800/// at every consumer site (rate-window evaluators, breathe-band
3801/// regression detectors, asymptotic-health probes).
3802#[derive(
3803 Clone,
3804 Copy,
3805 Debug,
3806 PartialEq,
3807 Eq,
3808 Hash,
3809 Serialize,
3810 Deserialize,
3811 JsonSchema,
3812 Default,
3813 tatara_closed_set::DeriveClosedSet,
3814)]
3815#[serde(rename_all = "PascalCase")]
3816#[closed_set(via = "as_str", generate_unknown, display)]
3817pub enum OptimizationDirection {
3818 /// Cost / latency / error rate — lower is better. The default for
3819 /// an under-specified `Asymptotic` horizon so an unannotated
3820 /// metric can't silently flip the rate-window evaluator's polarity
3821 /// (a future `Maximize`-default-via-rename would silently invert
3822 /// every existing alert that treats decreasing rate as healthy).
3823 #[default]
3824 Minimize,
3825 /// Throughput / coverage / revenue — higher is better.
3826 Maximize,
3827}
3828
3829impl OptimizationDirection {
3830 /// The closed set of optimization directions — single source of
3831 /// truth that drives the `as_str` / Display / `FromStr` triad AND
3832 /// the `prefers_lower` partition AND the `is_improvement`
3833 /// load-bearing primitive AND both `From` bridge arms. Adding a
3834 /// third variant (e.g. a `Stabilize` sentinel for "drive toward
3835 /// a target value", which neither minimization nor maximization
3836 /// names) lands at one `ALL` entry + one `as_str` arm + one
3837 /// `prefers_lower` arm + one `is_improvement` arm + two bridge
3838 /// arms — exhaustively checked by the compiler (the `[Self; 2]`
3839 /// array literal forces the arity) AND by the per-variant
3840 /// truth-table tests (a new variant must declare its own
3841 /// improvement semantics, or every asymptotic-health probe will
3842 /// silently bucket it). Closes the load-bearing classification
3843 /// sub-axis that the `Horizon.direction` field threads through
3844 /// every `Asymptotic` Process.
3845 pub const ALL: [Self; 2] = [Self::Minimize, Self::Maximize];
3846
3847 /// Canonical PascalCase wire-format projection — matches the serde
3848 /// `rename_all = "PascalCase"` output verbatim AND the CRD `enum:`
3849 /// enumeration the Process schema stamps on
3850 /// `spec.classification.horizon.direction`. Pinned by
3851 /// `optimization_direction_as_str_matches_serde` so a variant
3852 /// rename can't drift between the typed surface, the CRD enum, the
3853 /// YAML wire format AND any future operator-facing diagnostic
3854 /// composed as `direction={kind}` via Display rather than a
3855 /// hard-coded literal. Display + `FromStr` triad over `ALL`
3856 /// mirrors every sibling closed-set enum in this crate.
3857 pub const fn as_str(self) -> &'static str {
3858 match self {
3859 Self::Minimize => "Minimize",
3860 Self::Maximize => "Maximize",
3861 }
3862 }
3863
3864 /// Does this direction prefer numerically lower values?
3865 /// Closed-set match (not `matches!`) so a future variant triggers
3866 /// the compiler's exhaustiveness check at this site rather than
3867 /// silently defaulting to `false` (which would mis-bucket a
3868 /// `Stabilize`-style variant onto the maximization path). The
3869 /// boolean partition is the algebraic shape of an optimization
3870 /// direction: `Minimize ⇒ true`, `Maximize ⇒ false`. Mirrors
3871 /// [`CalmClassification::requires_coordination`] — a two-variant
3872 /// truth-table that any future dispatch on a per-direction policy
3873 /// (rate-window evaluator polarity, breathe-band regression
3874 /// detector sign, asymptotic-health threshold direction) reads
3875 /// once rather than re-deriving from the variant name.
3876 pub const fn prefers_lower(self) -> bool {
3877 match self {
3878 Self::Minimize => true,
3879 Self::Maximize => false,
3880 }
3881 }
3882
3883 /// POSITIVE-FRAMING PEER of [`Self::prefers_lower`] — does this
3884 /// direction prefer numerically higher values? Closed-set match
3885 /// (not `matches!`) so a future variant triggers the compiler's
3886 /// exhaustiveness check at this site rather than silently
3887 /// defaulting to `false` (which would mis-bucket a `Stabilize`-
3888 /// style variant onto the minimization path). The boolean
3889 /// partition is the antisymmetric image of [`Self::prefers_lower`]:
3890 /// `Minimize ⇒ false`, `Maximize ⇒ true`. Exactly one of
3891 /// `(prefers_lower, prefers_higher)` is true per variant on the
3892 /// current two-variant closed set — pinned by
3893 /// `optimization_direction_prefers_lower_xor_prefers_higher` —
3894 /// exactly the binary XOR partition already sealed on the sibling
3895 /// calm axis by `calm_classification_monotone_xor_requires_coordination`
3896 /// and on the sibling data axis by `data_classification_public_xor_restricted`.
3897 /// Structural mirror of [`CalmClassification::is_monotone`] as the
3898 /// positive-framing peer that any future dispatch on the higher-
3899 /// is-better polarity (throughput / coverage / revenue rate-window
3900 /// evaluator, breathe-band regression detector's positive sign)
3901 /// reads once rather than re-deriving from either the variant name
3902 /// or the `!prefers_lower()` inversion at each callsite.
3903 ///
3904 /// A future third variant (a hypothetical `Stabilize` sentinel for
3905 /// "drive toward a target value", which neither minimization nor
3906 /// maximization names) MUST answer `false` here — matching the
3907 /// antisymmetric complement on [`Self::prefers_lower`] so the
3908 /// binary XOR partition either extends into a ternary partition
3909 /// deliberately (adding a third derived-nullary predicate on the
3910 /// closed set) OR the author flips one of the existing predicates
3911 /// to reclaim the XOR. The exhaustiveness check plus the XOR pin
3912 /// force the decision at the closed set rather than silently
3913 /// bucketing the new variant onto an existing polarity.
3914 pub const fn prefers_higher(self) -> bool {
3915 match self {
3916 Self::Minimize => false,
3917 Self::Maximize => true,
3918 }
3919 }
3920
3921 /// LOAD-BEARING OPTIMIZATION PRIMITIVE: under this direction, is
3922 /// `after` strictly better than `before`? Closed-set match so a
3923 /// future variant triggers the compiler's exhaustiveness check
3924 /// rather than silently defaulting to `false` (which would
3925 /// silently mark every sample as a regression). For `Minimize`,
3926 /// improvement means `after < before`; for `Maximize`, `after >
3927 /// before`. Strict inequality so a no-op sample (equal values) is
3928 /// NOT counted as improvement — pinned by
3929 /// `optimization_direction_no_op_is_not_improvement`, which
3930 /// guarantees a flatlined rate-window evaluator doesn't silently
3931 /// keep claiming "still improving" forever and skipping the
3932 /// healthy-rate-threshold gate. NaN on either operand short-
3933 /// circuits to `false` (no improvement claim from indeterminate
3934 /// data) via the standard `PartialOrd` behavior — pinned by
3935 /// `optimization_direction_nan_is_not_improvement`. The
3936 /// asymmetry contract (`is_improvement(a, b)` xor
3937 /// `is_improvement(b, a)` for distinct finite samples) is pinned
3938 /// by `optimization_direction_is_improvement_is_antisymmetric`,
3939 /// the algebraic shape that every asymptotic-health rate-window
3940 /// evaluator depends on to avoid double-counting an improvement
3941 /// as a regression on the reverse traversal.
3942 pub fn is_improvement(self, before: f64, after: f64) -> bool {
3943 match self {
3944 Self::Minimize => after < before,
3945 Self::Maximize => after > before,
3946 }
3947 }
3948}
3949
3950// `impl FromStr for OptimizationDirection` +
3951// `impl tatara_lisp::ClosedSet for OptimizationDirection` +
3952// `impl std::fmt::Display for OptimizationDirection` +
3953// `pub struct UnknownOptimizationDirection(pub String)` are all
3954// generated by `#[derive(tatara_closed_set::DeriveClosedSet)]` +
3955// `#[closed_set(via = "as_str", generate_unknown, display)]` on the
3956// enum declaration above. The auto-derived carrier label
3957// "optimization direction" matches the prior hand-rolled
3958// `#[error("unknown optimization direction: {0}")]` annotation
3959// byte-for-byte. See the retrofit comment block on
3960// [`ConvergencePointType`] for the canonical narrative.
3961
3962/// CALM theorem classification — determines whether coordination is required.
3963///
3964/// Closed-set sibling on the classification axis algebra; the `ALL` /
3965/// `as_str` / Display / `FromStr` triad mirrors
3966/// [`ConvergencePointType::ALL`], [`SubstrateType::ALL`],
3967/// [`DataClassification::ALL`], [`crate::pool::PoolPhase::ALL`],
3968/// [`crate::pool::MemberState::ALL`], [`crate::pool::ReplacementPolicy::ALL`],
3969/// [`crate::pool::ReturnPolicy::ALL`],
3970/// [`crate::boundary::ConditionKind::ALL`],
3971/// [`crate::lifetime::TeardownPolicy::ALL`],
3972/// [`crate::lifetime::LifetimeKind::ALL`],
3973/// [`crate::intent::IntentKind::ALL`],
3974/// [`crate::phase::ProcessPhase::ALL`],
3975/// [`crate::signal::ProcessSignal::ALL`]. The
3976/// [`Self::requires_coordination`] predicate is the CALM theorem
3977/// keystone — Hellerstein's "Consistency As Logical Monotonicity"
3978/// states that a program can be distributed without coordination iff
3979/// it computes a monotone function, so `Monotone ⇒ no coordination`
3980/// and `NonMonotone ⇒ requires coordination` is a typed image of the
3981/// theorem itself rather than a runtime convention. Future reconciler
3982/// dispatch on `calm.requires_coordination()` (Raft for non-monotone
3983/// writes; gossip for monotone ones) reads this projection rather
3984/// than re-deriving from variant names.
3985#[derive(
3986 Clone,
3987 Copy,
3988 Debug,
3989 PartialEq,
3990 Eq,
3991 Hash,
3992 Serialize,
3993 Deserialize,
3994 JsonSchema,
3995 Default,
3996 tatara_closed_set::DeriveClosedSet,
3997)]
3998#[serde(rename_all = "PascalCase")]
3999#[closed_set(via = "as_str", generate_unknown, display)]
4000pub enum CalmClassification {
4001 /// Can be distributed without coordination (CALM ⇒ the program
4002 /// computes a monotone function).
4003 #[default]
4004 Monotone,
4005 /// Requires coordination (CALM ⇒ the program is not monotone).
4006 NonMonotone,
4007}
4008
4009impl CalmClassification {
4010 /// The closed set of CALM classifications — single source of truth
4011 /// that drives the `as_str` / Display / `FromStr` triad AND the
4012 /// `requires_coordination` predicate. Adding a third variant
4013 /// (e.g. a `ConditionallyMonotone` sentinel for ops that are
4014 /// monotone under a witness, like CRDT joins under a fixed
4015 /// schema) lands at one `ALL` entry + one `as_str` arm + one
4016 /// predicate arm + one bridge-pair arm — exhaustively checked by
4017 /// the compiler (the `[Self; 2]` array literal forces the arity)
4018 /// AND by the per-variant predicate truth-table test (a new
4019 /// variant must declare its own coordination requirement or any
4020 /// future reconciler-side dispatch will silently bucket it).
4021 /// Closes the load-bearing classification-axis enum that the
4022 /// `Classification.calm` field exposes to every Process and that
4023 /// [`tatara_lattice`]'s boolean-lattice `Lattice for
4024 /// CalmClassification` impl reads via [`Self::requires_coordination`]
4025 /// as the lattice's `top()` predicate.
4026 pub const ALL: [Self; 2] = [Self::Monotone, Self::NonMonotone];
4027
4028 /// Canonical PascalCase wire-format projection — matches the
4029 /// serde `rename_all = "PascalCase"` output verbatim AND the CRD
4030 /// `enum:` enumeration that the Process schema stamps on
4031 /// `spec.classification.calm`. Pinned by
4032 /// `calm_classification_as_str_matches_serde` so a variant rename
4033 /// can't drift between the typed surface, the CRD enum, the YAML
4034 /// wire format AND any future operator-facing diagnostic that
4035 /// composes `calm={kind}` via Display rather than a hard-coded
4036 /// literal that would silently rot. Display + FromStr triad over
4037 /// `ALL` mirrors every sibling closed-set enum in this crate.
4038 pub const fn as_str(self) -> &'static str {
4039 match self {
4040 Self::Monotone => "Monotone",
4041 Self::NonMonotone => "NonMonotone",
4042 }
4043 }
4044
4045 /// CALM-THEOREM KEYSTONE: does this classification require
4046 /// distributed coordination? Closed-set match (not `matches!`) so
4047 /// a future variant triggers the compiler's exhaustiveness check
4048 /// at this site rather than silently defaulting to `false` and
4049 /// shipping a non-monotone operation onto the no-coordination
4050 /// path. The theorem (Hellerstein 2010) states that a program can
4051 /// be distributed without coordination iff it computes a monotone
4052 /// function — `Monotone ⇒ false` and `NonMonotone ⇒ true` is the
4053 /// typed image of that biconditional. Consumers (future reconciler
4054 /// dispatch between Raft writes and gossip propagation; current
4055 /// `tatara_lattice` boolean-lattice ordering where `Monotone ≤
4056 /// NonMonotone`) read this predicate rather than re-deriving from
4057 /// variant names.
4058 pub const fn requires_coordination(self) -> bool {
4059 match self {
4060 Self::Monotone => false,
4061 Self::NonMonotone => true,
4062 }
4063 }
4064
4065 /// CALM-THEOREM POSITIVE FRAMING: is this classification monotone
4066 /// — i.e. can it be distributed WITHOUT coordination per the
4067 /// biconditional half of Hellerstein's CALM theorem
4068 /// (Consistency As Logical Monotonicity)? Closed-set match (not
4069 /// `matches!`) so a future variant triggers the compiler's
4070 /// exhaustiveness check at this site rather than silently
4071 /// defaulting to `false` (which would silently mark a genuinely
4072 /// monotone operation as coordination-required and pay the Raft
4073 /// tax indefinitely) or `true` (which would silently ship a non-
4074 /// monotone operation onto the no-coordination path). The typed
4075 /// image of the theorem's LOAD-BEARING half: `Monotone ⇒ true`
4076 /// and `NonMonotone ⇒ false` is the antisymmetric partner of
4077 /// [`Self::requires_coordination`] — exactly one of
4078 /// `(is_monotone, requires_coordination)` is true per variant —
4079 /// pinned by `calm_classification_monotone_xor_requires_coordination`.
4080 /// Mirror of [`HorizonKind::terminates`] /
4081 /// [`HorizonKind::requires_metric_axes`] on the horizon axis:
4082 /// both closed sets are binary and both publish their two
4083 /// derived-nullary-bool projections at ONE site each so the axis
4084 /// carves into complementary buckets by construction. The
4085 /// positive framing is the substrate primitive Hellerstein
4086 /// himself names ("Consistency As Logical Monotonicity"); a
4087 /// future consumer asking "can this Process participate in
4088 /// gossip-only writes?" reads [`Self::is_monotone`] rather than
4089 /// re-deriving via `!requires_coordination()` at the callsite.
4090 pub const fn is_monotone(self) -> bool {
4091 match self {
4092 Self::Monotone => true,
4093 Self::NonMonotone => false,
4094 }
4095 }
4096}
4097
4098// `impl FromStr for CalmClassification` +
4099// `impl tatara_lisp::ClosedSet for CalmClassification` +
4100// `impl std::fmt::Display for CalmClassification` +
4101// `pub struct UnknownCalmClassification(pub String)` are all generated
4102// by `#[derive(tatara_closed_set::DeriveClosedSet)]` +
4103// `#[closed_set(via = "as_str", generate_unknown, display)]` on the
4104// enum declaration above. The auto-derived carrier label
4105// "calm classification" matches the prior hand-rolled
4106// `#[error("unknown calm classification: {0}")]` annotation
4107// byte-for-byte. See the retrofit comment block on
4108// [`ConvergencePointType`] for the canonical narrative.
4109
4110/// Data sensitivity, drives compliance baseline selection.
4111///
4112/// Sibling closed-set on the classification axis algebra; the `ALL` /
4113/// `as_str` / Display / `FromStr` triad mirrors
4114/// [`crate::pool::PoolPhase::ALL`], [`crate::pool::MemberState::ALL`],
4115/// [`crate::pool::ReplacementPolicy::ALL`],
4116/// [`crate::pool::ReturnPolicy::ALL`],
4117/// [`crate::boundary::ConditionKind::ALL`],
4118/// [`crate::lifetime::TeardownPolicy::ALL`],
4119/// [`crate::lifetime::LifetimeKind::ALL`],
4120/// [`crate::intent::IntentKind::ALL`],
4121/// [`crate::phase::ProcessPhase::ALL`],
4122/// [`crate::signal::ProcessSignal::ALL`].
4123#[derive(
4124 Clone,
4125 Copy,
4126 Debug,
4127 PartialEq,
4128 Eq,
4129 PartialOrd,
4130 Ord,
4131 Hash,
4132 Serialize,
4133 Deserialize,
4134 JsonSchema,
4135 Default,
4136 tatara_closed_set::DeriveClosedSet,
4137)]
4138#[serde(rename_all = "PascalCase")]
4139#[closed_set(via = "as_str", generate_unknown, display)]
4140pub enum DataClassification {
4141 Public,
4142 #[default]
4143 Internal,
4144 Confidential,
4145 Pii,
4146 Phi,
4147 Pci,
4148}
4149
4150impl DataClassification {
4151 /// The closed set of data classifications — single source of truth
4152 /// that drives the `as_str` / Display / `FromStr` triad AND the
4153 /// `sensitivity_rank` total-order projection AND the
4154 /// `is_restricted` / `is_regulated` predicate pair. Adding a
4155 /// seventh variant lands at one `ALL` entry + one `as_str` arm +
4156 /// one `sensitivity_rank` arm + one arm per predicate —
4157 /// exhaustively checked by the compiler (the `[Self; 6]` array
4158 /// literal forces the arity) AND by the per-variant truth-table
4159 /// contract test (a new variant must declare its own
4160 /// `(is_restricted, is_regulated)` bucket or any future
4161 /// compliance-baseline auto-selector that dispatches on the pair
4162 /// will silently bucket it into the wrong sensitivity column).
4163 /// This closes the sixth classification-axis enum and the closure
4164 /// is consumed by [`tatara_lattice`]'s total-order `Lattice` impl
4165 /// via [`Self::sensitivity_rank`] so the lattice ordering no
4166 /// longer rides silently on declaration order.
4167 pub const ALL: [Self; 6] = [
4168 Self::Public,
4169 Self::Internal,
4170 Self::Confidential,
4171 Self::Pii,
4172 Self::Phi,
4173 Self::Pci,
4174 ];
4175
4176 /// Canonical PascalCase wire-format projection — matches the
4177 /// serde `rename_all = "PascalCase"` output verbatim AND the CRD
4178 /// `enum:` enumeration that the Process schema stamps on
4179 /// `spec.classification.dataClassification`. Pinned by
4180 /// `data_classification_as_str_matches_serde` so a variant rename
4181 /// can't drift between the typed surface, the CRD enum, the YAML
4182 /// wire format AND any future operator-facing diagnostic that
4183 /// composes `dataClassification={class}` via Display rather than
4184 /// a hard-coded literal that would silently rot. Display +
4185 /// FromStr triad over `ALL` mirrors `PoolPhase` / `MemberState` /
4186 /// `ReplacementPolicy` / `ReturnPolicy` / `TeardownPolicy` /
4187 /// `ConditionKind` / `ProcessPhase` / `ProcessSignal`.
4188 pub const fn as_str(self) -> &'static str {
4189 match self {
4190 Self::Public => "Public",
4191 Self::Internal => "Internal",
4192 Self::Confidential => "Confidential",
4193 Self::Pii => "Pii",
4194 Self::Phi => "Phi",
4195 Self::Pci => "Pci",
4196 }
4197 }
4198
4199 /// Explicit total-order rank, sealed at one site so the lattice
4200 /// ordering stops riding silently on declaration order. Pre-lift
4201 /// the tatara-lattice `Lattice for DataClassification` impl
4202 /// compared variants via `(*self as u8) <= (*other as u8)`, so a
4203 /// future variant inserted in the middle of the enum (say a
4204 /// `Restricted` between `Internal` and `Confidential`) would
4205 /// silently shift every subsequent variant's `as u8` value AND
4206 /// the lattice's `leq` relation — no compile error, no test
4207 /// failure, but every compliance-baseline comparison
4208 /// downstream would have moved by one slot. Post-lift the rank
4209 /// is declared explicitly per variant; an insertion forces the
4210 /// author to pick a rank deliberately (and
4211 /// `data_classification_rank_is_strictly_monotone_over_all`
4212 /// pins the existing six variants at 0..6 so the lattice's
4213 /// total order remains the documented
4214 /// `Public < Internal < Confidential < Pii < Phi < Pci`).
4215 pub const fn sensitivity_rank(self) -> u8 {
4216 match self {
4217 Self::Public => 0,
4218 Self::Internal => 1,
4219 Self::Confidential => 2,
4220 Self::Pii => 3,
4221 Self::Phi => 4,
4222 Self::Pci => 5,
4223 }
4224 }
4225
4226 /// Is this classification subject to external regulatory regime
4227 /// (HIPAA / PCI-DSS / GDPR-style data-subject controls)?
4228 /// Closed-set match (not `matches!`) so a future variant triggers
4229 /// the compiler's exhaustiveness check at this site rather than
4230 /// silently defaulting to `false`. Paired with `is_restricted`
4231 /// they form the two-axis projection that future
4232 /// compliance-baseline auto-selectors dispatch against —
4233 /// `(false, false)` ⇒ freely distributable (`Public`);
4234 /// `(false, true)` ⇒ access-controlled but not regulated
4235 /// (`Internal | Confidential`); `(true, true)` ⇒ regulated data
4236 /// that implies access control (`Pii | Phi | Pci`). The
4237 /// impossible bucket `(true, false)` — regulated data without
4238 /// access control — is pinned empty by
4239 /// `data_classification_regulated_implies_restricted`.
4240 pub const fn is_regulated(self) -> bool {
4241 match self {
4242 Self::Pii | Self::Phi | Self::Pci => true,
4243 Self::Public | Self::Internal | Self::Confidential => false,
4244 }
4245 }
4246
4247 /// Does this classification require access controls beyond
4248 /// freely-distributable? Closed-set match so a future variant
4249 /// triggers the compiler's exhaustiveness check. See
4250 /// `is_regulated` for the predicate-pair contract + bucket
4251 /// definitions.
4252 pub const fn is_restricted(self) -> bool {
4253 match self {
4254 Self::Public => false,
4255 Self::Internal | Self::Confidential | Self::Pii | Self::Phi | Self::Pci => true,
4256 }
4257 }
4258
4259 /// POSITIVE-FRAMING PEER of [`Self::is_restricted`] — is this
4260 /// classification freely distributable (i.e. bearing no access-
4261 /// control requirement)? Closed-set match (not `matches!`) so a
4262 /// future variant triggers the compiler's exhaustiveness check at
4263 /// this site rather than silently defaulting to `false` (silently
4264 /// marking a genuinely-public dataset as restricted and paying the
4265 /// access-control tax indefinitely) or `true` (silently shipping a
4266 /// restricted or regulated dataset onto the freely-distributable
4267 /// path — a compliance-catastrophic mislabel). The typed image of
4268 /// the "freely distributable?" question: `Public ⇒ true` and every
4269 /// other variant `⇒ false` is the antisymmetric partner of
4270 /// [`Self::is_restricted`] — exactly one of
4271 /// `(is_public, is_restricted)` is true per variant — pinned by
4272 /// `data_classification_public_xor_restricted`. Mirror of
4273 /// [`CalmClassification::is_monotone`] /
4274 /// [`CalmClassification::requires_coordination`] on the calm axis
4275 /// and [`HorizonKind::terminates`] /
4276 /// [`HorizonKind::requires_metric_axes`] on the horizon axis: each
4277 /// closed set publishes its two derived-nullary-bool projections
4278 /// at ONE site each so the axis carves into complementary buckets
4279 /// by construction. The positive framing is the substrate primitive
4280 /// a compliance auditor asks first ("is this dataset publicly
4281 /// distributable?"); a future consumer answering that question
4282 /// reads [`Self::is_public`] rather than re-deriving via
4283 /// `!is_restricted()` at the callsite. Sealed further against
4284 /// [`Self::is_regulated`] by
4285 /// `data_classification_regulated_implies_not_public` — regulated
4286 /// data is by definition not publicly distributable, the exact
4287 /// closed-set-internal implication that composes forward through
4288 /// both the parent-composed and resolver-hop layers on this axis.
4289 pub const fn is_public(self) -> bool {
4290 match self {
4291 Self::Public => true,
4292 Self::Internal | Self::Confidential | Self::Pii | Self::Phi | Self::Pci => false,
4293 }
4294 }
4295}
4296
4297// `impl FromStr for DataClassification` +
4298// `impl tatara_lisp::ClosedSet for DataClassification` +
4299// `impl std::fmt::Display for DataClassification` +
4300// `pub struct UnknownDataClassification(pub String)` are all generated
4301// by `#[derive(tatara_closed_set::DeriveClosedSet)]` +
4302// `#[closed_set(via = "as_str", generate_unknown, display)]` on the
4303// enum declaration above. The auto-derived carrier label
4304// "data classification" matches the prior hand-rolled
4305// `#[error("unknown data classification: {0}")]` annotation
4306// byte-for-byte. See the retrofit comment block on
4307// [`ConvergencePointType`] for the canonical narrative.
4308
4309// ───────────────────────────── bridges to tatara-core ─────────────────
4310
4311impl From<ConvergencePointType> for core::ConvergencePointType {
4312 fn from(v: ConvergencePointType) -> Self {
4313 use ConvergencePointType::*;
4314 match v {
4315 Transform => Self::Transform,
4316 Fork => Self::Fork,
4317 Join => Self::Join,
4318 Gate => Self::Gate,
4319 Select => Self::Select,
4320 Broadcast => Self::Broadcast,
4321 Reduce => Self::Reduce,
4322 Observe => Self::Observe,
4323 }
4324 }
4325}
4326
4327impl From<core::ConvergencePointType> for ConvergencePointType {
4328 fn from(v: core::ConvergencePointType) -> Self {
4329 use core::ConvergencePointType as C;
4330 match v {
4331 C::Transform => Self::Transform,
4332 C::Fork => Self::Fork,
4333 C::Join => Self::Join,
4334 C::Gate => Self::Gate,
4335 C::Select => Self::Select,
4336 C::Broadcast => Self::Broadcast,
4337 C::Reduce => Self::Reduce,
4338 C::Observe => Self::Observe,
4339 }
4340 }
4341}
4342
4343impl From<SubstrateType> for core::SubstrateType {
4344 fn from(v: SubstrateType) -> Self {
4345 use SubstrateType::*;
4346 match v {
4347 Financial => Self::Financial,
4348 Compute => Self::Compute,
4349 Network => Self::Network,
4350 Storage => Self::Storage,
4351 Security => Self::Security,
4352 Identity => Self::Identity,
4353 Observability => Self::Observability,
4354 Regulatory => Self::Regulatory,
4355 }
4356 }
4357}
4358
4359impl From<core::SubstrateType> for SubstrateType {
4360 fn from(v: core::SubstrateType) -> Self {
4361 use core::SubstrateType as C;
4362 match v {
4363 C::Financial => Self::Financial,
4364 C::Compute => Self::Compute,
4365 C::Network => Self::Network,
4366 C::Storage => Self::Storage,
4367 C::Security => Self::Security,
4368 C::Identity => Self::Identity,
4369 C::Observability => Self::Observability,
4370 C::Regulatory => Self::Regulatory,
4371 }
4372 }
4373}
4374
4375impl From<OptimizationDirection> for core::OptimizationDirection {
4376 fn from(v: OptimizationDirection) -> Self {
4377 match v {
4378 OptimizationDirection::Minimize => Self::Minimize,
4379 OptimizationDirection::Maximize => Self::Maximize,
4380 }
4381 }
4382}
4383
4384impl From<core::OptimizationDirection> for OptimizationDirection {
4385 fn from(v: core::OptimizationDirection) -> Self {
4386 use core::OptimizationDirection as C;
4387 match v {
4388 C::Minimize => Self::Minimize,
4389 C::Maximize => Self::Maximize,
4390 }
4391 }
4392}
4393
4394impl From<Horizon> for core::ConvergenceHorizon {
4395 fn from(v: Horizon) -> Self {
4396 match v.kind {
4397 HorizonKind::Bounded => Self::Bounded,
4398 HorizonKind::Asymptotic => Self::Asymptotic {
4399 metric: v.metric.unwrap_or_default(),
4400 direction: v.direction.unwrap_or_default().into(),
4401 healthy_rate_threshold: v.healthy_rate_threshold.unwrap_or_default(),
4402 },
4403 }
4404 }
4405}
4406
4407impl From<CalmClassification> for core::CalmClassification {
4408 fn from(v: CalmClassification) -> Self {
4409 match v {
4410 CalmClassification::Monotone => Self::Monotone,
4411 CalmClassification::NonMonotone => Self::NonMonotone,
4412 }
4413 }
4414}
4415
4416impl From<core::CalmClassification> for CalmClassification {
4417 fn from(v: core::CalmClassification) -> Self {
4418 use core::CalmClassification as C;
4419 match v {
4420 C::Monotone => Self::Monotone,
4421 C::NonMonotone => Self::NonMonotone,
4422 }
4423 }
4424}
4425
4426impl From<DataClassification> for core_compl::DataClassification {
4427 fn from(v: DataClassification) -> Self {
4428 use DataClassification::*;
4429 match v {
4430 Public => Self::Public,
4431 Internal => Self::Internal,
4432 Confidential => Self::Confidential,
4433 Pii => Self::Pii,
4434 Phi => Self::Phi,
4435 Pci => Self::Pci,
4436 }
4437 }
4438}
4439
4440impl From<core_compl::DataClassification> for DataClassification {
4441 fn from(v: core_compl::DataClassification) -> Self {
4442 use core_compl::DataClassification as C;
4443 match v {
4444 C::Public => Self::Public,
4445 C::Internal => Self::Internal,
4446 C::Confidential => Self::Confidential,
4447 C::Pii => Self::Pii,
4448 C::Phi => Self::Phi,
4449 C::Pci => Self::Pci,
4450 }
4451 }
4452}
4453
4454#[cfg(test)]
4455mod tests {
4456 use super::*;
4457 // The closed-set tests below call `T::from_str(bad)` via the
4458 // derive-generated `FromStr` impls — bring the trait into scope at
4459 // the test module so the lib body doesn't carry an otherwise-unused
4460 // `use std::str::FromStr;` at the file head.
4461 use std::str::FromStr;
4462
4463 #[test]
4464 fn bridges_roundtrip() {
4465 let pt: core::ConvergencePointType = ConvergencePointType::Gate.into();
4466 let back: ConvergencePointType = pt.into();
4467 assert_eq!(back, ConvergencePointType::Gate);
4468
4469 let sub: core::SubstrateType = SubstrateType::Observability.into();
4470 let back: SubstrateType = sub.into();
4471 assert_eq!(back, SubstrateType::Observability);
4472 }
4473
4474 #[test]
4475 fn data_classification_ordering() {
4476 assert!(DataClassification::Public < DataClassification::Pii);
4477 assert!(DataClassification::Internal < DataClassification::Confidential);
4478 }
4479
4480 #[test]
4481 fn horizon_default_is_bounded() {
4482 assert_eq!(Horizon::default().kind, HorizonKind::Bounded);
4483 }
4484
4485 // ── Classification::gate_compute substrate pins ─────────────────────
4486 //
4487 // The six-line `Classification { point_type: Gate, substrate: Compute,
4488 // horizon: Default::default(), calm: Default::default(),
4489 // data_classification: Default::default() }` struct-literal was
4490 // open-coded verbatim at ten hand-authored callsites before the
4491 // primitive closed it. These pins bind the composed shape at
4492 // fail-before-pass-after granularity so a regression that flipped a
4493 // baseline axis, drifted a sibling default, or leaked a non-baseline
4494 // slot into the substrate composer surfaces HERE rather than as
4495 // silent operator-visible drift at every unadorned ephemeral env
4496 // (the one production consumer, `default_ephemeral_class`) AND every
4497 // downstream test fixture that keys assertions on the shape.
4498
4499 #[test]
4500 fn gate_compute_composes_the_five_baseline_axes() {
4501 // Primary shape: every axis parked at the workspace baseline.
4502 // A regression that flipped `point_type` off `Gate` or
4503 // `substrate` off `Compute` — the two axes with no `Default` —
4504 // surfaces here.
4505 let c = Classification::gate_compute();
4506 assert_eq!(c.point_type, ConvergencePointType::Gate);
4507 assert_eq!(c.substrate, SubstrateType::Compute);
4508 assert_eq!(c.horizon, Horizon::default());
4509 assert_eq!(c.calm, CalmClassification::default());
4510 assert_eq!(c.data_classification, DataClassification::default());
4511 }
4512
4513 #[test]
4514 fn gate_compute_defaulted_axes_ride_sibling_closed_set_defaults() {
4515 // Pins the sibling-default correspondence the doc comment
4516 // names — a regression that flipped a sibling default (a new
4517 // `HorizonKind` variant promoted to `#[default]`, a rename of
4518 // `CalmClassification::Monotone`, a promotion of `Pii` above
4519 // `Internal` in the `DataClassification` ordering) would move
4520 // the baseline HERE rather than at every downstream consumer.
4521 let c = Classification::gate_compute();
4522 assert_eq!(c.horizon.kind, HorizonKind::Bounded);
4523 assert_eq!(c.calm, CalmClassification::Monotone);
4524 assert_eq!(c.data_classification, DataClassification::Internal);
4525 }
4526
4527 #[test]
4528 fn gate_compute_matches_hand_authored_pre_lift_bytewise() {
4529 // Byte-identical parity with the pre-lift six-line struct-literal
4530 // that recurred at ten hand-authored sites. A regression that
4531 // reshaped the primitive would diverge from the pre-lift block
4532 // HERE rather than at every downstream fixture that keys on the
4533 // shape.
4534 let composed = Classification::gate_compute();
4535 let hand_authored = Classification {
4536 point_type: ConvergencePointType::Gate,
4537 substrate: SubstrateType::Compute,
4538 horizon: Horizon::default(),
4539 calm: CalmClassification::default(),
4540 data_classification: DataClassification::default(),
4541 };
4542 assert_eq!(composed, hand_authored);
4543 }
4544
4545 #[test]
4546 fn gate_compute_is_call_time_construction_not_a_shared_singleton() {
4547 // Two independent calls produce structurally-equal but distinct
4548 // values — pins that the primitive is a plain constructor
4549 // rather than a `lazy_static` clone (which would leak a shared
4550 // singleton whose in-place mutation at one consumer would
4551 // silently mutate the shape at every other consumer). The `!=`
4552 // check on `&mut _`-obtained pointer addresses is intentional:
4553 // a shared singleton would collide, and the pin catches the
4554 // regression at the primitive rather than at the operator-facing
4555 // shape-drift downstream.
4556 let a = Classification::gate_compute();
4557 let b = Classification::gate_compute();
4558 assert_eq!(a, b);
4559 assert!(!std::ptr::eq(&a, &b));
4560 }
4561
4562 // ── Classification::gate_compute_with_axis substrate pins ────────
4563 //
4564 // Fail-before-pass-after granularity: `gate_compute_with_axis` did
4565 // not exist before this commit — the (`gate_compute()` with ONE
4566 // axis slot overwritten by a per-test swept variant) shape recurred
4567 // at ≥ 40 hand-authored test-fixture callsites, each restating the
4568 // SAME six-line struct-literal that names FOUR baseline slots
4569 // verbatim and mutates ONE. Post-lift the shape lives at ONE
4570 // substrate primitive that composes `Self::gate_compute` with a
4571 // per-axis overlay through the [`ClassificationAxis`] trait. The
4572 // two pins below fence the primitive's contract:
4573 // (1) at every axis, feeding the baseline-of-that-axis variant
4574 // reconstructs exactly `gate_compute()` byte-for-byte, so the
4575 // overlay is the IDENTITY under baseline input;
4576 // (2) at every axis, feeding a variant mutates ONLY that axis
4577 // slot and leaves the other four at their baseline.
4578 // A regression that crossed the wires between the five per-axis
4579 // impls (silently overlaying the wrong slot) or that broke the
4580 // identity under baseline input (silently drifting the baseline
4581 // slot on a non-baseline overlay) fails HERE at the substrate
4582 // primitive rather than at each of the ≥ 40 downstream test
4583 // callsites that would otherwise silently key an assertion on the
4584 // wrong axis's variant.
4585
4586 #[test]
4587 fn gate_compute_with_axis_is_identity_under_axis_baseline_input() {
4588 // For each axis, feeding the baseline-of-that-axis variant
4589 // reconstructs exactly `gate_compute()`. On the two axes with
4590 // no `Default` (`ConvergencePointType`, `SubstrateType`) the
4591 // baseline is the `gate_compute` chosen value (`Gate`,
4592 // `Compute`); on the three defaulted axes the baseline is the
4593 // sibling closed-set `#[default]` (`Bounded`, `Monotone`,
4594 // `Internal`).
4595 let baseline = Classification::gate_compute();
4596 assert_eq!(
4597 Classification::gate_compute_with_axis(HorizonKind::Bounded),
4598 baseline,
4599 );
4600 assert_eq!(
4601 Classification::gate_compute_with_axis(CalmClassification::Monotone),
4602 baseline,
4603 );
4604 assert_eq!(
4605 Classification::gate_compute_with_axis(DataClassification::Internal),
4606 baseline,
4607 );
4608 assert_eq!(
4609 Classification::gate_compute_with_axis(ConvergencePointType::Gate),
4610 baseline,
4611 );
4612 assert_eq!(
4613 Classification::gate_compute_with_axis(SubstrateType::Compute),
4614 baseline,
4615 );
4616 }
4617
4618 #[test]
4619 fn gate_compute_with_axis_mutates_only_the_named_axis_slot() {
4620 // For each axis, sweep every variant and pin that the four
4621 // sibling axis slots stay at their `gate_compute` baseline
4622 // while only the named axis slot carries the swept variant.
4623 // A regression that crossed the per-axis impls (a
4624 // `ClassificationAxis for HorizonKind` body that mutated
4625 // `c.calm` instead of `c.horizon.kind`, or a swap between
4626 // `data_classification` and `calm` impls) fails HERE.
4627 let baseline = Classification::gate_compute();
4628 for populated in HorizonKind::ALL {
4629 let c = Classification::gate_compute_with_axis(populated);
4630 assert_eq!(c.horizon.kind, populated);
4631 assert_eq!(c.calm, baseline.calm);
4632 assert_eq!(c.data_classification, baseline.data_classification);
4633 assert_eq!(c.point_type, baseline.point_type);
4634 assert_eq!(c.substrate, baseline.substrate);
4635 }
4636 for populated in CalmClassification::ALL {
4637 let c = Classification::gate_compute_with_axis(populated);
4638 assert_eq!(c.calm, populated);
4639 assert_eq!(c.horizon, baseline.horizon);
4640 assert_eq!(c.data_classification, baseline.data_classification);
4641 assert_eq!(c.point_type, baseline.point_type);
4642 assert_eq!(c.substrate, baseline.substrate);
4643 }
4644 for populated in DataClassification::ALL {
4645 let c = Classification::gate_compute_with_axis(populated);
4646 assert_eq!(c.data_classification, populated);
4647 assert_eq!(c.horizon, baseline.horizon);
4648 assert_eq!(c.calm, baseline.calm);
4649 assert_eq!(c.point_type, baseline.point_type);
4650 assert_eq!(c.substrate, baseline.substrate);
4651 }
4652 for populated in ConvergencePointType::ALL {
4653 let c = Classification::gate_compute_with_axis(populated);
4654 assert_eq!(c.point_type, populated);
4655 assert_eq!(c.horizon, baseline.horizon);
4656 assert_eq!(c.calm, baseline.calm);
4657 assert_eq!(c.data_classification, baseline.data_classification);
4658 assert_eq!(c.substrate, baseline.substrate);
4659 }
4660 for populated in SubstrateType::ALL {
4661 let c = Classification::gate_compute_with_axis(populated);
4662 assert_eq!(c.substrate, populated);
4663 assert_eq!(c.horizon, baseline.horizon);
4664 assert_eq!(c.calm, baseline.calm);
4665 assert_eq!(c.data_classification, baseline.data_classification);
4666 assert_eq!(c.point_type, baseline.point_type);
4667 }
4668 }
4669
4670 // ── Classification::with_axis chaining primitive pins ────────────
4671 //
4672 // Fail-before-pass-after granularity: `with_axis` did not exist
4673 // before this commit — the (Classification, N-axis-conjunction)
4674 // construction shape recurred at ≥ 5 hand-authored test-fixture
4675 // callsites in this file (Fork+Storage, Fork+Storage+NonMonotone,
4676 // Fork+Storage+NonMonotone+Pii, +HorizonKind::Asymptotic,
4677 // +direction=Maximize) each restating the FIVE-field struct-
4678 // literal (`point_type`, `substrate`, `horizon`, `calm`,
4679 // `data_classification`) verbatim with distinct axis conjunctions.
4680 // Post-lift the shape lives at ONE substrate primitive that
4681 // post-composes ONE additional [`ClassificationAxis`] overlay onto
4682 // an arbitrary [`Classification`] carrier through the SAME trait
4683 // dispatch [`Classification::gate_compute_with_axis`] uses for the
4684 // start-from-baseline single-axis overlay. The pins below fence
4685 // the primitive's contract:
4686 // (1) chaining N distinct-slot axes onto `gate_compute_with_axis(x)`
4687 // produces the SAME [`Classification`] as populating every
4688 // slot at once via a hand-authored struct-literal;
4689 // (2) chaining any permutation of a fixed set of distinct-slot
4690 // axes produces the SAME [`Classification`] (order-independent
4691 // across distinct slots);
4692 // (3) the [`OptimizationDirection`] sub-slot overlay PRESERVES the
4693 // [`HorizonKind`] sub-slot's prior overlay (both slots live on
4694 // the nested `Horizon` struct — a stomping overlay would drop
4695 // `direction` to `None` on `.with_axis(HorizonKind::_)`).
4696
4697 #[test]
4698 fn with_axis_chains_multi_axis_overlays_matching_open_coded_struct_literal() {
4699 // Chain the six-axis conjunction (point_type + substrate +
4700 // calm + data_classification + horizon.kind + horizon.direction)
4701 // through `with_axis` and pin byte-identical parity with the
4702 // open-coded FIVE-field struct-literal + nested `Horizon`
4703 // struct-literal that recurred at the six-axis-independence
4704 // test-fixture callsite. A regression that (a) mis-routed one
4705 // `ClassificationAxis::overlay` impl (a stray slot assignment),
4706 // (b) stomped a prior overlay (the [`HorizonKind`] impl
4707 // resetting the whole nested `Horizon`), or (c) collapsed the
4708 // fluent chain onto a single-axis overlay (only the last axis
4709 // takes effect) would drop parity here.
4710 let composed = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
4711 .with_axis(SubstrateType::Storage)
4712 .with_axis(CalmClassification::NonMonotone)
4713 .with_axis(DataClassification::Pii)
4714 .with_axis(HorizonKind::Asymptotic)
4715 .with_axis(OptimizationDirection::Maximize);
4716 let hand_authored = Classification {
4717 point_type: ConvergencePointType::Fork,
4718 substrate: SubstrateType::Storage,
4719 horizon: Horizon {
4720 kind: HorizonKind::Asymptotic,
4721 direction: Some(OptimizationDirection::Maximize),
4722 ..Horizon::default()
4723 },
4724 calm: CalmClassification::NonMonotone,
4725 data_classification: DataClassification::Pii,
4726 };
4727 assert_eq!(composed, hand_authored);
4728 }
4729
4730 #[test]
4731 fn with_axis_is_order_independent_across_distinct_slot_axes() {
4732 // Chain the same set of five distinct-slot axes in TWO
4733 // permutations and pin byte-identical parity. A regression
4734 // that leaked cross-slot dependency into an overlay impl (a
4735 // stray [`ConvergencePointType`] impl mutating `c.substrate`,
4736 // a stray [`DataClassification`] impl mutating `c.calm`, or
4737 // any impl that read from another slot before writing its
4738 // own) would drop parity here — an order-dependent overlay
4739 // means the impls are not commutative, which the
4740 // (distinct-slot × per-slot-overlay) contract requires. The
4741 // horizon-nested (`HorizonKind`, `OptimizationDirection`)
4742 // pair is deliberately NOT included in either permutation
4743 // here — that pair lives on the SAME nested-struct slot and
4744 // has an ordering constraint tested by
4745 // `with_axis_optimization_direction_overlay_preserves_horizon_kind_overlay`
4746 // below.
4747 let axes_forward = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
4748 .with_axis(SubstrateType::Storage)
4749 .with_axis(CalmClassification::NonMonotone)
4750 .with_axis(DataClassification::Pii)
4751 .with_axis(HorizonKind::Asymptotic);
4752 let axes_reversed = Classification::gate_compute_with_axis(HorizonKind::Asymptotic)
4753 .with_axis(DataClassification::Pii)
4754 .with_axis(CalmClassification::NonMonotone)
4755 .with_axis(SubstrateType::Storage)
4756 .with_axis(ConvergencePointType::Fork);
4757 assert_eq!(axes_forward, axes_reversed);
4758 }
4759
4760 #[test]
4761 fn with_axis_optimization_direction_overlay_preserves_horizon_kind_overlay() {
4762 // Chain `HorizonKind::Asymptotic` THEN
4763 // `OptimizationDirection::Maximize` — both overlays live on
4764 // the SAME nested `Horizon` struct's distinct sub-slots
4765 // (`kind`, `direction`). Pin that the second overlay
4766 // PRESERVES the first. A regression that either (a) reverted
4767 // [`ClassificationAxis for HorizonKind`] to the pre-change
4768 // whole-`Horizon`-reset shape (which would drop `direction`
4769 // to `None` if that overlay ran after `direction` was set) —
4770 // pinned via `.with_axis(Maximize).with_axis(Asymptotic)`
4771 // below — or (b) wrote `OptimizationDirection::overlay`
4772 // through a whole-`Horizon` reset (which would drop `kind`
4773 // to `HorizonKind::default()` — Bounded — on this call
4774 // sequence) would fail HERE. Also pins the byte-symmetric
4775 // reverse ordering `.with_axis(Maximize).with_axis(Asymptotic)`
4776 // preserves `direction: Some(Maximize)` — the sub-slot
4777 // overlays are commutative on the nested struct.
4778 let forward = Classification::gate_compute_with_axis(HorizonKind::Asymptotic)
4779 .with_axis(OptimizationDirection::Maximize);
4780 assert_eq!(forward.horizon.kind, HorizonKind::Asymptotic);
4781 assert_eq!(
4782 forward.horizon.direction,
4783 Some(OptimizationDirection::Maximize),
4784 );
4785
4786 let reversed = Classification::gate_compute_with_axis(OptimizationDirection::Maximize)
4787 .with_axis(HorizonKind::Asymptotic);
4788 assert_eq!(reversed.horizon.kind, HorizonKind::Asymptotic);
4789 assert_eq!(
4790 reversed.horizon.direction,
4791 Some(OptimizationDirection::Maximize),
4792 );
4793
4794 // Byte-parity across the two orderings — both produce the
4795 // identical (kind, direction) pair AND both preserve every
4796 // other slot at its `gate_compute` baseline.
4797 assert_eq!(forward, reversed);
4798 let baseline = Classification::gate_compute();
4799 assert_eq!(forward.point_type, baseline.point_type);
4800 assert_eq!(forward.substrate, baseline.substrate);
4801 assert_eq!(forward.calm, baseline.calm);
4802 assert_eq!(forward.data_classification, baseline.data_classification);
4803 assert_eq!(forward.horizon.metric, baseline.horizon.metric);
4804 assert_eq!(
4805 forward.horizon.healthy_rate_threshold,
4806 baseline.horizon.healthy_rate_threshold,
4807 );
4808 }
4809
4810 #[test]
4811 fn with_axis_optimization_direction_overlay_wraps_variant_in_some() {
4812 // For every `OptimizationDirection` variant, `with_axis`
4813 // sets `horizon.direction = Some(variant)`. A regression
4814 // that dropped the `Some(...)` wrap (a stray `c.horizon.direction
4815 // = self.into()` that only compiles because
4816 // [`Option<OptimizationDirection>: From<OptimizationDirection>`]
4817 // is derived, but which would silently answer `None` on
4818 // some variants), or that wrote through the wrong nested
4819 // slot, fails HERE.
4820 for populated in OptimizationDirection::ALL {
4821 let c = Classification::gate_compute_with_axis(HorizonKind::Asymptotic)
4822 .with_axis(populated);
4823 assert_eq!(
4824 c.horizon.direction,
4825 Some(populated),
4826 "OptimizationDirection::{populated:?} overlay must set horizon.direction = Some({populated:?})",
4827 );
4828 assert_eq!(
4829 c.horizon.kind,
4830 HorizonKind::Asymptotic,
4831 "OptimizationDirection::{populated:?} overlay must preserve prior HorizonKind::Asymptotic overlay",
4832 );
4833 }
4834 }
4835
4836 // ── closed-set algebra contracts for DataClassification
4837 // (ALL × as_str × FromStr × rank × predicate pair) ────────────
4838
4839 /// Structural well-formedness of [`DataClassification`] as a
4840 /// [`tatara_lisp::ClosedSet`] implementor — the workspace-wide
4841 /// testkit lift that pins all three structural invariants (`ALL`
4842 /// is non-empty, every variant round-trips through
4843 /// `label ↔ parse_label`, labels are pairwise distinct, `""` is
4844 /// outside the closed set) at ONE call site. Replaces the hand-
4845 /// derived `data_classification_all_is_unique_and_complete` +
4846 /// `data_classification_roundtrip_via_as_str` + the empty-input arm
4847 /// of `unknown_data_classification_errors`. `FromStr` delegates to
4848 /// `<Self as tatara_closed_set::ClosedSet>::parse_label`, so this helper
4849 /// exercises the same code path the reconciler hits when parsing a
4850 /// CRD `enum:`-validated `dataClassification` value back to the
4851 /// typed classification.
4852 #[test]
4853 fn data_classification_is_well_formed_closed_set() {
4854 tatara_closed_set::assert_closed_set_well_formed::<DataClassification>();
4855 }
4856
4857 /// CANONICAL-KEY CONTRACT: `as_str` matches serde's PascalCase
4858 /// output verbatim for every variant. A future variant rename (or
4859 /// an `as_str` arm typo) lands here at one site, instead of
4860 /// drifting between the typed surface, the CRD enum, and the YAML
4861 /// wire format the reconciler stamps on
4862 /// `spec.classification.dataClassification`.
4863 #[test]
4864 fn data_classification_as_str_matches_serde() {
4865 crate::tagged_union::assert_label_matches_serde_serialization::<DataClassification>();
4866 }
4867
4868 /// The Display impl IS `as_str` — pinning this lets future callers
4869 /// reach for either projection without drift. Any operator-facing
4870 /// "dataClassification={class}" diagnostic that composes through
4871 /// Display inherits the canonical wire-format string automatically.
4872 #[test]
4873 fn data_classification_display_matches_as_str() {
4874 crate::tagged_union::assert_display_matches_label::<DataClassification>();
4875 }
4876
4877 /// `FromStr` rejects strings that aren't in the canonical
4878 /// projection — lowercased / typo / cross-axis-leaked — and the
4879 /// error echoes the input verbatim so the operator-facing
4880 /// diagnostic carries the offending value, not a normalized form.
4881 /// The empty-input arm is pinned by
4882 /// [`data_classification_is_well_formed_closed_set`] via the
4883 /// `tatara_lisp::ClosedSet` testkit; the cases here pin the
4884 /// verbatim-echo contract on the [`UnknownDataClassification`]
4885 /// newtype, which the trait's `make_unknown` can't see.
4886 #[test]
4887 fn unknown_data_classification_errors() {
4888 for bad in [
4889 "pii", // lowercased
4890 "PII", // uppercased
4891 "PersonalData", // typo
4892 "internal_data",
4893 "Steady", // PoolPhase-axis leak
4894 "Replace", // ReturnPolicy-axis leak
4895 "Attested", // ProcessPhase-axis leak
4896 "Compute", // SubstrateType-axis leak
4897 "Gate", // ConvergencePointType-axis leak
4898 "Monotone", // CalmClassification-axis leak
4899 ] {
4900 let err = DataClassification::from_str(bad).unwrap_err();
4901 assert_eq!(err.0, bad, "error payload should echo input verbatim");
4902 }
4903 }
4904
4905 // `unknown_data_classification_message_matches_substrate_convention`
4906 // removed — clause (5) of
4907 // `tatara_closed_set::assert_closed_set_well_formed::<DataClassification>()`
4908 // verifies the substrate-wide `"unknown {SET_LABEL}: {input}"`
4909 // shape generically (called from
4910 // `data_classification_is_well_formed_closed_set` above); the
4911 // `SET_LABEL` projection is pinned by
4912 // `tatara_lisp_derive::pascal_to_spaced_lowercase_tests`.
4913
4914 /// TRUTH-TABLE CONTRACT: the predicate pair agrees with the
4915 /// documented per-variant compliance role. Pinning this table at
4916 /// one site means any future compliance-baseline auto-selector
4917 /// reads the same projection that the reconciler writes.
4918 #[test]
4919 fn data_classification_predicate_truth_tables() {
4920 assert!(DataClassification::Public.is_public());
4921 assert!(!DataClassification::Public.is_restricted());
4922 assert!(!DataClassification::Public.is_regulated());
4923
4924 assert!(!DataClassification::Internal.is_public());
4925 assert!(DataClassification::Internal.is_restricted());
4926 assert!(!DataClassification::Internal.is_regulated());
4927
4928 assert!(!DataClassification::Confidential.is_public());
4929 assert!(DataClassification::Confidential.is_restricted());
4930 assert!(!DataClassification::Confidential.is_regulated());
4931
4932 assert!(!DataClassification::Pii.is_public());
4933 assert!(DataClassification::Pii.is_restricted());
4934 assert!(DataClassification::Pii.is_regulated());
4935
4936 assert!(!DataClassification::Phi.is_public());
4937 assert!(DataClassification::Phi.is_restricted());
4938 assert!(DataClassification::Phi.is_regulated());
4939
4940 assert!(!DataClassification::Pci.is_public());
4941 assert!(DataClassification::Pci.is_restricted());
4942 assert!(DataClassification::Pci.is_regulated());
4943 }
4944
4945 /// IMPLICATION CONTRACT: every regulated classification is also
4946 /// restricted. The impossible bucket (regulated AND
4947 /// freely-distributable) is pinned empty so a future variant that
4948 /// returned `(true, false)` from the predicate pair would FAIL
4949 /// here, forcing the author to either flip `is_restricted` or
4950 /// extend the consumer dispatch sites (compliance-baseline
4951 /// auto-selector, audit-log mandatory-fields validator)
4952 /// deliberately rather than silently producing a regulated class
4953 /// the API server would accept as freely-distributable. Encoded as
4954 /// material implication `is_regulated → is_restricted` so the
4955 /// boolean reads as the documented contract, not its NAND form.
4956 #[test]
4957 fn data_classification_regulated_implies_restricted() {
4958 for class in DataClassification::ALL {
4959 assert!(
4960 !class.is_regulated() || class.is_restricted(),
4961 "{class:?} is regulated but not restricted — \
4962 regulated data is by definition not freely distributable",
4963 );
4964 }
4965 }
4966
4967 /// POSITIVE-FRAMING TRUTH-TABLE CONTRACT: `is_public` implements
4968 /// the antisymmetric partner of `is_restricted` — `Public ⇒ true`
4969 /// and every other variant `⇒ false`. Pinning this table at one
4970 /// site means any future consumer asking the positive
4971 /// distribution framing ("is this dataset publicly distributable?")
4972 /// reads the same projection the compliance auditor reads. A
4973 /// future variant that flipped this mapping would have to renumber
4974 /// every consumer deliberately rather than silently promoting an
4975 /// access-controlled dataset onto the freely-distributable path.
4976 #[test]
4977 fn data_classification_is_public_truth_table() {
4978 assert!(DataClassification::Public.is_public());
4979 assert!(!DataClassification::Internal.is_public());
4980 assert!(!DataClassification::Confidential.is_public());
4981 assert!(!DataClassification::Pii.is_public());
4982 assert!(!DataClassification::Phi.is_public());
4983 assert!(!DataClassification::Pci.is_public());
4984 }
4985
4986 /// XOR PARTITION CONTRACT: for every [`DataClassification`]
4987 /// variant, EXACTLY ONE of `is_public` / `is_restricted` is true
4988 /// — the two predicates carve the closed set into COMPLEMENTARY
4989 /// buckets (publicly distributable ↔ no access-control regime
4990 /// applies; access-controlled ↔ some regime applies), the exact
4991 /// binary partition already sealed on the sibling calm axis by
4992 /// `calm_classification_monotone_xor_requires_coordination` on the
4993 /// two-variant closed set, now lifted through the projection layer
4994 /// to the six-variant data axis. A future variant that returned
4995 /// `true` for both (publicly distributable AND access-controlled —
4996 /// a category error) or `false` for both (an inert variant with
4997 /// no distribution classification — nothing to dispatch on) would
4998 /// fail here, forcing the author to extend either the predicates
4999 /// or the [`DataClassification`] enum deliberately. Structural
5000 /// twin of `calm_classification_monotone_xor_requires_coordination`
5001 /// and `horizon_kind_terminate_xor_requires_metric_axes` on the
5002 /// sibling calm + horizon axes — all three binary XOR partitions
5003 /// publish their two derived-nullary-bool projections as
5004 /// complementary XOR pairs at ONE site each so the axis carves
5005 /// into disjoint buckets by construction.
5006 #[test]
5007 fn data_classification_public_xor_restricted() {
5008 for class in DataClassification::ALL {
5009 assert!(
5010 class.is_public() ^ class.is_restricted(),
5011 "{class:?}: is_public() XOR is_restricted() must hold",
5012 );
5013 }
5014 }
5015
5016 /// ANTISYMMETRIC IMPLICATION CONTRACT: every regulated
5017 /// classification is NEVER publicly distributable — the impossible
5018 /// bucket (regulated AND public) is pinned empty on the closed
5019 /// set. Paired with `data_classification_regulated_implies_restricted`
5020 /// this is the antisymmetric MUTEX pin against the positive
5021 /// framing peer — a future variant that returned `(true, true)`
5022 /// from `(is_regulated, is_public)` would fail HERE, forcing the
5023 /// author to either flip `is_public` or extend the consumer
5024 /// dispatch sites (compliance-baseline auto-selector, audit-log
5025 /// mandatory-fields validator) deliberately rather than silently
5026 /// producing a regulated class the API server would accept as
5027 /// freely distributable.
5028 #[test]
5029 fn data_classification_regulated_implies_not_public() {
5030 for class in DataClassification::ALL {
5031 assert!(
5032 !class.is_regulated() || !class.is_public(),
5033 "{class:?} is regulated AND public — \
5034 regulated data is by definition not freely distributable",
5035 );
5036 }
5037 }
5038
5039 /// COVERAGE CONTRACT: every variant lands in exactly one of three
5040 /// compliance buckets — freely distributable (`Public`),
5041 /// restricted-only (`Internal | Confidential`), or regulated
5042 /// (`Pii | Phi | Pci`). Pins the three buckets at their declared
5043 /// cardinalities (1, 2, 3 — sum to `ALL.len()`) so a future
5044 /// variant lands somewhere deliberately.
5045 #[test]
5046 fn data_classification_buckets_cover_every_variant() {
5047 let mut free = 0u32;
5048 let mut restricted_only = 0u32;
5049 let mut regulated = 0u32;
5050 for class in DataClassification::ALL {
5051 match (class.is_restricted(), class.is_regulated()) {
5052 (false, false) => free += 1,
5053 (true, false) => restricted_only += 1,
5054 (true, true) => regulated += 1,
5055 (false, true) => {
5056 panic!("regulated_implies_restricted already pins this empty for {class:?}")
5057 }
5058 }
5059 }
5060 assert_eq!(free, 1, "free bucket: Public");
5061 assert_eq!(
5062 restricted_only, 2,
5063 "restricted-only bucket: Internal + Confidential"
5064 );
5065 assert_eq!(regulated, 3, "regulated bucket: Pii + Phi + Pci");
5066 assert_eq!(
5067 free + restricted_only + regulated,
5068 DataClassification::ALL.len() as u32
5069 );
5070 }
5071
5072 /// MONOTONE-RANK CONTRACT: `sensitivity_rank` is strictly
5073 /// monotone over `ALL`'s declared order, so the lattice ordering
5074 /// `Public < Internal < Confidential < Pii < Phi < Pci` is sealed
5075 /// at one site (this enum's projection) instead of riding on the
5076 /// silent `as u8` cast in [`tatara_lattice`]. A future variant
5077 /// inserted in the middle would either preserve strict monotonicity
5078 /// here (and the lattice keeps working) or FAIL here at compile or
5079 /// test time (and the author has to renumber deliberately). Also
5080 /// pins the rank codomain at `0..ALL.len()` so no variant can
5081 /// silently outrank the documented top.
5082 #[test]
5083 fn data_classification_rank_is_strictly_monotone_over_all() {
5084 let ranks: Vec<u8> = DataClassification::ALL
5085 .into_iter()
5086 .map(DataClassification::sensitivity_rank)
5087 .collect();
5088 for win in ranks.windows(2) {
5089 assert!(win[0] < win[1], "ranks not strictly monotone: {ranks:?}");
5090 }
5091 assert_eq!(*ranks.first().unwrap(), 0, "bottom rank must be 0");
5092 assert_eq!(
5093 *ranks.last().unwrap(),
5094 (DataClassification::ALL.len() as u8) - 1,
5095 "top rank must be ALL.len() - 1"
5096 );
5097 }
5098
5099 /// RANK-AGREES-WITH-ORD CONTRACT: the typed `sensitivity_rank`
5100 /// projection agrees with the derived `PartialOrd` / `Ord` for
5101 /// every pair in `ALL × ALL`. This is the bridge that lets
5102 /// [`tatara_lattice`]'s total-order `Lattice for DataClassification`
5103 /// impl call `sensitivity_rank` instead of `as u8` without changing
5104 /// any observable lattice behavior — and it lets a future
5105 /// reordering of the enum's variant declarations land at this test
5106 /// site (forcing the rank arms to be renumbered) rather than
5107 /// silently shifting the lattice's `leq` relation.
5108 #[test]
5109 fn data_classification_rank_agrees_with_partial_ord() {
5110 for a in DataClassification::ALL {
5111 for b in DataClassification::ALL {
5112 assert_eq!(
5113 a.sensitivity_rank() <= b.sensitivity_rank(),
5114 a <= b,
5115 "rank vs. PartialOrd drift on ({a:?}, {b:?})"
5116 );
5117 }
5118 }
5119 }
5120
5121 /// DEFAULT-AGREEMENT CONTRACT: `DataClassification::default()`
5122 /// returns `Internal` (the variant tagged `#[default]`), AND that
5123 /// variant lands in the restricted-only bucket — neither freely
5124 /// distributable nor externally regulated. A future `#[default]`
5125 /// rename without flipping the predicates fails here.
5126 #[test]
5127 fn data_classification_default_is_internal_in_restricted_only_bucket() {
5128 let d = DataClassification::default();
5129 assert_eq!(d, DataClassification::Internal);
5130 assert!(d.is_restricted());
5131 assert!(!d.is_regulated());
5132 assert_eq!(d.sensitivity_rank(), 1);
5133 }
5134
5135 /// BRIDGE ROUND-TRIP CONTRACT: every variant survives the
5136 /// CRD-facing (`PascalCase`) ↔ tatara-core (`snake_case`)
5137 /// `From` hop. Today the bridge is two hand-written 6-arm matches
5138 /// in this file; pinning the round-trip over `ALL` means a future
5139 /// variant added without extending the bridge fails here at one
5140 /// site instead of drifting between the CRD wire format and the
5141 /// `core_compl::DataClassification` selector axis.
5142 #[test]
5143 fn data_classification_bridge_roundtrip_over_all() {
5144 for class in DataClassification::ALL {
5145 let core: core_compl::DataClassification = class.into();
5146 let back: DataClassification = core.into();
5147 assert_eq!(back, class, "bridge round-trip failed for {class:?}");
5148 }
5149 }
5150
5151 // ── closed-set algebra contracts for ConvergencePointType
5152 // (ALL × as_str × FromStr × arity-pair × predicate triple) ────
5153
5154 /// Structural well-formedness of [`ConvergencePointType`] as a
5155 /// [`tatara_lisp::ClosedSet`] implementor — the workspace-wide
5156 /// testkit lift that pins all three structural invariants (`ALL`
5157 /// is non-empty, every variant round-trips through `label ↔
5158 /// parse_label`, labels are pairwise distinct, `""` is outside
5159 /// the closed set) at ONE call site. Replaces the hand-derived
5160 /// `convergence_point_type_all_is_unique_and_complete` +
5161 /// `convergence_point_type_roundtrip_via_as_str` + the empty-
5162 /// input arm of `unknown_convergence_point_type_errors`.
5163 /// `FromStr` delegates to `<Self as tatara_closed_set::ClosedSet>::parse_label`,
5164 /// so this helper exercises the same code path the reconciler
5165 /// hits when parsing a CRD `enum:`-validated value back to the
5166 /// typed point-type. The forced `[Self; 8]` array literal on
5167 /// `ConvergencePointType::ALL` still pins the cardinality at the
5168 /// declaration site.
5169 #[test]
5170 fn convergence_point_type_is_well_formed_closed_set() {
5171 tatara_closed_set::assert_closed_set_well_formed::<ConvergencePointType>();
5172 }
5173
5174 /// CANONICAL-KEY CONTRACT: `as_str` matches serde's PascalCase
5175 /// output verbatim for every variant. A future variant rename (or
5176 /// an `as_str` arm typo) lands here at one site, instead of
5177 /// drifting between the typed surface, the CRD enum, and the YAML
5178 /// wire format the reconciler reads from
5179 /// `spec.classification.pointType`.
5180 #[test]
5181 fn convergence_point_type_as_str_matches_serde() {
5182 crate::tagged_union::assert_label_matches_serde_serialization::<ConvergencePointType>();
5183 }
5184
5185 /// The Display impl IS `as_str` — pinning this lets future callers
5186 /// reach for either projection without drift.
5187 #[test]
5188 fn convergence_point_type_display_matches_as_str() {
5189 crate::tagged_union::assert_display_matches_label::<ConvergencePointType>();
5190 }
5191
5192 /// `FromStr` rejects strings outside the canonical projection —
5193 /// lowercased / typo / cross-axis-leaked — and the error echoes
5194 /// the input verbatim so the operator-facing diagnostic surfaces
5195 /// the bad value, not a normalized form. The empty-input arm is
5196 /// pinned by [`convergence_point_type_is_well_formed_closed_set`]
5197 /// via the `tatara_lisp::ClosedSet` testkit; the cases here pin
5198 /// the verbatim-echo contract on the
5199 /// [`UnknownConvergencePointType`] newtype, which the trait's
5200 /// `make_unknown` can't see.
5201 #[test]
5202 fn unknown_convergence_point_type_errors() {
5203 for bad in [
5204 "gate", // lowercased
5205 "GATE", // uppercased
5206 "Transformr", // typo
5207 "Filter",
5208 "Steady", // PoolPhase-axis leak
5209 "Pii", // DataClassification-axis leak
5210 "Attested", // ProcessPhase-axis leak
5211 "Compute", // SubstrateType-axis leak
5212 "Monotone", // CalmClassification-axis leak
5213 "PromQL", // ConditionKind-axis leak
5214 ] {
5215 let err = ConvergencePointType::from_str(bad).unwrap_err();
5216 assert_eq!(err.0, bad, "error payload should echo input verbatim");
5217 }
5218 }
5219
5220 // `unknown_convergence_point_type_message_matches_substrate_convention`
5221 // removed — clause (5) of
5222 // `tatara_closed_set::assert_closed_set_well_formed::<ConvergencePointType>()`
5223 // verifies the substrate-wide `"unknown {SET_LABEL}: {input}"`
5224 // shape generically (called from
5225 // `convergence_point_type_is_well_formed_closed_set` above); the
5226 // `SET_LABEL` projection is pinned by
5227 // `tatara_lisp_derive::pascal_to_spaced_lowercase_tests`.
5228
5229 /// TRUTH-TABLE CONTRACT: the predicate triple agrees with the
5230 /// documented per-variant topology role. Pinning this table at
5231 /// one site means any future DAG validator reads the same
5232 /// projection that compliance bindings dispatch against.
5233 #[test]
5234 fn convergence_point_type_predicate_truth_tables() {
5235 // Endomorphic: 1→1
5236 assert!(ConvergencePointType::Transform.is_endomorphic());
5237 assert!(!ConvergencePointType::Transform.is_diffusive());
5238 assert!(!ConvergencePointType::Transform.is_convergent());
5239
5240 assert!(ConvergencePointType::Observe.is_endomorphic());
5241 assert!(!ConvergencePointType::Observe.is_diffusive());
5242 assert!(!ConvergencePointType::Observe.is_convergent());
5243
5244 // Diffusive: 1→N
5245 assert!(!ConvergencePointType::Fork.is_endomorphic());
5246 assert!(ConvergencePointType::Fork.is_diffusive());
5247 assert!(!ConvergencePointType::Fork.is_convergent());
5248
5249 assert!(!ConvergencePointType::Broadcast.is_endomorphic());
5250 assert!(ConvergencePointType::Broadcast.is_diffusive());
5251 assert!(!ConvergencePointType::Broadcast.is_convergent());
5252
5253 // Convergent: N→1
5254 for t in [
5255 ConvergencePointType::Join,
5256 ConvergencePointType::Gate,
5257 ConvergencePointType::Select,
5258 ConvergencePointType::Reduce,
5259 ] {
5260 assert!(!t.is_endomorphic(), "{t:?} should not be endomorphic");
5261 assert!(!t.is_diffusive(), "{t:?} should not be diffusive");
5262 assert!(t.is_convergent(), "{t:?} should be convergent");
5263 }
5264 }
5265
5266 /// COVERAGE CONTRACT: every variant lands in *exactly one* of the
5267 /// three topology buckets — endomorphic, diffusive, or convergent.
5268 /// Pins the three buckets at their declared cardinalities (2, 2, 4
5269 /// — sum to `ALL.len()`) so a future variant lands somewhere
5270 /// deliberately. No variant returns true from more than one
5271 /// predicate; no variant returns false from all three.
5272 #[test]
5273 fn convergence_point_type_buckets_cover_every_variant() {
5274 let mut endomorphic = 0u32;
5275 let mut diffusive = 0u32;
5276 let mut convergent = 0u32;
5277 for t in ConvergencePointType::ALL {
5278 let buckets = [t.is_endomorphic(), t.is_diffusive(), t.is_convergent()];
5279 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
5280 assert_eq!(
5281 hits, 1,
5282 "{t:?} landed in {hits} buckets: {buckets:?} (must be exactly one)"
5283 );
5284 if t.is_endomorphic() {
5285 endomorphic += 1;
5286 }
5287 if t.is_diffusive() {
5288 diffusive += 1;
5289 }
5290 if t.is_convergent() {
5291 convergent += 1;
5292 }
5293 }
5294 assert_eq!(endomorphic, 2, "endomorphic bucket: Transform + Observe");
5295 assert_eq!(diffusive, 2, "diffusive bucket: Fork + Broadcast");
5296 assert_eq!(
5297 convergent, 4,
5298 "convergent bucket: Join + Gate + Select + Reduce"
5299 );
5300 assert_eq!(
5301 endomorphic + diffusive + convergent,
5302 ConvergencePointType::ALL.len() as u32
5303 );
5304 }
5305
5306 /// ARITY-PAIR ⇔ BUCKET CONTRACT: the `(input_arity, output_arity)`
5307 /// projection names the same topology partition as the
5308 /// `is_endomorphic` / `is_diffusive` / `is_convergent` predicate
5309 /// triple. `(One, One) ⇒ endomorphic`; `(One, Many) ⇒ diffusive`;
5310 /// `(Many, One) ⇒ convergent`. The impossible `(Many, Many)`
5311 /// bucket is pinned empty here — a `(Many, Many)` point would
5312 /// have no convergence semantics (many independent inputs
5313 /// replicated across many independent outputs) and every future
5314 /// DAG-composition validator would have to special-case it. This
5315 /// seal is the bridge that lets a future graph validator dispatch
5316 /// on either projection (arity pair OR bucket predicates) without
5317 /// drift — and a future variant that wants `(Many, Many)` must
5318 /// extend the bucket carving deliberately rather than silently
5319 /// shipping a fourth topology class.
5320 #[test]
5321 fn convergence_point_type_arity_pair_agrees_with_bucket() {
5322 for t in ConvergencePointType::ALL {
5323 match (t.input_arity(), t.output_arity()) {
5324 (Arity::One, Arity::One) => assert!(
5325 t.is_endomorphic(),
5326 "{t:?} has (One, One) arity but is not endomorphic"
5327 ),
5328 (Arity::One, Arity::Many) => assert!(
5329 t.is_diffusive(),
5330 "{t:?} has (One, Many) arity but is not diffusive"
5331 ),
5332 (Arity::Many, Arity::One) => assert!(
5333 t.is_convergent(),
5334 "{t:?} has (Many, One) arity but is not convergent"
5335 ),
5336 (Arity::Many, Arity::Many) => panic!(
5337 "{t:?} has (Many, Many) arity — pinned empty; \
5338 extend the topology carving before adding a variant here"
5339 ),
5340 }
5341 }
5342 }
5343
5344 /// BRIDGE ROUND-TRIP CONTRACT: every variant survives the
5345 /// CRD-facing (`PascalCase`) ↔ tatara-core (`snake_case`)
5346 /// `From` hop. Today the bridge is two hand-written 8-arm
5347 /// matches in this file; pinning the round-trip over `ALL`
5348 /// means a future variant added without extending the bridge
5349 /// fails here at one site instead of drifting between the CRD
5350 /// wire format and the
5351 /// `core::ConvergencePointType` selector axis that
5352 /// `compliance_binding::PointSelector::ByType` already
5353 /// dispatches against.
5354 #[test]
5355 fn convergence_point_type_bridge_roundtrip_over_all() {
5356 for t in ConvergencePointType::ALL {
5357 let core_t: core::ConvergencePointType = t.into();
5358 let back: ConvergencePointType = core_t.into();
5359 assert_eq!(back, t, "bridge round-trip failed for {t:?}");
5360 }
5361 }
5362
5363 // ── closed-set algebra contracts for Arity ───────────────────
5364
5365 /// `ALL` is the source of truth — pin its closure so a variant
5366 /// added without an `ALL` entry fails here. The arity is asserted
5367 /// by the `[Self; 2]` array type itself.
5368 #[test]
5369 fn arity_all_is_unique_and_complete() {
5370 let mut seen = std::collections::HashSet::new();
5371 for a in Arity::ALL {
5372 assert!(seen.insert(a), "duplicate variant in ALL: {a:?}");
5373 }
5374 assert_eq!(seen.len(), Arity::ALL.len());
5375 }
5376
5377 /// The Display impl IS `as_str` — pinning this lets future
5378 /// callers reach for either projection without drift. No serde
5379 /// matching here because `Arity` is a typed projection, not a
5380 /// CRD-facing enum — it never crosses the wire. Routed through
5381 /// the substrate-wide [`crate::tagged_union::assert_display_matches_label`]
5382 /// primitive so the sweep body lives at ONE substrate site rather
5383 /// than restated per-implementor. Also exercised through the
5384 /// substrate-wide `every_production_display_impl_binds_through_the_testkit_primitive`
5385 /// sweep so a per-crate test-site drop cannot silently disable the
5386 /// check.
5387 #[test]
5388 fn arity_display_matches_as_str() {
5389 crate::tagged_union::assert_display_matches_label::<Arity>();
5390 }
5391
5392 /// PREDICATE CONTRACT: `is_one` is true exactly for `Arity::One`.
5393 /// The disjointness against `Many` is structural (only two
5394 /// variants) but pinning the codomain here means a future
5395 /// `Arity::Zero` variant must declare its own `is_one` arm
5396 /// deliberately rather than silently defaulting through a
5397 /// non-closed-set match.
5398 #[test]
5399 fn arity_is_one_predicate_truth_table() {
5400 assert!(Arity::One.is_one());
5401 assert!(!Arity::Many.is_one());
5402 }
5403
5404 /// PREDICATE CONTRACT: `is_many` is true exactly for `Arity::Many`
5405 /// — the antisymmetric image of `is_one` on the current two-
5406 /// variant closed set. Pins the codomain here means a future
5407 /// `Arity::Zero` (or any other) variant must declare its own
5408 /// `is_many` arm deliberately rather than silently defaulting
5409 /// through a non-closed-set match.
5410 #[test]
5411 fn arity_is_many_predicate_truth_table() {
5412 assert!(!Arity::One.is_many());
5413 assert!(Arity::Many.is_many());
5414 }
5415
5416 /// BINARY XOR PARTITION pin — for every [`Arity`] variant, EXACTLY
5417 /// ONE of `is_one` / `is_many` holds. Structural twin of the
5418 /// optimization-direction axis
5419 /// (`optimization_direction_prefers_lower_xor_prefers_higher`),
5420 /// the calm axis
5421 /// (`calm_classification_monotone_xor_requires_coordination`), and
5422 /// the data axis (`data_classification_public_xor_restricted`) —
5423 /// all four binary XOR partitions publish their two derived-
5424 /// nullary-bool projections as complementary XOR pairs at ONE
5425 /// site each so the closed set carves into disjoint buckets by
5426 /// construction. A future variant that returned `true` for both
5427 /// (single AND multi — a category error) or `false` for both (an
5428 /// inert cardinality with no edge count: a hypothetical `Zero`
5429 /// sink sentinel MUST answer `false` on BOTH here, forcing the
5430 /// author to add a third derived-nullary predicate on the closed
5431 /// set deliberately rather than silently bucketing it onto an
5432 /// existing cardinality) would fail here, forcing the author to
5433 /// extend either the predicates or the [`Arity`] enum
5434 /// deliberately.
5435 #[test]
5436 fn arity_is_one_xor_is_many_over_all() {
5437 for a in Arity::ALL {
5438 assert!(
5439 a.is_one() ^ a.is_many(),
5440 "{a:?}: is_one() XOR is_many() must hold",
5441 );
5442 }
5443 }
5444
5445 /// COVERAGE CONTRACT: every [`Arity`] variant lands in exactly one
5446 /// of two cardinality buckets — single (`One`) or multi (`Many`).
5447 /// Pins the two buckets at their declared cardinalities (1, 1 —
5448 /// sum to `ALL.len()`) so a future variant lands somewhere
5449 /// deliberately. Structural mirror of
5450 /// `optimization_direction_buckets_cover_every_variant` on the
5451 /// sibling optimization-direction axis.
5452 #[test]
5453 fn arity_buckets_cover_every_variant() {
5454 let mut single = 0u32;
5455 let mut multi = 0u32;
5456 for a in Arity::ALL {
5457 if a.is_one() {
5458 single += 1;
5459 } else {
5460 multi += 1;
5461 }
5462 }
5463 assert_eq!(single, 1, "single-edge bucket: One");
5464 assert_eq!(multi, 1, "multi-edge bucket: Many");
5465 assert_eq!(single + multi, Arity::ALL.len() as u32);
5466 }
5467
5468 // ── closed-set algebra contracts for SubstrateType
5469 // (ALL × as_str × FromStr × predicate triple × bridge) ─────────
5470
5471 /// Structural well-formedness of [`SubstrateType`] as a
5472 /// [`tatara_lisp::ClosedSet`] implementor — see
5473 /// [`convergence_point_type_is_well_formed_closed_set`] for the
5474 /// canonical lift narrative. Replaces
5475 /// `substrate_type_all_is_unique_and_complete` +
5476 /// `substrate_type_roundtrip_via_as_str` + the empty-input arm
5477 /// of `unknown_substrate_type_errors`.
5478 #[test]
5479 fn substrate_type_is_well_formed_closed_set() {
5480 tatara_closed_set::assert_closed_set_well_formed::<SubstrateType>();
5481 }
5482
5483 /// CANONICAL-KEY CONTRACT: `as_str` matches serde's PascalCase
5484 /// output verbatim for every variant. A future variant rename
5485 /// (or an `as_str` arm typo) lands here at one site, instead of
5486 /// drifting between the typed surface, the CRD enum, and the
5487 /// YAML wire format the reconciler reads from
5488 /// `spec.classification.substrate`.
5489 #[test]
5490 fn substrate_type_as_str_matches_serde() {
5491 crate::tagged_union::assert_label_matches_serde_serialization::<SubstrateType>();
5492 }
5493
5494 /// The Display impl IS `as_str` — pinning this lets future
5495 /// callers reach for either projection without drift. Any
5496 /// operator-facing `substrate={kind}` diagnostic that composes
5497 /// through Display inherits the canonical wire-format string
5498 /// automatically.
5499 #[test]
5500 fn substrate_type_display_matches_as_str() {
5501 crate::tagged_union::assert_display_matches_label::<SubstrateType>();
5502 }
5503
5504 /// `FromStr` rejects strings outside the canonical projection —
5505 /// lowercased / typo / cross-axis-leaked — and the error echoes
5506 /// the input verbatim so the operator-facing diagnostic surfaces
5507 /// the bad value, not a normalized form. The empty-input arm is
5508 /// pinned by [`substrate_type_is_well_formed_closed_set`] via
5509 /// the `tatara_lisp::ClosedSet` testkit; the cases here pin the
5510 /// verbatim-echo contract on the [`UnknownSubstrateType`]
5511 /// newtype, which the trait's `make_unknown` can't see.
5512 #[test]
5513 fn unknown_substrate_type_errors() {
5514 for bad in [
5515 "compute", // lowercased
5516 "COMPUTE", // uppercased
5517 "Computte", // typo
5518 "Database", "Steady", // PoolPhase-axis leak
5519 "Pii", // DataClassification-axis leak
5520 "Attested", // ProcessPhase-axis leak
5521 "Gate", // ConvergencePointType-axis leak
5522 "Monotone", // CalmClassification-axis leak
5523 "PromQL", // ConditionKind-axis leak
5524 ] {
5525 let err = SubstrateType::from_str(bad).unwrap_err();
5526 assert_eq!(err.0, bad, "error payload should echo input verbatim");
5527 }
5528 }
5529
5530 // `unknown_substrate_type_message_matches_substrate_convention`
5531 // removed — clause (5) of
5532 // `tatara_closed_set::assert_closed_set_well_formed::<SubstrateType>()`
5533 // verifies the substrate-wide `"unknown {SET_LABEL}: {input}"`
5534 // shape generically (called from
5535 // `substrate_type_is_well_formed_closed_set` above); the
5536 // `SET_LABEL` projection is pinned by
5537 // `tatara_lisp_derive::pascal_to_spaced_lowercase_tests`.
5538
5539 /// TRUTH-TABLE CONTRACT: the predicate triple agrees with the
5540 /// documented per-variant plane role. Pinning this table at one
5541 /// site means any future compliance-baseline selector reads the
5542 /// same projection that the reconciler stamps on the CRD.
5543 #[test]
5544 fn substrate_type_predicate_truth_tables() {
5545 // Resource plane: you allocate budgets from it.
5546 for t in [
5547 SubstrateType::Financial,
5548 SubstrateType::Compute,
5549 SubstrateType::Network,
5550 SubstrateType::Storage,
5551 ] {
5552 assert!(t.is_resource(), "{t:?} should be a resource substrate");
5553 assert!(!t.is_policy(), "{t:?} should not be a policy substrate");
5554 assert!(
5555 !t.is_telemetry(),
5556 "{t:?} should not be a telemetry substrate"
5557 );
5558 }
5559
5560 // Policy plane: it gates access for other workloads.
5561 for t in [
5562 SubstrateType::Security,
5563 SubstrateType::Identity,
5564 SubstrateType::Regulatory,
5565 ] {
5566 assert!(!t.is_resource(), "{t:?} should not be a resource substrate");
5567 assert!(t.is_policy(), "{t:?} should be a policy substrate");
5568 assert!(
5569 !t.is_telemetry(),
5570 "{t:?} should not be a telemetry substrate"
5571 );
5572 }
5573
5574 // Telemetry plane: it observes other workloads.
5575 assert!(!SubstrateType::Observability.is_resource());
5576 assert!(!SubstrateType::Observability.is_policy());
5577 assert!(SubstrateType::Observability.is_telemetry());
5578 }
5579
5580 /// COVERAGE CONTRACT: every variant lands in *exactly one* of
5581 /// the three plane buckets — resource, policy, or telemetry.
5582 /// Pins the three buckets at their declared cardinalities (4,
5583 /// 3, 1 — sum to `ALL.len()`) so a future variant lands
5584 /// somewhere deliberately. No variant returns true from more
5585 /// than one predicate; no variant returns false from all three.
5586 #[test]
5587 fn substrate_type_buckets_cover_every_variant() {
5588 let mut resource = 0u32;
5589 let mut policy = 0u32;
5590 let mut telemetry = 0u32;
5591 for t in SubstrateType::ALL {
5592 let buckets = [t.is_resource(), t.is_policy(), t.is_telemetry()];
5593 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
5594 assert_eq!(
5595 hits, 1,
5596 "{t:?} landed in {hits} buckets: {buckets:?} (must be exactly one)"
5597 );
5598 if t.is_resource() {
5599 resource += 1;
5600 }
5601 if t.is_policy() {
5602 policy += 1;
5603 }
5604 if t.is_telemetry() {
5605 telemetry += 1;
5606 }
5607 }
5608 assert_eq!(
5609 resource, 4,
5610 "resource bucket: Financial + Compute + Network + Storage"
5611 );
5612 assert_eq!(policy, 3, "policy bucket: Security + Identity + Regulatory");
5613 assert_eq!(telemetry, 1, "telemetry bucket: Observability");
5614 assert_eq!(
5615 resource + policy + telemetry,
5616 SubstrateType::ALL.len() as u32
5617 );
5618 }
5619
5620 /// BRIDGE ROUND-TRIP CONTRACT: every variant survives the
5621 /// CRD-facing (`PascalCase`) ↔ tatara-core (`snake_case`)
5622 /// `From` hop. Today the bridge is two hand-written 8-arm
5623 /// matches in this file; pinning the round-trip over `ALL`
5624 /// means a future variant added without extending the bridge
5625 /// fails here at one site instead of drifting between the CRD
5626 /// wire format and the `core::SubstrateType` selector axis
5627 /// that `compliance_binding::PointSelector::BySubstrate`
5628 /// already dispatches against.
5629 #[test]
5630 fn substrate_type_bridge_roundtrip_over_all() {
5631 for t in SubstrateType::ALL {
5632 let core_t: core::SubstrateType = t.into();
5633 let back: SubstrateType = core_t.into();
5634 assert_eq!(back, t, "bridge round-trip failed for {t:?}");
5635 }
5636 }
5637
5638 // ── closed-set algebra contracts for CalmClassification
5639 // (ALL × as_str × FromStr × requires_coordination × bridge) ─────
5640
5641 /// Structural well-formedness of [`CalmClassification`] as a
5642 /// [`tatara_lisp::ClosedSet`] implementor — see
5643 /// [`convergence_point_type_is_well_formed_closed_set`] for the
5644 /// canonical lift narrative. Replaces
5645 /// `calm_classification_all_is_unique_and_complete` +
5646 /// `calm_classification_roundtrip_via_as_str` + the empty-input
5647 /// arm of `unknown_calm_classification_errors`.
5648 #[test]
5649 fn calm_classification_is_well_formed_closed_set() {
5650 tatara_closed_set::assert_closed_set_well_formed::<CalmClassification>();
5651 }
5652
5653 /// CANONICAL-KEY CONTRACT: `as_str` matches serde's PascalCase
5654 /// output verbatim for every variant. A future variant rename
5655 /// (or an `as_str` arm typo) lands here at one site, instead of
5656 /// drifting between the typed surface, the CRD enum, and the
5657 /// YAML wire format the reconciler reads from
5658 /// `spec.classification.calm`.
5659 #[test]
5660 fn calm_classification_as_str_matches_serde() {
5661 crate::tagged_union::assert_label_matches_serde_serialization::<CalmClassification>();
5662 }
5663
5664 /// The Display impl IS `as_str` — pinning this lets future
5665 /// callers reach for either projection without drift. Any
5666 /// operator-facing `calm={kind}` diagnostic that composes
5667 /// through Display inherits the canonical wire-format string
5668 /// automatically.
5669 #[test]
5670 fn calm_classification_display_matches_as_str() {
5671 crate::tagged_union::assert_display_matches_label::<CalmClassification>();
5672 }
5673
5674 /// `FromStr` rejects strings outside the canonical projection —
5675 /// lowercased / typo / cross-axis-leaked — and the error echoes
5676 /// the input verbatim so the operator-facing diagnostic surfaces
5677 /// the bad value, not a normalized form. The empty-input arm is
5678 /// pinned by [`calm_classification_is_well_formed_closed_set`]
5679 /// via the `tatara_lisp::ClosedSet` testkit; the cases here pin
5680 /// the verbatim-echo contract on the
5681 /// [`UnknownCalmClassification`] newtype, which the trait's
5682 /// `make_unknown` can't see.
5683 #[test]
5684 fn unknown_calm_classification_errors() {
5685 for bad in [
5686 "monotone", // lowercased
5687 "MONOTONE", // uppercased
5688 "Mono", // typo
5689 "non_monotone", // core's snake_case form (must not cross axes)
5690 "non-monotone", // dashed
5691 "Monotonic", // close-typo
5692 "Steady", // PoolPhase-axis leak
5693 "Pii", // DataClassification-axis leak
5694 "Attested", // ProcessPhase-axis leak
5695 "Compute", // SubstrateType-axis leak
5696 "Gate", // ConvergencePointType-axis leak
5697 "PromQL", // ConditionKind-axis leak
5698 ] {
5699 let err = CalmClassification::from_str(bad).unwrap_err();
5700 assert_eq!(err.0, bad, "error payload should echo input verbatim");
5701 }
5702 }
5703
5704 // `unknown_calm_classification_message_matches_substrate_convention`
5705 // removed — clause (5) of
5706 // `tatara_closed_set::assert_closed_set_well_formed::<CalmClassification>()`
5707 // verifies the substrate-wide `"unknown {SET_LABEL}: {input}"`
5708 // shape generically (called from
5709 // `calm_classification_is_well_formed_closed_set` above); the
5710 // `SET_LABEL` projection is pinned by
5711 // `tatara_lisp_derive::pascal_to_spaced_lowercase_tests`.
5712
5713 /// CALM-THEOREM TRUTH-TABLE CONTRACT: `requires_coordination`
5714 /// implements the biconditional half of Hellerstein's CALM
5715 /// theorem — `Monotone ⇒ false` and `NonMonotone ⇒ true`.
5716 /// Pinning this table at one site means any future reconciler
5717 /// dispatch that picks between Raft writes and gossip
5718 /// propagation reads the same projection the lattice ordering
5719 /// (`Monotone ≤ NonMonotone`) does. A future variant that
5720 /// flipped this mapping would have to renumber every consumer
5721 /// deliberately rather than silently shipping a non-monotone
5722 /// operation onto the no-coordination path.
5723 #[test]
5724 fn calm_classification_requires_coordination_truth_table() {
5725 assert!(!CalmClassification::Monotone.requires_coordination());
5726 assert!(CalmClassification::NonMonotone.requires_coordination());
5727 }
5728
5729 /// COVERAGE CONTRACT: every variant lands in exactly one of two
5730 /// coordination buckets — no-coordination (`Monotone`) or
5731 /// requires-coordination (`NonMonotone`). Pins the two buckets
5732 /// at their declared cardinalities (1, 1 — sum to `ALL.len()`)
5733 /// so a future variant lands somewhere deliberately. The
5734 /// biconditional structure of the CALM theorem makes this
5735 /// partition exhaustive by construction.
5736 #[test]
5737 fn calm_classification_buckets_cover_every_variant() {
5738 let mut no_coord = 0u32;
5739 let mut coord = 0u32;
5740 for c in CalmClassification::ALL {
5741 if c.requires_coordination() {
5742 coord += 1;
5743 } else {
5744 no_coord += 1;
5745 }
5746 }
5747 assert_eq!(no_coord, 1, "no-coordination bucket: Monotone");
5748 assert_eq!(coord, 1, "requires-coordination bucket: NonMonotone");
5749 assert_eq!(no_coord + coord, CalmClassification::ALL.len() as u32);
5750 }
5751
5752 /// DEFAULT-AGREEMENT CONTRACT: `CalmClassification::default()`
5753 /// returns `Monotone` (the variant tagged `#[default]`) AND that
5754 /// variant lands in the no-coordination bucket. A future
5755 /// `#[default]` rename without flipping the predicate fails
5756 /// here — the default for an under-specified Process must
5757 /// remain the no-coordination side so that an unannotated
5758 /// Process can't silently demand Raft writes the reconciler
5759 /// isn't configured to provide.
5760 #[test]
5761 fn calm_classification_default_is_monotone_no_coordination() {
5762 let c = CalmClassification::default();
5763 assert_eq!(c, CalmClassification::Monotone);
5764 assert!(!c.requires_coordination());
5765 }
5766
5767 /// CALM-THEOREM POSITIVE-FRAMING TRUTH-TABLE CONTRACT:
5768 /// `is_monotone` implements the antisymmetric partner of
5769 /// `requires_coordination` — `Monotone ⇒ true` and
5770 /// `NonMonotone ⇒ false`. Pinning this table at one site means
5771 /// any future consumer asking the positive CALM framing "can
5772 /// this Process participate in gossip-only writes?" reads the
5773 /// same projection the lattice ordering and the antisymmetric
5774 /// `requires_coordination` peer read. A future variant that
5775 /// flipped this mapping would have to renumber every consumer
5776 /// deliberately rather than silently promoting a non-monotone
5777 /// operation onto the gossip path.
5778 #[test]
5779 fn calm_classification_is_monotone_truth_table() {
5780 assert!(CalmClassification::Monotone.is_monotone());
5781 assert!(!CalmClassification::NonMonotone.is_monotone());
5782 }
5783
5784 /// XOR PARTITION CONTRACT: for every [`CalmClassification`]
5785 /// variant, EXACTLY ONE of `is_monotone` /
5786 /// `requires_coordination` is true — the two predicates carve
5787 /// the closed set into COMPLEMENTARY buckets (monotone ↔ no
5788 /// coordination; non-monotone ↔ requires coordination), the
5789 /// biconditional half of Hellerstein's CALM theorem as a
5790 /// closed-set-driven proof. A future variant that returned
5791 /// `true` for both (a monotone operation that nonetheless
5792 /// requires coordination — a category error under CALM) or
5793 /// `false` for both (an inert variant with no monotonicity
5794 /// classification — nothing to dispatch on) would fail here,
5795 /// forcing the author to extend either the predicates or the
5796 /// [`CalmClassification`] enum deliberately. Structural twin of
5797 /// [`horizon_kind_terminate_xor_requires_metric_axes`] on the
5798 /// horizon axis — both binary closed sets publish their two
5799 /// derived-nullary-bool projections as complementary XOR pairs
5800 /// at ONE site each so the axis carves into disjoint buckets
5801 /// by construction.
5802 #[test]
5803 fn calm_classification_monotone_xor_requires_coordination() {
5804 for c in CalmClassification::ALL {
5805 assert!(
5806 c.is_monotone() ^ c.requires_coordination(),
5807 "{c:?}: is_monotone() XOR requires_coordination() must hold",
5808 );
5809 }
5810 }
5811
5812 /// BRIDGE ROUND-TRIP CONTRACT: every variant survives the
5813 /// CRD-facing (`PascalCase`) ↔ tatara-core (`snake_case`)
5814 /// `From` hop. Today the bridge is two hand-written 2-arm
5815 /// matches in this file; pinning the round-trip over `ALL`
5816 /// means a future variant added without extending the bridge
5817 /// fails here at one site instead of drifting between the CRD
5818 /// wire format and the `core::CalmClassification` selector
5819 /// axis. Closes the asymmetry that pre-lift had a
5820 /// `From<CalmClassification> for core::CalmClassification`
5821 /// forward bridge but no reverse — symmetric to every other
5822 /// classification-axis bridge in this file.
5823 #[test]
5824 fn calm_classification_bridge_roundtrip_over_all() {
5825 for c in CalmClassification::ALL {
5826 let core_c: core::CalmClassification = c.into();
5827 let back: CalmClassification = core_c.into();
5828 assert_eq!(back, c, "bridge round-trip failed for {c:?}");
5829 }
5830 }
5831
5832 // ── closed-set algebra contracts for OptimizationDirection
5833 // (ALL × as_str × FromStr × prefers_lower × is_improvement) ───
5834
5835 /// Structural well-formedness of [`OptimizationDirection`] as a
5836 /// [`tatara_lisp::ClosedSet`] implementor — see
5837 /// [`convergence_point_type_is_well_formed_closed_set`] for the
5838 /// canonical lift narrative. Replaces
5839 /// `optimization_direction_all_is_unique_and_complete` +
5840 /// `optimization_direction_roundtrip_via_as_str` + the empty-
5841 /// input arm of `unknown_optimization_direction_errors`.
5842 #[test]
5843 fn optimization_direction_is_well_formed_closed_set() {
5844 tatara_closed_set::assert_closed_set_well_formed::<OptimizationDirection>();
5845 }
5846
5847 /// CANONICAL-KEY CONTRACT: `as_str` matches serde's PascalCase
5848 /// output verbatim for every variant. A future variant rename
5849 /// (or an `as_str` arm typo) lands here at one site, instead of
5850 /// drifting between the typed surface, the CRD enum, and the
5851 /// YAML wire format the reconciler reads from
5852 /// `spec.classification.horizon.direction`.
5853 #[test]
5854 fn optimization_direction_as_str_matches_serde() {
5855 crate::tagged_union::assert_label_matches_serde_serialization::<OptimizationDirection>();
5856 }
5857
5858 /// The Display impl IS `as_str` — pinning this lets future
5859 /// callers reach for either projection without drift. Any
5860 /// operator-facing `direction={kind}` diagnostic that composes
5861 /// through Display inherits the canonical wire-format string
5862 /// automatically.
5863 #[test]
5864 fn optimization_direction_display_matches_as_str() {
5865 crate::tagged_union::assert_display_matches_label::<OptimizationDirection>();
5866 }
5867
5868 /// `FromStr` rejects strings outside the canonical projection —
5869 /// lowercased / typo / cross-axis-leaked — and the error echoes
5870 /// the input verbatim so the operator-facing diagnostic surfaces
5871 /// the bad value, not a normalized form. The empty-input arm is
5872 /// pinned by [`optimization_direction_is_well_formed_closed_set`]
5873 /// via the `tatara_lisp::ClosedSet` testkit; the cases here pin
5874 /// the verbatim-echo contract on the
5875 /// [`UnknownOptimizationDirection`] newtype, which the trait's
5876 /// `make_unknown` can't see.
5877 #[test]
5878 fn unknown_optimization_direction_errors() {
5879 for bad in [
5880 "minimize", // lowercased
5881 "MINIMIZE", // uppercased
5882 "Minimze", // typo
5883 "Lower", // synonym, not canonical
5884 "Higher", // synonym, not canonical
5885 "Asc", // wire-leak from sort-order axis
5886 "Desc", // wire-leak from sort-order axis
5887 "Bounded", // HorizonKind-axis leak
5888 "Monotone", // CalmClassification-axis leak
5889 "Steady", // PoolPhase-axis leak
5890 "Pii", // DataClassification-axis leak
5891 "Attested", // ProcessPhase-axis leak
5892 "Compute", // SubstrateType-axis leak
5893 "Gate", // ConvergencePointType-axis leak
5894 "PromQL", // ConditionKind-axis leak
5895 ] {
5896 let err = OptimizationDirection::from_str(bad).unwrap_err();
5897 assert_eq!(err.0, bad, "error payload should echo input verbatim");
5898 }
5899 }
5900
5901 // `unknown_optimization_direction_message_matches_substrate_convention`
5902 // removed — clause (5) of
5903 // `tatara_closed_set::assert_closed_set_well_formed::<OptimizationDirection>()`
5904 // verifies the substrate-wide `"unknown {SET_LABEL}: {input}"`
5905 // shape generically (called from
5906 // `optimization_direction_is_well_formed_closed_set` above); the
5907 // `SET_LABEL` projection is pinned by
5908 // `tatara_lisp_derive::pascal_to_spaced_lowercase_tests`.
5909
5910 /// TRUTH-TABLE CONTRACT: `prefers_lower` is the boolean
5911 /// partition `Minimize ⇒ true`, `Maximize ⇒ false`. Pinning this
5912 /// table at one site means any future dispatch on per-direction
5913 /// polarity (rate-window evaluator, breathe-band regression
5914 /// detector) reads the same projection rather than re-deriving
5915 /// from the variant name. Mirrors
5916 /// [`CalmClassification::requires_coordination`]'s truth-table
5917 /// shape.
5918 #[test]
5919 fn optimization_direction_prefers_lower_truth_table() {
5920 assert!(OptimizationDirection::Minimize.prefers_lower());
5921 assert!(!OptimizationDirection::Maximize.prefers_lower());
5922 }
5923
5924 /// POSITIVE-FRAMING TRUTH-TABLE CONTRACT: `prefers_higher`
5925 /// implements the antisymmetric partner of `prefers_lower` —
5926 /// `Minimize ⇒ false` and `Maximize ⇒ true`. Pinning this table
5927 /// at one site means any future consumer asking the positive
5928 /// higher-is-better framing ("does this direction reward
5929 /// throughput / coverage / revenue rate?") reads the same
5930 /// projection every asymptotic-health probe writes. Mirrors
5931 /// [`CalmClassification::is_monotone`]'s positive-framing shape
5932 /// on the sibling binary closed set.
5933 #[test]
5934 fn optimization_direction_prefers_higher_truth_table() {
5935 assert!(!OptimizationDirection::Minimize.prefers_higher());
5936 assert!(OptimizationDirection::Maximize.prefers_higher());
5937 }
5938
5939 /// XOR PARTITION CONTRACT: for every [`OptimizationDirection`]
5940 /// variant, EXACTLY ONE of `prefers_lower` / `prefers_higher` is
5941 /// true — the two predicates carve the closed set into
5942 /// COMPLEMENTARY buckets (lower-is-better ↔ higher-is-better),
5943 /// the exact binary partition already sealed on the sibling
5944 /// [`CalmClassification`] axis by
5945 /// `calm_classification_monotone_xor_requires_coordination` and
5946 /// on the sibling [`DataClassification`] axis (through the
5947 /// projection layer) by `data_classification_public_xor_restricted`,
5948 /// now lifted to the two-variant optimization-direction axis. A
5949 /// future variant that returned `true` for both (lower AND higher —
5950 /// a category error) or `false` for both (an inert direction with
5951 /// no polarity — nothing to dispatch on: a hypothetical `Stabilize`
5952 /// sentinel MUST answer `false` on BOTH here, forcing the author
5953 /// to add a third derived-nullary predicate on the closed set
5954 /// deliberately rather than silently bucketing it onto an existing
5955 /// polarity) would fail here, forcing the author to extend either
5956 /// the predicates or the [`OptimizationDirection`] enum deliberately.
5957 /// Structural twin of `calm_classification_monotone_xor_requires_coordination`
5958 /// and `data_classification_public_xor_restricted` on the sibling
5959 /// calm + data axes — all three binary XOR partitions publish
5960 /// their two derived-nullary-bool projections as complementary
5961 /// XOR pairs at ONE site each so the axis carves into disjoint
5962 /// buckets by construction.
5963 #[test]
5964 fn optimization_direction_prefers_lower_xor_prefers_higher() {
5965 for d in OptimizationDirection::ALL {
5966 assert!(
5967 d.prefers_lower() ^ d.prefers_higher(),
5968 "{d:?}: prefers_lower() XOR prefers_higher() must hold",
5969 );
5970 }
5971 }
5972
5973 /// COVERAGE CONTRACT: every variant lands in exactly one of two
5974 /// polarity buckets — prefers-lower (`Minimize`) or
5975 /// prefers-higher (`Maximize`). Pins the two buckets at their
5976 /// declared cardinalities (1, 1 — sum to `ALL.len()`) so a
5977 /// future variant lands somewhere deliberately.
5978 #[test]
5979 fn optimization_direction_buckets_cover_every_variant() {
5980 let mut lower = 0u32;
5981 let mut higher = 0u32;
5982 for d in OptimizationDirection::ALL {
5983 if d.prefers_lower() {
5984 lower += 1;
5985 } else {
5986 higher += 1;
5987 }
5988 }
5989 assert_eq!(lower, 1, "prefers-lower bucket: Minimize");
5990 assert_eq!(higher, 1, "prefers-higher bucket: Maximize");
5991 assert_eq!(lower + higher, OptimizationDirection::ALL.len() as u32);
5992 }
5993
5994 /// LOAD-BEARING TRUTH-TABLE: `is_improvement` answers "is `after`
5995 /// strictly better than `before` under this direction?" for the
5996 /// canonical samples. Pins the strict-improvement semantic at
5997 /// one site so a future rate-window evaluator or breathe-band
5998 /// regression detector reads the same projection that the
5999 /// asymptotic-health probe writes.
6000 #[test]
6001 fn optimization_direction_is_improvement_truth_table() {
6002 // Minimize: lower-is-better
6003 assert!(OptimizationDirection::Minimize.is_improvement(10.0, 5.0));
6004 assert!(!OptimizationDirection::Minimize.is_improvement(5.0, 10.0));
6005
6006 // Maximize: higher-is-better
6007 assert!(OptimizationDirection::Maximize.is_improvement(5.0, 10.0));
6008 assert!(!OptimizationDirection::Maximize.is_improvement(10.0, 5.0));
6009 }
6010
6011 /// NO-OP CONTRACT: a sample equal to the previous one is NOT an
6012 /// improvement under either direction. Pinning this guarantees
6013 /// a flatlined rate-window evaluator doesn't silently keep
6014 /// claiming "still improving" forever and skipping the
6015 /// healthy-rate-threshold gate.
6016 #[test]
6017 fn optimization_direction_no_op_is_not_improvement() {
6018 for d in OptimizationDirection::ALL {
6019 assert!(
6020 !d.is_improvement(7.0, 7.0),
6021 "{d:?}: equal samples must not count as improvement",
6022 );
6023 assert!(
6024 !d.is_improvement(0.0, 0.0),
6025 "{d:?}: zero/zero must not count as improvement",
6026 );
6027 }
6028 }
6029
6030 /// NaN CONTRACT: NaN on either operand short-circuits to `false`
6031 /// (no improvement claim from indeterminate data) via the
6032 /// standard `PartialOrd` behavior. Without this, a rate-window
6033 /// evaluator that sampled a NaN partway through (a transient
6034 /// metric-scrape failure) would either panic on an `Ord`
6035 /// comparison or — worse — silently claim improvement on the
6036 /// next valid sample by treating NaN as the worst case.
6037 #[test]
6038 fn optimization_direction_nan_is_not_improvement() {
6039 let nan = f64::NAN;
6040 for d in OptimizationDirection::ALL {
6041 assert!(
6042 !d.is_improvement(nan, 1.0),
6043 "{d:?}: NaN before must not count as improvement",
6044 );
6045 assert!(
6046 !d.is_improvement(1.0, nan),
6047 "{d:?}: NaN after must not count as improvement",
6048 );
6049 assert!(
6050 !d.is_improvement(nan, nan),
6051 "{d:?}: NaN/NaN must not count as improvement",
6052 );
6053 }
6054 }
6055
6056 /// ANTISYMMETRY CONTRACT: for distinct finite samples,
6057 /// `is_improvement(a, b)` xor `is_improvement(b, a)` —
6058 /// exactly one direction of the pair counts as improvement.
6059 /// This is the algebraic shape every asymptotic-health
6060 /// rate-window evaluator depends on to avoid double-counting
6061 /// an improvement as a regression on the reverse traversal.
6062 /// A future variant that returned `true` for both directions
6063 /// (or `false` for both, the equal-sample case) would FAIL
6064 /// here, forcing the author to extend the consumer dispatch
6065 /// deliberately.
6066 #[test]
6067 fn optimization_direction_is_improvement_is_antisymmetric() {
6068 let pairs = [(1.0_f64, 2.0_f64), (0.0, 100.0), (-3.5, 3.5), (1e9, 1e-9)];
6069 for d in OptimizationDirection::ALL {
6070 for (a, b) in pairs {
6071 assert!(a != b, "test fixture requires distinct samples");
6072 assert!(
6073 d.is_improvement(a, b) ^ d.is_improvement(b, a),
6074 "{d:?}: antisymmetry violated on ({a}, {b})",
6075 );
6076 }
6077 }
6078 }
6079
6080 /// DEFAULT-AGREEMENT CONTRACT:
6081 /// `OptimizationDirection::default()` returns `Minimize` (the
6082 /// variant tagged `#[default]`), AND that variant lands in the
6083 /// prefers-lower bucket. A future `#[default]` rename without
6084 /// flipping the predicate fails here — `Minimize` is the
6085 /// canonical default for distributed-systems asymptotic
6086 /// optimization (cost / latency / error rate), so an
6087 /// unannotated metric must not silently flip the rate-window
6088 /// evaluator's polarity. This is also the same value the
6089 /// `Horizon → ConvergenceHorizon` bridge falls back to when
6090 /// `direction` is unset, so pinning the default here pins the
6091 /// bridge's behavior at one site.
6092 #[test]
6093 fn optimization_direction_default_is_minimize_prefers_lower() {
6094 let d = OptimizationDirection::default();
6095 assert_eq!(d, OptimizationDirection::Minimize);
6096 assert!(d.prefers_lower());
6097 }
6098
6099 /// BRIDGE ROUND-TRIP CONTRACT: every variant survives the
6100 /// CRD-facing (`PascalCase`) ↔ tatara-core (`snake_case`)
6101 /// `From` hop. Pre-lift the bridge was a one-way
6102 /// `From<OptimizationDirection> for core::OptimizationDirection`
6103 /// with no reverse — asymmetric to every other classification-
6104 /// axis bridge in this file. Pinning the round-trip over `ALL`
6105 /// means a future variant added without extending the bridge
6106 /// fails here at one site instead of drifting between the CRD
6107 /// wire format and `core::OptimizationDirection`.
6108 #[test]
6109 fn optimization_direction_bridge_roundtrip_over_all() {
6110 for d in OptimizationDirection::ALL {
6111 let core_d: core::OptimizationDirection = d.into();
6112 let back: OptimizationDirection = core_d.into();
6113 assert_eq!(back, d, "bridge round-trip failed for {d:?}");
6114 }
6115 }
6116
6117 // ── closed-set algebra contracts for HorizonKind
6118 // (ALL × as_str × FromStr × terminates × requires_metric_axes) ──
6119
6120 /// Structural well-formedness of [`HorizonKind`] as a
6121 /// [`tatara_lisp::ClosedSet`] implementor — see
6122 /// [`convergence_point_type_is_well_formed_closed_set`] for the
6123 /// canonical lift narrative. Replaces
6124 /// `horizon_kind_all_is_unique_and_complete` +
6125 /// `horizon_kind_roundtrip_via_as_str` + the empty-input arm of
6126 /// `unknown_horizon_kind_errors`.
6127 #[test]
6128 fn horizon_kind_is_well_formed_closed_set() {
6129 tatara_closed_set::assert_closed_set_well_formed::<HorizonKind>();
6130 }
6131
6132 /// CANONICAL-KEY CONTRACT: `as_str` matches serde's PascalCase
6133 /// output verbatim for every variant. A future variant rename
6134 /// (or an `as_str` arm typo) lands here at one site, instead of
6135 /// drifting between the typed surface, the CRD enum, and the
6136 /// YAML wire format the reconciler stamps on
6137 /// `spec.classification.horizon.kind`.
6138 #[test]
6139 fn horizon_kind_as_str_matches_serde() {
6140 crate::tagged_union::assert_label_matches_serde_serialization::<HorizonKind>();
6141 }
6142
6143 /// The Display impl IS `as_str` — pinning this lets future
6144 /// callers reach for either projection without drift. Any
6145 /// operator-facing `horizon.kind={kind}` diagnostic that
6146 /// composes through Display inherits the canonical wire-format
6147 /// string automatically.
6148 #[test]
6149 fn horizon_kind_display_matches_as_str() {
6150 crate::tagged_union::assert_display_matches_label::<HorizonKind>();
6151 }
6152
6153 /// `FromStr` rejects strings outside the canonical projection —
6154 /// lowercased / typo / cross-axis-leaked — and the error echoes
6155 /// the input verbatim so the operator-facing diagnostic surfaces
6156 /// the bad value, not a normalized form. The empty-input arm is
6157 /// pinned by [`horizon_kind_is_well_formed_closed_set`] via the
6158 /// `tatara_lisp::ClosedSet` testkit; the cases here pin the
6159 /// verbatim-echo contract on the [`UnknownHorizonKind`] newtype,
6160 /// which the trait's `make_unknown` can't see.
6161 #[test]
6162 fn unknown_horizon_kind_errors() {
6163 for bad in [
6164 "bounded", // lowercased
6165 "BOUNDED", // uppercased
6166 "Boundd", // typo
6167 "Finite", // synonym, not canonical
6168 "Perpetual", // synonym, not canonical
6169 "Infinite", // synonym, not canonical
6170 "Minimize", // OptimizationDirection-axis leak
6171 "Monotone", // CalmClassification-axis leak
6172 "Pii", // DataClassification-axis leak
6173 "Steady", // PoolPhase-axis leak
6174 "Attested", // ProcessPhase-axis leak
6175 "Compute", // SubstrateType-axis leak
6176 "Gate", // ConvergencePointType-axis leak
6177 "PromQL", // ConditionKind-axis leak
6178 ] {
6179 let err = HorizonKind::from_str(bad).unwrap_err();
6180 assert_eq!(err.0, bad, "error payload should echo input verbatim");
6181 }
6182 }
6183
6184 // `unknown_horizon_kind_message_matches_substrate_convention`
6185 // removed — clause (5) of
6186 // `tatara_closed_set::assert_closed_set_well_formed::<HorizonKind>()`
6187 // verifies the substrate-wide `"unknown {SET_LABEL}: {input}"`
6188 // shape generically (called from
6189 // `horizon_kind_is_well_formed_closed_set` above); the
6190 // `SET_LABEL` projection is pinned by
6191 // `tatara_lisp_derive::pascal_to_spaced_lowercase_tests`.
6192
6193 /// LOAD-BEARING TRUTH-TABLE: `terminates` is the boolean
6194 /// partition `Bounded ⇒ true`, `Asymptotic ⇒ false`. Pinning
6195 /// this table at one site means any future scheduler asking
6196 /// "will this Process reach `Reaped` via natural termination?"
6197 /// reads the same projection that the lattice ordering encodes
6198 /// (Bounded ≤ Asymptotic BECAUSE the bounded horizon strictly
6199 /// refines the asymptotic one by also terminating).
6200 #[test]
6201 fn horizon_kind_terminates_truth_table() {
6202 assert!(HorizonKind::Bounded.terminates());
6203 assert!(!HorizonKind::Asymptotic.terminates());
6204 }
6205
6206 /// LOAD-BEARING TRUTH-TABLE: `requires_metric_axes` is the
6207 /// boolean partition `Bounded ⇒ false`, `Asymptotic ⇒ true` —
6208 /// the typed image of the optionality the [`Horizon`] struct
6209 /// encodes via its three `Option<…>` fields (`metric`,
6210 /// `direction`, `healthy_rate_threshold`). The implicit
6211 /// "Asymptotic only" invariant in the field docs is now a
6212 /// checkable per-kind predicate. Pinning this table at one site
6213 /// means any future horizon-shape validator (CRD admission,
6214 /// `tatara-check` form linter, Lisp authoring-time predicate)
6215 /// reads the same projection.
6216 #[test]
6217 fn horizon_kind_requires_metric_axes_truth_table() {
6218 assert!(!HorizonKind::Bounded.requires_metric_axes());
6219 assert!(HorizonKind::Asymptotic.requires_metric_axes());
6220 }
6221
6222 /// COVERAGE CONTRACT: every variant lands in exactly one of two
6223 /// termination buckets — terminating (`Bounded`) or perpetual
6224 /// (`Asymptotic`). Pins the two buckets at their declared
6225 /// cardinalities (1, 1 — sum to `ALL.len()`) so a future variant
6226 /// lands somewhere deliberately.
6227 #[test]
6228 fn horizon_kind_buckets_cover_every_variant() {
6229 let mut terminating = 0u32;
6230 let mut perpetual = 0u32;
6231 for k in HorizonKind::ALL {
6232 if k.terminates() {
6233 terminating += 1;
6234 } else {
6235 perpetual += 1;
6236 }
6237 }
6238 assert_eq!(terminating, 1, "terminating bucket: Bounded");
6239 assert_eq!(perpetual, 1, "perpetual bucket: Asymptotic");
6240 assert_eq!(terminating + perpetual, HorizonKind::ALL.len() as u32);
6241 }
6242
6243 /// ANTISYMMETRY CONTRACT: for every variant, exactly one of
6244 /// `(terminates, requires_metric_axes)` is true — the two
6245 /// predicates carve the variants into complementary buckets
6246 /// (terminating ↔ no metric axes; perpetual ↔ requires metric
6247 /// axes). A future variant that returned `true` for both (a
6248 /// terminating horizon that nonetheless tracks an asymptotic
6249 /// metric) or `false` for both (an inert horizon with no
6250 /// termination AND no metric signal — there'd be nothing to
6251 /// observe) would fail here, forcing the author to extend
6252 /// either the predicates or the [`Horizon`] struct's
6253 /// optionality contract deliberately.
6254 #[test]
6255 fn horizon_kind_terminate_xor_requires_metric_axes() {
6256 for k in HorizonKind::ALL {
6257 assert!(
6258 k.terminates() ^ k.requires_metric_axes(),
6259 "{k:?}: terminates() XOR requires_metric_axes() must hold",
6260 );
6261 }
6262 }
6263
6264 /// DEFAULT-AGREEMENT CONTRACT: `HorizonKind::default()` returns
6265 /// `Bounded` (the variant tagged `#[default]`), AND that
6266 /// variant lands in the terminating bucket. A future
6267 /// `#[default]` rename without flipping the predicate fails
6268 /// here — `Bounded` is the canonical default for a convergence
6269 /// horizon (a point with no asymptotic axes declared should
6270 /// terminate naturally, not silently flip into a perpetual
6271 /// rate-window evaluator with zero threshold). This is also
6272 /// the same value `Horizon::default()` carries, so pinning the
6273 /// default here pins the struct-default behavior at one site.
6274 #[test]
6275 fn horizon_kind_default_is_bounded_terminates() {
6276 let k = HorizonKind::default();
6277 assert_eq!(k, HorizonKind::Bounded);
6278 assert!(k.terminates());
6279 assert!(!k.requires_metric_axes());
6280 }
6281
6282 /// HORIZON ↔ KIND AGREEMENT: every variant in `HorizonKind::ALL`
6283 /// composes with the existing [`Horizon::bounded`] /
6284 /// [`Horizon::asymptotic`] constructors to produce a `Horizon`
6285 /// whose `kind` matches AND whose `Option<…>` fields agree
6286 /// with `requires_metric_axes`. Pins the implicit contract
6287 /// between the kind discriminator and the optionality at one
6288 /// site — a future kind added without extending either the
6289 /// constructors or `requires_metric_axes` fails here before
6290 /// drifting between the typed surface and the documented
6291 /// "Asymptotic only" field invariant.
6292 #[test]
6293 fn horizon_kind_agrees_with_struct_optionality() {
6294 let bounded = Horizon::bounded();
6295 assert_eq!(bounded.kind, HorizonKind::Bounded);
6296 assert!(!bounded.kind.requires_metric_axes());
6297 assert!(bounded.metric.is_none());
6298 assert!(bounded.direction.is_none());
6299 assert!(bounded.healthy_rate_threshold.is_none());
6300
6301 let asymp = Horizon::asymptotic("p99_latency", OptimizationDirection::Minimize, 0.1);
6302 assert_eq!(asymp.kind, HorizonKind::Asymptotic);
6303 assert!(asymp.kind.requires_metric_axes());
6304 assert!(asymp.metric.is_some());
6305 assert!(asymp.direction.is_some());
6306 assert!(asymp.healthy_rate_threshold.is_some());
6307 }
6308
6309 // ── scalar-carrier presence probe on Classification × ConvergencePointType ──
6310 //
6311 // Fail-before-pass-after granularity: [`Classification::has_point_type`]
6312 // did not exist before this commit — every consumer of the
6313 // `(Classification, ConvergencePointType) -> bool` scalar-carrier
6314 // probe shape restated the `classification.point_type == kind`
6315 // equality body at its own callsite. Post-lift the shape lives at
6316 // ONE substrate owner and every downstream (the `point-type-<kind>`
6317 // require-tag family in `tatara-check`, future audit dispatchers
6318 // walking [`ConvergencePointType::ALL`], any future CRD-facing
6319 // closed-set discriminator on a required scalar `ProcessSpec` field
6320 // such as `has_substrate`/`has_calm`/`has_data_classification`)
6321 // binds through the SAME `has(kind)` shape the Option-slot
6322 // (`Intent::has`, `Lifetime::has`), slice-level
6323 // (`ConditionSliceExt::has_kind`, `DependsOnSliceExt::has_must_reach`,
6324 // `ComplianceBindingSliceExt::has_verification_phase`,
6325 // `ExportSpecSliceExt::has_{when,channel_kind,report_format,artifact_kind}`),
6326 // and prior scalar-carrier
6327 // (`SignalPolicy::has_sighup_strategy`,
6328 // `EncapsulatesSpec::has_mode`) peers publish.
6329
6330 /// DIAGONAL — for every [`ConvergencePointType`] variant, a
6331 /// [`Classification`] whose `point_type` field is set to that
6332 /// variant returns `true` from `has_point_type` on that same
6333 /// variant AND `false` on every other variant. Sweep the
6334 /// [`ConvergencePointType::ALL`] × ALL cross so a regression that
6335 /// hard-coded the arm to a single variant (silently returning
6336 /// `true` on every populated classification regardless of query
6337 /// kind) or wired the equality to a fixed unrelated field fails
6338 /// HERE at the substrate primitive before landing at the
6339 /// operator-facing checks.lisp surface.
6340 #[test]
6341 fn classification_has_point_type_returns_true_iff_variant_matches() {
6342 for populated in ConvergencePointType::ALL {
6343 let c = Classification::gate_compute_with_axis(populated);
6344 for query in ConvergencePointType::ALL {
6345 assert_eq!(
6346 c.has_point_type(query),
6347 query == populated,
6348 "point_type={populated:?}: query {query:?} classification drifted",
6349 );
6350 }
6351 }
6352 }
6353
6354 /// GATE-COMPUTE BASELINE — the workspace-baseline
6355 /// [`Classification::gate_compute`] shape carries
6356 /// `point_type: Gate`, so `has_point_type` returns `true` on
6357 /// [`ConvergencePointType::Gate`] and `false` on every other of
6358 /// the eight variants. Pins the composition of the substrate's
6359 /// baseline-constructor primitive with the scalar-carrier
6360 /// presence probe — a regression that flipped
6361 /// `gate_compute().point_type` off `Gate` (or wired
6362 /// `has_point_type` to a fixed variant answer) fails here at ONE
6363 /// narrow site before drifting across every unadorned ephemeral
6364 /// env (`default_ephemeral_class`) and every downstream test
6365 /// fixture that keys assertions on the shape.
6366 #[test]
6367 fn classification_gate_compute_has_point_type_gate_only() {
6368 let c = Classification::gate_compute();
6369 for kind in ConvergencePointType::ALL {
6370 let expected = kind == ConvergencePointType::Gate;
6371 assert_eq!(
6372 c.has_point_type(kind),
6373 expected,
6374 "gate_compute (point_type=Gate) must return {expected} for {kind:?}",
6375 );
6376 }
6377 }
6378
6379 // ── scalar-carrier presence probe on Classification × SubstrateType ──
6380 //
6381 // Fail-before-pass-after granularity: [`Classification::has_substrate`]
6382 // did not exist before this commit — every consumer of the
6383 // `(Classification, SubstrateType) -> bool` scalar-carrier probe
6384 // shape restated the `classification.substrate == kind` equality
6385 // body at its own callsite. Post-lift the shape lives at ONE
6386 // substrate owner and every downstream (the `substrate-<kind>`
6387 // require-tag family in `tatara-check`, future audit dispatchers
6388 // walking [`SubstrateType::ALL`], any future CRD-facing closed-set
6389 // discriminator on a required scalar `ProcessSpec` field such as
6390 // `has_calm`/`has_data_classification`) binds through the SAME
6391 // `has(kind)` shape the Option-slot (`Intent::has`, `Lifetime::has`),
6392 // slice-level (`ConditionSliceExt::has_kind`,
6393 // `DependsOnSliceExt::has_must_reach`,
6394 // `ComplianceBindingSliceExt::has_verification_phase`,
6395 // `ExportSpecSliceExt::has_{when,channel_kind,report_format,artifact_kind}`),
6396 // and prior scalar-carrier
6397 // (`SignalPolicy::has_sighup_strategy`,
6398 // `EncapsulatesSpec::has_mode`, `Classification::has_point_type`)
6399 // peers publish.
6400
6401 /// DIAGONAL — for every [`SubstrateType`] variant, a
6402 /// [`Classification`] whose `substrate` field is set to that
6403 /// variant returns `true` from `has_substrate` on that same
6404 /// variant AND `false` on every other variant. Sweep the
6405 /// [`SubstrateType::ALL`] × ALL cross so a regression that
6406 /// hard-coded the arm to a single variant (silently returning
6407 /// `true` on every populated classification regardless of query
6408 /// kind) or wired the equality to a fixed unrelated field (a
6409 /// stray probe on `classification.point_type`) fails HERE at the
6410 /// substrate primitive before landing at the operator-facing
6411 /// checks.lisp surface.
6412 #[test]
6413 fn classification_has_substrate_returns_true_iff_variant_matches() {
6414 for populated in SubstrateType::ALL {
6415 let c = Classification::gate_compute_with_axis(populated);
6416 for query in SubstrateType::ALL {
6417 assert_eq!(
6418 c.has_substrate(query),
6419 query == populated,
6420 "substrate={populated:?}: query {query:?} classification drifted",
6421 );
6422 }
6423 }
6424 }
6425
6426 /// GATE-COMPUTE BASELINE — the workspace-baseline
6427 /// [`Classification::gate_compute`] shape carries
6428 /// `substrate: Compute`, so `has_substrate` returns `true` on
6429 /// [`SubstrateType::Compute`] and `false` on every other of the
6430 /// eight variants. Pins the composition of the substrate's
6431 /// baseline-constructor primitive with the fourth scalar-carrier
6432 /// presence probe — a regression that flipped
6433 /// `gate_compute().substrate` off `Compute` (or wired
6434 /// `has_substrate` to a fixed variant answer, or crossed the
6435 /// wires to `point_type`) fails here at ONE narrow site before
6436 /// drifting across every unadorned ephemeral env
6437 /// (`default_ephemeral_class`) and every downstream test fixture
6438 /// that keys assertions on the shape. Byte-symmetric with the
6439 /// peer `classification_gate_compute_has_point_type_gate_only`
6440 /// pin on the third scalar-carrier — the two co-tenants on the
6441 /// (required-parent × required-scalar-child) corner walk their
6442 /// own required axis independently.
6443 #[test]
6444 fn classification_gate_compute_has_substrate_compute_only() {
6445 let c = Classification::gate_compute();
6446 for kind in SubstrateType::ALL {
6447 let expected = kind == SubstrateType::Compute;
6448 assert_eq!(
6449 c.has_substrate(kind),
6450 expected,
6451 "gate_compute (substrate=Compute) must return {expected} for {kind:?}",
6452 );
6453 }
6454 }
6455
6456 /// TWO-AXIS INDEPENDENCE — the two co-tenants on the (required-
6457 /// parent × required-scalar-child) corner of the presence-probe
6458 /// algebra ([`Classification::has_point_type`] and
6459 /// [`Classification::has_substrate`]) probe distinct required
6460 /// scalar slots on the SAME [`Classification`] parent, so a
6461 /// carrier with `point_type: Fork` AND `substrate: Storage`
6462 /// answers `true` on both fine tags simultaneously and `false`
6463 /// on every off-diagonal probe of either axis. Pins the two
6464 /// probes' independence at ONE narrow site — a regression that
6465 /// collapsed either onto the other's field (a stray probe of
6466 /// `has_substrate` reading `self.point_type`, or of
6467 /// `has_point_type` reading `self.substrate`) would fail HERE
6468 /// before landing at any consumer. The audit `every Fork-topology
6469 /// Storage-plane point handles SIGHUP by Restart` composes this
6470 /// exact two-axis conjunction on the required scalars of the
6471 /// six-axis classification lattice.
6472 #[test]
6473 fn classification_has_point_type_and_has_substrate_are_independent() {
6474 let c = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
6475 .with_axis(SubstrateType::Storage);
6476 assert!(c.has_point_type(ConvergencePointType::Fork));
6477 assert!(c.has_substrate(SubstrateType::Storage));
6478 assert!(!c.has_point_type(ConvergencePointType::Gate));
6479 assert!(!c.has_substrate(SubstrateType::Compute));
6480 // Cross-wiring probe: `has_point_type(Storage-as-if-Point)` and
6481 // `has_substrate(Fork-as-if-Substrate)` cannot even typecheck
6482 // — the closed-set enums are disjoint types — but a stray
6483 // implementation reading the WRONG required field would flip
6484 // both diagonal answers off. The four asserts above pin the
6485 // independence at ONE narrow site.
6486 }
6487
6488 // ── scalar-carrier presence probe on Classification × CalmClassification ──
6489 //
6490 // Fail-before-pass-after granularity: [`Classification::has_calm`]
6491 // did not exist before this commit — every consumer of the
6492 // `(Classification, CalmClassification) -> bool` scalar-carrier
6493 // probe shape restated the `classification.calm == kind` equality
6494 // body at its own callsite. Post-lift the shape lives at ONE
6495 // substrate owner and every downstream (the `calm-<kind>`
6496 // require-tag family in `tatara-check`, future audit dispatchers
6497 // walking [`CalmClassification::ALL`], any future CRD-facing
6498 // closed-set discriminator on a defaulted scalar `ProcessSpec`
6499 // field such as `has_data_classification`) binds through the SAME
6500 // `has(kind)` shape the Option-slot (`Intent::has`, `Lifetime::has`),
6501 // slice-level (`ConditionSliceExt::has_kind`,
6502 // `DependsOnSliceExt::has_must_reach`,
6503 // `ComplianceBindingSliceExt::has_verification_phase`,
6504 // `ExportSpecSliceExt::has_{when,channel_kind,report_format,artifact_kind}`),
6505 // and prior scalar-carrier
6506 // (`SignalPolicy::has_sighup_strategy`,
6507 // `EncapsulatesSpec::has_mode`, `Classification::has_point_type`,
6508 // `Classification::has_substrate`) peers publish. FIRST occupant
6509 // on the (required-parent × defaulted-scalar-child) corner of the
6510 // presence-probe algebra — a fresh corner distinct from all four
6511 // prior scalar-carrier peers.
6512
6513 /// DIAGONAL — for every [`CalmClassification`] variant, a
6514 /// [`Classification`] whose `calm` field is set to that variant
6515 /// returns `true` from `has_calm` on that same variant AND
6516 /// `false` on every other variant. Sweep the
6517 /// [`CalmClassification::ALL`] × ALL cross so a regression that
6518 /// hard-coded the arm to a single variant (silently returning
6519 /// `true` on every populated classification regardless of query
6520 /// kind) or wired the equality to a fixed unrelated field (a
6521 /// stray probe on `classification.point_type` or
6522 /// `classification.substrate`) fails HERE at the substrate
6523 /// primitive before landing at the operator-facing checks.lisp
6524 /// surface.
6525 #[test]
6526 fn classification_has_calm_returns_true_iff_variant_matches() {
6527 for populated in CalmClassification::ALL {
6528 let c = Classification::gate_compute_with_axis(populated);
6529 for query in CalmClassification::ALL {
6530 assert_eq!(
6531 c.has_calm(query),
6532 query == populated,
6533 "calm={populated:?}: query {query:?} classification drifted",
6534 );
6535 }
6536 }
6537 }
6538
6539 /// GATE-COMPUTE BASELINE — the workspace-baseline
6540 /// [`Classification::gate_compute`] shape carries
6541 /// `calm: CalmClassification::default()` which is
6542 /// [`CalmClassification::Monotone`] via `#[default]`, so
6543 /// `has_calm` returns `true` on [`CalmClassification::Monotone`]
6544 /// and `false` on [`CalmClassification::NonMonotone`]. Pins the
6545 /// composition of the substrate's baseline-constructor primitive
6546 /// with the FIFTH scalar-carrier presence probe AND the sibling-
6547 /// default correspondence documented on [`Classification::gate_compute`]
6548 /// (which pins the three defaulted axes to the sibling closed-set
6549 /// defaults `HorizonKind::Bounded` / `CalmClassification::Monotone`
6550 /// / `DataClassification::Internal`) — a regression that flipped
6551 /// `gate_compute().calm` off `Monotone` (or promoted a different
6552 /// variant to `#[default]` on the closed set, or wired `has_calm`
6553 /// to a fixed variant answer, or crossed the wires to
6554 /// `point_type` / `substrate`) fails here at ONE narrow site
6555 /// before drifting across every unadorned ephemeral env
6556 /// (`default_ephemeral_class`) and every downstream test fixture
6557 /// that keys assertions on the shape. FIRST occupant on the
6558 /// (required-parent × defaulted-scalar-child) corner — locks the
6559 /// corner's characteristic "default-arm short-circuit" property
6560 /// at ONE narrow classifier site: a bare classification answers
6561 /// `true` on the default variant (distinct from the
6562 /// required-child corner peers, where a bare classification must
6563 /// name a variant deliberately to answer `true`).
6564 #[test]
6565 fn classification_gate_compute_has_calm_monotone_only() {
6566 let c = Classification::gate_compute();
6567 for kind in CalmClassification::ALL {
6568 let expected = kind == CalmClassification::Monotone;
6569 assert_eq!(
6570 c.has_calm(kind),
6571 expected,
6572 "gate_compute (calm=Monotone) must return {expected} for {kind:?}",
6573 );
6574 }
6575 }
6576
6577 /// THREE-AXIS INDEPENDENCE — the three co-tenants on the
6578 /// [`Classification`] parent
6579 /// ([`Classification::has_point_type`] +
6580 /// [`Classification::has_substrate`] on the (required-parent ×
6581 /// required-scalar-child) corner AND [`Classification::has_calm`]
6582 /// on the fresh (required-parent × defaulted-scalar-child)
6583 /// corner) probe distinct scalar slots on the SAME parent, so a
6584 /// carrier with `point_type: Fork` AND `substrate: Storage` AND
6585 /// `calm: NonMonotone` answers `true` on all three fine tags
6586 /// simultaneously and `false` on every off-diagonal probe of any
6587 /// axis. Pins the three probes' independence at ONE narrow site
6588 /// — a regression that collapsed any of the three onto another's
6589 /// field (a stray probe of `has_calm` reading `self.point_type`
6590 /// or `self.substrate`, or of either required-axis probe reading
6591 /// `self.calm`) would fail HERE before landing at any consumer.
6592 /// The audit `every Fork-topology Storage-plane NonMonotone-CALM
6593 /// point declares a Raft-guarded write path` composes this exact
6594 /// three-axis conjunction on the required + defaulted scalars of
6595 /// the six-axis classification lattice.
6596 #[test]
6597 fn classification_has_point_type_and_has_substrate_and_has_calm_are_independent() {
6598 let c = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
6599 .with_axis(SubstrateType::Storage)
6600 .with_axis(CalmClassification::NonMonotone);
6601 assert!(c.has_point_type(ConvergencePointType::Fork));
6602 assert!(c.has_substrate(SubstrateType::Storage));
6603 assert!(c.has_calm(CalmClassification::NonMonotone));
6604 assert!(!c.has_point_type(ConvergencePointType::Gate));
6605 assert!(!c.has_substrate(SubstrateType::Compute));
6606 assert!(!c.has_calm(CalmClassification::Monotone));
6607 }
6608
6609 // ── scalar-carrier presence probe on Classification × DataClassification ──
6610 //
6611 // Fail-before-pass-after granularity:
6612 // [`Classification::has_data_classification`] did not exist before
6613 // this commit — every consumer of the
6614 // `(Classification, DataClassification) -> bool` scalar-carrier
6615 // probe shape would have to restate the
6616 // `classification.data_classification == kind` equality body at
6617 // its own callsite. Post-lift the shape lives at ONE substrate
6618 // owner and every downstream (the `data-classification-<kind>`
6619 // require-tag family in `tatara-check`, future audit dispatchers
6620 // walking [`DataClassification::ALL`], any future CRD-facing
6621 // closed-set discriminator on a defaulted scalar `ProcessSpec`
6622 // field) binds through the SAME `has(kind)` shape the four prior
6623 // scalar-carrier peers on [`Classification`]
6624 // ([`Classification::has_point_type`],
6625 // [`Classification::has_substrate`],
6626 // [`Classification::has_calm`]) plus
6627 // [`crate::spec::SignalPolicy::has_sighup_strategy`] and
6628 // [`crate::encapsulates::EncapsulatesSpec::has_mode`] publish.
6629 // SECOND occupant on the (required-parent × defaulted-scalar-
6630 // child) corner of the presence-probe algebra after
6631 // [`Classification::has_calm`] opened it — pins the corner as a
6632 // proven-repeatable primitive shape rather than a single-example
6633 // curiosity and closes the four-scalar-carrier corner-coverage
6634 // contract on the six-axis classification lattice.
6635
6636 /// DIAGONAL — for every [`DataClassification`] variant, a
6637 /// [`Classification`] whose `data_classification` field is set to
6638 /// that variant returns `true` from `has_data_classification` on
6639 /// that same variant AND `false` on every other variant. Sweep
6640 /// the [`DataClassification::ALL`] × ALL cross so a regression
6641 /// that hard-coded the arm to a single variant (silently returning
6642 /// `true` on every populated classification regardless of query
6643 /// kind) or wired the equality to a fixed unrelated field (a
6644 /// stray probe on `classification.point_type` /
6645 /// `classification.substrate` / `classification.calm`) fails HERE
6646 /// at the substrate primitive before landing at the operator-
6647 /// facing checks.lisp surface.
6648 #[test]
6649 fn classification_has_data_classification_returns_true_iff_variant_matches() {
6650 for populated in DataClassification::ALL {
6651 let c = Classification::gate_compute_with_axis(populated);
6652 for query in DataClassification::ALL {
6653 assert_eq!(
6654 c.has_data_classification(query),
6655 query == populated,
6656 "data_classification={populated:?}: query {query:?} classification drifted",
6657 );
6658 }
6659 }
6660 }
6661
6662 /// GATE-COMPUTE BASELINE — the workspace-baseline
6663 /// [`Classification::gate_compute`] shape carries
6664 /// `data_classification: DataClassification::default()` which is
6665 /// [`DataClassification::Internal`] via `#[default]`, so
6666 /// `has_data_classification` returns `true` on
6667 /// [`DataClassification::Internal`] and `false` on every other
6668 /// variant ([`DataClassification::Public`],
6669 /// [`DataClassification::Confidential`],
6670 /// [`DataClassification::Pii`], [`DataClassification::Phi`],
6671 /// [`DataClassification::Pci`]). Pins the composition of the
6672 /// substrate's baseline-constructor primitive with the SIXTH
6673 /// scalar-carrier presence probe AND the sibling-default
6674 /// correspondence documented on [`Classification::gate_compute`]
6675 /// (which pins the three defaulted axes to the sibling closed-set
6676 /// defaults `HorizonKind::Bounded` / `CalmClassification::Monotone`
6677 /// / `DataClassification::Internal`) — a regression that flipped
6678 /// `gate_compute().data_classification` off `Internal` (or
6679 /// promoted a different variant to `#[default]` on the closed
6680 /// set, or wired `has_data_classification` to a fixed variant
6681 /// answer, or crossed the wires to `point_type` / `substrate` /
6682 /// `calm`) fails here at ONE narrow site before drifting across
6683 /// every unadorned ephemeral env (`default_ephemeral_class`) and
6684 /// every downstream test fixture that keys assertions on the
6685 /// shape. SECOND occupant on the (required-parent × defaulted-
6686 /// scalar-child) corner — pins the corner's characteristic
6687 /// "default-arm short-circuit" property on its second occupant
6688 /// (peer to `classification_gate_compute_has_calm_monotone_only`
6689 /// which pins the same shape on the corner's first occupant).
6690 #[test]
6691 fn classification_gate_compute_has_data_classification_internal_only() {
6692 let c = Classification::gate_compute();
6693 for kind in DataClassification::ALL {
6694 let expected = kind == DataClassification::Internal;
6695 assert_eq!(
6696 c.has_data_classification(kind),
6697 expected,
6698 "gate_compute (data_classification=Internal) must return {expected} for {kind:?}",
6699 );
6700 }
6701 }
6702
6703 /// FOUR-AXIS INDEPENDENCE — the four scalar-carrier co-tenants
6704 /// on the [`Classification`] parent
6705 /// ([`Classification::has_point_type`] plus
6706 /// [`Classification::has_substrate`] on the (required-parent ×
6707 /// required-scalar-child) corner AND [`Classification::has_calm`]
6708 /// plus [`Classification::has_data_classification`] on the
6709 /// (required-parent × defaulted-scalar-child) corner) probe
6710 /// distinct scalar slots on the SAME parent, so a carrier with
6711 /// `point_type: Fork` AND `substrate: Storage` AND
6712 /// `calm: NonMonotone` AND `data_classification: Pii` answers
6713 /// `true` on all four fine tags simultaneously and `false` on
6714 /// every off-diagonal probe of any axis. Pins the four probes'
6715 /// independence at ONE narrow site — a regression that collapsed
6716 /// any of the four onto another's field (a stray probe of
6717 /// `has_data_classification` reading `self.point_type` /
6718 /// `self.substrate` / `self.calm`, or of any prior probe reading
6719 /// `self.data_classification`) would fail HERE before landing at
6720 /// any consumer. The audit `every Fork-topology Storage-plane
6721 /// NonMonotone-CALM Pii-classification point declares a
6722 /// Raft-guarded write path AND a downstream PII-scrub sink`
6723 /// composes this exact four-axis conjunction on the required +
6724 /// defaulted scalars of the six-axis classification lattice.
6725 /// Closes the four-scalar-carrier corner-coverage contract on
6726 /// [`Classification`] — its two required-scalar-child slots
6727 /// (`point_type`, `substrate`) AND its two defaulted-scalar-
6728 /// child slots (`calm`, `data_classification`) all publish
6729 /// independent presence probes through the same shape.
6730 #[test]
6731 fn classification_four_scalar_carrier_probes_are_independent() {
6732 let c = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
6733 .with_axis(SubstrateType::Storage)
6734 .with_axis(CalmClassification::NonMonotone)
6735 .with_axis(DataClassification::Pii);
6736 assert!(c.has_point_type(ConvergencePointType::Fork));
6737 assert!(c.has_substrate(SubstrateType::Storage));
6738 assert!(c.has_calm(CalmClassification::NonMonotone));
6739 assert!(c.has_data_classification(DataClassification::Pii));
6740 assert!(!c.has_point_type(ConvergencePointType::Gate));
6741 assert!(!c.has_substrate(SubstrateType::Compute));
6742 assert!(!c.has_calm(CalmClassification::Monotone));
6743 assert!(!c.has_data_classification(DataClassification::Internal));
6744 assert!(!c.has_data_classification(DataClassification::Public));
6745 assert!(!c.has_data_classification(DataClassification::Phi));
6746 }
6747
6748 // ── nested-struct-scalar-carrier presence probe on Classification × HorizonKind ──
6749 //
6750 // Fail-before-pass-after granularity:
6751 // [`Classification::has_horizon_kind`] did not exist before this
6752 // commit — every consumer of the `(Classification, HorizonKind) ->
6753 // bool` two-hop `self.horizon.kind == kind` probe shape would have
6754 // to restate the nested-struct field walk at its own callsite.
6755 // Post-lift the shape lives at ONE substrate owner and every
6756 // downstream (the `horizon-<kind>` require-tag family in
6757 // `tatara-check`, future audit dispatchers walking
6758 // [`HorizonKind::ALL`], any future CRD-facing nested-struct-scalar
6759 // discriminator on `ProcessSpec`) binds through the SAME
6760 // `has(kind)` shape the four prior scalar-carrier peers on
6761 // [`Classification`] ([`Classification::has_point_type`],
6762 // [`Classification::has_substrate`], [`Classification::has_calm`],
6763 // [`Classification::has_data_classification`]) plus
6764 // [`crate::spec::SignalPolicy::has_sighup_strategy`] and
6765 // [`crate::encapsulates::EncapsulatesSpec::has_mode`] publish.
6766 // FIRST occupant on the (required-parent × nested-struct-scalar-
6767 // child) corner of the presence-probe algebra — a fresh corner
6768 // distinct from the four corner-property-exhaustive scalar-carrier
6769 // peers on [`Classification`] (whose bodies read a closed-set
6770 // discriminator directly off a scalar slot without an intermediate
6771 // struct hop).
6772
6773 /// DIAGONAL — for every [`HorizonKind`] variant, a
6774 /// [`Classification`] whose `horizon.kind` field is set to that
6775 /// variant returns `true` from `has_horizon_kind` on that same
6776 /// variant AND `false` on every other variant. Sweep the
6777 /// [`HorizonKind::ALL`] × ALL cross so a regression that
6778 /// hard-coded the arm to a single variant (silently returning
6779 /// `true` on every populated classification regardless of query
6780 /// kind) or wired the equality to a fixed unrelated field (a
6781 /// stray probe on `classification.point_type` /
6782 /// `classification.substrate` / `classification.calm` /
6783 /// `classification.data_classification`, or a direct probe on the
6784 /// nested [`Horizon`] struct that ignored the discriminator arm)
6785 /// fails HERE at the substrate primitive before landing at the
6786 /// operator-facing checks.lisp surface. The nested-struct hop
6787 /// distinguishes this corner from the four scalar-carrier peers:
6788 /// the probe walks `self.horizon.kind` not `self.<field>`, so a
6789 /// regression that mis-routed the field walk (a stray
6790 /// `self.horizon == kind` that could not typecheck, or a stray
6791 /// `self.horizon.direction == kind` that would trip a different
6792 /// closed-set discriminator) fails at the compiler before the
6793 /// runtime diagonal even runs.
6794 #[test]
6795 fn classification_has_horizon_kind_returns_true_iff_variant_matches() {
6796 for populated in HorizonKind::ALL {
6797 let c = Classification::gate_compute_with_axis(populated);
6798 for query in HorizonKind::ALL {
6799 assert_eq!(
6800 c.has_horizon_kind(query),
6801 query == populated,
6802 "horizon.kind={populated:?}: query {query:?} classification drifted",
6803 );
6804 }
6805 }
6806 }
6807
6808 /// GATE-COMPUTE BASELINE — the workspace-baseline
6809 /// [`Classification::gate_compute`] shape carries
6810 /// `horizon: Horizon::default()` whose `kind` field defaults to
6811 /// [`HorizonKind::Bounded`] via `#[default]`, so `has_horizon_kind`
6812 /// returns `true` on [`HorizonKind::Bounded`] and `false` on
6813 /// [`HorizonKind::Asymptotic`]. Pins the composition of the
6814 /// substrate's baseline-constructor primitive with the SEVENTH
6815 /// presence-probe peer AND the sibling-default correspondence
6816 /// documented on [`Classification::gate_compute`] (which pins the
6817 /// three defaulted axes to the sibling closed-set defaults
6818 /// `HorizonKind::Bounded` / `CalmClassification::Monotone` /
6819 /// `DataClassification::Internal`) — a regression that flipped
6820 /// `Horizon::default().kind` off `Bounded` (or promoted
6821 /// `Asymptotic` to `#[default]` on [`HorizonKind`], or wired
6822 /// `has_horizon_kind` to a fixed variant answer, or crossed the
6823 /// wires through the wrong nested struct) fails here at ONE
6824 /// narrow site before drifting across every unadorned ephemeral
6825 /// env (`default_ephemeral_class`) and every downstream test
6826 /// fixture that keys assertions on the shape. FIRST occupant on
6827 /// the (required-parent × nested-struct-scalar-child) corner —
6828 /// locks the corner's characteristic "default-arm short-circuit
6829 /// reaches through the nested struct's own default" property at
6830 /// ONE narrow site.
6831 #[test]
6832 fn classification_gate_compute_has_horizon_kind_bounded_only() {
6833 let c = Classification::gate_compute();
6834 for kind in HorizonKind::ALL {
6835 let expected = kind == HorizonKind::Bounded;
6836 assert_eq!(
6837 c.has_horizon_kind(kind),
6838 expected,
6839 "gate_compute (horizon.kind=Bounded) must return {expected} for {kind:?}",
6840 );
6841 }
6842 }
6843
6844 /// FIVE-AXIS INDEPENDENCE — the FIVE presence-probe co-tenants on
6845 /// the [`Classification`] parent
6846 /// ([`Classification::has_point_type`] plus
6847 /// [`Classification::has_substrate`] on the (required-parent ×
6848 /// required-scalar-child) corner AND
6849 /// [`Classification::has_calm`] plus
6850 /// [`Classification::has_data_classification`] on the (required-
6851 /// parent × defaulted-scalar-child) corner AND
6852 /// [`Classification::has_horizon_kind`] on the fresh (required-
6853 /// parent × nested-struct-scalar-child) corner) probe distinct
6854 /// slots on the SAME parent, so a carrier with `point_type: Fork`
6855 /// AND `substrate: Storage` AND `calm: NonMonotone` AND
6856 /// `data_classification: Pii` AND `horizon.kind: Asymptotic`
6857 /// answers `true` on all five fine tags simultaneously and
6858 /// `false` on every off-diagonal probe of any axis. Pins the five
6859 /// probes' independence at ONE narrow site — a regression that
6860 /// collapsed any of the five onto another's field (a stray probe
6861 /// of `has_horizon_kind` reading `self.point_type` /
6862 /// `self.substrate` / `self.calm` / `self.data_classification`,
6863 /// or of any prior probe reading through `self.horizon.kind`)
6864 /// would fail HERE before landing at any consumer. The audit
6865 /// `every Fork-topology Storage-plane NonMonotone-CALM
6866 /// Pii-classification Asymptotic-horizon point declares a
6867 /// Raft-guarded write path AND a downstream PII-scrub sink AND a
6868 /// rate-window healthy-threshold metric` composes this exact
6869 /// five-axis conjunction on the five classification-axis
6870 /// discriminators of the six-axis classification lattice — opens
6871 /// the five-way corner-coverage contract on [`Classification`],
6872 /// straddling THREE distinct corners of the (parent-shape ×
6873 /// child-shape) algebra (the required-child corner
6874 /// `has_point_type` + `has_substrate` share, the defaulted-child
6875 /// corner `has_calm` + `has_data_classification` share, and the
6876 /// nested-struct-child corner `has_horizon_kind` opens).
6877 #[test]
6878 fn classification_five_presence_probes_are_independent() {
6879 let c = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
6880 .with_axis(SubstrateType::Storage)
6881 .with_axis(CalmClassification::NonMonotone)
6882 .with_axis(DataClassification::Pii)
6883 .with_axis(HorizonKind::Asymptotic);
6884 assert!(c.has_point_type(ConvergencePointType::Fork));
6885 assert!(c.has_substrate(SubstrateType::Storage));
6886 assert!(c.has_calm(CalmClassification::NonMonotone));
6887 assert!(c.has_data_classification(DataClassification::Pii));
6888 assert!(c.has_horizon_kind(HorizonKind::Asymptotic));
6889 assert!(!c.has_point_type(ConvergencePointType::Gate));
6890 assert!(!c.has_substrate(SubstrateType::Compute));
6891 assert!(!c.has_calm(CalmClassification::Monotone));
6892 assert!(!c.has_data_classification(DataClassification::Internal));
6893 assert!(!c.has_horizon_kind(HorizonKind::Bounded));
6894 }
6895
6896 // ── nested-struct-Option-scalar-carrier presence probe on Classification × OptimizationDirection ──
6897 //
6898 // Fail-before-pass-after granularity:
6899 // [`Classification::has_optimization_direction`] did not exist
6900 // before this commit — every consumer of the
6901 // `(Classification, OptimizationDirection) -> bool` two-hop
6902 // `self.horizon.direction.unwrap_or_default() == kind` probe
6903 // shape would have to restate the nested-struct-Option field
6904 // walk at its own callsite. Post-lift the shape lives at ONE
6905 // substrate owner and every downstream (the
6906 // `optimization-direction-<kind>` require-tag family in
6907 // `tatara-check`, future audit dispatchers walking
6908 // [`OptimizationDirection::ALL`], any future CRD-facing nested-
6909 // struct-Option-scalar discriminator on `ProcessSpec`) binds
6910 // through the SAME `has(kind)` shape the six prior presence
6911 // probes on [`Classification`] plus its cousins on
6912 // [`crate::spec::SignalPolicy`] and
6913 // [`crate::encapsulates::EncapsulatesSpec`] publish. SECOND
6914 // occupant on the (required-parent × nested-struct-scalar-
6915 // child) corner of the presence-probe algebra — the FIRST
6916 // occupant [`Classification::has_horizon_kind`] read the nested
6917 // scalar `horizon.kind: HorizonKind` DIRECTLY; this probe adds
6918 // the `Option`-hop through `direction: Option<OptimizationDirection>`
6919 // via `Option::unwrap_or_default`, pinning the corner as a
6920 // proven-repeatable primitive shape rather than a single-example
6921 // curiosity.
6922
6923 /// DIAGONAL — for every [`OptimizationDirection`] variant, a
6924 /// [`Classification`] whose `horizon.direction` field is set to
6925 /// `Some(that variant)` returns `true` from
6926 /// `has_optimization_direction` on that same variant AND
6927 /// `false` on every other variant. Sweep the
6928 /// [`OptimizationDirection::ALL`] × ALL cross so a regression
6929 /// that hard-coded the arm to a single variant (silently
6930 /// returning `true` on every populated classification regardless
6931 /// of query kind) or wired the equality to a fixed unrelated
6932 /// field (a stray probe on `classification.point_type` /
6933 /// `classification.substrate` / `classification.calm` /
6934 /// `classification.data_classification` /
6935 /// `classification.horizon.kind`, or a direct probe on the
6936 /// nested [`Horizon`] struct that ignored the `direction` arm)
6937 /// fails HERE at the substrate primitive before landing at the
6938 /// operator-facing checks.lisp surface. The `Option`-hop
6939 /// distinguishes this method from the direct-nested-scalar
6940 /// peer [`Classification::has_horizon_kind`]: the probe walks
6941 /// `self.horizon.direction.unwrap_or_default()` not
6942 /// `self.horizon.kind`, so a regression that mis-routed the
6943 /// field walk (a stray `self.horizon.kind == kind` that could
6944 /// not typecheck, or a stray `self.horizon == kind` that also
6945 /// could not typecheck) fails at the compiler before the
6946 /// runtime diagonal even runs.
6947 #[test]
6948 fn classification_has_optimization_direction_returns_true_iff_variant_matches() {
6949 for populated in OptimizationDirection::ALL {
6950 let c = Classification::gate_compute_with_axis(HorizonKind::Asymptotic)
6951 .with_axis(populated);
6952 for query in OptimizationDirection::ALL {
6953 assert_eq!(
6954 c.has_optimization_direction(query),
6955 query == populated,
6956 "horizon.direction=Some({populated:?}): query {query:?} classification drifted",
6957 );
6958 }
6959 }
6960 }
6961
6962 /// GATE-COMPUTE BASELINE — the workspace-baseline
6963 /// [`Classification::gate_compute`] shape carries
6964 /// `horizon: Horizon::default()` whose `direction` field defaults
6965 /// to `None`. Under [`Option::unwrap_or_default`] the probe
6966 /// answers as if the field were `OptimizationDirection::default()`
6967 /// = [`OptimizationDirection::Minimize`] via `#[default]`, so
6968 /// `has_optimization_direction` returns `true` on
6969 /// [`OptimizationDirection::Minimize`] and `false` on
6970 /// [`OptimizationDirection::Maximize`]. Pins the composition of
6971 /// the substrate's baseline-constructor primitive with the
6972 /// EIGHTH presence-probe peer AND the closed-set-default
6973 /// correspondence documented on [`OptimizationDirection`] —
6974 /// a regression that flipped `OptimizationDirection::default()`
6975 /// off `Minimize` (which would silently invert every unadorned
6976 /// `Asymptotic` Process's rate-window evaluator polarity), or
6977 /// wired `has_optimization_direction` to a fixed variant answer,
6978 /// or crossed the wires through the wrong nested struct or the
6979 /// wrong Option-slot, fails here at ONE narrow site before
6980 /// drifting across every unadorned ephemeral env
6981 /// (`default_ephemeral_class`) and every downstream test fixture
6982 /// that keys assertions on the shape. SECOND occupant on the
6983 /// (required-parent × nested-struct-scalar-child) corner —
6984 /// locks the corner's Option-hop default-arm short-circuit
6985 /// property at ONE narrow site (the Option `None` folds onto
6986 /// the closed set's `#[default]` via `unwrap_or_default`,
6987 /// mirroring the direct-nested-scalar's default-arm short-
6988 /// circuit through the nested struct's own default).
6989 #[test]
6990 fn classification_gate_compute_has_optimization_direction_minimize_only() {
6991 let c = Classification::gate_compute();
6992 for kind in OptimizationDirection::ALL {
6993 let expected = kind == OptimizationDirection::Minimize;
6994 assert_eq!(
6995 c.has_optimization_direction(kind),
6996 expected,
6997 "gate_compute (horizon.direction=None ⇒ default Minimize) must return {expected} for {kind:?}",
6998 );
6999 }
7000 }
7001
7002 /// SIX-AXIS INDEPENDENCE — the SIX presence-probe co-tenants on
7003 /// the [`Classification`] parent
7004 /// ([`Classification::has_point_type`] plus
7005 /// [`Classification::has_substrate`] on the (required-parent ×
7006 /// required-scalar-child) corner AND
7007 /// [`Classification::has_calm`] plus
7008 /// [`Classification::has_data_classification`] on the (required-
7009 /// parent × defaulted-scalar-child) corner AND
7010 /// [`Classification::has_horizon_kind`] plus
7011 /// [`Classification::has_optimization_direction`] on the
7012 /// (required-parent × nested-struct-scalar-child) corner) probe
7013 /// distinct slots on the SAME parent, so a carrier with
7014 /// `point_type: Fork` AND `substrate: Storage` AND
7015 /// `calm: NonMonotone` AND `data_classification: Pii` AND
7016 /// `horizon.kind: Asymptotic` AND
7017 /// `horizon.direction: Some(Maximize)` answers `true` on all six
7018 /// fine tags simultaneously and `false` on every off-diagonal
7019 /// probe of any axis. Pins the six probes' independence at ONE
7020 /// narrow site — a regression that collapsed any of the six
7021 /// onto another's field (a stray probe of
7022 /// `has_optimization_direction` reading `self.point_type` /
7023 /// `self.substrate` / `self.calm` /
7024 /// `self.data_classification` / `self.horizon.kind`, or of any
7025 /// prior probe reading through `self.horizon.direction`) would
7026 /// fail HERE before landing at any consumer. The audit
7027 /// `every Fork-topology Storage-plane NonMonotone-CALM
7028 /// Pii-classification Asymptotic-horizon Maximize-direction
7029 /// point declares a rate-window healthy-threshold metric and a
7030 /// throughput-oriented SLO` composes this exact six-axis
7031 /// conjunction on the six classification-axis discriminators of
7032 /// the six-axis classification lattice — populates the six-way
7033 /// corner-coverage contract on [`Classification`], now
7034 /// straddling THREE distinct corners of the (parent-shape ×
7035 /// child-shape) algebra with TWO co-tenants each on the
7036 /// nested-struct-child corner: direct-nested-scalar
7037 /// (`has_horizon_kind`) and Option-nested-scalar
7038 /// (`has_optimization_direction`).
7039 #[test]
7040 fn classification_six_presence_probes_are_independent() {
7041 let c = Classification::gate_compute_with_axis(ConvergencePointType::Fork)
7042 .with_axis(SubstrateType::Storage)
7043 .with_axis(CalmClassification::NonMonotone)
7044 .with_axis(DataClassification::Pii)
7045 .with_axis(HorizonKind::Asymptotic)
7046 .with_axis(OptimizationDirection::Maximize);
7047 assert!(c.has_point_type(ConvergencePointType::Fork));
7048 assert!(c.has_substrate(SubstrateType::Storage));
7049 assert!(c.has_calm(CalmClassification::NonMonotone));
7050 assert!(c.has_data_classification(DataClassification::Pii));
7051 assert!(c.has_horizon_kind(HorizonKind::Asymptotic));
7052 assert!(c.has_optimization_direction(OptimizationDirection::Maximize));
7053 assert!(!c.has_point_type(ConvergencePointType::Gate));
7054 assert!(!c.has_substrate(SubstrateType::Compute));
7055 assert!(!c.has_calm(CalmClassification::Monotone));
7056 assert!(!c.has_data_classification(DataClassification::Internal));
7057 assert!(!c.has_horizon_kind(HorizonKind::Bounded));
7058 assert!(!c.has_optimization_direction(OptimizationDirection::Minimize));
7059 }
7060
7061 // ── derived-typed-projection presence probe on Classification × Arity ──
7062 //
7063 // Fail-before-pass-after granularity:
7064 // [`Classification::has_input_arity`] did not exist before this
7065 // commit — every consumer of the `(Classification, Arity) -> bool`
7066 // two-hop `self.point_type.input_arity() == kind` probe shape
7067 // would have to restate the derived-typed-projection walk at its
7068 // own callsite. Post-lift the shape lives at ONE substrate owner
7069 // and every downstream (the `input-arity-<kind>` require-tag
7070 // family in `tatara-check`, future DAG-composition validators
7071 // walking [`Arity::ALL`], any future consumer keying on the
7072 // input-edge cardinality of a Process's convergence point) binds
7073 // through the SAME `has(kind)` shape the two prior nested-struct-
7074 // scalar-child peers on [`Classification`]
7075 // ([`Classification::has_horizon_kind`] and
7076 // [`Classification::has_optimization_direction`]) publish. FIRST
7077 // occupant of the DERIVED-TYPED-PROJECTION variant on the
7078 // (required-parent × nested-struct-scalar-child) corner — widening
7079 // the corner from "raw discriminator only" to "raw discriminator
7080 // OR typed projection over the child", mirroring the derived-typed-
7081 // projection precedent
7082 // [`crate::export::ExportSpecSliceExt::has_report_payload_shape`]
7083 // set on the (Option-parent × Vec-child × nested-Option-carrier ×
7084 // derived-typed-projection) corner.
7085
7086 /// PROJECTION-TRUTH-TABLE — for every [`ConvergencePointType`]
7087 /// variant, `has_input_arity` on a [`Classification`] whose
7088 /// `point_type` field is set to that variant returns `true` on
7089 /// EXACTLY the [`Arity`] variant that
7090 /// [`ConvergencePointType::input_arity`] projects to (and `false`
7091 /// on every other variant). Sweep the
7092 /// [`ConvergencePointType::ALL`] × [`Arity::ALL`] cross so a
7093 /// regression that (a) probed [`ConvergencePointType`] directly
7094 /// (dropping the `.input_arity()` call, silently answering `true`
7095 /// on the populated slot only when the query happens to name the
7096 /// same variant), (b) inverted the projection (`One ↔ Many`), (c)
7097 /// crossed the wires with the sibling
7098 /// [`ConvergencePointType::output_arity`] projection (which
7099 /// disagrees on the fan-out arms), (d) hard-coded the arm to a
7100 /// single [`Arity`] (silently returning `true` for every
7101 /// populated classification regardless of query kind), or (e)
7102 /// wired the equality to a fixed unrelated field fails HERE at
7103 /// the substrate primitive before landing at the operator-facing
7104 /// checks.lisp surface. The projection's many-to-one shape is
7105 /// pinned SYMMETRICALLY on both sides of the cross: `Transform`,
7106 /// `Fork`, `Broadcast`, `Observe` populated arms answer `true`
7107 /// only for `Arity::One`; `Join`, `Gate`, `Select`, `Reduce`
7108 /// populated arms answer `true` only for `Arity::Many`.
7109 #[test]
7110 fn classification_has_input_arity_returns_true_iff_projection_matches_per_kind() {
7111 for populated in ConvergencePointType::ALL {
7112 let c = Classification::gate_compute_with_axis(populated);
7113 let expected_arity = populated.input_arity();
7114 for query in Arity::ALL {
7115 assert_eq!(
7116 c.has_input_arity(query),
7117 query == expected_arity,
7118 "point_type={populated:?} → input_arity={expected_arity:?}: query {query:?} classification drifted",
7119 );
7120 }
7121 }
7122 }
7123
7124 /// GATE-COMPUTE BASELINE — the workspace-baseline
7125 /// [`Classification::gate_compute`] shape carries
7126 /// `point_type: ConvergencePointType::Gate`, and
7127 /// [`ConvergencePointType::input_arity`] projects `Gate → Many`,
7128 /// so `has_input_arity` returns `true` on [`Arity::Many`] and
7129 /// `false` on [`Arity::One`]. Pins the composition of the
7130 /// substrate's baseline-constructor primitive with this
7131 /// presence-probe peer and the sibling-projection correspondence
7132 /// (which pins `Gate` to the fan-in `Many` bucket at ONE
7133 /// projection site) — a regression that flipped `Gate`'s
7134 /// `input_arity` bucket (silently mis-classifying every Gate as a
7135 /// `One`-input point at every downstream DAG-composition
7136 /// validator + this require-tag family), or that wired
7137 /// `has_input_arity` to a fixed arity answer, or that crossed the
7138 /// wires with `output_arity` (which sends `Gate → One`, the
7139 /// opposite bucket) fails here at ONE narrow site before drifting
7140 /// across every downstream fixture that keys assertions on the
7141 /// shape. FIRST derived-typed-projection occupant on the
7142 /// (required-parent × nested-struct-scalar-child) corner — locks
7143 /// the corner's characteristic "projection propagates through a
7144 /// bucket collapse consistently" property at ONE narrow site.
7145 #[test]
7146 fn classification_gate_compute_has_input_arity_many_only() {
7147 let c = Classification::gate_compute();
7148 for kind in Arity::ALL {
7149 let expected = kind == Arity::Many;
7150 assert_eq!(
7151 c.has_input_arity(kind),
7152 expected,
7153 "gate_compute (point_type=Gate → input_arity=Many) must return {expected} for {kind:?}",
7154 );
7155 }
7156 }
7157
7158 /// SIBLING-INDEPENDENCE — the peer scalar-carrier
7159 /// [`Classification::has_point_type`] and the peer derived-typed-
7160 /// projection [`Classification::has_input_arity`] read the SAME
7161 /// underlying slot (`self.point_type`) but through different
7162 /// closed sets ([`ConvergencePointType::ALL`] vs.
7163 /// [`Arity::ALL`]) — the arity probe is a many-to-one collapse of
7164 /// the point-type probe through
7165 /// [`ConvergencePointType::input_arity`]. A carrier with
7166 /// `point_type: Fork` MUST simultaneously answer
7167 /// `has_point_type(Fork) = true` AND
7168 /// `has_input_arity(One) = true` (Fork's input_arity projection),
7169 /// AND simultaneously answer
7170 /// `has_point_type(Broadcast) = false` (different variant, same
7171 /// bucket) AND `has_input_arity(Many) = false` (opposite bucket).
7172 /// Pins the projection-composition contract at ONE narrow site —
7173 /// a regression that (a) collapsed `has_input_arity` onto
7174 /// `has_point_type` (silently answering `true` only when the
7175 /// query names the raw point type, an out-of-vocabulary Arity
7176 /// query), (b) collapsed `has_point_type` onto `has_input_arity`
7177 /// (silently answering `true` for every point-type in the same
7178 /// arity bucket), or (c) swapped the projection direction fails
7179 /// HERE at the substrate before landing at any consumer. Peer of
7180 /// the [`crate::export::ExportSpecSliceExt`]'s
7181 /// SAME-CARRIER PROJECTION-COEXISTENCE pins on the
7182 /// `Option<TestReportSource>` nested-Option carrier
7183 /// (`has_report_format` vs. `has_report_payload_shape`) — the
7184 /// same "one carrier, two probes at different projection depths"
7185 /// contract pinned on the (required-parent × nested-struct-
7186 /// scalar-child) corner rather than on the (Option-parent ×
7187 /// Vec-child × nested-Option-carrier) corner.
7188 #[test]
7189 fn classification_has_input_arity_and_has_point_type_coexist_via_projection() {
7190 let c = Classification::gate_compute_with_axis(ConvergencePointType::Fork);
7191 assert!(c.has_point_type(ConvergencePointType::Fork));
7192 assert!(c.has_input_arity(Arity::One));
7193 assert!(!c.has_point_type(ConvergencePointType::Broadcast));
7194 assert!(!c.has_input_arity(Arity::Many));
7195 }
7196
7197 // ── second derived-typed-projection presence probe on Classification × Arity ──
7198 //
7199 // Fail-before-pass-after granularity:
7200 // [`Classification::has_output_arity`] did not exist before this
7201 // commit — every consumer of the `(Classification, Arity) -> bool`
7202 // two-hop `self.point_type.output_arity() == kind` probe shape
7203 // would have to restate the derived-typed-projection walk at its
7204 // own callsite. Post-lift the shape lives at ONE substrate owner
7205 // and every downstream (the `output-arity-<kind>` require-tag
7206 // family in `tatara-check`, future DAG-composition validators
7207 // walking [`Arity::ALL`] on the fan-out side, any future consumer
7208 // keying on the output-edge cardinality of a Process's convergence
7209 // point) binds through the SAME `has(kind)` shape the peer input-
7210 // side probe [`Classification::has_input_arity`] publishes. SECOND
7211 // occupant of the DERIVED-TYPED-PROJECTION variant on the
7212 // (required-parent × nested-struct-scalar-child) corner — closing
7213 // the DAG-composition arity pair by mirroring `has_input_arity`
7214 // through the sibling [`ConvergencePointType::output_arity`]
7215 // projection.
7216
7217 /// PROJECTION-TRUTH-TABLE — for every [`ConvergencePointType`]
7218 /// variant, `has_output_arity` on a [`Classification`] whose
7219 /// `point_type` field is set to that variant returns `true` on
7220 /// EXACTLY the [`Arity`] variant that
7221 /// [`ConvergencePointType::output_arity`] projects to (and `false`
7222 /// on every other variant). Sweep the
7223 /// [`ConvergencePointType::ALL`] × [`Arity::ALL`] cross so a
7224 /// regression that (a) probed [`ConvergencePointType`] directly
7225 /// (dropping the `.output_arity()` call, silently answering `true`
7226 /// on the populated slot only when the query happens to name the
7227 /// same variant), (b) inverted the projection (`One ↔ Many`), (c)
7228 /// crossed the wires with the sibling
7229 /// [`ConvergencePointType::input_arity`] projection (which
7230 /// disagrees on the diffusive `Fork | Broadcast → Many` output vs.
7231 /// `Fork | Broadcast → One` input, AND on the convergent `Join |
7232 /// Gate | Select | Reduce → One` output vs. `Many` input), (d)
7233 /// hard-coded the arm to a single [`Arity`] (silently returning
7234 /// `true` for every populated classification regardless of query
7235 /// kind), or (e) wired the equality to a fixed unrelated field
7236 /// fails HERE at the substrate primitive before landing at the
7237 /// operator-facing checks.lisp surface. The projection's many-to-
7238 /// one shape is pinned SYMMETRICALLY on both sides of the cross:
7239 /// `Fork`, `Broadcast` populated arms answer `true` only for
7240 /// `Arity::Many`; every other variant answers `true` only for
7241 /// `Arity::One`.
7242 #[test]
7243 fn classification_has_output_arity_returns_true_iff_projection_matches_per_kind() {
7244 for populated in ConvergencePointType::ALL {
7245 let c = Classification::gate_compute_with_axis(populated);
7246 let expected_arity = populated.output_arity();
7247 for query in Arity::ALL {
7248 assert_eq!(
7249 c.has_output_arity(query),
7250 query == expected_arity,
7251 "point_type={populated:?} → output_arity={expected_arity:?}: query {query:?} classification drifted",
7252 );
7253 }
7254 }
7255 }
7256
7257 /// GATE-COMPUTE BASELINE — the workspace-baseline
7258 /// [`Classification::gate_compute`] shape carries
7259 /// `point_type: ConvergencePointType::Gate`, and
7260 /// [`ConvergencePointType::output_arity`] projects `Gate → One`,
7261 /// so `has_output_arity` returns `true` on [`Arity::One`] and
7262 /// `false` on [`Arity::Many`] — the MIRROR of the peer
7263 /// [`Self::has_input_arity`] baseline (`Gate → input_arity = Many`),
7264 /// which pins the convergent `(Many, One)` bucket at ONE
7265 /// projection pair site. Pins the composition of the substrate's
7266 /// baseline-constructor primitive with this presence-probe peer
7267 /// and the sibling-projection correspondence (which pins `Gate` to
7268 /// the fan-in `Many` input × fan-out `One` output cell) — a
7269 /// regression that flipped `Gate`'s `output_arity` bucket
7270 /// (silently mis-classifying every Gate as a `Many`-output point
7271 /// at every downstream DAG-composition validator + this
7272 /// require-tag family), or that wired `has_output_arity` to a
7273 /// fixed arity answer, or that crossed the wires with
7274 /// `input_arity` (which sends `Gate → Many`, the opposite bucket)
7275 /// fails here at ONE narrow site before drifting across every
7276 /// downstream fixture that keys assertions on the shape.
7277 #[test]
7278 fn classification_gate_compute_has_output_arity_one_only() {
7279 let c = Classification::gate_compute();
7280 for kind in Arity::ALL {
7281 let expected = kind == Arity::One;
7282 assert_eq!(
7283 c.has_output_arity(kind),
7284 expected,
7285 "gate_compute (point_type=Gate → output_arity=One) must return {expected} for {kind:?}",
7286 );
7287 }
7288 }
7289
7290 /// CROSS-PROJECTION COEXISTENCE — the peer input-side probe
7291 /// [`Classification::has_input_arity`] and the output-side probe
7292 /// [`Classification::has_output_arity`] read the SAME underlying
7293 /// slot (`self.point_type`) through the SAME closed set
7294 /// ([`Arity::ALL`]) but through DIFFERENT typed projections
7295 /// ([`ConvergencePointType::input_arity`] vs.
7296 /// [`ConvergencePointType::output_arity`]). A carrier with
7297 /// `point_type: Fork` (the diffusive `(One, Many)` cell) MUST
7298 /// simultaneously answer `has_input_arity(One) = true` AND
7299 /// `has_output_arity(Many) = true` (Fork's arity pair), AND
7300 /// simultaneously answer `has_input_arity(Many) = false` AND
7301 /// `has_output_arity(One) = false` (opposite buckets). A carrier
7302 /// with `point_type: Transform` (the endomorphic `(One, One)`
7303 /// cell) MUST answer both probes with `Arity::One = true` — the
7304 /// two projections AGREE in the endomorphic bucket. A carrier with
7305 /// `point_type: Gate` (the convergent `(Many, One)` cell) MUST
7306 /// answer `has_input_arity(Many) = true` AND
7307 /// `has_output_arity(One) = true` — the mirror of the Fork case.
7308 /// Pins the projection-composition contract at ONE narrow site —
7309 /// a regression that (a) collapsed `has_output_arity` onto
7310 /// `has_input_arity` (silently answering the input arity for
7311 /// every output query on Fork/Broadcast/Join/Gate/Select/Reduce,
7312 /// the six variants where the two projections disagree), (b)
7313 /// swapped the projection direction (`Fork → (Many, One)` instead
7314 /// of `(One, Many)`), or (c) drifted the topology-bucket contract
7315 /// (silently mis-classifying Fork as endomorphic) fails HERE at
7316 /// the substrate before landing at any consumer. THIS is the DAG-
7317 /// composition arity pair pinned at ONE narrow site — the exact
7318 /// property `convergence_point_type_arity_pair_agrees_with_bucket`
7319 /// pins on the source projection functions themselves.
7320 #[test]
7321 fn classification_has_input_arity_and_has_output_arity_pin_dag_composition_pair() {
7322 let fork = Classification::gate_compute_with_axis(ConvergencePointType::Fork);
7323 assert!(fork.has_input_arity(Arity::One));
7324 assert!(fork.has_output_arity(Arity::Many));
7325 assert!(!fork.has_input_arity(Arity::Many));
7326 assert!(!fork.has_output_arity(Arity::One));
7327
7328 let transform = Classification::gate_compute_with_axis(ConvergencePointType::Transform);
7329 assert!(transform.has_input_arity(Arity::One));
7330 assert!(transform.has_output_arity(Arity::One));
7331 assert!(!transform.has_input_arity(Arity::Many));
7332 assert!(!transform.has_output_arity(Arity::Many));
7333
7334 let gate = Classification::gate_compute();
7335 assert!(gate.has_input_arity(Arity::Many));
7336 assert!(gate.has_output_arity(Arity::One));
7337 assert!(!gate.has_input_arity(Arity::One));
7338 assert!(!gate.has_output_arity(Arity::Many));
7339 }
7340
7341 // ── Classification::horizon_terminates substrate pins ─────────────
7342 //
7343 // Fail-before-pass-after granularity: [`Classification::horizon_terminates`]
7344 // did not exist before this commit — the `(Classification) -> bool`
7345 // derived-nullary-boolean walk over the nested [`Horizon`] slot's
7346 // [`HorizonKind::terminates`] projection had no substrate owner.
7347 // Post-lift the shape lives at ONE substrate primitive and every
7348 // downstream (the `terminating-horizon` fixed tag in
7349 // `tatara-check`, the [`crate::ephemeral::EphemeralSpec::horizon_terminates`]
7350 // peer, future scheduler / termination-shape validators) composes
7351 // against the SAME `horizon_terminates()` shape rather than
7352 // restating the `classification.horizon.kind.terminates()` chain
7353 // at its own callsite.
7354
7355 /// PER-VARIANT pin — for every [`HorizonKind`] variant, a
7356 /// [`Classification`] whose `horizon.kind` field carries that
7357 /// variant returns `horizon_terminates()` matching the closed
7358 /// set's own [`HorizonKind::terminates`] truth table. Sweep
7359 /// [`HorizonKind::ALL`] so a regression that (a) hard-coded the
7360 /// method body to a fixed answer (silently returning `true`
7361 /// regardless of the stored variant, silently rejecting every
7362 /// Asymptotic Process's scheduler-facing termination check), (b)
7363 /// inverted the projection (silently promoting Asymptotic to
7364 /// "terminates"), or (c) crossed the wires with the antisymmetric
7365 /// partner [`HorizonKind::requires_metric_axes`] fails HERE at
7366 /// the substrate primitive before drifting through the
7367 /// `terminating-horizon` fixed tag or the peer ephemeral surface.
7368 #[test]
7369 fn classification_horizon_terminates_matches_horizon_kind_projection() {
7370 for populated in HorizonKind::ALL {
7371 let c = Classification::gate_compute_with_axis(populated);
7372 assert_eq!(
7373 c.horizon_terminates(),
7374 populated.terminates(),
7375 "horizon.kind={populated:?}: horizon_terminates() drift from HorizonKind::terminates()",
7376 );
7377 }
7378 }
7379
7380 /// GATE-COMPUTE BASELINE — the workspace-baseline
7381 /// [`Classification::gate_compute`] shape carries
7382 /// `horizon: Horizon::default()` whose `kind` field defaults to
7383 /// [`HorizonKind::Bounded`] via `#[default]`, and
7384 /// [`HorizonKind::Bounded::terminates`] projects `true`, so
7385 /// `horizon_terminates()` returns `true`. Pins the default-arm
7386 /// short-circuit through TWO layers of `Default` (`Horizon`'s +
7387 /// `HorizonKind`'s) at ONE narrow site — a regression that
7388 /// promoted [`HorizonKind::Asymptotic`] to `#[default]`, or that
7389 /// swapped `Horizon::default`'s stored `kind`, or that wired
7390 /// [`HorizonKind::Bounded`] to `terminates() = false` would fail
7391 /// HERE before drifting through every unadorned Process's
7392 /// scheduler-facing termination answer.
7393 #[test]
7394 fn classification_gate_compute_horizon_terminates_is_true() {
7395 let c = Classification::gate_compute();
7396 assert!(
7397 c.horizon_terminates(),
7398 "gate_compute (horizon.kind=Bounded → terminates=true) baseline",
7399 );
7400 }
7401
7402 /// ANTISYMMETRY pin — [`HorizonKind::terminates`] XOR
7403 /// [`HorizonKind::requires_metric_axes`] holds on every variant
7404 /// (pinned by `horizon_kind_terminate_xor_requires_metric_axes`
7405 /// on the closed set itself); this composition-level test walks
7406 /// the same XOR contract through THIS derived-nullary predicate
7407 /// to prove the composition is faithful — a
7408 /// [`Classification`] answering `horizon_terminates() = true`
7409 /// implies its horizon does NOT require metric axes and vice
7410 /// versa. Pins the composition-level XOR at ONE narrow site so
7411 /// a regression that crossed the wires (`horizon_terminates`
7412 /// silently composed [`HorizonKind::requires_metric_axes`]
7413 /// instead of [`HorizonKind::terminates`]) surfaces here rather
7414 /// than at every downstream consumer that trusts the shape.
7415 #[test]
7416 fn classification_horizon_terminates_xor_horizon_kind_requires_metric_axes() {
7417 for kind in HorizonKind::ALL {
7418 let c = Classification::gate_compute_with_axis(kind);
7419 assert!(
7420 c.horizon_terminates() ^ kind.requires_metric_axes(),
7421 "{kind:?}: horizon_terminates() XOR requires_metric_axes() must hold",
7422 );
7423 }
7424 }
7425
7426 // ── Classification::horizon_requires_metric_axes substrate pins ──
7427 //
7428 // Fail-before-pass-after granularity: [`Classification::horizon_requires_metric_axes`]
7429 // did not exist before this commit — the `(Classification) -> bool`
7430 // derived-nullary-boolean walk over the nested [`Horizon`] slot's
7431 // [`HorizonKind::requires_metric_axes`] projection had no substrate
7432 // owner. Post-lift the shape lives at ONE substrate primitive and
7433 // every downstream (the `metric-axes-required` fixed tag in
7434 // `tatara-check`, the [`crate::ephemeral::EphemeralSpec::horizon_requires_metric_axes`]
7435 // peer, future scheduler / metric-provisioning validators)
7436 // composes against the SAME `horizon_requires_metric_axes()` shape
7437 // rather than restating the
7438 // `classification.horizon.kind.requires_metric_axes()` chain at
7439 // its own callsite.
7440
7441 /// PER-VARIANT pin — for every [`HorizonKind`] variant, a
7442 /// [`Classification`] whose `horizon.kind` field carries that
7443 /// variant returns `horizon_requires_metric_axes()` matching the
7444 /// closed set's own [`HorizonKind::requires_metric_axes`] truth
7445 /// table. Sweep [`HorizonKind::ALL`] so a regression that (a)
7446 /// hard-coded the method body to a fixed answer, (b) inverted the
7447 /// projection, or (c) crossed the wires with the antisymmetric
7448 /// partner [`HorizonKind::terminates`] fails HERE at the substrate
7449 /// primitive before drifting through the `metric-axes-required`
7450 /// fixed tag or the peer ephemeral surface.
7451 #[test]
7452 fn classification_horizon_requires_metric_axes_matches_horizon_kind_projection() {
7453 for populated in HorizonKind::ALL {
7454 let c = Classification::gate_compute_with_axis(populated);
7455 assert_eq!(
7456 c.horizon_requires_metric_axes(),
7457 populated.requires_metric_axes(),
7458 "horizon.kind={populated:?}: horizon_requires_metric_axes() drift from HorizonKind::requires_metric_axes()",
7459 );
7460 }
7461 }
7462
7463 /// GATE-COMPUTE BASELINE — the workspace-baseline
7464 /// [`Classification::gate_compute`] shape carries
7465 /// `horizon: Horizon::default()` whose `kind` field defaults to
7466 /// [`HorizonKind::Bounded`] via `#[default]`, and
7467 /// [`HorizonKind::Bounded::requires_metric_axes`] projects `false`,
7468 /// so `horizon_requires_metric_axes()` returns `false`. Pins the
7469 /// default-arm short-circuit through TWO layers of `Default`
7470 /// (`Horizon`'s + `HorizonKind`'s) at ONE narrow site — a
7471 /// regression that promoted [`HorizonKind::Asymptotic`] to
7472 /// `#[default]`, or that swapped `Horizon::default`'s stored
7473 /// `kind`, or that wired [`HorizonKind::Bounded`] to
7474 /// `requires_metric_axes() = true`, would fail HERE before
7475 /// drifting through every unadorned Process's metric-provisioning
7476 /// answer. Mirror image of
7477 /// `classification_gate_compute_horizon_terminates_is_true`.
7478 #[test]
7479 fn classification_gate_compute_horizon_requires_metric_axes_is_false() {
7480 let c = Classification::gate_compute();
7481 assert!(
7482 !c.horizon_requires_metric_axes(),
7483 "gate_compute (horizon.kind=Bounded → requires_metric_axes=false) baseline",
7484 );
7485 }
7486
7487 /// BINARY XOR PARTITION pin — for every [`HorizonKind`] variant,
7488 /// EXACTLY ONE of [`Classification::horizon_terminates`] and
7489 /// [`Classification::horizon_requires_metric_axes`] returns `true`
7490 /// on a [`Classification`] whose `horizon.kind` field carries that
7491 /// variant. CLOSES the horizon axis into the FULL binary XOR
7492 /// partition contract sealed on the closed set by
7493 /// `horizon_kind_terminate_xor_requires_metric_axes` AND now
7494 /// composed through the parent-composed layer as a substrate-wide
7495 /// theorem. Binary counterpart of the ternary XOR partitions
7496 /// sealed on the sibling `point_type` and `substrate` axes by
7497 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`
7498 /// and
7499 /// `classification_substrate_probes_form_three_way_xor_partition_over_all`
7500 /// — where those axes carve the closed set into THREE disjoint
7501 /// buckets, the horizon axis carves into TWO. Structural twin of
7502 /// the calm-axis and data-axis binary XOR partitions
7503 /// `classification_calm_probes_form_binary_xor_partition_over_all`
7504 /// and
7505 /// `classification_data_probes_form_binary_xor_partition_over_all`
7506 /// on the sibling axes — this pin is the FIFTH (and final)
7507 /// classification axis to reach the closed XOR partition landmark
7508 /// on the (parent × derived-nullary-bool) corner, promoting the
7509 /// axis-closure milestone from a proven-repeatable quadruple
7510 /// (`point_type` + `substrate` ternary; `calm` + `data` binary)
7511 /// to a proven-repeatable QUINTUPLE that spans every axis of
7512 /// [`Classification`]. Rewritten from the earlier binary-XOR-only
7513 /// form (walked as `a ^ b`) into the canonical bucket-array
7514 /// `hits == 1` shape shared with the calm/data partitions so
7515 /// downstream N-ary consumers (audit dispatchers, coverage
7516 /// checkers) walk every axis through the SAME contract. A
7517 /// regression that crossed the wires between the two parent-
7518 /// composed probes (one probe silently composing the wrong
7519 /// closed-set arm) fails HERE rather than at every downstream
7520 /// consumer that trusts the two probes partition the horizon
7521 /// slot into disjoint buckets whose union covers every variant.
7522 #[test]
7523 fn classification_horizon_probes_form_binary_xor_partition_over_all() {
7524 for populated in HorizonKind::ALL {
7525 let c = Classification::gate_compute_with_axis(populated);
7526 let buckets = [c.horizon_terminates(), c.horizon_requires_metric_axes()];
7527 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
7528 assert_eq!(
7529 hits, 1,
7530 "horizon.kind={populated:?}: probes {buckets:?} — exactly one must be true (binary XOR partition violated)",
7531 );
7532 }
7533 }
7534
7535 // ── Classification::calm_requires_coordination substrate pins ────
7536 //
7537 // Fail-before-pass-after granularity: [`Classification::calm_requires_coordination`]
7538 // did not exist before this commit — the `(Classification) -> bool`
7539 // derived-nullary-boolean walk over the scalar [`CalmClassification`]
7540 // slot's [`CalmClassification::requires_coordination`] projection
7541 // had no substrate owner. Post-lift the shape lives at ONE
7542 // substrate primitive and every downstream (the
7543 // `coordination-required` fixed tag in `tatara-check`, the
7544 // [`crate::ephemeral::EphemeralSpec::calm_requires_coordination`]
7545 // peer, future scheduler / coordination-mode validators) composes
7546 // against the SAME `calm_requires_coordination()` shape rather than
7547 // restating the `classification.calm.requires_coordination()` chain
7548 // at its own callsite. THIRD occupant of the (parent × derived-
7549 // nullary-bool) corner across TWO closed-set axes (`HorizonKind`,
7550 // `CalmClassification`), pinning the corner as a proven-repeatable
7551 // primitive shape rather than a single-axis curiosity.
7552
7553 /// PER-VARIANT pin — for every [`CalmClassification`] variant, a
7554 /// [`Classification`] whose `calm` field carries that variant
7555 /// returns `calm_requires_coordination()` matching the closed
7556 /// set's own [`CalmClassification::requires_coordination`] truth
7557 /// table. Sweep [`CalmClassification::ALL`] so a regression that
7558 /// (a) hard-coded the method body to a fixed answer (silently
7559 /// returning `true` regardless of the stored variant, silently
7560 /// forcing every Monotone Process onto the Raft coordination path
7561 /// and eliminating the CALM theorem's practical dividend), (b)
7562 /// inverted the projection (silently promoting Monotone to
7563 /// "requires coordination"), or (c) crossed the wires with a
7564 /// sibling classification-axis probe fails HERE at the substrate
7565 /// primitive before drifting through the `coordination-required`
7566 /// fixed tag or the peer ephemeral surface.
7567 #[test]
7568 fn classification_calm_requires_coordination_matches_calm_classification_projection() {
7569 for populated in CalmClassification::ALL {
7570 let c = Classification::gate_compute_with_axis(populated);
7571 assert_eq!(
7572 c.calm_requires_coordination(),
7573 populated.requires_coordination(),
7574 "calm={populated:?}: calm_requires_coordination() drift from CalmClassification::requires_coordination()",
7575 );
7576 }
7577 }
7578
7579 /// GATE-COMPUTE BASELINE — the workspace-baseline
7580 /// [`Classification::gate_compute`] shape carries
7581 /// `calm: CalmClassification::default()` which defaults to
7582 /// [`CalmClassification::Monotone`] via `#[default]`, and
7583 /// [`CalmClassification::Monotone::requires_coordination`] projects
7584 /// `false`, so `calm_requires_coordination()` returns `false`. Pins
7585 /// the default-arm short-circuit through ONE layer of `Default`
7586 /// (`CalmClassification`'s) at ONE narrow site — a regression that
7587 /// promoted [`CalmClassification::NonMonotone`] to `#[default]`, or
7588 /// that wired [`CalmClassification::Monotone`] to
7589 /// `requires_coordination() = true`, would fail HERE before
7590 /// drifting through every unadorned Process's scheduler-facing
7591 /// coordination-mode answer. Distinct from the two sibling
7592 /// `horizon_*` gate-compute-baseline pins by ONE structural
7593 /// degree: those short-circuit through TWO layers of `Default`
7594 /// (`Horizon`'s + `HorizonKind`'s); this pin walks ONE layer of
7595 /// `Default` because [`Classification::calm`] is a scalar rather
7596 /// than a nested-struct wrapper.
7597 #[test]
7598 fn classification_gate_compute_calm_requires_coordination_is_false() {
7599 let c = Classification::gate_compute();
7600 assert!(
7601 !c.calm_requires_coordination(),
7602 "gate_compute (calm=Monotone → requires_coordination=false) baseline",
7603 );
7604 }
7605
7606 // ── Classification::data_is_regulated substrate pins ─────────────
7607 //
7608 // Fail-before-pass-after granularity: [`Classification::data_is_regulated`]
7609 // did not exist before this commit — the `(Classification) -> bool`
7610 // derived-nullary-boolean walk over the scalar [`DataClassification`]
7611 // slot's [`DataClassification::is_regulated`] projection had no
7612 // substrate owner. Post-lift the shape lives at ONE substrate
7613 // primitive and every downstream (the `data-regulated` fixed tag
7614 // in `tatara-check`, the
7615 // [`crate::ephemeral::EphemeralSpec::data_is_regulated`] peer,
7616 // future compliance-baseline / regulatory-regime validators)
7617 // composes against the SAME `data_is_regulated()` shape rather
7618 // than restating the
7619 // `classification.data_classification.is_regulated()` chain at
7620 // its own callsite. FOURTH occupant of the (parent × derived-
7621 // nullary-bool) corner across THREE closed-set axes
7622 // (`HorizonKind`, `CalmClassification`, `DataClassification`),
7623 // pinning the corner as a proven-repeatable primitive shape
7624 // across the substrate's three defaulted-child classification-
7625 // axis closed sets rather than a two-axis curiosity. SECOND
7626 // direct-scalar peer on the corner after
7627 // [`Self::calm_requires_coordination`] opened the direct-scalar
7628 // sub-corner variant.
7629
7630 /// PER-VARIANT pin — for every [`DataClassification`] variant, a
7631 /// [`Classification`] whose `data_classification` field carries
7632 /// that variant returns `data_is_regulated()` matching the closed
7633 /// set's own [`DataClassification::is_regulated`] truth table.
7634 /// Sweep [`DataClassification::ALL`] so a regression that (a)
7635 /// hard-coded the method body to a fixed answer (silently
7636 /// stamping every Process as regulated, silently forcing
7637 /// compliance-baseline overlays that only apply to PII/PHI/PCI
7638 /// onto every unadorned Process), (b) inverted the projection
7639 /// (silently downgrading regulated Pii/Phi/Pci to unregulated),
7640 /// or (c) crossed the wires with the sibling
7641 /// [`DataClassification::is_restricted`] projection (which
7642 /// disagrees on the two `Internal | Confidential` variants) fails
7643 /// HERE at the substrate primitive before drifting through the
7644 /// `data-regulated` fixed tag or the peer ephemeral surface.
7645 #[test]
7646 fn classification_data_is_regulated_matches_data_classification_projection() {
7647 for populated in DataClassification::ALL {
7648 let c = Classification::gate_compute_with_axis(populated);
7649 assert_eq!(
7650 c.data_is_regulated(),
7651 populated.is_regulated(),
7652 "data_classification={populated:?}: data_is_regulated() drift from DataClassification::is_regulated()",
7653 );
7654 }
7655 }
7656
7657 /// GATE-COMPUTE BASELINE — the workspace-baseline
7658 /// [`Classification::gate_compute`] shape carries
7659 /// `data_classification: DataClassification::default()` which
7660 /// defaults to [`DataClassification::Internal`] via `#[default]`,
7661 /// and [`DataClassification::Internal::is_regulated`] projects
7662 /// `false`, so `data_is_regulated()` returns `false`. Pins the
7663 /// default-arm short-circuit through ONE layer of `Default`
7664 /// (`DataClassification`'s) at ONE narrow site — a regression
7665 /// that promoted [`DataClassification::Pii`] (or any other
7666 /// regulated variant) to `#[default]`, or that wired
7667 /// [`DataClassification::Internal`] to `is_regulated() = true`,
7668 /// would fail HERE before drifting through every unadorned
7669 /// Process's compliance-baseline answer. Byte-for-byte
7670 /// structural peer of the sibling
7671 /// `classification_gate_compute_calm_requires_coordination_is_false`
7672 /// on the classification-data axis — same ONE-layer-of-Default
7673 /// short-circuit shape distinct from the two horizon-axis
7674 /// baselines which walk TWO layers of `Default`.
7675 #[test]
7676 fn classification_gate_compute_data_is_regulated_is_false() {
7677 let c = Classification::gate_compute();
7678 assert!(
7679 !c.data_is_regulated(),
7680 "gate_compute (data_classification=Internal → is_regulated=false) baseline",
7681 );
7682 }
7683
7684 // ── Classification::data_is_restricted substrate pins ────────────
7685 //
7686 // Fail-before-pass-after granularity: [`Classification::data_is_restricted`]
7687 // did not exist before this commit — the `(Classification) -> bool`
7688 // derived-nullary-boolean walk over the scalar [`DataClassification`]
7689 // slot's [`DataClassification::is_restricted`] projection had no
7690 // substrate owner. Post-lift the shape lives at ONE substrate
7691 // primitive and every downstream (the `data-restricted` fixed tag
7692 // in `tatara-check`, the
7693 // [`crate::ephemeral::EphemeralSpec::data_is_restricted`] peer,
7694 // future compliance-baseline / access-control-mandatory validators)
7695 // composes against the SAME `data_is_restricted()` shape rather
7696 // than restating the
7697 // `classification.data_classification.is_restricted()` chain at
7698 // its own callsite. FIFTH occupant of the (parent × derived-
7699 // nullary-bool) corner across THREE closed-set axes and the SECOND
7700 // occupant on the classification-data axis, pinning the axis as
7701 // a proven-repeatable structural sub-corner across TWO sibling
7702 // closed-set projections (`is_regulated` / `is_restricted`).
7703 // THIRD direct-scalar peer on the corner and the FIRST corner peer
7704 // whose gate-compute baseline projects to `true` rather than
7705 // `false` (mirror-image of the `Bounded`-default
7706 // `horizon_terminates` baseline on the nested-struct sub-corner).
7707
7708 /// PER-VARIANT pin — for every [`DataClassification`] variant, a
7709 /// [`Classification`] whose `data_classification` field carries
7710 /// that variant returns `data_is_restricted()` matching the closed
7711 /// set's own [`DataClassification::is_restricted`] truth table.
7712 /// Sweep [`DataClassification::ALL`] so a regression that (a)
7713 /// hard-coded the method body to a fixed answer, (b) inverted the
7714 /// projection (silently promoting `Public` to restricted), or
7715 /// (c) crossed the wires with the sibling
7716 /// [`DataClassification::is_regulated`] projection (which
7717 /// disagrees on the two `Internal | Confidential` variants) fails
7718 /// HERE at the substrate primitive before drifting through the
7719 /// `data-restricted` fixed tag or the peer ephemeral surface.
7720 #[test]
7721 fn classification_data_is_restricted_matches_data_classification_projection() {
7722 for populated in DataClassification::ALL {
7723 let c = Classification::gate_compute_with_axis(populated);
7724 assert_eq!(
7725 c.data_is_restricted(),
7726 populated.is_restricted(),
7727 "data_classification={populated:?}: data_is_restricted() drift from DataClassification::is_restricted()",
7728 );
7729 }
7730 }
7731
7732 /// GATE-COMPUTE BASELINE — the workspace-baseline
7733 /// [`Classification::gate_compute`] shape carries
7734 /// `data_classification: DataClassification::default()` which
7735 /// defaults to [`DataClassification::Internal`] via `#[default]`,
7736 /// and [`DataClassification::Internal::is_restricted`] projects
7737 /// `true`, so `data_is_restricted()` returns `true`. Pins the
7738 /// default-arm short-circuit through ONE layer of `Default` at
7739 /// ONE narrow site — a regression that promoted
7740 /// [`DataClassification::Public`] to `#[default]`, or that wired
7741 /// [`DataClassification::Internal`] to `is_restricted() = false`,
7742 /// would fail HERE before drifting through every unadorned
7743 /// Process's access-control-mandatory answer. FIRST direct-scalar
7744 /// corner peer whose gate-compute baseline projects to `true`
7745 /// (`data_is_regulated` / `calm_requires_coordination` both
7746 /// project `false` on the same defaulted parent), mirror-image of
7747 /// the nested-struct sub-corner where
7748 /// `classification_gate_compute_horizon_terminates_is_true`
7749 /// pins the `Bounded`-default `true` baseline.
7750 #[test]
7751 fn classification_gate_compute_data_is_restricted_is_true() {
7752 let c = Classification::gate_compute();
7753 assert!(
7754 c.data_is_restricted(),
7755 "gate_compute (data_classification=Internal → is_restricted=true) baseline",
7756 );
7757 }
7758
7759 /// COMPOSED IMPLICATION pin — the substrate-primitive-level
7760 /// counterpart of
7761 /// `data_classification_regulated_implies_restricted` at the
7762 /// [`Classification`] parent site: for every
7763 /// [`DataClassification`] variant, a [`Classification`] carrying
7764 /// that variant answers `data_is_regulated() ⇒
7765 /// data_is_restricted()` — regulated data is by construction
7766 /// restricted at the parent-composed derived-nullary-boolean
7767 /// projection, not just at the closed-set primitives. Pins the
7768 /// implication contract at the SAME substrate site that composes
7769 /// each side of the pair, so a regression that (a) reversed the
7770 /// [`Classification::data_is_regulated`] arm, (b) reversed the
7771 /// [`Classification::data_is_restricted`] arm, or (c) crossed
7772 /// their wires while the closed-set primitives stayed intact
7773 /// fails HERE. FIRST corner-peer pair on the workspace-wide
7774 /// (parent × derived-nullary-bool) corner whose two projections
7775 /// carry a non-trivial closed-set-internal implication
7776 /// relationship — a future compliance-baseline auto-selector
7777 /// binds through the parent-composed contract rather than
7778 /// restating the closed-set-primitive contract at the callsite.
7779 #[test]
7780 fn classification_data_is_regulated_implies_data_is_restricted_over_all() {
7781 for populated in DataClassification::ALL {
7782 let c = Classification::gate_compute_with_axis(populated);
7783 assert!(
7784 !c.data_is_regulated() || c.data_is_restricted(),
7785 "data_classification={populated:?}: data_is_regulated ⇒ data_is_restricted violated",
7786 );
7787 }
7788 }
7789
7790 // ── Classification::point_is_endomorphic substrate pins ──────────
7791 //
7792 // Fail-before-pass-after granularity: [`Classification::point_is_endomorphic`]
7793 // did not exist before this commit — the `(Classification) -> bool`
7794 // derived-nullary-boolean walk over the scalar [`ConvergencePointType`]
7795 // slot's [`ConvergencePointType::is_endomorphic`] projection had no
7796 // substrate owner. Post-lift the shape lives at ONE substrate
7797 // primitive and every downstream (the `endomorphic-point` fixed
7798 // tag in `tatara-check`, the
7799 // [`crate::ephemeral::EphemeralSpec::point_is_endomorphic`] peer,
7800 // future DAG composition / edge-cardinality validators) composes
7801 // against the SAME `point_is_endomorphic()` shape rather than
7802 // restating the `classification.point_type.is_endomorphic()` chain
7803 // at its own callsite. SIXTH occupant of the (parent × derived-
7804 // nullary-bool) corner across FOUR closed-set axes, and the FIRST
7805 // occupant threading the `point_type` axis, pinning the axis as a
7806 // proven-repeatable structural sub-corner rather than a horizon /
7807 // calm / data curiosity. FIRST direct-scalar corner peer whose
7808 // parent-composed baseline is NOT a substrate-`#[default]` short-
7809 // circuit — [`ConvergencePointType`] has no `impl Default`, so the
7810 // [`Classification::gate_compute`] baseline's `false` answer comes
7811 // from the chosen `point_type: Gate` field rather than a
7812 // defaulted-chain projection.
7813
7814 /// PER-VARIANT pin — for every [`ConvergencePointType`] variant, a
7815 /// [`Classification`] whose `point_type` field carries that variant
7816 /// returns `point_is_endomorphic()` matching the closed set's own
7817 /// [`ConvergencePointType::is_endomorphic`] truth table. Sweep
7818 /// [`ConvergencePointType::ALL`] so a regression that (a)
7819 /// hard-coded the method body to a fixed answer, (b) inverted the
7820 /// projection, or (c) crossed the wires with a sibling closed-set
7821 /// projection ([`ConvergencePointType::is_diffusive`] /
7822 /// [`ConvergencePointType::is_convergent`]) fails HERE at the
7823 /// substrate primitive before drifting through the
7824 /// `endomorphic-point` fixed tag or the peer ephemeral surface.
7825 #[test]
7826 fn classification_point_is_endomorphic_matches_point_type_projection() {
7827 for populated in ConvergencePointType::ALL {
7828 let c = Classification::gate_compute_with_axis(populated);
7829 assert_eq!(
7830 c.point_is_endomorphic(),
7831 populated.is_endomorphic(),
7832 "point_type={populated:?}: point_is_endomorphic() drift from ConvergencePointType::is_endomorphic()",
7833 );
7834 }
7835 }
7836
7837 /// GATE-COMPUTE BASELINE — the workspace-baseline
7838 /// [`Classification::gate_compute`] shape carries
7839 /// `point_type: ConvergencePointType::Gate` deliberately (NOT via
7840 /// `#[default]` — [`ConvergencePointType`] has no `impl Default`),
7841 /// and [`ConvergencePointType::Gate::is_endomorphic`] projects
7842 /// `false` (Gate is N→1 convergent, not 1→1 endomorphic), so
7843 /// `point_is_endomorphic()` returns `false`. Pins the baseline's
7844 /// chosen-field answer at ONE narrow site — a regression that
7845 /// promoted [`ConvergencePointType::Transform`] to the gate-compute
7846 /// baseline (silently retargeting every unadorned Process's
7847 /// topology bucket), or that wired [`ConvergencePointType::Gate`]
7848 /// to `is_endomorphic() = true`, would fail HERE before drifting
7849 /// through every unadorned Process's DAG-composition answer.
7850 /// FIRST direct-scalar corner peer whose parent-composed baseline
7851 /// is a chosen-field answer (not a substrate-`#[default]` short-
7852 /// circuit): distinct from the two `horizon_*` baselines (which
7853 /// short-circuit through TWO layers of `Default`), the sibling
7854 /// `calm_requires_coordination` baseline (ONE layer of `Default`),
7855 /// and the two `data_is_*` baselines (ONE layer of `Default`).
7856 #[test]
7857 fn classification_gate_compute_point_is_endomorphic_is_false() {
7858 let c = Classification::gate_compute();
7859 assert!(
7860 !c.point_is_endomorphic(),
7861 "gate_compute (point_type=Gate → is_endomorphic=false) baseline",
7862 );
7863 }
7864
7865 // ── Classification::point_is_diffusive substrate pins ───────────
7866 //
7867 // Fail-before-pass-after granularity: [`Classification::point_is_diffusive`]
7868 // did not exist before this commit — the `(Classification) -> bool`
7869 // derived-nullary-boolean walk over the scalar [`ConvergencePointType`]
7870 // slot's [`ConvergencePointType::is_diffusive`] projection had no
7871 // substrate owner. Post-lift the shape lives at ONE substrate
7872 // primitive and every downstream (the `diffusive-point` fixed tag
7873 // in `tatara-check`, the
7874 // [`crate::ephemeral::EphemeralSpec::point_is_diffusive`] peer,
7875 // future DAG composition / edge-cardinality validators) composes
7876 // against the SAME `point_is_diffusive()` shape. SEVENTH occupant
7877 // of the (parent × derived-nullary-bool) corner and SECOND
7878 // occupant threading the `point_type` axis, promoting that axis
7879 // from a proven-repeatable one-off (endomorphic alone) to a
7880 // proven-repeatable pair. FIRST corner-peer pair on the
7881 // `point_type` axis whose two projections carry a non-trivial
7882 // closed-set-internal MUTEX relationship (`point_is_endomorphic ⇒
7883 // ¬point_is_diffusive`), distinct from the sibling `data` axis
7884 // corner-peer pair whose two projections carry a non-trivial
7885 // implication (`data_is_regulated ⇒ data_is_restricted`).
7886
7887 /// PER-VARIANT pin — for every [`ConvergencePointType`] variant, a
7888 /// [`Classification`] whose `point_type` field carries that variant
7889 /// returns `point_is_diffusive()` matching the closed set's own
7890 /// [`ConvergencePointType::is_diffusive`] truth table. Sweep
7891 /// [`ConvergencePointType::ALL`] so a regression that (a)
7892 /// hard-coded the method body to a fixed answer, (b) inverted the
7893 /// projection, or (c) crossed the wires with a sibling closed-set
7894 /// projection ([`ConvergencePointType::is_endomorphic`] /
7895 /// [`ConvergencePointType::is_convergent`]) fails HERE at the
7896 /// substrate primitive before drifting through the
7897 /// `diffusive-point` fixed tag or the peer ephemeral surface.
7898 #[test]
7899 fn classification_point_is_diffusive_matches_point_type_projection() {
7900 for populated in ConvergencePointType::ALL {
7901 let c = Classification::gate_compute_with_axis(populated);
7902 assert_eq!(
7903 c.point_is_diffusive(),
7904 populated.is_diffusive(),
7905 "point_type={populated:?}: point_is_diffusive() drift from ConvergencePointType::is_diffusive()",
7906 );
7907 }
7908 }
7909
7910 /// GATE-COMPUTE BASELINE — the workspace-baseline
7911 /// [`Classification::gate_compute`] shape carries
7912 /// `point_type: ConvergencePointType::Gate` deliberately (NOT via
7913 /// `#[default]` — [`ConvergencePointType`] has no `impl Default`),
7914 /// and [`ConvergencePointType::Gate::is_diffusive`] projects
7915 /// `false` (Gate is N→1 convergent, not 1→N diffusive), so
7916 /// `point_is_diffusive()` returns `false`. Pins the baseline's
7917 /// chosen-field answer at ONE narrow site — a regression that
7918 /// promoted [`ConvergencePointType::Fork`] to the gate-compute
7919 /// baseline, or that wired [`ConvergencePointType::Gate`] to
7920 /// `is_diffusive() = true`, would fail HERE before drifting
7921 /// through every unadorned Process's DAG-composition answer.
7922 /// SECOND direct-scalar corner peer whose parent-composed baseline
7923 /// is a chosen-field answer (peer of
7924 /// `classification_gate_compute_point_is_endomorphic_is_false`).
7925 #[test]
7926 fn classification_gate_compute_point_is_diffusive_is_false() {
7927 let c = Classification::gate_compute();
7928 assert!(
7929 !c.point_is_diffusive(),
7930 "gate_compute (point_type=Gate → is_diffusive=false) baseline",
7931 );
7932 }
7933
7934 /// MUTEX pin — [`Classification::point_is_endomorphic`] AND
7935 /// [`Classification::point_is_diffusive`] are NEVER simultaneously
7936 /// true for ANY [`ConvergencePointType`] variant, since the closed
7937 /// set's own `is_endomorphic` / `is_diffusive` / `is_convergent`
7938 /// triple carves it into THREE disjoint buckets (sealed on the
7939 /// closed set by
7940 /// `convergence_point_type_buckets_cover_every_variant`). Sweep
7941 /// [`ConvergencePointType::ALL`] so a regression that crossed the
7942 /// wires between the two corner peers at the parent-composed layer
7943 /// (one probe silently composing the wrong closed-set arm) fails
7944 /// HERE rather than at every downstream consumer that trusts the
7945 /// two probes partition the point-type slot into disjoint buckets.
7946 /// FIRST corner-peer pair on the workspace-wide (parent × derived-
7947 /// nullary-bool) corner whose two projections carry a non-trivial
7948 /// closed-set-internal MUTEX relationship (distinct from the
7949 /// sibling `data`-axis IMPLICATION pair sealed by
7950 /// `classification_data_is_regulated_implies_data_is_restricted_over_all`
7951 /// — that pair contains one bucket in another; this pair
7952 /// disjointly partitions two buckets of a three-way carving).
7953 /// When [`Classification::point_is_convergent`] lands the mutex
7954 /// closes into the full three-way XOR partition contract
7955 /// `point_is_endomorphic ⊕ point_is_diffusive ⊕
7956 /// point_is_convergent` composed through this corner as a
7957 /// substrate-wide theorem.
7958 #[test]
7959 fn classification_point_is_endomorphic_and_point_is_diffusive_are_mutex_over_all() {
7960 for populated in ConvergencePointType::ALL {
7961 let c = Classification::gate_compute_with_axis(populated);
7962 assert!(
7963 !(c.point_is_endomorphic() && c.point_is_diffusive()),
7964 "point_type={populated:?}: point_is_endomorphic AND point_is_diffusive both true (mutex violated)",
7965 );
7966 }
7967 }
7968
7969 // ── Classification::point_is_convergent substrate pins ──────────
7970 //
7971 // Fail-before-pass-after granularity: [`Classification::point_is_convergent`]
7972 // did not exist before this commit — the `(Classification) -> bool`
7973 // derived-nullary-boolean walk over the scalar [`ConvergencePointType`]
7974 // slot's [`ConvergencePointType::is_convergent`] projection had no
7975 // substrate owner. Post-lift the shape lives at ONE substrate
7976 // primitive and every downstream (the `convergent-point` fixed
7977 // tag in `tatara-check`, the
7978 // [`crate::ephemeral::EphemeralSpec::point_is_convergent`] peer,
7979 // future DAG composition / edge-cardinality validators) composes
7980 // against the SAME `point_is_convergent()` shape. EIGHTH occupant
7981 // of the (parent × derived-nullary-bool) corner and THIRD
7982 // occupant threading the `point_type` axis, closing the axis into
7983 // a proven-repeatable three-peer sub-corner. CLOSES the mutex
7984 // pair [`Self::point_is_endomorphic`] / [`Self::point_is_diffusive`]
7985 // into the FULL three-way XOR partition contract on the axis.
7986
7987 /// PER-VARIANT pin — for every [`ConvergencePointType`] variant, a
7988 /// [`Classification`] whose `point_type` field carries that variant
7989 /// returns `point_is_convergent()` matching the closed set's own
7990 /// [`ConvergencePointType::is_convergent`] truth table. Sweep
7991 /// [`ConvergencePointType::ALL`] so a regression that (a)
7992 /// hard-coded the method body to a fixed answer, (b) inverted the
7993 /// projection, or (c) crossed the wires with a sibling closed-set
7994 /// projection ([`ConvergencePointType::is_endomorphic`] /
7995 /// [`ConvergencePointType::is_diffusive`]) fails HERE at the
7996 /// substrate primitive before drifting through the
7997 /// `convergent-point` fixed tag or the peer ephemeral surface.
7998 #[test]
7999 fn classification_point_is_convergent_matches_point_type_projection() {
8000 for populated in ConvergencePointType::ALL {
8001 let c = Classification::gate_compute_with_axis(populated);
8002 assert_eq!(
8003 c.point_is_convergent(),
8004 populated.is_convergent(),
8005 "point_type={populated:?}: point_is_convergent() drift from ConvergencePointType::is_convergent()",
8006 );
8007 }
8008 }
8009
8010 /// GATE-COMPUTE BASELINE — the workspace-baseline
8011 /// [`Classification::gate_compute`] shape carries
8012 /// `point_type: ConvergencePointType::Gate` deliberately (NOT via
8013 /// `#[default]` — [`ConvergencePointType`] has no `impl Default`),
8014 /// and [`ConvergencePointType::Gate::is_convergent`] projects
8015 /// `true` (Gate is the canonical N→1 convergent barrier), so
8016 /// `point_is_convergent()` returns `true`. Pins the baseline's
8017 /// chosen-field answer at ONE narrow site — a regression that
8018 /// promoted [`ConvergencePointType::Transform`] to the gate-compute
8019 /// baseline (silently retargeting every unadorned Process's
8020 /// topology bucket), or that wired [`ConvergencePointType::Gate`]
8021 /// to `is_convergent() = false`, would fail HERE before drifting
8022 /// through every unadorned Process's DAG-composition answer.
8023 /// FIRST direct-scalar corner peer whose parent-composed
8024 /// gate-compute baseline projects `true` — mirror-inverted from
8025 /// the two sibling `point_is_endomorphic` /
8026 /// `point_is_diffusive` baselines which both project `false`.
8027 #[test]
8028 fn classification_gate_compute_point_is_convergent_is_true() {
8029 let c = Classification::gate_compute();
8030 assert!(
8031 c.point_is_convergent(),
8032 "gate_compute (point_type=Gate → is_convergent=true) baseline",
8033 );
8034 }
8035
8036 /// THREE-WAY XOR PARTITION pin — for every
8037 /// [`ConvergencePointType`] variant, EXACTLY ONE of
8038 /// [`Classification::point_is_endomorphic`],
8039 /// [`Classification::point_is_diffusive`], and
8040 /// [`Classification::point_is_convergent`] returns `true` on a
8041 /// [`Classification`] carrying that variant. Closes the mutex pair
8042 /// `classification_point_is_endomorphic_and_point_is_diffusive_are_mutex_over_all`
8043 /// into the FULL ternary XOR partition contract sealed on the
8044 /// closed set by `convergence_point_type_buckets_cover_every_variant`
8045 /// AND now composed through the parent-composed layer as a
8046 /// substrate-wide theorem. Ternary lift of the closed-set XOR
8047 /// pair `terminates ^ requires_metric_axes` that already composes
8048 /// through this corner today — where the `horizon` axis carves
8049 /// its closed set into TWO non-empty buckets, the `point_type`
8050 /// axis carves into THREE non-empty buckets. A regression that
8051 /// crossed the wires between any two of the three parent-composed
8052 /// probes (one probe silently composing the wrong closed-set arm)
8053 /// fails HERE rather than at every downstream consumer that
8054 /// trusts the three probes partition the point-type slot into
8055 /// disjoint buckets whose union covers every variant.
8056 #[test]
8057 fn classification_point_type_probes_form_three_way_xor_partition_over_all() {
8058 for populated in ConvergencePointType::ALL {
8059 let c = Classification::gate_compute_with_axis(populated);
8060 let buckets = [
8061 c.point_is_endomorphic(),
8062 c.point_is_diffusive(),
8063 c.point_is_convergent(),
8064 ];
8065 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
8066 assert_eq!(
8067 hits, 1,
8068 "point_type={populated:?}: probes {buckets:?} — exactly one must be true (three-way XOR partition violated)",
8069 );
8070 }
8071 }
8072
8073 // ── Classification::substrate_is_resource substrate pins ────────
8074 //
8075 // Fail-before-pass-after granularity: [`Classification::substrate_is_resource`]
8076 // did not exist before this commit — the `(Classification) -> bool`
8077 // derived-nullary-boolean walk over the scalar [`SubstrateType`]
8078 // slot's [`SubstrateType::is_resource`] projection had no
8079 // substrate owner. Post-lift the shape lives at ONE substrate
8080 // primitive and every downstream (the `resource-substrate` fixed
8081 // tag in `tatara-check`, the
8082 // [`crate::ephemeral::EphemeralSpec::substrate_is_resource`]
8083 // peer, future plane-baseline / compliance-baseline selectors)
8084 // composes against the SAME `substrate_is_resource()` shape.
8085 // NINTH occupant of the (parent × derived-nullary-bool) corner
8086 // and FIRST occupant threading the classification-`substrate`
8087 // axis — opens the fourth of six classification axes on the
8088 // corner after `horizon`, `calm`, `data_classification`, and
8089 // `point_type`.
8090
8091 /// PER-VARIANT pin — for every [`SubstrateType`] variant, a
8092 /// [`Classification`] whose `substrate` field carries that
8093 /// variant returns `substrate_is_resource()` matching the closed
8094 /// set's own [`SubstrateType::is_resource`] truth table. Sweep
8095 /// [`SubstrateType::ALL`] so a regression that (a) hard-coded
8096 /// the method body to a fixed answer, (b) inverted the
8097 /// projection, or (c) crossed the wires with a sibling closed-
8098 /// set projection ([`SubstrateType::is_policy`] /
8099 /// [`SubstrateType::is_telemetry`]) fails HERE at the substrate
8100 /// primitive before drifting through the `resource-substrate`
8101 /// fixed tag or the peer ephemeral surface.
8102 #[test]
8103 fn classification_substrate_is_resource_matches_substrate_projection() {
8104 for populated in SubstrateType::ALL {
8105 let c = Classification::gate_compute_with_axis(populated);
8106 assert_eq!(
8107 c.substrate_is_resource(),
8108 populated.is_resource(),
8109 "substrate={populated:?}: substrate_is_resource() drift from SubstrateType::is_resource()",
8110 );
8111 }
8112 }
8113
8114 /// GATE-COMPUTE BASELINE — the workspace-baseline
8115 /// [`Classification::gate_compute`] shape carries
8116 /// `substrate: SubstrateType::Compute` deliberately (NOT via
8117 /// `#[default]` — [`SubstrateType`] has no `impl Default`), and
8118 /// [`SubstrateType::Compute::is_resource`] projects `true`
8119 /// (Compute is a resource-plane substrate you allocate budgets
8120 /// from), so `substrate_is_resource()` returns `true`. Pins the
8121 /// baseline's chosen-field answer at ONE narrow site — a
8122 /// regression that promoted [`SubstrateType::Security`] (or any
8123 /// non-resource plane) to the gate-compute baseline (silently
8124 /// retargeting every unadorned Process's plane bucket), or that
8125 /// wired [`SubstrateType::Compute`] to `is_resource() = false`,
8126 /// would fail HERE before drifting through every unadorned
8127 /// Process's plane-baseline answer. Structural peer of
8128 /// `classification_gate_compute_point_is_convergent_is_true`:
8129 /// both walk direct-scalar chosen fields with `true` baseline
8130 /// answers (mirror-aligned with each other, mirror-inverted from
8131 /// the two other `point_type`-axis peers whose baselines answer
8132 /// `false`).
8133 #[test]
8134 fn classification_gate_compute_substrate_is_resource_is_true() {
8135 let c = Classification::gate_compute();
8136 assert!(
8137 c.substrate_is_resource(),
8138 "gate_compute (substrate=Compute → is_resource=true) baseline",
8139 );
8140 }
8141
8142 // ── Classification::substrate_is_policy substrate pins ──────────
8143 //
8144 // Fail-before-pass-after granularity: [`Classification::substrate_is_policy`]
8145 // did not exist before this commit — the `(Classification) -> bool`
8146 // derived-nullary-boolean walk over the scalar [`SubstrateType`]
8147 // slot's [`SubstrateType::is_policy`] projection had no
8148 // substrate owner. Post-lift the shape lives at ONE substrate
8149 // primitive and every downstream (the `policy-substrate` fixed
8150 // tag in `tatara-check`, the
8151 // [`crate::ephemeral::EphemeralSpec::substrate_is_policy`] peer,
8152 // future plane-baseline / compliance-baseline selectors)
8153 // composes against the SAME `substrate_is_policy()` shape.
8154 // TENTH occupant of the (parent × derived-nullary-bool) corner
8155 // and SECOND occupant threading the classification-`substrate`
8156 // axis, promoting that axis from a proven-repeatable one-off
8157 // (`substrate_is_resource` alone) to a proven-repeatable pair.
8158 // FIRST substrate-axis corner-peer pair carrying a non-trivial
8159 // closed-set-internal MUTEX relationship
8160 // (`substrate_is_resource ⇒ ¬substrate_is_policy`).
8161
8162 /// PER-VARIANT pin — for every [`SubstrateType`] variant, a
8163 /// [`Classification`] whose `substrate` field carries that
8164 /// variant returns `substrate_is_policy()` matching the closed
8165 /// set's own [`SubstrateType::is_policy`] truth table. Sweep
8166 /// [`SubstrateType::ALL`] so a regression that (a) hard-coded
8167 /// the method body to a fixed answer, (b) inverted the
8168 /// projection, or (c) crossed the wires with a sibling closed-
8169 /// set projection ([`SubstrateType::is_resource`] /
8170 /// [`SubstrateType::is_telemetry`]) fails HERE at the substrate
8171 /// primitive before drifting through the `policy-substrate`
8172 /// fixed tag or the peer ephemeral surface.
8173 #[test]
8174 fn classification_substrate_is_policy_matches_substrate_projection() {
8175 for populated in SubstrateType::ALL {
8176 let c = Classification::gate_compute_with_axis(populated);
8177 assert_eq!(
8178 c.substrate_is_policy(),
8179 populated.is_policy(),
8180 "substrate={populated:?}: substrate_is_policy() drift from SubstrateType::is_policy()",
8181 );
8182 }
8183 }
8184
8185 /// GATE-COMPUTE BASELINE — the workspace-baseline
8186 /// [`Classification::gate_compute`] shape carries
8187 /// `substrate: SubstrateType::Compute` deliberately (NOT via
8188 /// `#[default]` — [`SubstrateType`] has no `impl Default`), and
8189 /// [`SubstrateType::Compute::is_policy`] projects `false`
8190 /// (Compute is a resource-plane substrate, not a policy plane),
8191 /// so `substrate_is_policy()` returns `false`. Pins the
8192 /// baseline's chosen-field answer at ONE narrow site — a
8193 /// regression that promoted [`SubstrateType::Security`] (or any
8194 /// policy plane) to the gate-compute baseline, or that wired
8195 /// [`SubstrateType::Compute`] to `is_policy() = true`, would
8196 /// fail HERE before drifting through every unadorned Process's
8197 /// plane-baseline answer. Mirror-inverted from the sibling
8198 /// `classification_gate_compute_substrate_is_resource_is_true`
8199 /// baseline (both walk the SAME chosen `substrate: Compute`
8200 /// field, so `is_resource = true` ⇒ `is_policy = false` on the
8201 /// closed set's disjoint plane partition).
8202 #[test]
8203 fn classification_gate_compute_substrate_is_policy_is_false() {
8204 let c = Classification::gate_compute();
8205 assert!(
8206 !c.substrate_is_policy(),
8207 "gate_compute (substrate=Compute → is_policy=false) baseline",
8208 );
8209 }
8210
8211 /// MUTEX pin — [`Classification::substrate_is_resource`] AND
8212 /// [`Classification::substrate_is_policy`] are NEVER simultaneously
8213 /// true for ANY [`SubstrateType`] variant, since the closed set's
8214 /// own `is_resource` / `is_policy` / `is_telemetry` triple carves
8215 /// it into THREE disjoint buckets (sealed on the closed set by
8216 /// `substrate_type_buckets_cover_every_variant`). Sweep
8217 /// [`SubstrateType::ALL`] so a regression that crossed the wires
8218 /// between the two corner peers at the parent-composed layer (one
8219 /// probe silently composing the wrong closed-set arm) fails HERE
8220 /// rather than at every downstream consumer that trusts the two
8221 /// probes partition the substrate slot into disjoint buckets.
8222 /// FIRST substrate-axis corner-peer pair whose two projections
8223 /// carry a non-trivial closed-set-internal MUTEX relationship —
8224 /// structural twin of the sibling `point_type`-axis MUTEX pair
8225 /// sealed by
8226 /// `classification_point_is_endomorphic_and_point_is_diffusive_are_mutex_over_all`.
8227 /// When [`Classification::substrate_is_telemetry`] lands the
8228 /// mutex closes into the full three-way XOR partition contract
8229 /// `substrate_is_resource ⊕ substrate_is_policy ⊕ substrate_is_telemetry`
8230 /// composed through this corner as a substrate-wide theorem.
8231 #[test]
8232 fn classification_substrate_is_resource_and_substrate_is_policy_are_mutex_over_all() {
8233 for populated in SubstrateType::ALL {
8234 let c = Classification::gate_compute_with_axis(populated);
8235 assert!(
8236 !(c.substrate_is_resource() && c.substrate_is_policy()),
8237 "substrate={populated:?}: substrate_is_resource AND substrate_is_policy both true (mutex violated)",
8238 );
8239 }
8240 }
8241
8242 // ── Classification::substrate_is_telemetry substrate pins ───────
8243 //
8244 // Fail-before-pass-after granularity: [`Classification::substrate_is_telemetry`]
8245 // did not exist before this commit — the `(Classification) -> bool`
8246 // derived-nullary-boolean walk over the scalar [`SubstrateType`]
8247 // slot's [`SubstrateType::is_telemetry`] projection had no
8248 // substrate owner. Post-lift the shape lives at ONE substrate
8249 // primitive and every downstream (the `telemetry-substrate` fixed
8250 // tag in `tatara-check`, the
8251 // [`crate::ephemeral::EphemeralSpec::substrate_is_telemetry`]
8252 // peer, future plane-baseline / compliance-baseline selectors)
8253 // composes against the SAME `substrate_is_telemetry()` shape.
8254 // ELEVENTH occupant of the (parent × derived-nullary-bool) corner
8255 // and THIRD occupant threading the classification-`substrate`
8256 // axis — CLOSES the substrate axis on the corner into the FULL
8257 // three-way XOR partition contract
8258 // `substrate_is_resource ⊕ substrate_is_policy ⊕ substrate_is_telemetry`
8259 // sealed on the closed set by
8260 // `substrate_type_buckets_cover_every_variant` and composed
8261 // through the parent-composed layer by
8262 // `classification_substrate_probes_form_three_way_xor_partition_over_all`.
8263
8264 /// PER-VARIANT pin — for every [`SubstrateType`] variant, a
8265 /// [`Classification`] whose `substrate` field carries that
8266 /// variant returns `substrate_is_telemetry()` matching the closed
8267 /// set's own [`SubstrateType::is_telemetry`] truth table. Sweep
8268 /// [`SubstrateType::ALL`] so a regression that (a) hard-coded
8269 /// the method body to a fixed answer, (b) inverted the
8270 /// projection, or (c) crossed the wires with a sibling closed-
8271 /// set projection ([`SubstrateType::is_resource`] /
8272 /// [`SubstrateType::is_policy`]) fails HERE at the substrate
8273 /// primitive before drifting through the `telemetry-substrate`
8274 /// fixed tag or the peer ephemeral surface.
8275 #[test]
8276 fn classification_substrate_is_telemetry_matches_substrate_projection() {
8277 for populated in SubstrateType::ALL {
8278 let c = Classification::gate_compute_with_axis(populated);
8279 assert_eq!(
8280 c.substrate_is_telemetry(),
8281 populated.is_telemetry(),
8282 "substrate={populated:?}: substrate_is_telemetry() drift from SubstrateType::is_telemetry()",
8283 );
8284 }
8285 }
8286
8287 /// GATE-COMPUTE BASELINE — the workspace-baseline
8288 /// [`Classification::gate_compute`] shape carries
8289 /// `substrate: SubstrateType::Compute` deliberately (NOT via
8290 /// `#[default]` — [`SubstrateType`] has no `impl Default`), and
8291 /// [`SubstrateType::Compute::is_telemetry`] projects `false`
8292 /// (Compute is a resource-plane substrate, not a telemetry
8293 /// plane), so `substrate_is_telemetry()` returns `false`. Pins
8294 /// the baseline's chosen-field answer at ONE narrow site — a
8295 /// regression that promoted [`SubstrateType::Observability`] to
8296 /// the gate-compute baseline, or that wired
8297 /// [`SubstrateType::Compute`] to `is_telemetry() = true`, would
8298 /// fail HERE before drifting through every unadorned Process's
8299 /// plane-baseline answer. Mirror-inverted from the sibling
8300 /// `classification_gate_compute_substrate_is_resource_is_true`
8301 /// baseline (both walk the SAME chosen `substrate: Compute`
8302 /// field, so `is_resource = true` ⇒ `is_telemetry = false` on the
8303 /// closed set's disjoint plane partition), aligned with the
8304 /// sibling `substrate_is_policy` baseline's `false`.
8305 #[test]
8306 fn classification_gate_compute_substrate_is_telemetry_is_false() {
8307 let c = Classification::gate_compute();
8308 assert!(
8309 !c.substrate_is_telemetry(),
8310 "gate_compute (substrate=Compute → is_telemetry=false) baseline",
8311 );
8312 }
8313
8314 /// MUTEX pin — [`Classification::substrate_is_resource`] AND
8315 /// [`Classification::substrate_is_telemetry`] are NEVER
8316 /// simultaneously true for ANY [`SubstrateType`] variant, since
8317 /// the closed set's own `is_resource` / `is_policy` /
8318 /// `is_telemetry` triple carves it into THREE disjoint buckets
8319 /// (sealed on the closed set by
8320 /// `substrate_type_buckets_cover_every_variant`). Second
8321 /// substrate-axis corner-peer MUTEX pin — peer of
8322 /// `classification_substrate_is_resource_and_substrate_is_policy_are_mutex_over_all`
8323 /// on a sibling closed-set projection.
8324 #[test]
8325 fn classification_substrate_is_resource_and_substrate_is_telemetry_are_mutex_over_all() {
8326 for populated in SubstrateType::ALL {
8327 let c = Classification::gate_compute_with_axis(populated);
8328 assert!(
8329 !(c.substrate_is_resource() && c.substrate_is_telemetry()),
8330 "substrate={populated:?}: substrate_is_resource AND substrate_is_telemetry both true (mutex violated)",
8331 );
8332 }
8333 }
8334
8335 /// MUTEX pin — [`Classification::substrate_is_policy`] AND
8336 /// [`Classification::substrate_is_telemetry`] are NEVER
8337 /// simultaneously true for ANY [`SubstrateType`] variant. Third
8338 /// substrate-axis corner-peer MUTEX pin — completes the three
8339 /// pairwise MUTEX relations on the substrate axis alongside
8340 /// `classification_substrate_is_resource_and_substrate_is_policy_are_mutex_over_all`
8341 /// and
8342 /// `classification_substrate_is_resource_and_substrate_is_telemetry_are_mutex_over_all`.
8343 #[test]
8344 fn classification_substrate_is_policy_and_substrate_is_telemetry_are_mutex_over_all() {
8345 for populated in SubstrateType::ALL {
8346 let c = Classification::gate_compute_with_axis(populated);
8347 assert!(
8348 !(c.substrate_is_policy() && c.substrate_is_telemetry()),
8349 "substrate={populated:?}: substrate_is_policy AND substrate_is_telemetry both true (mutex violated)",
8350 );
8351 }
8352 }
8353
8354 /// THREE-WAY XOR PARTITION pin — for every [`SubstrateType`]
8355 /// variant, EXACTLY ONE of
8356 /// [`Classification::substrate_is_resource`],
8357 /// [`Classification::substrate_is_policy`], and
8358 /// [`Classification::substrate_is_telemetry`] returns `true` on
8359 /// a [`Classification`] carrying that variant. CLOSES the three
8360 /// pairwise MUTEX pins on the substrate axis
8361 /// (`substrate_is_resource ⇒ ¬substrate_is_policy`,
8362 /// `substrate_is_resource ⇒ ¬substrate_is_telemetry`,
8363 /// `substrate_is_policy ⇒ ¬substrate_is_telemetry`) into the FULL
8364 /// ternary XOR partition contract sealed on the closed set by
8365 /// `substrate_type_buckets_cover_every_variant` AND now composed
8366 /// through the parent-composed layer as a substrate-wide theorem.
8367 /// Structural twin of the sibling `point_type`-axis ternary lift
8368 /// sealed on this surface by
8369 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`.
8370 /// A regression that crossed the wires between any two of the
8371 /// three parent-composed probes (one probe silently composing the
8372 /// wrong closed-set arm) fails HERE rather than at every
8373 /// downstream consumer that trusts the three probes partition the
8374 /// substrate slot into disjoint buckets whose union covers every
8375 /// variant.
8376 #[test]
8377 fn classification_substrate_probes_form_three_way_xor_partition_over_all() {
8378 for populated in SubstrateType::ALL {
8379 let c = Classification::gate_compute_with_axis(populated);
8380 let buckets = [
8381 c.substrate_is_resource(),
8382 c.substrate_is_policy(),
8383 c.substrate_is_telemetry(),
8384 ];
8385 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
8386 assert_eq!(
8387 hits, 1,
8388 "substrate={populated:?}: probes {buckets:?} — exactly one must be true (three-way XOR partition violated)",
8389 );
8390 }
8391 }
8392
8393 // ── Classification::calm_is_monotone substrate pins ─────────────
8394 //
8395 // Fail-before-pass-after granularity: [`Classification::calm_is_monotone`]
8396 // did not exist before this commit — the `(Classification) -> bool`
8397 // derived-nullary-boolean walk over the scalar [`CalmClassification`]
8398 // slot's [`CalmClassification::is_monotone`] projection had no
8399 // substrate owner. Post-lift the shape lives at ONE substrate
8400 // primitive and every downstream (the `monotone-calm` fixed tag
8401 // in `tatara-check`, the
8402 // [`crate::ephemeral::EphemeralSpec::calm_is_monotone`] peer,
8403 // future scheduler / gossip-eligibility validators asking the
8404 // positive CALM framing) composes against the SAME
8405 // `calm_is_monotone()` shape rather than restating either
8406 // `!self.calm_requires_coordination()` or the
8407 // `self.calm.is_monotone()` chain at its own callsite. TWELFTH
8408 // occupant of the (parent × derived-nullary-bool) corner and
8409 // SECOND occupant threading the classification-`calm` axis —
8410 // CLOSES the calm axis on the corner into the FULL binary XOR
8411 // partition contract `calm_is_monotone ⊕ calm_requires_coordination`
8412 // sealed on the closed set by
8413 // `calm_classification_monotone_xor_requires_coordination` and
8414 // composed through the parent-composed layer by
8415 // `classification_calm_probes_form_binary_xor_partition_over_all`.
8416
8417 /// PER-VARIANT pin — for every [`CalmClassification`] variant, a
8418 /// [`Classification`] whose `calm` field carries that variant
8419 /// returns `calm_is_monotone()` matching the closed set's own
8420 /// [`CalmClassification::is_monotone`] truth table. Sweep
8421 /// [`CalmClassification::ALL`] so a regression that (a) hard-
8422 /// coded the method body to a fixed answer (silently returning
8423 /// `true` regardless of the stored variant, silently marking
8424 /// every Process as gossip-eligible and shipping non-monotone
8425 /// operations onto the no-coordination path), (b) inverted the
8426 /// projection (silently promoting NonMonotone to "monotone"),
8427 /// or (c) crossed the wires with a sibling classification-axis
8428 /// probe fails HERE at the substrate primitive before drifting
8429 /// through the `monotone-calm` fixed tag or the peer ephemeral
8430 /// surface.
8431 #[test]
8432 fn classification_calm_is_monotone_matches_calm_classification_projection() {
8433 for populated in CalmClassification::ALL {
8434 let c = Classification::gate_compute_with_axis(populated);
8435 assert_eq!(
8436 c.calm_is_monotone(),
8437 populated.is_monotone(),
8438 "calm={populated:?}: calm_is_monotone() drift from CalmClassification::is_monotone()",
8439 );
8440 }
8441 }
8442
8443 /// GATE-COMPUTE BASELINE — the workspace-baseline
8444 /// [`Classification::gate_compute`] shape carries
8445 /// `calm: CalmClassification::default()` which defaults to
8446 /// [`CalmClassification::Monotone`] via `#[default]`, and
8447 /// [`CalmClassification::Monotone::is_monotone`] projects `true`,
8448 /// so `calm_is_monotone()` returns `true`. Pins the default-arm
8449 /// short-circuit through ONE layer of `Default`
8450 /// (`CalmClassification`'s) at ONE narrow site — a regression
8451 /// that promoted [`CalmClassification::NonMonotone`] to
8452 /// `#[default]`, or that wired [`CalmClassification::Monotone`]
8453 /// to `is_monotone() = false`, would fail HERE before drifting
8454 /// through every unadorned Process's positive-CALM-framing
8455 /// answer. Mirror-inverted from the sibling
8456 /// `classification_gate_compute_calm_requires_coordination_is_false`
8457 /// baseline (both walk the SAME defaulted `calm` field, so
8458 /// `requires_coordination = false` ⇒ `is_monotone = true` on the
8459 /// closed set's disjoint XOR partition).
8460 #[test]
8461 fn classification_gate_compute_calm_is_monotone_is_true() {
8462 let c = Classification::gate_compute();
8463 assert!(
8464 c.calm_is_monotone(),
8465 "gate_compute (calm=Monotone → is_monotone=true) baseline",
8466 );
8467 }
8468
8469 /// MUTEX pin — [`Classification::calm_requires_coordination`] AND
8470 /// [`Classification::calm_is_monotone`] are NEVER simultaneously
8471 /// true for ANY [`CalmClassification`] variant, since the closed
8472 /// set's own `is_monotone` / `requires_coordination` pair carves
8473 /// it into TWO disjoint buckets sealed on the closed set by
8474 /// `calm_classification_monotone_xor_requires_coordination`.
8475 /// FIRST calm-axis corner-peer MUTEX pin — the calm axis's
8476 /// counterpart to the sibling substrate-axis
8477 /// `classification_substrate_is_resource_and_substrate_is_policy_are_mutex_over_all`
8478 /// on a binary (rather than ternary) closed set.
8479 #[test]
8480 fn classification_calm_requires_coordination_and_calm_is_monotone_are_mutex_over_all() {
8481 for populated in CalmClassification::ALL {
8482 let c = Classification::gate_compute_with_axis(populated);
8483 assert!(
8484 !(c.calm_requires_coordination() && c.calm_is_monotone()),
8485 "calm={populated:?}: calm_requires_coordination AND calm_is_monotone both true (mutex violated)",
8486 );
8487 }
8488 }
8489
8490 /// BINARY XOR PARTITION pin — for every [`CalmClassification`]
8491 /// variant, EXACTLY ONE of
8492 /// [`Classification::calm_is_monotone`] and
8493 /// [`Classification::calm_requires_coordination`] returns `true`
8494 /// on a [`Classification`] carrying that variant. CLOSES the
8495 /// calm-axis MUTEX pin
8496 /// (`calm_requires_coordination ⇒ ¬calm_is_monotone`) into the
8497 /// FULL binary XOR partition contract sealed on the closed set
8498 /// by `calm_classification_monotone_xor_requires_coordination`
8499 /// AND now composed through the parent-composed layer as a
8500 /// substrate-wide theorem. Binary counterpart of the ternary XOR
8501 /// partitions sealed on the sibling `point_type` and `substrate`
8502 /// axes by
8503 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`
8504 /// and
8505 /// `classification_substrate_probes_form_three_way_xor_partition_over_all`
8506 /// — where those axes carve the closed set into THREE disjoint
8507 /// buckets, the calm axis carves into TWO. Structural twin of
8508 /// the closed-set-layer binary XOR
8509 /// `horizon_kind_terminate_xor_requires_metric_axes` on the
8510 /// sibling horizon axis, lifted through the parent-composed
8511 /// layer to make the calm axis the THIRD classification axis to
8512 /// reach a closed XOR partition landmark on this corner. A
8513 /// regression that crossed the wires between the two parent-
8514 /// composed probes (one probe silently composing the wrong
8515 /// closed-set arm) fails HERE rather than at every downstream
8516 /// consumer that trusts the two probes partition the calm slot
8517 /// into disjoint buckets whose union covers every variant.
8518 #[test]
8519 fn classification_calm_probes_form_binary_xor_partition_over_all() {
8520 for populated in CalmClassification::ALL {
8521 let c = Classification::gate_compute_with_axis(populated);
8522 let buckets = [c.calm_is_monotone(), c.calm_requires_coordination()];
8523 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
8524 assert_eq!(
8525 hits, 1,
8526 "calm={populated:?}: probes {buckets:?} — exactly one must be true (binary XOR partition violated)",
8527 );
8528 }
8529 }
8530
8531 // ── Classification::data_is_public substrate pins ───────────────
8532 //
8533 // Fail-before-pass-after granularity: [`Classification::data_is_public`]
8534 // did not exist before this commit — the `(Classification) -> bool`
8535 // derived-nullary-boolean walk over the scalar [`DataClassification`]
8536 // slot's [`DataClassification::is_public`] projection had no
8537 // substrate owner. Post-lift the shape lives at ONE substrate
8538 // primitive and every downstream (the `public-data` fixed tag
8539 // in `tatara-check`, the
8540 // [`crate::ephemeral::EphemeralSpec::data_is_public`] peer,
8541 // future compliance-baseline / audit-log-optional validators
8542 // reading the positive distribution framing) composes against the
8543 // SAME `data_is_public()` shape rather than restating either
8544 // `!self.data_is_restricted()` or the `self.data_classification.is_public()`
8545 // chain at its own callsite. THIRTEENTH occupant of the (parent ×
8546 // derived-nullary-bool) corner and THIRD occupant threading the
8547 // classification-`data_classification` axis — CLOSES the data axis
8548 // on the corner into the FULL binary XOR partition contract
8549 // `data_is_public ⊕ data_is_restricted` sealed on the closed set
8550 // by `data_classification_public_xor_restricted` and composed
8551 // through the parent-composed layer by
8552 // `classification_data_probes_form_binary_xor_partition_over_all`.
8553
8554 /// PER-VARIANT pin — for every [`DataClassification`] variant, a
8555 /// [`Classification`] whose `data_classification` field carries
8556 /// that variant returns `data_is_public()` matching the closed
8557 /// set's own [`DataClassification::is_public`] truth table. Sweep
8558 /// [`DataClassification::ALL`] so a regression that (a) hard-
8559 /// coded the method body to a fixed answer (silently returning
8560 /// `true` regardless of the stored variant, silently promoting
8561 /// every dataset onto the freely-distributable path and shipping
8562 /// PII/PHI/PCI content past every compliance gate), (b) inverted
8563 /// the projection (silently demoting `Public` to access-controlled),
8564 /// or (c) crossed the wires with a sibling classification-axis
8565 /// probe fails HERE at the substrate primitive before drifting
8566 /// through the `public-data` fixed tag or the peer ephemeral
8567 /// surface.
8568 #[test]
8569 fn classification_data_is_public_matches_data_classification_projection() {
8570 for populated in DataClassification::ALL {
8571 let c = Classification::gate_compute_with_axis(populated);
8572 assert_eq!(
8573 c.data_is_public(),
8574 populated.is_public(),
8575 "data_classification={populated:?}: data_is_public() drift from DataClassification::is_public()",
8576 );
8577 }
8578 }
8579
8580 /// GATE-COMPUTE BASELINE — the workspace-baseline
8581 /// [`Classification::gate_compute`] shape carries
8582 /// `data_classification: DataClassification::default()` which
8583 /// defaults to [`DataClassification::Internal`] via `#[default]`,
8584 /// and [`DataClassification::Internal::is_public`] projects
8585 /// `false`, so `data_is_public()` returns `false`. Pins the
8586 /// default-arm short-circuit through ONE layer of `Default`
8587 /// ([`DataClassification`]'s) at ONE narrow site — a regression
8588 /// that promoted [`DataClassification::Public`] to `#[default]`
8589 /// (silently ballooning the workspace's default compliance
8590 /// posture from access-controlled to publicly-distributable), or
8591 /// that wired [`DataClassification::Internal`] to
8592 /// `is_public() = true`, would fail HERE before drifting through
8593 /// every unadorned Process's positive-distribution-framing
8594 /// answer. Mirror-inverted from the sibling
8595 /// `classification_gate_compute_data_is_restricted_is_true`
8596 /// baseline (both walk the SAME defaulted `data_classification`
8597 /// field, so `is_restricted = true` ⇒ `is_public = false` on the
8598 /// closed set's disjoint XOR partition).
8599 #[test]
8600 fn classification_gate_compute_data_is_public_is_false() {
8601 let c = Classification::gate_compute();
8602 assert!(
8603 !c.data_is_public(),
8604 "gate_compute (data_classification=Internal → is_public=false) baseline",
8605 );
8606 }
8607
8608 /// MUTEX pin — [`Classification::data_is_regulated`] AND
8609 /// [`Classification::data_is_public`] are NEVER simultaneously
8610 /// true for ANY [`DataClassification`] variant, since the closed
8611 /// set's own `is_public` / `is_regulated` pair carves it into
8612 /// disjoint buckets sealed by
8613 /// `data_classification_regulated_implies_not_public`. FIRST
8614 /// substrate-composed antisymmetric MUTEX pin against the
8615 /// positive-distribution framing: complementary to
8616 /// `data_is_regulated ⇒ data_is_restricted` on the sibling
8617 /// projection, this seals `data_is_regulated ⇒ ¬data_is_public`
8618 /// at the parent-composed layer, closing the closed-set-internal
8619 /// implication into the substrate primitive's own contract.
8620 #[test]
8621 fn classification_data_is_regulated_and_data_is_public_are_mutex_over_all() {
8622 for populated in DataClassification::ALL {
8623 let c = Classification::gate_compute_with_axis(populated);
8624 assert!(
8625 !(c.data_is_regulated() && c.data_is_public()),
8626 "data_classification={populated:?}: data_is_regulated AND data_is_public both true (mutex violated)",
8627 );
8628 }
8629 }
8630
8631 /// BINARY XOR PARTITION pin — for every [`DataClassification`]
8632 /// variant, EXACTLY ONE of [`Classification::data_is_public`] and
8633 /// [`Classification::data_is_restricted`] returns `true` on a
8634 /// [`Classification`] carrying that variant. CLOSES the data-axis
8635 /// MUTEX pin (`data_is_regulated ⇒ ¬data_is_public`) into the
8636 /// FULL binary XOR partition contract sealed on the closed set
8637 /// by `data_classification_public_xor_restricted` AND now
8638 /// composed through the parent-composed layer as a substrate-wide
8639 /// theorem. Binary counterpart of the ternary XOR partitions
8640 /// sealed on the sibling `point_type` and `substrate` axes by
8641 /// `classification_point_type_probes_form_three_way_xor_partition_over_all`
8642 /// and
8643 /// `classification_substrate_probes_form_three_way_xor_partition_over_all`
8644 /// — where those axes carve the closed set into THREE disjoint
8645 /// buckets, the data axis carves into TWO. Structural twin of
8646 /// the calm-axis binary XOR partition
8647 /// `classification_calm_probes_form_binary_xor_partition_over_all`
8648 /// on the sibling calm axis — both bind a two-bucket (positive-
8649 /// framing/negative-framing) closed-set partition through the
8650 /// parent-composed layer. A regression that crossed the wires
8651 /// between the two parent-composed probes (one probe silently
8652 /// composing the wrong closed-set arm) fails HERE rather than at
8653 /// every downstream consumer that trusts the two probes partition
8654 /// the data slot into disjoint buckets whose union covers every
8655 /// variant.
8656 #[test]
8657 fn classification_data_probes_form_binary_xor_partition_over_all() {
8658 for populated in DataClassification::ALL {
8659 let c = Classification::gate_compute_with_axis(populated);
8660 let buckets = [c.data_is_public(), c.data_is_restricted()];
8661 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
8662 assert_eq!(
8663 hits, 1,
8664 "data_classification={populated:?}: probes {buckets:?} — exactly one must be true (binary XOR partition violated)",
8665 );
8666 }
8667 }
8668
8669 // ── Classification::direction_prefers_lower substrate pins ──────
8670 //
8671 // Fail-before-pass-after granularity:
8672 // [`Classification::direction_prefers_lower`] did not exist before
8673 // this commit — the `(Classification) -> bool` derived-nullary-
8674 // boolean walk over the [`Horizon::direction`] slot's
8675 // [`OptimizationDirection::prefers_lower`] projection had no
8676 // substrate owner. Post-lift the shape lives at ONE substrate
8677 // primitive and every downstream (the `prefers-lower-direction`
8678 // fixed tag in `tatara-check`, the
8679 // [`crate::ephemeral::EphemeralSpec::direction_prefers_lower`]
8680 // peer, future asymptotic-health rate-window / regression-detector
8681 // evaluators keying on the optimization-polarity) composes against
8682 // the SAME `direction_prefers_lower()` shape rather than restating
8683 // the `self.horizon.direction.unwrap_or_default().prefers_lower()`
8684 // chain at its own callsite. FOURTEENTH occupant of the (parent ×
8685 // derived-nullary-bool) corner and FIRST occupant threading the
8686 // classification-`horizon.direction` axis — opens the SIXTH
8687 // classification axis into the fixed-tag algebra.
8688
8689 /// PER-VARIANT pin — for every [`OptimizationDirection`] variant, a
8690 /// [`Classification`] whose `horizon.direction` slot carries
8691 /// `Some(variant)` returns `direction_prefers_lower()` matching
8692 /// the closed set's own [`OptimizationDirection::prefers_lower`]
8693 /// truth table. Sweep [`OptimizationDirection::ALL`] so a regression
8694 /// that (a) hard-coded the method body to a fixed answer (silently
8695 /// returning `true` regardless of the stored variant, silently
8696 /// keeping every Process on the lower-is-better path and inverting
8697 /// every rate-window evaluator that expected Maximize polarity),
8698 /// (b) inverted the projection (silently promoting `Maximize` to
8699 /// "prefers lower"), (c) dropped the `.unwrap_or_default()` hop
8700 /// (defaulting a `None` slot to a fixed `false` rather than the
8701 /// closed-set-level `Minimize.prefers_lower() = true`), or
8702 /// (d) crossed the wires with a sibling classification-axis probe
8703 /// fails HERE at the substrate primitive before drifting through
8704 /// the `prefers-lower-direction` fixed tag or the peer ephemeral
8705 /// surface.
8706 #[test]
8707 fn classification_direction_prefers_lower_matches_optimization_direction_projection() {
8708 for populated in OptimizationDirection::ALL {
8709 let c = Classification::gate_compute_with_axis(populated);
8710 assert_eq!(
8711 c.direction_prefers_lower(),
8712 populated.prefers_lower(),
8713 "horizon.direction={populated:?}: direction_prefers_lower() drift from OptimizationDirection::prefers_lower()",
8714 );
8715 }
8716 }
8717
8718 /// GATE-COMPUTE BASELINE — the workspace-baseline
8719 /// [`Classification::gate_compute`] shape carries
8720 /// `horizon: Horizon::default()` whose `direction` field is `None`,
8721 /// so `self.horizon.direction.unwrap_or_default()` defaults to
8722 /// [`OptimizationDirection::Minimize`] via `#[default]`, and
8723 /// [`OptimizationDirection::Minimize::prefers_lower`] projects
8724 /// `true`, so `direction_prefers_lower()` returns `true`. Pins the
8725 /// default-arm short-circuit through TWO layers of `Default`
8726 /// ([`Horizon::default`] → `direction: None`; then
8727 /// [`OptimizationDirection::default = Minimize`]) at ONE narrow
8728 /// site — a regression that promoted [`OptimizationDirection::Maximize`]
8729 /// to `#[default]` (silently flipping every unadorned Process's
8730 /// rate-window evaluator polarity), that wired `Minimize` to
8731 /// `prefers_lower() = false`, or that dropped the
8732 /// `.unwrap_or_default()` hop (silently defaulting `None` to
8733 /// `false` rather than to the closed-set-level `Minimize` baseline),
8734 /// would fail HERE before drifting through every unadorned Process's
8735 /// optimization-polarity answer.
8736 #[test]
8737 fn classification_gate_compute_direction_prefers_lower_is_true() {
8738 let c = Classification::gate_compute();
8739 assert!(
8740 c.direction_prefers_lower(),
8741 "gate_compute (horizon.direction=None → unwrap_or_default=Minimize → prefers_lower=true) baseline",
8742 );
8743 }
8744
8745 // ── Classification::direction_prefers_higher substrate pins ─────
8746 //
8747 // Fail-before-pass-after granularity:
8748 // [`Classification::direction_prefers_higher`] did not exist before
8749 // this commit — the positive higher-is-better framing peer of
8750 // [`Classification::direction_prefers_lower`] had no substrate
8751 // owner. Post-lift the shape lives at ONE substrate primitive and
8752 // every downstream (the `prefers-higher-direction` fixed tag in
8753 // `tatara-check`, the
8754 // [`crate::ephemeral::EphemeralSpec::direction_prefers_higher`]
8755 // peer, future asymptotic-health rate-window / regression-detector
8756 // evaluators keying on the higher-is-better polarity) composes
8757 // against the SAME `direction_prefers_higher()` shape rather than
8758 // restating either `!self.direction_prefers_lower()` or the
8759 // `self.horizon.direction.unwrap_or_default().prefers_higher()`
8760 // chain at its own callsite. FIFTEENTH occupant of the (parent ×
8761 // derived-nullary-bool) corner and SECOND occupant threading the
8762 // classification-`horizon.direction` axis — CLOSES the axis on the
8763 // corner into the FULL binary XOR partition contract
8764 // `direction_prefers_lower ⊕ direction_prefers_higher` sealed on
8765 // the closed set by
8766 // `optimization_direction_prefers_lower_xor_prefers_higher` and
8767 // composed through the parent-composed layer by
8768 // `classification_direction_probes_form_binary_xor_partition_over_all`.
8769 // ALL SIX classification axes (horizon, calm, data, point,
8770 // substrate, optimization-direction) now have their partitions
8771 // closed at the corner.
8772
8773 /// PER-VARIANT pin — for every [`OptimizationDirection`] variant, a
8774 /// [`Classification`] whose `horizon.direction` slot carries
8775 /// `Some(variant)` returns `direction_prefers_higher()` matching
8776 /// the closed set's own [`OptimizationDirection::prefers_higher`]
8777 /// truth table. Sweep [`OptimizationDirection::ALL`] so a
8778 /// regression that (a) hard-coded the method body to a fixed
8779 /// answer (silently returning `false` regardless of the stored
8780 /// variant, silently keeping every Process on the lower-is-better
8781 /// path and inverting every rate-window evaluator that expected
8782 /// Maximize polarity), (b) inverted the projection (silently
8783 /// promoting `Minimize` to "prefers higher"), (c) dropped the
8784 /// `.unwrap_or_default()` hop (defaulting a `None` slot to a
8785 /// fixed `true` rather than the closed-set-level
8786 /// `Minimize.prefers_higher() = false`), or (d) crossed the wires
8787 /// with a sibling classification-axis probe fails HERE at the
8788 /// substrate primitive before drifting through the
8789 /// `prefers-higher-direction` fixed tag or the peer ephemeral
8790 /// surface.
8791 #[test]
8792 fn classification_direction_prefers_higher_matches_optimization_direction_projection() {
8793 for populated in OptimizationDirection::ALL {
8794 let c = Classification::gate_compute_with_axis(populated);
8795 assert_eq!(
8796 c.direction_prefers_higher(),
8797 populated.prefers_higher(),
8798 "horizon.direction={populated:?}: direction_prefers_higher() drift from OptimizationDirection::prefers_higher()",
8799 );
8800 }
8801 }
8802
8803 /// GATE-COMPUTE BASELINE — the workspace-baseline
8804 /// [`Classification::gate_compute`] shape carries
8805 /// `horizon: Horizon::default()` whose `direction` field is `None`,
8806 /// so `self.horizon.direction.unwrap_or_default()` defaults to
8807 /// [`OptimizationDirection::Minimize`] via `#[default]`, and
8808 /// [`OptimizationDirection::Minimize::prefers_higher`] projects
8809 /// `false`, so `direction_prefers_higher()` returns `false`. Pins
8810 /// the default-arm short-circuit through TWO layers of `Default`
8811 /// ([`Horizon::default`] → `direction: None`; then
8812 /// [`OptimizationDirection::default = Minimize`]) at ONE narrow
8813 /// site — a regression that promoted [`OptimizationDirection::Maximize`]
8814 /// to `#[default]` (silently flipping every unadorned Process's
8815 /// rate-window evaluator polarity onto the higher-is-better path),
8816 /// that wired `Minimize` to `prefers_higher() = true`, or that
8817 /// dropped the `.unwrap_or_default()` hop (silently defaulting
8818 /// `None` to `true` rather than the closed-set-level `Minimize`
8819 /// baseline) would fail HERE before drifting through every
8820 /// unadorned Process's optimization-polarity answer. Mirror-
8821 /// inverted from the sibling
8822 /// `classification_gate_compute_direction_prefers_lower_is_true`
8823 /// baseline (both walk the SAME defaulted `horizon.direction`
8824 /// slot, so `prefers_lower = true` ⇒ `prefers_higher = false` on
8825 /// the closed set's disjoint XOR partition).
8826 #[test]
8827 fn classification_gate_compute_direction_prefers_higher_is_false() {
8828 let c = Classification::gate_compute();
8829 assert!(
8830 !c.direction_prefers_higher(),
8831 "gate_compute (horizon.direction=None → unwrap_or_default=Minimize → prefers_higher=false) baseline",
8832 );
8833 }
8834
8835 /// MUTEX pin — [`Classification::direction_prefers_lower`] AND
8836 /// [`Classification::direction_prefers_higher`] are NEVER
8837 /// simultaneously true for ANY [`OptimizationDirection`] variant,
8838 /// since the closed set's own `prefers_lower` / `prefers_higher`
8839 /// pair carves it into disjoint buckets sealed by
8840 /// `optimization_direction_prefers_lower_xor_prefers_higher`.
8841 /// Substrate-composed antisymmetric MUTEX pin against the
8842 /// positive higher-is-better framing peer at the parent-composed
8843 /// layer.
8844 #[test]
8845 fn classification_direction_prefers_lower_and_prefers_higher_are_mutex_over_all() {
8846 for populated in OptimizationDirection::ALL {
8847 let c = Classification::gate_compute_with_axis(populated);
8848 assert!(
8849 !(c.direction_prefers_lower() && c.direction_prefers_higher()),
8850 "horizon.direction={populated:?}: direction_prefers_lower AND direction_prefers_higher both true (mutex violated)",
8851 );
8852 }
8853 }
8854
8855 /// BINARY XOR PARTITION pin — for every [`OptimizationDirection`]
8856 /// variant, EXACTLY ONE of [`Classification::direction_prefers_lower`]
8857 /// and [`Classification::direction_prefers_higher`] returns `true`
8858 /// on a [`Classification`] carrying that variant on its
8859 /// `horizon.direction` slot. CLOSES the optimization-direction
8860 /// axis into the FULL binary XOR partition contract sealed on the
8861 /// closed set by
8862 /// `optimization_direction_prefers_lower_xor_prefers_higher` and
8863 /// composed through the parent-composed layer as a substrate-wide
8864 /// theorem — the SIXTH (and final) classification axis to reach
8865 /// the parent-composed binary XOR partition landmark at this
8866 /// corner. Structural twin of the calm-axis binary XOR partition
8867 /// `classification_calm_probes_form_binary_xor_partition_over_all`
8868 /// and the data-axis binary XOR partition
8869 /// `classification_data_probes_form_binary_xor_partition_over_all`
8870 /// on the sibling calm + data axes — all three binary XOR
8871 /// partitions publish their two derived-nullary-bool projections
8872 /// as complementary XOR pairs at ONE site each so the axis carves
8873 /// into disjoint buckets by construction. A regression that
8874 /// crossed the wires between the two parent-composed probes (one
8875 /// probe silently composing the wrong closed-set arm) fails HERE
8876 /// rather than at every downstream consumer that trusts the two
8877 /// probes partition the direction slot into disjoint buckets
8878 /// whose union covers every variant.
8879 #[test]
8880 fn classification_direction_probes_form_binary_xor_partition_over_all() {
8881 for populated in OptimizationDirection::ALL {
8882 let c = Classification::gate_compute_with_axis(populated);
8883 let buckets = [c.direction_prefers_lower(), c.direction_prefers_higher()];
8884 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
8885 assert_eq!(
8886 hits, 1,
8887 "horizon.direction={populated:?}: probes {buckets:?} — exactly one must be true (binary XOR partition violated)",
8888 );
8889 }
8890 }
8891
8892 // ── Classification::input_arity_is_one / input_arity_is_many
8893 // substrate pins ─────────────────────────────────────────────────
8894 //
8895 // Fail-before-pass-after granularity:
8896 // [`Classification::input_arity_is_one`] and
8897 // [`Classification::input_arity_is_many`] did not exist before this
8898 // commit — the input-arity axis, previously reachable only through
8899 // the parameterized [`Classification::has_input_arity`] probe, had
8900 // no derived-nullary-bool corner occupant. Post-lift the two
8901 // shapes live at ONE substrate primitive each and every future
8902 // downstream (the `single-input-arity` / `multi-input-arity` fixed
8903 // tags in `tatara-check`, DAG composition validators, an ephemeral
8904 // surface peer through [`crate::ephemeral::EphemeralSpec::resolved_classification`])
8905 // composes against the SAME shape rather than restating either
8906 // `self.point_type.input_arity().is_one()` or
8907 // `self.has_input_arity(Arity::One)` at its own callsite.
8908 // SIXTEENTH + SEVENTEENTH occupants of the (parent × derived-
8909 // nullary-bool) corner and FIRST + SECOND occupants threading the
8910 // classification-`point_type`-derived input-arity axis — CLOSE the
8911 // SEVENTH classification axis into the FULL binary XOR partition
8912 // contract `input_arity_is_one ⊕ input_arity_is_many` sealed on
8913 // the closed set by `arity_is_one_xor_is_many_over_all` and
8914 // composed through the parent-composed layer by
8915 // `classification_input_arity_probes_form_binary_xor_partition_over_all`.
8916
8917 /// PER-VARIANT pin — for every [`ConvergencePointType`] variant, a
8918 /// [`Classification`] whose `point_type` slot carries that variant
8919 /// returns `input_arity_is_one()` matching the closed set's own
8920 /// [`ConvergencePointType::input_arity`] projection composed with
8921 /// [`Arity::is_one`]. Sweep [`ConvergencePointType::ALL`] so a
8922 /// regression that (a) hard-coded the method body to a fixed
8923 /// answer, (b) inverted the projection (silently promoting the
8924 /// multi-input variants to "single-input"), (c) crossed the wires
8925 /// with [`ConvergencePointType::output_arity`] (which disagrees
8926 /// on the four `Fork | Broadcast | Join | Gate | Select | Reduce`
8927 /// arms), or (d) dropped the `.is_one()` hop (silently returning
8928 /// the raw [`Arity`] variant discriminant) fails HERE before
8929 /// drifting through every future downstream that trusts the
8930 /// derived-nullary shape.
8931 #[test]
8932 fn classification_input_arity_is_one_matches_input_arity_projection() {
8933 for kind in ConvergencePointType::ALL {
8934 let mut c = Classification::gate_compute();
8935 c.point_type = kind;
8936 assert_eq!(
8937 c.input_arity_is_one(),
8938 kind.input_arity().is_one(),
8939 "point_type={kind:?}: input_arity_is_one() drift from ConvergencePointType::input_arity().is_one()",
8940 );
8941 }
8942 }
8943
8944 /// PER-VARIANT pin — antisymmetric peer of the sibling
8945 /// `classification_input_arity_is_one_matches_input_arity_projection`.
8946 /// For every [`ConvergencePointType`] variant, a
8947 /// [`Classification`] whose `point_type` slot carries that variant
8948 /// returns `input_arity_is_many()` matching
8949 /// [`ConvergencePointType::input_arity`] composed with
8950 /// [`Arity::is_many`]. Regressions matching the sibling
8951 /// per-variant pin's shape fail HERE for the multi-input side of
8952 /// the axis.
8953 #[test]
8954 fn classification_input_arity_is_many_matches_input_arity_projection() {
8955 for kind in ConvergencePointType::ALL {
8956 let mut c = Classification::gate_compute();
8957 c.point_type = kind;
8958 assert_eq!(
8959 c.input_arity_is_many(),
8960 kind.input_arity().is_many(),
8961 "point_type={kind:?}: input_arity_is_many() drift from ConvergencePointType::input_arity().is_many()",
8962 );
8963 }
8964 }
8965
8966 /// GATE-COMPUTE BASELINE — the workspace-baseline
8967 /// [`Classification::gate_compute`] carries `point_type: Gate`;
8968 /// [`ConvergencePointType::Gate::input_arity`] projects to
8969 /// [`Arity::Many`], so `input_arity_is_one()` returns `false` on
8970 /// the baseline. Pins the closed-set-driven default arm at ONE
8971 /// narrow site — a regression that promoted a different
8972 /// [`ConvergencePointType`] variant to the workspace-wide
8973 /// baseline, that flipped `Gate.input_arity()` from `Many` to
8974 /// `One`, or that inverted the `is_one()` projection would fail
8975 /// HERE before drifting through every unadorned Process's
8976 /// input-arity answer.
8977 #[test]
8978 fn classification_gate_compute_input_arity_is_one_is_false() {
8979 let c = Classification::gate_compute();
8980 assert!(
8981 !c.input_arity_is_one(),
8982 "gate_compute (point_type=Gate → input_arity=Many → is_one=false) baseline",
8983 );
8984 }
8985
8986 /// GATE-COMPUTE BASELINE — the antisymmetric mirror of the
8987 /// sibling `_input_arity_is_one_is_false` pin: `Gate.input_arity()
8988 /// = Many`, so `input_arity_is_many()` returns `true` on the
8989 /// baseline. Together with the sibling pin the two seal the
8990 /// input-arity slot's default-arm answer on the workspace-wide
8991 /// baseline as a binary XOR partition — a regression breaking
8992 /// either bucket's default-arm answer fails HERE.
8993 #[test]
8994 fn classification_gate_compute_input_arity_is_many_is_true() {
8995 let c = Classification::gate_compute();
8996 assert!(
8997 c.input_arity_is_many(),
8998 "gate_compute (point_type=Gate → input_arity=Many → is_many=true) baseline",
8999 );
9000 }
9001
9002 /// SUBSTRATE-COMPOSED MUTEX pin — for every
9003 /// [`ConvergencePointType`] variant, both predicates are NEVER
9004 /// simultaneously `true` on a [`Classification`] carrying that
9005 /// variant on its `point_type` slot. A regression that broke the
9006 /// disjointness (either predicate silently answering `true` for
9007 /// both single AND multi input variants) fails HERE.
9008 #[test]
9009 fn classification_input_arity_is_one_and_is_many_are_mutex_over_all() {
9010 for kind in ConvergencePointType::ALL {
9011 let mut c = Classification::gate_compute();
9012 c.point_type = kind;
9013 assert!(
9014 !(c.input_arity_is_one() && c.input_arity_is_many()),
9015 "point_type={kind:?}: input_arity_is_one AND input_arity_is_many both true (mutex violated)",
9016 );
9017 }
9018 }
9019
9020 /// BINARY XOR PARTITION pin — for every [`ConvergencePointType`]
9021 /// variant, EXACTLY ONE of [`Classification::input_arity_is_one`]
9022 /// and [`Classification::input_arity_is_many`] returns `true` on
9023 /// a [`Classification`] carrying that variant on its `point_type`
9024 /// slot. CLOSES the input-arity axis (the SEVENTH classification
9025 /// axis) into the FULL binary XOR partition contract sealed on
9026 /// the closed set by `arity_is_one_xor_is_many_over_all` and
9027 /// composed through the parent-composed layer as a substrate-wide
9028 /// theorem. Structural twin of the calm-axis binary XOR partition
9029 /// (`classification_calm_probes_form_binary_xor_partition_over_all`),
9030 /// the data-axis binary XOR partition
9031 /// (`classification_data_probes_form_binary_xor_partition_over_all`),
9032 /// and the optimization-direction-axis binary XOR partition
9033 /// (`classification_direction_probes_form_binary_xor_partition_over_all`)
9034 /// on the sibling axes — all four binary XOR partitions publish
9035 /// their two derived-nullary-bool projections as complementary
9036 /// XOR pairs at ONE site each so the axis carves into disjoint
9037 /// buckets by construction. A regression that crossed the wires
9038 /// between the two parent-composed probes (one probe silently
9039 /// composing the wrong closed-set arm) fails HERE rather than at
9040 /// every future downstream consumer that trusts the two probes
9041 /// partition the input-arity projection into disjoint buckets
9042 /// whose union covers every [`ConvergencePointType`] variant.
9043 #[test]
9044 fn classification_input_arity_probes_form_binary_xor_partition_over_all() {
9045 for kind in ConvergencePointType::ALL {
9046 let mut c = Classification::gate_compute();
9047 c.point_type = kind;
9048 let buckets = [c.input_arity_is_one(), c.input_arity_is_many()];
9049 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
9050 assert_eq!(
9051 hits, 1,
9052 "point_type={kind:?}: probes {buckets:?} — exactly one must be true (binary XOR partition violated)",
9053 );
9054 }
9055 }
9056
9057 // ── Classification::output_arity_is_one / output_arity_is_many
9058 // substrate pins ─────────────────────────────────────────────────
9059 //
9060 // Fail-before-pass-after granularity:
9061 // [`Classification::output_arity_is_one`] and
9062 // [`Classification::output_arity_is_many`] did not exist before this
9063 // commit — the output-arity axis, previously reachable only through
9064 // the parameterized [`Classification::has_output_arity`] probe, had
9065 // no derived-nullary-bool corner occupant. Post-lift the two shapes
9066 // live at ONE substrate primitive each and every future downstream
9067 // (the `single-output-arity` / `multi-output-arity` fixed tags in
9068 // `tatara-check`, DAG composition validators, an ephemeral surface
9069 // peer through
9070 // [`crate::ephemeral::EphemeralSpec::resolved_classification`])
9071 // composes against the SAME shape rather than restating either
9072 // `self.point_type.output_arity().is_one()` or
9073 // `self.has_output_arity(Arity::One)` at its own callsite.
9074 // EIGHTEENTH + NINETEENTH occupants of the (parent × derived-
9075 // nullary-bool) corner and FIRST + SECOND occupants threading the
9076 // classification-`point_type`-derived output-arity axis — CLOSE the
9077 // EIGHTH classification axis into the FULL binary XOR partition
9078 // contract `output_arity_is_one ⊕ output_arity_is_many` sealed on
9079 // the closed set by `arity_is_one_xor_is_many_over_all` and
9080 // composed through the parent-composed layer by
9081 // `classification_output_arity_probes_form_binary_xor_partition_over_all`.
9082
9083 /// PER-VARIANT pin — for every [`ConvergencePointType`] variant, a
9084 /// [`Classification`] whose `point_type` slot carries that variant
9085 /// returns `output_arity_is_one()` matching the closed set's own
9086 /// [`ConvergencePointType::output_arity`] projection composed with
9087 /// [`Arity::is_one`]. Sweep [`ConvergencePointType::ALL`] so a
9088 /// regression that (a) hard-coded the method body to a fixed
9089 /// answer, (b) inverted the projection (silently demoting the
9090 /// multi-output variants `Fork | Broadcast` into the single-output
9091 /// bucket), (c) crossed the wires with
9092 /// [`ConvergencePointType::input_arity`] (which disagrees on the
9093 /// six `Fork | Broadcast | Join | Gate | Select | Reduce` arms —
9094 /// six of eight variants), or (d) dropped the `.is_one()` hop
9095 /// (silently returning the raw [`Arity`] variant discriminant)
9096 /// fails HERE before drifting through every future downstream
9097 /// that trusts the derived-nullary shape.
9098 #[test]
9099 fn classification_output_arity_is_one_matches_output_arity_projection() {
9100 for kind in ConvergencePointType::ALL {
9101 let mut c = Classification::gate_compute();
9102 c.point_type = kind;
9103 assert_eq!(
9104 c.output_arity_is_one(),
9105 kind.output_arity().is_one(),
9106 "point_type={kind:?}: output_arity_is_one() drift from ConvergencePointType::output_arity().is_one()",
9107 );
9108 }
9109 }
9110
9111 /// PER-VARIANT pin — antisymmetric peer of the sibling
9112 /// `classification_output_arity_is_one_matches_output_arity_projection`.
9113 /// For every [`ConvergencePointType`] variant, a
9114 /// [`Classification`] whose `point_type` slot carries that variant
9115 /// returns `output_arity_is_many()` matching
9116 /// [`ConvergencePointType::output_arity`] composed with
9117 /// [`Arity::is_many`]. Regressions matching the sibling per-variant
9118 /// pin's shape fail HERE for the multi-output side of the axis.
9119 #[test]
9120 fn classification_output_arity_is_many_matches_output_arity_projection() {
9121 for kind in ConvergencePointType::ALL {
9122 let mut c = Classification::gate_compute();
9123 c.point_type = kind;
9124 assert_eq!(
9125 c.output_arity_is_many(),
9126 kind.output_arity().is_many(),
9127 "point_type={kind:?}: output_arity_is_many() drift from ConvergencePointType::output_arity().is_many()",
9128 );
9129 }
9130 }
9131
9132 /// GATE-COMPUTE BASELINE — the workspace-baseline
9133 /// [`Classification::gate_compute`] carries `point_type: Gate`;
9134 /// [`ConvergencePointType::Gate::output_arity`] projects to
9135 /// [`Arity::One`], so `output_arity_is_one()` returns `true` on
9136 /// the baseline. Pins the closed-set-driven default arm at ONE
9137 /// narrow site — a regression that promoted a different
9138 /// [`ConvergencePointType`] variant to the workspace-wide
9139 /// baseline, that flipped `Gate.output_arity()` from `One` to
9140 /// `Many`, or that inverted the `is_one()` projection would fail
9141 /// HERE before drifting through every unadorned Process's
9142 /// output-arity answer. NOTE the workspace-baseline answer FLIPS
9143 /// between the input-arity and output-arity axes on the exact
9144 /// same baseline: `input_arity_is_one` is `false` on
9145 /// `gate_compute` (`Gate.input_arity() = Many`), but
9146 /// `output_arity_is_one` is `true` — direct evidence the two axes
9147 /// carve the closed set into structurally different partitions.
9148 #[test]
9149 fn classification_gate_compute_output_arity_is_one_is_true() {
9150 let c = Classification::gate_compute();
9151 assert!(
9152 c.output_arity_is_one(),
9153 "gate_compute (point_type=Gate → output_arity=One → is_one=true) baseline",
9154 );
9155 }
9156
9157 /// GATE-COMPUTE BASELINE — the antisymmetric mirror of the sibling
9158 /// `_output_arity_is_one_is_true` pin: `Gate.output_arity() = One`,
9159 /// so `output_arity_is_many()` returns `false` on the baseline.
9160 /// Together with the sibling pin the two seal the output-arity
9161 /// slot's default-arm answer on the workspace-wide baseline as a
9162 /// binary XOR partition — a regression breaking either bucket's
9163 /// default-arm answer fails HERE.
9164 #[test]
9165 fn classification_gate_compute_output_arity_is_many_is_false() {
9166 let c = Classification::gate_compute();
9167 assert!(
9168 !c.output_arity_is_many(),
9169 "gate_compute (point_type=Gate → output_arity=One → is_many=false) baseline",
9170 );
9171 }
9172
9173 /// SUBSTRATE-COMPOSED MUTEX pin — for every
9174 /// [`ConvergencePointType`] variant, both predicates are NEVER
9175 /// simultaneously `true` on a [`Classification`] carrying that
9176 /// variant on its `point_type` slot. A regression that broke the
9177 /// disjointness (either predicate silently answering `true` for
9178 /// both single AND multi output variants) fails HERE.
9179 #[test]
9180 fn classification_output_arity_is_one_and_is_many_are_mutex_over_all() {
9181 for kind in ConvergencePointType::ALL {
9182 let mut c = Classification::gate_compute();
9183 c.point_type = kind;
9184 assert!(
9185 !(c.output_arity_is_one() && c.output_arity_is_many()),
9186 "point_type={kind:?}: output_arity_is_one AND output_arity_is_many both true (mutex violated)",
9187 );
9188 }
9189 }
9190
9191 /// BINARY XOR PARTITION pin — for every [`ConvergencePointType`]
9192 /// variant, EXACTLY ONE of [`Classification::output_arity_is_one`]
9193 /// and [`Classification::output_arity_is_many`] returns `true` on
9194 /// a [`Classification`] carrying that variant on its `point_type`
9195 /// slot. CLOSES the output-arity axis (the EIGHTH classification
9196 /// axis) into the FULL binary XOR partition contract sealed on
9197 /// the closed set by `arity_is_one_xor_is_many_over_all` and
9198 /// composed through the parent-composed layer as a substrate-wide
9199 /// theorem. Structural twin of the input-arity binary XOR partition
9200 /// (`classification_input_arity_probes_form_binary_xor_partition_over_all`),
9201 /// the calm-axis binary XOR partition
9202 /// (`classification_calm_probes_form_binary_xor_partition_over_all`),
9203 /// the data-axis binary XOR partition
9204 /// (`classification_data_probes_form_binary_xor_partition_over_all`),
9205 /// and the optimization-direction-axis binary XOR partition
9206 /// (`classification_direction_probes_form_binary_xor_partition_over_all`)
9207 /// on the sibling axes — all five binary XOR partitions publish
9208 /// their two derived-nullary-bool projections as complementary
9209 /// XOR pairs at ONE site each so the axis carves into disjoint
9210 /// buckets by construction. A regression that crossed the wires
9211 /// between the two parent-composed probes (one probe silently
9212 /// composing the wrong closed-set arm) fails HERE rather than at
9213 /// every future downstream consumer that trusts the two probes
9214 /// partition the output-arity projection into disjoint buckets
9215 /// whose union covers every [`ConvergencePointType`] variant.
9216 #[test]
9217 fn classification_output_arity_probes_form_binary_xor_partition_over_all() {
9218 for kind in ConvergencePointType::ALL {
9219 let mut c = Classification::gate_compute();
9220 c.point_type = kind;
9221 let buckets = [c.output_arity_is_one(), c.output_arity_is_many()];
9222 let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
9223 assert_eq!(
9224 hits, 1,
9225 "point_type={kind:?}: probes {buckets:?} — exactly one must be true (binary XOR partition violated)",
9226 );
9227 }
9228 }
9229
9230 /// DISTINCTNESS pin — the input-arity and output-arity axes carve
9231 /// the eight-variant [`ConvergencePointType`] closed set into
9232 /// DISTINCT partitions. Six of the eight variants disagree between
9233 /// [`Classification::input_arity_is_one`] and
9234 /// [`Classification::output_arity_is_one`] (the six non-endomorphic
9235 /// variants `Fork | Broadcast | Join | Gate | Select | Reduce`
9236 /// — the four multi-input-single-output arms and the two
9237 /// single-input-multi-output arms), and only the two endomorphic
9238 /// variants (`Transform | Observe` — both `(One, One)`) agree.
9239 /// Pins the axis-distinctness invariant at ONE narrow site — a
9240 /// regression that (a) collapsed the two axes onto the same
9241 /// projection (silently reading `output_arity` as an alias for
9242 /// `input_arity`), (b) copy-pasted `input_arity_is_one`'s body
9243 /// verbatim onto `output_arity_is_one`, or (c) crossed the
9244 /// projection wires between the sibling `is_one` / `is_many`
9245 /// closed-set predicates would fail HERE by shrinking the six-arm
9246 /// disagreement to zero (identical axes) rather than at every
9247 /// future downstream that trusts the two axes name distinct
9248 /// closed-set partitions. Structural anchor for the compounding
9249 /// insight: opening a SECOND derived-typed-projection axis
9250 /// (`ConvergencePointType::output_arity`) on the corner is
9251 /// substantive precisely because it disagrees on 75% of the
9252 /// closed set with the FIRST derived-typed-projection axis
9253 /// (`ConvergencePointType::input_arity`).
9254 #[test]
9255 fn classification_input_arity_and_output_arity_disagree_on_six_of_eight_variants() {
9256 let mut disagreements = 0u32;
9257 for kind in ConvergencePointType::ALL {
9258 let mut c = Classification::gate_compute();
9259 c.point_type = kind;
9260 if c.input_arity_is_one() != c.output_arity_is_one() {
9261 disagreements += 1;
9262 }
9263 }
9264 assert_eq!(
9265 disagreements, 6,
9266 "input_arity_is_one and output_arity_is_one must disagree on exactly six of {} ConvergencePointType variants (the six non-endomorphic arms Fork|Broadcast|Join|Gate|Select|Reduce)",
9267 ConvergencePointType::ALL.len(),
9268 );
9269 }
9270}