audit: cycle-close tidy for the #256/#272 latecomer block

Drift review (architect) over a55e4cf..HEAD found the cycle substantially
clean — C25 closed vocabulary, C1 determinism/behaviour-preservation, the
additive-serde widening, exhaustive StageBlock matches, and the uniform exit-3
convention all hold. Two drift items resolved:

- RATIFY: the `SilencedPanic` member-boundary panic-hook silencer (added by the
  #272 implementer, not named in the spec) is a legitimate mechanism — it keeps
  "recorded, campaign continues" observably true on stderr by suppressing the
  default crash backtrace around each contained `catch_unwind`. Its mutex
  serialises only the ref-count/hook-swap (O(1)), never member computation, so
  C1 disjoint-parallel determinism is preserved. Documented in the ledger's
  #272 realization paragraph rather than left as undocumented global state.
- FIX: `cell_fault_kind_label` hand-wrote the snake_case strings that must match
  `CellFaultKind`'s serde `rename_all` (two sources of truth an aggregate over
  campaign_runs.jsonl could silently diverge from). Pinned with a test asserting
  each label equals the serialized form; the efficient `&'static str` stays.

(The #272 commit's own concern-driven doc fixes and the wf panic-containment
test landed in d3b1a1a; this commit carries only the two audit-phase items.)

Suite: cargo test --workspace green (1311 tests, 0 failed); clippy clean.
This commit is contained in:
2026-07-14 17:01:03 +02:00
parent d3b1a1aead
commit f0aadb54f8
2 changed files with 28 additions and 1 deletions
+10 -1
View File
@@ -1620,7 +1620,16 @@ notes + a completion summary) and a run with ≥1 failed cell exits **3**
window carries a `CellCoverage` annotation (effective bounds + interior gap
months, from the #264 archive primitives). Generalize already treats a
no-nominee cell as `missing`, so a failed cell surfaces there unchanged.
**Guarantee.** Construction is a distinct phase, recursive at every level. Each
Member panics are caught with `catch_unwind`(`AssertUnwindSafe`) at the three
member-run sites and recorded as `MemberFault::Panic`; a ref-counted
`SilencedPanic` guard (a process-global panic-hook save/no-op/restore behind a
`static Mutex`, held only around each `catch_unwind`) suppresses the default
crash backtrace so "recorded, campaign continues" is observably true on stderr,
not merely true in the record. The guard's mutex serialises only the
ref-count/hook-swap (O(1)), never the member computation, so C1 disjoint-parallel
execution and determinism are preserved; ref-counting (save on 0→1, restore on
1→0) keeps concurrent sweep/walk-forward threads and any caller-installed hook
correct. **Guarantee.** Construction is a distinct phase, recursive at every level. Each
node type has a **factory** `params → sized concrete node` (e.g. `SMA(length)`
sizes its ring buffer). A **blueprint** is the param-generic, input-role-generic
graph-as-data produced by running a Rust builder (C9); it carries *free* numeric