Files
AILang/docs/journals/2026-05-18-audit-embedding-abi-m3.md
T

6.7 KiB
Raw Blame History

audit Embedding ABI — M3 (milestone close)

Date: 2026-05-18 Milestone range: 9a609ae..4ea8bc5 (M2 roadmap-close → M3 DONE) Outcome: DRIFT — one [medium] + one [low] doc-honesty item → a single docs-honesty tidy iteration; bench check.py exit 1 decisively causally exonerated (byte-identical generated IR), NO ratify. compile_check / cross_lang clean.

Step 1 — Architect drift review (drift_found)

Dispatched ailang-architect over 9a609ae..HEAD.

What holds (audited clean):

  • Invariant 1 (clean core): zero Cargo.toml/runtime dep changes; ailang-core/ailang-codegen/runtime/ touches are only the spec-scoped widen + lockstep comments + pins. No data-server/finance knowledge entered.
  • M1/M2 internal-convention byte-invariant held: the M2 Target::StaticLib forwarder body and the internal @ail_<mod>_<fn> / _adapter / _clos convention are absent from the diff (untouched). The llvm_scalar / is_c_abi_type widen is exactly the spec scope — no new CheckError variant, no schema field, no Form-A change (M2-style honoured).
  • Frozen-layout SSOT consistent: DESIGN.md ### Frozen value layout (:2321-2359) is present-tense and matches both match_lower.rs lower_ctor (size = 8 + n*8, tag@0, fields@8+i*8) and the enforcing byte-pin (@ailang_rc_alloc(i64 24), tag@0, @8/@16). All three lockstep // FROZEN ABI pointers present and aimed at the SSOT. The Boss spec-consistency repair note + §"Testing strategy" 3/4 + the journal Boss-adjudication / Re-dispatch sections are mutually consistent and honest about the M2-TLS cross-attribution (correct behaviour, not a leak).

Drift / debt:

  • [medium] docs/DESIGN.md:2299-2302 — a surviving M1-era paragraph still asserts modes "apply only to heap-shaped types, which the scalar-only rule above forbids at an export boundary anyway". :2280-2284 was rewritten to accept a single-ctor record, so there is no longer a scalar-only rule; this sentence now contradicts the section's own freeze and the (own (con State))/(borrow (con State)) mode contract at :2345-2351. Canonical-spec internal contradiction the milestone owned. → fix (docs-honesty tidy).
  • [low] crates/ailang-codegen/src/lib.rs:608-610 — the forwarder-body comment still says the gate "guarantees every param and the ret are Int/Float; map Int→i64, Float→double", now false (records→ptr). The architect classified this "carried debt, not a scope miss" — the forwarder body is contractually byte-frozen, so the comment was genuinely outside any M3 edit region. Comment-only; correcting it changes no emitted IR (the byte-pin + forwarder-IR pin assert IR, not source comments). → fix, folded into the same tidy (doc-honesty hygiene; the IR pins are the guard that generated code stays byte-frozen).

(Boss already caught + fixed in-line one sibling stale // gate-comment block at check/lib.rs:1917-1922 during the DONE inspect; the architect found no further siblings.)

Step 2 — Bench-regression trio

script exit summary
bench/check.py 1 63 metrics; 3 regressed, 2 improved, 58 stable
bench/compile_check.py 0 24 metrics; 0 regressed, 24 stable
bench/cross_lang.py 0 25 metrics; 0 regressed, 25 stable (every rc_over_c within tol)

check.py exit 1 — the 3 firings:

metric baseline actual diff tol
throughput.bench_list_sum.bump_s 0.046 0.052 +12.62% 10.0%
latency.implicit_at_rc.p99_9_us 452.0 580.6 +28.45% 25.0%
latency.implicit_at_rc.max_us 477.3 645.2 +35.18% 30.0%

Both are the two standing tracked P2 noise families (roadmap P2): the *.bump_s stale-baseline (~+513% environmental band on current hardware) and the *.max_us/p99_9 -n 5 tail-jitter structural false-positive (signature: same benchmark's median_us +5.11% ok, p99_us +15.08% ok — only the extreme tail quantiles fire, the worst-of-~5000-samples-over-5-runs pattern).

Causal exoneration (decisive, not hand-waved — M2-audit method). M3 changed no executable-path codegen (architect-confirmed: M2 forwarder body byte-unchanged; the only codegen touches are the llvm_scalar record→ptr arm — reachable solely for an (export) single-ctor record, and no bench_* program has an (export) — the ailang-check is_c_abi_type widen, and lockstep comments). Built ail at HEAD and at the pre-M3 commit 9a609ae in an isolated worktree; the generated IR is byte-identical (cmp -s) for every firing benchmark and its neighbours:

bench_list_sum:          IR BYTE-IDENTICAL (HEAD == 9a609ae)
bench_list_sum_explicit:  IR BYTE-IDENTICAL
bench_latency_implicit:   IR BYTE-IDENTICAL
bench_tree_walk:          IR BYTE-IDENTICAL

The IR is what is handed to clang -O2 (deterministic), so the bench binaries are byte-identical and M3 causation is logically impossible. NO baseline ratify (these are not M3 artefacts; the two P2 items stay separately tracked). Bench → carry-on.

Step 3 — Classification

item class recommendation
[medium] DESIGN.md:2299-2302 scalar-only-rule contradiction drift fix — docs-honesty tidy
[low] codegen forwarder-comment Int/Float-only staleness drift fix — folded into the same tidy
check.py exit 1 (3 firings) tracked-noise carry-on, NO ratify (byte-identical-IR causal exoneration)
compile_check / cross_lang clean carry-on

Step 4 — Resolution (Boss)

  • Drift → one docs-honesty tidy iteration embedding-abi-m3.tidy (the M2-audit [medium]+[low] doc-honesty → tidy precedent shape): reconcile the stale DESIGN.md:2299-2302 "scalar-only rule above forbids" paragraph against the frozen SSOT + the own/borrow mode contract, pin-safe (the docs_honesty_pin.rs:135 pinned sentence — "Export parameters are written bare…", shifted to ~:2299 by the M3.1 DONE — sits in/adjacent to the edit zone; the tidy plan must keep it byte-verbatim+contiguous, planner Step-5 item-6 / M2.tidy precedent); plus the [low] codegen forwarder-comment honesty fix (comment-only, the byte-pin + forwarder-IR pin stay green as the guard that generated code is untouched). Routed via plannerimplement.
  • Bench → carry-on, NO ratify. Causally exonerated; the two tracked P2 noise todos stay as-is.

Milestone is substantively closed + sound (record crosses the C ABI in/out, ownership follows the declared mode, the value layout is frozen + byte-pin-enforced, all contract invariants held, Invariant 1 clean). The roadmap M3 [~][x] follows the tidy landing clean.