DC-CINPUT-04
DC derived enforcedThe receive/feed-path header-validation consensus view -- the LedgerView passed to block_validity -> validate_and_apply_header for Step 5 (VRF-keyhash binding) and Step 7 (leader threshold) -- MUST be the RECOVERED consensus surface: ASC + total_active_stake + pool_distribution + per-pool VRF keyhash, projected from the recovered SeedEpochConsensusInputs via the SAME single authority the forge uses (PoolDistrView::from_seed_epoch_consensus_inputs). It is NEVER an empty/zero/default placeholder. Forge and feed validation share ONE recovered consensus surface. Fail-closed: a missing recovered SeedEpochConsensusInputs on a feed-wired node (--peer) -> a structured NodeLifecycleError::FeedMissingRecoveredConsensusInputs / halt -- never an empty view, never "accept if missing stake," never a leader-threshold bypass. NARROW: the header-validation consensus view ONLY; the authoritative ledger state stays the authority for ledger verdicts. Receive-side mirror of DC-CINPUT-02b (forge leadership view from recovered); same class as DC-CINPUT-03 / T-REC-04 (G-N forge eta0) but a different recovered input (stake distribution + ASC, not the nonce) on a different path (feed, not forge).
- Source
docs/clusters/PHASE4-N-F-G-P/cluster.md
- Cluster
- PHASE4-N-F-G-P
- Introduced in
- PHASE4-N-F-G-P
Enforcement trace
Code
Tests 1
- feed_header_validates_against_recovered_surface_not_empty_view
Cross-references
Evidence notes
PHASE4-N-F-G-P S1 (2026-06-04). Capture-first: instrumenting validate_and_apply_header (FEED-VRF-DIAG, reverted) PROVED the eta0/VRF-mirror hypothesis WRONG -- eta0=953a4c34 (recovered, correct), verify_ok=true, recomputed_eq_output=true. The VrfCert(VerificationFailed) is Step 7 (leader threshold): DIAG-2 showed epoch=0 pool_active_stake=None total_active_stake=Some(0) asc=Some((0,1)) -- the receive-path ledger_view had an EMPTY pool distribution. ROOT CAUSE: node_lifecycle.rs (forge-on On-arm) built the feed ledger_view as PoolDistrView::new(epoch, 0, ASC{0,1}, BTreeMap::new()) -- an empty placeholder justified pre-G-O by 'feed source empty, UNCONSUMED' (now consumed: the live feed delivers blocks). The forge path already used the populated PoolDistrView::from_seed_epoch_consensus_inputs(recovered) (node_sync.rs:553), so the forge self-accepted while the feed rejected (forge/feed asymmetry). The persisted SeedEpochConsensusInputs already carried ASC + total_active_stake + pool_distribution (with per-pool VRF keyhash) -- purely a WIRING gap. FIX: the On-arm feed ledger_view is now from_seed_epoch_consensus_inputs(recovered), fail-closed FeedMissingRecoveredConsensusInputs when --peer is set + the record absent (no empty fallback, no accept-if-missing). The ForgeIntent::Off relay-only arm hardcodes an always-empty in-memory source (no --peer) so its placeholder is genuinely unconsumed (no fix). feed_header_validates_against_recovered_surface_not_empty_view forges the genesis-successor block 0 and proves the recovered-surface view validates the header through Step 5 + Step 7 while the empty placeholder fails closed (VrfCert(VerificationFailed)) -- locking the regression. NO VRF/eta0/Step-5/6/7/ledger-state change. CE-G-P-2 (live C1 feed past Step 5 + Step 7; serve alive; correlate adoption) stays operator-gated; no RO-LIVE flip; no acceptance claim without the follower log through correlate. LIVE-CONFIRMED 2026-06-04 13:20Z: the C1 --mode node rerun shows VerificationFailed count = 0 -- the feed validates Step 5 + Step 7 and INGESTS Ade's block 0 (tip genesis -> slot 107405). The next failure moved to the SEPARATE forge-successor path (RecoveredTipMissingBlockNo: forge_header_position selected_tip=Some + last_block_no=None) -> PHASE4-N-F-G-Q, NOT a DC-CINPUT-04 gap.