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]).
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).
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).
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.
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.
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.
Post-audit downstream-LLM-author field test of the shipped
loop/recur surface (DESIGN.md + public examples only). 3 real
iterative programs (Newton isqrt, Collatz, Euclidean gcd) + 5
plausible-mistake negatives + 2 no-termination probes, all run
through the public ail CLI. 0 bugs. 4 working findings on the
milestone's own axes: rejection diagnostics point-exact AND
self-fixing; recur tail-position threads through match/let/outer-if
(spec only showed if); loop composes as a value sub-expression +
byte-stable round-trip; no-termination boundary exact. This
empirically substantiates the "LLM author can now write iterative
programs" claim.
Two orthogonal non-blocking findings, neither in loop/recur scope,
both routed to P2 todos (refused the scope creep into a loop/recur
tidy): niladic (app f) spec_gap independently re-confirms the
existing mut-local-F3 roadmap item (the design-fork decision
deliberately NOT auto-ratified under /boss — parked,
priority-strengthened); module-level (doc) diagnostic-hint friction
(one-line tidy). Boss-verified independently (gcd->27;
recur-outside-loop fires exact).
The standalone loop/recur milestone is fully ratified and CLOSED:
3 iterations + tidy shipped, audit clean (drift resolved, bench
pristine carry-on), fieldtest clean on every axis. Roadmap P0
marked closed.
First of three iterations of the standalone loop/recur milestone
(spec 97c1ed1). loop/recur become real parseable / printable /
round-trippable / hash-stable strictly-additive AST nodes across
every no-wildcard exhaustive Term match in all six crates, plus
parse/print, prose arms, DESIGN.md + form_a.md schema blocks,
drift/coverage/hash anchors, and the spec's worked sum_to program
as a green round-trip fixture. NO typecheck semantics and NO real
codegen this iter by design: synth and lower_term are stubbed
CheckError::Internal / CodegenError::Internal exactly as mut.1
(real typecheck = iter 2, real loop-header/phi/back-edge = iter 3).
Two binding Boss design calls recorded in the plan header and the
journal: (1) verify_tail_positions "byte-unchanged" = its tail-app
verification role is unchanged, not its source — it is an
exhaustive no-wildcard match so two descent-only arms are
mandatory; acceptance evidence is the tail-app non-regression test.
(2) codegen is in iter-1 scope as stubs/pass-throughs because the
workspace must compile for cargo test --workspace.
Three plan-pseudo-vs-reality substitutions (serde Type::Con
literal, bare Int -> (con Int), unqualified LoopBinder) and one
recon-undercount integration-test site, all intent-preserving and
journalled. Boss forward-fix folded in: the committed specs
themselves wrote bare Int in the loop-binder snippets (parses as
Type::Var) — corrected the three headline snippets to (con Int) for
doc-honesty (no design/schema change).
cargo test --workspace 600 -> 608 / 0 red (Boss-reran
independently); iter13a + new loop_recur hash pins green.
Brainstorm milestone spec for first-class additive Term::Loop /
Term::Recur (Approach A). De-bundled from the reverted
Iteration-discipline milestone: no structural-guardedness checker,
no Diverge effect — the half-enforced-dichotomy failure that sank
the original bundle is explicitly out of scope. recur has no
non-tail spelling (structural jump, by-construction stack safety).
verify_tail_positions left byte-unchanged; new private
verify_loop_body pass owns recur-tail-position checking. Feature
acceptance: all 3 clauses pass. Grounding-check Step 7.5: PASS,
9 ratified load-bearing assumptions. User-approved.
Distillation of the effects→input→state→closures→recursion design
session. Ratifies one meta-principle (disciplined surface, mechanism
stays in the compiler) as standing orchestrator guidance, separates
the three bundled DESIGN.md commitments (content-address-definitions
is cheap and kept; total value-purity + RC-no-collector are the
expensive ones), and parks four open forks with epistemic status for
later brainstorm pickup. No feature ratified here.
One forward iteration; main never rewound. 1ff7e81 (the pre-9973546
commit) is the per-region byte oracle — every reverted source/test
file is byte-identical to it; crates/ailang-check/src/lib.rs fully so.
Root cause being corrected: the Iteration-discipline milestone was an
over-escalation of fieldtest finding F1 (a [friction] item whose own
minimal recommendation was a DESIGN.md note). Its totality dichotomy
made the maximally-LLM-natural build(d:Int)=Node(1,build(d-1),
build(d-1)) inexpressible (it.3 BLOCKED); the only in-thesis escape
(A1/it.2b) conceded the language's first documented-unenforced
totality precondition — a purity-pillar dilution the user rejected in
favour of a full revert + rebuild.
Removed: Term::Loop/Term::Recur/LoopBinder; the verify_structural_
recursion guardedness pass + term_contains_loop + Diverge-injection +
the transitively-it.2 module_fns plumbing; the five Recur*/
NonStructuralRecursion CheckError variants (+ code() + the 3 dedicated
ctx() arms); the it.1 codegen loop-header/phi/back-edge + parallel
block_terminated setter; all Loop/Recur walker arms; 16 it.1/it.2
fixtures; 2 pin files; bench/it3-oracle/. Restored: 2 RC fixtures to
1ff7e81 content.
Surgically kept (not in 1ff7e81, landed with the milestone but
independently sound): feature-acceptance clause 3 in DESIGN.md and
skills/brainstorm/SKILL.md, with its worked example de-claimed from
"shipped" to hypothetical-illustration form; the F3 P2 todo.
bench/orchestrator-stats/2026-05-15-iter-it.{1,2,3}.json kept as
historical record (like journals/plans).
Sole net addition: an honest F1/F4 documented-idiom note in DESIGN.md
(the tail-recursive accumulator fallback; examples/mut_counter.ail),
guarded by a doc-presence test — "a documentation note is not a
reshape", asserts nothing at the typecheck level.
Roadmap: the Iteration-discipline block + blocking-fork section
removed; the genuine total-Int-recursion ambition preserved as a
deferred P2 milestone sequenced behind a future Nat/refinement-types
milestone (not abandoned — correctly sequenced after the type
machinery it needs). 2026-05-15-iteration-discipline.md carries a
superseded header; it.1/it.2/it.3 journals + plans stay as history.
Correctness gate PRISTINE: 164 surviving 1ff7e81-era fixtures
ail check/ail run byte-identical to pre-milestone behaviour (verified
against a 1ff7e81 worktree reference compiler, zero drift);
cargo test --workspace 600/0; zero residual it.1/it.2 production
surface.
Spec docs/specs/2026-05-16-iteration-discipline-revert.md (b3853bf),
plan docs/plans/2026-05-16-iter-revert.md (abf0013).
The Iteration-discipline milestone was scoped from fieldtest finding
F1 (a [friction] item whose own minimal recommendation was "tighten
DESIGN.md") and escalated into "retire tail-app, recursion total-by-
construction, add Diverge". it.3 BLOCKED on the most LLM-natural
tree-builder shape (build(d:Int)=Node(1,build(d-1),build(d-1))),
which the thesis makes inexpressible; the only escape (A1/it.2b)
concedes the language's first documented-unenforced totality
precondition (no Nat/refinement enforcement — Decision 4). it.2's
NonStructuralRecursion checker is not a stable additive stopping
point — it half-enforces a dichotomy only the destructive it.3
completes.
User decision (2026-05-16): full revert to the pre-milestone state.
Both it.1 and it.2 come out via one forward iteration (main
sacrosanct). tail-app/structural recursion remain the iteration
mechanism exactly as before 9973546. Feature-acceptance clause 3 is
kept (it is the tool that diagnosed the over-escalation); F1/F4 get
the honest DESIGN.md documentation note the fieldtester actually
recommended. The genuine total-Int-recursion ambition is re-
sequenced behind a future Nat/refinement milestone, not diluted to
fit today. Stateful-islands (P2, the real ~/sma_factory.myc
descendant) is untouched.
Grounding-check (brainstorm Step 7.5): PASS after one factual
correction (the ctx()-arm removal split). Spec is the contract for
the revert planner+implement.
Two HEAD-vs-spec defects the it.3 recon found, fixed at the spec:
(1) "remove is_false" was wrong — is_false is shared with
WorkspaceDef.drop_iterative; it survives, doc re-scoped only.
(2) "remove the Decision-3 Diverge line" struck — it.2 already
rewrote Decision 3 to make Diverge the real effect (the milestone's
payload); it.3 touches Decision 8 only.
(3) The codegen-rework bullet under-described the real risk: the
18g.1 pre-tail-call husk-dec (match_lower.rs:658-736) reads
Term::App{tail:true} directly, protects the 18f.2 RC-RSS pin, and
its field-forced deletion is RC-safe ONLY if it.1 loop codegen
drops superseded owned binders across recur — unverified. Spec now
names this as the load-bearing it.3 risk with a RED-gated
verification + a named remediation (owned-loop-binder-drop-on-recur
in scope for it.3). Only 3 (not 7) setters are tail-driven.
No design decision (D1-D4) changes; design validated by shipped
it.1/it.2. Not relitigating shipped work (spec_over_plan_patches).
The original spec premise "21 .ail fixtures / 34 (tail-app …) sites"
under-counted the corpus's non-structural-recursion surface. it.2
proved the true it.3 migration set is three classes: the ~20
tail-app-marked fixtures + ~18 no-ADT-candidate counter-recursion
fixtures (deferred via it.2's no-candidate skip) + the 2 RC fixtures
it.2 joined to the transitional grandfather. it.3 removes the
tail==false grandfather AND the no-ADT-candidate skip together.
No design decision (D1-D4) changes — factual scope-widening only,
traceable to 2026-05-15-iter-it.2.md §Concerns. Not relitigating
the complete, green it.2 (feedback: spec_over_plan_patches — fix
the spec where it governs, not the plan around it).
User-approved 2026-05-15 (read, probed via the sma_factory.myc streaming
analysis, no D1/D2 change requested, proceed-by-/boss). Grounding-check
PASS holds: spec bytes unchanged since the Step 7.5 dispatch (the
non-load-bearing "34 vs 36 tail-app sites" wording left as attested
rather than re-grounding for a count the agent ruled non-defect; the
21-fixture migration unit is exact). Three ordered iterations: it.1
loop/recur additive, it.2 guardedness checker + Diverge effect, it.3
tail-app/tail-do retirement + corpus migration.
Boss-dispatched fieldtest after audit-mut-local closed. Six AIL
Surface (.ail) fixtures under examples/fieldtest/ exercise the
shipped mut-local surface from a downstream-LLM-author's perspective
(no compiler-source access; DESIGN.md + public examples only).
Positive fixtures all run end-to-end first-try:
- mut-local_1_factorial.ail: straight-line Int accumulator
unroll (5!), prints 120.
- mut-local_2_classify_temp.ail: nested-if assigns into a Unit-
typed mut block, prints classification code.
- mut-local_3_horner.ail: Float mut accumulator for polynomial
evaluation, prints 18.
- mut-local_4_has_small_factor.ail: Bool mut flag via four
if-then-assign checks, prints true.
Negative probes confirm diagnostics fire as documented:
- mut-local_5_lambda_capture_probe.ail: [mut-var-captured-by-lambda].
- mut-local_6_diag_probe.ail: [mut-var-unsupported-type].
Findings:
[friction] F1 — mut without iteration: the accumulator-over-an-
iteration shape never materializes. Without while/for, the LLM-
author still writes a tail-recursive helper (the very pattern
the milestone Goal said mut would replace). examples/mut_counter.ail
illustrates the degeneration. Routing: planner for a while/for
iteration OR tighten DESIGN.md to name the gap honestly.
[friction] F2 — all four mut-related diagnostics emit their
bracketed [code] twice ('error: [code] fn-name: [code] message').
Mechanical bug: the #[error('[code] ...')] Display attributes I
authored in mut.2/mut.4-tidy include the bracketed prefix in the
message body, and the cli-diag-human formatter adds another from
CheckError::code(). Routing: debug (mechanical message-body
cleanup).
[friction] F3 — no surface form to call a zero-arg fn ('(app f)'
rejected at parse with 'expected at least one argument').
Orthogonal to mut-local but surfaced building the closure-factory
probe. Routing: planner for a small tidy iter.
[spec_gap] F4 — DESIGN.md does not name the 'use a tail-rec
helper instead' workaround for the iteration-over-accumulator
shape that mut alone cannot express. Routing: ratify in DESIGN.md
alongside F1's resolution.
[working] W1/W2/W3 — surface reachable on first read; diagnostics
pinpoint cause (mut-assign-out-of-scope even lists available
vars); composes cleanly with if + lambda-without-capture +
final-expression position.
Spec: docs/specs/2026-05-15-fieldtest-mut-local.md (333 lines).
Refs: docs/specs/2026-05-15-mut-local.md, audit-mut-local close
at 8685e96.
Tidy iter addressing the audit-mut-local drift. Plus paired baseline
update on bench/baseline_compile.json (audit-skill discipline).
Architect [high] items closed:
1. CheckError::MutVarCapturedByLambda rejects lambdas whose body
free vars include a mut-var of the enclosing mut_scope_stack.
Uses the existing ailang_core::desugar::free_vars_in_term walker
(which honours Term::Match pattern bindings). The scan runs only
when mut_scope_stack is non-empty.
2. crates/ailang-codegen/src/lambda.rs: the capture-not-in-locals
path that previously raised CodegenError::Internal blaming the
typechecker now uses unreachable!. The companion comment block
was rewritten to state the current reality.
Architect [medium] items closed (stale mut.1-stub history comments):
3. docs/DESIGN.md §'Term (expression)' mut/assign block: the
trailing paragraph describing the iter mut.1 stub state was
replaced with one describing the current mut.3-end-state. The
inline jsonc comment on {'t': 'assign'} was updated to drop the
'deferred to mut.2/mut.3' language.
4. crates/ailang-codegen/src/lib.rs: the stale comment block above
the real Term::Mut arm describing the mut.1 stub was removed
entirely.
Other:
- Short-circuit on empty mut_scope_stack in synth's Term::Var arm:
the iter mut.2 prepend now skips the iter-and-find walk when
the stack is empty, eliminating any per-Var-resolution overhead
for the common case (programs with no mut blocks). The
short-circuit did NOT close the check_ms regression — see ratify
below.
- Spec docs/specs/2026-05-15-mut-local.md §'Out of scope' amended
with the lambda-capture rejection bullet.
- Negative fixture examples/test_mut_var_captured_by_lambda.ail.json
+ driver test extension in crates/ailang-check/tests/
mut_typecheck_pin.rs (6th test) +
crates/ailang-core/tests/carve_out_inventory.rs EXPECTED bumped
12 → 13.
Bench-regression ratify:
bench/compile_check.py check_ms showed a uniform ~30-50% relative
shift across the entire 11-fixture suite (~0.5ms absolute on a
1.4-1.5ms baseline). The uniformity across fixtures of very
different Var counts argues for a fixed-cost-per-invocation tax,
not a Var-proportional hot path. The Term::Var short-circuit
falsified the hot-path hypothesis. The plausible remaining causes
(synth-parameter-passing through ~19 recursive sites, and binary-
size startup tax from mut-* adding ~1400 LOC to typecheck/codegen)
are both feature-cost, not pathological. Ratified by paired
journal entry; bench/baseline_compile.json updated to the post-
mut-local numbers via 'bench/compile_check.py --update-baseline'.
bench/check.py continues to show the established tail-latency-noise
envelope from audit-pd (2026-05-14) — no separate ratify needed.
bench/cross_lang.py clean.
Tests: 594 → 598 green (4 new lib.rs mod tests + 1 driver test +
1 fixture-corpus uptake).
Journal: docs/journals/2026-05-15-iter-mut.4-tidy.md.
mut-local milestone end-to-end status:
- mut.1 (7b92719): AST + Form A surface.
- mut.2 (b24718a): typecheck.
- mut.3 (03fb633): codegen + e2e.
- mut.4-tidy (this commit): audit-drift close + bench ratify.
mut-local milestone CLOSED.
Refs: docs/specs/2026-05-15-mut-local.md,
docs/plans/2026-05-15-iter-mut.4-tidy.md.
First shippable milestone on the Stateful-islands roadmap path:
sealed-by-construction local mutable bindings in fn bodies, with
no ref-types, no effect handlers, no escape. Lowers entirely to
LLVM allocas with statically-bounded lifetime; fn signatures stay
pure (no !Mut effect leakage).
Three iterations: mut.1 (schema + surface), mut.2 (typecheck +
diagnostics), mut.3 (codegen + e2e). Var element types restricted
to Int/Float/Bool/Unit (non-RC-managed scalars) in this milestone;
Str/ADT/fn-value vars deferred.
Grounding-check PASS on iteration mut.1 assumptions: Term enum
extension is gated by design_schema_drift, round-trip by
ailang-surface round_trip auto-discovery, DESIGN.md amendment by
the same drift test, schema_coverage forces a corpus fixture.
Deleted examples/prelude.ail.json (-559 lines). The cross-form-identity
preflight test that ratified pd.3's load-bearing assumption at module
hash 3abe0d3fa3c11c99 has discharged its purpose and was removed
along with its supporting bytes; the long-term prelude_parse_yields_canonical_hash
anchor stays. The ail-CLI migrate-bare-cross-module-refs subcommand's
defensive include + lockstep skip-branch removed; the rewrite logic's
prelude-fallback capability silently retired with the synthetic insert
(known debt, doc-comment updated to reflect). One in-mod core test
relocated to crates/ailang-core/tests/workspace_pin.rs (pd.2.4 dev-dep
cycle precedent — in-mod call to ailang_surface still structurally
impossible).
carve_out_inventory.rs: 8 → 7 carve-outs, §C4(b) row dropped, header
sentence updated. form-a-default-authoring.md §C4(b) gets a "RETIRED
2026-05-14 by milestone prelude-decouple" status marker; original
historical text preserved. New prelude_decouple_carve_out_pin.rs
asserts examples/prelude.ail.json does NOT exist.
Milestone prelude-decouple closed: prelude exists on disk only as
examples/prelude.ail; ailang-core embeds zero prelude bytes; CLAUDE.md
"authors write .ail" doctrine holds without exception.
cargo test --workspace 573 green; bench/cross_lang.py +
bench/compile_check.py exit 0; bench/check.py exit 1 with the
established noise envelope (14th observation of bench_list_sum.bump_s
since audit-cma; pd.3 is filesystem + spec text + test deletion only,
no codegen / runtime / typecheck path edited — baseline pristine).
Folds in the orphan pd.2 INDEX entry that was left uncommitted in the
working tree.
Brainstorm settled on the β.2 loader-split: ailang-core stops
embedding prelude bytes, stops auto-injecting a "prelude" module,
and stops hardcoding the literal "prelude" in cross-module-ref
diagnostics. ailang-surface assumes ownership of the prelude
content and the reservation. Three iters: pd.1 splits the core
API into load_modules_with + build_workspace; pd.2 moves the
embed source from .ail.json to .ail with a cross-form-identity
preflight; pd.3 deletes examples/prelude.ail.json and updates the
form-a §C4 (b) carve-out. Grounding-check PASS twice (initial +
post-self-review re-dispatch).
Single-iter milestone closing the post-milestone-24 follow-up named
in docs/roadmap.md lines 80–90 and DESIGN.md §"Polymorphic print"
lines 1990–1992. Migrates the 98 examples/*.ail fixtures from
(do io/print_int|bool|float x) to (app print x), deletes the three
per-type effect-op builtins + codegen arms + tests, and sweeps the
seven DESIGN.md sites that reference the retired ops.
§C4 decides the bench-latency-fixture carve-out question (option a:
migrate everything, ratify any latency-baseline drift as part of the
milestone; option b's carve-out would defeat the milestone's
premise).
Grounding-check PASS — all seven load-bearing assumptions
ratified by named workspace tests.
Six-task post-fieldtest documentary tidy. No production-code behaviour
changes; 559 tests green at every per-task gate.
T1-T3: form_a.md additions
- §Definitions intro "Three kinds" -> "Five kinds".
- New `### Class — (class ...)` subsection: EBNF carries optional
superclass (0 or 1 per ClassDef.superclass schema), method
signatures with optional defaults; anchored to
examples/test_22c_user_class_e2e.ail (ok 24/2).
- New `### Instance — (instance ...)` subsection: EBNF carries the
(method NAME (body LAM-TERM))* shape; canonical-form CLASS-REF
rule explicitly stated (bare same-module / qualified cross-module);
two examples — same-module abbreviated from
mq3_class_eq_vs_fn_eq_classmod.ail and cross-module qualified
from show_user_adt.ail; bare-cross-module-class-ref diagnostic
named inline.
- §Types `(forall ...)` line extended with optional `(constraints
(constraint CLASS-REF TYPE)+)?` clause; explanatory paragraph
added with no-instance diagnostic anchor; fifth example added
to the Examples block anchored to cmp_max_smoke.ail.
T4: docs/specs/2026-05-13-form-a-default-authoring.md "seven
carve-outs" → "eight carve-outs" at 6 sites contradicting the
§C4(b) compile-time-embed amendment (commit 9fcda8b). Sites:
preamble line 11, §C1 line 170, §C2 line 191, §C3 line 218,
§"Data flow" lines 363 + 374. Post-edit grep returns 4 surviving
"seven" lines (233, 238, 463, 469), all correctly §C4(a)-scope
or arithmetic/future-state.
T5: crates/ailang-core/src/hash.rs:50-57 — delete empty
`#[cfg(test)] mod tests {}` placeholder + 6-line relocation
comment. Tests live in crates/ailang-core/tests/hash_pin.rs
since form-a.1 T5; placeholder served no purpose. hash_pin.rs
still 10/10 passing.
T6: crates/ailang-surface/tests/round_trip.rs — module-level
`//!` and inner `///` docstrings rewritten to the post-T10
four-property framing (parse-determinism / idempotency /
CLI-pipeline-idempotency / carve-out-anchor) instead of the
retired Direction-1/Direction-2 language. Sibling-crate
breadcrumbs added pointing at the other two enforcement points
(roundtrip_cli.rs, carve_out_inventory.rs).
Drift item B2 (audit-form-a "plan file two sites") dropped per
recon verification: docs/plans/2026-05-13-iter-form-a.1.md
contains zero defective "seven" sites; all four hits are
internally scoped to §C4(a), arithmetic, or future-state.
Decision recorded in the journal.
Closes 2 of 3 fieldtest-form-a spec_gap findings (#2 form_a.md
typeclass surface + #3 form_a.md class-qualifier rule for
instance) and 3 of 4 audit-form-a drift items.
Boss-dispatched fieldtest at milestone close. Agent authored 4 .ail
fixtures (factorial smoke + Show user-ADT + user-class Describe with
two instances + two-module workspace) from DESIGN.md + form_a.md only
(no compiler-source reads, no spec-of-milestone reads). All four
fixtures `ail check` ok and `ail run` produces expected stdout.
Findings (1 bug, 1 friction, 2 spec_gaps, 3 working):
- [bug] instance-method-body unbound-var bypasses `ail check` —
forma_3 first attempt called `str_concat` inside the instance
method body; `ail check` returned ok, `ail build` died with the
monomorphise_workspace "unknown identifier" diagnostic. Same
shape at fn-body level correctly fires `[unbound-var]` at check
time. Next: debug skill, RED-first against `ail check`.
- [friction] no `str_concat` primitive. Every realistic Show MyType
body wants string concatenation; the absence forced the agent to
shape examples around bare int_to_str / ctor-arity-1 patterns.
Next: small planner tidy iter wiring `str_concat` symmetric to
`str_clone` and `int_to_str`.
- [spec_gap] form_a.md has zero references to class, instance,
constraint, or method productions — pre-22 surface only. The
form-a-default-authoring milestone made .ail the authoring form,
but the form_a spec doc remains pre-typeclass.
- [spec_gap] form_a.md leaves the class-qualifier ambiguity in
`(instance (class X))` unspecified — bare-class-name vs canonical-
form rule from mq.1 is not documented at the surface level. The
agent picked the bare-name reading from the corpus; the canonical-
form reading is equally plausible from the schema.
Boss-side cleanup at commit time:
- Deleted 8 stale .ail.json sidecars in examples/fieldtest/ (4
forma_* derived by the fieldtester per old dual-form workflow + 4
pre-existing floats_* from the prior fieldtest milestone that
iter form-a.1 T8 missed because the bash deletion loop globbed
only examples/*.ail.json direct children).
- Updated skills/fieldtest/agents/ailang-fieldtester.md to remove
the now-obsolete "generate canonical JSON sidecar" step (Phase 3
rewritten + Iron Law + Reading list + Common Rationalisations +
Red Flags all aligned to the post-form-a single-form doctrine).
cargo test --workspace: 557 passed, 0 failed, 3 ignored (unchanged
from audit-form-a — the fieldtest fixtures are standalone, not
referenced by any test).
Findings deferred to follow-up iters; the milestone close itself is
still clean.
Iter form-a.1 recon surfaced a load-bearing constraint the original
spec didn't anticipate: ailang-core embeds prelude.ail.json at
compile time via include_str! + serde_json::from_str (workspace.rs:417,
main.rs:474), and ailang-core cannot import ailang-surface to switch
the embed to .ail (crate-cycle, documented at loader.rs:9-13).
§C4 splits into two carve-out categories:
- (a) seven subject-matter carve-outs (unchanged, the original list)
- (b) one compile-time-embed carve-out: prelude.ail.json
Acceptance criteria #1, #2 and §T4 carve-out inventory test updated
from 7 to 8.
Roadmap: new [milestone] "Prelude embed: Form-A as compile-time source"
queued to retire §C4(b) by either splitting the workspace loader
(prelude-init moves to ailang-surface) or generating prelude.ail.json
via build.rs. examples/prelude.ail (rendered iter form-a.0) is the
dual-form symptom that milestone exists to resolve. Strike the [todo]
"Author examples/prelude.ail" entry — satisfied by iter form-a.0.
Re-grounding-checked PASS over six load-bearing assumptions (embed
sites verified at workspace.rs:417 + main.rs:474; crate-cycle
constraint real; eight carve-outs all on disk; prelude.ail green
under both roundtrip tests).
Form A (.ail) becomes the sole authoring surface for every program
in the working tree. The seven negative-test JSON-AST fixtures are
the only post-milestone .ail.json files; everything else is rendered
to .ail and the JSON counterpart is deleted (single representation
per program).
Spec decides the four open design questions inline:
- A1: in-process parse via ailang_surface::parse, no build-time
target/ artefacts (would reintroduce a second representation).
- A2: prelude.ail ships as iter-0 pilot, validated by the existing
every_ail_fixture_matches_its_json_counterpart gate.
- A3: per-file deletion cadence; iter 0 is the singular dual-form
window because the JSON counterpart is the witness the CI gate
uses.
- A4: CLAUDE.md and DESIGN.md reworded — canonical vs authoring
forms separated, JSON-AST stays canonical/hashable, .ail becomes
the authoring entry point.
Roundtrip invariant restates from "two forms agree byte-for-byte"
to "parse is deterministic + idempotent under print"; carve-out
inventory test pins the seven JSON-only fixtures against silent
list drift.
Grounding-check PASS over 8 load-bearing assumptions.
Iteration scope: iter 0 = prelude pilot only (render
prelude.ail.json -> prelude.ail; do not delete the JSON yet; do
not touch CLAUDE.md/DESIGN.md/tests yet).
Re-derives the deferred iters 24.2 (class Show + 4 prim instances)
and 24.3 (print free fn + E2E) against the post-mq architecture.
Iter 24.1 shipped at f38bad8 and is unchanged. The supersedes-note
in the spec frontmatter explains the relation to the predecessor at
docs/specs/2026-05-12-24-show-print.md.
Substantive deltas vs. predecessor:
- Dispatch routing through the mq.2/.3 5-step rule; constraint-driven
filter (mq.tidy T1) is load-bearing for show calls inside print's
body.
- 24.2 grows to include the 22b-Show -> TShow/tshow migration
(~14 fixtures + 2 Rust test files) to eliminate post-prelude.Show
ambiguity, analogous to the existing TEq/TOrd convention.
Grounding-check PASS (re-dispatched after two LBA path corrections;
12 load-bearing assumptions all ratified).
Retires the workspace-global MethodNameCollision pre-pass
(crates/ailang-core/src/workspace.rs:547) via a phased three-iter
milestone. Iter 1 canonicalises InstanceDef.class, Constraint.class,
and SuperclassRef.class (extends ct.1's validator); Iter 2 installs
type-driven dispatch (method_to_candidate_classes index + multi-
candidate residual + AmbiguousMethodResolution / UnknownClass
diagnostics) while the workaround still gates real workspaces;
Iter 3 deletes the pre-pass and ships multi-class E2E plus DESIGN.md
sync. Unblocks the deferred milestone 24 (Show + print rewire).
Step 7.5 grounding-check PASS: all 18 load-bearing assumptions
ratified by named, currently-green tests.
24.2 plan-recon surfaced a spec-gap: adding `class Show` to the prelude
would collide with the user-class `Show` declared by 14 test fixtures
under examples/test_22b{1,2,3}_*.ail.json (plus hardcoded "Show" /
"show" assertions in crates/ail/tests/typeclass_22b{2,3}.rs) through
the workspace-global method-name-collision pre-pass at
crates/ailang-core/src/workspace.rs:547.
Three resolution paths surfaced: (A) prep-iter rename Show→Render in
fixtures+tests, (B) inline-rename in 24.2 (makes iter bigger),
(C) defer 24.2+24.3 until the P2 milestone "Module-qualified class
names + type-driven method dispatch" retires the MethodNameCollision
workaround. User picked C.
Spec status flips Draft → Partial; the document remains as historical
context for the future re-brainstorm. Iter 24.1 retains as standalone
runtime infrastructure (`bool_to_str` + `str_clone` heap-Str
primitives are user-callable today; they wait for the deferred Show
instances to find their primary caller). Roadmap P1 entry flips
`[ ] → [~]` with `depends on:` line pointing at the P2 milestone.
Milestone 24 closes the Post-22 Prelude roadmap entry's second half.
Architecture: `class Show a where show : (a borrow) -> Str`, four
primitive instances (Int/Bool/Str/Float — Float included because
float_to_str is semantically unproblematic, unlike Eq/Ord's IEEE-754
issues), and `print : forall a. Show a => (a borrow) -> () !IO` as
a polymorphic free fn following 23.5's `ne/lt`/etc. shape. Two new
runtime primitives (`bool_to_str`, `str_clone`) let Show Bool and
Show Str honour the uniform `(a borrow) -> Str Own` signature without
codegen intercept.
Three iters: 24.1 (runtime + codegen for the two new primitives),
24.2 (class + 4 instances in prelude.ail.json + DESIGN.md anchor),
24.3 (print free fn + positive/user-ADT/negative E2E + DESIGN.md
sync).
io/print_int|bool|float STAY this milestone — redundancy with `print`
ratified as transitional per the 23-spec precedent for ==/eq. Corpus
migration (86 fixtures) queued as separate P2 follow-up.
Grounding-check PASS: all 12 enumerated load-bearing assumptions plus
two additional implicit claims ratified by currently-green named tests
(eob.1 RC-discipline tests anchor 24.1's critical group; milestone-23
mono unification anchors 24.2/24.3's group).
hs.4 surfaced a leak the heap-str-abi spec didn't account for:
heap-Str slabs handed back by int_to_str / float_to_str and
immediately printed via io/print_str leak at scope close under
--alloc=rc. RED tests at e2e.rs (commit 592d87b) pin it.
Brainstorm settled on naming the rule rather than working
around it: Term::Do.args[*] are walked in Borrow position by
uniqueness and linearity passes, symmetric to Term::Ctor.args[*]
being walked in Consume position. The kind itself carries the
ownership default — no per-op field on EffectOpSig.
The rule alone doesn't close the leak; two heap-Str-specific
shape fixes follow (int_to_str / float_to_str gain ret_mode: Own;
drop_symbol_for_binder's App arm gets a Str carve-out symmetric
to field_drop_call's existing one). DESIGN anchor + WhatsNew +
audit-close from hs.5 roll into this milestone.
Grounding-check PASS — all nine load-bearing assumptions
ratified against currently-green tests (with the two RED tests
ratifying the leak as the spec's premise).
hs.2's implementer-orchestrator BLOCKED with an empirical finding: the iter 18d.3 move-tracking and iter 18b non-escape lowering together prevent static-Str pointers from ever reaching ailang_rc_inc/_dec along any shipping execution path. The previously-proposed runtime sentinel guard and the i64 -1 sentinel slot in static-Str globals were both dead by construction.
Amendment is subtractive: remove the runtime/rc.c guard from §Architecture/Runtime layer + §Components/runtime/rc.c (none needed), shrink static-Str globals from <{i64, i64, [N+1 x i8]}> to <{i64, [N+1 x i8]}> (saves 8 bytes per literal), update GEP indices (i32 0, i32 1 → i32 0, i32 0), drop the §Error-handling 'Sentinel collision' subsection, drop the proposed str_field_in_adt_drops_static_str_noop safety-gate test from §Testing strategy (vacuous against natural fixtures), reframe §Architecture/Codegen-4 as 'codegen-level elision invariant, no runtime guard'. Goal/consumer-ABI claims tightened to 'unified along consumer paths, producer + RC sides differ'.
Acceptance: re-dispatched grounding-check PASS. The amendment leaves hs.1 (committed at c56498a) needing a forward-fix retrofit — that is the new hs.2's scope, planned next.
Two builtins ship together: int_to_str (new) and float_to_str (today type-installed but codegen-deferred). Both produce malloc-backed, refcounted Str slabs via new ailang_int_to_str / ailang_float_to_str runtime exports.
Slab layout is {rc_header, len, bytes, NUL}. Static-Str globals migrate to the same packed-struct shape with a UINT64_MAX sentinel rc_header; ailang_rc_inc / _dec short-circuit on the sentinel. From every caller's POV static and heap Str values are indistinguishable, so existing code paths (eq__Str, compare__Str, io/print_str, per-type drop walks) keep working with a single +8 GEP at the three C-API callsites and no change to drop dispatch.
Out of scope: ++ concat operator, Show typeclass + print rewire, length-aware comparison for embedded-NUL Strs.
Single foreign subject (Qwen3-Coder-Next via IONOS). Two blind
cohorts: one sees only a JSON mini-spec, the other only an .ailx
mini-spec; same four tasks. Fairness anchored by a master source
plus a renderer (built on the existing ailang-surface roundtrip
machinery) that projects two form versions from one canonical
content base. Harness shells out to ail parse / check / build / run
and feeds back location-stripped errors so the JSON-pointer
asymmetry doesn't tilt the experiment. Out of scope for v1: a
verdict on Decision 6, a free-choice cohort, repetitions, a second
subject.
Grounding-check PASS on cma.1 (master + renderer + tests).
Recon surfaced that several draft 'moved OUT' sections were universal,
not mode-specific (agent role boundaries, authority over skills, design
rationale, feature-acceptance criterion, when-not-to-delegate). These
apply in any session — interactive or /boss-active — because agents can
be dispatched, design choices can be made, and skills can be edited
outside /boss too.
Tighten the move-list to the three genuinely mode-specific subsections:
Direction freedom, Notifications, Done-state notifications: WhatsNew.md.
Everything else stays in CLAUDE.md. /boss becomes leaner, the universal/
mode-specific boundary is drawn at content that only applies inside the
autonomous loop. Re-dispatched grounding-check: PASS.
Brainstorm assumed all four 23.4-prep commits had shipped to main.
Branch verification (post-iter/23.4 deletion) showed only prep1
(linearity + check bare-name) is on main; prep2 + prep3 were
attempted on the stranded iter/23.4 branch and never landed.
Spec corrections:
- Goal section: prep-commit status block reflects actual main state.
- Architecture: drop §2 (prep2/prep3 rollback) — no rollback exists
on main; section count drops from four to three artefacts.
- Components table: prep2/prep3 row now reads 'abandoned 2026-05-11
with iter/23.4 deletion', not 'shipped, rolled back in 23.4'.
- Acceptance criterion 1: drop the 'prep2 + prep3 are rolled back'
clause.
- Load-bearing assumption 5: now states prep2/prep3 never reached
main (fixes the silent-assumption pattern this spec exists to
prevent — same failure mode the original Spec-23 had).
- Load-bearing assumption 6: cite the cherry-picked main SHAs
(0caaced, 923dd8c) alongside the stranded-branch originals
(8d39f13, aef4ab8).
- Known costs: drop the '23.4 rollback' line item.
Plan-recon for iter 23.4 surfaced that poly_box_proj.ail.json does
not exist in examples/. The three load-bearing regression fixtures
are poly_id, poly_apply, and poly_rec_capture (the latter at
examples/poly_rec_capture.ail.json, driven by e2e.rs::poly_rec_capture_demo).
Three references in the spec corrected. Substantive intent (three
existing polymorphic fixtures regress unchanged under unified mono)
unchanged.
Re-brainstorm of milestone 23 after the original spec retired in
iter gc.1. The original silently assumed polymorphic free fns are
mono-specialised parallel to class methods; iter 23.4 BLOCKED three
times on that seam. Revised spec corrects the architecture by
committing to a unified typecheck-time mono pass (B1) — one
specialiser for all Type::Forall Defs, codegen-time
lower_polymorphic_call retired in same iter. First real run of the
grounding-check agent (Step 7.5) shipped in gc.1: PASS, 15
assumptions ratified.
Discussion-draft, not an approved spec. Captures today's findings:
- Repeated BLOCKEDs on iter 23.4 family were a spec-defect signal,
not a plan-defect signal.
- Today's spec-verification (brainstorm Step 7 + 8) is purely
linguistic — no code-grounded check of load-bearing assumptions.
- Spec-23's 'work the same way as 22b.3' half-sentence was the
exact load-bearing assumption that broke. Three preps spent
patching what should have been caught pre-approval.
Proposes a new agent that, with fresh context between brainstorm
Step 6 and Step 7, extracts load-bearing assumptions from the spec
draft and searches for an existing green fixture ratifying each.
Default on miss: spec discarded, blocked idea moved to roadmap with
'depends on: <missing prerequisite>'.
Eight open design questions left for the next session's brainstorm
to answer.