From f0aadb54f80c327ed564be06cf47ab8ddaec2dcd Mon Sep 17 00:00:00 2001 From: claude Date: Tue, 14 Jul 2026 17:01:03 +0200 Subject: [PATCH] audit: cycle-close tidy for the #256/#272 latecomer block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- crates/aura-cli/src/campaign_run.rs | 18 ++++++++++++++++++ docs/design/INDEX.md | 11 ++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/aura-cli/src/campaign_run.rs b/crates/aura-cli/src/campaign_run.rs index fcc4332..c68010f 100644 --- a/crates/aura-cli/src/campaign_run.rs +++ b/crates/aura-cli/src/campaign_run.rs @@ -1564,6 +1564,24 @@ mod tests { /// bounds fall short of full coverage. GAPSYM-shaped input (files at /// 2024-01..02 and 2024-05..06, absent 03..04) over a Jan-through-June /// window must name exactly the two missing interior months. + /// #272: the summary label is a CHECKED mirror of the persisted serde form + /// — an aggregate over `campaign_runs.jsonl` counts by the serialized + /// `CellFaultKind` string, so the human-facing label must be exactly that + /// string (no second source of truth that could silently drift). + fn cell_fault_kind_label_matches_the_serialized_kind() { + use aura_registry::CellFaultKind as K; + for kind in [K::NoData, K::Bind, K::Run, K::Panic, K::Window] { + let serde_form = serde_json::to_string(&kind).expect("serialize kind"); + let serde_form = serde_form.trim_matches('"'); + assert_eq!( + cell_fault_kind_label(kind), + serde_form, + "the summary label must equal the persisted serde string" + ); + } + } + + #[test] fn interior_gap_months_names_a_whole_missing_month_spanned_by_the_window() { let months = [(2024u16, 1u8), (2024, 2), (2024, 5), (2024, 6)]; // 2024-01-01T00:00:00Z .. 2024-07-01T00:00:00Z (Unix ms) — spans every diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index db8a4b1..b4582e4 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -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