iter form-a.1 (Tasks 6-12): milestone close

Second half of the form-a-default-authoring milestone-close iter
(Boss-decided strategy C, big-bang). All seven tasks DONE; cargo
test --workspace green at every per-task boundary.

T6 — Bench-driver suffix flip from .ail.json to .ail across 4
Python scripts + run.sh. compile_check.py + cross_lang.py exit 0.

T7 — Re-author e2e.rs raw-JSON-inspect tests:
- diff_detects_changed_def — derive sum.ail.json on-the-fly via
  `ail parse examples/sum.ail` into tempdir, then mutate + diff.
- borrow_own_demo_modes_are_metadata_only — same pattern.
- reuse_as_demo_under_rc_uses_inplace_rewrite — same pattern.
- render_parse_round_trip_canonical — RETIRED (subsumed by T1's
  cli_parse_then_render_then_parse_is_idempotent over whole corpus).
- ail_run_accepts_ail_source_with_same_stdout_as_ail_json —
  re-authored to derive hello.ail.json in a per-process tempdir
  from hello.ail via `ail parse`, then assert dual-form stdout.

T8 — Bulk-delete 156 non-carve-out .ail.json. Inventory:
8 .ail.json (carve-outs, alphabetical: broken_unbound + prelude
+ 3× test_22b2_* + 3× test_ct1_*) + 157 .ail. carve_out_inventory
test un-#[ignore]'d and green. Forward-pulled 20 repairs that the
T1-5 dispatch's recon missed (12 Group-B suffix + 5 Group-A
load_workspace + 3 ail_run sites). Also forward-pulled T9 Step 5
(schema_coverage corpus flip from .ail.json to .ail) to satisfy
T8's green-gate.

T9 — Retire obsolete roundtrip tests:
- print_then_parse_round_trips_every_fixture (round_trip.rs)
- every_ail_fixture_matches_its_json_counterpart (round_trip.rs)
- cli_render_then_parse_preserves_canonical_bytes_on_every_fixture
- Dead helpers: list_json_fixtures ×2, round_trip_one,
  strip_trailing_newlines.
Schema-coverage corpus already flipped in T8 (forward-pull).

T10 — DESIGN.md §"Roundtrip Invariant" (lines 2027-2109) restated
with parse-determinism + idempotency + CLI-pipeline-idempotency +
carve-out-anchor framing. Five surviving enforcement tests named.
§"Float literals" and §"Why anchored at top level" preserved.

T11 — §A4 doctrine edits: CLAUDE.md:5-6 + DESIGN.md:465-466.
Canonical form remains JSON-AST; authoring projection is .ail;
build derives JSON-AST in-process via ailang_surface::parse.

T12 — Milestone close:
- WhatsNew entry: user-facing language, lead with the change.
- Roadmap: [milestone] form-a struck [x] with closing note.
- Final inventory verified: 8 .ail.json + 157 .ail.
- Final cargo test --workspace: 557 passed, 0 failed, 3 ignored.
- bench/compile_check.py + bench/cross_lang.py: exit 0.

Test math: pre-iter 558 baseline + 3 new T1 tests = 561, − 1
(T7 retire) − 3 (T9 retire) = 557 final.

INDEX.md appended with the full iter summary covering T1-T12 (the
T1-5 commit at 77b28ad deferred the INDEX line to full-iter close).

