58 KiB
AILang Roadmap
Priority-ordered list of upcoming work — milestones, features, todos, and ideas. The orchestrator maintains this file. The user can request additions; the orchestrator chooses what to remove or reprioritise as work progresses.
Conventions
- One checkbox per entry.
- [ ]is open;- [~]is in progress (work has started — a plan exists, a branch is open, or commits are landing);- [x]is done. A finished entry may stay briefly for context, then is removed (with a one-line mirror indocs/journals/). - Each entry is tagged by kind and lives under a priority
bucket:
- [milestone] — big chunk that will get a
docs/specs/<milestone>.md. - [feature] — smaller addition inside a milestone, no full spec.
- [todo] — concrete task that can run without a brainstorm (cleanup, doc fix, mechanical refactor, test backfill).
- [idea] — not yet decision-ready, no commitment.
- [milestone] — big chunk that will get a
- Optional
depends on:line names another entry that has to land first. - Optional
context:line points to the journal entry (per-iter file underdocs/journals/or, for pre-2026-05-11 entries, the archiveddocs/journal-archive.md) where the rationale lives. The roadmap is intentionally terse; rationale stays in the journals. - Priority buckets:
- P0 — in flight. Spec or plan already exists.
- P1 — next up. Decision made; not yet started.
- P2 — medium-term. Decided in principle, scheduled later.
- P3 — ideas. No commitment; may be cut.
P0 — In flight
-
[milestone] Remove
mut/var/assign— CLOSED 2026-05-18. The local-mutable-state construct removed entirely and atomically (Term::Mut/Term::Assign/MutVar, the 3 Form-A keywords, the 4mutCheckErrorvariants,mut_scope_stack, every exhaustiveTermarm across 17 src files) in lockstep with DESIGN.md + fixtures + drift trio + carve-out + roadmap;loop/recur+let/ifare the surviving forms. Justified by 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; shared codegen alloca machinery kept (loop reuses it, renamedbinder_allocas) + theTerm::Lamescape-guard loop half byte-equivalent. spec/plan/ iter (d1ad50e/f355899/07f0802), milestone-closeauditclean (architect[high]form_a.md fixed in.tidy4837871; bench causally exonerated — HEAD vs pre-milestone bench binariescmp-byte-identical, no ratify),fieldtestclean (4 fresh programs, all worked first try without mutable locals — the removal thesis empirically confirmed). Decoupled from Stateful-islands. Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- context:
docs/specs/2026-05-18-remove-mut-var-assign.md;docs/specs/2026-05-18-fieldtest-remove-mut-var-assign.md;docs/journals/2026-05-18-iter-remove-mut-var-assign.1.md;docs/journals/2026-05-18-audit-remove-mut-var-assign.md
- context:
-
[milestone] Prose
loopbinders — projection redesign — CLOSED 2026-05-18. Form-B prose now renders loop binders as a parenthesised init-list on the keyword (loop(acc = 0, i = 1) { … }, positionally isomorphic torecur(...)) instead of barename = init;statements inside the body block (which misread as C/Rust re-init-every-iteration). Single-iteration, projection-only: oneailang-prosewrite_termTerm::Looparm + 2 committed byte-equality.prose.txtsnapshots/tests; loop/recur AST, Form A, JSON-AST, typecheck, codegen, and the Form-A↔JSON round-trip invariant all byte-unchanged. brainstorm→plan→implement (c657e74/6533134/c9355d7); milestone-closeauditclean (architect zero drift; bench carry-on — sole firing is the tracked P2*.bump_senvironmental staleness, latency-tail proven sampling noise by re-run); no fieldtest (projection-only, no authoring- surface change). Stays here briefly for context; remove once stale.- context:
docs/specs/2026-05-18-prose-loop-binders.md;docs/journals/2026-05-18-audit-prose-loop-binders.md; surfaced from the loop/recur prose review (2026-05-18 chat).
- context:
-
[milestone] Standalone
loop/recur— CLOSED 2026-05-18. Strictly-additive strict-iteration surface,recurtail-position-only, no totality claim. Shipped: iter 1a179ec3(additive AST nodes), iter 21566ce0(typecheck), iter 3edd2558(codegen + run-to-value E2E), tidy39380d3/2ee9794(lambda-captures-loop-binder rejected at check). Milestone-closeauditclean (architect drift resolved, bench pristine 25/0 carry-on);fieldtest2026-05-18 clean on all four milestone axes (0 bugs; diagnostics point-exact+self-fixing, recur-tail through match/let, loop-as-value-subexpr byte-stable, no-termination exact). Two orthogonal non-blocking findings routed to P2 todos (niladic(app f)— re-confirms mut-local F3; module(doc)diagnostic hint). Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- context:
docs/specs/2026-05-17-loop-recur.md;docs/specs/2026-05-18-fieldtest-loop-recur.md; principles entrydocs/specs/2026-05-17-llm-surface-discipline.md§6.2.
- context:
-
[milestone] DESIGN.md / docs honesty lint — CLOSED 2026-05-18.
docs/DESIGN.md+docs/PROSE_ROUNDTRIP.mdnow mirror ONLY the current state, present-tense: 14 DESIGN.md corrections (Wunschdenken stated-as-fact + non-citation post-mortem/doc- archaeology stripped) + the PROSE tool-use/MCP paragraph; genuine forward intent (LLM tool-use/MCP/LSP) relocated to P3. The two-pronged tense+modality discriminator is codified present-tense as a DESIGN.md### What this document is …meta-subsection (Approach A) the architect cites. Anti-regrowth two ways: a wrap-robust enumerated absent/present pincrates/ailang-core/tests/docs_honesty_pin.rs(anorm()whitespace-collapse helper structurally discharges the recurring grep/contains line-wrap failure family — strictly better than the effect-doc-honesty "keep-on-one-line" precedent) + wrap-robust advisory Sweep 5 inarchitect_sweeps.sh(contiguous-fragment regex) with full sweep-count lockstep + a newailang-architect.md"DESIGN.md honesty drift" bullet. Procedural enumeration vindicated: the Task-4 Step-14 catch-all caught a genuine soft-wrapped extra FIX (Form-B prose-projection bullet) a frozen list + the spec's illustrative regex would both have missed. Single iter (aff25cd/de66eb7/7580d43); milestone-closeauditCLEAN (architect clean, one[medium]advisory Sweep-5 self-match wart → P3 below; bench causally exonerated — HEAD vs5bb7211/de66eb7bench binariescmp-byte-identical, NO ratify); no fieldtest (zero authoring-surface change). Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- context:
docs/specs/2026-05-18-docs-honesty-lint.md(grounding-check PASS 10/10);docs/journals/2026-05-18-iter-docs-honesty-lint.1.md;docs/journals/2026-05-18-audit-docs-honesty-lint.md
- context:
P1 — Next
-
[milestone] Embedding ABI — M1: linkable artifact + scalar C entrypoint +
main-free lifecycle — CLOSED 2026-05-18. First of the five-milestone arc (M1–M5) making a compiled AILang kernel callable in-process from a concurrent Rust host. Shipped: additiveFnDef.export: Option<String>(hash-stable, ~85-site compile-driven thread); Form-A(export "<sym>")modifier (round-trip-gated); check-side scalar-only+effect-free export gate (export-non-scalar-signature/export-has-effects— the feature-acceptance clause-3 discriminator in code); codegenTarget::StaticLib(suppresses@main+MissingEntryMain, emits one external@<sym>forwarder per export, decoupled fromail_<module>_<fn>mangling per Decision 2); CLIail build --emit=staticlib(lib<entry>.a+ separatelibailang_rt.a). Coherent stop PROVEN: C host links both archives, calls the scalar kernel, typed return holds. spec51160e9(grounding-check PASS) → planb0bd7ef(Repaired) → iter818177d(partial 1–3 + Boss plan Repair: a module≠stem fixture defect, resolved Option 2)e406d07(DONE 4–7). Milestone-closeaudit425c4ebCLEAN (architect clean — Invariant 1 holds semantically, lockstep intact; sole[low]rustfmt-divergence evidence-adjudicated carry-on, 1137 pre-existing tree-wide divergences prove rustfmt is not a project convention; benchcheck.pyexit 1 decisively causally exonerated — 21/21 bench binariescmp-byte-identical vs pre-milestone, the two tracked-P2 noise families, NO ratify).fieldtest6a4e866substantiated the thesis (0 bugs; Int+Float positive E2E first-try clean = clause-1; both clause-3 rejections precise+self-correcting; 3 working) — 3 non-blocking findings routed to the two follow-up items directly below. Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).
- context:
docs/specs/2026-05-18-embedding-abi-m1.md;docs/specs/2026-05-18-fieldtest-embedding-abi-m1.md;docs/journals/2026-05-18-iter-embedding-abi-m1.1.md;docs/journals/2026-05-18-audit-embedding-abi-m1.md
-
[todo] form_a.md scalar-parameter mode carve-out — docs- honesty tidy (M1 fieldtest friction + spec_gap#1, shared root) — CLOSED 2026-05-18.
crates/ailang-core/specs/form_a.mdstated an unconditional "every(fn …)param MUST carry an(own/borrow)mode" rule in four places that contradicts shipped checker behaviour (scalars take and require bare(con Int); a mode on a scalar trips body-pointinguse-after-consume/consume-while-borrowed). All four sites rewritten symmetric to the pre-existing return-type carve-out; the already-correct few-shot annotation left verbatim by design; DESIGN.md §"Embedding ABI (M1)" gained the bare-scalar export-param rule + a corpus-groundedstepForm-A snippet; RED-first anti-regrowth pin viaailang_core::FORM_A_SPEC+norm()(4 ABSENT + 4 PRESENT form_a + 1 PRESENT DESIGN). Zero language/checker/codegen change; Boss-verified docs_honesty_pin 5/0, spec_drift 8/8 (not a lockstep partner), ailang-core 112/0, workspace 622→623 (+1 = the pin), zerocrates/**/src/**diff. Pure docs+pin tidy — no audit/fieldtest gate (the pin IS the regression coverage). plandocs/plans/form-a-scalar-param-mode-carveout.md(4c266a6) → iter7d7f04e. Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- context:
docs/specs/2026-05-18-fieldtest-embedding-abi-m1.mdfindings [friction] + [spec_gap]#1;docs/journals/2026-05-18-iter-form-a-scalar-param-mode-carveout.md.
- context:
-
[feature]
ail emit-ir --emit=staticlib— restore the Decision-5 IR-readability affordance for kernels (M1 fieldtest spec_gap#2) — CLOSED 2026-05-18.ail emit-irhad no--emit=staticlib(onlyail builddid) and on amain-free kernel hit the executable-pathMissingEntryMainrejection — an author could not read the generated@<sym>forwarder for an exported kernel. Resolution added (DESIGN.md widened, never narrowed): a one-line symmetric codegen conveniencelower_workspace_staticlib(ws)routing through the M1-audited unchangedTarget::StaticLibpath, anemitclap field onCmd::EmitIrsymmetric withCmd::Build's, a zero-export guard byte-identical tobuild_staticlib's; DESIGN.md §"Embedding ABI (M1)" affordance sentence + a CLI-synopsis correction also discharging a pre-existing M1ail build --emit=staticlibomission. No new doc pin (E2E pins behaviour; architect's milestone-close DESIGN.md read catches stale prose). Boss-verified: 3 new E2E 3/0 (incl. functional CLI spot-check —@backtest_stepexternal forwarder readable, no@main),embed_staticlib_cli2/0 (build-side untouched),docs_honesty_pin5/0,ail186/0, workspace 623→626 (+3), zero out-of-scope diff, no fixture minted. Scoped feature — no audit/fieldtest gate (E2E is the coverage; reuses the M1-audited codegen path, no invariant/surface change). plandocs/plans/emit-ir-staticlib.md(03493c9) → iterbcfe554. Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- context:
docs/specs/2026-05-18-fieldtest-embedding-abi-m1.mdfinding [spec_gap]#2;docs/journals/2026-05-18-iter-emit-ir-staticlib.md.
- context:
-
[milestone] Embedding ABI — M2: per-thread runtime context + concurrency safety — CLOSED 2026-05-18. A compiled scalar AILang kernel is now callable concurrently from a host thread swarm without an RC-runtime data race.
ailang_ctx_t*is a mandatory leading parameter of the (M3-frozen-shape) C@<sym>(ctx, scalars…)ABI; the M1 forwarder publishes it via a__threadslot around the byte-unchanged internal@ail_<mod>_<fn>call (internal convention +_adapter/_closuntouched — M1 decision held; TLS sound because the kernel call is synchronous, ctx never held across a suspension).runtime/rc.cde-globalised: the two RC-counter sites becameif (ctx) ctx->{alloc,free}_count++ else g_rc_*++, theg_rc_*statics +atexitretained verbatim as the null-ctx single-threaded executable fallback (executable-path leak readback byte-preserved). ctx near-empty by discipline ({alloc,free}_countonly — no arena/lock/atomic/IO; the build-ahead trap named out-of-scope). Staticlib is RC-only enforced (--emit=staticlibrejects--alloc=gc|bump; Boehm never linked into a swarm artefact; standing P2 Boehm-retirement untouched). No authoring-surface / schema /ailang-checkchange — the.ailis byte-identical to M1; the deliverable is a swarm-safe generated ABI + de-globalised runtime, sanitiser-verified (per-thread-ctx scalar swarm tsan-clean == oracle; direct rc-accounting per-ctx clean; shared-ctx negative control a genuineThreadSanitizerrace at the de-globalised counters, exit 66 — teeth non-vacuous). Process note: the first implement dispatch correctly BLOCKED on a genuine spec defect (a negative control on the non-allocating scalar swarm is structurally impossible — the spec's own honesty point); Boss adjudicated a spec-consistency repair (teeth relocated to the rc-accounting harness) rather than a brainstorm bounce. spec1c58055(grounding-check PASS 9/9) → planb3388c8(Boss-corrected) → iterc9a84b3(PARTIAL 4/9 + Boss repair) +fbeeade(DONE 5–9); milestone-closeauditad88dec(architect one[medium]+[low]doc-honesty drift; benchcheck.pyexit 1 decisively causally exonerated — bencher H0-refuted, all 3 firings the two tracked-P2 noise families, rc.c hunk branchless+free, NO ratify) → tidya80d495(the## Embedding ABIlockstep rename, drift resolved). No fieldtest (zero authoring-surface change). Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- context:
docs/specs/2026-05-18-embedding-abi-m2.md;docs/journals/2026-05-18-iter-embedding-abi-m2.1.md;docs/journals/2026-05-18-audit-embedding-abi-m2.md;docs/journals/2026-05-18-iter-embedding-abi-m2.tidy.md.
- context:
-
[milestone] Embedding ABI — M3: frozen value layout + single ADT/record crossing + RC ownership contract — CLOSED 2026-05-18. A single-constructor record of
Int/Floatfields now crosses the embedding C ABI in and out; ownership follows the declaredown/borrowmode (mechanically inherited — the M2 forwarder body is byte-unchanged, all mode-driven RC stays in the byte-unchanged internal@ail_<mod>_<fn>); the record memory layout (header@p-8 / i64 tag@0 / fields i64-strided@8+i·8 / size=8+n·8) is frozen as a one-way commitment — a new DESIGN.md §"Embedding ABI"### Frozen value layoutSSOT +// FROZEN ABIlockstep pointers at the three encoders + an enforceable@ailang_rc_allocheap-box byte-pin (RED-on-offset- perturbation proven); host construction viaailang_rc_alloc, host-free viaailang_rc_dec(leak-free because M3 fields are scalar — no boxed children; non-scalar recursive-free named M4- additive). No authoring-surface / schema / Form-A /CheckErrorchange (M2-style — the.ailis the minimal evolution of the M1/M2 scalar kernel into a recordState). The(State,Float)-> Statefold round-trip is proven globally leak-free for bothownandborrow. Process: spec1fbb9c4(grounding-check PASS 8/8) → plan15ee3c5→ iterd5c565d(PARTIAL 5/7 + a Boss spec-consistency repair: the orchestrator correctly BLOCKED on a genuine spec defect — the single-ctx-readback proof model is unsatisfiable forborrowby M2's TLS-ctx design; Boss M2.1-precedent adjudication → a stronger global-leak-freedom proof model) +4ea8bc5(DONE 6-7: the freeze). Milestone-closeauditb8a60b1(architect: Invariant 1 clean, M1/M2 byte-invariant held, frozen-SSOT consistent — DRIFT only[medium]+[low]doc-honesty → tidy; benchcheck.pyexit 1 decisively causally exonerated — byte-identical generated IR HEAD vs pre-M39a609aefor every firing bench, the two tracked-P2 noise families, NO ratify) → tidy63d7d60(pin-safe; drift resolved). No fieldtest (zero authoring-surface change). Stays here briefly for context; remove once stale (full record indocs/journals/INDEX.md).- depends on: Embedding ABI — M2.
- context:
docs/specs/2026-05-18-embedding-abi-m3.md;docs/journals/2026-05-18-iter-embedding-abi-m3.1.md;docs/journals/2026-05-18-audit-embedding-abi-m3.md;docs/journals/2026-05-18-iter-embedding-abi-m3.tidy.md.
-
[milestone] Embedding ABI — M4: sequence crossing via the existing
ListADT. Host builds aList Recordper chunk;(State, List Record) -> Statecallable end-to-end. Pure ABI/marshalling, no language change — applies M3's frozen layout repeatedly. Makes the real fold runnable over real chunks. The array-vs-cons-list performance question (1024 RC cons-cells per chunk on the hot path) is deliberately not in scope here — capability now, performance as a separate later non-ABI milestone (P2 below), keeping the user's "focus on the ABI, ignore the array gap" cut. Coherent stop:(State, List M1) -> Stateruns.- depends on: Embedding ABI — M3.
- context: 2026-05-18 chat.
-
[milestone] Embedding ABI — M5:
ail-embedadapter +data-serverwiring + thread-swarm backtest (fieldtest target). The host-side adapter crate (sole meeting point ofdata-serverand AILang, per Invariant 1) wiresdata-server'swhile let next_chunkloop to the AILang kernel via the ABI; an actual small backtest runs over a thread swarm. Naturalfieldtestmilestone: existence proof of the whole goal + friction harvest feeding the array-primitive decision. Coherent stop: the goal itself.- depends on: Embedding ABI — M4.
- context: 2026-05-18 chat.
-
[milestone] Heap-
StrABI — runtime infrastructure for malloc-backed, refcountedStrvalues alongside the existing static@.str_*globals. Today theStrpath is static-only (DESIGN.md §"Float semantics" notes this explicitly), so any primitive that needs to produce aStrat runtime —int_to_str,float_to_str(currently type-installed butCodegenError::Internalon call), eventualShow.show, future++on strings — cannot ship. Scope: pick the representation (likely a{rc_header, len, bytes…}slab consistent with the rest of the RC runtime), teach codegen to accept both static and heapStrat the same ABI slot, wire RCinc/drop/clone/compare/eqon the heap form, and shipint_to_str+float_to_stras the first two callers so the ABI gets exercised end-to-end. Unblocks Show + print rewire below.- context: DESIGN.md §"Float semantics" (
float_to_stris type- installed, codegen-deferred); spec 2026-05-11-23-eq-ord-prelude §"Show. Defers behind a heap-Str-ABI milestone"; spec 2026-05-10-fieldtest-floats §F4 ("dynamic Str allocation in the runtime"); spec 2026-05-09-22-typeclasses §22b.4b ("Show#Int needs anint_to_strprimitive returning heap-allocated Str").
- context: DESIGN.md §"Float semantics" (
-
[milestone] Post-22 Prelude — Show + print rewire — shipped 2026-05-13 as iters 24.1 (heap-Str runtime + codegen for
bool_to_strstr_clone,f38bad8), 24.2 (preludeclass Show+ four primitive instances Int/Bool/Str/Float + 22b TShow/tshow migration), and 24.3 (polymorphicfn print : forall a. Show a => (a borrow) -> () !IO- positive 4-prim E2E + user-ADT E2E + Show-aware NoInstance
diagnostic + DESIGN.md amendments to §"Prelude (built-in) classes"
and §"Float semantics"). The
MethodNameCollisionworkaround that blocked the original spec retired in mq.3 (2026-05-13); specdocs/specs/2026-05-13-24-show-print.mdre-derived 24.2 + 24.3 against the post-mq architecture.
- context: spec
docs/specs/2026-05-13-24-show-print.md; per-iter journals 2026-05-12-iter-24.1, 2026-05-13-iter-24.2, 2026-05-13-iter-24.3.
P2 — Medium-term
-
[milestone] DESIGN.md →
design/— role-split into a typed contract ledger + per-model whitepapers, decision-records rehomed todocs/journals/.docs/DESIGN.mdis one 2905-line file doing three different jobs for three different consumers with three different lifetimes; the line count is the symptom of role-conflation, not of mess. Replace it with adesign/directory split along the consumer/lifetime axis, with a typeddesign/INDEX.mdas the sole addressable spine and primary entry point.Motivation. The just-closed
docs-honesty-lintmilestone is the proof this is not a cleanup problem: it ran a full docs pass and DESIGN.md stayed 2905 lines, because honesty-lint operates within a job (tense / Wunschdenken / citation) and its own audit-trail invariant mandates retaining the bulky decision-record prose (DESIGN.md:242 "records the why … for the audit trail"; the architect Sweep-5 discriminator explicitly keeps "present-tense design rationale"). You cannot clean your way out of conflation — the conflation itself is the structural defect.The three conflated jobs and their distinct consumers:
- Contract layer — prescriptive, test-linked invariants
(e.g. Decision 6's seven hard constraints, the Roundtrip
Invariant, the borrow/own binding rules). Consumer:
architect(mandatory full read at every milestone close),grounding-check(every spec), the bench drift lints. Wants: structured, addressable, test-linked, small, hot. This is the only job that belongs on the per-milestone hot path. - Model exposition — whitepaper-shaped model narratives
(RC + Uniqueness, typeclasses, effects). Consumer: onboarding
(fresh-context LLM,
fieldtester). Irreducible — the code cannot speak the gestalt; one whitepaper per model. - Decision-record / relitigating-guard — why X was chosen,
why Y/Z were rejected (region inference, tracing GC, …).
Consumer: a future
brainstorm, so it does not re-propose a settled-and-rejected idea. This already has a home —docs/journals/— and sits in DESIGN.md only because the audit-trail invariant predates per-iter addressable journals.
Underlying principle: the code is authoritative for what it does — delete every description of behaviour, the code speaks; the spec's irreducible job is what is promised plus a pointer to the green test that ratifies it (code answers what; spec answers what is promised; test answers does the promise still hold).
Decided shape.
design/split on the consumer/lifetime axis — not by Decision-number (that is cosmetic; the architect would still read everything).design/contracts/(the hot, test-linked invariant set),design/models/(one whitepaper per model).design/INDEX.mdis the typed ledger spine: per entry a one-liner + metadata{kind, ratifying-test, consumer/lifetime}+ a content link whose target is polymorphic — adesign/contracts/…file, a single-owner//!source header (mangling, env, roundtrip, float, tail-calls, data-model), or adesign/models/…whitepaper. INDEX.md is the sole addressable entry point. Decision-records move out todocs/journals/; the honesty-lint audit-trail invariant is repointed there in the same milestone.Rejected — do not relitigate. Quarto /
.qmdwas evaluated and rejected: every distinctive Quarto feature (rendered HTML/site, figures, citations, cross-ref resolution, executable chunks) is render-time value for a human reader who does not exist here — thedesign/consumer is an LLM reading raw files. Executable chunks would reintroduce a second "is the invariant green?" truth that can diverge fromcargo test(the duplicate-source-of-truth failure mode); Quarto@refcross-refs degrade the raw-file reader (unresolved tokens vs. resolving relative-path links); plus a non-Rust toolchain dependency for zero in-loop value. Plain Markdown + a typed INDEX.md is strictly better for this consumer. A plain shard by Decision-number is likewise rejected (changes nothing for the architect hot path).Sequencing / blast radius. Deliberately scheduled after the in-flight Embedding ABI arc — a substantive sequencing reason, not effort.
DESIGN.mdis referenced by name by at leastbench/check.py(history-anchor /design_schema_drift),bench/architect_sweeps.sh(Sweep 5; exit 2 = "could not find DESIGN.md"), the reading lists ofailang-architect/ailang-grounding-check/ailang-fieldtester, the CLAUDE.md "Roles of docs/…" section, and the honesty-lint invariant's own scope — load-bearing invariants and agent contracts, not just paths. Every Embedding-ABI milestone close runsaudit(architect + bench) against DESIGN.md; restructuring it mid-arc would break the architect's reading list and the drift scripts under an in-flight milestone. Hence no overlap with active implementation that closes audits against the current DESIGN.md. Brainstorm hard-gate before any plan/code — it rewrites enforced invariants and agent contracts.- context: 2026-05-18 chat (DESIGN.md-management dialogue — six-turn convergence: role-conflation diagnosis, three-job split axis, "let the code speak" principle, qmd rejection, blast-radius sequencing). No journal entry yet; pre-brainstorm.
- Contract layer — prescriptive, test-linked invariants
(e.g. Decision 6's seven hard constraints, the Roundtrip
Invariant, the borrow/own binding rules). Consumer:
-
[milestone] Flat array/slice primitive — performance follow-up to the Embedding ABI arc, not a capability gap. AILang's only sequence is the recursive
ListADT (one RC cell per element); marshalling a 1024-record chunk across the embedding boundary builds a 1024-cell cons-chain per chunk on a multi-GB hot path (Embedding ABI M4 ships the capability this way). A contiguous array/slice primitive would remove that, but it is a language change (interacts with uniqueness inference, RC, and the structurally-decreasing-recursion totality story) and is explicitly out of the ABI arc's scope. Sequenced after M5 so the decision is driven by M5's fieldtest measurements, not speculation.- depends on: Embedding ABI — M5 (for the measured justification).
- context: 2026-05-18 chat (user deferred this explicitly to keep the ABI arc clean).
-
[milestone] Iteration-totality story — structural + Int-bounded total recursion with enforced non-negativity. AILang's iteration story stays as-is (structural / tail recursion;
tail-appintact). The genuine ambition — makef(n-1)-family recursion (incl. branching tree builders) total by construction with the non-negative-entry precondition enforced, not merely documented — is deferred here because doing it without a purity- pillar concession requires refinement/Nattype machinery the language has not built (Decision 4 keeps refinements opaque, no SMT). Not abandoned; correctly sequenced after the type machinery.- depends on: a future
Nat/refinement-types milestone (no spec yet). - context:
docs/specs/2026-05-16-iteration-discipline-revert.md(why the 2026-05 attempt was reverted) anddocs/journals/2026-05-15-iter-it.3.md(the branching-builder counter-example that surfaced the gap).
- depends on: a future
-
[milestone] Retire
io/print_int/io/print_bool/io/print_floateffect-ops + migrate example corpus toprint. Shipped 2026-05-14 as iter rpe.1.- context: per-iter journal
docs/journals/2026-05-14-iter-rpe.1.md.
- context: per-iter journal
-
[todo] Author
examples/prelude.ailalongsideexamples/prelude.ail.json. (Satisfied 2026-05-13 by iter form-a.0 —examples/prelude.ailrendered viaail render, 116 lines / 6386 bytes, round-trip-CI green.) -
[milestone] Form-A as the default authoring surface for examples and docs. (Closed 2026-05-13 by iter form-a.1.) Render every
examples/*.ail.jsonto its.ailsibling viaail render, delete the now-redundant.ail.json, and regenerate the JSON-AST perail parseat build / test time. Same for inline JSON-AST blocks indocs/markdown (~7 in DESIGN.md plus ~29 other md files) — convert to Form-A snippets where the snippet's purpose is to show "what the language looks like", not "what the schema is".After this milestone the working tree contains exactly one representation per program: the
.ailsource. The JSON-AST is a build artefact, not a checked-in twin. Tests and benches that currently glob*.ail.jsoneither parse-then-consume or are rewired to point at.aildirectly. The round-trip invariant flips role: today it gates that the two forms agree; afterwards it gates thatparseis deterministic.Carve-outs that MUST stay JSON-AST (no Form-A counterpart, and no
.ailsibling shall be created — these are the only seven files that remain.ail.json-only post-milestone):- Fixtures that test canonical-form rejection — Form A would
reject them at parse, defeating the test:
test_ct1_bare_xmod_rejected.ail.json,test_ct1_qualified_class_rejected.ail.json,test_ct1_bad_qualifier.ail.json,broken_unbound.ail.json,test_22b2_invalid_superclass_param.ail.json,test_22b2_kind_mismatch.ail.json,test_22b2_unbound_constraint_var.ail.json. - DESIGN.md schema documentation blocks where the JSON-AST shape is the point (Decision 11, ParamMode, canonical-form invariants).
- Any other case where the structured form is the artefact under discussion, not a vehicle for a program.
Touches CLAUDE.md ("source of truth is structured data") — the language doctrine doesn't change (JSON-AST is still the canonical hashable form), but the authoring doctrine does: authors write
.ail, the build derives JSON-AST. Sentence in CLAUDE.md needs rewording in the same milestone.Mechanical for the bulk; per-fixture judgement call only for the carve-out list. Run as one milestone so the corpus flip-over happens at a single, audit-gated point.
- context: post-Form-A-as-canonical-authoring corollary of the
examples/prelude.ailentry above. Generalises the same idea to the rest of the corpus and follows through on the cross- model authoring data (textual form cheaper, more first-try hits) by treating Form A as the privileged surface in the working tree, not just in flavour text.
- Fixtures that test canonical-form rejection — Form A would
reject them at parse, defeating the test:
-
[feature] Operator routing through
Eq/Ord—==,<etc. resolved via the typeclass instead of the built-in primitive comparators. No commitment; gated on bench re-baselining to make sure the indirection doesn't tank latency.- context: JOURNAL 2026-05-09
- depends on: Post-22 Prelude — Eq/Ord (shipped 23.5)
-
[todo]
types/ctor_indexoverlay shape question — decide whether the env's two parallel ctor maps should collapse into one overlay, or stay split. Surfaced during the env-construction unify audit.- context: JOURNAL 2026-05-10 ("Audit close: env-construction unify"); closed by iter ctt.1 — DESIGN.md §"Env construction" anchors the split decision.
-
[todo] CLI human-mode diagnostic surface for
WorkspaceLoadError. Shipped 2026-05-14 as iter cli-diag-human — a newload_workspace_humanhelper incrates/ail/src/main.rsroutes 9 non-JSONailang_surface::load_workspace(&path)?call sites throughworkspace_error_to_diagnostic, so the bracketed[code]prefix is preserved acrossail check,build,run,emit-ir,prose,describe,deps,diff,manifest.- context: per-iter journal
docs/journals/2026-05-14-iter-cli-diag-human.md.
- context: per-iter journal
-
[todo] Retire dead
KindMismatcharm —validate_classdefs'swalk_kind_mismatchpath is structurally unreachable through well-formed schema post-ct.1 (the canonical-form validator catches the malformedType::Con { name: param }shape earlier). The enum variant +walk_kind_mismatchhelper stay as dead-but-defensive code; a future tidy can delete both.- context: JOURNAL 2026-05-11 ("Iteration ct.1"); closed by iter ctt.3 — variant + helper + dispatch + Display arm all deleted; canonical-form-rejection test stays green asserting
BareCrossModuleTypeRef.
- context: JOURNAL 2026-05-11 ("Iteration ct.1"); closed by iter ctt.3 — variant + helper + dispatch + Display arm all deleted; canonical-form-rejection test stays green asserting
-
[todo] Re-key
Registry.type_def_moduleto handle bare-name-collision-across-modules —BTreeMap<String, String>keyed by bare type name silently overwrites when two modules each definetype Foo;normalize_type_for_registrywould then collapseM.FooandN.Footo whichever insert won. Acceptable for current corpus (distinct bare type names across modules), but the proper fix is to key by(owning_module, bare_name) → defining_module.- context: JOURNAL 2026-05-11 ("Iteration ct.1") — flagged by ct.1.5a quality reviewer.
-
[feature] 22c — typeclass corpus expansion. User-defined classes beyond the prelude four; multi-parameter classes; superclass chains; richer instance bodies. Deferred from milestone 22.
- context: JOURNAL 2026-05-09
-
[milestone] Module-qualified class names + type-driven method dispatch — retired the
MethodNameCollisionworkaround; shipped 2026-05-13 as iters mq.1 (canonical-form extension for class-ref fields + workspace-internal qualification), mq.2 (type- driven dispatch mechanism installed:method_to_candidate_classesinverse index, multi-candidateResidualConstraint,resolve_method_dispatch5-step rule,AmbiguousMethodResolution+UnknownClassdiagnostics), and mq.3 (retirement + multi-class E2Eclass-method-shadowed-by-fnwarning + DESIGN.md sync). Two libraries can now each declareclass Eqwith their owneq; cross-class method ambiguity is resolved at the call site via type-driven dispatch with<module>.<Class>.<method>as the disambiguation form.
- context:
docs/specs/2026-05-10-canonical-type-names.md"Out of scope: Class names" — the workaround was named there so it stayed visible until this milestone retired it.
-
[todo] Boehm full retirement — remove the transitional Boehm GC path now that RC + uniqueness is the canonical memory story.
- context: JOURNAL pre-22, "Boehm transitional"
-
[feature] Closure-pair slab / pool — codegen tweak to pool the env+code closure pairs instead of one-shot heap allocs. Bench-gated.
-
[todo]
FnDef::syntheticflag — formalise the monomorphiser-emitted FnDefs so downstream passes can tell user-authored from synthesised at a glance. Currently inferred from symbol naming. -
[todo] 21'h iteration — final 21' carry-over (latency methodology pass). Numbering kept for continuity with the 21' arc.
-
[todo] DESIGN.md effect-prose is fiction — standalone documentation-honesty tidy. Shipped 2026-05-16 as iter effect-doc-honesty (
a29700c): the three false effect-system claims (row-polymorphic![IO | r];IO+Divergeboth wired up;Term::Do"effect-handler table at link time") reconciled to the real flat-closed-set / IO-only /IndexMap+codegen-matchmechanism, satellite lockstep done, guarded by a 4-test doc-presence pin. No language/checker/codegen change.- context: per-iter journal
docs/journals/2026-05-16-iter-effect-doc-honesty.md.
- context: per-iter journal
-
[todo]
io/print_floatalways-emit-.0— surface printer always emits.ore/Eso re-lex routes to Float; the runtime printer (printf("%g\n", v)) doesn't, so2.0prints as2(Int-shaped). Asymmetric. Either switch the runtime path to a.0-fallback printer (matching surface) or document the%gcontract in DESIGN.md §"Float semantics" so the LLM-author knowsio/print_float's output is for-humans not round-trip.- context:
docs/specs/2026-05-10-fieldtest-floats.mdfinding F1.
- context:
-
[todo] Rustdoc warning sweep —
cargo doc --no-depsreports 16 pre-existing warnings (15 inailang-check, 1 inailang-core: private-item links from public doc, unresolved intra-crate links). All predate the design-md-consolidation milestone; treat as a one-off sweep.- context: JOURNAL 2026-05-10 ("Audit close: design-md-consolidation").
-
[todo]
ailang-plan-reconsite-undercount countermeasure (P2, escalated — now a structural recon-contract defect, no longer a single-milestone curiosity) — the recon agent hand-lists the change blast radius and has under-counted it four times across two milestones, through a different site type each time: loop-recur.1 walker arms, loop-recur.2 cross-modulesynthcallers, loop-recur.tidy implicit, and now remove-mut-var-assign.1 (in-sourcemod testsfns + a drift-pin fn + 5 orphaned.ail.jsoncarve-outs- a non-enumerated
codegen_import_map_fallback_pin.rsE0599) plus a spec-named doc the recon was told did not exist (crates/ailang-core/specs/form_a.md— the spec listed it for deletion; a Boss plan-time grep checked onlydocs/form_a.md, concluded "no such file", and propagated that into the recon brief; caught only at milestone-close audit). Two distinct gaps: (a) the compile-driven sweep catches exhaustive-match/caller misses but not non-compile-checked sites (docs, fixtures, drift pins) — those need a separate "every spec-named path is verified to exist and is handled" cross-check; (b) a recon brief must never inherit an unverified "X does not exist" — existence claims feeding a recon are themselves load-bearing and must be tree-wide, not dir-scoped. Tightenskills/planner/agents/ailang-plan-recon.md: for any signature-change / enum-variant / removal scope the recon REPORTS the compile-driven enumeration as the authoritative code-site set (hand-list advisory) AND emits a spec-named-path existence table (every path the spec names,ls-verified, with its handling task). No language change; an agent-definition discipline fix.
- context: loop/recur close audit (architect
[low], 2026-05-18) + remove-mut-var-assign close audit (architect[high]form_a.md +[medium]process-drift, 2026-05-18); pairs with planner Step-5 items 7+8 (those scrub the plan; this scrubs the recon and the recon brief).
- a non-enumerated
-
[todo]
design_schema_drift.rsfidelity widening — current test checks anchor presence anywhere in DESIGN.md; the audit found that[high]schema gaps in §"Data model" are invisible because anchors live in Decision 11 instead. Constrain the test to scan only §"Data model" + ParamMode block, or extract JSON-schema blocks into a machine-readable file the test consumes.- context: JOURNAL 2026-05-10 ("Audit close").
-
[todo] Split
BadCrossModuleTypeRefinto two diagnostics — the current single shape collapses unknown-owner and known-owner / unknown-type-in-owner into one message. The two cases suggest different fixes (add(import <owner>)vs. fix the type name). In the known-owner branch, list the owner's available type defs as candidates the waybare-cross-module-type-reflists candidates from imports.- context: fieldtest 2026-05-11 —
examples/ct_3*.ailexhibits both branches with identical-shape diagnostics.
- context: fieldtest 2026-05-11 —
-
[todo] Zero-arg
(app f)rejected at parse — the Form-A parser refuses an application with an empty argument list, so a nullary call has no surface form. Surfaced by the mut-local fieldtest (F3) AND independently re-confirmed by the loop/recur fieldtest (2026-05-18, finding spec_gap): the maximally-natural infinite-event-loop shape is a niladicrun_forever : fn() -> Intcalled(app run_forever), which dies at parse before reaching loop/recur semantics. Two independent fieldtests hitting the same gap raises the priority signal. Decide: accept(app f)as the nullary-call surface, or ratify in DESIGN.md that nullary functions are expressed differently (and say how). DESIGN.md'sTerm::Appargs:[Term...]states no minimum, so the surface "expected at least one argument" rule is unbacked by spec — a genuine design fork, deliberately NOT auto-ratified under autonomous orchestration. Not a blocker; no current corpus program needs it, but an LLM author reaches for it.- context:
docs/specs/2026-05-15-fieldtest-mut-local.mdfinding F3;docs/specs/2026-05-18-fieldtest-loop-recur.mdspec_gap.
- context:
-
[todo] Module-level
(doc …)diagnostic omits wheredocbelongs — a(module NAME (doc "…") (fn …))is correctly rejected (unknown def head \doc`) but the message lists valid def heads without saying doc strings attach *inside*fn/datadefs; an author can read it and conclude doc strings are unsupported. One-line tidy: append a hint like "(doc strings attach insidefn/data` defs, not at module level)". Low cost; verbose-diagnostic-philosophy gap, not a bug.- context:
docs/specs/2026-05-18-fieldtest-loop-recur.mdfriction.
- context:
-
[todo] Workspace search beyond entry-module's directory —
load_workspaceonly finds sibling.ail.jsonfiles in the same directory as the entry module, so any consumer of prelude/std in a subdirectory has no way to resolve cross-module imports. Add either a--workspace-rootflag onail check/ail build/ail run, or upward-search from the entry module's directory. Alternatively ratify the flat-workspace assumption in DESIGN.md if intentional.- context: fieldtest 2026-05-11 — fieldtest fixtures could not be
placed under
examples/fieldtest/because of this; predates the canonical-type-names milestone but surfaces every time.
- context: fieldtest 2026-05-11 — fieldtest fixtures could not be
placed under
-
[todo]
*.bump_sthroughput baseline is stale vs current hardware —bench/check.py'sthroughput.*.bump_sfamily (the fastest, most jitter-prone metrics) reads ~+5–13% overbench/baseline.jsonon the current machine. Localised at the iteration-discipline-revert audit (2026-05-16): an interleaved 3×60-run measurement ofbench_list_sumbump_s built from the byte-oracle commit1ff7e81shows the same ~+11% elevation as HEAD, and the two bump binaries arecmp-identical — so this is environmental drift relative to the 2026-05-09 baseline-capture machine state, not a codegen regression. Re-capture the full*.bump_sset on current hardware from a known-clean commit and recalibrate thebump_sbaseline+tolerance pair (or widen the tolerance) so the noise floor stops trippingcheck.pyexit 1. Pure bench-harness recalibration; no language change. -
[todo]
check.pyRC-latency*.max_usis a structural false-positive at-n 5— distinct from the*.bump_sstaleness above (different metric family, different root cause).latency.{explicit,implicit}_at_rc.max_usis the single worst of ~5000 samples over only 5 runs, dominated by OS scheduling / THP / IRQ jitter on a shared host, not allocator behaviour. It has fired a falseREGRESSIONon three consecutive no-runtime-change milestones (iteration-discipline-revert, prose-loop-binders, remove-mut-var-assign) and vanished on identical-code re-run every time (remove-mut-var-assign close: HEAD vs48e7774bench binariescmp-byte-identical,explicit_at_rc.max_uscollapsed +108%→-2.30% ok by rerun3) — a ~3-for-3 false-positive rate on null changes, while the median/p99/p99.9 of the same benchmarks held across all re-runs. Pick one mitigation: drop*.max_usfrom the gating set (keep median/p99/p99.9, which are the trustworthy signal), or raise-nsubstantially for the tail metrics, or pin the latency arm to an isolated cpuset. Pure bench-harness change; no language change.- context: remove-mut-var-assign close audit, bencher localisation (2026-05-18) — byte-identical-binary causal exoneration + the 3-milestone false-positive history.
- context:
docs/journals/2026-05-16-audit-iteration-discipline-revert.md(the bencher localisation evidence).
-
[todo]
check_in_workspaceper-module overlay narrowing —crates/ailang-check/src/lib.rs:1234still clears+rebuildsenv.ctor_indexper-module; ct.3.2 narrowed the analogous mono overlay to types-only. The typecheck-side overlay'senv.ctor_indexhalf serves the duplicate-detection diagnostic at workspace-build time, not the runtime ctor lookup (which is type-driven post-ct.2.2). Narrowing is mechanical but needs a careful read to confirm no other consumer survives.- context: JOURNAL 2026-05-11 ("Iteration ct.4") — milestone close
follow-up; closed by iter ctt.1 — recon confirmed the rebuild is the load-bearing consumer of in-band DuplicateCtor (pinned by
crates/ailang-check/tests/duplicate_ctor_pin.rs); the asymmetry with the mono side is intentional.
- context: JOURNAL 2026-05-11 ("Iteration ct.4") — milestone close
follow-up; closed by iter ctt.1 — recon confirmed the rebuild is the load-bearing consumer of in-band DuplicateCtor (pinned by
-
[feature]
str_concat : (borrow Str, borrow Str) -> Str— heap-Str concatenation primitive. Shipped 2026-05-13 as iter str-concat (closes fieldtest-form-a friction #4). Symmetric to the iter 24.1str_clone/int_to_str/bool_to_strplumbing: runtime C helper (ailang_str_concat),ailang-checkbuiltin registration,ailang-codegenextern +lower_apparm, plus a freshexamples/show_user_adt_with_label.ailcorpus fixture exercising the LLM-natural Show-body shape.- context: per-iter journal 2026-05-13-iter-str-concat.md.
-
[~] [milestone] Stateful islands — bounded mutation for streaming workloads (
Stateful a b+!Muteffect +mutsyntactic block). Adds a sealed mutable-state layer on top of the pure core: aStateful a bfirst-class type whose interior is mutable, whose exterior is a typed callable with!Mutin its effect set, and whose state non-aliasing is enforced by uniqueness inference at the block boundary. Targets the online / streaming workload class — rolling indicators, IIR filters, online aggregates, sensor fusion, online learning — whose mathematics is "new sample + old state → new state + output" per step, and which today's pure-functional state- threading makes ergonomically expensive at scale (multi-record explicit threading for the canonical sliding-window SMA, no zero-allocation pipe combinator, growing tuple-state types as pipelines lengthen).Sub-milestone sequencing is UNDER RE-THINK with the user (2026-05-16) — no further sub-milestone is planned or brainstormed until that conversation happens. Why: the 2026-05-15 decomposition named "(2) effect-handler infrastructure as a prerequisite for any non-IO/non-Diverge effect" as the next step. A read-only recon of the live effect subsystem (2026-05-16) showed that premise is false: the effect raise / declared-set /
UndeclaredEffect-subset / call- propagation machinery is already fully generic over an arbitrary effect string;!Mutneeds no effect-handler machinery. The only real code prerequisite the recon found is one hard-coded assumption (linearity.rswalks everyTerm::Doarg asBorrow;EffectOpSighas no per-arg mode field) — a single struct field, not a milestone. A brainstorm spec that tried to make sub-ms-2 a standalone deliverable bundled that speculative one-field capability with an unrelated DESIGN.md honesty fix; the user correctly rejected the bundle as incoherent and the build-ahead-of-consumer half as the iteration-discipline trap repeated. Resolution: (a) the DESIGN.md effect-honesty correction is split out and runs now as a standalone documentation tidy (see the P2[todo]"DESIGN.md effect-prose is fiction" below); (b) thearg_modesfinding is recorded as recon context for the future!Mutdesign, NOT built ahead — it is first-iteration material of whatever the!Mutmilestone turns out to be, validated there against a real consuming op, never a synthetic test op; (c) the old "(2)…(5)" sequence (effect-handler infra →!Mut+ref a→MutArray a→Stateful a b+pipe) is no longer treated as settled — the whole ordering and granularity is what the pending user conversation re-decides.Motivation. AILang's signature-as-contract thesis is better served by an explicit
Stateful a b+!Mutannotation than by the implicit-closure-mutation idiom of myc / Lua / JS factory patterns: the signature tells the truth about time-identity without the body needing to be read — exactly the LLM-author correctness affordance AILang exists to deliver, extended to a workload class it does not yet serve. Decision 10's constraint #3 forbids shared mutable refs (DESIGN.md:1082); it does not forbid uniqueness-bounded mutation. Lean 4 (ST), Roc (Task), Haskell (ST/IO), and Koka (effects) all use a layered design of this shape to host exactly this workload. AILang's existingown/borrowmode machinery plus its effect-slot architecture are the foundation; this milestone supplies the layer that sits on top.Scope (subject to brainstorm refinement).
Stateful a bas a first-class type — a sealed callable with a hidden mutable env, externally a typed callable whose effect set includes!Mut.!Muteffect, the first non-IO / non-Diverge effect; forces the effect-handler infrastructure forward.mutblock as the syntactic boundary in Form A — outside, AILang's pure self; inside,var/assign/ mutable arrays legal. (Iteration is not part of this boundary: AILang has nowhile/forand this milestone does not introduce one — repetition stays recursion, exactly as the language has it today (structural / tail recursion); amutblock is a sealed expression, never a loop over mutable state.)var x = expr+assign x exprAST nodes, legal only insidemut.- Mutable array primitive (
MutArray a, O(1) index/update under uniqueness) — co-developed because the ring-buffer use case that motivates the whole effort has no carrier today. pipe : Stateful a b → Stateful b c → Stateful a cas a built-in combinator with zero-allocation lowering — composition is fusion at codegen, not closure-pair layering at runtime.- Decision 12 (or amendment to Decision 10) that names uniqueness-bounded mutation as the legitimate exception to "no shared mutable refs", and the pure / mutable-island layering as the architectural shape.
Blockers (hard prerequisites + open design questions).
-
Effect handlers absent. DESIGN.md:2663 — "No effect handlers — only the built-in IO and Diverge ops."
!Mutis the first non-trivial effect and forces handler infrastructure to ship. May warrant lifting out as its own prerequisite milestone; brainstorm decides. -
Uniqueness inference through
varcaptures. Current inference operates over the immutable RC graph; mutable bindings captured by closures need a more powerful pass. Lean 4 has a known algorithm; AILang does not implement it. -
No mutable-array primitive. No
Array a, no slab container of any kind in the language today. Separate spec needed inside this milestone (representation,own-only orborrow-able, bounds-checking discipline). -
runST-equivalent escape discharge. Producing aStatefulthat legitimately escapes itsmutblock while proving the inner state doesn't leak. Haskell's rank-2 trick (runST :: (forall s. ST s a) -> a) is unavailable — DESIGN.md:1930 confirms higher-rank polymorphism is not supported. Need an alternative — likely sealed-by-construction at the factory boundary, or an effect-mode tag that gates escape. -
Form A surface design. Decision 1 forbids macros (source = data, not text), so
mut/var/assignare genuine AST nodes with round-trip-invariant coverage. Surface needs LLM- utility validation (does the author reach forvar/mutunprompted?) before implementation. -
Codegen for in-place struct-field writes.
Term::ReuseAstoday lowers ADT in-place rewrite; no direct mutable struct- field-write path exists.crates/ailang-codegen/src/escape.rsplus the lowering passes need extension. -
Boundary escape analysis. "Interior state doesn't leak" is an escape analysis specifically over
var/refvalues; the existing pass covers allocations, not mutable cells. -
Decision-10 status. Whether to amend Decision 10 inline or add a Decision 12 that names the mutable-island layer alongside the pure layer. The latter is probably cleaner — Decision 10 stays load-bearing for the pure layer, Decision 12 names the extension and its discipline.
-
Streaming bench corpus. Current corpus (list_sum, tree_walk, closure_chain, hof_pipeline) is all pure. Streaming-specific benches (SMA pipeline, IIR filter, online stats) plus an external baseline (myc, hand-C, Python/NumPy) need to exist to validate that the layered design hits the zero-alloc performance target that myc demonstrates.
-
LLM-utility test. DESIGN.md §"Feature-acceptance criterion" is the gate: the surface must produce code an LLM author naturally writes. Fieldtest after spec, before any code commits.
-
context: 2026-05-15 chat on the
~/sma_factory.mycanalysis — myc's stateful-closure-plus-pipe idiom delivers a streaming workload pattern (3-line SMA factory, 2-line pipeline, zero runtime allocation per tick) that AILang's pure-only model cannot match without this layered extension. Pending brainstorm will producedocs/specs/<date>-stateful-islands.mdand decide the effect-handler-prerequisite question.
P3 — Ideas
-
[todo]
compare_primitives_smoke.ailcounterpart. Satisfied 2026-05-13 by milestone form-a-default-authoring —examples/compare_primitives_smoke.ailis the canonical authoring form for that fixture. Form A is now the default authoring surface across the entire corpus.- context: closed incidentally by form-a iter form-a.1.
-
[todo] Codegen
lookup_ctor_in_patterntype-anchoring —crates/ailang-codegen/src/lib.rs:1790still walks every module's ctor_index by bare ctor name. Plumbing the scrutinee's qualifiedType::Conthrough pattern lowering would type-anchor it symmetric to the ct.2.2 typecheck-side fix. Not load-bearing (uniqueness is enforced at typecheck), but cleaner.- context: JOURNAL 2026-05-11 ("Iteration ct.3" + ct.4 close).
-
[todo]
compare_primitives_smokeIR-shape assertion — observecompare__Int/compare__Bool/compare__Strsymbols in the emitted IR. Blocked onemit-irCLI not running mono; resolution paths include extending the CLI to run mono, using library APIs directly in e2e.rs, or adding--dump-irtoail build. The E2E stdout assertion already covers correctness; the IR-shape test would catch refactor regressions that rename mono symbols.- context: JOURNAL 2026-05-11 ("Iteration ct.4") — dropped from ct.4.4 when the BLOCKED condition surfaced.
-
[idea] Latency methodology rework — switch from per-run timing to a histogram-based approach so tail-latency regressions are visible without re-running. Queued from 21'g.
-
[idea] Parser-test backfill for 22b.4a-era duplicate-clause sites (class × 3, class method × 2, instance × 3, instance method × 1). No regression pin today; only worth it if a 22b.4a-era diagnostic needs to change.
- context: JOURNAL 2026-05-10 ("Iteration 22-tidy.7")
-
[idea]
write_typeType::Forallarm incrates/ailang-prose/src/lib.rssilently drops constraints in inline-type rendering. Dormant — surface forms today only carry forall at fn-signature top level. Fix only if a future feature carries forall + constraints inline.- context: JOURNAL 2026-05-10 ("Iteration 22-tidy.6")
-
[idea] Richer integration paths between RC and uniqueness — deferred from the 21' arc; revisit once the uniqueness inference covers more program shapes.
-
[idea] LLM tool-use schema / MCP server / LSP front-end over the prose-roundtrip cycle — additive layers on top of the static-prompt
ail merge-prose | client | ail parse | ail checkpath (LLM calls back intoail parse/ail checkmid-turn; an MCP-compatible client discovers AILang's resources/tools/prompts). Relocated here from DESIGN.md §"prose roundtrip" + PROSE_ROUNDTRIP.md by the docs-honesty-lint milestone (forward intent does not live in the canonical docs).- context:
docs/specs/2026-05-18-docs-honesty-lint.md
- context:
-
[todo] Sweep 5 self-match anchor-exclusion —
bench/architect_sweeps.shSweep 5's regex matches the DESIGN.md discriminator subsection's own forbidden-phrasing catalogue (L62"planned / will back / on the path to / if-when X arrives") forever, so the script inherits a guaranteed self-referential EXIT 1 the architect must re-adjudicate by hand each run. Not a new failure mode (Sweeps 1-4 already retain legitimate date-anchors; non-zero is advisory-by-design per the script header) — minor signal-erosion only. Optional fix: a negative-lookbehind / line-range exclusion so the rule's own example list is not a hit. P3 — may be cut; the architect adjudicates the single known self-match trivially today.- context:
docs/journals/2026-05-18-audit-docs-honesty-lint.md(architect[medium]advisory wart, carry-on)
- context: