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.
11 KiB
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/implementto 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-2300untouched;:2302kept) - 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_absentstays 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 modecontiguous with:2299's Export parameters are written bare: a
scalar type carries no(thenorm()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 . Theconnective 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-2302line 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.