iter pd.3: prelude.ail.json retired — milestone prelude-decouple closed

Deleted examples/prelude.ail.json (-559 lines). The cross-form-identity
preflight test that ratified pd.3's load-bearing assumption at module
hash 3abe0d3fa3c11c99 has discharged its purpose and was removed
along with its supporting bytes; the long-term prelude_parse_yields_canonical_hash
anchor stays. The ail-CLI migrate-bare-cross-module-refs subcommand's
defensive include + lockstep skip-branch removed; the rewrite logic's
prelude-fallback capability silently retired with the synthetic insert
(known debt, doc-comment updated to reflect). One in-mod core test
relocated to crates/ailang-core/tests/workspace_pin.rs (pd.2.4 dev-dep
cycle precedent — in-mod call to ailang_surface still structurally
impossible).

carve_out_inventory.rs: 8 → 7 carve-outs, §C4(b) row dropped, header
sentence updated. form-a-default-authoring.md §C4(b) gets a "RETIRED
2026-05-14 by milestone prelude-decouple" status marker; original
historical text preserved. New prelude_decouple_carve_out_pin.rs
asserts examples/prelude.ail.json does NOT exist.

Milestone prelude-decouple closed: prelude exists on disk only as
examples/prelude.ail; ailang-core embeds zero prelude bytes; CLAUDE.md
"authors write .ail" doctrine holds without exception.

cargo test --workspace 573 green; bench/cross_lang.py +
bench/compile_check.py exit 0; bench/check.py exit 1 with the
established noise envelope (14th observation of bench_list_sum.bump_s
since audit-cma; pd.3 is filesystem + spec text + test deletion only,
no codegen / runtime / typecheck path edited — baseline pristine).