Milestone [Form-A as the default authoring surface] structurally
closed. The compile-time-embed carve-out (prelude.ail.json) is
the subject of the queued follow-up milestone [Prelude embed:
Form-A as compile-time source]. audit-form-a runs as the next
dispatch.
This commit is contained in:
2026-05-13 11:31:39 +02:00
parent 9332d1e155
commit 9fdc4cacff
173 changed files with 551 additions and 6645 deletions
+55 -37
View File
@@ -462,8 +462,14 @@ on the shelf for a future iter only if both fail.
### What this Decision deliberately does not do
- It does not promote form (A) to the source of truth. Form (A) is
one projection; the JSON-AST stays canonical.
- It does not change which form is canonical: the JSON-AST remains
the hashable, content-addressed representation, and all hashing,
content-addressing, and cross-module references flow through it
unchanged. What did change in 2026-05-13 (this milestone) is
which form is authored: authors now write Form A; the JSON-AST
is materialised in-process by callers that need it. The two
forms are byte-isomorphic by the round-trip invariant. Form (A)
is one projection; the JSON-AST stays canonical.
- It does not foreclose visual or graphical front-ends. The crate
layout (`core` owns AST; `surface`/`visual`/... are siblings)
reserves that lane.
@@ -2026,26 +2032,41 @@ would invoke literal-defaulting which axis-7 already excluded.
## Roundtrip Invariant
Every well-formed AILang module has both a canonical `.ail.json`
representation and a textual `.ail` representation, and the two
are exact projections of the same AST. Concretely, both directions
of the bijection hold:
Every well-formed AILang module has a canonical `.ail.json`
representation (the hashable, content-addressed JSON-AST) and a
hand-authored `.ail` representation (Form A, the authoring
projection). The JSON-AST is derived from `.ail` in-process by
consumers that need it; the round-trip is now the *property* of
that derivation, not the byte-level agreement of two on-disk forms.
1. **JSON → text → JSON.** For every valid `.ail.json` module `J`,
`parse(print(load_module(J)))` is canonical-byte-equal to
`canonical::to_bytes(load_module(J))`. The textual surface is
the inverse of the loader composed with the printer; no
information is lost across the round-trip.
2. **text → JSON → text.** For every well-formed `.ail` text `t`,
`parse(t)` is a complete AST, and re-printing `print(parse(t))`
produces a text that re-parses to the same AST (modulo
formatting). The parser is total over the well-formed surface
and the printer is deterministic.
Concretely:
1. **Parse-determinism.** For every well-formed `.ail` text `t`,
`ailang_surface::parse(t)` produces a unique AST. The parser is
a pure function of input — no randomness, no time dependence,
no environment leak. Hashing `canonical::to_bytes(parse(t))` is
therefore well-defined for any `.ail` source.
2. **Idempotency under print.** For every well-formed `.ail` text
`t`, `canonical(parse(t)) == canonical(parse(print(parse(t))))`.
The printer is a left-inverse of the parser modulo canonical
form: print-then-parse is a no-op on the canonical bytes.
3. **CLI-pipeline idempotency.** For every `.ail` fixture, the
public CLI pipeline `ail parse | ail render | ail parse` is
byte-identical to direct `ail parse` of the source `.ail`.
Pins drift that crate-internal tests cannot see.
4. **Carve-out anchor.** Eight `.ail.json`-only fixtures (seven
subject-matter rejection tests + one compile-time-embed for
the prelude) survive in the corpus by structural necessity.
They participate in their own dedicated rejection-shape or
embed-mechanism tests, not in the round-trip gate.
Hashing is the consequence the language depends on: BLAKE3 of the
canonical bytes is identical for the two paths, so content-
addressing is form-agnostic. An LLM author can pick either form
without changing the identity of the module it produces.
canonical bytes is well-defined for any `.ail` source via parse-
determinism. An LLM author writes `.ail`; the build derives the
canonical hash without ambiguity.
### Float literals are inside the invariant
@@ -2065,29 +2086,26 @@ operating on the `examples/` corpus via dynamic `read_dir`
collection (no hardcoded fixture list, so newly added fixtures
inherit the gate automatically):
- `crates/ailang-surface/tests/round_trip.rs::print_then_parse_round_trips_every_fixture`
— for every `.ail.json`, `print` then `parse` produces canonical-
byte-equal output. Direction 1 above.
- `crates/ailang-surface/tests/round_trip.rs::parse_is_deterministic_over_every_ail_fixture`
— for every `.ail`, parse twice and assert canonical-byte
equality between the two ASTs. Direction 1 above.
- `crates/ailang-surface/tests/round_trip.rs::parse_then_print_then_parse_is_idempotent_on_every_ail_fixture`
— for every `.ail` text `t`, `parse(t)` and `parse(print(parse(t)))`
produce canonical-byte-equal AST. Direction 2 above.
- `crates/ailang-surface/tests/round_trip.rs::every_ail_fixture_matches_its_json_counterpart`
— for every `.ail` with a same-stem `.ail.json` counterpart,
`parse` of the text yields canonical bytes equal to the JSON
counterpart. Pins the hand-authored `.ail` corpus against
drift between the two forms at the fixture level.
- `crates/ail/tests/roundtrip_cli.rs::cli_parse_then_render_then_parse_is_idempotent`
— for every `.ail`, the public CLI pipeline `ail parse | ail render | ail parse`
reproduces canonical bytes byte-identical to direct `ail parse`.
Pins drift internal tests cannot see.
- `crates/ailang-core/tests/schema_coverage.rs::every_ast_variant_is_observed_in_the_fixture_corpus`
— every variant of `Def`, `Term`, `Pattern`, `Literal`, `Type`,
and `ParamMode` appears in at least one fixture. The visitor
matches each AST enum exhaustively without wildcard arms, so
any new AST variant fails to compile until the visitor is
extended in lockstep — the coverage table cannot silently fall
behind the schema.
- `crates/ail/tests/roundtrip_cli.rs::cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`
— for every `.ail.json`, the public CLI pipeline `ail render` →
tempfile → `ail parse` reproduces BLAKE3-identical canonical
bytes. Pins the user-facing CLI against drift that crate-
internal tests cannot see.
and `ParamMode` appears in at least one `.ail` fixture (corpus
flipped from `.ail.json` to `.ail` at iter form-a.1). New AST
variants fail compile until the visitor and corpus are extended
in lockstep.
- `crates/ailang-core/tests/carve_out_inventory.rs::examples_ail_json_inventory_matches_carve_outs`
— exactly the eight named carve-out files exist under
`examples/*.ail.json` at any commit. A new `.ail.json` or a
missing carve-out fails the test.
A new fixture or a new AST variant that violates the invariant
fails one of these tests; the fix is in render or parse code,
+6
View File
@@ -118,3 +118,9 @@ The per-type `io/print_int`, `io/print_bool`, `io/print_float` operators stay fo
Bench continues on the same noise envelope observed across the last ten audits — baseline pristine.
Queue back to user-direction: the next roadmap item is that corpus migration, which retires the per-type print operators.
## 2026-05-13 — Form A is now the authoring surface
`.ail` is now the form you read, edit, and check in. The JSON-AST counterpart is still the canonical hashable representation, but it is no longer something you look at or maintain by hand — the tools derive it from `.ail` whenever they need it. About a hundred example programs that previously existed as JSON-AST were converted to `.ail` and the JSON files were deleted; only eight stay as `.ail.json` (seven negative-test fixtures whose subject matter cannot be expressed in `.ail`, plus the prelude, which is loaded at compile time and depends on internal plumbing that lands in a later milestone).
If you were used to opening a `.ail.json` file to see what a program looks like, you now open the `.ail` sibling instead.
+244
View File
@@ -185,3 +185,247 @@ fixtures = 150 paths. Detail:
## Stats
bench/orchestrator-stats/2026-05-13-iter-form-a.1.json
---
# iter form-a.1 — Big-bang migration (Tasks 6-12: bench drivers, e2e rewrites, deletion, doctrine, milestone close)
**Date:** 2026-05-13
**Started from:** 9332d1e (post-T1-5 commit 77b28ad + plan-amendment 9332d1e)
**Status:** DONE (Tasks 6-12; iter form-a.1 fully closed)
**Tasks completed:** 7 of 7 (this dispatch); 12 of 12 (iter total)
## Summary
Second half of the form-a-default-authoring milestone-close iter: T6
flips the bench-driver fixture suffix from `.ail.json` to `.ail` (4
Python scripts + run.sh). T7 re-authors three e2e tests
(`diff_detects_changed_def`, `borrow_own_demo_modes_are_metadata_only`,
`reuse_as_demo_under_rc_uses_inplace_rewrite`) to derive their
canonical-JSON via `ail parse` on the `.ail` source rather than
raw-reading the soon-to-be-deleted `.ail.json` file, retires the
redundant `render_parse_round_trip_canonical` (subsumed by T1's
`cli_parse_then_render_then_parse_is_idempotent`), and re-authors
`ail_run_accepts_ail_source_with_same_stdout_as_ail_json` to derive
a tempdir-based `hello.ail.json` from `hello.ail` via `ail parse`
rather than reading a deleted `.ail.json` sibling. T8 deletes the
156 non-carve-out `.ail.json` files (count drops 164 → 8), removes
the `#[ignore]` on the carve-out inventory test, and pulls forward
20 stale-`.ail.json`-reference repairs that the T1-5 dispatch missed
(12 `let example = "X.ail.json"` Group-B sites + 5
`ailang_core::load_workspace` Group-A sites in e2e.rs + 3 `ail_run`
Group-B sites in typeclass_22b3.rs); to keep T8's green-gate, T9
Step 5 (schema_coverage corpus flip from `.ail.json` to `.ail`) is
also pulled forward into T8. T9 retires the 3 obsolete roundtrip
tests (`print_then_parse_round_trips_every_fixture`,
`every_ail_fixture_matches_its_json_counterpart`,
`cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`)
plus the dead helpers `list_json_fixtures` (×2),
`round_trip_one`, and `strip_trailing_newlines`. T10 restates the
DESIGN.md §Roundtrip Invariant with parse-determinism + idempotency
+ CLI-pipeline-idempotency + carve-out-anchor framing, replacing
the old Direction-1/Direction-2 framing and the five enforcement
bullets with the five surviving test names. T11 replaces the
CLAUDE.md and DESIGN.md doctrine sentences per spec §A4. T12
appends the WhatsNew milestone-close entry, strikes the roadmap
entry (`- [x]` + `(Closed 2026-05-13 by iter form-a.1.)`), and
verifies final inventory (8 `.ail.json` carve-outs + 157 `.ail`).
Final test count: 557 green + 3 ignored (3 pre-existing doctests).
The `cargo test --workspace` baseline holds green at every per-task
boundary; both `python3 bench/compile_check.py` and
`python3 bench/cross_lang.py` exit 0. The milestone
`[Form-A as the default authoring surface]` is fully closed.
## Per-task notes
- **iter form-a.1.6** — Bench-driver suffix flips in
`bench/compile_check.py:43,101`, `bench/cross_lang.py:48,80`,
`bench/mono_dispatch.py:10,112`, `bench/run.sh:68,182,183`.
Mechanical edit; comment text and path string updated at each
site. `python3 bench/compile_check.py` exit 0; `python3
bench/cross_lang.py` exit 0. (First compile_check run reported
exit-1 due to sub-millisecond `check_ms` noise on `hello` and
`borrow_own_demo`; second run clean. The noise is unrelated to
the migration — the bench measures `ail check` runtime, and the
Python edits did not touch the binary path.)
- **iter form-a.1.7** — Re-authored 3 raw-JSON-inspect tests +
retired 1 + re-authored the dual-form smoke. Pattern for the
three substring-assert tests: replace
`std::fs::read*("examples/<X>.ail.json")` with a `Command::new(ail_bin()).args(["parse", "examples/<X>.ail", "-o", tmpfile])`
+ `read_to_string(tmpfile)`. `reuse_as_demo_under_rc_uses_inplace_rewrite`
additionally switches its `ailang_core::load_workspace(&json_path)`
call to `ailang_surface::load_workspace(&ail_path)` (the
IR-lowering path no longer needs the JSON file). The dual-form
smoke (`ail_run_accepts_ail_source_with_same_stdout_as_ail_json`)
uses a per-process tempdir with `hello.ail.json` as the file
basename — necessary because the loader name-checks the module
name against the file stem, and the first attempt at a
tempfile-with-PID-suffix path tripped that check. Net test
count: 1 (retirement of `render_parse_round_trip_canonical`).
559 green at task close.
- **iter form-a.1.8** — CRITICAL task. Before the deletion command,
20 stale-`.ail.json`-reference repairs were pulled forward
(T1-5 dispatch missed these despite the plan's Group-A/B scope):
(a) 12 `let example = "X.ail.json"` patterns in `e2e.rs` flipped
to `"X.ail"` via sed; (b) 5 `ailang_core::load_workspace(&json_path)`
sites in `e2e.rs` switched to `ailang_surface::load_workspace`
(the `let example = "X.ail"` from (a) feeds into `workspace.join("examples").join(example)`,
which is `.ail` post-flip — needs the extension-dispatching loader);
(c) 3 `ail_run("X.ail.json")` sites in `typeclass_22b3.rs` flipped
via sed. Cargo-test green pre-deletion at 559. The plan's deletion
bash loop ran clean (exit 0); `ls examples/*.ail.json | wc -l`
8, `ls examples/*.ail | wc -l` → 157. The `#[ignore]` attribute
on `examples_ail_json_inventory_matches_carve_outs` was removed;
the test passes (8 files match `EXPECTED`). Post-deletion
cargo-test surfaced 1 failure
(`every_ast_variant_is_observed_in_the_fixture_corpus` in
`schema_coverage.rs`) because its corpus walker still looked at
`.ail.json` (now down to 8 carve-outs, insufficient to cover all
AST variants). The plan-T8 vs. T9 ordering implicitly assumed T9
Step 5 (schema_coverage corpus flip) would land before T8 — but
T9 is plan-ordered after T8. To satisfy T8's green-gate, T9
Step 5 was pulled forward inline (helper rename
`list_json_fixtures``list_ail_fixtures`, filter `.ail.json`
`.ail`, loader `ailang_core::load_module`
`ailang_surface::load_module`). Post-fix: 560 green + 3 ignored
(was 559 pre-T8 with 4 ignored including carve_out_inventory;
un-ignore + correct schema_coverage flip = +1 net = 560).
- **iter form-a.1.9** — Retired 3 obsolete roundtrip tests +
cleanups. `round_trip.rs`: retired
`print_then_parse_round_trips_every_fixture` (lines 57-101 in
pre-iter numbering) and `every_ail_fixture_matches_its_json_counterpart`
(lines 120-204); retired the `list_json_fixtures` helper and
the `round_trip_one` helper (only consumers were the two retired
tests); updated the file's doc-comment to describe the two
surviving tests (`parse_is_deterministic_*` and
`parse_then_print_then_parse_*`); removed the unused `Path`
import (only `PathBuf` remains). `roundtrip_cli.rs`: retired
`cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`
(lines 116-146 pre-iter) and the `list_json_fixtures` +
`roundtrip_one` + `strip_trailing_newlines` helpers; updated the
doc-comment. T9 Step 5 (schema_coverage corpus flip) was already
done in T8; nothing to do here. 557 green + 3 ignored at task
close (560 pre-T9 3 retired = 557).
- **iter form-a.1.10** — DESIGN.md §Roundtrip Invariant restatement.
Lines 2029-2048 (Direction 1/Direction 2 framing) replaced with
the new 4-property framing (parse-determinism +
idempotency-under-print + CLI-pipeline-idempotency +
carve-out-anchor) verbatim from the plan. Lines 2061-2094
(Enforcement bullets, five tests) replaced with the five
surviving tests verbatim. Float-literals subsection (lines
2050-2059 pre-edit, 2065-2074 post-edit) preserved. Why-anchored-at-top-level
subsection (lines 2096-2108 pre-edit, 2108-2120 post-edit)
preserved. The numbered prose (4 properties) and the bulleted
enforcement (5 tests) are internally consistent; the carve-out
inventory is the 5th enforcement bullet, covering property 4
("carve-out anchor") as a meta-property.
- **iter form-a.1.11** — Doctrine edits. CLAUDE.md:5-6 sentence
replaced verbatim with spec §A4 wording. DESIGN.md:465-466 first
sentence replaced verbatim with spec §A4 wording; second
sentence ("Form (A) is one projection; the JSON-AST stays
canonical.") preserved as the trailing sentence of the new
replacement block. Doc-only; tests unaffected.
- **iter form-a.1.12** — Milestone close. WhatsNew.md entry
appended ("Form A is now the authoring surface", per-boss
editorial rules: no crate names, no iter codes, lead with the
change, factual). docs/roadmap.md entry at line 97 changed from
`- [ ]` to `- [x]` with `(Closed 2026-05-13 by iter form-a.1.)`
prepended. Final cargo-test: 557 green + 3 ignored. Final bench:
both compile_check and cross_lang exit 0. Final inventory:
exactly 8 `.ail.json` (carve-outs alphabetically: broken_unbound,
prelude, test_22b2_invalid_superclass_param,
test_22b2_kind_mismatch, test_22b2_unbound_constraint_var,
test_ct1_bad_qualifier, test_ct1_bare_xmod_rejected,
test_ct1_qualified_class_rejected) + 157 `.ail`.
## Concerns
- **Forward-pull of T9 Step 5 into T8.** The plan ordered T8
(deletion) before T9 (test retirement + schema_coverage flip),
but T8's green-gate required schema_coverage to be flipped
*first* — otherwise the schema_coverage corpus walker shrinks
from 164 `.ail.json` to 8 carve-outs and the AST-variant
coverage assertion fails. Pulled T9 Step 5 inline into T8;
T9 then had no schema_coverage work left to do. Recorded so a
future planner-skill recon pass can detect this ordering
defect class (a Task K green-gate depending on an edit
scripted for Task K+N).
- **T1-5 Group-A/B classification gaps.** The T1-5 dispatch's
Concerns flagged 4 raw-JSON-inspect e2e.rs tests but missed
20 additional sites of the same kind in two patterns: 12
`let example = "X.ail.json"` Group-B-pattern sites in e2e.rs
(feeds `build_and_run_with_alloc`) + 5
`ailang_core::load_workspace` Group-A-pattern sites in e2e.rs
+ 3 `ail_run` Group-B sites in typeclass_22b3.rs. All repaired
inline in T8 before the deletion command ran. The pattern that
T1-5 missed is "binding pulled out of the call expression" —
the `let example = "X.ail.json"` introduces a local that the
Group-B sed for `build_and_run("X.ail.json")` doesn't match.
Worth noting for a future planner-recon tightening pass.
- **bench/compile_check.py first-run flakiness.** The first run
after T6 reported exit-1 because two `check_ms` metrics on
sub-millisecond timings (`hello`, `borrow_own_demo`) drifted
past the 25% tolerance; the second run was exit-0. The drift is
measurement noise (system load + ms-scale latency), not a
migration-induced regression. Final T12 bench run was exit-0
on both scripts.
## Known debt
- **None known.** The iter closes the milestone cleanly. Two
follow-up roadmap items already exist:
- `[milestone] Prelude embed: Form-A as compile-time source`
(queued; retires carve-out (b) `prelude.ail.json`).
- The Show/print fieldtest example-corpus migration (separately
queued; orthogonal to this milestone).
- Cosmetic: the `mod tests {}` placeholder in
`ailang-core/src/hash.rs` from T5 is still in-tree; could be
deleted entirely in a doctrinal cleanup pass. Functionally
harmless.
## Files touched (Tasks 6-12)
### Modified bench (4)
- `bench/compile_check.py`
- `bench/cross_lang.py`
- `bench/mono_dispatch.py`
- `bench/run.sh`
### Modified test source (5)
- `crates/ail/tests/e2e.rs` — T7 re-authoring of 5 tests; T8
forward-pull of 12 Group-B + 5 Group-A sites
- `crates/ail/tests/typeclass_22b3.rs` — T8 forward-pull of 3
Group-B sites
- `crates/ail/tests/roundtrip_cli.rs` — T9 retirement +
helpers cleanup + doc-comment update
- `crates/ailang-surface/tests/round_trip.rs` — T9 retirement +
helpers cleanup + doc-comment update + import cleanup
- `crates/ailang-core/tests/schema_coverage.rs` — T8 corpus flip
to `.ail` (pulled forward from T9 Step 5)
### Modified test discipline (1)
- `crates/ailang-core/tests/carve_out_inventory.rs` — T8 un-ignored
### Modified doc (4)
- `CLAUDE.md` — T11 doctrine sentence (lines 5-6)
- `docs/DESIGN.md` — T10 §Roundtrip Invariant restatement; T11
§"What this Decision deliberately does not do" first sentence
- `docs/WhatsNew.md` — T12 milestone-close entry
- `docs/roadmap.md` — T12 strike of the Form-A milestone entry
### Deleted (T8) — 156 files
`examples/*.ail.json` — every non-carve-out fixture (the eight
carve-outs `broken_unbound`, `prelude`,
`test_22b2_invalid_superclass_param`, `test_22b2_kind_mismatch`,
`test_22b2_unbound_constraint_var`, `test_ct1_bad_qualifier`,
`test_ct1_bare_xmod_rejected`, `test_ct1_qualified_class_rejected`
preserved).
## Stats
bench/orchestrator-stats/2026-05-13-iter-form-a.1.json
+1
View File
@@ -52,3 +52,4 @@
- 2026-05-13 — audit-24: milestone close (Show + print rewire) — architect drift report surfaces 5 actionable items routing to `24.tidy` (3× [high]: DESIGN.md §"Monomorphisation" doc-anchor missing for three iter-24.3 strengthenings — MonoTarget::FreeFn::type_args canonical-form normalisation, post-mono synthesised-body cross-module-ref import_map-bypass invariant, FreeFnCall constraint-residual push; codegen import_map-fallback path has no unit-level pin — only E2E catches regression; FreeFnCall constraint-residual push covers only dot-qualified branch, bare-name poly-fn refs uncovered; 2× [medium]: unwrap_or_default in method-name lookup masks class-index drift, normalize_type_for_lookup duplicated across two mono.rs sites with manual-lockstep invariant), plus 1× [medium] deferred to roadmap P3 (negative-test coverage single-shape — only f:Int→Int, broader shapes wait for downstream corpus-migration milestone), plus 1× [low] carry-on (bench/architect_sweeps.sh noise on pre-milestone-24 DESIGN.md lines, not new drift). Bench: cross_lang.py exit 0 (25/25 stable); check.py + compile_check.py exit 1 with metric-identity-migrating noise envelope per audit-cma → audit-ms → audit-eob → audit-ct-tidy → audit-mq → audit-mq.tidy → iter-24.2 → iter-24.3 lineage — 9th consecutive observation; conservative-call convention holds baseline pristine across all 9, the metric-migration-between-runs is itself attribution evidence variance not signal; right ratification path is the queued P3 latency-methodology-histogram rework, not --update-baseline → 2026-05-13-audit-24.md
- 2026-05-13 — iter 24.tidy: close 5 actionable drift items from audit-24 — T1 DESIGN.md new subsection §Cross-module references in synthesised bodies (3 invariants installed iter 24.3: canonical-form MonoTarget::FreeFn::type_args via normalize_type_for_lookup, post-mono synthesised body import_map-bypass + module_user_fns fallback, FreeFnCall constraint-residual push per declared forall-constraint); T2 codegen_import_map_fallback_pin (integration test asserts prelude.print__<UserType> body references user_module.show__<UserType> AND prelude imports do not contain user_module); T3 polyfn_dot_qualified_branch_pin (asserts bare-name print f fires exactly one no-instance + zero unknown-variable, proving constraint-residual push fires via dot-qualified branch); T4 check/lib.rs:2858 unwrap_or_default → expect(class_methods registry coherence) — surfaces class-index drift on regression; T5 mono.rs apply_subst_and_normalize helper extracted from byte-identical sites at :685-714 + :1284-1303 with Option<Type> return — each call site keeps own rigid-var/unit-default policy. Tests 558/558 (was 556+2 pins). Bench cross_lang exit 0 stable, compile_check + check both exit 0 this run (10th consecutive lineage observation unobserved-firing). audit-24 medium-3 negative-test breadth defers to roadmap P3; low-1 sweep noise carry-on → 2026-05-13-iter-24.tidy.md
- 2026-05-13 — iter form-a.0: prelude pilot for Form-A-as-default-authoring milestone — examples/prelude.ail rendered (116 lines / 6386 bytes) via `ail render`; two auto-discovering roundtrip tests (every_ail_fixture_matches_its_json_counterpart + parse_then_print_then_parse_is_idempotent_on_every_ail_fixture) green on the new fixture without test-code changes; prelude.ail.json retained per spec §A2 (singular dual-form iter, deletion lands iter 1 with bulk test-infra refactor); cargo test --workspace green at 558 tests → 2026-05-13-iter-form-a.0.md
- 2026-05-13 — iter form-a.1: Form-A-as-default-authoring milestone close (Boss-decided strategy C, big-bang) — 12 tasks across two implementer dispatches; T1 added 3 new tests (parse-determinism + CLI-pipeline-idempotency + carve_out_inventory#[ignore]) + T2 bulk-rendered 99 missing examples/<stem>.ail (corpus 58→157 .ail) + T3-4 migrated 26 fixture-loading test files (Group A load_workspace→ailang_surface::load_workspace + Group B subprocess suffix flip) + T5 relocated 23 #[cfg(test)] mod tests blocks from ailang-core/-codegen production source to integration test crates with ailang-surface dev-dep (hash_pin.rs + workspace_pin.rs + eq_primitives_pin.rs + prose snapshot migration) + T6 bench-driver suffix flips (4 Python + run.sh, both compile_check.py + cross_lang.py exit 0) + T7 re-authored 4 raw-JSON-inspect e2e tests via `ail parse`-derived tempfiles + retired 1 (render_parse_round_trip_canonical subsumed by T1) + T8 deleted 156 non-carve-out .ail.json (inventory 8 carve-outs + 157 .ail post-T8, alphabetical: broken_unbound + prelude + 3× test_22b2_* + 3× test_ct1_*) + 20 forward-pulled stale-.ail.json-ref repairs missed by T1-5 recon + T9 retired 3 obsolete roundtrip tests (print_then_parse_round_trips_every_fixture + every_ail_fixture_matches_its_json_counterpart + cli_render_then_parse_preserves_canonical_bytes_on_every_fixture) + dead helpers (list_json_fixtures ×2, round_trip_one, strip_trailing_newlines) + flipped schema_coverage corpus to .ail (forward-pulled into T8 for green-gate) + T10 §C3 DESIGN.md §Roundtrip Invariant restated with parse-determinism + idempotency + CLI-pipeline-idempotency + carve-out-anchor framing (5 surviving enforcement tests named) + T11 §A4 CLAUDE.md + DESIGN.md doctrine sentences replaced (canonical form is JSON-AST; authoring form is .ail) + T12 WhatsNew milestone-close entry + roadmap [milestone] form-a struck [x] (Closed 2026-05-13 by iter form-a.1). 4 carve-outs added beyond the original 7 §C4(a): only 1 — prelude.ail.json — landed as §C4(b) compile-time-embed (rationale: include_str! at workspace.rs:417 + main.rs:474; resolution queued as separate milestone Prelude embed: Form-A as compile-time source). Spec amendment + grounding-recheck PASS at 9fcda8b. Final tests: 557 green + 3 ignored (561 from T1 4 retired = 557); bench compile_check.py + cross_lang.py exit 0; check.py noise envelope continues 11th consecutive audit, baseline pristine. Milestone structurally closed → 2026-05-13-iter-form-a.1.md
+2 -2
View File
@@ -94,8 +94,8 @@ context. Pick the next milestone from P1.)_
form-a.0 — `examples/prelude.ail` rendered via `ail render`,
116 lines / 6386 bytes, round-trip-CI green.)
- [ ] **\[milestone\]** Form-A as the default authoring surface for
examples and docs. Render every `examples/*.ail.json` to its
- [x] **\[milestone\]** Form-A as the default authoring surface for
examples and docs. (Closed 2026-05-13 by iter form-a.1.) Render every `examples/*.ail.json` to its
`.ail` sibling via `ail render`, **delete the now-redundant
`.ail.json`**, and regenerate the JSON-AST per `ail parse` at
build / test time. Same for inline JSON-AST blocks in `docs/`