RUE-506: ADR-0081 — rue test MVP (test declarations, runner, event protocol) - #2566
Conversation
Narrowed successor to the full agent-first test-runner proposal (rue-language#2239), scoped per review consensus to test declarations, the rue test driver mode and versioned NDJSON event stream, process-per-test execution under pinned inventories, the structured failure channel, and structured assertion payloads. Capability inference, verdict caching/selection, scheduling, and the provider protocol are deferred to follow-up ADRs (RUE-1621..1624), with the schema fields and contracts they need reserved here so each lands additively. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPBpmZU3DpwkumLHNwHsgu
Nine findings from an adversarial pass over the distillation, all remnants of the pre-narrowing scope: the RUE-1623 deferral bullet now names which two of its four items require capability inference (the seedable @random_* call is attached separately, and §4's pointer agrees with §6 on where that call lives); per-test compile_error verdicts are no longer falsely gated on capability inference; the shuffle bullet and the Go/Bazel prior-art bullets no longer claim present-tense verified hermeticity the MVP disclaims; Phase 2's bold note yields "the MVP" to the document title (Phases 1-2.5); the unproducible `ice` failure kind is reserved on the same grounds as compile_error/cached_pass; the dangling HyRTS citation is dropped; ADR-0038 and ADR-0005 join relates; undefined --keep-going leaves the synopsis. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPBpmZU3DpwkumLHNwHsgu
|
Pushed The four that mattered:
Smaller: the Go/Bazel prior-art bullets no longer assert "Rue verifies/enforces" in present tense; Phase 2's bold note becomes "the minimum usable runner" so "the MVP" consistently means Phases 1–2.5 as the title and Summary use it; Registry and doc-link gates still pass (82 records). |
…dary Rewrite per maintainer notes, 1259 -> 846 lines: - The process history is cut to two sentences in Status; the document no longer depends on PR rue-language#2239 context to read. Context shrinks to the facts the design is built on plus one-lesson-each prior art. - The user experience is shown, not described: worked CLI invocations with illustrative human and NDJSON output in section 2, the test-body example retained, and the import-wiring idiom shown as code in section 1 with its tradeoff stated plainly. - A new top-level section pins the compiler-CLI vs build-integration boundary: everything in the ADR is the compiler's; build integration supplies exactly one optional input (--test-candidates). - File discovery becomes an explicit maintainer call: import-closure-only with the orphan warning (as drafted) vs a closure-anchored naming convention that auto-roots conventional test files, with costs and the compile_error containment dependency stated. Phase 2 gates on resolving it; the package-model end state is recorded under deferred questions. - Explanatory prose compressed throughout; every contract value, reserved schema surface, and adversarial-review fix from 345daad is preserved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPBpmZU3DpwkumLHNwHsgu
|
Pushed
Every contract value, reserved schema surface, and adversarial-review fix from |
Ruling: rue test does not implicitly enable test_declarations. The gate covers a parser change, so any request whose closure contains test items — executable builds included — needs the flag to compile at all; test-mode auto-enable would leave those builds failing while bypassing ADR-0005's explicit opt-in for no net convenience. Open Questions reorganized: a front group of three rulings needed before acceptance (declaration surface, file discovery mechanism, --filter root-vs-run semantics), and a second group of lower-impact decisions resolvable within their phase (failure channel mechanism, @Assert stabilization, exit codes, skipped verdict, homonym, naming). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPBpmZU3DpwkumLHNwHsgu
|
Pushed Ruled: no implicit preview enable. Open Questions now splits into two groups. "Needs a ruling before acceptance": the test declaration surface, the file discovery mechanism, and |
steveklabnik
left a comment
There was a problem hiding this comment.
Codex review, requested by Steve.
The overall MVP boundary is much clearer after the editorial pass, and I recommend resolving the three acceptance-level questions as follows: keep the test "name" { ... } surface; use import-closure discovery for the MVP (with the optional declared candidate inventory warning) rather than adding directory contents as compiler inputs; and have --filter narrow the run set, not the analysis root set. The dedicated inherited failure pipe is also the right Phase 2 mechanism.
I found two correctness/sequencing gaps that should be resolved in the ADR:
-
Phase 1 says test-body ? becomes legal and test bodies semantically analyze, while the failure-arm lowering is deferred to Phase 2. Current semantic analysis does not have a separable legality-only step: analyze_try immediately builds the Option/Result match and early-return AIR against the enclosing return type. A ()-typed test body therefore cannot analyze successfully until the test-specific failure arm exists. Move legality and lowering together into Phase 2, or specify a real Phase 1 lowering that makes the claimed emit-level analysis possible.
-
The accepted std.exit(0) blind spot makes a test that exits before its assertions report as a pass. With one process per test and the dedicated parent-child channel already in the MVP, require a terminal completion record that only the dispatcher writes after the test body returns normally. Exit 0/EOF without that record should be a runner failure. This is false-positive test evidence, so it should not be deferred as optional hygiene.
The ADR-registry and documentation-link gates pass at this head.
— Codex
Rulings (2026-08-23, on review): test "name" blocks stand; discovery is import-closure-only for the MVP (the convention alternative moves to Rejected alternatives, with the package-model revisit recorded); --filter narrows the run set, never the root set; the failure channel is the dedicated inherited pipe. Open Questions' front group becomes the ruling record; the channel entry leaves the lower-impact list. Gap 1: analyze_try builds the Option/Result match and early return against the enclosing return type as it analyzes — there is no legality-only step — so the test-body ? rule ships whole in Phase 2, and Phase 1 keeps today's compile error. Stated in section 1 and both phase items. Gap 2: std.exit(0) before assertions must not pass. The dispatcher writes a terminal completion record on the failure channel after the body returns normally; exit 0 with end-of-stream and no record is a failure with new kind `incomplete`. The pass definition, event sketch, execution contract, and Phase 2 all carry it; the channel's forgeability caveat is stated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPBpmZU3DpwkumLHNwHsgu
|
Both gaps resolved and all four rulings recorded, as Gap 1 — the Phase 1/2 Gap 2 — the Rulings recorded: Registry and doc-link gates pass at this head. |
Refs RUE-506. Successor to #2239, scoped down per the review consensus there: this is the MVP ADR, and only the MVP ADR. The document stands alone — the process history is two sentences in Status, and reading #2239 is not required.
What the MVP commits to
test "name" { ... }blocks (contextual keyword, preview-gated astest_declarations), placement-is-visibility, tests rooted only by test requests.?in test bodies gets unwrap-and-report semantics with the skipped-destructor consequence accepted explicitly.rue testas the driver's first subcommand, with worked CLI examples in the text: NDJSON event stream v1.0, byte-safe bounded capture, asymmetric verbosity, stable IDs, repro argv on every failure, andcapability_summarypresent from v1.0 with an explicitunavailablestatus.--test-candidatesfor the orphan warning).The open discovery question
File discovery is a first-class maintainer call, to be taken before Phase 2: import-closure-only with the orphan warning, vs a closure-anchored naming convention that auto-roots conventional test files (a bounded compiler demand over directories the closure occupies — not a directory walk). The import-wiring papercut, its Zig history, and the convention's costs (spec-pinned name, directory contents as request inputs, whole-run blast radius until per-test
compile_errorlands) are stated in §1 and Open Questions.What this defers, and where it went
Capability inference, hermetic verdict caching/selection, scheduling/flake policy, and the public provider protocol are deferred to focused follow-up ADRs — deferred, not rejected. §6 records what the MVP does now so each lands additively.
The full design capture stays on #2239 (closed unmerged, five review rounds). Follow-up issues seeded with the extracted sections: RUE-1621 (capability inference), RUE-1622 (verdict caching, blocked by 1621), RUE-1623 (scheduling, partially blocked by 1621), RUE-1624 (provider protocol) — Linear project "rue test follow-ups". MVP phases are RUE-1618/1619/1620 in project "rue test MVP".
Registry and doc-link gates pass (82 records).
🤖 Generated with Claude Code
https://claude.ai/code/session_01NPBpmZU3DpwkumLHNwHsgu