Folds in the orphan pd.2 INDEX entry that was left uncommitted in the
working tree.
This commit is contained in:
2026-05-14 13:24:40 +02:00
parent c0dd2bc334
commit 9a8d3850e7
11 changed files with 354 additions and 664 deletions
+209
View File
@@ -0,0 +1,209 @@
# iter pd.3 — prelude.ail.json deleted; prelude-decouple milestone closed
**Date:** 2026-05-14
**Started from:** c0dd2bc334d490e5e90ad10501c33e48076ff2bd
**Status:** DONE
**Tasks completed:** 8 of 8
## Summary
pd.3 closes the **prelude-decouple milestone** (pd.1 + pd.2 + pd.3) by
deleting `examples/prelude.ail.json` from the working tree, sweeping the
three remaining `include_str!` consumers (one in-mod test in
`workspace.rs`, the cross-form-identity preflight in
`prelude_module_hash_pin.rs`, the defensive include in `ail/src/main.rs`'s
`migrate-canonical-types` subcommand) and the lockstep skip-branch the
defensive include necessitated, dropping the §C4 (b) entry from
`carve_out_inventory.rs` (8 → 7 named carve-outs), retiring §C4 (b) of
`docs/specs/2026-05-13-form-a-default-authoring.md` in place with a
"Status: RETIRED 2026-05-14" marker that preserves the original framing
as historical context, and adding `prelude_decouple_carve_out_pin.rs`
as the milestone's permanent guard against regression. At milestone
close: the prelude exists on disk only as `examples/prelude.ail`; core
embeds zero prelude bytes; the `migrate-canonical-types` subcommand no
longer auto-injects a synthetic prelude entry; the doctrine "authors
write `.ail`; the build derives the JSON-AST in-process via
`ailang_surface::parse`" (CLAUDE.md) holds without exception. Test count:
573 green workspace-wide (preserved from pd.2; +1 carve-out pin -1
cross-form-identity preflight +1 relocated `build_workspace_accepts...`
test -1 in-mod twin = net 0). `bench/cross_lang.py` + `bench/compile_check.py`
exit 0; `bench/check.py` exit 1 with the same envelope-noise pattern
observed since audit-cma (14th consecutive observation; pd.3 is a
file-system + spec-text + test deletion + dead-code cleanup with zero
codegen / runtime / typecheck touch, so cannot be the source).
## Per-task notes
- iter pd.3.1: `build_workspace_accepts_assembled_modules_and_runs_validation`
RELOCATED from `crates/ailang-core/src/workspace.rs::tests` (in-mod) to
`crates/ailang-core/tests/workspace_pin.rs` (integration crate) instead
of the literal call-site swap the plan prescribed. The plan specified
"use the fully-qualified `ailang_surface::parse_prelude()` at the call
site" claiming it was the workaround pd.2 used; in fact pd.2 worked
around this same dev-dep cycle by inlining
`serde_json::from_str(include_str!("prelude.ail.json"))` precisely
BECAUSE `parse_prelude()` doesn't typecheck from in-mod (the lib-test
target sees two distinct `ailang-core` compilations and the `Module`
types fail to unify). pd.3 cannot use the JSON workaround because the
JSON file is being deleted. The structural fix is the relocation
pattern pd.2.4 already used for 10 sibling tests — same crate edge,
same outcome. A 6-line stub-comment in `workspace.rs::tests` documents
the dev-dep cycle so future maintainers don't try to put the test
back. New test `load_one_adapter` helper at the top of `workspace_pin.rs`
mirrors the in-mod `load_one` exactly (Io/Schema mapping). DONE_WITH_CONCERNS:
plan defect (treated under pd.2.4 lesson recommendation but not
caught at planning time).
- iter pd.3.2: 5 deletions in `prelude_module_hash_pin.rs` (cross-form-
identity preflight test fn, `PRELUDE_JSON` const, `PRELUDE_AIL` import,
`const _: &str = PRELUDE_AIL;` shape-pin, lines 1-15 of original
module doc-comment); module doc-comment replaced verbatim with the
surviving-only version (preserves the historical record of why the
preflight existed, what it discharged, when it was retired). Hash
`3abe0d3fa3c11c99` still asserted by the surviving
`prelude_parse_yields_canonical_hash`. Zero orphan-import warnings.
First-shot clean.
- iter pd.3.3: defensive `include_str!` block (12 lines) deleted from
`Cmd::MigrateCanonicalTypes` arm; lockstep skip-branch (4 lines)
deleted from the rewrite loop's Pass 2. The plan referenced the
subcommand by its variant tag `MigrateBareCrossModuleRefs` but the
user-facing subcommand name is `migrate-canonical-types` — spot-test
ran under the correct name and the help text printed. DONE_WITH_CONCERNS:
plan referenced obsolete variant name; doc-comment update on
`MigrateCanonicalTypes` (one paragraph) was needed beyond strict task
text because the prelude-fallback capability that the doc-comment
asserted ("Prelude is consulted as an implicit last-resort fallback
when no listed import owns the name") was silently removed by Step 2
— leaving the doc-comment in would have been an active mis-statement
in `--help` output. Update names pd.3 as the retirement point.
- iter pd.3.4: 3 edits to `carve_out_inventory.rs` (header sentence
"eight" → "seven"; comment block re-published per plan; `"prelude.ail.json"`
entry + its `// §C4 (b) — compile-time-embed` comment dropped from
EXPECTED). Test RED-on-purpose post-edit (file still on disk);
flips GREEN at Task 7.
- iter pd.3.5: Status marker inserted verbatim above §C4 (b) heading
in `docs/specs/2026-05-13-form-a-default-authoring.md`. Original §C4
(b) text preserved as historical context (per the spec's convention
for retired sections). Reads coherently top-to-bottom; the marker
reads as a forward-pointer to the resolution and the original text
reads as historical motivation.
- iter pd.3.6: `crates/ailang-surface/tests/prelude_decouple_carve_out_pin.rs`
created verbatim per the plan. RED-on-purpose at this task (file still
exists); flips GREEN at Task 7. Failure message names the four things
a future maintainer must do to legitimately reintroduce the file —
pre-empts the "it's just one file" rationalisation.
- iter pd.3.7: pre-deletion verification clean (zero `include_str!`
consumers; the two non-`include_str!` `.rs` references are inert —
`print_no_leak_pin.rs:110` is a string-literal in an assertion
message, `prelude_injection_pin.rs:28` constructs a tempdir-relative
path that does not read the in-tree file). `rm examples/prelude.ail.json`.
Both pin tests flip RED → GREEN at this step. Workspace test count
unchanged at 573 green.
- iter pd.3.8: `bench/compile_check.py` exit 0; `bench/cross_lang.py`
exit 0; `bench/check.py` exit 1 with the established noise envelope
(the `bench_list_sum.bump_s` and `implicit_at_rc` tail-latency
oscillation observed since audit-cma — 14th consecutive observation).
Acceptance criterion sweep: zero `include_str!` of `prelude.ail.json`
workspace-wide; zero literal-`"prelude"` in `crates/ailang-core/src/`
production scope (the matches in `workspace.rs` are all inside
`#[cfg(test)] mod tests`); CLAUDE.md "Authors write `.ail`" sentence
is consistent with the post-milestone state without modification (the
prelude exception it implicitly tolerated pre-milestone is gone);
`docs/DESIGN.md` carries no production-doctrine assertions about core
embedding the prelude or referencing `prelude.ail.json`.
## Concerns
- pd.3.1: plan defect — the task text instructed a call-site swap
("In each affected test fn body, replace the pattern ... with
`ailang_surface::parse_prelude()`") that doesn't typecheck due to
the dev-dep cycle. The plan also misattributed pd.2's actual
workaround (`serde_json::from_str(include_str!(...))`) as
successful use of `parse_prelude()` from in-mod. Recommend planner
recon-check: when a plan proposes a call-site change involving
`ailang_surface::*` from in-mod tests, verify the test target can
resolve the dev-dep edge (the lib-test target generally cannot;
the integration-test crate generally can — same lesson pd.2.4
recorded but didn't propagate to the planner skill).
- pd.3.3: plan referenced subcommand by its internal variant tag
(`MigrateBareCrossModuleRefs`) instead of its user-facing name
(`migrate-canonical-types`). Trivial repair (test under correct
name) but recommend planner check: verify subcommand-arm references
in spot-test commands by enumeration-after-rename.
- pd.3.3 (deeper): the plan's "Architecture" preamble called the
defensive include "a documented no-op" because the inserted entry
was unconditionally skipped by the lockstep guard at lines 500-505.
This is correct about WRITING the rewritten module file back, but
not about CONSULTING `local_types["prelude"]` for fallback rewrites
(which the inserted entry populated, lines 487-497, before the Pass
2 skip). Removing both blocks silently retired the prelude-fallback
capability of the rewrite logic. The plan called the change net-zero
behaviour; it isn't. The doc-comment update I made on
`MigrateCanonicalTypes` makes the new behaviour visible. The
rewrite-helper's prelude-fallback branch at lines ~2436-2446 in
`main.rs` is now dead-by-construction (the `local_types` map will
never have a `"prelude"` key, since no prelude module is loaded by
this subcommand) — left in place per the implementer's
no-surrounding-cleanup discipline; tagged below as known debt.
## Known debt
- `crates/ail/src/main.rs:~2436-2446`: the `local_types.get("prelude")`
fallback in `rewrite_def`'s `rewrite_type_con_owner` (or analogue)
is dead-by-construction post-pd.3 since the `local_types` map for
the `migrate-canonical-types` subcommand no longer contains a
`"prelude"` key. Out of pd.3's literal scope (no surrounding cleanup);
candidate for a follow-up tidy iter or for the post-pd.3 audit's
drift sweep.
- 3 cargo doc warnings on dangling `[`load_workspace`]` references in
`Workspace` and `Registry` rustdoc — pre-existing baseline carried
forward from pd.2; out of pd.3 scope. (Identical entry was in the
pd.2 known-debt section.)
- The `migrate-canonical-types` subcommand's substantive behaviour
(rewriting bare cross-module refs across a directory of `.ail.json`
files) hasn't been exercised since the canonical-type-names
milestone. No in-tree fixtures known to need rewriting today; spot-
tested via `--help` only. If a future migration is requested, the
prelude-fallback removal + the rewrite-helper dead-branch should
be reviewed together.
## Files touched
Modified:
- `crates/ail/src/main.rs` (delete defensive include 472-484, delete
skip-branch 500-505, update `MigrateCanonicalTypes` doc-comment to
reflect retired prelude-fallback)
- `crates/ailang-core/src/workspace.rs` (delete in-mod
`build_workspace_accepts_assembled_modules_and_runs_validation` test;
replace with 6-line stub comment documenting the dev-dep cycle as
invariant)
- `crates/ailang-core/tests/carve_out_inventory.rs` (header sentence
+ comment block + EXPECTED list — 8 → 7)
- `crates/ailang-core/tests/workspace_pin.rs` (add `load_one_adapter`
helper at top; append the relocated test at end)
- `crates/ailang-surface/tests/prelude_module_hash_pin.rs` (delete
cross-form-identity preflight + supporting `PRELUDE_JSON` /
`PRELUDE_AIL` references; trim doc-comment to surviving-only
framing)
- `docs/specs/2026-05-13-form-a-default-authoring.md` (insert "Status:
RETIRED" marker above §C4 (b) heading)
New:
- `crates/ailang-surface/tests/prelude_decouple_carve_out_pin.rs`
(single test asserting `examples/prelude.ail.json` does not exist)
Deleted:
- `examples/prelude.ail.json` (the milestone's primary artefact
retirement)
## Stats
`bench/orchestrator-stats/2026-05-14-iter-pd.3.json`
## Note on pre-existing dirty INDEX.md
When this iter dispatched, `docs/journals/INDEX.md` was already
modified in the working tree with one Boss-side line for pd.2 (the
prior iter); that edit was not committed before pd.3 dispatch. This
agent did NOT touch INDEX.md (it is Boss-only per skill discipline).
The Boss should commit the pd.2 INDEX line either with the pd.3
commit or as a separate prior commit — both options are clean.
+2
View File
@@ -67,3 +67,5 @@
- 2026-05-14 — iter rpe.1.tidy: subst.rs preserves Type::Fn modes through rebuild → 2026-05-14-iter-rpe.1.tidy.md
- 2026-05-14 — iter cli-diag-human: WorkspaceLoadError thru diagnostic in non-JSON CLI path → 2026-05-14-iter-cli-diag-human.md
- 2026-05-14 — iter pd.1: core API split — load_modules_with + build_workspace + implicit_imports threading; load_workspace_with kept as 3-line shim so surface unchanged; production literal-"prelude" count in workspace.rs dropped 8→4 → 2026-05-14-iter-pd.1.md
- 2026-05-14 — iter pd.2: surface owns prelude embed (PRELUDE_AIL + parse_prelude in ailang-surface); pd.1 shim load_workspace_with retired along with PRELUDE_JSON / load_prelude / load_one; cross-form-identity preflight PASSED at module_hash 3abe0d3fa3c11c99; production literal-"prelude" in core/src/ now zero → 2026-05-14-iter-pd.2.md
- 2026-05-14 — iter pd.3: prelude.ail.json deleted from working tree; cross-form-identity preflight + supporting bytes deleted from prelude_module_hash_pin (purpose discharged); migrate-bare-cross-module-refs defensive include + lockstep skip-branch deleted; carve_out_inventory.rs §C4(b) row dropped (8→7); form-a-default-authoring spec §C4(b) RETIRED status marker added; new prelude_decouple_carve_out_pin.rs asserts JSON file does not exist; milestone prelude-decouple closed → 2026-05-14-iter-pd.3.md
@@ -267,6 +267,15 @@ Justification per file:
(changing the diagnostic) or refuse to encode at all (changing
the test subject).
> **Status: RETIRED 2026-05-14 by milestone prelude-decouple.** The
> §C4 (b) compile-time-embed carve-out is empty post that milestone;
> the prelude is now authored exclusively as `examples/prelude.ail`
> and parsed at compile time via `ailang_surface::parse_prelude`. The
> original §C4 (b) framing below is preserved as historical context;
> it documents the doctrine inconsistency that prelude-decouple
> resolved. See `docs/specs/2026-05-14-prelude-decouple.md` and the
> per-iter journals 2026-05-14-iter-pd.{1,2,3}.md for the resolution.
**(b) Compile-time-embed carve-outs (one file as of 2026-05-13):**
```