refactor(std): std_vocabulary_roster! macro — one source for the vocabulary roster

The three hand-kept copies of the 22-key zero-arg roster in
aura-std/vocabulary.rs (std_vocabulary match arms, std_vocabulary_types
list, the test's inline array) collapse into one private declarative
macro invoked once with the "TypeId" => Type pairs — the resolver and
the enumerable list now agree by construction (the #160 failure mode:
a node resolvable but silently absent from graph introspect
--vocabulary, or vice versa). Byte-preserving: same fn signatures, same
22 ids, same order; lib.rs re-export and every consumer untouched; the
vocabulary stays a closed compiled-in set (invariant 9 / C24 — a
compile-time expansion, no registry). Adding a zero-arg node is now one
roster line plus the conscious count-pin bumps.

Tests: the two unit tests reshaped (round-trip iterates the generated
list with PrimitiveBuilder::label() as the independent oracle; the shape
test keeps the count pin as deliberate friction). The E2E phase added
one cross-boundary pin beyond the plan — kept:
graph_introspect_vocabulary_lists_exactly_the_closed_roster_count checks
the same count through Env::type_ids() and the CLI print loop across the
real process boundary, which no roster-internal test can see.

Accepted residual (documented at the roster site, recorded on #160):
a new zero-arg node never rostered at all stays unguarded — no
enumeration of zero-arg builders exists — and fails safe in both
directions (clean UnknownNodeType on load; merely absent from
--vocabulary).

Verification: cargo build clean; cargo test --workspace 885 passed /
0 failed (884 baseline + 1 new e2e); clippy --all-targets -D warnings
clean; cargo doc --no-deps 0 warnings.

closes #160, refs #180
This commit is contained in:
2026-07-02 21:56:07 +02:00
parent e0c745a9b0
commit 57f401f2ab
2 changed files with 93 additions and 94 deletions
+22
View File
@@ -104,6 +104,28 @@ fn graph_introspect_vocabulary_lists_the_node_types() {
assert!(!stdout.contains("Recorder"), "a sink is not in the zero-arg vocabulary: {stdout}");
}
/// The #160 roster macro's whole point is that `std_vocabulary`'s match arms and
/// `std_vocabulary_types`'s enumerable list can never drift apart — but that
/// guarantee is checked in-process, inside `aura-std`'s own unit tests. This pins
/// the SAME closed-roster count one layer further out, through a code path the
/// roster macro cannot see: `Env::type_ids()` (project std concatenation) and
/// the CLI's println loop, observed across the real process boundary. A bug in
/// that CLI-side plumbing (a dropped or duplicated entry in the concatenation or
/// the print loop) would pass every roster-internal test yet still change what a
/// user actually sees from `aura graph introspect --vocabulary` with no project
/// loaded — this test is the only thing that would catch it.
#[test]
fn graph_introspect_vocabulary_lists_exactly_the_closed_roster_count() {
let (stdout, _stderr, ok) = run(&["graph", "introspect", "--vocabulary"], "");
assert!(ok, "exit success");
let lines: Vec<&str> = stdout.lines().filter(|l| !l.is_empty()).collect();
assert_eq!(
lines.len(),
22,
"the std-only (no project) vocabulary has exactly the roster's 22 entries: {stdout}"
);
}
#[test]
fn graph_introspect_node_answers_ports_without_a_build() {
let (stdout, _stderr, ok) = run(&["graph", "introspect", "--node", "SMA"], "");