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.
12 KiB
iter pd.3 — prelude.ail.json deleted; prelude-decouple milestone closed
Date: 2026-05-14
Started from: c0dd2bc334
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_validationRELOCATED fromcrates/ailang-core/src/workspace.rs::tests(in-mod) tocrates/ailang-core/tests/workspace_pin.rs(integration crate) instead of the literal call-site swap the plan prescribed. The plan specified "use the fully-qualifiedailang_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 inliningserde_json::from_str(include_str!("prelude.ail.json"))precisely BECAUSEparse_prelude()doesn't typecheck from in-mod (the lib-test target sees two distinctailang-corecompilations and theModuletypes 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 inworkspace.rs::testsdocuments the dev-dep cycle so future maintainers don't try to put the test back. New testload_one_adapterhelper at the top ofworkspace_pin.rsmirrors the in-modload_oneexactly (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_JSONconst,PRELUDE_AILimport,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). Hash3abe0d3fa3c11c99still asserted by the survivingprelude_parse_yields_canonical_hash. Zero orphan-import warnings. First-shot clean. - iter pd.3.3: defensive
include_str!block (12 lines) deleted fromCmd::MigrateCanonicalTypesarm; lockstep skip-branch (4 lines) deleted from the rewrite loop's Pass 2. The plan referenced the subcommand by its variant tagMigrateBareCrossModuleRefsbut the user-facing subcommand name ismigrate-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 onMigrateCanonicalTypes(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--helpoutput. 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-embedcomment 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.rscreated 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!.rsreferences are inert —print_no_leak_pin.rs:110is a string-literal in an assertion message,prelude_injection_pin.rs:28constructs 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.pyexit 0;bench/cross_lang.pyexit 0;bench/check.pyexit 1 with the established noise envelope (thebench_list_sum.bump_sandimplicit_at_rctail-latency oscillation observed since audit-cma — 14th consecutive observation). Acceptance criterion sweep: zeroinclude_str!ofprelude.ail.jsonworkspace-wide; zero literal-"prelude"incrates/ailang-core/src/production scope (the matches inworkspace.rsare 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.mdcarries no production-doctrine assertions about core embedding the prelude or referencingprelude.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 ofparse_prelude()from in-mod. Recommend planner recon-check: when a plan proposes a call-site change involvingailang_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 onMigrateCanonicalTypesmakes the new behaviour visible. The rewrite-helper's prelude-fallback branch at lines ~2436-2446 inmain.rsis now dead-by-construction (thelocal_typesmap 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: thelocal_types.get("prelude")fallback inrewrite_def'srewrite_type_con_owner(or analogue) is dead-by-construction post-pd.3 since thelocal_typesmap for themigrate-canonical-typessubcommand 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 inWorkspaceandRegistryrustdoc — 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-typessubcommand's substantive behaviour (rewriting bare cross-module refs across a directory of.ail.jsonfiles) hasn't been exercised since the canonical-type-names milestone. No in-tree fixtures known to need rewriting today; spot- tested via--helponly. 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, updateMigrateCanonicalTypesdoc-comment to reflect retired prelude-fallback)crates/ailang-core/src/workspace.rs(delete in-modbuild_workspace_accepts_assembled_modules_and_runs_validationtest; 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(addload_one_adapterhelper at top; append the relocated test at end)crates/ailang-surface/tests/prelude_module_hash_pin.rs(delete cross-form-identity preflight + supportingPRELUDE_JSON/PRELUDE_AILreferences; 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 assertingexamples/prelude.ail.jsondoes 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.