Decomposes the Boehm-retirement spec (50dc478) into 10 bite-sized
tasks. Task 1 ships the RED milestone-pin first (TDD); Task 2 is
the compile-gated atomic core (drops `AllocStrategy::Gc` variant +
the `Default` derive + threads every caller in codegen + main.rs in
one cohesive task, so the workspace-build gate at the end is
satisfiable). Tasks 3-9 cover the scrub work that cascades off the
core (e2e suite, doc-comments, bench harness, design ledger,
honesty-pin inversion, example fixtures + agent prompts, IR
snapshots). Task 10 is the acceptance gate.
Plan-recon (DONE_WITH_CONCERNS) surfaced 9 spec gaps; the plan
absorbs all 9:
- `runtime_alloc_fn` → actual identifier `fn_name` (no rename)
- 5 checked-in IR snapshots (`hello.ll`, `list.ll`, `max3.ll`,
`sum.ll`, `ws_main.ll`) regenerate via `UPDATE_SNAPSHOTS=1`
- `design/contracts/scope-boundaries.md:67,114-127` Boehm block
+ `examples/gc_stress.ail.json` dead-reference
- `design/contracts/memory-model.md:232` "pre-Boehm era" phrase
- `bench/check.py:91,94` `implicit @ gc` arm label map
- `crates/ailang-codegen/src/match_lower.rs:40,113`
`@GC_malloc` doc-comments
- `skills/implement/agents/ailang-implementer.md:95,185` Decision
10/Boehm references
- `AllocStrategy`'s `Default` derive (no callers — strip)
- e2e.rs spec line numbers refer to gc-call lines, not test-fn
header lines
Plan self-review caught a planner-grade defect that recon had
not flagged: `bench/check.py:62` hardcodes `"gc(s)" in line` as
the throughput-table header sentinel and `:72` hardcodes the
9-column count — both must shift in lockstep with the
`bench/run.sh` 9→6 column compaction; without the pair-edit,
`parse_throughput_table` silently returns an empty dict and the
"green" check pins nothing. Task 5 now carries Steps 4a-4c (header
+ count + field-set) as a coherent unit, plus the explicit pin in
the rationale.
Net delta on landing: 1 new test, ~30 modified files, 5
regenerated IR snapshots, 1 deleted fixture. Workspace passing-
test count shifts by `-3` (4 deletions − 1 new). The iter commit
will close Gitea #4 via the trailer.
refs #4
Resolves the design fork in Gitea #12 (the bounce-back from the
2026-05-20 /boss session). User accepted both half-decisions:
(a) the surface form `(app f)` becomes the canonical nullary
call shape, dropping the "expected at least one argument"
parser guard in `parse_app_body`;
(b) `Term::App.args` mirrors the *actual* serde attrs of
`Term::Ctor.args` — `#[serde(default)]` for read-tolerance,
no `skip_serializing_if`, so writes always emit
`"args":[]`.
The plan covers five small tasks: a RED→GREEN E2E (nullary user fn
called as `(app greet)`), the four-line parser-guard removal, the
one-attribute serde edit, and a doc-honesty fix on
`design/contracts/data-model.md` — the current "args omitted when
empty" comment on `Term::Ctor` is factually false relative to the
code (verified by a serde probe at plan time) and gets rewritten to
describe actual write/read behaviour while we are in the same jsonc
block. `design/contracts/honesty-rule.md` enforcement folded into
the same iter because leaving a stale comment behind in the block
we're modifying would be the exact failure mode the rule names.
Hash-impact verified at plan time: `grep -rn '"args":\[\]'
examples/*.ail.json` returns zero matches, so the new
`#[serde(default)]` on `App.args` is read-only behaviour change —
write side is unchanged, no existing fixture hash mutates. The
plan documents this explicitly under Task 3.2.
Two prior fieldtest specs already supplied the LLM-natural shape
evidence — `docs/specs/2026-05-15-fieldtest-mut-local.md` F3
(mut-local) and `docs/specs/2026-05-18-fieldtest-loop-recur.md`
spec_gap (`run_forever`) — so the feature-acceptance gate in
`design/contracts/feature-acceptance.md` is already passed; no
brainstorm phase needed for this iter.
refs #12
One terminal iteration covering the whole spec. Four tasks, all on
`bench/baseline.json`:
- Task 1: pre-recapture JSON edit — drop `max_us` + `p99_9_us` × 3
latency arms (6 entries) and rewrite the `note` field forward-
looking. The 6 entries must go before `--update-baseline` runs
because `write_new_baseline` faithfully re-baselines anything
left in the file (recon Open Q). The note rewrite is folded in
here because `--update-baseline` preserves the existing note as-
is, so any change has to happen before recapture (or as a
separate post-recapture edit; one-edit is cleaner).
- Task 2: `bench/check.py --update-baseline` regenerates every
remaining `baseline` value from a fresh `bench/run.sh -n 5`,
updating `captured` → 2026-05-20 and `captured_via`.
- Task 3: acceptance §1 — fresh-HEAD replay → exit 0, 0 regressed,
57 metrics in summary (= pre-edit 63 minus the 6 drops).
- Task 4: acceptance §2 — synthetic injection (halve
`bench_list_sum.bump_s.baseline` via `jq`) → exit 1 + REGRESSION
row on that metric, then restore via `jq` and confirm a final
exit-0 replay.
Recon adjudications:
- Replay-source (recon Open Q1): fresh `bench/run.sh -n 5` for
replay, not the same output that produced the recapture.
Realistic acceptance scenario; with 10% throughput tolerance vs.
~1-2% measured run-to-run variance on the affected metrics
(run-1 / run-2 reproduction data in spec body), there is ample
margin.
- Note rewrite (recon Open Q2): forward-looking — drop stale
refs (JOURNAL workflow retired 8e586f4; the `*.max_us`
tolerance convention is now moot since the metric is gone),
replace with pointer to docs/specs/2026-05-20-bench-harness-
recalibration.md + closed issues #15 / #16. Spec lives where
the rationale lives; the note carries the gate-policy
one-liner only.
No Rust crate touched. `bench/check.py` / `bench/run.sh` /
`bench/latency_harness.py` unmodified.
Plan self-review (all 8 checklist items): clean. Step granularity
checked; Task 3 collapsed from two `bench/check.py` runs to one
(single 3-minute run captures both summary and exit code).
Ready for handoff to `skills/implement`.
Single iteration covering the whole milestone (same shape as
rolesplit.1; spec is small, no build-atomicity issue — clause-5 is
isolated additive code, prose edits don't affect compilation).
Five tasks, each at task-level review granularity:
Task 1: clause-5 added to design_index_pin.rs RED-first via
identity-stubbed strip_fences (synthetic vector FAILS) →
correct toggle-on-fence impl (GREEN); module //!-header
extended to name clause-5. Test count 4 → 5.
Task 2: 7 prose-ref conversions to file-relative Markdown links
(float-semantics:69/100, embedding-abi:45, memory-model:44/
105, scope-boundaries:48/88 with the source+Pipeline split).
Exact verbatim before→after for every line. clause-5 stays
GREEN by construction (every introduced link resolves
durable).
Task 3: 2 disposition-(b) homeless-ref removals (pipeline:60-61
in-fence CLI block + authoring-surface:178-181 prose).
Pointer dropped, behavioural prose preserved.
Task 4: honesty-rule.md pin-safe positive-half paragraph between
L14 and the existing L15-blank (the two docs_honesty_pin
phrases at L14/L19 each stay verbatim on their physical
line; the additive insertion splits neither). The new
paragraph names design_index_pin.rs clause-5 by name
(nominal mention, not a link — consistent with the
existing 'Ratified by:' footer style and with §Scope).
Task 5: Whole-suite gate (646 → 647) + 5 grep+diff verifications
(no docs/ link, no #fragment, link count = 8, in-fence
schema-annotations intact, INDEX.md + decision-records
journal + clauses 1-4 byte-unchanged).
Self-review 8/8: spec coverage complete; zero placeholders; names
consistent; bite-sized; no commit steps; pin contiguity verified
(L14 + L19 stay verbatim on their physical lines, replacement body
shows L14 contiguous); no signature change ⇒ no compile-gate
ordering issue; every cargo-test filter substring is a real test
name + unfiltered runs have explicit count assertions.
The tidy's gate-first Task 1 RED-verification + Boss independent
verification surfaced two defects in the audit Resolution as first
written — caught exactly where the planner->Boss loop is designed to,
before any contract byte moved. Per the 'two+ defects in one
iteration => fix the upstream artifact, do not patch a third time'
discipline, the audit Resolution is corrected in lockstep with the
plan re-derivation:
- Mechanism (Resolution-4): the 'case-insensitive iter-code regex'
clause-3 design is REJECTED as unworkable — a blanket
iter/milestone detector conflates the memory-model rule-names
'Iter A'/'Iter B' and ordinary words 'pre-existing'/'pre-set'/
'pre-Boehm' with provenance, over-firing on legit present-tense
contract prose (4 no-strip files). Replaced by a FAITHFUL Sweep-1
superset: case-sensitive digit-anchored Sweep-1 line anchors
(confirmed ZERO across all contracts) + Sweep-1's ^[^/]*
path-excluded date (so docs/specs/2026-.. citations are not
flagged — repairs the iso_date over-fire the implement
orchestrator correctly BLOCKED on) + the audit-named
decision-record phrases (case-insensitive). No regex dep. The
load-bearing invariant (clause-3 GREEN => Sweep-1 clean) is
preserved; it never required the blanket detector.
- Scope (Resolution-1): the architect's [medium] was a 3-file
spot-check; the exhaustive scan found roundtrip-invariant.md:73
('at iter form-a.1') and data-model.md:149,161 ('loop-recur iter
1:') also carry lowercase provenance. True strip set = 5 files;
plan Task 5b adds the 2 (spirit-cleanup, not gate-blocking).
Plan self-review 8/8 re-run; clause-3 = hand-rolled faithful Sweep-1
superset, no regex dep, no blanket iter detector.
7 tasks executing the audit Resolution's 5 points: (1) gate-first
RED — widen design_index_pin.rs clause-3 to a hand-rolled PROVABLE
SUPERSET of architect_sweeps Sweep-1 over design/contracts/ (no
regex dep; subsumption proof inline), verify RED vs the un-stripped
tree; (2-4) sentence-level strip the faithfully-migrated
history/decision-record prose out of typeclasses.md / str-abi.md /
scope-boundaries.md into the decision-record journal, per recon's
per-sentence contract-residue map, each docs_honesty_pin pinned run
guarded contiguous; (5) fix float-semantics.md stale 'see Str ABI
below' -> str-abi.md; (6) re-scope architect_sweeps DESIGN_GLOB to
design/contracts only (models/ is the narrative tier) + lockstep
ailang-architect.md; (7) whole-tree GREEN gate (clause-3 RED->GREEN,
4/4, sweep exit 0, suite >=646/0, acceptance grep CLEAN).
Self-review 8/8.
Resolves the M5 milestone-close audit DRIFT (audit journal
28ab56a). 3 tasks, doc/comment-only, recon-verified pin-safe:
T1 docs/DESIGN.md — drop the retired-M4 forward-reference
(§"Free (host side)" ~:2354-2360) + reconcile the "no shared
mutable runtime state … data-race-free" claim with the now-atomic
global RC-stats fallback (§"Embedding ABI" ~:2287-2298, must not
disturb the adjacent line-2299 pinned bare-scalar sentence);
T2 runtime/rc.c:88 — comment-only fix of the stale "two
unconditional ++" performance aside (consistent with the adjacent
already-corrected :93-106 atomic block); T3 consolidated
doc-only/pin-safe/scope gate. All 3 sites recon-verified OUTSIDE
every pinned/hashed region (design_schema_drift scans only the
post-line-2362 data-model slice; docs_honesty_pin:135 pins the
distinct line-2299 sentence; the IR-byte pin asserts generated IR
not rc.c comments). Pins green before+after = the mechanical
pin-safety proof; no RED, no audit/fieldtest gate — mirrors the
M2.tidy a80d495 / M3.tidy 63d7d60 precedent (single cohesive
commit, pins are the coverage). Last step before M5 fully closes.
Final functional M5 iteration (spec ae905de; builds on green
m5.1 204c171 + m5.2 b724cd1 whose leak-proof is resolved through
dbd76e5). 3 tasks: (1) additive adapter::fold_window (windowed
sibling of fold_symbol) + chrono dev-dep + a second
[[bin]] timeshard_runner declaration; (2) tests/timeshard.rs
written FIRST — RED is the deterministic `env!(CARGO_BIN_EXE_
timeshard_runner) not defined` compile failure (bin absent); (3)
the timeshard_runner bin → GREEN, with the spec §3 strength-ordered
assertions (a) per-shard bit-exact vs single-thread windowed host
fold (THE boundary-invisibility proof), (b) Σ bit-exact by
construction, (c) whole-window within REL_TOL=1e-6 (derived from
the recursive-summation error bound, never bit-exact — spec
explicit), plus the now-deterministic leak-Σ and a journal-only
friction-timing capture.
Boss decisions in-plan: new bin not an arg-mode (shipped symbol-fan
path byte-untouched, no regression surface); chrono dev-only (date
math in the test, bin date-math-free; Invariant 1 unaffected);
concrete pin EURUSD 2017_03/04/05 (recon-verified present, no
gaps; data-server has no month-listing API); friction is a journal
observation, no bench gate, no timing assertion (flake-free);
pre-existing DESIGN.md:2358-2360 M4-drift explicitly out of scope.
Milestone close + mandatory audit run after Boss-verification.
M5 iteration 2 (spec ae905de; builds on m5.1 204c171). 3 tasks:
(1) promote data-server dev-dep -> real dep + additive `adapter`
module (tick_to_px / MidPriceStream lazy Iterator / fold_symbol),
RED-first on tick_to_px; (2) `swarm_runner` [[bin]] — one thread per
symbol, each owning its Kernel (Ctx: !Send makes one-ctx-per-thread
a compile-time guarantee), prints RESULT <sym> <acc_bits> <n>;
(3) integration test spawning that bin as a subprocess under
AILANG_RC_STATS=1 (atexit stat line is unobservable in-process —
runtime/rc.c:132-138), asserting per-symbol bit-exact vs an
independent same-order host reference + Σallocs==Σfrees (ported from
embed_tick_e2e.rs:84-104), skip-if-absent mirroring data-server's
own precedent.
Boss decisions recorded in-plan for the audit: TSan needs NO new
nightly harness — per-thread-ctx race-freedom is compile-time
enforced by Ctx:!Send AND already green-tested by the C-host
embed_swarm_tsan.rs (same pattern); m5.2 adds no new AILang-side
concurrency primitive. data-server dev->real dep is Invariant-1
sanctioned (compiler crates untouched; gate shifts to "AILang
workspace graph data-server count == 0" + zero compiler-surface
diff). Time-shard + friction-harvest deferred to m5.3.
First iteration of M5 (spec ae905de). 3 tasks, RED-first on the
core: (1) scaffold the workspace-EXCLUDED ail-embed crate +
build.rs (de-risks the no-in-repo-precedent ail-binary resolution
in isolation with a stub lib), (2) the lean embedding core
(Ctx/Kernel/frozen-layout helpers, Rust port of the audited
tick_roundtrip.c:31-75, zero data_server use) with an in-source
data-server-free RED unit test, (3) hermetic data-server smoke
(synthetic Pepperstone-format ZIP fixture via the public
RawTickRecord type → real DataServer → Kernel, bit-exact vs host
reference).
Boss decomposition calls recorded in-plan: data-server is dev-only
(iter-1 library has ZERO deps — Invariant 1 maximally honest);
build.rs resolves ail via AIL_BIN-else-cargo-build-parent-workspace
(separate target dir, no nested-cargo lock); fixture writer mirrors
data-server/src/loader.rs:110-124. Invariant-1/no-language-change
mechanically gated (cargo metadata graph check + git status path
check). Adapter + swarm explicitly deferred to iter 2+.
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
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]).
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.
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).
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.
Terminal iteration of the standalone loop/recur milestone.
Replaces the iter-1 lower_term CodegenError::Internal stub with
real LLVM-IR lowering: loop binders as entry-block allocas (the
mut.3 pending_entry_allocas mechanism, reusing mut_var_allocas so
the existing Term::Var load path needs zero new code), a fresh
loop-header block reached by an unconditional br, recur stores +
back-edge br, a new loop_frames codegen stack saved/restored at
the lambda boundary (mut.3 triple precedent). Four Boss design
calls baked into the plan header, all on architectural-consistency
/ spec-pinned-invariant grounds (not effort): (1) alloca + clang
-O2 mem2reg, NOT hand-emitted phi (no linear-emit phi precedent;
spec's "phi" is the secondary impl-shape; mem2reg gives identical
optimized output); (2) reuse mut_var_allocas + the existing
Term::Var load path (Var-lowering byte-unchanged; representation-
sharing only); (3) loop-exit value is the emergent product of the
existing if/match join once recur sets block_terminated, no
separate result phi; (4) reuse the single block_terminated field,
recur sets it at its own emit site (parallel setter), zero edits
to existing SET/READ sites (tail-app byte-unchanged). Three new
.ail fixtures: sum_to->55 run, deep-n 1e6->500000500000 (clause-2
correctness made executable), infinite-loop build-only. iter-3 is
codegen-only: no schema/typecheck change, hash pins + drift trio
stay green untouched. Self-review item 7 (the systemic fix folded
into iter-2) applied: T1's field-add is not a fn-signature change,
no deferred-caller-past-gate.
Second of three iterations of the standalone loop/recur milestone.
Replaces the iter-1 synth CheckError::Internal stub with real
binder typing + positional recur arity/type checking via a
loop_stack frame, a new private verify_loop_body tail-position
pass (sibling of the spec-frozen verify_tail_positions), and the
four Recur* diagnostics. Three Boss design calls baked into the
plan header: (1) RecurTypeMismatch is an Assign-style structural
subst-compare not a unify-propagate (so the dedicated code fires
point-exactly per spec acceptance); (2) loop_stack element type is
Vec<Type> (positional, not name-keyed IndexMap — recur rebinds by
position; binder names enter ordinary locals like Term::Let);
(3) diagnostic-code precedence is by pass ordering (synth before
verify_loop_body), already correct, no explicit logic needed.
Every code step literal — synth signature/threading, the two real
arms, verify_loop_body full body, four negative .ail.json
fixtures, carve-out 13->17 + stale-header fix, pin harness, ct1 F2
sibling — all verified against read source. Codegen stays the
iter-1 stub (iter 3). Self-review: reused iter-1's loop_sum_to.ail
as the positive-check fixture rather than create a near-duplicate.
First iteration of the loop-recur milestone: Term::Loop /
Term::Recur / LoopBinder as strictly-additive nodes across all six
crates' no-wildcard Term matches, parse/print/round-trip,
hash-stability + drift anchors. No typecheck semantics (synth
stubs CheckError::Internal — iter 2), no real codegen (lower_term
stubs CodegenError::Internal — iter 3); both stub points mirror
mut.1. Two Boss calls baked into the plan header: (1)
verify_tail_positions 'byte-unchanged' = tail-app role unchanged,
operationalised via the tail-app IR-snapshot non-regression test
(literal source freeze impossible — exhaustive no-wildcard match);
(2) codegen is in iter-1 scope as stubs/pass-throughs because the
workspace must compile for cargo test --workspace (the iter goal).
Recon DONE_WITH_CONCERNS — all three open questions resolved at
plan time (Q3: print.rs:352 is a Type match, untouched).
The effect-op-arg-modes brainstorm spec bundled a real, self-contained
DESIGN.md honesty fix with speculative build-ahead infra (an EffectOpSig
arg-mode field whose only consumer was a synthetic test op). Recon had
already destroyed the "effect-handler infrastructure" premise: the effect
raise/declare/subset/propagation machinery is fully generic over any
effect string; the only real prerequisite was one struct field, not a
milestone. The user rejected the bundle as incoherent and the
build-ahead half as the iteration-discipline trap repeated.
- Retire the uncommitted effect-op-arg-modes spec (deleted from the
working tree; never committed).
- roadmap: drop the false "sub-ms-2 = effect-handler infrastructure"
framing; mark Stateful-islands sub-milestone sequencing as UNDER
RE-THINK with the user (no !Mut planning until that conversation);
add the split-out effect-doc-honesty as an in-flight P2 [~] todo.
- plan docs/plans/2026-05-16-effect-doc-honesty.md: placeholder-free
tidy plan (the three DESIGN.md fictions + form_a.md + main.rs +
a new doc-presence pin) over recon-mapped exact byte sites.
- brainstorm SKILL: specs and design talk LEAD with the AILang (.ail)
program that should work (= the feature-acceptance clause-1
evidence); the Rust implementation shape is secondary, never a
substitute; a no-surface infra milestone still shows concrete .ail
(often a must-fail fixture). Codifies user feedback from this session.
11 tasks clustered on the recon's lockstep-invariant pairs so each
task leaves the workspace in a defined state. Forward revert against
git show 1ff7e81: as the per-region byte oracle (no git revert/reset;
main sacrosanct). Boss judgement folded in: bench/orchestrator-stats
it.* json KEPT (historical record like journals); A1 amendment
discard already done Boss-side pre-plan (the checkout step is a
no-op, only the superseded header remains on that file);
verify_structural_recursion helper provenance resolved by
oracle-diff method, not guess. carve_out_inventory corrected from
the spec's "recompute count" to the recon-accurate "remove 7
string-set entries". Net additions written verbatim (F1/F4 note,
de-claimed clause-3 sentence, deferred roadmap entry, superseded
header, doc-presence test) per the Iron Law. Behavioural-equivalence
gate (Task 11) builds a 1ff7e81 worktree reference compiler and
diffs the surviving corpus byte-for-byte — pristine, not ratified.
Parent spec: docs/specs/2026-05-16-iteration-discipline-revert.md
(b3853bf). Grounding-check PASS. Recon DONE_WITH_CONCERNS, all three
concerns Boss-resolved.
Boss-resolved design decisions baked in (DD-1 loop_stack in synth like
mut.2's mut_scope_stack + RecurNotInTailPosition in verify_tail_positions;
DD-2 LoopBinder derives = MutVar's, no PartialEq; DD-3 stub-then-fill
sequencing). Recon-enumerated walker-arm site list incl. the test-side
exhaustive match (codegen_import_map_fallback_pin.rs:62) mut.1's plan
missed. it.2/it.3 explicitly out of scope.
Eight tasks addressing the architect's two [high] drift items
(lambda-captures-of-mut-var diagnostic + codegen comment cleanup),
two [medium] items (stale mut.1-stub history comments in DESIGN.md
and codegen), plus the bench compile_check.py check_ms regression
(~30-50% relative; closed by short-circuiting the empty
mut_scope_stack walk in synth's Term::Var arm).
Architect's [low] item (prose render of MutVar drops type
annotation) deliberately deferred per architect recommendation —
prose surface design is itself pending.
Plan unblocks the follow-on Stateful-islands milestone (effect-
handler infrastructure + !Mut + refs) per architect gate.
Nine tasks: Emitter struct extension with mut_var_allocas +
pending_entry_allocas + entry_block_end_marker fields (Task 1);
start_block captures the entry-block byte marker (Task 2);
Term::Var resolution prepends mut-var lookup with load emission
(Task 3); Term::Mut codegen — alloca to side buffer, init at
current position, store to alloca, push binding (Task 4);
Term::Assign codegen — load alloca, lower value, store (Task 5);
final flush of pending_entry_allocas into self.body at the marker
(Task 6); examples/mut_counter.ail (Int) + examples/mut_sum_floats.ail
(Float) (Task 7); e2e tests in crates/ail/tests/e2e.rs (Task 8);
DESIGN.md bullet under 'What is supported' (Task 9).
Five Boss decisions encoded: entry-block hoist via String::insert_str
at the captured marker (chosen over post-pass or non-standard
emit-at-current); no LLVM helper wrapper — direct push_str matches
existing codebase convention; e2e tests append to the existing
crates/ail/tests/e2e.rs (reuse build_and_run helper); DESIGN.md
bullet lives in 'What is supported' subsection (recon misread —
the section exists at line 2680); Unit-codegen via the existing
Term::Lit { lit: Unit } canonical form.
Seven tasks: three new CheckError variants + code() + ctx() arms
(Task 1); synth signature extended with mut_scope_stack threaded
through ~19 recursive call sites in lib.rs plus the two re-synth
sites in mono.rs:712/1337 (Task 2); Term::Var resolution prepended
with innermost-first mut-scope lookup (Task 3); Term::Mut arm
(Task 4) and Term::Assign arm (Task 5) replacing the iter mut.1
Internal stubs with real logic; five negative fixtures + driver
(Task 6); positive verification of examples/mut.ail typechecking
clean (Task 7).
Four Boss decisions encoded: fixtures under examples/ with driver
at crates/ailang-check/tests/ (convention wins over spec wording);
mut_scope_stack as a synth parameter not an Env field (matches the
locals/effects/subst threading convention); MutAssignOutOfScope's
available list flattens all frames innermost-first;
mono.rs:712/1337 the two re-synth sites that need the threading.
Six tasks: AST + serde (Task 1), substantive walker arms across the
~25 exhaustive Term match sites (Task 2), the two dispatch stubs in
check_term and lower_term that produce CheckError::Internal /
CodegenError::Internal per the spec's out-of-iteration boundary
(Task 3), Form A parser + printer (Task 4), schema-drift + coverage
+ spec-drift extensions + form_a.md + DESIGN.md amendments (Task 5),
examples/mut.ail fixture with round-trip + corpus-coverage gate
(Task 6).
Three Boss decisions made explicit in the plan: walker-arm policy
(substantive everywhere except the two dispatch entry points),
empty-vars canonical-bytes pin, parse rejection of (mut) without
body. Plan-recon flagged all three; the plan resolves them rather
than deferring.
8 tasks. Closes the prelude-decouple milestone by deleting
examples/prelude.ail.json and sweeping the surviving consumers + spec
text + inventory. Three production consumers retire: the migrate-bare-
cross-module-refs defensive include in ail/src/main.rs (with its
lockstep skip-branch), the cross-form-identity preflight test in
ailang-surface (its purpose discharged at pd.2-close), and one in-mod
test in core's workspace.rs (re-pointed from inline include_str! to
ailang_surface::parse_prelude via the dev-dep). Adds a carve-out
retirement pin asserting the JSON file does NOT exist. Updates
carve_out_inventory.rs (eight → seven; §C4(b) row dropped) and the
form-a-default-authoring spec §C4(b) (RETIRED status marker added,
historical text preserved).
6 tasks, scoped to crates/ailang-core/src/workspace.rs only. Surface
unchanged in pd.1 (load_workspace_with survives as a thin shim
composed of the new fns + prelude inject). pd.2 will rewire surface
to call the new API directly and retire the shim. Plan-recon flagged
two ambiguities in the spec's iter-sketch vs. Components wording;
resolved here in favour of the shim approach so all existing tests
stay green without migration. ~12 in-tree validate_canonical_type_names
callers add &["prelude"] as the new second arg.
Adds the six IR-shape tests in crates/ail/tests/e2e.rs to Task 5's
file list and documents the test-harness patch (replace home-rolled
desugar+lift loop with monomorphise_workspace). The patch is the
small structural fix the rpe.1 BLOCKED orchestrator's Cat B
findings pointed to. With the two upstream codegen bugs now fixed
(commits 1fb225e + feb9413), the rpe.1 corpus migration plus this
Cat B harness patch should make the full retry green.
Single-iter plan implementing the rpe.1 spec. Ten tasks:
RED test, 92 .ail corpus migration, 6 .prose.txt regen,
four-site compiler deletion, five test-body migrations,
six doc-comment touch-ups, seven DESIGN.md sites, three E2E
comment touch-ups, bench ratification (per spec §C4 (a)),
and the close-out (roadmap strike, journal, stats).
Plan absorbs four spec-vs-code mismatches surfaced by recon
(one install-test instead of three, 92/6 fixture split rather
than 98, synth.rs:215 parallel registry, incidental test-body +
doc-comment sites) as an "Errata vs. spec" block at the top of
the plan; the spec itself is unchanged because none of the
mismatches affect load-bearing invariants.
Seven-task plan for adding str_concat : (borrow Str, borrow Str) -> Str
as a runtime + checker + codegen primitive in the four-site-lockstep
pattern established by str_clone / int_to_str / bool_to_str (iter
24.1).
T1: RED — new fixture examples/show_user_adt_with_label.ail
(LLM-natural Show body using str_concat) + E2E test
crates/ail/tests/str_concat_e2e.rs.
T2: runtime/str.c — append ailang_str_concat C helper after the
existing ailang_str_clone implementation (slab-alloc, memcpy
twice, terminate).
T3: ailang-check/src/builtins.rs — install + list() + new unit test
install_str_concat_signature; type is Fn { 2x Str borrow -> Str own,
effects empty }.
T4: ailang-codegen/src/lib.rs — extern declare ptr @ailang_str_concat
(ptr, ptr); lower_app arm after str_clone arm; extend
is_builtin_callable match list; append IR-pin unit test
str_concat_emits_call_to_ailang_str_concat.
T5: lockstep collision repair — rename str_concat -> format_label in
examples/bug_unbound_in_instance_method.ail and the corresponding
pin test (the fixture currently uses str_concat as the unbound
symbol because that was the literal fieldtester repro; after
shipping the builtin it would silently become a builtin call and
the pin would fail; format_label preserves the pin's intent under
an LLM-author-realistic name that will never become a builtin).
T6: DESIGN.md new §"Heap-Str primitives" subsection between the
milestone-24 amend block and the Primitive output paragraph,
cataloguing all 5 primitives (int_to_str, bool_to_str, float_to_str,
str_clone, str_concat) with one-line signatures + descriptions and
cross-references to runtime/str.c.
T7: verification + roadmap [x] strike entry.
Open questions resolved Boss-side ahead of dispatch:
- DESIGN.md anchor: new §"Heap-Str primitives" subsection (option (b)
in recon report) — the existing milestone-24 Show-backer enumeration
stays unchanged; the new section gives the heap-Str-primitive
category an explicit home.
- bug-fixture collision: rename to format_label (option (a) in recon
report) — LLM-author-realistic, preserves regression coverage.
Expected net delta: +3 tests from baseline (559 -> 562 green).
Post-fieldtest documentary tidy. Six tasks: T1-3 add three new
sections to crates/ailang-core/specs/form_a.md (Class, Instance,
Constraints on polymorphic fns) anchored against the live corpus
(test_22c_user_class_e2e for class-decl, show_user_adt +
mq3_class_eq_vs_fn_eq_classmod for instance, cmp_max_smoke for
constraints), each with EBNF + canonical-form-rule paragraph +
verified example. T4 fixes 5 contradictory "seven carve-outs"
sites in docs/specs/2026-05-13-form-a-default-authoring.md (the
audit-form-a journal flagged 3 sections; recon expanded to 5
total). T5 deletes the empty mod tests {} placeholder + its
6-line explanatory comment in crates/ailang-core/src/hash.rs
(form-a.1 T5 relocated the unit tests; placeholder serves no
purpose). T6 rewrites round_trip.rs module + inner test
docstrings to use the post-T10 four-property framing
(parse-determinism + idempotency + CLI-pipeline-idempotency +
carve-out-anchor) instead of retired Direction-1/Direction-2
language.
Drift item B2 (plan-file "seven carve-outs") dropped from this
iter per recon: the docs/plans/2026-05-13-iter-form-a.1.md file
contains zero defective sites; all four "seven" mentions are
internally scoped to §C4(a), arithmetic, or future-state. The
audit-form-a journal "two sites" claim does not match what is
in the plan file at HEAD.
All tasks are pure docs/comment changes. cargo test --workspace
stays at 559 green at every task boundary.
T1-5 dispatch journal surfaced 4 additional e2e.rs tests beyond
the originally-named diff_detects_changed_def that raw-read
.ail.json bytes and will break at T8 deletion:
- borrow_own_demo_modes_are_metadata_only (substring assertions)
- reuse_as_demo_under_rc_uses_inplace_rewrite (substring assertions)
- render_parse_round_trip_canonical (whole-corpus property already
pinned by T1's cli_parse_then_render_then_parse_is_idempotent —
retire as redundant)
- ail_run_accepts_ail_source_with_same_stdout_as_ail_json (dual-form
smoke — re-author to derive the .ail.json on-the-fly via ail parse
on a working fixture like hello.ail)
T7 grows from 4 steps to 7 steps; net test-count change −1 (retire
render_parse_round_trip_canonical). T7 close: 559 tests green.
Iter form-a.1 of the form-a-default-authoring milestone, Boss-decided
strategy C. End-of-milestone iter — all 156 non-carve-out .ail.json
files render+delete in this iter, plus all consumer migrations, plus
the roundtrip-CI restatement, plus the §A4 doctrine edits, plus
WhatsNew + roadmap strike.
Sequence: additive-then-subtractive.
- T1-2: new T1/T4 tests (additive) + render 99 missing .ail.
- T3-5: consumer migration (Group A load_workspace + Group B
subprocess + Group C production-code unit-test relocation).
- T6: bench-driver suffix updates.
- T7: e2e.rs synthesised-diff re-author to derive sum.ail.json
on-the-fly via ail parse.
- T8: bulk delete 156 .ail.json (carve-outs preserved).
- T9: retire obsolete roundtrip tests + flip schema_coverage corpus.
- T10: §C3 DESIGN.md roundtrip invariant restatement (4 properties
named, 5 enforcement tests pinned).
- T11: §A4 doctrine edits — CLAUDE.md + DESIGN.md "What this
Decision does not do" sentence.
- T12: WhatsNew + roadmap strike + final cargo test + bench check
+ 8-file inventory verification.
cargo test --workspace expected green at every task boundary. The
carve_out_inventory test is added #[ignore]'d in T1 and un-ignored
in T8 (RED-pinned until deletion happens).
Boss will dispatch implement in two task-ranges: [1,5] then [6,12]
to keep orchestrator-agent context bounded.
Iter 0 of the form-a-default-authoring milestone. One file
rendered (examples/prelude.ail.json -> examples/prelude.ail via
`ail render`), zero source-code edits, zero test-infra changes.
The migration mechanism is validated on the hardest single file
in the corpus (prelude exercises every language feature: classes,
superclasses, polymorphic free fns, IO effects, ctor patterns,
loader auto-injection). The two auto-discovering roundtrip tests
in round_trip.rs pick up the new .ail via read_dir without test
edits; both must pass for the iter to close.
Task 1: render + verify both roundtrip tests green + workspace
sanity check (5 steps).
Task 2: per-iter journal + INDEX append (2 steps).
prelude.ail.json retained per spec §A2 — this is the singular
dual-form iter; iter 1 deletes it with the bulk test-infra
refactor.
Tasks: T1 DESIGN.md new subsection §Cross-module references in
synthesised bodies documenting three iter-24.3 strengthenings
(canonical-form type_args, post-mono cross-module-ref import_map-
bypass, FreeFnCall constraint-residual push). T2 codegen import_map-
fallback pin (integration-style in crates/ail/tests/). T3 bare-name
poly-fn dot-qualified-branch invariant pin (asserts NoInstance fires
at typecheck not codegen). T4 replace unwrap_or_default() at
check/lib.rs:2852-2858 with expect(class_methods registry coherence).
T5 extract apply_subst_and_normalize helper from duplicated mono.rs
sites at :685-714 + :1284-1303. T6 integration + bench verification.
Boss decisions in Pre-flight section: T1 placement = new subsection
between DESIGN.md:1693 and :1695 (anchorable block beats append-in-
place); T2+T3 = integration-style tests (canonical xmod-test pattern,
not in-crate codegen); T5 helper extracts common concrete-resolved
arm only, returns Option<Type> so each call site keeps its rigid-
var / unit-default policy explicit.
Plan for iter 24.3, the second + final half of milestone 24.
Task 1: append fn print to prelude.ail.json with explicit-let body
\\x -> let s = show x in do io/print_str s. Task 2: mono symbol
IR-shape pin (AST-level Term-pattern match on post-mono
print__Int.body — protects the load-bearing let-binder for the
heap-Str RC discipline per eob.1 Str carve-out). Tasks 3-5:
three E2E fixtures + tests (positive 4-prim smoke, user-ADT
data IntBox + instance prelude.Show IntBox, negative print f
where f : Int -> Int firing NoInstance). Task 5 also extends
the Float-aware NoInstance arm at lib.rs:770-779 with a parallel
Show-aware branch. Task 6: DESIGN.md amendments (§Prelude classes
flip print to shipped, §Float semantics gains Show-Float NaN
paragraph). Task 7: roadmap P1 Show+print flips to [x] + new
P2 entry for io/print_int|bool|float retirement (insert at top of P2).
Task 8: integration + bench.
Boss decisions in plan Pre-flight section: ship explicit-let
(no auto-desugarer); AST-level IR-shape pin (Term pattern match);
NoInstance Show diagnostic wording with literal DESIGN.md section
cross-reference; P2 top-insertion for the retirement entry;
let-bound concrete fn-type for the negative fixture.
Plan for iter 24.2. Tasks 1-2: preemptive 22b-Show → TShow/tshow
rename across 21 fixtures + 2 Rust test files (the recon-corrected
count vs spec's '~14' undercount). Task 3: insert 5 new top-level
defs (class Show + 4 primitive instances Int/Bool/Str/Float) at
prelude.ail.json:223 before fn ne. Task 4: mono-synthesis existence
test for show__T. Task 5: dispatch-singleton pin (show vs tshow,
both Step-2 singletons post-migration). Task 6: hash-stability pin
extension. Task 7: DESIGN.md §Prelude(built-in) classes amendment.
Task 8: integration + bench verification.
Recon-Boss reconciliation captured in Pre-flight notes: 21 fixtures
(not 14), prelude line 223 insertion point, str_clone-reachability
verified by Task 3 round-trip.
Rigid-var refinement type-unification leg in refine_multi_candidate_residual
(high-1); same-module bare-class qualifier shape accepted (high-2);
class-method-shadowed-by-fn warning tightened to require an instance
in workspace_registry (medium-1); DESIGN.md Data Model schema fragments
cross-reference the canonical-form rule (medium-2).
Q1 revised from carrier "fix both sites" to "fix only discharge-time"
after code inspection: synth-time resolve_method_dispatch is invoked
with concrete_arg_type: None and the residual's metavar is constructed
AFTER the dispatch call, so the rigid-var leg has no residual type to
unify against — class-only filter is semantically correct there.
Q2 conservative tightening: filter via "any candidate class has any
registry instance" instead of deferring to App-arm via pending-warning
list (full spec rule).