# audit-eob — Milestone close: heap-str-abi (closing iter eob.1) **Date:** 2026-05-12 **Milestone:** heap-str-abi (hs.1 + hs.2 + hs.3 + hs.4 + eob.1) **Status:** Closed, three DESIGN.md tidies applied inline (`eob.tidy`) ## Architect drift review `ailang-architect` reported `drift_found` across the commit range `750f97e..78e8338`. Lockstep invariants and codegen ABI all intact; three high-severity items in DESIGN.md plus one medium record-keeping note. **[high — spec acceptance]** `docs/DESIGN.md:2338-2342` — `float_to_str` described as "type-installed but codegen-deferred" with `CodegenError::Internal`. Stale since hs.4. **[high — spec acceptance]** `docs/DESIGN.md:2387` — same caveat inside the "What is supported" inventory; `int_to_str` was absent from the inventory entirely. **[high — spec acceptance]** `docs/DESIGN.md` (missing) — no "Str ABI" anchor documenting the heap-Str / static-Str dual realisation, shared consumer ABI, or codegen-elision invariant for static-Str-in-RC-paths. **[medium — record-keeping]** `docs/journals/2026-05-12-iter-hs.4.md` closed `DONE_WITH_CONCERNS` with weakened RC assertions; eob.1 retroactively restored the strict invariants. No forward-pointer appended; readers cross-walk via INDEX.md. ### Tidy fixes applied inline (`eob.tidy`) All three high-severity DESIGN.md drift items addressed in this audit commit (Boss-mechanical edits — no separate plan / implement dispatch warranted; the spec amend was small, the Str-ABI-anchor content was already fully known from the just-closed milestone): 1. `docs/DESIGN.md:2338-2343` (float_to_str caveat block): replaced the codegen-deferred prose with a one-paragraph statement that `float_to_str` and `int_to_str` are fully wired, allocate a heap-Str slab, and carry `ret_mode: Own`. Forward-references the new Str-ABI anchor. 2. `docs/DESIGN.md:2387-2392` (inventory bullet): dropped the codegen-deferred parenthetical from `float_to_str`; added `int_to_str : (Int) -> Str` to the inventory; pointer to the Str-ABI section for the dual realisation. 3. `docs/DESIGN.md` (new "Str ABI" subsection placed after the Float-semantics block, before "What is not (yet) supported"): documents the two realisations (static-Str packed-struct `<{ i64, [N+1 x i8] }>` globals in `.rodata`; heap-Str slabs allocated via `ailang_rc_alloc(8 + len + 1)`); the shared consumer ABI (Str pointer at len-field offset 0, bytes at `payload + 8`, inherited `strcmp` semantics); and the codegen-level non-RC invariant for static-Str (move-tracking partial-drop + non-escape lowering + `Type::Con { name: "Str" }` carve-outs at `field_drop_call` and `drop_symbol_for_binder`'s App arm). Medium-severity hs.4-journal forward-pointer: skipped. INDEX.md already links hs.4 → eob.1 chronologically; the eob.1 journal explicitly cross-references hs.4's deferred fix as the iter's motivation. A forward-pointer in hs.4's own file would push the append-only convention; the cross-walk from INDEX is sufficient. ## Bench-regression check Sequence run as Boss (the `&&` chain in audit-SKILL.md tripped at `check.py`'s exit 1; `compile_check.py` and `cross_lang.py` then run separately to read their exit codes cleanly): - `check.py`: **exit 1** — 63 metrics; 2 regressed, 5 improved beyond tolerance, 56 stable. - Regressions: `bench_list_sum.bump_s` +12.60% (tol 10%); `bench_hof_pipeline.bump_s` +11.65% (tol 10%). Both only marginally over tolerance; the other four `bump_s` metrics (`bench_tree_walk`, `bench_closure_chain`, `bench_compute_collatz`, `bench_list_sum_explicit`) are stable within ±7%. - Improvements: three on the `latency.explicit_at_rc` cluster (`p99_us` -37.37%, `p99_9_us` -40.14%, `p99_over_median` -37.35%); two `gc_over_bump` mirrors on `bench_list_sum` and `bench_hof_pipeline` (ratio falls because the denominator — `bump_s` — rose; same physical signal as the bump regressions). - `compile_check.py`: exit 0; 24 metrics, all stable within ±25%. - `cross_lang.py`: exit 0; 25 metrics, all stable within ±15%. ### Classification **Latency cluster** (`latency.explicit_at_rc.p99_us` / `p99_9_us` / `p99_over_median`): third consecutive sighting across `audit-cma` → `audit-ms` → `audit-eob`. `audit-ms` flagged this as "one more audit before considering ratification"; this is that one more audit. eob.1's only codegen-side touchpoints are the `drop.rs` Str carve-out (8 LOC) and the `ret_mode: Own` flip at four signature sites; none of those should plausibly shift latency p99 by 37%. The signal predates this milestone (audit-cma was three milestones ago). Conservative call: still **do not** baseline-update on this audit. The cluster is real and persistent, but the underlying cause is unknown, and a baseline update without an identified attribution would obscure the next signal that *does* have an attributable cause. Recommendation forward: if the cluster persists into the next two audits unchanged, ratify with `--update-baseline` and a journal entry naming the persistence as the ratify rationale (absence of identified cause being the standing fact). If the cluster shifts or shrinks meaningfully, that is itself the attribution signal. **bump_s cluster** (`bench_list_sum.bump_s`, `bench_hof_pipeline.bump_s`): **first sighting** in any recent audit. Both metrics only marginally over the 10% tolerance. The other four `bump_s` measurements are stable, which makes "shared underlying bump-allocator change" unlikely; per-fixture system noise (12.6% on a ~50ms benchmark is ~6ms of jitter) is the most parsimonious explanation. eob.1 made zero changes to bump-allocator codepaths. The implementer's end-report flagged this same cluster as appearing during the workspace bench sweep before commit. Conservative call: first-sighting rule — **do not** baseline-update; observe in the next audit; if it persists, investigate. **Baseline left pristine on every script** for the third consecutive audit. No `--update-baseline` invocation. ## Status Closed. Heap-str-abi milestone fully landed: - Static-Str layout migrated (hs.1, hs.2). - Heap-Str runtime additions wired (hs.3, hs.4). - Effect-op-borrow rule + RC-discipline closes (eob.1). - DESIGN.md anchors both arg-position rules + Str-ABI dual realisation (eob.1 + eob.tidy in this audit). - WhatsNew entry + roadmap P1 close (eob.1). Working tree exits audit clean. main HEAD advances by exactly this audit commit.