audit: trace-handle cycle close — refusal parity, measurement pin, ledger lockstep
Architect review over 9636b00..9221bcd. What holds, confirmed against the diff rather than the commit body: no stored record shape moved (neither `aura-engine/src/report.rs` nor the registry compat mirror appears in the change at all, and the byte pins pass unedited); the handle travels the beside-the-report route C27/#297 established for the unbound-tap names, with the library still printing nothing; trace enumeration landed inside `aura-registry` where C22 puts trace file I/O; no C14 exit class moved, both refusal arms falling through to the same exit 1. Two high drift items, both fixed here: - The corrected refusal claimed a campaign run prints its handle as `trace_name` on stdout. It prints `campaign_run.trace_name` — the campaign leg wraps its record, as the glossary states outright — so the chain the refusal advertised returns null there. This is the third instance of one error class in this cycle: a false claim inside the very prose meant to stop misdirecting callers. Grounding caught the first two, review the third. - The measurement leg shipped without the handle pin the spec asked for. All three new pins drove the strategy path, so the measurement leg emitted a handle nothing asserted. It has its own test now, on the shared bind pair the two legs cannot drift across. Ledger and vocabulary brought into lockstep: C27's current state records the `RunOutcome` carrier that replaced the pair; the glossary's tap entry names the single-run handle and warns that a family id is not one; the authoring guide's own single-run tap example now says the name is printed rather than guessed. The suggestion line gained the `aura:` prefix every other stderr line carries. Bench: all five fingerprints OK — the decisive signal, since they hang on the record bytes this cycle was required not to move. Timing deltas are load noise (loadavg 8.7 under concurrent agents), not regressions. refs #309
This commit is contained in:
@@ -455,16 +455,17 @@ fn render_chart_by_kind(
|
||||
handles.join(", ")
|
||||
);
|
||||
if handles.len() == 1 {
|
||||
eprintln!("Did you mean: aura chart {}", handles[0]);
|
||||
eprintln!("aura: Did you mean: aura chart {}", handles[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
eprintln!(
|
||||
"aura: no recorded run or family '{name}' under runs/traces \
|
||||
(both a single run and a campaign run print their handle as `trace_name` \
|
||||
on stdout — one per run — so check that value for a typo. A trace is \
|
||||
produced by `aura exec --tap <NODE.FIELD>=<FOLD>` on a blueprint \
|
||||
(a single run prints its handle as `trace_name` on stdout; a campaign \
|
||||
run prints it as `campaign_run.trace_name`, one per run — check that \
|
||||
value for a typo. A trace is produced by \
|
||||
`aura exec --tap <NODE.FIELD>=<FOLD>` on a blueprint \
|
||||
or a campaign's `presentation.persist_taps` section, not by naming a handle here)"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,3 +138,31 @@ fn run_refuses_a_hand_crafted_envelope_with_a_bad_root_name_before_any_trace_wri
|
||||
"no trace directory of any shape is written on a refused run"
|
||||
);
|
||||
}
|
||||
|
||||
/// #309: the measurement leg reports its trace handle exactly as the strategy
|
||||
/// leg does — both bind through one shared tap-plan pair, so a handle present
|
||||
/// on one and absent on the other would mean the seam had drifted.
|
||||
#[test]
|
||||
fn measurement_run_reports_its_trace_handle_on_stdout() {
|
||||
let cwd = temp_cwd("measurement-trace-handle");
|
||||
let bp_path = cwd.join("measurement.json");
|
||||
std::fs::write(&bp_path, measurement_blueprint_json()).expect("write measurement blueprint");
|
||||
|
||||
let out = Command::new(BIN)
|
||||
.args(["exec", bp_path.to_str().expect("utf-8 path")])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn exec");
|
||||
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
|
||||
|
||||
let line = String::from_utf8_lossy(&out.stdout);
|
||||
let report: serde_json::Value =
|
||||
serde_json::from_str(line.trim()).expect("stdout is one JSON object");
|
||||
let handle = report["trace_name"].as_str().expect("trace_name is present and a string");
|
||||
assert!(
|
||||
cwd.join("runs/traces").join(handle).join("fast_tap.json").exists(),
|
||||
"the reported handle must name the directory the tapped series landed in; got {handle}"
|
||||
);
|
||||
|
||||
let _ = std::fs::remove_dir_all(&cwd);
|
||||
}
|
||||
|
||||
@@ -334,7 +334,9 @@ The built blueprint carries a `taps` array naming the resolved wire
|
||||
(`{"name":"spread","from":{"node":<sub's index>,"field":0}}` — the name is
|
||||
addressed, the index is resolved *for* you). A single `aura exec <blueprint>`
|
||||
then constructs a recorder at that point and persists the `spread` series as a
|
||||
`ColumnarTrace` in the run's trace store, chartable by its name. A tap is inert
|
||||
`ColumnarTrace` in the run's trace store, chartable by its name — which the
|
||||
run prints for you as `trace_name` on its stdout line, so it need not be
|
||||
guessed. A tap is inert
|
||||
in a campaign member run (no per-cell recorder) — it is a single-run
|
||||
observation surface (or, per campaign, what a nominee's `persist_taps`
|
||||
re-run records, §3).
|
||||
|
||||
@@ -77,7 +77,12 @@ data-reachable: no flag keeps the record-all default, any flag replaces the
|
||||
plan entirely (unlisted taps stay unbound/inert). `BoundTaps` carries the
|
||||
unbound tap names out (`skipped: Vec<String>`), riding beside the returned
|
||||
report rather than inside it, so the CLI — not the library — prints the
|
||||
unbound-tap note (#297). The boundary is thereby
|
||||
unbound-tap note (#297). Since #309 both entry points return that pair as a
|
||||
named `RunOutcome { report, skipped, trace_name }`, the third field being the
|
||||
trace-store handle the run recorded under (`Some` under exactly the condition
|
||||
that opens the write path, `None` otherwise) — the same beside-the-report
|
||||
discipline, widened rather than re-cut: the record keeps its shape and the
|
||||
shell renders the handle. The boundary is thereby
|
||||
fixed in place: *selecting* a subscription is run-mode authority, exercised
|
||||
by the run-mode owner — on the one-shot path the CLI invocation itself, a
|
||||
projection exercising this contract's authority, not a second home for
|
||||
|
||||
+1
-1
@@ -337,7 +337,7 @@ An orchestration axis varying tuning params (grid or random) within a fixed stru
|
||||
|
||||
### tap
|
||||
**Avoid:** probe, monitor, scope (for the observation slot — "probe" is taken by the sweep-terminal `blueprint_axis_probe` sense; the #77 `Recorder`→`Probe` rename was retired, 2026-07-21)
|
||||
A named recorded stream produced by a recording `sink` — the addressable label (e.g. `equity`, `net_r_equity`) under which one sink's per-cycle output is persisted as a columnar (SoA) `ColumnarTrace` and selected for charting via `--tap`. Distinct from the `sink` node that emits it (a tap is the stream, the sink is the role) and from a whole recorded run (a bundle of taps); taps fire at their own cadences and are fused only by joining on the recorded timestamp, never by positional index. In a `campaign document`, `persist_taps` names taps from the CLOSED vocabulary `equity | exposure | r_equity | net_r_equity` (`tap_vocabulary`, 0109/#201) — a new observable is a new vocabulary entry or an authored blueprint sink, never an open node-path namespace. Persisted taps are charted by the printed handle: a campaign run's deterministic `trace_name` (`"{campaign8}-{run}"`, never a user-chosen name since #319) charts its whole family (`aura chart <handle>`; members keyed `<cell>/<member>` in the chart) — or, equivalently, a bare campaign id/name that uniquely resolves against the recorded campaign documents (#238; a name reused across runs refuses rather than guessing).
|
||||
A named recorded stream produced by a recording `sink` — the addressable label (e.g. `equity`, `net_r_equity`) under which one sink's per-cycle output is persisted as a columnar (SoA) `ColumnarTrace` and selected for charting via `--tap`. Distinct from the `sink` node that emits it (a tap is the stream, the sink is the role) and from a whole recorded run (a bundle of taps); taps fire at their own cadences and are fused only by joining on the recorded timestamp, never by positional index. In a `campaign document`, `persist_taps` names taps from the CLOSED vocabulary `equity | exposure | r_equity | net_r_equity` (`tap_vocabulary`, 0109/#201) — a new observable is a new vocabulary entry or an authored blueprint sink, never an open node-path namespace. Persisted taps are charted by the printed handle: a campaign run's deterministic `trace_name` (`"{campaign8}-{run}"`, never a user-chosen name since #319) charts its whole family (`aura chart <handle>`; members keyed `<cell>/<member>` in the chart) — or, equivalently, a bare campaign id/name that uniquely resolves against the recorded campaign documents (#238; a name reused across runs refuses rather than guessing). A single run reports its own handle the same way, as `trace_name` on its stdout line (#309) — the run's render name, absent when the run recorded nothing. NB a `family id` is not a handle: it names one cell/stage record within a run, and cutting it down does not yield the run's handle.
|
||||
|
||||
Since C27 (#282) the word also names a second, author-facing sense: a **declared tap** — a `Composite.taps` entry `Tap { name, from: {node, field} }` a hand-authored blueprint declares on an interior output wire, the output-side twin of an `input_role`. It is a pure declaration (no channel endpoint); the harness binds it run-mode-aware (a single `aura exec` constructs a recorder at each and persists the series through the trace store; a campaign member run leaves it unbound and inert). This is an OPEN, per-blueprint author-declared name — distinct from the CLOSED campaign `persist_taps` vocabulary above, which selects among fixed observables of the standard R-harness. Both senses land as `ColumnarTrace`s in the same trace store; the closed vocabulary is what a `campaign document` selects, the declared tap is what a blueprint author names.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user