832375f2ac
All 176 files in the four accumulating directories now use a zero-padded 4-digit counter prefix that reflects creation order (`NNNN-slug.md`). The counter is assigned per directory in strict git-log creation order; ties broken alphabetically by original name. The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is dropped — the date is recoverable from git log and the counter carries the ordering. A file's counter is stable for the life of the file: never reassigned, never reused, never compacted. Deleted files retire their counter; subsequent files do not fill the gap. This is the property that lets cross-references stay literal — refs use the full filename including the counter (`design/contracts/0007-honesty-rule.md`) so they grep cleanly and resolve directly without a glob step. 313 cross-references updated across .md/.rs/.toml/.c/.json files (test pins, include_str! paths, design-INDEX entries, baseline notes, runtime C comments, inter-contract markdown links incl. bare basename and `../models/foo.md` forms). CLAUDE.md gets a new "File-naming convention" section spelling out the rule and rationale. skills/brainstorm/SKILL.md and skills/planner/SKILL.md updated so new spec/plan creation produces counter-prefixed names from the start. The full test suite (cargo test --workspace) passes.
248 lines
11 KiB
Markdown
248 lines
11 KiB
Markdown
# Embedding ABI — M3.tidy — Implementation Plan
|
|
|
|
> **Parent spec:** `docs/specs/0043-embedding-abi-m3.md`
|
|
> (the milestone whose §"Embedding ABI" surface this reconciles);
|
|
> scoping source-of-truth: `docs/journals/2026-05-18-audit-embedding-abi-m3.md`.
|
|
>
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
|
|
> to run this plan. Steps use `- [ ]` checkboxes for tracking.
|
|
|
|
**Goal:** Reconcile the two M3-audit doc-honesty DRIFT items —
|
|
a self-contradicting M1-era parenthetical in DESIGN.md §"Embedding
|
|
ABI" and a stale forwarder-body comment — to present-tense current
|
|
state, pin-safe, with zero language/checker/codegen behaviour change.
|
|
|
|
**Architecture:** Two independent, surgical text edits. (1)
|
|
`docs/DESIGN.md:2300-2301` — replace *only* the parenthetical
|
|
`(modes apply only to heap-shaped types, which the scalar-only rule
|
|
above forbids at an export boundary anyway)`, which now contradicts
|
|
the M3 frozen-layout SSOT (a single-ctor record IS an accepted
|
|
export type) and the `(own/borrow (con T))` mode contract; the
|
|
`docs_honesty_pin.rs:135`-pinned sentence words on `:2299-2300`
|
|
(`norm()`-whitespace-collapsed) are kept verbatim-present. (2)
|
|
`crates/ailang-codegen/src/lib.rs:608-610` — a comment-only honesty
|
|
fix (no test pins it; the IR byte-pins assert generated code, not
|
|
source comments). The four standing pins bracket both edits green.
|
|
|
|
**Tech Stack:** `docs/DESIGN.md`, `crates/ailang-codegen/src/lib.rs`
|
|
(comment only); regression gates in `ailang-core`
|
|
(`docs_honesty_pin`, `design_schema_drift`) and `ailang-codegen`
|
|
(`embed_record_layout_pin`, `embed_staticlib_lowering`).
|
|
|
|
---
|
|
|
|
## Files this plan creates or modifies
|
|
|
|
- Modify: `docs/DESIGN.md:2300-2301` — replace the contradicted M1-era parenthetical only (pinned sentence words on `:2299-2300` untouched; `:2302` kept)
|
|
- Modify: `crates/ailang-codegen/src/lib.rs:608-610` — forwarder-body comment honesty (comment-only, no IR change)
|
|
- Test (gate, unmodified): `crates/ailang-core/tests/docs_honesty_pin.rs` — `form_a_scalar_param_carveout_present_and_old_rule_absent` stays GREEN (pinned sentence words survive)
|
|
- Test (gate, unmodified): `crates/ailang-core/tests/design_schema_drift.rs` — stays GREEN (no schema-drift anchor moves)
|
|
- Test (gate, unmodified): `crates/ailang-codegen/tests/embed_record_layout_pin.rs` + `embed_staticlib_lowering.rs` — stay GREEN (comment edit changes no IR)
|
|
|
|
---
|
|
|
|
## Task 1: Reconcile the contradicted DESIGN.md parenthetical (`[medium]`)
|
|
|
|
The stale clause is strictly the parenthetical spanning the back of
|
|
`:2300` and the front of `:2301`. The pinned sentence
|
|
("Export parameters are written **bare**: a scalar type carries no
|
|
`own`/`borrow` mode", `docs_honesty_pin.rs:135`, `norm()`-collapsed)
|
|
occupies `:2299` + the front of `:2300` and MUST keep all its words
|
|
(planner Step-5 item-6: presence-pin vs. verbatim-edit collision —
|
|
the M2.tidy discipline). The edit replaces only the parenthetical's
|
|
words; it does not touch `:2299`, the pinned-sentence words on
|
|
`:2300`, the `. The` connective, or `:2302`.
|
|
|
|
**Files:**
|
|
- Modify: `docs/DESIGN.md:2300-2301`
|
|
- Test: `crates/ailang-core/tests/docs_honesty_pin.rs` (gate, unmodified)
|
|
|
|
- [ ] **Step 1: Baseline — the pin is GREEN before the edit**
|
|
|
|
Run: `cargo test -p ailang-core --test docs_honesty_pin form_a_scalar_param_carveout_present_and_old_rule_absent -- --exact`
|
|
Expected: PASS, `1 passed` (the pinned "written **bare**" sentence
|
|
present; baseline before the edit).
|
|
|
|
Run: `grep -n 'modes apply only to heap-shaped types' docs/DESIGN.md`
|
|
Expected: one hit on line `2300` (confirms the stale clause is
|
|
present and located exactly where recon mapped it; if the line
|
|
number differs, re-locate before editing — the edit is by verbatim
|
|
string, not line number, so a shift is non-fatal but must be noted).
|
|
|
|
- [ ] **Step 2: Replace only the parenthetical (verbatim edit)**
|
|
|
|
In `docs/DESIGN.md`, the current text of lines `:2300-2301` is
|
|
exactly (two lines, soft-wrapped):
|
|
|
|
```
|
|
`own`/`borrow` mode (modes apply only to heap-shaped types, which the
|
|
scalar-only rule above forbids at an export boundary anyway). The
|
|
```
|
|
|
|
Replace that exact two-line block with:
|
|
|
|
```
|
|
`own`/`borrow` mode (a single-constructor record export parameter,
|
|
by contrast, carries `own`/`borrow` — the ownership contract the
|
|
frozen value layout below specifies). The
|
|
```
|
|
|
|
This (a) keeps the pinned-sentence words `own`/`borrow` mode`
|
|
contiguous with `:2299`'s `Export parameters are written **bare**: a
|
|
scalar type carries no` (the `norm()` pin only needs the *words*
|
|
present, in any wrapping — verified: `docs_honesty_pin.rs:21-26`);
|
|
(b) removes exactly the false clause (post-M3 the export boundary
|
|
*accepts* a single-ctor record — a heap-shaped type — so "the
|
|
scalar-only rule above forbids" is no longer true and contradicted
|
|
`:2280-2284` + the mode contract at `:2345-2351`); (c) replaces it
|
|
with the present-tense truth that points at the new SSOT; (d)
|
|
preserves the `. The` connective and `:2302`
|
|
`canonical M1 export shape:` untouched (audit did not flag `:2302`;
|
|
scope discipline — fix only the flagged contradiction).
|
|
|
|
- [ ] **Step 3: The stale clause is gone, the pin still GREEN**
|
|
|
|
Run: `grep -n 'scalar-only rule above forbids' docs/DESIGN.md`
|
|
Expected: no output (the contradicted clause is removed).
|
|
|
|
Run: `cargo test -p ailang-core --test docs_honesty_pin`
|
|
Expected: PASS, `5 passed` — in particular
|
|
`form_a_scalar_param_carveout_present_and_old_rule_absent` stays
|
|
GREEN (the pinned sentence's words survived the edit). **If RED:
|
|
STOP, restore the file (`git checkout -- docs/DESIGN.md`), and
|
|
re-scope the edit to leave every pinned-sentence word in place —
|
|
do not push past a RED pin (planner Step-5 item-6).**
|
|
|
|
- [ ] **Step 4: No schema-drift anchor moved**
|
|
|
|
Run: `cargo test -p ailang-core --test design_schema_drift`
|
|
Expected: PASS, `8 passed` — the parenthetical is prose, not a
|
|
JSON-schema-drift anchor; the count is byte-unchanged from the
|
|
recon-confirmed baseline.
|
|
|
|
---
|
|
|
|
## Task 2: Honesty-fix the stale forwarder-body comment (`[low]`)
|
|
|
|
`crates/ailang-codegen/src/lib.rs:608-610` is a comment-only block
|
|
inside the `Target::StaticLib` arm asserting the gate guarantees
|
|
`Int`/`Float`-only — false post-M3 (a gate-guaranteed single-ctor
|
|
record lowers to `ptr`). Recon tree-wide-grep-confirmed **no test
|
|
pins this comment text**; the byte-pin and forwarder-IR pin assert
|
|
emitted IR, not source comments, so this edit changes no generated
|
|
code. First code/IR line is `:618` — `:608-610` are comment-only.
|
|
|
|
**Files:**
|
|
- Modify: `crates/ailang-codegen/src/lib.rs:608-610`
|
|
- Test: `crates/ailang-codegen/tests/embed_record_layout_pin.rs` + `embed_staticlib_lowering.rs` (gate, unmodified)
|
|
|
|
- [ ] **Step 1: Baseline — the IR pins are GREEN before the edit**
|
|
|
|
Run: `cargo test -p ailang-codegen --test embed_record_layout_pin --test embed_staticlib_lowering`
|
|
Expected: PASS, `1 passed` + `3 passed` (the byte-pin
|
|
`heap_box_layout_is_frozen_8_plus_n_times_8_tag_at_0_fields_from_8`
|
|
and the forwarder-IR pins
|
|
`staticlib_emits_forwarder_no_main` /
|
|
`staticlib_record_forwarder_is_ptr_passthrough` /
|
|
`executable_target_still_emits_main` — the guard that generated
|
|
code is untouched by a comment edit).
|
|
|
|
- [ ] **Step 2: Replace the stale comment (verbatim edit)**
|
|
|
|
In `crates/ailang-codegen/src/lib.rs`, the current text of lines
|
|
`:608-610` is exactly:
|
|
|
|
```
|
|
// The check-side gate (Task 4) guarantees every param
|
|
// and the ret are `Int`/`Float`; map Int→i64,
|
|
// Float→double. M1 scalar fns have no captured env, so
|
|
```
|
|
|
|
Replace that exact three-line block with:
|
|
|
|
```
|
|
// The check-side export gate guarantees every param and
|
|
// the ret are `Int`/`Float` or a single-constructor
|
|
// record of those (M3); map Int→i64, Float→double, a
|
|
// record → ptr. Scalar fns have no captured env, so
|
|
```
|
|
|
|
(Honesty-only: the gate now accepts a single-ctor scalar record →
|
|
`ptr`; the trailing "…have no captured env, so" continuation on
|
|
`:610`'s tail is preserved as a clause start for the unchanged
|
|
following line. Removed the stale `M1` qualifier on the env clause
|
|
in passing — it is the *same* sentence the gate-rule fix rewrites,
|
|
so it is in-scope contiguous text, not scope creep.)
|
|
|
|
- [ ] **Step 3: Generated code is byte-unchanged (IR pins GREEN)**
|
|
|
|
Run: `cargo test -p ailang-codegen --test embed_record_layout_pin --test embed_staticlib_lowering`
|
|
Expected: PASS, `1 passed` + `3 passed` — identical to Step 1; a
|
|
comment edit emits no IR delta. **If any IR pin goes RED the edit
|
|
touched code, not just a comment — STOP and restore
|
|
(`git checkout -- crates/ailang-codegen/src/lib.rs`).**
|
|
|
|
- [ ] **Step 4: The crate still builds + full codegen suite GREEN**
|
|
|
|
Run: `cargo test -p ailang-codegen 2>&1 | tail -1`
|
|
Expected: the final line shows `test result: ok` with `0 failed`
|
|
(comment-only change; the whole codegen crate is unaffected).
|
|
|
|
---
|
|
|
|
## Task 3: Milestone-close verification gate
|
|
|
|
Not a code change — the consolidated proof that the tidy removed the
|
|
drift and moved nothing else.
|
|
|
|
**Files:** none (verification only).
|
|
|
|
- [ ] **Step 1: Both stale phrases are gone tree-wide**
|
|
|
|
Run: `grep -rn 'scalar-only rule above forbids' docs/DESIGN.md ; grep -n 'guarantees every param' crates/ailang-codegen/src/lib.rs`
|
|
Expected: no output from either grep (both audit-flagged stale
|
|
fragments removed).
|
|
|
|
- [ ] **Step 2: The four standing pins + workspace GREEN**
|
|
|
|
Run: `cargo test -p ailang-core --test docs_honesty_pin --test design_schema_drift -p ailang-codegen --test embed_record_layout_pin --test embed_staticlib_lowering`
|
|
Expected: PASS — `docs_honesty_pin` 5, `design_schema_drift` 8,
|
|
`embed_record_layout_pin` 1, `embed_staticlib_lowering` 3 (every
|
|
count identical to the recon-confirmed baseline; the tidy moved no
|
|
pin).
|
|
|
|
Run: `cargo test --workspace 2>&1 | grep -oE '[0-9]+ passed' | awk '{s+=$1} END{print s" passed across "NR" suites"}'`
|
|
Expected: `639 passed across 77 suites` (the M3-DONE baseline,
|
|
byte-unchanged — a docs/comment tidy adds no tests and regresses
|
|
none; if the number differs from 639 the tidy had an unintended
|
|
behaviour effect — STOP and investigate).
|
|
|
|
- [ ] **Step 3: The diff is exactly two files, no behaviour change**
|
|
|
|
Run: `git diff --stat`
|
|
Expected: exactly `docs/DESIGN.md` (a few lines) and
|
|
`crates/ailang-codegen/src/lib.rs` (3 comment lines) changed — no
|
|
`.ail`, no fixture, no test, no schema, no other source. (The
|
|
journal + INDEX line are Boss-added at commit, not implement-tree.)
|
|
|
|
---
|
|
|
|
## Notes for the implement orchestrator
|
|
|
|
- **No audit/fieldtest gate after this tidy.** The four pins ARE the
|
|
regression coverage (the M2.tidy precedent: a docs/test-string
|
|
tidy's guard is the docs_honesty_pin + the IR pins, Boss-verified
|
|
before and after — no fresh architect/bench). Record in the
|
|
per-iter journal that this closes the M3 audit's `[medium]`+`[low]`
|
|
drift and that bench was already carry-on (causally exonerated at
|
|
the audit, NO ratify).
|
|
- **Pin-safety is the whole point of Task 1.** The pinned sentence
|
|
shares a physical line with the stale clause; the only safe edit
|
|
is *replace the parenthetical, keep every pinned word*. A
|
|
free-rewrite of the `:2299-2302` line range is a plan violation —
|
|
Step 3's RED→STOP→restore is mandatory, not advisory.
|
|
- **Boss-only-commits / main-sacrosanct.** Leave both edits + the
|
|
per-iter journal + stats uncommitted in the working tree; the
|
|
Boss inspects `git diff`, commits the tidy, flips roadmap M3
|
|
`[~]`→`[x]`, and adds the INDEX.md line.
|