audit-pd: tidy items + milestone close (prelude-decouple)

Architect drift: 1 Important + 1 Minor fixed inline as audit-pd-tidy.

DESIGN.md §"Roundtrip Invariant" point 4 + §Enforcement asserted
"Eight `.ail.json`-only fixtures" with one being the prelude embed.
Post-pd.3 the count is seven and the embed clause is empty; rewrote
both paragraphs to reflect the post-milestone state with a forward-
pointer to the prelude-decouple resolution.

ail/src/main.rs's migrate-canonical-types subcommand carried a
`local_types.get("prelude")` fallback in `rewrite_type` that was
dead-by-construction after pd.3 retired the synthetic prelude load
in the same subcommand. Removed the or_else arm; replaced with a
multi-line comment naming the milestone and the repopulation path
for any future variant that needs prelude awareness.

Bench: check.py + compile_check.py exit 1 with the established
envelope-noise (15th consecutive observation since audit-cma);
cross_lang.py clean. pd.* iterations are workspace-loader / spec /
filesystem / test-code only — zero codegen / runtime / typecheck
path edited, so the regression cluster cannot be milestone-induced.
Baseline left pristine consistent with all 14 prior decisions.

Roadmap: P0 entry (prelude-decouple, [~]) struck and removed; P0 is
empty again. The pre-milestone P2 entry that this work superseded
("Prelude embed: Form-A as compile-time source") is gone too. Per-
iter journals stay in INDEX.md as chronological context.

