Files
AILang/docs/plans/0088-embedding-abi-m3.tidy.md
T
Brummel 832375f2ac convention: counter-prefix file naming across docs/specs/, docs/plans/, design/contracts/, design/models/
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.
2026-05-28 13:31:31 +02:00

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/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.rsform_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 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-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.