# audit-rt — Milestone close: Roundtrip Invariant **Date:** 2026-05-12 **Milestone:** Roundtrip Invariant (rt.1 + rt.2) **Status:** Closed, clean (after rt.tidy fixes) ## Architect drift review `ailang-architect` reported `drift_found` with four items over `daf9f4f..HEAD`: - `[high]` DESIGN.md §"Roundtrip Invariant" Direction 2 (text → JSON → text idempotency) is stated as a property but not directly enforced by any of the four listed tests. Test 1 covers Direction 1; test 2 covers `.ailx` → JSON ≡ counterpart; test 4 covers CLI render → parse. None tests `parse → print → parse` idempotency on a hand-authored `.ailx` text directly. Architect recommendation: claim soften OR add a fifth test. - `[high]` `docs/roadmap.md` P1 entry "Round-trip completeness invariant" still `- [ ]` (open) after the milestone closed. Stale per roadmap convention (finished entries → `[x]` then removal with one-line journal mirror). - `[low]` DESIGN.md wording: `<16-hex>` in new section vs `<16-lowercase-hex>` in §"Data model". Casing constraint is load-bearing for canonical-byte equality; should be stated identically. - `[low]` rt.1 plan errata note (planner emitted ast.rs-mismatching destructure scaffold). Single occurrence absorbed cleanly by the Step-3.4 escape hatch. Not a deeper drift pattern; informational. ## Bench-regression check `bench/check.py && bench/compile_check.py && bench/cross_lang.py`: - `check.py`: exit 0; 63 metrics; 0 regressed, 0 improved beyond tolerance, 63 stable. - `compile_check.py`: exit 0; 24 metrics; 0 regressed, 0 improved beyond tolerance, 24 stable. - `cross_lang.py`: exit 0; 25 metrics; 0 regressed, 0 improved beyond tolerance, 25 stable. All three bench gates green. Bench was the most plausible source of a regression given rt.1 added three new tests but the tests are pure readers and are not exercised by the bench harness; the green signal matches that expectation. ## Resolution (rt.tidy, boss-direct edits) Three fixes, mechanical, no plan/implement dispatch: 1. **Direction-2 enforcement** — `crates/ailang-surface/tests/round_trip.rs` gains a third test `parse_then_print_then_parse_is_idempotent_on_every_ailx_fixture`. For every `.ailx` fixture asserts `canonical_bytes(parse(t)) == canonical_bytes(parse(print(parse(t))))`. For the 57 fixtures with a JSON counterpart this is logically derivable from tests 1 + 2; the dedicated test stays robust for future `.ailx` fixtures without a counterpart. DESIGN.md §"Roundtrip Invariant" "Enforcement" list updated from four to five tests; module doc-comment updated from "two complementary checks" to "three complementary checks". Test PASS first-shot across all 57 fixtures. 2. **Roadmap P1 entry removed.** The "Round-trip completeness invariant" milestone entry deleted; this journal entry is the one-line mirror per roadmap convention. The P1 todo "Brainstorm Step 7.5" remains; the P1 Show + print-rewire milestone remains. 3. **Wording fix.** DESIGN.md §"Roundtrip Invariant" Float-bits-hex description changed from `<16-hex>` to `<16-lowercase-hex>` to match §"Data model". The `[low]` planner-errata carry-on item is retained in the rt.1 journal "Concerns" section; it will surface again only if a future tests-against-AST iteration repeats the pattern. ## Spec acceptance criteria — final check 1. ✓ Top-level `## Roundtrip Invariant` section in DESIGN.md; Decision 6 Constraint 2 carries upward cross-reference. (rt.2) 2. ✓ `every_ailx_fixture_matches_its_json_counterpart` dynamic in `crates/ailang-surface/tests/round_trip.rs`. (rt.1) 3. ✓ `crates/ailang-core/tests/schema_coverage.rs` with exhaustive-match visitor; 34/34 variants observed. (rt.1) 4. ✓ `crates/ail/tests/roundtrip_cli.rs` with BLAKE3 identity over `ail render` → tempfile → `ail parse`. (rt.1) 5. ✓ `cargo test --workspace` green with all four (now five) tests. (rt.1 + rt.2 + rt.tidy) 6. ✓ No roundtrip gaps surfaced; no render/parse code changes needed in this milestone. (rt.1) 7. ✓ Tests are pure readers; the CLI test's only filesystem side effect is `tempfile::TempDir`. (rt.1) ## Outcome Milestone closed clean. Five workspace-wide tests now anchor the `.ail.json` ↔ `.ailx` bijection plus AST-variant coverage; the property has a dedicated top-level section in DESIGN.md. No follow-up iterations queued in this milestone.