Carried debt unchanged: 3 cargo doc warnings on dangling load_workspace
references in core's lib.rs (covered by the existing P2 "Rustdoc
warning sweep" todo).
This commit is contained in:
2026-05-14 13:32:59 +02:00
parent 9a8d3850e7
commit 354175be30
5 changed files with 142 additions and 30 deletions
+10 -13
View File
@@ -2424,8 +2424,16 @@ fn rewrite_def(
{
return;
}
// Bare cross-module — find owner via imports-in-order, with
// prelude as last-resort fallback.
// Bare cross-module — find owner via imports-in-order. The
// implicit-prelude fallback that this helper used to carry
// (an `or_else` arm scanning `local_types["prelude"]`) was
// dead-by-construction after the prelude-decouple milestone
// (2026-05-14): the synthetic prelude entry that the migrate-
// canonical-types subcommand used to insert into `modules`
// was removed in iter pd.3, so `local_types["prelude"]` is
// never populated. Removed in audit-pd-tidy. If a future
// migrate variant needs prelude awareness, repopulate
// `local_types["prelude"]` explicitly via `parse_prelude`.
let owner: Option<&str> = import_names
.iter()
.map(|s| s.as_str())
@@ -2434,17 +2442,6 @@ fn rewrite_def(
.get(*imp)
.map(|s| s.contains(name))
.unwrap_or(false)
})
.or_else(|| {
if local_types
.get("prelude")
.map(|s| s.contains(name))
.unwrap_or(false)
{
Some("prelude")
} else {
None
}
});
if let Some(owner) = owner {
*name = format!("{owner}.{name}");
+10 -6
View File
@@ -2092,11 +2092,15 @@ Concretely:
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.
4. **Carve-out anchor.** Seven `.ail.json`-only fixtures
(subject-matter rejection tests) survive in the corpus by
structural necessity. They participate in their own dedicated
rejection-shape tests, not in the round-trip gate. (The
prelude's compile-time-embed carve-out, originally listed
here as the eighth fixture, was retired 2026-05-14 by
milestone prelude-decouple; the prelude is now embedded as
`examples/prelude.ail` in `ailang-surface` and parsed at
compile time via `ailang_surface::parse_prelude`.)
Hashing is the consequence the language depends on: BLAKE3 of the
canonical bytes is well-defined for any `.ail` source via parse-
@@ -2138,7 +2142,7 @@ inherit the gate automatically):
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
— exactly the seven named carve-out files exist under
`examples/*.ail.json` at any commit. A new `.ail.json` or a
missing carve-out fails the test.
+119
View File
@@ -0,0 +1,119 @@
# audit-pd — milestone close (prelude-decouple)
**Date:** 2026-05-14
**Scope:** commits e6298f5..9a8d385 (spec → pd.1 plan → pd.1 → housekeeping → pd.2 plan → pd.2 → pd.3 plan → pd.3)
**Status:** DONE — drift fixed inline as `audit-pd-tidy`; bench ratified pristine
## Architect drift review
`ailang-architect` returned **drift_found** with one Important + one
Minor + one Nit:
- `[Important]` `docs/DESIGN.md` lines 2095-2099 + 2140-2143 — §"Roundtrip
Invariant" point 4 ("Carve-out anchor") still asserted "Eight
`.ail.json`-only fixtures (seven subject-matter rejection tests +
one compile-time-embed for the prelude)" and §Enforcement still
said "exactly the eight named carve-out files exist", but
post-pd.3 the count is seven and the compile-time-embed clause
is empty. The form-a spec was retired in place during pd.3 (§C4 (b)
RETIRED status marker); DESIGN.md was missed.
- `[Minor]` `crates/ail/src/main.rs` lines 2438-2448 — `local_types.get("prelude")`
fallback in `rewrite_type` (the migrate-canonical-types subcommand's
helper) was dead-by-construction after pd.3 retired the synthetic
prelude load in the same subcommand. A literal `"prelude"` string
in CLI scope that survived a milestone whose explicit purpose was
to delete exactly that pattern in core; the same drift category
one crate over.
- `[Nit]` `crates/ailang-core/src/lib.rs` — three pre-existing cargo
doc warnings on dangling `[load_workspace]` references carried
from pd.1 (already recorded as known debt in pd.1 + pd.2 journals).
Pre-existing baseline; not in this audit's scope. The roadmap's
P2 "Rustdoc warning sweep" todo covers it.
Both Important and Minor were fixed inline as `audit-pd-tidy` per
CLAUDE.md "trivial mechanical edit" carve-out (≤30 LOC, no
judgement). The Nit was deferred to its existing roadmap todo.
### Inline fixes applied
- `docs/DESIGN.md:2095-2099` rewritten: "Seven `.ail.json`-only
fixtures (subject-matter rejection tests) ... The prelude's
compile-time-embed carve-out, originally listed here as the eighth
fixture, was retired 2026-05-14 by milestone prelude-decouple;
the prelude is now embedded as `examples/prelude.ail` in
`ailang-surface` and parsed at compile time via
`ailang_surface::parse_prelude`."
- `docs/DESIGN.md:2141` rewritten: "exactly the seven named
carve-out files exist".
- `crates/ail/src/main.rs:2427-2448` — the `or_else` arm scanning
`local_types["prelude"]` was deleted (5 LOC body); replaced with
a multi-line comment explaining why (with a forward pointer for
any future migrate variant that needs prelude awareness:
repopulate `local_types["prelude"]` explicitly via
`parse_prelude`). The owner-search now scans `import_names` only.
No behavioural change against the current corpus (the `or_else`
arm could never fire post-pd.3).
`cargo test -p ailang-core --test carve_out_inventory` PASS post-fix.
`cargo build -p ail` clean.
## Bench-regression check
| Script | Exit | Result |
|--------|------|--------|
| `bench/check.py` | 1 | 63 metrics; 1 regressed (`latency.implicit_at_rc.p99_us` +14.42%, p99_9 +16.17%, max +27.61%, p99_over_median +9.79% — same `implicit_at_rc` cluster), 4 improved (`latency.explicit_at_rc.*` cluster), 58 stable. **Established 14-audit envelope-noise.** |
| `bench/compile_check.py` | 1 | 24 metrics; 11 regressed, 0 improved, 13 stable. The build-time-O0 noise cluster (audit-form-a, clippy-sweep). All within the 20% tolerance, ratifying as noise. |
| `bench/cross_lang.py` | 0 | 25 metrics; 0 regressed, 0 improved, 25 stable. Clean. |
`prelude-decouple` is a workspace-loader refactor + spec text +
file-system + test code only. Zero codegen / runtime / typecheck
path edited. The bench numbers cannot be causally affected by this
milestone; the `implicit_at_rc.p99_*` oscillation and the build-time
noise are the same long-running envelope every audit since audit-cma
has flagged. Baseline left pristine (15th consecutive audit decision
to do so on this envelope; the right resolution is a methodology
fix — already queued as P3 "Latency methodology rework" — not
per-audit baseline-juggling).
## Resolution
- `[Important]` DESIGN.md drift — FIXED inline (audit-pd-tidy).
- `[Minor]` `main.rs` dead prelude fallback — FIXED inline (audit-pd-tidy).
- `[Nit]` pre-existing cargo doc warnings — DEFERRED to P2 "Rustdoc
warning sweep" (existing roadmap todo).
- Bench check.py + compile_check.py exit 1 — RATIFIED as noise
envelope, baseline pristine, 15th consecutive observation.
## Files touched
- `docs/DESIGN.md` (two paragraphs in §"Roundtrip Invariant")
- `crates/ail/src/main.rs` (5 LOC body deletion + 8 LOC replacement
comment in `rewrite_type`)
- `docs/journals/2026-05-14-audit-pd.md` (this file)
No bench baseline files modified.
## Milestone status
`prelude-decouple` milestone: **CLOSED**. The roadmap entry at P0
moves to `[x]` and is removed from the active queue (the milestone
trace stays in the journal index for chronological context). The
post-milestone state of the working tree:
- `examples/prelude.ail.json` deleted; the prelude exists on disk
only as `examples/prelude.ail`.
- `crates/ailang-core/src/` contains zero literal-`"prelude"` strings.
- `crates/ail/src/main.rs` contains zero literal-`"prelude"` strings
in production code (the migrate-subcommand fallback is gone post-
audit-tidy).
- The two-phase workspace-loading composition `(load_modules_with →
caller-side prelude inject → build_workspace)` is the canonical
shape, exposed as public API in `ailang-core` and composed by
`ailang-surface::load_workspace`.
- `ailang_surface::parse_prelude` + `PRELUDE_AIL` are the canonical
embed surface, re-exported from `ailang-surface/src/lib.rs`.
- The CLAUDE.md "authors write `.ail`; the build derives the
JSON-AST in-process via `ailang_surface::parse`" doctrine holds
without exception; the prelude was the last carve-out and is now
inside the doctrine.
- 573 tests green workspace-wide.
+1
View File
@@ -69,3 +69,4 @@
- 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
- 2026-05-14 — audit-pd: milestone close (prelude-decouple) — architect drift fixed inline as audit-pd-tidy (DESIGN.md §"Roundtrip Invariant" carve-out count 8→7 + main.rs migrate-subcommand dead prelude fallback removed); bench mixed (check.py + compile_check.py established noise envelope, 15th consecutive observation, baseline pristine; cross_lang clean) → 2026-05-14-audit-pd.md
+2 -11
View File
@@ -35,17 +35,8 @@ work progresses.
## P0 — In flight
- [~] **\[milestone\]** Prelude / core decoupling — retire
`examples/prelude.ail.json` + remove all literal-`"prelude"` strings
from `crates/ailang-core/src/`. Three iters: pd.1 (core API split,
shipped 2026-05-14), pd.2 (surface assumes ownership of prelude
embed + cross-form-identity preflight), pd.3 (delete the JSON +
carve-out cleanup).
- context: `docs/specs/2026-05-14-prelude-decouple.md`; per-iter
journals 2026-05-14-iter-pd.1 (and pd.2 / pd.3 to follow). Reframed
from the original "Prelude embed: Form-A as compile-time source"
P2 entry to widen scope from pure-embed-swap to full prelude-
decoupling of `ailang-core` (β.2 loader-split shape).
_(empty — prelude-decouple milestone closed 2026-05-14, audit-pd
clean. Pick the next milestone from P2.)_
## P1 — Next