User-approved 2026-05-19; grounding-check PASS (all load-bearing
assumptions are already-shipped M3 ABI behaviour, each pinned by a
green non-ignored integration test: embed_tick_e2e own+borrow,
embed/tick_roundtrip.c, embed_staticlib_cli, embed_swarm_tsan,
embed_staticlib_alloc_guard). Terminal embedding milestone, zero
language/compiler/runtime change — ail-embed is a lean reusable
embedding module (Rust port of the audited tick_roundtrip.c) + the
real E2E; in-repo, [workspace]-excluded so the compiler workspace
owes nothing to ../libs/data-server or /mnt (Invariant 1 in the
dependency graph, not just on paper). Real data-server + real
Pepperstone ticks; symbol-fan headline + time-shard
boundary-invisibility proof (per-shard bit-exact; whole-window only
within f64-reassociation tolerance — self-review fix).
roadmap: M5 [ ]->[~] open in-flight, spec pointer added, dangling
"todo above" dependency reconciled to shipped 170464f; M4-retired
and Tick-coverage struck/done entries pruned (their own text
scheduled deletion at next-milestone-start; permanent rationale
survives in 2026-05-18-brainstorm-embedding-abi-m4-retired.md, still
pointed to by M5's context line). Mirrors the M3 1fbb9c4 precedent
(spec + roadmap-flip in one commit).
Drives the RED test from a11cb7c to GREEN. Bug-fix iter
bugfix-over-strict-mode-ctor-rebuild-consume (debug -> implement
mini). Check-only lint-precision fix; zero codegen / runtime / ABI /
schema / DESIGN.md change.
The [over-strict-mode] lint's consume-detection
(any_sub_binder_consumed_for / pattern_has_consumed_heap_binder,
crates/ailang-check/src/linearity.rs) only recognised a consume of an
(own (con T)) param when a heap-typed pattern-binder was moved out of
`match p`. When p was destructured into purely primitive fields fed
into a Term::Ctor rebuilding p's own ctor, that genuine
dismantle+rebuild consume was invisible, so the lint spuriously
advised "(borrow ...) would suffice". An LLM author "fixing" that by
flipping an export own->borrow would silently invert the ABI
ownership contract — why a low-severity advisory FP got a real
RED-first fix.
Fix: a second recognition path in any_sub_binder_consumed_for — a
`match p` arm destructuring binders out of p's ctor that references
any of them (primitive or not) inside a Term::Ctor's args in the arm
body genuinely consumes p. Two pure helpers: ctor_uses_any_binder
(finds a fresh-allocation Term::Ctor reachable in the arm body) +
term_mentions_any_binder (deep free-var scan, so binder flow through
an intervening expr like (+ acc px) is recognised, not only a bare
Var arg). Conservative toward NOT suppressing: a ctor ignoring p's
payload still warns (negative-control verified). Over-strict-only —
by-name-shadowing imprecision is extra-silence, never under-strict
(Known debt in the journal + the fn doc). The two stale doc comments
that mis-attributed this FP to a nested `match` corrected for
doc-honesty (debugger concern #2 — same code region, in-scope).
Boss-verified independently: RED test now GREEN; full
cargo test -p ailang-check 108/0 lib + every binary 0-failed with NO
existing test modified; ail check examples/embed_backtest_step_tick.ail
no longer warns over-strict on st/tick (exit 0);
embed_backtest_step_tick_borrow.ail + M3 embed_backtest_step_record.ail
still clean; embed_tick_e2e + bench posture untouched.
+166/-20 in crates/ailang-check/src/linearity.rs only. Journal +
stats + INDEX line in this commit.
M4 (sequence crossing via the List ADT) was struck during its own
/boss brainstorm, in the Step-2/3 Q&A, before any spec — the
"problem mis-framed -> don't ratify a known-unneeded shape into the
roadmap" brainstorm path. No spec, no grounding-check, no planner
handoff.
Why: held against DESIGN.md feature-acceptance criterion clause 2,
M4 removes no redundancy. The shipped M3 export gate is_c_abi_type
(crates/ailang-check/src/lib.rs:1934-1953) is a per-parameter loop
accepting a C scalar OR a single-ctor all-scalar record
independently per param; the forwarder's llvm_scalar maps every
non-scalar Type::Con to ptr (M3-frozen). So (State, Tick) -> State
with both as single-ctor all-scalar records is already
gate-accepted and forwarder-supported today. The minimal
data-server binding is M3 (shipped) + a host-side per-tick loop;
cons-list crossing would add a 2N+1-box-per-chunk host builder and
the deferred flat-array perf debt, with no named consumer (M5's
adapter unrolls each chunk host-side; whole-chunk in-kernel
visibility is semantically void — State threads across calls
regardless of chunk boundaries).
Outcome: M4 retired in docs/roadmap.md (struck entry kept one
cycle for context, never [x] — never shipped); M5 reconciled
(depends on M4 -> M3 + the Tick-coverage todo; adapter unrolls
host-side; friction feeds the host-per-tick-FFI vs. batch-crossing
P2 perf decision); residual recorded as a new [todo] Tick-coverage
on M3 — an E2E + fixture pinning the two-record-param per-tick
(State, Tick) -> State shape (test backfill, no brainstorm).
Rationale + the honest mid-Q&A correction (I had wrongly asserted
M5 needs M4) in
docs/journals/2026-05-18-brainstorm-embedding-abi-m4-retired.md;
INDEX.md mirrors it.
[medium] DESIGN.md §"Embedding ABI": surgically replaced ONLY the
contradicted M1-era parenthetical (asserted the export boundary is
scalar-only — false post-M3, a single-ctor record is an accepted
export type) with the present-tense truth pointing at the frozen-layout
SSOT + the own/borrow mode contract. The parenthetical shared physical
line :2300 with the docs_honesty_pin:135 pinned bare-scalar sentence;
the edit kept every pinned word (planner Step-5 item-6 pin-safety, the
M2.tidy precedent — docs_honesty_pin stayed 5/5 green, RED-restore path
never triggered). [low] codegen forwarder-body comment honesty fix
(comment-only; the IR byte-pins assert generated code not comments —
byte-identical before/after).
Boss-verified: both stale fragments grep-absent; 4 standing pins green
at the recon baseline; workspace 639/77 byte-unchanged; diff exactly
2 files. No behaviour change; the pins are the coverage (M2.tidy
precedent, no audit/fieldtest gate). bench already carry-on/NO-ratify
at the M3 audit (causally exonerated). One non-gating planner-quality
grep defect recorded in the journal Concerns (orchestrator handled it
correctly, no code bent).
Tasks 1-5 GREEN. T1 baseline pins (re-point annotation + @ailang_rc_alloc
heap-box byte-pin: size=8+n*8, tag@0, fields@8/16). T2 export gate widened
(is_c_scalar -> two-level is_c_abi_type: single-ctor all-Int/Float record;
multi-ctor/Str/List/nested still RED; gate suite 10/10; M1 adt-ret must-fail
re-pointed to multi-ctor+Str Reading). T3 codegen forwarder widened
(llvm_scalar record Type::Con -> ptr; M2 forwarder body byte-unchanged;
3/3 staticlib pins). T4/T5 E2E record round-trip own+borrow, global
leak-freedom.
Boss spec-consistency repair (M2.1-precedent class): orchestrator
correctly BLOCKED Task 5 on a genuine spec defect -- the single-ctx-readback
allocs==frees proof model is unsatisfiable for borrow (and only
coincidentally passes for own) because M2's TLS-ctx is bound only during
the synchronous forwarder call, so host-side decs land on g_rc_*, not ctx.
Boss-verified globally leak-free + value-correct both modes. Spec + plan +
harness amended to the stronger global model (sum all ailang_rc_stats:
lines; the M2-TLS cross-attribution documented as correct behaviour). No
fresh grounding-check (removes an over-strong measurement assumption).
Tasks 6 (DESIGN.md frozen-layout SSOT + lockstep pointers + freeze wording
+ enforceability demo) and 7 (workspace-green gate) re-dispatched on the
amended plan. Bench/architect milestone-close is audit-owned.
iter embedding-abi-m3.1 (PARTIAL); INDEX.md line deferred to the DONE commit
Resolves the M2 milestone-close audit's only actionable drift item
(architect [medium] DESIGN.md:2266 stale (M1) header vs its now-M2
present-tense body + coupled [low] :2354 xref). Current-state-mirror:
the section describes the current embedding ABI (M1+M2), so the
milestone tag is internal history, not current state.
5 live-coupling sites renamed in lockstep, 3 files:
- docs/DESIGN.md:2266 header '## Embedding ABI (M1)' -> '## Embedding ABI'
- docs/DESIGN.md:2354 schema-block xref 'see §"Embedding ABI"'
- docs_honesty_pin.rs:134 test comment + :136 assert-message
- crates/ailang-core/specs/form_a.md:89 live forward-xref (Boss-added
5th site: plan-recon-undercount countermeasure surfaced a live
dangling-xref the architect's 3-site scope missed; folded in on
the merits — a half-rename contradicts the tidy's own thesis)
docs_honesty_pin.rs:135 asserted substring (the rename-immune
DESIGN.md body sentence) byte-verbatim untouched. Committed
append-only history NOT falsified (Boss-verified diff = 3 content
files + journal + stats only). Pins green before AND after
(docs_honesty_pin 5/0, design_schema_drift 8/0). Zero
language/checker/codegen/schema change.
Architect drift_found: the only actionable item is the stale
'## Embedding ABI (M1)' DESIGN.md header (:2266) vs its now-M2 body
+ coupled :2354 xref — a current-state-mirror honesty desync the
iter journal flagged truthfully (Task-7-scope-deferred to preserve
the docs_honesty_pin:135 verbatim sentence). Everything substantive
holds (Invariant 1, internal-convention byte-invariance, Decision-10
note present-tense-correct, lockstep, no unrequested extras).
Bench check.py exit 1 (bump_s + 2x rc-latency max_us). M2 changed
the benched runtime path so byte-identical exoneration did not apply
-> ailang-bencher localised: H0 refuted, all 3 firings are the two
tracked roadmap-P2 noise families (bump_s causally impossible from
M2's diff; rc.c hunk branchless+free; max_us median/p99 flat +
non-reproducible). NO baseline ratified; not M2 artefacts.
Resolution: doc-honesty drift -> tidy iter embedding-abi-m2.tidy;
bench -> carry-on. Roadmap [~]->[x] after the tidy lands clean.
Completes Embedding ABI — M2.1 (Tasks 1-4 committed c9a84b3 as the
known-good subset; this commit lands Tasks 5-9 from the re-dispatch
against the Boss-corrected plan).
- T5: swarm.c per-thread-ctx scalar-swarm capability demo (no
SHARED_CTX) + rc_accounting_shared_ctx_is_flagged_by_tsan added to
the item-1 harness driver (de-globalisation negative-control teeth,
where a shared ctx genuinely races on ctx->alloc_count).
- T6: M1 host.c migrated to the ctx ABI; embed_e2e green (s==25
through the ctx-threaded forwarder).
- T7: DESIGN.md current-state update (provisional-until-M3 narrowed
to the value/record layout; Decision-10 per-thread-ctx note);
docs_honesty-pinned sentence + (con Int) snippet preserved verbatim.
- T8: regression gate — workspace green; null-ctx fallback
byte-behaviour preserved.
- T9: bench-trio — compile_check/cross_lang clean; check.py
tracked-P2 noise only, causally exonerated (zero codegen/runtime
diff vs HEAD), NO baseline ratified.
Boss-verified directly (not on report trust): docs_honesty_pin 5/0,
design_schema_drift 8/0, embed_export_hash_stable 1/0,
embed_export_gate 6/0, embed_e2e 1/0, embed_staticlib_alloc_guard
2/0, print_no_leak_pin 1/0 + e2e rc_stats 4/0; the tsan coherent-stop
proven by hand — per-ctx clean (exit 0, 0 warnings), shared-ctx a
real ThreadSanitizer data race at rc.c:157/:208 (exit 66).
Known debt (journal + roadmap): DESIGN.md '## Embedding ABI (M1)'
header still says (M1) while the body mirrors M2 — out of Task 7's
scope-limited regions by design; post-audit doc-honesty tidy.
Milestone-close audit next.
Tasks 1-4 land fully review-green and are the cohesive shippable
subset (the per-thread embedding ABI, fully wired + proven):
- T1: FIXED-FIRST alloc-guard baseline pin (RED captured -> GREEN at T4).
- T2: runtime/rc.c gains ailang_ctx_t {alloc_count,free_count} +
ailang_ctx_new/_free + __thread __ail_tls_ctx; the two increment
sites become 'if (_ctx) _ctx->... else g_rc_...'. g_rc_* statics +
ailang_rc_stats_atexit + the constructor RETAINED VERBATIM as the
null-ctx (single-threaded executable) fallback. rc_accounting_tsan.c
+ driver: per-ctx 8x200000 tsan-clean (de-globalisation positive proof).
- T3: codegen Target::StaticLib forwarder gains a leading 'ptr %ctx'
+ one '@__ail_tls_ctx = external thread_local global ptr' decl +
TLS save/store/restore around the BYTE-UNCHANGED internal call;
_adapter/_clos + internal arg vector untouched (M1 decision held);
doc-comment provisionality narrowed to the value/record layout.
- T4: build_staticlib rejects --alloc != rc (RC-only swarm artefact).
Boss adjudication of the orchestrator's Task-5 BLOCKED (spec-defect,
correctly surfaced not hacked): swarm.c's -DSHARED_CTX negative
control is structurally impossible — examples/embed_backtest_step.ail
is a non-allocating scalar kernel that never writes a ctx field, and
__ail_tls_ctx is __thread, so a shared-ctx scalar swarm has no
shared-memory write to race on (the spec's OWN item-1 honesty point).
The de-globalisation teeth belong to the item-1 rc_accounting harness
(shared ctx genuinely races on ctx->alloc_count; orchestrator
independently confirmed tsan exit 66). Spec amended in lockstep
(Goal coherent-stop, must-fail-axis item 2, Testing item 3,
Acceptance) so item 3's negative control is item-1's by the
de-globalisation-proof / capability-demo split; plan Task 5
restructured (swarm.c per-ctx capability demo only; negative-control
standing test relocated into the item-1 harness driver) + Task 3's
plan-transcription error (@ail_backtest_step ->
@ail_embed_backtest_step_step) corrected. This is a Boss
consistency-repair of an internally-contradictory clause whose intent
is already correctly realised in the same spec — not a redesign; no
brainstorm bounce. Task-5 working files discarded (corrected plan
reproduces them; a structurally-RED test must not enter main).
INDEX.md + final journal land at iter completion (re-dispatch [5,9]).
Restores the Decision-5 IR-readability affordance for main-free
kernels: ail emit-ir gains --emit=staticlib, symmetric with
ail build, reusing the M1-audited Target::StaticLib path via a new
one-line lower_workspace_staticlib convenience. Zero-export guard
byte-identical to build_staticlib's. DESIGN.md widened (not
narrowed) + a pre-existing M1 synopsis omission corrected. 3 new
E2E tests; no fixture minted, no doc pin (E2E is the coverage).
Plan 03493c9.
Resolves the M1-fieldtest [friction] + [spec_gap]#1 shared root:
form_a.md stated an unconditional 'every (fn ...) param needs an
(own/borrow) mode' rule in 4 places, contradicting shipped checker
behaviour (scalars take and require bare (con Int); a mode on a
scalar trips body-pointing use-after-consume/consume-while-borrowed).
All 4 sites rewritten symmetric to the existing return-type carve-out;
DESIGN.md gains the bare-scalar export-param rule + a corpus-grounded
Form-A snippet; RED-first anti-regrowth pin via FORM_A_SPEC + norm().
Zero language/checker/codegen change. Plan 4c266a6.
Surface-touch fieldtest of M1's (export "<sym>") + --emit=staticlib
+ scalar/effect-free gate. DESIGN.md + public examples only (no
compiler source). The M1 thesis is empirically substantiated:
- [working] Int EMA + Float leaky-integrator both first-try clean
end-to-end (author -> --emit=staticlib -> C link -> typed scalar
return; s==67 / s==1.875, exit 0). Clause-1 confirmed.
- [working] Both clause-3 rejections precise + self-correcting
(export-non-scalar-signature on IntList param;
export-has-effects on !IO). Clause-3 confirmed.
- [working] (export) orthogonality + zero-export staticlib guard
match spec.
- [friction] form_a.md 'wrap every param in own/borrow' misdirects
the headline scalar export -> body-pointing use-after-consume /
consume-while-borrowed; only bare (con Int) checks. Pre-existing
form_a.md defect M1 made acute (not introduced).
- [spec_gap] form_a.md item 1 unconditional; scalar params take no
mode (shares root with the friction).
- [spec_gap] no public emit-ir --emit=staticlib though Decision 5
makes kernel-IR readability load-bearing.
Boss verified independently via the public CLI (positive E2E builds
both archives; both rejections fire the documented codes). 0 bugs:
M1 capability + gate sound. Findings route to the roadmap as
follow-up (not M1-blocking, no debug).
Tasks 1-3 of docs/plans/embedding-abi-m1.1.md, a verified known-good
subset (cargo build --workspace exit 0; full workspace green; the
roundtrip_cli all-examples gate green):
- Task 1: CLI build-path MissingEntryMain baseline pin
(examples/embed_noentry_baseline.ail + embed_missing_main_baseline.rs;
triple-assertion, layered on the green codegen-unit pin lib.rs:3314).
- Task 2: additive FnDef.export: Option<String> (serde default +
skip_serializing_if, modelled on FnDef.doc); compile-driven thread
of export: None across ~85 FnDef/AstFnDef literals / 18 files incl.
all in-source #[cfg(test)] mod tests + drift/hash/spec-drift
literals + the codegen lib.rs:3320 in-source pin; hash-stability
golden pin; DESIGN.md fn-JSON "export" line. DONE_WITH_CONCERNS
(plan symbol content_hash_fn -> def_hash per hash_pin.rs, plan-
pseudo-vs-reality class, plan corrected).
- Task 3: Form-A (export "<sym>") modifier — parse_export +
parse_fn thread + write_fn_def emission + form_a.md grammar;
byte-identical round-trip.
Task 4 BLOCKED (Boss plan-defect: fixtures declared module != file
stem; AILang's loader hard-enforces module==stem at workspace.rs:438,
so ail check panicked on load before the gate). Boss resolution
(Option 2, overriding the orchestrator's Option 1, rationale in the
journal + plan Design-decision 6): keep descriptive embed_* filenames,
rename fixture MODULES to their stems — the C symbol backtest_step
stays via (export ...), demonstrating spec Decision 2's mangling-
decoupling rather than violating it; archive becomes
libembed_backtest_step.a, internal symbol @ail_embed_backtest_step_step,
host.c unchanged. Plan fixed (Design-decision 6 + Task-4 module==stem
+ Task-5/6/7 dependent strings + the no-*. Float-head + content_hash_fn
concerns folded). Headline fixture corrected; blocked-Task-4 WIP
discarded (recreated by the [4,7] re-dispatch from the fixed plan).
PARTIAL commit (not the iter's final commit): the implement Repair
path mandates committing the known-good subset so the [4,7]
re-dispatch starts from a clean tree that includes Tasks 1-3 (Tasks
4-7 structurally depend on the schema field + surface). INDEX line
added when the full iter lands post-re-dispatch.
User-authored proposal added during the embedding-abi-m1.1 implement
run (path-disjoint from the iter; Boss roadmap maintenance, not
bundled into the iter commit). Role-split of the 2905-line DESIGN.md
into a typed contract ledger + per-model whitepapers + decision-
records rehomed to docs/journals/, on the consumer/lifetime axis.
Brainstorm complete for Embedding ABI M1 (first of the M1–M5 arc).
User-approved 2026-05-18. Grounding-check PASS on 3rd dispatch
(dispatch 1 false-BLOCK on an in-source unit test it missed;
dispatch 2 PASS + located the pin; dispatch 3 PASS after honest
prose correction).
7 design decisions pinned, all derived from the M1–M5 arc except
the one genuine fork the user decided:
- additive FnDef.export: Option<String> (FnDef.doc precedent)
- (export "<sym>") author-chosen, mangling-decoupled C symbol
- lib<entry>.a (program only) + separate libailang_rt.a
- no runtime lifecycle API — documented no-call contract
- --emit=staticlib suppresses @main + MissingEntryMain; needs >=1 (export)
- export-signature gate: scalar-only + effect-free (clause-3 discriminator)
- Task 1 fixed: MissingEntryMain build-path baseline pin (RED-first)
Roadmap M1 flipped [ ] -> [~]. Next: planner in a fresh session
(user-chosen session shape).
The data-server-driven goal: a compiled AILang kernel callable
in-process from a concurrent Rust host so a backtest swarm runs
each backtest as an independent single-threaded computation.
Decomposed into five chronologically-bounded milestones (M1
linkable artifact+scalar entrypoint, M2 per-thread ctx+concurrency
safety, M3 frozen value layout+ADT crossing, M4 List-ADT sequence
crossing, M5 ail-embed adapter+swarm fieldtest), each its own full
brainstorm->plan->implement->audit cycle. Shared motivation + three
audited invariants (clean core / single-threaded per computation /
native-AOT-only) carried on the M1 entry. The flat array/slice
primitive is recorded P2 as a measured performance follow-up
gated on M5's fieldtest, not a capability gap — keeping the ABI
arc's scope clean. Decision made in the 2026-05-18 data-server
analysis chat; no spec yet (brainstorm produces M1's spec at start).
Architect clean (one [medium] advisory Sweep-5 self-match wart filed
as P3, not a fix iteration). Bench causally exonerated: HEAD vs
5bb7211/de66eb7 — all 5 firing bench binaries cmp-byte-identical, ail
sha256 identical at all 3 commits; the check.py firings are the two
tracked-P2 environmental classes (*.bump_s anchor staleness; *.max_us
-n5 tail-jitter, 4th on a zero-runtime-change milestone), NOT this
milestone — NO baseline ratify (Iron Law forbids ratifying noise).
compile_check 0/24, cross_lang 0/25 EXIT 0. No fieldtest (zero
authoring-surface change). docs-honesty-lint CLOSED: roadmap [~]->[x],
WhatsNew appended, INDEX line added.
Single-iteration milestone (mirror effect-doc-honesty). Two-pronged
tense+modality discriminator codified present-tense as a DESIGN.md
meta-subsection (Approach A, user-ratified); procedural enumeration =
discriminator applied to the full architect_sweeps.sh + new Sweep 5
output (not a frozen orchestrator list — the sweep already surfaces
post-mortem sites the architect has been waving through as legitimate
quotes); anti-regrowth = enumerated docs_honesty_pin.rs (hard
cargo-test gate, incl. protected-exception present-anchors against
over-correction) + Sweep 5 + ailang-architect.md "DESIGN.md honesty
drift" bullet (advisory standing forward check). No language/checker/
codegen/runtime change. grounding-check PASS (10/10 ratified).
Post-audit downstream-LLM-author field test of the post-removal
Form-A surface. 4 fresh real-world programs written from DESIGN.md +
form_a.md + public examples only (no compiler source): running
sum-of-squares accumulator (loop/recur → 385), grade cascade
(let-threaded if → 4/2/0), Horner polynomial straight-line build-up
(let-shadow chain → 73), multi-state bracket scanner threading
(rest,depth,ok) by tail recursion → true/false. 0 bugs, 0 friction,
0 spec_gap, 4 working — every task clean and correct on the first
try with only let/if/loop/recur; all parse|render|parse
byte-identical; zero mut/var/assign tokens produced (a doc-faithful
author did not reach for the removed construct).
The closest-to-friction case (multi-state machine restates the full
state tuple per tail-call) is correctly classified working, not a
spec_gap: that explicit-dataflow cost is the local-reasoning pillar
working as designed; mut's implicit cross-iteration persistence is
exactly the failure class the removal eliminates. mut-keyword
rejection is fail-closed with a diagnostic that enumerates the
surviving forms (no tombstone, no-nostalgia, as spec'd).
Removal thesis empirically CONFIRMED — mut was redundant with
let/if/loop/recur in 100% of the fresh tasks. The
remove-mut-var-assign milestone is fully ratified and CLOSED:
spec+plan+iter, audit clean (architect [high] form_a.md fixed in
.tidy, bench causally exonerated), fieldtest clean. Roadmap P0
flipped [~]→[x]; WhatsNew user-facing entry appended.
Milestone-close audit for remove-mut-var-assign (48e7774..07f0802).
Architect drift: one [high] — crates/ailang-core/specs/form_a.md
still documented the full mut/var/assign construct (EBNF 286-288,
prose 308-328, dangling `like mut` at 332). The spec named it for
deletion; the iter missed it. Root cause = the recon-undercount
class (4th recurrence) plus a Boss error: a plan-time grep checked
only docs/form_a.md (dir-scoped), got "No such file", and that
unverified non-existence claim propagated into the recon brief —
the real file is crates/ailang-core/specs/form_a.md. A stale doc
never compile-fails so the implement compile-sweep could not catch
it. Fixed inline as a Boss .tidy (CLAUDE.md context-already-loaded
carve-out; full review discipline kept — tree-wide verified zero
construct residue except the roadmap entry naming the milestone
itself; grammar now reads coherently reuse-as -> loop -> recur).
Bench causally exonerated: HEAD vs 48e7774 bench binaries
cmp-byte-identical (the -2520-line removal alters zero bytes of the
firing fixtures' machine code). check.py exit 1's 3 firings are the
tracked P2 bump_s environmental staleness + single-sample -n5
max_us jitter (explicit_at_rc.max_us +108% -> -2.30% ok on
identical-code rerun). PRISTINE met on the merits; NO baseline
ratify (Iron Law + spec foreclosure).
Roadmap: P0 refreshed (audit clean, fieldtest remains); the
ailang-plan-recon P2 escalated in place to a structural
recon-contract defect (2 named gaps + concrete fix); a new distinct
P2 filed for the check.py *.max_us -n5 3-for-3 false-positive.
mut/var/assign removed from AILang entirely and atomically. Deleted:
Term::Mut/Term::Assign/struct MutVar; the three Form-A keywords +
parse_mut/parse_assign + grammar EBNF; the 4 mut CheckError variants;
the mut_scope_stack synth threading (param dropped from synth + every
internal/external/test caller); the two lower_term arms; and every
exhaustive no-_ Term::Mut/Term::Assign match arm across 17 source
files — cut in lockstep with DESIGN.md, fixtures, the drift trio,
carve-out and roadmap so the schema is honest at every commit. No
catch-all wildcard introduced (verified). loop/recur + let/if are
the surviving forms.
The shared codegen alloca machinery survives (loop reuses it):
mut_var_allocas renamed binder_allocas (representation-only, loop
codegen byte-identical) and the shared Term::Lam escape guard
simplified to !loop_stack.is_empty() with the loop half
(LoopBinderCapturedByLambda) byte-equivalent. Feature-acceptance
applied inverted: the removed feature fails clause 2 (redundant)
and clause 3 (IS the iterated-mutable-state bug class).
Behaviour preservation is executable: mut_counter/mut_sum_floats
still print 55 after the faithful let/if rewrite. The removal is
made executable by the new mut_removed_pin.rs (4 must-fail pins).
Independent verification: cargo test --workspace 605/0, zero
residual mut symbols in any crate source, loop/recur non-regression
all green (55 / 500000500000 / infinite-compiles / the
lambda_capturing_loop_binder pin), roundtrip_cli PASS.
One DONE_WITH_CONCERNS: a 4th recurrence of the recon-undercount
class (in-source mod tests + a drift-pin fn + 5 orphaned mut
.ail.json carve-outs + a non-enumerated E0599); all resolved within
implementer remit, no behaviour change. Milestone-close audit then
fieldtest remain.
spec docs/specs/2026-05-18-remove-mut-var-assign.md (grounding PASS)
plan docs/plans/remove-mut-var-assign.1.md
One iteration (not the 4-then-3 split the brainstorm carrier
assumed): the recon's cross-references prove a Rust exhaustive-match
enum-variant removal is atomic and the workspace test suite is
necessarily red between the Rust cut and the fixture/doc/drift
cleanup, so the full cargo-test green gate can only sit at the final
task. 6 tasks: T1 RED must-fail pins, T2 the atomic Rust cut
(~40 match arms + mut_scope_stack signature + all ~37 callers +
escape-guard loop-half-preserving simplification + codegen rename
mut_var_allocas→binder_allocas; gate cargo build 0-errors + T1
GREEN), T3 dangling test-pin deletions, T4 DESIGN.md hard-delete,
T5 faithful let/if fixture rewrites + 3 rejection-probe deletions,
T6 carve_out 18→12 + roadmap + final full-suite + loop/recur
non-regression gate. Plan-recon resolved 3 open Qs (form_a.md does
not exist — grammar lives in parse.rs doc-comment; round_trip.rs +
roundtrip_cli.rs auto-sweep examples/; escape.rs:533 walker is
loop-reachable).
Removal milestone: Term::Mut + Term::Assign + the MutVar surface decl,
one indivisible feature. loop/recur (shipped, closed) + let/if cover
every shipped use; the construct fails the feature-acceptance criterion
applied inverted (clause 2 redundant, clause 3 IS the iterated-mutable-
state bug class). Approach A: no deprecation window, JSON tags fail
closed as generic unknown-variant, codegen alloca machinery kept (loop
reuses it) renamed binder_allocas, shared Term::Lam escape guard keeps
its loop half. Decoupled from Stateful-islands. Grounding-check PASS —
all 7 load-bearing assumptions ratified by currently-green tests.
Roadmap: mut-removal as in-flight P0; the DESIGN.md/docs honesty-lint
queued as a distinct P1 milestone (depends on the removal closing),
its own brainstorm — no aspirational Wunschdenken / no post-mortem in
DESIGN.md; reader sees the language as it IS now.
Architect drift review clean (zero drift/debt, diff-verified: single
Term::Loop write_term hunk, no non-render site / Term::Recur / doc /
lockstep touched). Bench: compile_check 0/24 + cross_lang 0/25 exit
0; check.py's latency-tail firings proven single-sample jitter by an
identical confirmatory re-run (p99.9 +37%→+10% ok, max +114%→+22%
ok); the sole persistent firing is the pre-tracked P2 *.bump_s
environmental staleness, causally impossible to attribute to a
projection-only ailang-prose change. All items carry-on — no fix, no
baseline ratify. Fieldtest not applicable (no authoring-surface
change). Roadmap P0 flipped to closed; WhatsNew user-facing entry
appended (user present → notification suppressed per policy).
The Term::Loop arm of write_term rendered binders as bare
`name = init;` statements inside the `loop { … }` body block, which
reads as C/Rust re-init-every-iteration semantics — a projection
lying about a body the prose surface exists to let the reader trust.
Rewrite to a parenthesised init-list on the keyword line,
`loop(acc = 0, i = 1) { … }`, positionally isomorphic to the
unchanged Term::Recur arm. Projection-only: loop/recur AST, Form-A,
JSON-AST, typecheck, codegen, and the Form-A↔JSON round-trip
invariant untouched. RED-first via two new committed
examples/*.prose.txt byte-equality snapshots + two snapshot_loop_*
tests; full ailang-prose suite 10/0; both ail-prose CLI byte-matches
green. Single-iteration milestone, brainstorm→plan→implement.
Spec: docs/specs/2026-05-18-prose-loop-binders.md
Plan: docs/plans/prose-loop-binders.1.md
Single-iteration, RED-first plan for the prose-loop-binders spec.
Task 1 pins the desired Option-A bytes in two new committed
.prose.txt fixtures + two snapshot tests (RED against the old
renderer). Task 2 rewrites the Term::Loop arm of write_term and
gates GREEN via the snapshot suite + two ail-prose CLI byte-matches
+ an exact untouched-set check. Recon-verified line anchors; planner
Step-5 self-review clean on all 8 items.
Form-B prose renders loop binders as bare `name = init;` statements
inside the `loop { … }` body, which reads as C/Rust re-init-every-
iteration semantics — a lie about a body the projection exists to
let the reader trust. Redesign: parenthesised init-list on the
keyword, `loop(acc = 0, i = 1) { … }`, positionally isomorphic to
`recur(...)`. Projection-only; loop/recur AST, Form A, JSON-AST,
typecheck, codegen, and the Form-A↔JSON round-trip invariant are
untouched. Step-7.5 grounding-check PASS. Roadmap entry opened P0
in-flight.