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
+5 -21
View File
@@ -231,9 +231,11 @@ enum Cmd {
///
/// Disambiguation: the first import (in declaration order) that
/// owns a matching type wins. Ties are NOT diagnosed — the
/// migration silently picks the first match. Prelude is consulted
/// as an implicit last-resort fallback when no listed import owns
/// the name.
/// migration silently picks the first match. (The prelude
/// last-resort fallback was retired in pd.3 alongside the
/// `prelude.ail.json` embed; bare cross-module refs that resolve
/// only via the prelude are now left bare and surfaced by the
/// validator instead.)
MigrateCanonicalTypes {
/// Directory containing `*.ail.json` to migrate (typically
/// `examples/`).
@@ -469,20 +471,6 @@ fn main() -> Result<()> {
modules.insert(m.name.clone(), (path, m));
}
// Include the embedded prelude (so the implicit fallback
// matches the loader's behaviour).
let prelude_json: &str = include_str!(
"../../../examples/prelude.ail.json"
);
let prelude: Module = serde_json::from_str(prelude_json)
.expect("embedded prelude must parse");
if !modules.contains_key("prelude") {
modules.insert(
"prelude".to_string(),
(PathBuf::new(), prelude),
);
}
// Pre-pass: per-module local-types index.
let mut local_types: BTreeMap<String, BTreeSet<String>> =
BTreeMap::new();
@@ -497,12 +485,8 @@ fn main() -> Result<()> {
}
// Pass 2: rewrite each module's bare cross-module refs.
// Skip the synthetic prelude entry (no path to write to).
let mut rewritten = 0usize;
for (mod_name, (path, m)) in modules.iter_mut() {
if mod_name == "prelude" && path.as_os_str().is_empty() {
continue;
}
let import_names: Vec<String> =
m.imports.iter().map(|i| i.module.clone()).collect();
let owning = mod_name.clone();