Two tasks. Task 1 (atomic): git mv ailang-kernel-stub → ailang-kernel, carve the STUB_AIL Form-A body verbatim into src/kernel_stub/source.ail (incl. the answer (intrinsic) fn — a perturbed byte shifts the .ll snapshots + kernel_stub_module_round_trips), add mod.rs (include_str!) + lib.rs hub (pub use kernel_stub::SOURCE as STUB_AIL), thread all 8 compile sites across 6 files (Cargo package + workspace member + dep-alias + ailang-surface dep + loader.rs use-paths), end with cargo build + cargo test green. Task 2: doc/ledger crate-path honesty fixes (INDEX, CLAUDE.md code-layout + lockstep rows, model 0007) — path-only, retirement narrative left for raw-buf.4. Zero behavioural change; public symbol STUB_AIL preserved via the re-export so ailang-surface + the bijection test bind unchanged. NO raw_buf submodule (that is raw-buf.3). plan-recon mapped 8 compile-breaking sites + 5 doc sites (two beyond the spec's named row list — CLAUDE.md:312 lockstep + model 0007:8,235 — folded in per honesty-rule). Baseline measured this session: 669 passed / 0 failed / 2 ignored (not the stale 667 from the pre-recarve 0105 plan; intrinsic-bodies added 2 tests).
18 KiB
raw-buf.2 — Kernel family-crate rename — Implementation Plan
Parent spec:
docs/specs/0054-raw-buf.mdFor agentic workers: REQUIRED SUB-SKILL: use the
implementskill to run this plan. Steps use- [ ]checkboxes for tracking.
Goal: Rename the crate ailang-kernel-stub → ailang-kernel
and reshape it into a family-crate (a re-export hub src/lib.rs
plus one submodule per kernel-tier module, here just
src/kernel_stub/{mod.rs, source.ail}), with ZERO behavioural
change and NO raw_buf submodule (that is raw-buf.3).
Architecture: A pure crate rename. Task 1 does the atomic,
build-breaking work: git mv the crate dir, carve the embedded
STUB_AIL Form-A text verbatim into src/kernel_stub/source.ail,
add the mod.rs + lib.rs hub, and thread every compile site
(Cargo package name, workspace member + dep-alias, ailang-surface
dep + loader.rs use-paths) — ending with cargo build +
cargo test green. Task 2 fixes the in-tree doc/ledger crate-path
references the honesty-rule requires (no build impact). The
public symbol STUB_AIL is preserved (re-exported from the new
submodule) so ailang-surface and the bijection test bind to it
unchanged.
Tech Stack: Rust (Cargo workspace), crates/ailang-kernel/
(renamed), crates/ailang-surface/ (dep + parse hop), root
Cargo.toml, design/INDEX.md, design/models/0007-kernel-extensions.md,
CLAUDE.md.
Files this plan creates or modifies:
- Create:
crates/ailang-kernel/src/kernel_stub/source.ail— the Form-Akernel_stubmodule text, carved verbatim from the currentSTUB_AILraw string (incl. theanswer(intrinsic)fn). - Create:
crates/ailang-kernel/src/kernel_stub/mod.rs— theSOURCEconst viainclude_str!("source.ail"). - Modify (rewrite):
crates/ailang-kernel/src/lib.rs— becomes the family-crate hub (mod kernel_stub; pub use kernel_stub::SOURCE as STUB_AIL;); replaces the carved-out single-file crate body. (Path arrives viagit mvfromcrates/ailang-kernel-stub/src/lib.rs.) - Modify:
crates/ailang-kernel/Cargo.toml:2— packagename(arrives viagit mv). - Modify:
Cargo.toml:7— workspace member entry. - Modify:
Cargo.toml:37— workspace dep-alias entry. - Modify:
crates/ailang-surface/Cargo.toml:9— dep entry. - Modify:
crates/ailang-surface/src/loader.rs:48,55,56—ailang_kernel_stub→ailang_kernel(rustdoc, call, expect-message) inparse_kernel_stub. - Modify:
design/INDEX.md:112— kernel-extensions Models row crate-path string. - Modify:
CLAUDE.md:52— Code-layout table row (path + role description). - Modify:
CLAUDE.md:312— lockstep-invariant-pairs row, markers-source path string. - Modify:
design/models/0007-kernel-extensions.md:8,235— crate-path strings (path-only; the retirement narrative stays for raw-buf.4).
Task 1: Crate rename + family-crate reshape + all compile sites
This task is atomic: the crate rename breaks the build at 6 files
until every site is threaded, so all compile-breaking edits live
here and the task ends with a green workspace build + test. The
STUB_AIL carve must be byte-verbatim — a single perturbed byte
shifts the kernel_stub-derived codegen symbols in the .ll
snapshots and the kernel_stub_module_round_trips round-trip,
both of which then fail cargo test (the carve's ratification).
Files:
-
Move:
crates/ailang-kernel-stub/→crates/ailang-kernel/ -
Create:
crates/ailang-kernel/src/kernel_stub/source.ail -
Create:
crates/ailang-kernel/src/kernel_stub/mod.rs -
Modify (rewrite):
crates/ailang-kernel/src/lib.rs -
Modify:
crates/ailang-kernel/Cargo.toml:2 -
Modify:
Cargo.toml:7,Cargo.toml:37 -
Modify:
crates/ailang-surface/Cargo.toml:9 -
Modify:
crates/ailang-surface/src/loader.rs:48,55,56 -
Step 1: Move the crate folder.
Run: git mv crates/ailang-kernel-stub crates/ailang-kernel
Expected: the folder rename succeeds; git status shows
renamed: crates/ailang-kernel-stub/Cargo.toml -> crates/ailang-kernel/Cargo.toml
and the same for src/lib.rs.
- Step 2: Carve the
STUB_AILbody verbatim intosource.ail.
The current crates/ailang-kernel/src/lib.rs (just moved) holds
the Form-A text as a raw string at lines 27-41 (line 27 carries
the pub const STUB_AIL: &str = r#" prefix; the string closes
with "#; on line 42). Carve the body — byte-preserving, do NOT
retype — with:
Run:
mkdir -p crates/ailang-kernel/src/kernel_stub
sed -n '27,41p' crates/ailang-kernel/src/lib.rs | sed '1s/^pub const STUB_AIL: &str = r#"//' > crates/ailang-kernel/src/kernel_stub/source.ail
wc -c crates/ailang-kernel/src/kernel_stub/source.ail
Expected: 500 crates/ailang-kernel/src/kernel_stub/source.ail.
The file content is exactly (for verification — the carve, not a
retype, is authoritative; this block is fenced text because the
module name kernel_stub is a reserved built-in and cannot be
ail check-ed standalone — reserved-module-name — so the
parse-gate is N/A; ratification is the verbatim carve + the
kernel_stub_module_round_trips test + cargo test):
(module kernel_stub
(kernel)
(data StubT (vars a)
(ctor Stub a)
(param-in (a Int Float)))
(fn new
(doc "Construct StubT<Int> from an Int. Exercises Term::New end-to-end.")
(type (fn-type (params (con Int)) (ret (con StubT (con Int)))))
(params x)
(body (term-ctor StubT Stub x)))
(fn answer
(doc "Ratifies the intrinsic mechanism end-to-end: codegen intercept answer emits ret i64 42.")
(type (fn-type (params) (ret (con Int))))
(params)
(intrinsic)))
The file ends with a single trailing newline after (intrinsic))).
- Step 3: Create
crates/ailang-kernel/src/kernel_stub/mod.rs.
Write exactly:
//! Kernel-stub submodule — minimal ratifying fixture for the
//! kernel-extension-mechanics milestone (prep.3). The Form-A text
//! lives in the sibling `source.ail`.
//!
//! No domain content. Retired when the `raw-buf` milestone lands
//! its real kernel-tier consumer (raw-buf.4); until then it stays
//! as the ratifying-fixture anchor.
/// Source-of-truth Form-A text for the stub kernel module. Parsed
/// by `ailang_surface::parse_kernel_stub` (and round-trip-pinned by
/// `kernel_stub_module_round_trips` in `design_schema_drift.rs`).
///
/// Ships a `(fn new ...)` def so consumers can spell `(new StubT 42)`
/// (Term::New end-to-end, per prep.3 fieldtest F4) and an `answer`
/// `(intrinsic)` fn whose `INTERCEPTS` entry the bijection test pins.
pub const SOURCE: &str = include_str!("source.ail");
- Step 4: Rewrite
crates/ailang-kernel/src/lib.rsas the family-crate hub.
Replace the entire file contents with exactly:
//! Kernel-tier modules — family-crate hosting the Form-A source of
//! every kernel-tier `.ail` module the AILang workspace
//! auto-injects. One Cargo crate, one Rust submodule per
//! kernel-tier module, one `pub const SOURCE` per submodule.
//!
//! The acyclic dependency chain is preserved:
//! `ailang-surface → ailang-kernel → ailang-core`. Per-module parse
//! hops live in `ailang-surface` (`parse_kernel_stub`, …) so this
//! crate carries zero parser code.
mod kernel_stub;
pub use kernel_stub::SOURCE as STUB_AIL;
- Step 5: Rename the Cargo package.
Edit crates/ailang-kernel/Cargo.toml. Change line 2:
old: name = "ailang-kernel-stub"
new: name = "ailang-kernel"
Leave every other line unchanged (the [dependencies] section
stays empty).
- Step 6: Update the root
Cargo.tomlworkspace member.
Edit Cargo.toml line 7:
old: "crates/ailang-kernel-stub",
new: "crates/ailang-kernel",
- Step 7: Update the root
Cargo.tomlworkspace dep-alias.
Edit Cargo.toml line 37:
old: ailang-kernel-stub = { path = "crates/ailang-kernel-stub" }
new: ailang-kernel = { path = "crates/ailang-kernel" }
- Step 8: Update
crates/ailang-surface/Cargo.tomldep.
Edit crates/ailang-surface/Cargo.toml line 9:
old: ailang-kernel-stub.workspace = true
new: ailang-kernel.workspace = true
- Step 9: Update
crates/ailang-surface/src/loader.rsuse-paths inparse_kernel_stub.
Three edits in the parse_kernel_stub fn (the module name
kernel_stub and the fn name stay — only the crate identifier
ailang_kernel_stub → ailang_kernel changes):
(a) Line 48 (rustdoc):
old: /// Source-of-truth: \ailang_kernel_stub::STUB_AIL`. The stubnew:/// Source-of-truth: `ailang_kernel::STUB_AIL`. The stub`
(b) Line 55 (call):
old: crate::parse(ailang_kernel_stub::STUB_AIL)
new: crate::parse(ailang_kernel::STUB_AIL)
(c) Line 56 (expect-message):
old: .expect("ailang_kernel_stub::STUB_AIL must parse as a Module")
new: .expect("ailang_kernel::STUB_AIL must parse as a Module")
- Step 10: Build the workspace.
Run: cargo build --workspace 2>&1 | tail -8
Expected: build succeeds; zero errors. Cargo.lock is
regenerated automatically (the ailang-kernel-stub entries become
ailang-kernel) — do not hand-edit it. No reference to
ailang-kernel-stub / ailang_kernel_stub remains in any
compiled crate (a dangling ref would be a hard compile error
here).
- Step 11: Run the full workspace test suite — zero behavioural change.
Run: cargo test --workspace 2>&1 | grep -E "^test result:" | awk -F"[: ;]+" '{p+=$4; f+=$6; i+=$8} END{print "passed:",p," failed:",f," ignored:",i}'
Expected: passed: 669 failed: 0 ignored: 2 — the post-intrinsic-bodies baseline (measured this session), unchanged (this iteration is a pure rename; no test is added or removed). In particular kernel_stub_module_round_trips (design_schema_drift), intercepts_bijection_with_intrinsic_markers (codegen), workspace_pin, and the .ll snapshot tests all stay green — they reach STUB_AIL through the preserved re-export and the verbatim-carved source, so the crate rename is invisible to them.
Task 2: Doc/ledger crate-path honesty updates
No build or test impact — these are in-tree, present-tense
references to the old crate path that the rename makes stale. Per
the honesty-rule (design/contracts/0007-honesty-rule.md), a
rename that leaves half its present-state paths stale is an
incomplete rename. Path-only edits; the retirement narrative in
design/INDEX.md / design/models/0007 stays untouched (that is
raw-buf.4 territory).
Files:
-
Modify:
design/INDEX.md:112 -
Modify:
CLAUDE.md:52,CLAUDE.md:312 -
Modify:
design/models/0007-kernel-extensions.md:8,235 -
Step 1: Update
design/INDEX.md:112crate-path.
Edit design/INDEX.md line 112. Change the single occurrence of
the crate path:
old substring: ratified end-to-end by the `ailang-kernel-stub` fixture
new substring: ratified end-to-end by the `ailang-kernel/src/kernel_stub` fixture
Leave the rest of the row (retirement language, milestone status) unchanged.
- Step 2: Rewrite the
CLAUDE.md:52Code-layout row.
Edit CLAUDE.md line 52. Replace the entire row:
old:
| `crates/ailang-kernel-stub/` | Zero-dependency leaf crate carrying only the Form-A source of the `kernel_stub` ratifying-fixture module (`pub const STUB_AIL: &str`). The parse hop (`parse_kernel_stub`) lives in `ailang-surface` to keep the crate-dependency graph acyclic. Injected into every workspace load alongside `prelude`; may be retired when the `raw-buf` milestone lands a real second kernel-tier consumer. |
new:
| `crates/ailang-kernel/` | Family-crate hosting the Form-A source of every kernel-tier `.ail` module, one Rust submodule per module under `src/` (today: `kernel_stub`), each exposing a `pub const SOURCE` re-exported from `src/lib.rs` (`STUB_AIL`). Zero-dependency leaf; parse hops (`parse_kernel_stub`) live in `ailang-surface` to keep the graph acyclic (`ailang-surface → ailang-kernel → ailang-core`). The `kernel_stub` submodule is injected alongside `prelude` and is retired in raw-buf.4 once `raw_buf` becomes the real kernel-tier consumer. |
- Step 3: Update the
CLAUDE.md:312lockstep-pair markers-source path.
Edit CLAUDE.md line 312 (the INTERCEPTS ↔ (intrinsic)
markers row). Change only the kernel-stub markers-source path:
old substring: crates/ailang-kernel-stub/src/lib.rs::STUB_AIL
new substring: crates/ailang-kernel/src/kernel_stub/source.ail
Leave the rest of the row (the examples/prelude.ail reference,
the bijection mechanics, the allowlist language) unchanged.
- Step 4: Update
design/models/0007-kernel-extensions.md:8crate-path.
Edit line 8. Change:
old substring: ratified by the stub kernel crate\n(`crates/ailang-kernel-stub/`)
new substring: ratified by the stub kernel module\n(`crates/ailang-kernel/src/kernel_stub/`)
(The path string crates/ailang-kernel-stub/ → crates/ailang-kernel/src/kernel_stub/; "crate" → "module" because the stub is now a submodule, not its own crate. This is the only edit on this line; the surrounding milestone-status prose stays.)
- Step 5: Update
design/models/0007-kernel-extensions.md:235crate-path.
Edit line 235. Change:
old substring: The ratifying stub kernel module\n(`crates/ailang-kernel-stub/`)
new substring: The ratifying stub kernel module\n(`crates/ailang-kernel/src/kernel_stub/`)
(Path-only; the line already says "module".)
- Step 6: Confirm no stale crate-path references remain in-tree.
Run: git grep -nE 'ailang-kernel-stub|ailang_kernel_stub' -- ':!docs/plans' ':!docs/specs' ':!Cargo.lock'
Expected: no output (exit 1). All present-tense, in-tree
references are updated; history under docs/plans/ and
docs/specs/ (completed plans/specs) and the auto-regenerated
Cargo.lock are deliberately excluded — historical artefacts are
not retro-edited per the honesty-rule.
- Step 7: Final build + test sanity.
Run: cargo test --workspace 2>&1 | grep -E "^test result:" | awk -F"[: ;]+" '{p+=$4; f+=$6; i+=$8} END{print "passed:",p," failed:",f," ignored:",i}'
Expected: passed: 669 failed: 0 ignored: 2 (doc edits do not
touch compiled code or tests; this confirms Task 2 introduced no
accidental source change).
Self-review
-
Spec coverage.
- § Architecture point 2 ("Rename … reshape it as a
family-crate", "carries
src/kernel_stub/{mod.rs, source.ail}", "src/lib.rsre-exports …STUB_AIL", "parse hopparse_kernel_stubstays inailang-surface", "Noraw_bufsubmodule yet"): Task 1 Steps 1-9. - § Components "Kernel family-crate rename" row (git mv,
reshape, Cargo package + member + dep-alias, ailang-surface
dep + loader.rs, design/INDEX.md, CLAUDE.md): Task 1 (code)
- Task 2 (docs).
- § Testing-strategy raw-buf.2 bullet ("All existing tests pass unchanged … zero test-count change … cargo build + cargo test"): Task 1 Steps 10-11.
- § Architecture point 2 ("Rename … reshape it as a
family-crate", "carries
-
Placeholder scan. No "TBD", "TODO", "implement later", "similar to Task", "add appropriate error handling". None present.
-
Type consistency. Symbols across tasks:
STUB_AIL(the preserved re-exported const),SOURCE(submodule const),kernel_stub(module name + submodule name, unchanged),parse_kernel_stub(fn name, unchanged),ailang_kernel(new crate identifier),ailang-kernel(new package name). All consistent. The module namekernel_stub(string) is deliberately NOT renamed — only the crate is. -
Step granularity. Each step is one file edit, one carve, or one command. Task 1 is the largest (11 steps) but must be atomic — the crate rename cannot be half-landed (the build breaks until all 6 compile sites are threaded).
-
No commit steps. None.
-
Pin/replacement substring contiguity. The only presence assertions are:
git grepfor absence of the old crate name (Task 2 Step 6 — asserts NO match, satisfied by the edits in Tasks 1+2) and thewc -c500-byte pin on the carvedsource.ail(Task 1 Step 2). The 500-byte pin is satisfied by the byte-preservingsedcarve, not by a retyped body (thetextreference block is for human verification only, not the carve source). No substring is split across a soft-wrap in any verbatim replacement body. -
Compile-gate vs. deferred-caller ordering. The crate rename's full compile-breaking site set (Cargo package name, workspace member, workspace dep-alias,
ailang-surfacedep,loader.rsuse-path) is enumerated by recon as 8 sites across 6 files; ALL are threaded inside Task 1 before itscargo build --workspacegate (Step 10). No caller is deferred past the gate.Cargo.lockis the only other build-affected file and is auto-regenerated, not hand-threaded. -
Verification-command filter strings. Task 1 Step 11 and Task 2 Step 7 use the unfiltered
cargo test --workspacewith an explicit pass/fail/ignored count assertion (the awk pipeline), so "0 tests ran" cannot masquerade as success. Thegit grepin Task 2 Step 6 asserts absence (empty output); its pattern matched the real sites at recon time, so a regression that reintroduced the old name would re-trigger a match. No bare feature-word test filter is used. -
Parse-the-bytes gate. The one surface-language body the plan inlines (
source.ail, Task 1 Step 2) is thekernel_stubkernel module, whose name is a reserved built-in —ail checkon it standalone returnsreserved-module-name(verified this session), so the configuredailparser cannot validate it in isolation; the block is fencedtext(gate-skipped, reason noted in-step). Its ratification is the byte-verbatim carve from the live, already-building tree plus thekernel_stub_module_round_tripsround-trip and the.llsnapshot tests undercargo test(Task 1 Step 11). All other inlined bodies are Rust (mod.rs,lib.rs) — caught by theimplementcompile gate, not the parse gate.