fix(aura-cli): sweep --list-axes joins the gated intake class
Fieldtest finding B1: the one remaining authored-envelope FILE route, sweep --list-axes, skipped the root-name gate — a hand-edited "name":"../escape" listed mangled, non-bindable wrapped axis names at exit 0 while every sibling intake refused. The discovery surface now gates before any axis line prints (exit 1, shared prose), restoring both the #331 every-authored-intake claim and #328's discovery-surface identity. RED-first: the e2e refusal test was written and observed failing (exit 0, axis lines printed) before the fix. Re-enumeration of every read_to_string-fed envelope load confirms the class is now closed; C24 additionally ratifies the fieldtest's SG1 — the refusal core sentence is byte-uniform across sites while the leading context prefix varies by site convention. refs #331, #328
This commit is contained in:
@@ -913,6 +913,12 @@ pub(crate) fn composite_from_any(text: &str, env: &aura_runner::project::Env) ->
|
|||||||
/// reason, on the routes that bypass `validate_and_register_axes`
|
/// reason, on the routes that bypass `validate_and_register_axes`
|
||||||
/// entirely (#331 cycle-close — these used to plant an ungated envelope
|
/// entirely (#331 cycle-close — these used to plant an ungated envelope
|
||||||
/// in the store; see each fn's own comment).
|
/// in the store; see each fn's own comment).
|
||||||
|
/// - `list_blueprint_axes` (`aura sweep <FILE> --list-axes`, main.rs): no
|
||||||
|
/// registry write and no trace directory here, but a shape-violating root
|
||||||
|
/// name otherwise mangles through `wrapped_to_raw_axis` into a printed,
|
||||||
|
/// non-bindable axis name instead of refusing (#331 fieldtest finding
|
||||||
|
/// c331_2e) — the class rule is every CLI intake reading an authored
|
||||||
|
/// envelope from a file gates the root name, not only the writing ones.
|
||||||
///
|
///
|
||||||
/// All of these share the identical `name_gate` + `name_gate_fault_prose`
|
/// All of these share the identical `name_gate` + `name_gate_fault_prose`
|
||||||
/// primitives this wrapper uses, so the refusal wording is byte-identical
|
/// primitives this wrapper uses, so the refusal wording is byte-identical
|
||||||
|
|||||||
@@ -815,15 +815,29 @@ impl IcReport {
|
|||||||
/// alongside it, so the discovery surface must list it regardless too. Names
|
/// alongside it, so the discovery surface must list it regardless too. Names
|
||||||
/// are RAW `<node>.<param>` paths (#328: the wrapped `<blueprint>.<node>.<param>`
|
/// are RAW `<node>.<param>` paths (#328: the wrapped `<blueprint>.<node>.<param>`
|
||||||
/// form is retired from the surface) — exactly what `--axis` binds.
|
/// form is retired from the surface) — exactly what `--axis` binds.
|
||||||
|
///
|
||||||
|
/// **Gated (#331 fieldtest finding).** This is a FRESH-FILE intake exactly like
|
||||||
|
/// `register` / `introspect --content-id <FILE>` / `introspect --params <FILE>`
|
||||||
|
/// (`composite_from_authored_text`'s doc comment lists the class): a hand-edited
|
||||||
|
/// envelope with a shape-violating root name (`"../x"`) must be refused before
|
||||||
|
/// any axis line prints, not mangled through `wrapped_to_raw_axis` into a
|
||||||
|
/// non-bindable name. Gated immediately after load, before any axis derivation
|
||||||
|
/// — same placement discipline as the other sites — at exit 1, matching the
|
||||||
|
/// register-route convention (this route never `put_blueprint`s anything,
|
||||||
|
/// unlike the exit-2 sweep-EXECUTION route `run_blueprint_sweep` gates).
|
||||||
fn list_blueprint_axes(doc: &str, env: &aura_runner::project::Env) {
|
fn list_blueprint_axes(doc: &str, env: &aura_runner::project::Env) {
|
||||||
|
let signal = blueprint_from_json(doc, &|t| env.resolve(t))
|
||||||
|
.expect("doc parse-validated at the dispatch boundary");
|
||||||
|
if let Err(msg) = graph_construct::gate_authored_root_name(signal.name()) {
|
||||||
|
eprintln!("aura: {msg}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
let space = blueprint_axis_probe(doc, env).param_space();
|
let space = blueprint_axis_probe(doc, env).param_space();
|
||||||
for p in &space {
|
for p in &space {
|
||||||
// Strip the wrapper's one leading node segment (#328): open names print
|
// Strip the wrapper's one leading node segment (#328): open names print
|
||||||
// RAW, matching `--axis`'s own accepted namespace.
|
// RAW, matching `--axis`'s own accepted namespace.
|
||||||
println!("{}:{:?}", aura_runner::axes::wrapped_to_raw_axis(&p.name), p.kind); // ScalarKind Debug -> I64/F64/Bool/Timestamp
|
println!("{}:{:?}", aura_runner::axes::wrapped_to_raw_axis(&p.name), p.kind); // ScalarKind Debug -> I64/F64/Bool/Timestamp
|
||||||
}
|
}
|
||||||
let signal = blueprint_from_json(doc, &|t| env.resolve(t))
|
|
||||||
.expect("doc parse-validated at the dispatch boundary");
|
|
||||||
for b in signal.bound_param_space() {
|
for b in signal.bound_param_space() {
|
||||||
// `bound_param_space()`'s `.name` is already RAW (#203) — no blueprint-name
|
// `bound_param_space()`'s `.name` is already RAW (#203) — no blueprint-name
|
||||||
// concatenation (#328: the blueprint name stays out of axis paths, C23).
|
// concatenation (#328: the blueprint name stays out of axis paths, C23).
|
||||||
|
|||||||
@@ -5510,6 +5510,48 @@ fn aura_sweep_list_axes_rejects_malformed_blueprint() {
|
|||||||
assert!(!stderr.contains("panicked"), "must reject cleanly, not panic: {stderr}");
|
assert!(!stderr.contains("panicked"), "must reject cleanly, not panic: {stderr}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Property (#331 fieldtest finding, cycle-331-blueprint-name c331_2e): `--list-axes`
|
||||||
|
/// is a FRESH-FILE intake exactly like `register` / `introspect --content-id` /
|
||||||
|
/// `introspect --params`, but its own root-name gate was missing — a hand-edited
|
||||||
|
/// envelope with a shape-violating root name (`"../x"`) printed mangled,
|
||||||
|
/// non-bindable axis names instead of being refused. The route now shares
|
||||||
|
/// `gate_authored_root_name` + `name_gate_fault_prose` and exits 1 — the
|
||||||
|
/// register-route convention (this route never `put_blueprint`s anything, unlike
|
||||||
|
/// the exit-2 sweep-EXECUTION route pinned by
|
||||||
|
/// `aura_sweep_synthetic_blueprint_refuses_a_hand_crafted_envelope_with_a_bad_root_name`)
|
||||||
|
/// — printing no axis line at all.
|
||||||
|
#[test]
|
||||||
|
fn aura_sweep_list_axes_refuses_a_hand_crafted_envelope_with_a_bad_root_name() {
|
||||||
|
let dir = temp_cwd("sweep_list_axes_bad_root_name_refusal");
|
||||||
|
let fixture_text =
|
||||||
|
std::fs::read_to_string(format!("{}/tests/fixtures/r_sma_open.json", env!("CARGO_MANIFEST_DIR")))
|
||||||
|
.expect("read r_sma_open.json fixture");
|
||||||
|
let bad = fixture_text.replacen("\"name\":\"sma_signal\"", "\"name\":\"../x\"", 1);
|
||||||
|
assert!(bad.contains("\"name\":\"../x\""), "the root-name replace landed: {bad}");
|
||||||
|
let file = dir.join("bad-root-name.json");
|
||||||
|
std::fs::write(&file, &bad).expect("write envelope fixture");
|
||||||
|
|
||||||
|
let out = Command::new(BIN)
|
||||||
|
.args(["sweep", file.to_str().unwrap(), "--list-axes"])
|
||||||
|
.current_dir(&dir)
|
||||||
|
.output()
|
||||||
|
.expect("spawn aura sweep --list-axes (bad root name)");
|
||||||
|
assert_eq!(
|
||||||
|
out.status.code(),
|
||||||
|
Some(1),
|
||||||
|
"a shape-violating root name must be refused (register-route convention), not listed: status={:?} stderr={}",
|
||||||
|
out.status,
|
||||||
|
String::from_utf8_lossy(&out.stderr)
|
||||||
|
);
|
||||||
|
let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
|
||||||
|
assert!(
|
||||||
|
stderr.contains("blueprint name \"../x\" is invalid") && stderr.contains("must not contain '/' or '\\'"),
|
||||||
|
"names the offending root name with the shared gate prose: {stderr}"
|
||||||
|
);
|
||||||
|
assert!(out.stdout.is_empty(), "a refused root name must print no axis line: {out:?}");
|
||||||
|
let _ = std::fs::remove_dir_all(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
/// E2E (#210 c0110 fieldtest, "aura sweep <op-script> rejects the op-script
|
/// E2E (#210 c0110 fieldtest, "aura sweep <op-script> rejects the op-script
|
||||||
/// array with a raw serde error"): `aura sweep`'s blueprint slot accepts only
|
/// array with a raw serde error"): `aura sweep`'s blueprint slot accepts only
|
||||||
/// the built blueprint envelope; an un-built op-script (a JSON array) is
|
/// the built blueprint envelope; an un-built op-script (a JSON array) is
|
||||||
|
|||||||
@@ -205,11 +205,16 @@ replayed in order; nodes are referenced **by identifier**, ports as dotted
|
|||||||
`..`) applied at this op intake **plus every CLI intake that reads an
|
`..`) applied at this op intake **plus every CLI intake that reads an
|
||||||
authored blueprint envelope from a file** — `register`, `introspect
|
authored blueprint envelope from a file** — `register`, `introspect
|
||||||
--content-id <FILE>`, the bare graph-file viewer, `run`, `introspect
|
--content-id <FILE>`, the bare graph-file viewer, `run`, `introspect
|
||||||
--params <FILE>`, and each of `sweep`/`walkforward`/`mc`/`generalize`'s
|
--params <FILE>`, `sweep --list-axes`, and each of
|
||||||
file-reading entry points (synthetic and `--real` alike) — one class of
|
`sweep`/`walkforward`/`mc`/`generalize`'s file-reading entry points
|
||||||
intake, one gate. Store read-back (`reproduce`, `use` resolution,
|
(synthetic and `--real` alike) — one class of intake, one gate. The
|
||||||
`introspect`/`--params` by content id) stays deliberately ungated — C29: a
|
refusal's core sentence (`name_gate_fault_prose`) is byte-uniform across
|
||||||
registered artifact is never retroactively invalidated.
|
every one of these sites; only the leading context prefix varies —
|
||||||
|
`run` and the bare graph-file viewer prepend `aura: <path>:`, while
|
||||||
|
`register`, the sweep-axis family (`validate_and_register_axes`), and
|
||||||
|
`introspect` prepend bare `aura: `. Store read-back (`reproduce`, `use`
|
||||||
|
resolution, `introspect`/`--params` by content id) stays deliberately
|
||||||
|
ungated — C29: a registered artifact is never retroactively invalidated.
|
||||||
- `source` — `{"op":"source","role":<str>,"kind":<ScalarKind>}` — declare a root
|
- `source` — `{"op":"source","role":<str>,"kind":<ScalarKind>}` — declare a root
|
||||||
source role producing a base column of `kind`.
|
source role producing a base column of `kind`.
|
||||||
- `input` — `{"op":"input","role":<str>}` — declare a root input role (kind inferred
|
- `input` — `{"op":"input","role":<str>}` — declare a root input role (kind inferred
|
||||||
|
|||||||
Reference in New Issue
Block a user