fix(aura-cli, docs): fieldtest bugs — the non-literal override prose + the guide's family-id shape
- parse_override_tokens distinguishes the grammar fault (no '=' / no
dotted path — prose unchanged) from a shape-valid token whose VALUE
fails the scalar-literal parse: the refusal now names the value and
the literal requirement (styled after the kind-mismatch sibling)
instead of falsely claiming a NODE.PARAM=VALUE violation. RED-first;
exit stays 2 on both branches.
- the authoring guide's multi-regime family ids corrected to the
executor's real shape (infix -r{k} after the window segment, -r0
explicit on the default regime), and §1's name-op paragraph no
longer claims naming dissolves same-name trace overwriting (that
trace-dir question is tracked on #311, not resolved here).
This commit is contained in:
@@ -646,12 +646,25 @@ fn parse_override_tokens(tokens: &[String]) -> Vec<(String, Scalar)> {
|
||||
eprintln!("aura: exec: --override expects NODE.PARAM=VALUE, got `{tok}`");
|
||||
std::process::exit(2);
|
||||
}
|
||||
// B2 (2026-07-26 harvest fieldtest): `path=val_s` already satisfies the
|
||||
// NODE.PARAM=VALUE grammar (the two checks above passed) — a value
|
||||
// that fails BOTH scalar parses is a literal fault, not a shape
|
||||
// fault, and must not be misreported as one. Styled after the
|
||||
// compile-boundary kind-mismatch sibling
|
||||
// (`aura_runner::member::compile_error_prose`): name the offending
|
||||
// value and what this lexer accepts (its own vocabulary is
|
||||
// int-then-float, #319 Task 3/4 — no bool/timestamp override
|
||||
// literal exists here).
|
||||
let val = match val_s.trim().parse::<i64>() {
|
||||
Ok(i) => Scalar::i64(i),
|
||||
Err(_) => match val_s.trim().parse::<f64>() {
|
||||
Ok(f) => Scalar::f64(f),
|
||||
Err(_) => {
|
||||
eprintln!("aura: exec: --override expects NODE.PARAM=VALUE, got `{tok}`");
|
||||
eprintln!(
|
||||
"aura: exec: --override {path}: expects a scalar literal, got `{}` — \
|
||||
write a bare integer (e.g. 2) or a decimal (e.g. 2.0)",
|
||||
val_s.trim()
|
||||
);
|
||||
std::process::exit(2);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -667,6 +667,25 @@ fn exec_override_malformed_token_refuses_with_usage() {
|
||||
assert!(out.contains("NODE.PARAM=VALUE"), "stdout/stderr: {out}");
|
||||
}
|
||||
|
||||
/// B2 (2026-07-26 harvest fieldtest): `fast.length=abc` IS in the
|
||||
/// `NODE.PARAM=VALUE` grammar — a dotted path, an `=`, a value — so the
|
||||
/// grammar is not what is wrong here; `abc` simply is not a scalar literal.
|
||||
/// `parse_override_tokens` must not misreport this as a shape violation
|
||||
/// (the same "expects NODE.PARAM=VALUE" prose a token missing `=` gets);
|
||||
/// it must name the offending value and that a scalar literal is required,
|
||||
/// styled after the kind-mismatch sibling
|
||||
/// (`exec_override_kind_mismatch_refuses_with_prose_not_the_debug_struct`).
|
||||
#[test]
|
||||
fn exec_override_non_literal_value_names_the_value_not_a_grammar_fault() {
|
||||
let (out, code) = run_code(&["exec", "examples/r_sma.json", "--override", "fast.length=abc"]);
|
||||
assert_eq!(code, Some(2), "stdout/stderr: {out}");
|
||||
assert!(out.contains("abc"), "the offending value must be named: {out}");
|
||||
assert!(
|
||||
!out.contains("NODE.PARAM=VALUE"),
|
||||
"must not misreport a non-literal value as a NODE.PARAM=VALUE shape violation: {out}"
|
||||
);
|
||||
}
|
||||
|
||||
/// An override path naming no param of the blueprint (open or bound) refuses
|
||||
/// with `override_paths`' own prose (`member.rs:768-771`), pointing at the
|
||||
/// live axis-discovery verb (`aura graph introspect --params`) — the retired
|
||||
|
||||
+19
-10
@@ -248,10 +248,17 @@ are dotted `<identifier>.<port>` on both sides of a wire.
|
||||
Omitting `name` is fine for a single strategy, but it has three live
|
||||
consequences once a project has more than one: every unnamed store document
|
||||
is indistinguishable by name (`"graph"` again), every unnamed strategy's
|
||||
default tap recording lands in the same shared `traces/graph/` directory
|
||||
(later runs overwrite earlier ones), and two `use`-splices of unnamed
|
||||
blueprints collide on the same default instance identifier (`graph`) inside
|
||||
the same composing script. A one-line `name` op dissolves all three at once.
|
||||
default tap recording lands in the same shared `traces/graph/` directory (a
|
||||
second unnamed strategy's run overwrites the first's), and two `use`-splices
|
||||
of unnamed blueprints collide on the same default instance identifier
|
||||
(`graph`) inside the same composing script. A one-line `name` op dissolves
|
||||
the first and third of these — giving each blueprint its own distinct name
|
||||
stops *different* blueprints from colliding with each other. It does NOT by
|
||||
itself dissolve the second: two runs of the *identical*, now uniquely-named
|
||||
blueprint still share one `traces/<name>/` directory, so a later run still
|
||||
overwrites an earlier one's trace — naming separates blueprints from each
|
||||
other, not a blueprint's own repeated runs from each other (that trace-dir
|
||||
question is tracked separately, not resolved here).
|
||||
|
||||
Value forms are the typed-tag representations used everywhere in this
|
||||
family of artifacts:
|
||||
@@ -797,8 +804,8 @@ campaign document valid (executable): pipeline shape and static guards pass
|
||||
$ aura campaign register mra_3_campaign_full_v2.json
|
||||
registered campaign 42edebd2159de708009ba21e1ed4aea2cffabc373bf761c5765f79c190b677bd (…/runs/campaigns/42ed…json)
|
||||
$ aura exec 42edebd2159de708009ba21e1ed4aea2cffabc373bf761c5765f79c190b677bd
|
||||
{"family_id":"42edebd2-0-GER40-w0-s0-0","report":{...}}
|
||||
{"family_id":"42edebd2-0-GER40-w0-s0-0-r1","report":{...}}
|
||||
{"family_id":"42edebd2-0-GER40-w0-r0-s0-0","report":{...}}
|
||||
{"family_id":"42edebd2-0-GER40-w0-r1-s0-0","report":{...}}
|
||||
…
|
||||
{"campaign_run":{"campaign":"42edebd2…","process":"cd9127…","run":0,"seed":42,
|
||||
"cells":[{"strategy":"597d719b…","instrument":"GER40","window_ms":[...],
|
||||
@@ -817,10 +824,12 @@ $ aura exec 42edebd2159de708009ba21e1ed4aea2cffabc373bf761c5765f79c190b677bd
|
||||
```
|
||||
|
||||
With two stop regimes every (instrument, window) cell runs twice — the four
|
||||
cells above are the "4 cell(s)" the validate summary counted. The second
|
||||
regime's family ids and trace dirs carry the `-r1` ordinal suffix (the
|
||||
default/first regime stays unsuffixed), each cell record names its regime,
|
||||
and generalization is keyed per regime — regimes are compared, never pooled.
|
||||
cells above are the "4 cell(s)" the validate summary counted. The regime
|
||||
ordinal is an INFIX segment, `-r{k}`, right after the window segment
|
||||
(`{id8}-{ordinal}-{instrument}-w{k}-r{k}-s{seed}-{member}`) — the
|
||||
default/first regime carries `-r0` explicitly, never left unmarked — each
|
||||
cell record names its regime, and generalization is keyed per regime —
|
||||
regimes are compared, never pooled.
|
||||
|
||||
`aura exec` (#319) is register-then-run sugar for a `.json` file, but the
|
||||
canonical address is always the content id — running a bare file the first
|
||||
|
||||
Reference in New Issue
Block a user