# 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 (~+5–13% 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 `planner` → `implement`.
- **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.
