DC-VIEW-01
DC derived enforcedLiveLedgerView determinism + epoch-window guard. The view is constructed deterministically from LiveConsensusInputsCanonical.
Two guards on every LedgerView query: (a) Queried epoch != canonical.epoch_no → return None (BLUE then fails closed via MissingConsensusInput). (b) Block slot outside [epoch_start_slot, epoch_end_slot] → runner intercepts before admit and emits AdmissionHalted { reason: CrossEpochUse } (DC-ADMIT-11).
No ambient default view; no cross-epoch silent use.
- Source
docs/planning/phase4-n-m-c-operator-pass-invariants.md §1 (I-C4)
Enforcement trace
Tests 5
- consensus_inputs::view::tests::out_of_window_epoch_returns_none
- consensus_inputs::view::tests::in_window_epoch_answers_total_active_stake
- consensus_inputs::view::tests::in_window_per_pool_lookups_return_imported_values
- consensus_inputs::view::tests::in_window_unknown_pool_returns_none
- admission::bootstrap::tests::imported_window_schedule_uses_bundle_epoch
Cross-references
Strengthened in
Evidence
PHASE4-N-M-SCHED (2026-05-27) strengthens this guard by ensuring the era-schedule reports the bundle's actual epoch_no — without this,
LiveLedgerView's correct epoch-window guard would return None for every block in the imported window (because the schedule reported epoch=0 for all slots, never matchinginputs.epoch_no). Fix:make_schedule_for_imported_window(epoch_start_slot, epoch_no)now takes the bundle's epoch as a parameter and wires it intoEraSummary::start_epoch. Regression test assertsschedule.locate(slot_in_window).epoch == bundle_epochfor non-zero epoch_no.