persist_taps: name-to-tap recorder wiring so campaign presentation can persist traces #201
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Campaign presentation's persist_taps list is deferred LOUDLY in v1 (#198 triage, decided item 6): every shipped Recorder is hand-wired and no name-to-tap mechanism exists, so 'aura campaign run' prints 'persist_taps not yet honored (N tap(s) ignored)' on stderr. This item ships the wiring: a way to address a tap by name in a wrapped harness and persist its trace under the campaign's realization (TraceStore layout to be decided). depends on: cycle-0107 executor (shipped). context: never a silent drop - the F7 lesson.
Fork triage: persist_taps wiring (grounded stance review, 2026-07-04)
Five design lenses (minimalist / web-face consumer / maintainer / skeptic / methodology designer), grounded in the shipped 0107/0108 executor, the TraceStore/C22 disk contract, and #198 decision 6. Four forks are unanimous; the fifth resolves on a 4/5 majority with the dissent recorded. All decided (veto by replying here); none bounces.
Decided (with grounds)
Tap namespace: a closed vocabulary of the wrap-convention's own sinks —
equity,exposure,r_equity,net_r_equity— validated intrinsically besideemit_vocabulary(unanimous). These are exactly the tap names the shipped trace path writes (persist_traces_r's ColumnarTrace names) and the chart/viewer contract already keys on. A vocabulary tap the run's configuration cannot produce (net_r_equityneeds a cost run; the campaign runner wires none today) is skipped with a loud per-run line — the F7 lesson one level down, never a silent drop. Escalation path (methodologist's clause, adopted): a genuinely new observable becomes a new vocabulary entry or an authored sink in the strategy blueprint (C22: the choice of sinks is part of the experiment) — never an open node-path namespace in the campaign document (the RustAst-shaped hole).Member scope: the per-cell NOMINEE only (unanimous). One non-reduce re-run per cell after the pipeline settles — bounded (one full-trace run per cell), bit-identical under C1 (the shipped reproduce precedent), sequential and outside the engine sweep's parallel region. The nominee recipe already exists first-class (
CellOutcome.nominee). A gate-truncated cell persists nothing, with a loud per-cell line. Skeptic's guard adopted: the re-run's report is equality-asserted against the recorded nominee report (a drift alarm, not a silent divergence). Every-member persistence re-imports the O(cycles) cost reduce-mode exists to kill; a scope knob is vocabulary before any consumer asked.Layout: the existing TraceStore verbatim, family-shaped (unanimous) —
traces/<campaign8>-<run>/<cell-key>/<tap>.json,ensure_name_free(WriteKind::Family)per campaign run, the run counter the SAME one the CampaignRunRecord carries, cell keys content-derived filesystem-portable components (the member_key discipline, never a runtime ordinal). Inlining traces intocampaign_runs.jsonlis refused outright (traces are O(cycles); the record is thin by design). The web face's read-from-disk contract (chart / the C22 trace explorer readtraces/<name>/<member>today) is served unchanged.Wiring home: consumer-side, after
execute()returns (unanimous).aura-campaignstays byte-untouched and trace-agnostic; theMemberRunnerseam stays one-method. The CLI walksoutcome.cells, re-runs each nominee once through its own non-reduce machinery (the shippedrun_signal_r-style channel drain over the wrap convention), and persists via the TraceStore — replacing the loud-deferral eprintln at exactly today's site. A separate post-run verb would relocate the intent-drop #201 exists to close.Record: ONE sparse pointer —
CampaignRunRecord.trace_name: Option<String>(4/5 majority). The TraceStore family name (<campaign8>-<run>), serde-default,Nonewhen nothing persisted; tap names and cell keys are NOT duplicated into the record (the store's ownindex.jsoncarries manifest + tap order;read_family/name_kindenumerate the rest). Grounds: the 0108-F10 lesson is that reader-side convention knowledge is exactly the trap — one navigable pointer beats a derivation rule; per-cell fields and tap lists would be a second source of truth that drifts. [Dissent recorded: the minimalist held the name is a pure function of fields the record already carries and nothing should be stored; overruled by the navigability ground, veto rides here.]Consequence noted: the intrinsic tier gains
UnknownTapvalidation overpersist_taps— a document naming an unknown tap refuses at validate from this cycle on (no content-id movement; validation only).Status: decisions 1–5 settle #201's design; ready for spec production.