iter pd.2: surface owns prelude embed; pd.1 shim retired
Moved PRELUDE_AIL const + parse_prelude fn to ailang-surface; re-exported from surface's lib.rs. surface::load_workspace rewritten 3-line shim-call → 7-line composition: load_modules_with → reserved-name check → inject parse_prelude → build_workspace(&["prelude"]). Five deletions in core: PRELUDE_JSON, load_prelude, load_workspace_with (the pd.1 shim), the top-level cfg(test) load_one fn, and the cfg(test) crate::load_module import. Production literal-"prelude" count in crates/ailang-core/src/ is now zero. Cross-form-identity preflight PASSED at module_hash 3abe0d3fa3c11c99 — parse(prelude.ail) ≡ deserialize(prelude.ail.json), so pd.3's deletion of the JSON is safe. Three new pin tests in ailang-surface/tests/: prelude_parse_pin (succeeds + min defs); prelude_module_hash_pin (cross-form-identity + literal-hex anchor); prelude_injection_pin (inject + reservation). Plan deviations (recorded in journal): switched the regression-pin fixture from non-existent examples/hello.ail.json to hello.ail; relocated 10 in-mod core tests to crates/ailang-core/tests/workspace_pin.rs because the dev-dep cycle (core ↔ surface) prevents in-mod aliasing in the lib-test target (form-a.1 T5 precedent); preserved load_one production-symbol-deletion by adding a test-mod-private load_one helper in core's mod tests for the 2 pd.1-introduced tests still consuming it. cargo test --workspace 573 green (+9 net from pd.1 baseline). bench/cross_lang.py + bench/compile_check.py exit 0; bench/check.py exit 1 with established noise envelope (bench_list_sum.bump_s, 13th consecutive observation; pd.2 is workspace-loader-only, no codegen touch — baseline pristine).
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
# iter pd.2 — surface owns prelude embed; pd.1 shim retired
|
||||
|
||||
**Date:** 2026-05-14
|
||||
**Started from:** 116157a2b84a98060c1b6c04eb4ec071fe40eb93
|
||||
**Status:** DONE
|
||||
**Tasks completed:** 6 of 6
|
||||
|
||||
## Summary
|
||||
|
||||
pd.2 moves the prelude embed (`PRELUDE_AIL` const + `parse_prelude` fn) and
|
||||
the prelude-injection step (with the `ReservedModuleName` reservation) out
|
||||
of `ailang-core` into `ailang-surface`, rewires `surface::load_workspace`
|
||||
from the 3-line shim-call into the 7-line composition `(load_modules_with
|
||||
→ reserved-name check → inject parse_prelude → build_workspace(&["prelude"]))`,
|
||||
and retires the pd.1 compatibility shim `core::load_workspace_with` along
|
||||
with `load_one`, `load_prelude`, `PRELUDE_JSON`, and the `#[cfg(test)] use
|
||||
crate::load_module;` import. Cross-form-identity preflight (hash-equality
|
||||
between `parse(prelude.ail)` and `serde_json::from_str(prelude.ail.json)`)
|
||||
PASSES at hash `3abe0d3fa3c11c99` — the load-bearing assumption that
|
||||
justifies pd.3's deletion of `prelude.ail.json` is verified. Production
|
||||
literal-`"prelude"` count in `core/src/` is now zero. Test count: 573
|
||||
green (from the pd.1 baseline of 564, +9 net = 3 new surface pins
|
||||
[parse + hash + injection] + 6 tempdir/fixture relocations to
|
||||
workspace_pin.rs minus 6 in-mod placeholders that became comments;
|
||||
in-mod test deletion of the pd.1 shim test is offset by the
|
||||
`load_modules_with_custom_loader_is_called` rename + 2 pd.1 tests that
|
||||
now use an inline test-private `load_one` helper). `bench/cross_lang.py`
|
||||
+ `bench/compile_check.py` exit 0; `bench/check.py` exit 1 with the
|
||||
12-audit noise envelope (the `bench_list_sum.bump_s` + tail-latency
|
||||
oscillation that has been observed in audits since audit-cma; pd.2 is
|
||||
a workspace-loader refactor with zero codegen / runtime touch). pd.3
|
||||
will delete `examples/prelude.ail.json` plus the
|
||||
`prelude_ail_and_json_parse_to_identical_module` preflight, the
|
||||
`include_str!` carve-out in `crates/ail/src/main.rs:472-484`, the
|
||||
`carve_out_inventory.rs` §C4(b) row, the form-a §C4(b) spec text, and
|
||||
the `migrate-bare-cross-module-refs` defensive include.
|
||||
|
||||
## Per-task notes
|
||||
|
||||
- iter pd.2.1: `pub const PRELUDE_AIL: &str = include_str!("../../../examples/prelude.ail");`
|
||||
+ `pub fn parse_prelude() -> Module` added near the top of
|
||||
`crates/ailang-surface/src/loader.rs`; both re-exported from
|
||||
`ailang-surface/src/lib.rs`. RED test
|
||||
`parse_prelude_returns_module_named_prelude_with_min_defs` failed
|
||||
with the expected unresolved-import message, then GREEN. First-shot
|
||||
clean.
|
||||
- iter pd.2.2: `crates/ailang-surface/tests/prelude_module_hash_pin.rs`
|
||||
with `prelude_ail_and_json_parse_to_identical_module` (cross-form-
|
||||
identity preflight, load-bearing for pd.3) + `prelude_parse_yields_canonical_hash`
|
||||
(literal-hex anchor). Preflight PASSED first-run (the round-trip
|
||||
invariant from form-a.0 + form-a.1 was already exercising
|
||||
parse-then-print idempotency on every `.ail` fixture, so
|
||||
parse(prelude.ail) ≡ deserialize(prelude.ail.json) was not an
|
||||
accident). Hash `3abe0d3fa3c11c99` captured at pd.2 close.
|
||||
- iter pd.2.3: `surface::load_workspace` rewritten 3-line → 7-line
|
||||
composition; imports updated `load_workspace_with` → bare
|
||||
`Workspace, WorkspaceLoadError` with `load_modules_with` /
|
||||
`build_workspace` fully-qualified inline; module rustdoc rewritten
|
||||
to name the new injection point + the implicit-imports list.
|
||||
Regression-pin tests `surface_load_workspace_injects_prelude_into_every_workspace`
|
||||
+ `surface_load_workspace_rejects_user_module_named_prelude` PASS
|
||||
before AND after the rewrite (semantics preserved). DONE_WITH_CONCERNS:
|
||||
the plan's example used `examples/hello.ail.json` which doesn't
|
||||
exist post-form-a.1 (deleted in T8); switched to `examples/hello.ail`.
|
||||
- iter pd.2.4: 10 in-mod tests RELOCATED to
|
||||
`crates/ailang-core/tests/workspace_pin.rs` rather than aliased per
|
||||
the plan's literal text — the dev-dep cycle (`ailang-core` ↔
|
||||
`ailang-surface` via `[dev-dependencies]`) makes
|
||||
`surface::load_workspace` calls from `ailang-core`'s lib-test crate
|
||||
structurally impossible (two distinct compilations of `ailang-core`
|
||||
appear in the test build, types don't match). The integration-test
|
||||
crate consumes both crates against the same `ailang-core` artefact,
|
||||
so the cycle never materialises — same pattern form-a.1 T5 used for
|
||||
similar relocations. The 11th test (`load_workspace_with_custom_loader_is_called`)
|
||||
renamed to `load_modules_with_custom_loader_is_called` with the
|
||||
closure adapted to wrap `crate::load_module` directly via the same
|
||||
Io/Schema mapping `load_one` had. The 12th test
|
||||
(`load_workspace_with_shim_preserves_today_semantics`) deleted
|
||||
outright with a forwarding comment to the surface-side hash pin.
|
||||
- iter pd.2.5: 5 deletions (`PRELUDE_JSON`, `load_prelude`,
|
||||
`load_workspace_with`, top-level `load_one`, `#[cfg(test)] use
|
||||
crate::load_module;`); module rustdoc reworked to two-phase
|
||||
composition framing; lib.rs three rustdoc sites (lines 16-21, 50-51,
|
||||
120) re-pointed at `ailang_surface::load_workspace`. ONE plan-vs-actual
|
||||
deviation: the plan didn't enumerate the 2 pd.1-introduced in-mod
|
||||
tests at the bottom of `mod tests` that consume `load_one` directly
|
||||
(`load_modules_with_returns_modules_without_prelude`,
|
||||
`build_workspace_accepts_assembled_modules_and_runs_validation`);
|
||||
preserved by adding a test-mod-private `load_one` helper inside `mod
|
||||
tests` (production-symbol-level deletion preserved; helper is
|
||||
scoped only to the test module, not exported). The
|
||||
`build_workspace...` test also called `load_prelude()` directly;
|
||||
replaced inline with `serde_json::from_str(include_str!(...))` of
|
||||
`prelude.ail.json` (the same one-line code `load_prelude` was). Zero
|
||||
literal-`"prelude"` strings in production `core/src/` confirmed by
|
||||
grep. cargo doc warnings: 3 (unchanged from pre-pd.2 baseline; all
|
||||
three are dangling `[`load_workspace`]` references in the `Workspace`
|
||||
/ `Registry` rustdoc that pd.1 left behind when it deleted
|
||||
`load_workspace`; out of scope per the implementer's
|
||||
no-surrounding-cleanup discipline, recorded as known debt).
|
||||
- iter pd.2.6: bench verification — `cross_lang.py` exit 0 (25/25
|
||||
stable), `compile_check.py` exit 0 (24/24, "11 regressed" reported
|
||||
but exit code says baseline-tolerance check passes — this is the
|
||||
audit-form-a + clippy-sweep-named noise on the corpus's small build
|
||||
fixtures), `check.py` exit 1 with 1 regression on `bench_list_sum.bump_s`
|
||||
+13.61% (within established noise envelope; second run showed
|
||||
same `bump_s` plus a tail-latency `implicit_at_rc.p99_us` blip).
|
||||
All three are runtime/compile metrics that cannot be touched by a
|
||||
workspace.rs/loader.rs/lib.rs refactor (no codegen / no runtime /
|
||||
no typecheck path edited).
|
||||
|
||||
## Concerns
|
||||
|
||||
- pd.2.3: plan's regression-pin used `examples/hello.ail.json` which
|
||||
doesn't exist post-form-a.1 T8. Switched to `examples/hello.ail`.
|
||||
Recommend a planner check: when a plan references a `.ail.json`
|
||||
fixture, verify the fixture exists post-form-a.1 (the carve-out
|
||||
inventory is the right reference).
|
||||
- pd.2.4: plan's "alias to surface_load_workspace and stay in-mod" was
|
||||
structurally invalid because of the `ailang-core` ↔ `ailang-surface`
|
||||
dev-dep cycle inside the lib-test target. Relocated to
|
||||
`tests/workspace_pin.rs` instead — same pattern form-a.1 T5 used.
|
||||
Recommend: planner recon-check should detect when a planned in-mod
|
||||
test is meant to consume an external dev-dep cycle that the lib-test
|
||||
target can't resolve.
|
||||
- pd.2.5: plan's "delete `load_one`" preserved at production-symbol
|
||||
level (the top-level `#[cfg(test)] fn load_one` is gone) by
|
||||
introducing a test-mod-private `fn load_one` helper inside `mod
|
||||
tests` for the 2 pd.1 in-mod tests that still consume it. The
|
||||
symbol's name is preserved for clarity; its scope is now narrower
|
||||
than pre-pd.2.
|
||||
- pd.2.6: `check.py` exit 1 — established noise envelope, 13th
|
||||
consecutive observation pattern (audit-cma onwards). pd.2 is a
|
||||
workspace-loader refactor with zero codegen / runtime / typecheck
|
||||
touch, so cannot be the source. Baseline left pristine consistent
|
||||
with all prior audit decisions on this envelope.
|
||||
|
||||
## Known debt
|
||||
|
||||
- 3 cargo doc warnings on `[`load_workspace`]` references in the
|
||||
`Workspace` (line 44, 49) + `Registry` (line 64) rustdoc — pd.1
|
||||
deleted `load_workspace` but didn't sweep these references. Pre-
|
||||
pd.2 baseline already carried them; pd.2 didn't add to the count;
|
||||
not within pd.2 scope (no-surrounding-cleanup discipline).
|
||||
- pd.3 work explicitly out of scope: deleting `examples/prelude.ail.json`,
|
||||
the `prelude_ail_and_json_parse_to_identical_module` preflight test
|
||||
(which depends on the JSON file's existence), the `include_str!` of
|
||||
`prelude.ail.json` in `crates/ail/src/main.rs:472-484`, the
|
||||
`carve_out_inventory.rs` §C4(b) row, the form-a §C4(b) spec text
|
||||
edits, and the `migrate-bare-cross-module-refs` defensive include.
|
||||
|
||||
## Files touched
|
||||
|
||||
Modified:
|
||||
- `crates/ailang-core/src/lib.rs` (3 rustdoc sites updated)
|
||||
- `crates/ailang-core/src/workspace.rs` (5 deletions + module rustdoc
|
||||
reframe + 2 pd.1 in-mod test repairs + 6 in-mod test placeholders +
|
||||
test-mod-private `load_one` helper restored at narrow scope)
|
||||
- `crates/ailang-core/tests/workspace_pin.rs` (10 relocated tests
|
||||
appended + helper fn `write_simple_module_json` + preamble extension)
|
||||
- `crates/ailang-surface/src/lib.rs` (re-export of `parse_prelude` +
|
||||
`PRELUDE_AIL`)
|
||||
- `crates/ailang-surface/src/loader.rs` (`PRELUDE_AIL` const +
|
||||
`parse_prelude` fn added; `load_workspace` body 3-line → 7-line
|
||||
composition rewrite; module rustdoc reframed; imports updated)
|
||||
|
||||
New:
|
||||
- `crates/ailang-surface/tests/prelude_parse_pin.rs` (1 test)
|
||||
- `crates/ailang-surface/tests/prelude_module_hash_pin.rs` (2 tests:
|
||||
cross-form-identity preflight + literal-hex anchor `3abe0d3fa3c11c99`)
|
||||
- `crates/ailang-surface/tests/prelude_injection_pin.rs` (2 tests:
|
||||
inject + reservation pin)
|
||||
|
||||
## Stats
|
||||
|
||||
`bench/orchestrator-stats/2026-05-14-iter-pd.2.json`
|
||||
Reference in New Issue
Block a user