feat(cli,ledger): supply CLI run sources by role key; ledger note
closes #275 The CLI half of by-name source binding, plus the ledger record. Every production run site that carries a ResolvedBinding — `run_signal_r`, `run_blueprint_member` (sweep / reproduction), and the campaign re-run/trace path — now keys its opened sources by role name via `key_supply(binding, sources)` and drives the harness through `Harness::run_bound` instead of the positional `run(sources)`. `key_supply` pairs each opened column with its declared role from `binding.entries()` — the one place open-order and role-order meet, made explicit so `bind_sources` verifies the wiring↔supply role match by name rather than by a maintained canonical-order convention. Because the current single-binding CLI derives both the `SourceSpec` roles (via `wrap_r`) and the supply roles (via `key_supply`) from the same `binding.entries()`, the bind cannot fail on this path — so the call site asserts the invariant with `.expect`, matching the adjacent `close_handle.expect("ResolvedBinding guarantees a close entry")` idiom. The named `SourceBindError` refusal path lives in `bind_sources` for future decoupled-supply callers (independently-built multi-feed / recorded sources, #124), where a mismatch becomes reachable. Ledger: a C4 realization note (supply resolved by name into declaration order, so supply order is no longer load-bearing; the tie-break guarantee is unchanged) and a scoped C23 refinement (a `SourceSpec.role` is load-bearing for source binding; every other flat-graph name stays a non-load-bearing raw-index symbol). The fieldtest-corpus `SourceSpec` sweep (planned Task 5) was reverted: the fieldtest packages already fail to build against the current engine API for reasons unrelated to `SourceSpec` (bootstrap arity, removed `InputSpec`, drifted `Recorder`/`SimBroker`/`RMetrics`, renamed `Scalar` helpers) — pre-existing bit-rot from earlier cycles. A partial `SourceSpec` migration neither revives nor further breaks them, so the scope decision to touch them (premised on their being otherwise-buildable) was withdrawn; reviving the corpus is separate from #275. Verification: `cargo test --workspace` green (0 failed; the real-data OHLC channel e2e exercises the migrated `run_bound` path byte-identically); `cargo build --workspace --all-targets` clean; `cargo clippy --workspace --all-targets -D warnings` clean.
This commit is contained in:
@@ -1084,7 +1084,14 @@ pub(crate) fn persist_campaign_traces(
|
||||
crate::wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, false, geo.pip_size, &binding, cost_leg)
|
||||
.bootstrap_with_cells(&point)
|
||||
.expect("the member's point re-bootstraps (it already ran this realization)");
|
||||
h.run(sources);
|
||||
// The recorded member already ran this realization once (see the
|
||||
// `.expect` immediately above); `sources` are re-opened against the
|
||||
// SAME `binding` this trace re-run resolved, so a `SourceBindError`
|
||||
// here can only be an internal wiring inconsistency, not a fresh
|
||||
// user input mistake. Panic like the sibling bootstrap invariant
|
||||
// instead of a process-exit dressed as a refusal message.
|
||||
h.run_bound(crate::key_supply(&binding, sources))
|
||||
.expect("sources re-opened against `binding` key-match that binding's own roles by construction");
|
||||
// Drain ALL SIX channels (`run_signal_r` leaves req undrained; the
|
||||
// trace path must not): eq/ex/req/net feed the taps, r+cost feed
|
||||
// the metrics.
|
||||
|
||||
Reference in New Issue
Block a user