feat(aura-cli, aura-runner): exec routing-seam refusals + by-name unbound-role prose

Harvest sweep, batch 2 of 6.

- exec's file-target classification is now a four-way shape peek
  (campaign / blueprint / op-script / wrong-kind): a valid-JSON op-script
  array refuses at the routing seam with a build-first pointer ('aura
  graph build') instead of the blueprint leg's false 'not valid JSON'
  claim, and a kind-bearing non-campaign document names the found kind
  plus exec's two executable classes. Exit-code classes unchanged
  (op-script usage-class 2, wrong-kind runtime-class 1).
- the bare-tap measurement leg renders CompileError::UnboundRootRole by
  the signal's own root-role NAME (captured pre-consumption), retiring
  the raw Debug-form leak; every other variant keeps the total fallback.

refs #342
refs #339
This commit is contained in:
2026-07-26 11:47:21 +02:00
parent 6b6086fdef
commit 521459dd50
4 changed files with 186 additions and 39 deletions
+45
View File
@@ -258,6 +258,51 @@ fn exec_malformed_json_file_refuses_neutrally_not_misrouted() {
);
}
/// #342 item 3: a valid-JSON op-script (a top-level JSON array of
/// construction ops) handed to `exec` must not fall through to the
/// blueprint leg's "blueprint document is not valid JSON" refusal — that
/// claim is false, the document IS valid JSON, just the wrong shape. It
/// refuses right at the routing seam with prose that names the op-script
/// diagnosis and points at the build step that turns it into a runnable
/// blueprint (`aura graph build`).
#[test]
fn exec_op_script_file_refuses_with_build_hint_not_invalid_json() {
let dir = temp_cwd("exec-op-script");
let op_script = r#"[
{"op":"source","role":"price","kind":"F64"},
{"op":"add","type":"SMA","name":"fast","bind":{"length":{"I64":2}}},
{"op":"feed","role":"price","into":["fast.series"]},
{"op":"expose","from":"fast.value","as":"bias"}
]"#;
write_doc(&dir, "script.json", op_script);
let (out, code) = run_code_in(&dir, &["exec", "script.json"]);
assert_eq!(code, Some(2), "stdout/stderr: {out}");
assert!(out.contains("op-script"), "must name the op-script diagnosis: {out}");
assert!(out.contains("graph build"), "must point at the build step: {out}");
assert!(
!out.contains("not valid JSON"),
"the document IS valid JSON — must not claim otherwise: {out}"
);
}
/// #342 item 4: a kind-bearing document that is not a campaign (here, a
/// process document) refuses naming the found kind and exec's two
/// executable classes, instead of the campaign leg's generic "the \"kind\"
/// key must be \"campaign\"" — which never says WHAT was found, nor what
/// exec accepts at all.
#[test]
fn exec_process_document_names_found_kind_and_executable_classes() {
let dir = temp_cwd("exec-wrong-kind-process");
write_doc(&dir, "p.process.json", SWEEP_ONLY_PROCESS_DOC);
let (out, code) = run_code_in(&dir, &["exec", "p.process.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(out.contains("\"process\""), "must name the found kind: {out}");
assert!(
out.contains("campaign document") && out.contains("fully-bound blueprint"),
"must name both of exec's executable classes: {out}"
);
}
// ---------------------------------------------------------------------------
// Task 2: the exec blueprint leg (synthetic single run).
// ---------------------------------------------------------------------------