CN-REHEARSAL-FIDELITY-01
CN release enforcedPrivate-testnet accepted-block bounty dry-run fidelity (two coupled clauses; if either fails the rehearsal becomes misleading). (1) PATH FIDELITY: the C1 private dry-run uses the SAME --mode node accepted-block path as preview/preprod -- N-M-C extraction/import (import_live_consensus_inputs) -> forge -> self-accept -> sibling-serve -> block-fetch -> peer log -> correlate -- with NO private-only flag, branch, bootstrap authority, or from-genesis constructor. The only differences from the preprod pass are operator-controlled inputs (a private genesis whose stake allocation makes Ade win slots fast) and the evidence label (rehearsal). No private-only helper may make the rehearsal pass if the same condition would fail on preview/preprod -- such a condition is a shared-path bug to fix in the shared path, never special-cased. (2) EVIDENCE NON-PROMOTABILITY: any private-testnet manifest is clearly marked rehearsal / private-testnet, stored ONLY under the rehearsal home (docs/evidence/phase4-n-f-g-d-private-rehearsal-.toml, never the bounty home docs/clusters/PHASE4-N-F-G-C/CE-G-C-LIVE_.toml), sha256-bound to a real Haskell peer log, correlate-produced (ba02_evidence::correlate is the sole acceptance-evidence constructor; allow-list, hash-primary), and flips NO RO-LIVE rule. C1 rehearsal evidence may increase confidence in the bounty path, but it is NOT bounty evidence and MUST NOT be referenced by the CE-G-C-LIVE_* / ci_check_ba02_evidence_manifest_schema.sh gate. The single bounty deliverable is preview/preprod acceptance, captured separately.
- Source
docs/planning/phase4-n-f-g-d-invariants.md
- Introduced in
- PHASE4-N-F-G-D
Enforcement trace
Code
- crates/ade_node/src/ba02_evidence.rs
- crates/ade_node/src/ba02_pass.rs
- crates/ade_runtime/src/consensus_inputs/
- docs/evidence/phase4-n-f-g-c-operator-pass-README.md
- docs/evidence/phase4-n-f-g-d-private-rehearsal-
- ci/ci_check_rehearsal_manifest_schema.sh
- ci/ci_check_node_path_fidelity.sh
- crates/ade_node/tests/forge_succeeds.rs
- crates/ade_node/tests/node_c1_genesis_rehearsal.rs
- docs/evidence/phase4-n-f-g-j-genesis-rehearsal-README.md
- ci/ci_check_genesis_successor_reachability.sh
Tests 10
- node_accepted_block_consensus_inputs_via_shared_import
- rehearsal_envelope_wraps_correlate_produced_payload
- rehearsal_correlate_no_evidence_writes_nothing
- rehearsal_envelope_is_structurally_distinct_from_ba02_manifest
- c1_dry_run_correlate_to_rehearsal_envelope
- node_c1_dry_run_rehearsal_live
- rehearsal_gate_fails_on_archived_home_leak
- genesis_rehearsal_manifest_binds_block_zero_genesis
- genesis_rehearsal_no_evidence_writes_nothing
- node_c1_genesis_rehearsal_live
Cross-references
Strengthened in
Evidence notes
PHASE4-N-F-G-D invariant sketch (/invariants gate, 2026-06-02). Declared at sketch; tests + ci_script populate at slice time, flip to enforced at close. G-D is a BOUNTY DRY-RUN HARNESS -- a fast failure detector for the EXACT preview/preprod accepted-block path, run in a venue where the operator controls stake (private genesis) so Ade wins slots fast. It answers one question: will a real Haskell node accept an Ade-forged block when Ade has legitimate leader rights? -- surfacing the bounty-blocking failure classes (opcert/KES, Praos leader proof, header fields, block body/wire, tag-24 BlockFetch payload, serve path, peer-log parsing) early.
The mechanical accepted-block pipeline is already complete (G-A forge fidelity, G-B self-accept->serve handoff, G-C live feed + BA-02 evidence I/O, G-E live-feed bounded memory). G-D adds NO new BLUE authority, NO new canonical type, NO new NodeBlockSource/CoordinatorEvent variant, NO new --mode node argv flag, NO from-genesis consensus-inputs constructor, NO private-only bootstrap. It reuses the proven N-M-C import_live_consensus_inputs extraction (the SAME path preprod uses) -- the from-genesis offline constructor (C1-scoping doc G3/§4 item 3) is a private-only path and is DELIBERATELY NOT built (litmus test: every G-D element must transfer verbatim to preview/preprod).
Two halves, mirroring G-C: a MECHANICAL half (closeable hermetically -- the path-fidelity fence + the distinct rehearsal-evidence surface + gate + a dry-run runbook that is a provable strict subset of the preprod operator-pass runbook) and an OPERATOR-GATED half (the actual C1 live execution -- blocked_until_operator_c1_net_executed).
Hard limit (do not soften): private C1 acceptance != bounty completion; preview/preprod acceptance = bounty completion. No RO-LIVE flip; no strengthened_in bump on RO-LIVE-01 / RO-LIVE-06 / CN-OPERATOR-EVIDENCE-01 (G-D does not advance the bounty deliverable). The relay-loop containment gate, the served-chain handoff fence, and the live-feed memory bounds stay byte-unchanged.
PHASE4-N-F-G-D S1 (path-fidelity proof + fence) LANDED: OQ1 proven empirically -- the shared importer is venue-agnostic. A private / epoch-0-shaped bundle (epoch_no=0, epoch_start_slot=0, origin tip in-window) AND a synced-preprod-tip-shaped bundle both import through the single import_live_consensus_inputs_from_bytes with NO venue branch (no shared-path fix needed -- validate_and_lift's inclusive window check passes epoch 0). New test node_accepted_block_consensus_inputs_via_shared_import (crates/ade_node/tests/node_path_fidelity.rs) + new gate ci/ci_check_node_path_fidelity.sh (guard a: cli.rs flag set == the pinned 28-flag closed allow-list, G-D adds none; guard b: no from-genesis consensus-inputs constructor + node_lifecycle sources consensus inputs only via the shared importer; both fail-closed-smoke-verified against an injected --private-net flag + a build_consensus_inputs_from_genesis ctor). The 3 containment / handoff / memory fences are byte-unchanged + green; cargo test -p ade_node + -p ade_runtime green. The tests/ci_script array binding + the declared->enforced flip are deferred to the G-D close pass (clause 1 path fidelity is mechanically green in CI from S1 onward).
PHASE4-N-F-G-D S2 (rehearsal-evidence surface + gate) LANDED: new GREEN ade_node::rehearsal_evidence -- PrivateRehearsalManifest WRAPS a correlate-produced Ba02Manifest payload in a distinct rehearsal envelope; sole ctor from_correlate_outcome returns None on NoEvidence (nothing to write); to_canonical_toml emits is_rehearsal = true
- not_bounty_evidence = true as LITERALS (the type cannot represent a non-rehearsal). New RED ade_node::rehearsal_pass -- correlate_peer_log_file_into_rehearsal REUSES ba02_pass::correlate_peer_log_file verbatim (no alternate correlator); write_private_rehearsal_manifest accepts ONLY a PrivateRehearsalManifest. New gate ci/ci_check_rehearsal_manifest_schema.sh (vacuous-until-committed; closed rehearsal schema
- venue/private-testnet + is_rehearsal/not_bounty_evidence markers + peer_log_file_sha256 binding; THREE non-promotability barriers: distinct docs/evidence/ home, the rehearsal markers, and a cross-check that no rehearsal marker appears in any .toml under the bounty home docs/clusters/PHASE4-N-F-G-C/; fail-closed-smoke-verified on wrong sha256 / missing marker / bounty-home leak). 3 tests (rehearsal_envelope_wraps_correlate_produced_payload, rehearsal_correlate_no_evidence_writes_nothing, rehearsal_envelope_is_structurally_distinct_from_ba02_manifest). RO-LIVE-01 / RO-LIVE-06 + the bounty BA-02 gate (ci_check_ba02_evidence_manifest_schema.sh) + the S1 fence + the 3 containment / handoff / memory fences are byte-unchanged; no BLUE change; cargo test -p ade_node green. The tests/ci_script array binding + the declared->enforced flip remain deferred to the G-D close pass (clause 2 evidence non-promotability is mechanically green in CI from S2 onward).
PHASE4-N-F-G-D S3 (C1 dry-run runbook + operator-gated execution scaffold) LANDED: new runbook docs/evidence/phase4-n-f-g-d-private-rehearsal-README.md -- a STRICT SUBSET of the G-C preprod operator-pass runbook (same --mode node path / --peer feed / --json-seed / --consensus-inputs-path / operator-key flow / peer-log capture / correlate / NoEvidence fail-closed; ONLY venue=private-testnet-c1 + operator genesis stake + the PrivateRehearsalManifest envelope differ; the strict-subset property is ANCHORED by the S1 path-fidelity fence, not merely asserted). New RED test file crates/ade_node/tests/node_c1_dry_run_rehearsal.rs: hermetic c1_dry_run_correlate_to_rehearsal_envelope (file -> correlate_peer_log_file_into_rehearsal -> write_private_rehearsal_manifest -> read back; markers + payload asserted; NoEvidence -> None -> nothing written; missing log -> io::Error) + env-gated node_c1_dry_run_rehearsal_live (ADE_LIVE_C1_DRY_RUN; the operator execution harness -- a RED test, skipped in CI, NOT a runtime node mode; NoEvidence panics, never writes). NO binary wiring, NO new --mode node flag, NO new bootstrap/constructor, NO alternate correlator, NO new CI gate, NO synthetic manifest committed (the rehearsal gate stays vacuous), NO RO-LIVE flip, NO BLUE change. All 6 gates green; cargo test -p ade_node green. With S1 + S2 + S3 mechanically green, CN-REHEARSAL-FIDELITY-01 is complete; the tests/ci_script binding + the declared->enforced flip happen at /cluster-close PHASE4-N-F-G-D. The live C1 run is blocked_until_operator_c1_net_executed; the bounty deliverable remains the separate C2 preprod pass.
PHASE4-N-F-G-D S4 (rehearsal leak gate archived-home hardening) LANDED: fixes the per-cluster-security-review HIGH (barrier b dead). ci/ci_check_rehearsal_manifest_schema.sh now scans ALL real bounty homes -- docs/clusters/PHASE4-N-F-G-C/ (active) AND docs/clusters/completed/PHASE4-N-F-G-C/ (archived) -- by building the EXISTING-homes list first (no [[ -d ]] whole-check skip): "home absent" => empty contribution (deliberate); a scan error on an EXISTING home (grep rc>=2) => fail closed, not swallowed. New durable regression test crates/ade_node/tests/rehearsal_gate_archived_home.rs (rehearsal_gate_fails_on_archived_home_leak): clean tree => gate green; a rehearsal-marked .toml under the ARCHIVED home => gate FAILS (Drop-guarded fixture). VERIFIED: the exact pre-S4 smuggle that passed (exit 0) now fails (exit 1). NO change to the BA-02 bounty gate (its same stale active-home glob is a separate follow-up), to rehearsal_evidence / rehearsal_pass (no toml_escape fold-in -- deferred), to the S1 fence, or to any BLUE/containment surface. All 6 gates green; cargo test -p ade_node green. Barrier (b) is now actually enforced -- CN-REHEARSAL-FIDELITY-01 is mechanically complete (S1 + S2 + S3 + S4); the declared->enforced flip happens at the re-run /cluster-close PHASE4-N-F-G-D.
PHASE4-N-F-G-J S5 (2026-06-03) STRENGTHENS this rule to the GENESIS-SUCCESSOR rehearsal: the cold-start path (S4 reachability: both tips None -> forge block 0 + PrevHash::Genesis per S3) is exercised end-to-end under the SAME --mode node fidelity fence (ci_check_node_path_fidelity.sh + ci_check_genesis_successor_reachability.sh) and produces ONLY a non-promotable PrivateRehearsalManifest under the distinct genesis home docs/evidence/phase4-n-f-g-j-genesis-rehearsal-*.toml (now covered by ci_check_rehearsal_manifest_schema.sh). Reuses correlate + PrivateRehearsalManifest VERBATIM -- no new evidence type, no manifest-schema change, no BLUE change. Hermetic mechanics: genesis_rehearsal_manifest_binds_block_zero_genesis (reuses EligibleFixture's self-accepting block 0 + Genesis, correlates a follower served-block accept of its hash; a block_number 0 that decode_block accepts MUST carry Genesis via the S3 check_header_position rule) + genesis_rehearsal_no_evidence_writes_nothing (NoEvidence -> None). The live arm node_c1_genesis_rehearsal_live (ADE_LIVE_C1_GENESIS_REHEARSAL) is env-gated/skipped in CI. Acceptance is ONLY a real follower log through correlate -- never Ade self-accept / forge_succeeded / served bytes / wire success. NO RO-LIVE flip; the live C1 genesis run is blocked_until_operator_c1_genesis_successor_rehearsal.