From 93887aa03bdeee2bd26e6507da3c103a019ef795 Mon Sep 17 00:00:00 2001 From: Brummel Date: Wed, 20 May 2026 14:48:27 +0200 Subject: [PATCH] workflow: replace docs/roadmap.md with Gitea issue backlog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The forward queue moves out of the in-tree markdown file and into Gitea issues at http://192.168.178.103:3000/Brummel/AILang/issues. Labels: kind:{milestone,feature,todo,idea} + prio:{p1,p2,p3} + state:in-progress. Big chunks live as Gitea milestones (containers) with full prose in the description; smaller items are standalone issues. Browse-and-filter scales constant against growing item count; the previous markdown file was 1059 lines, of which ~850 were already-closed-entry verlauf (the same failure class the JOURNAL cut removed). Sync-drift Code<>Tracker mitigation: Soft-convention `closes #N` / `refs #N` in commit bodies — Gitea auto-closes the issue on push. Captured in user-level CLAUDE.md (~/.claude/CLAUDE.md, not in this commit) as the durable rule; no hook enforcement. In-repo changes: - docs/roadmap.md deleted. - CLAUDE.md (project): Code-layout drops roadmap; /boss gating retargeted; Roles section rewritten with a new "Gitea issues" bullet (URL + tea-CLI snippet) and the closes-#N trailer note. - skills/boss/SKILL.md: 10 sites retargeted, plus Step 1 now prescribes `tea issues ls --labels prio:p1` as the queue read. - skills/brainstorm/SKILL.md: Step 7.5 no-override BLOCK now files a Gitea issue via `tea issues create` instead of appending a roadmap entry; spec deletion stays. - skills/audit/SKILL.md + ailang-architect.md: deferral requirement and debt-heuristic retargeted; forward-intent belongs in the Gitea backlog. - skills/fieldtest/SKILL.md, skills/docwriter/SKILL.md + ailang-docwriter.md: roadmap → backlog. - design/contracts/honesty-rule.md: forward intent lives in the Gitea backlog (pinned phrases unchanged). - design/INDEX.md: Docs bullet drops roadmap, adds the backlog URL. - crates/ailang-core/tests/docs_honesty_pin.rs: two assert messages retargeted (assertion bodies unchanged). - bench/architect_sweeps.sh: Sweep-4 TABU extended with `docs/roadmap\.md` so the deleted path cannot quietly regrow as a cross-reference in design/contracts/. Verification: - cargo build --workspace clean. - cargo test --workspace: 647 passed, 0 failed, 2 ignored. - bench/architect_sweeps.sh exit 0 (all five sweeps clean, incl. new TABU). - grep over the live tree (excluding docs/specs/, docs/plans/) shows zero residual docs/roadmap.md refs. Not touched: ~55 historical files under docs/specs/ and docs/plans/ that mention docs/roadmap.md. Snapshot-character, analogous to the JOURNAL-cut precedent — historical specs are not mass-edited just because a live file was retired; their mentions were correct at write time. --- CLAUDE.md | 34 +- bench/architect_sweeps.sh | 2 +- crates/ailang-core/tests/docs_honesty_pin.rs | 4 +- design/INDEX.md | 7 +- design/contracts/honesty-rule.md | 2 +- docs/roadmap.md | 1058 ------------------ skills/audit/SKILL.md | 6 +- skills/audit/agents/ailang-architect.md | 7 +- skills/boss/SKILL.md | 51 +- skills/brainstorm/SKILL.md | 25 +- skills/docwriter/SKILL.md | 4 +- skills/docwriter/agents/ailang-docwriter.md | 2 +- skills/fieldtest/SKILL.md | 2 +- 13 files changed, 82 insertions(+), 1122 deletions(-) delete mode 100644 docs/roadmap.md diff --git a/CLAUDE.md b/CLAUDE.md index aad3181..fdac436 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,7 +43,7 @@ it measurably improves correctness or removes redundancy. | `bench/` | Regression harnesses (`check.py`, `compile_check.py`, `cross_lang.py`) and the throughput-and-latency runner (`run.sh`); `bench/reference/` holds the hand-C corpus for cross-language ratios | | `examples/` | AILang fixtures used by tests and benches | | `design/` | The canonical contract ledger — `design/INDEX.md` (sole addressable spine: a typed Contracts + Models table), `design/contracts/` (prose-authoritative test-linked invariants), `design/models/` (onboarding whitepapers) | -| `docs/` | Specs and roadmap — `docs/specs/` (per-milestone design specs), `docs/plans/` (per-iteration plans), `docs/roadmap.md` (forward queue), `PROSE_ROUNDTRIP.md`. Project history lives in `git log`. | +| `docs/` | Specs and plans — `docs/specs/` (per-milestone design specs), `docs/plans/` (per-iteration plans), `PROSE_ROUNDTRIP.md`. Project history lives in `git log`; the forward queue lives in Gitea issues (see "Roles" section below). | | `skills/` | Project-local skill definitions and their agents. See `skills/README.md` for the skill table, agent roster, and discovery layout. | ## Skill system @@ -54,8 +54,8 @@ are sharper tools, not a replacement for orchestrator judgement. Specs go to `docs/specs/.md`, plans to `docs/plans/.md`. -Autonomous orchestrator mode — picking the next iter from -`docs/roadmap.md` and looping until done-state — is gated to the +Autonomous orchestrator mode — picking the next iter from the +Gitea issue backlog and looping until done-state — is gated to the user-invoked `/boss` skill (`skills/boss/SKILL.md`). Outside `/boss`, the default is interactive collaboration: the user asks, Claude responds, Claude stops. @@ -197,7 +197,7 @@ Vocabulary note: pre-2026-05-09 git history uses "iter" / "family"; current vocabulary is "iteration" / "milestone". Old commits are not retroactively renamed. -## Roles of the `design/` ledger, `git log`, `docs/roadmap.md`, `docs/specs/`, `docs/plans/` +## Roles of the `design/` ledger, `git log`, Gitea issues, `docs/specs/`, `docs/plans/` - **The `design/` ledger** is the canonical specification. It describes what AILang *is*: schema, semantics, invariants, runtime @@ -210,7 +210,7 @@ not retroactively renamed. the same iteration. The `design/` ledger is also the artefact `ailang-architect` checks the code against during drift review. A contract describes only the actual present state; forward intent - goes to `docs/roadmap.md`, history and rationale to `git log` + goes to the Gitea backlog, history and rationale to `git log` (see `design/contracts/honesty-rule.md`). - **`git log`** is the project history. Iter and audit commit @@ -219,15 +219,21 @@ not retroactively renamed. these bodies at commit time; they are the durable record. Read recent state with `git log -5 --format=full`; chronological scan with `git log --oneline -30`; per-milestone scope with - `git log ..HEAD --format=full`. + `git log ..HEAD --format=full`. Commits + that close a backlog issue reference it via `closes #N` in the + body; Gitea auto-closes the issue on push. -- **`docs/roadmap.md`** (since 2026-05-10): the priority-ordered - forward queue — milestones, features, todos, and ideas. The - orchestrator owns this file and is responsible for keeping it - current: adding new entries, reprioritising, removing items - that are done or dropped. Entries are checkbox lines; finished - items get checked off, then removed once they stop being - interesting context. +- **Gitea issues** (since 2026-05-20) are the priority-ordered + forward queue — milestones, features, todos, and ideas. Browse: + http://192.168.178.103:3000/Brummel/AILang/issues. CLI: `tea + issues ls --labels prio:p1` etc. Labels: `kind:{milestone, + feature,todo,idea}` and `prio:{p1,p2,p3}`. Big chunks that get + their own `docs/specs/` entry live as Gitea **milestones** + (containers) plus a `kind:milestone` issue; smaller items are + standalone issues. The orchestrator owns the backlog and is + responsible for keeping it current: opening new issues, + re-labelling for priority, closing on completion (typically via + the `closes #N` commit-body trailer). - **`docs/specs/.md`** (since 2026-05-09): per-milestone design spec produced by `skills/brainstorm`. Hard-gate before any @@ -239,4 +245,4 @@ not retroactively renamed. Together these answer three questions: "what is the language right now?" (the `design/` ledger), "how did we get here?" (`git log`), -and "what's next?" (roadmap). +and "what's next?" (Gitea backlog). diff --git a/bench/architect_sweeps.sh b/bench/architect_sweeps.sh index 62aa3fb..83c897d 100755 --- a/bench/architect_sweeps.sh +++ b/bench/architect_sweeps.sh @@ -52,7 +52,7 @@ run_sweep "3 (schema SoT)" \ '^\s*(struct |enum |pub (struct|enum|fn))|whenever the two disagree|ast\.rs is the source of truth' run_sweep "4 (workflow + stale cross-references)" \ - 'agents/README\.md|ailang-docwriter|Recently lifted|see the JOURNAL queue|later the same day|Sharpened later|closure conversion in JOURNAL|see the per-iter journal|in a per-iter journal' + 'agents/README\.md|ailang-docwriter|Recently lifted|see the JOURNAL queue|later the same day|Sharpened later|closure conversion in JOURNAL|see the per-iter journal|in a per-iter journal|docs/roadmap\.md' run_sweep "5 (honesty: wunschdenken + non-citation post-mortem)" \ 'on the path to|may land in a future|ships in a future iter|[Ww]ill back `Show|[Ww]ill eventually (be|support|back)|[Ii]f/?when [a-z]+ (arrives|lands)|[Aa]n earlier draft of this|previously all diagnostics were|[Ww]hat did change in 20|were retired 20[0-9]{2}-|retired in iter [a-z]|originally listed|\bwas deferred\b|foundation for [a-z]' diff --git a/crates/ailang-core/tests/docs_honesty_pin.rs b/crates/ailang-core/tests/docs_honesty_pin.rs index c0e6e2e..9f2db0c 100644 --- a/crates/ailang-core/tests/docs_honesty_pin.rs +++ b/crates/ailang-core/tests/docs_honesty_pin.rs @@ -55,7 +55,7 @@ fn design_corpus() -> String { fn design_md_has_no_wunschdenken() { let d = norm(&design_corpus()); assert!(!d.contains("is on the path to retirement"), - "design/: Boehm retirement is forward intent — it lives in docs/roadmap.md, not the ledger"); + "design/: Boehm retirement is forward intent — it lives in the Gitea backlog, not the ledger"); assert!(!d.contains("Will back `Show Float`"), "design/: 'Will back Show Float' asserts a future capability as fact"); assert!(!d.contains("codegen ships in a future iter"), @@ -125,7 +125,7 @@ fn design_md_present_tense_anchors_present() { fn prose_roundtrip_md_has_no_wunschdenken() { let p = norm(&read("docs/PROSE_ROUNDTRIP.md")); assert!(!p.contains("A future iter may layer a tool-use schema"), - "PROSE_ROUNDTRIP.md: tool-use/MCP forward intent lives in docs/roadmap.md"); + "PROSE_ROUNDTRIP.md: tool-use/MCP forward intent lives in the Gitea backlog"); assert!(p.contains("the lowest-common-denominator cycle and always works with any client"), "PROSE_ROUNDTRIP.md must close present-tense on the static-prompt path"); } diff --git a/design/INDEX.md b/design/INDEX.md index b4dca43..3d15186 100644 --- a/design/INDEX.md +++ b/design/INDEX.md @@ -56,9 +56,10 @@ evolving in lockstep with the language: sole addressable spine for canonical state), `design/contracts/` (test-linked invariants), `design/models/` (onboarding whitepapers). -- **Docs** (`docs/`): `roadmap.md` (forward queue), `specs/` - (per-milestone design specs), `plans/` (per-iteration - implementation plans). Project history lives in `git log`. +- **Docs** (`docs/`): `specs/` (per-milestone design specs), + `plans/` (per-iteration implementation plans). Project history + lives in `git log`; the forward queue lives in the Gitea issue + backlog (http://192.168.178.103:3000/Brummel/AILang/issues). - **Tests**: unit tests per crate plus E2E in `crates/ail/tests/e2e.rs`. Every new compiler path needs a test, otherwise the feature does not count as done. diff --git a/design/contracts/honesty-rule.md b/design/contracts/honesty-rule.md index ffb7797..98e8d11 100644 --- a/design/contracts/honesty-rule.md +++ b/design/contracts/honesty-rule.md @@ -6,7 +6,7 @@ Two things never belong in a contract or model file: - **Forward intent** (anything stated as planned, intended, or expected of a future iteration rather than true today) — that - lives in `docs/roadmap.md`. + lives in the Gitea issue backlog. - **History and rationale** (how a prior draft read, what changed since, why one option was chosen, why another was rejected, what was dropped in some iteration) — that lives in `git log` (iter diff --git a/docs/roadmap.md b/docs/roadmap.md deleted file mode 100644 index f7948a6..0000000 --- a/docs/roadmap.md +++ /dev/null @@ -1,1058 +0,0 @@ -# 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 or commits are landing); `- [x]` - is done. A finished entry may stay briefly for context, then is - removed; the durable record stays in `git log`. -- Each entry is tagged by **kind** and lives under a **priority** - bucket: - - **\[milestone\]** — big chunk that will get a `docs/specs/.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. -- Optional `depends on:` line names another entry that has to land - first. -- Optional `context:` line points to the rationale: a spec file - under `docs/specs/`, a commit hash (`git show `), or a - `git log --grep=""` pointer for older entries. The - roadmap is intentionally terse; rationale stays in those sources. -- 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 - -- [x] **\[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 4 `mut` `CheckError` variants, `mut_scope_stack`, - every exhaustive `Term` arm across 17 src files) in lockstep with - DESIGN.md + fixtures + drift trio + carve-out + roadmap; `loop`/ - `recur` + `let`/`if` are 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, renamed `binder_allocas`) + the - `Term::Lam` escape-guard loop half byte-equivalent. spec/plan/ - iter (`d1ad50e`/`f355899`/`07f0802`), milestone-close `audit` - clean (architect `[high]` form_a.md fixed in `.tidy` `4837871`; - bench causally exonerated — HEAD vs pre-milestone bench binaries - `cmp`-byte-identical, no ratify), `fieldtest` clean (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 in `git log`). - - context: `docs/specs/2026-05-18-remove-mut-var-assign.md`; - `docs/specs/2026-05-18-fieldtest-remove-mut-var-assign.md` - -- [x] **\[milestone\]** Prose `loop` binders — 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 to `recur(...)`) instead of bare - `name = init;` statements inside the body block (which misread as - C/Rust re-init-every-iteration). Single-iteration, projection-only: - one `ailang-prose` `write_term` `Term::Loop` arm + 2 committed - byte-equality `.prose.txt` snapshots/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-close `audit` clean - (architect zero drift; bench carry-on — sole firing is the tracked - P2 `*.bump_s` environmental 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`; surfaced - from the loop/recur prose review (2026-05-18 chat). - -- [x] **\[milestone\]** Standalone `loop` / `recur` — CLOSED 2026-05-18. - Strictly-additive strict-iteration surface, `recur` tail-position-only, - no totality claim. Shipped: iter 1 `a179ec3` (additive AST nodes), - iter 2 `1566ce0` (typecheck), iter 3 `edd2558` (codegen + run-to-value - E2E), tidy `39380d3`/`2ee9794` (lambda-captures-loop-binder rejected - at check). Milestone-close `audit` clean (architect drift resolved, - bench pristine 25/0 carry-on); `fieldtest` 2026-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 in `git log`). - - context: `docs/specs/2026-05-17-loop-recur.md`; - `docs/specs/2026-05-18-fieldtest-loop-recur.md`; principles entry - `docs/specs/2026-05-17-llm-surface-discipline.md` §6.2. - -- [x] **\[milestone\]** DESIGN.md / docs honesty lint — CLOSED - 2026-05-18. `docs/DESIGN.md` + `docs/PROSE_ROUNDTRIP.md` now 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 pin - `crates/ailang-core/tests/docs_honesty_pin.rs` (a `norm()` - 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 in `architect_sweeps.sh` (contiguous-fragment - regex) with full sweep-count lockstep + a new `ailang-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-close `audit` CLEAN - (architect clean, one `[medium]` advisory Sweep-5 self-match wart → - P3 below; bench causally exonerated — HEAD vs `5bb7211`/`de66eb7` - bench binaries `cmp`-byte-identical, NO ratify); no fieldtest (zero - authoring-surface change). Stays here briefly for context; remove - once stale (full record in `git log`). - - context: `docs/specs/2026-05-18-docs-honesty-lint.md` - (grounding-check PASS 10/10). - -## P1 — Next - -- [x] **\[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: - additive `FnDef.export: Option` (hash-stable, ~85-site - compile-driven thread); Form-A `(export "")` 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*); codegen - `Target::StaticLib` (suppresses `@main`+`MissingEntryMain`, emits - one external `@` forwarder per export, decoupled from - `ail__` mangling per Decision 2); CLI `ail build - --emit=staticlib` (`lib.a` + separate `libailang_rt.a`). - Coherent stop PROVEN: C host links both archives, calls the - scalar kernel, typed return holds. spec `51160e9` (grounding-check - PASS) → plan `b0bd7ef` (Repaired) → iter `818177d` (partial 1–3 + - Boss plan Repair: a module≠stem fixture defect, resolved Option 2) - + `e406d07` (DONE 4–7). Milestone-close `audit` `425c4eb` CLEAN - (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; bench `check.py` exit 1 decisively - causally exonerated — 21/21 bench binaries `cmp`-byte-identical - vs pre-milestone, the two tracked-P2 noise families, NO ratify). - `fieldtest` `6a4e866` substantiated 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 in - `git log`). - - context: `docs/specs/2026-05-18-embedding-abi-m1.md`; - `docs/specs/2026-05-18-fieldtest-embedding-abi-m1.md` - -- [x] **\[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.md` stated 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-pointing `use-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-grounded `step` Form-A snippet; RED-first anti-regrowth pin - via `ailang_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), zero - `crates/**/src/**` diff. Pure docs+pin tidy — no audit/fieldtest - gate (the pin IS the regression coverage). plan - `docs/plans/form-a-scalar-param-mode-carveout.md` (`4c266a6`) → iter - `7d7f04e`. Stays here briefly for context; remove once stale (full - record in `git log`). - - context: `docs/specs/2026-05-18-fieldtest-embedding-abi-m1.md` - findings [friction] + [spec_gap]#1. - -- [x] **\[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-ir` had no - `--emit=staticlib` (only `ail build` did) and on a `main`-free - kernel hit the executable-path `MissingEntryMain` rejection — an - author could not read the generated `@` forwarder for an - exported kernel. Resolution **added** (DESIGN.md *widened*, never - narrowed): a one-line symmetric codegen convenience - `lower_workspace_staticlib(ws)` routing through the M1-audited - unchanged `Target::StaticLib` path, an `emit` clap field on - `Cmd::EmitIr` symmetric with `Cmd::Build`'s, a zero-export guard - byte-identical to `build_staticlib`'s; DESIGN.md §"Embedding ABI - (M1)" affordance sentence + a CLI-synopsis correction also - discharging a pre-existing M1 `ail build --emit=staticlib` - omission. 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_step` - external forwarder readable, no `@main`), `embed_staticlib_cli` - 2/0 (build-side untouched), `docs_honesty_pin` 5/0, `ail` 186/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). - plan `docs/plans/emit-ir-staticlib.md` (`03493c9`) → iter - `bcfe554`. Stays here briefly for context; remove once stale (full - record in `git log`). - - context: `docs/specs/2026-05-18-fieldtest-embedding-abi-m1.md` - finding [spec_gap]#2. - -- [x] **\[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 - `@(ctx, scalars…)` ABI; the M1 forwarder publishes it via - a `__thread` slot around the **byte-unchanged** internal - `@ail__` call (internal convention + `_adapter`/`_clos` - untouched — M1 decision held; TLS sound because the kernel call - is synchronous, ctx never held across a suspension). `runtime/rc.c` - de-globalised: the two RC-counter sites became `if (ctx) - ctx->{alloc,free}_count++ else g_rc_*++`, the `g_rc_*` statics + - `atexit` retained verbatim as the null-ctx single-threaded - executable fallback (executable-path leak readback byte-preserved). - ctx near-empty by discipline (`{alloc,free}_count` only — no - arena/lock/atomic/IO; the build-ahead trap named out-of-scope). - Staticlib is RC-only enforced (`--emit=staticlib` rejects - `--alloc=gc|bump`; Boehm never linked into a swarm artefact; - standing P2 Boehm-retirement untouched). No authoring-surface / - schema / `ailang-check` change — the `.ail` is 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 genuine `ThreadSanitizer` race 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. spec - `1c58055` (grounding-check PASS 9/9) → plan `b3388c8` - (Boss-corrected) → iter `c9a84b3` (PARTIAL 4/9 + Boss repair) + - `fbeeade` (DONE 5–9); milestone-close `audit` `ad88dec` (architect - one `[medium]`+`[low]` doc-honesty drift; bench `check.py` exit 1 - decisively causally exonerated — bencher H0-refuted, all 3 firings - the two tracked-P2 noise families, rc.c hunk branchless+free, NO - ratify) → tidy `a80d495` (the `## Embedding ABI` lockstep rename, - drift resolved). No fieldtest (zero authoring-surface change). - Stays here briefly for context; remove once stale (full record in - `git log`). - - context: `docs/specs/2026-05-18-embedding-abi-m2.md`. - -- [x] **\[milestone\]** Embedding ABI — M3: frozen value layout + - single ADT/record crossing + RC ownership contract — CLOSED - 2026-05-18. A single-constructor record of `Int`/`Float` fields - now crosses the embedding C ABI in **and** out; ownership follows - the declared `own`/`borrow` mode (mechanically inherited — the M2 - forwarder body is byte-unchanged, all mode-driven RC stays in the - byte-unchanged internal `@ail__`); 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 layout` SSOT + - `// FROZEN ABI` lockstep pointers at the three encoders + an - enforceable `@ailang_rc_alloc` heap-box byte-pin (RED-on-offset- - perturbation proven); host construction via `ailang_rc_alloc`, - host-free via `ailang_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 / `CheckError` - change (M2-style — the `.ail` is the minimal evolution of the - M1/M2 scalar kernel into a record `State`). The `(State,Float)-> - State` fold round-trip is proven **globally leak-free** for both - `own` and `borrow`. Process: spec `1fbb9c4` (grounding-check PASS - 8/8) → plan `15ee3c5` → iter `d5c565d` (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 for `borrow` by M2's TLS-ctx design; Boss - M2.1-precedent adjudication → a stronger global-leak-freedom proof - model) + `4ea8bc5` (DONE 6-7: the freeze). Milestone-close `audit` - `b8a60b1` (architect: Invariant 1 clean, M1/M2 byte-invariant - held, frozen-SSOT consistent — DRIFT only `[medium]`+`[low]` - doc-honesty → tidy; bench `check.py` exit 1 **decisively causally - exonerated** — byte-identical generated IR HEAD vs pre-M3 - `9a609ae` for every firing bench, the two tracked-P2 noise - families, NO ratify) → tidy `63d7d60` (pin-safe; drift resolved). - No fieldtest (zero authoring-surface change). Stays here briefly - for context; remove once stale (full record in - `git log`). - - depends on: Embedding ABI — M2. - - context: `docs/specs/2026-05-18-embedding-abi-m3.md`. - -- [x] **\[milestone\]** Embedding ABI — M5: `ail-embed` adapter + - `data-server` wiring + thread-swarm backtest — **DONE 2026-05-19**, - audited + ratified + doc-honest. Terminal milestone of the M1–M5 - Embedding ABI arc: a real backtest runs over **real Pepperstone - tick data** through the real external `data-server` crate into the - shipped M3-frozen AILang kernel, across a thread swarm of - independent per-thread embedding contexts. `ail-embed` is a lean - reusable embedding module (`extern "C"` to the M3-frozen ABI + - frozen-layout box helpers, zero finance knowledge) **plus** the - real E2E on top — in-repo but its own cargo workspace root - (`[workspace]`-excluded), the sole `data-server`↔AILang meeting - point (Invariant 1, architect-confirmed PASS at close). The - adapter (not the kernel) owns chunk iteration, unrolling each - chunk host-side into per-tick `(State, Tick) -> State` calls (M4's - cons-list crossing was retired as speculative infra). Symbol-fan - swarm = the headline existence proof (per-thread bit-exact vs an - independent host reference); time-shard swarm = the **first actual - proof** of the chunk/window-boundary invisibility the M4 - retirement rests on (per-shard bit-exact). Globally leak-free, - deterministic. Zero language/compiler change; one runtime change - (`7bfa11e`: the global RC-stats fallback counters made - atomic-relaxed — the swarm exposed that AILang's first concurrent - consumer needed it; user-adjudicated bounce-back → RED-first fix, - then a build-dependency staleness root-caused + fixed). Audit: - Invariant 1 PASS, M3 frozen-layout SSOT unmoved, bench `gc_rss` - trio evidenced-RATIFY (a Boehm conservative-scan artefact of the - necessary atomic fix; Decision-9 Boehm-transitional), P2 noise - causally exonerated baseline-pristine; doc-honesty tidy clean. - **Friction-harvest deliverable: host-per-tick-FFI ≈ ~206 ns/tick - at real EURUSD volume** — the P2 flat-array decision input. - Stays one cycle for context, then prune. - - depends on: Embedding ABI — M3 (shipped); Tick-coverage on M3 - (shipped `170464f`). - - context: `docs/specs/2026-05-19-embedding-abi-m5.md`. - -- [x] **\[milestone\]** Heap-`Str` ABI — runtime infrastructure for - malloc-backed, refcounted `Str` values alongside the existing - static `@.str_*` globals. Today the `Str` path is static-only - (DESIGN.md §"Float semantics" notes this explicitly), so any - primitive that needs to produce a `Str` at runtime — `int_to_str`, - `float_to_str` (currently type-installed but `CodegenError::Internal` - on call), eventual `Show.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 heap `Str` at the same ABI slot, - wire RC `inc`/`drop`/`clone`/`compare`/`eq` on the heap form, and - ship `int_to_str` + `float_to_str` as the first two callers so the - ABI gets exercised end-to-end. Unblocks Show + print rewire below. - - context: DESIGN.md §"Float semantics" (`float_to_str` is 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 an `int_to_str` primitive returning heap-allocated Str"). - -- [x] **\[milestone\]** Post-22 Prelude — Show + print rewire — shipped - 2026-05-13 as iters 24.1 (heap-Str runtime + codegen for `bool_to_str` - + `str_clone`, f38bad8), 24.2 (prelude `class Show` + four primitive - instances Int/Bool/Str/Float + 22b TShow/tshow migration), and 24.3 - (polymorphic `fn 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 `MethodNameCollision` workaround that - blocked the original spec retired in mq.3 (2026-05-13); spec - `docs/specs/2026-05-13-24-show-print.md` re-derived 24.2 + 24.3 - against the post-mq architecture. - - context: spec `docs/specs/2026-05-13-24-show-print.md`. - -## P2 — Medium-term - -- [x] **\[milestone\]** DESIGN.md → `design/` — CLOSED 2026-05-19. - The 3020-line `docs/DESIGN.md` is **deleted** (clean cut, no - stub) and replaced by the `design/` ledger: `design/INDEX.md` - (sole addressable spine, typed Contracts+Models tables with - polymorphic links — prose file OR authoritative source `//!`), - 14 `design/contracts/*.md` test-linked invariants + 3 - source-link-only contracts (mangling/env-construction/ - qualified-xref — code is SoT), and 5 `design/models/*.md` - whitepapers. RED-first - `design_index_pin.rs` 4-clause anti-regrowth spine; clause-3 is - a hand-rolled **faithful Sweep-1 superset** so the in-code hard - gate enforces the honesty spirit (clause-3 GREEN ⟹ Sweep-1 - clean in contracts/). Build-atomic by task ordering (the only - compile-time consumer's `include_str!` retargeted before the - deletion). Every live `DESIGN.md` reference — 4 executables, 2 - diagnostics + 2 E2Es, ~12 agent reading lists, 5 SKILL bodies, - CLAUDE.md, README, ~25 code/C/.ail/spec comment xrefs — - retargeted in lockstep; the honesty rule rewritten to name the - new rationale home. Process: spec `a64b2cc`/`314e5e4` - (grounding-check PASS ×2) → plan `deeffb1` → iter .1 `176821c` - (DONE 9/9) → `audit` `2ba5e16` (architect drift_found - `[medium]`+`[low]`, relocation byte-faithful; bencher - causally-exonerated DECISIVE on byte-identical IR+binaries, - baseline pristine — M2/M3/M5 disposition) → tidy `f2cdd67`/ - `f683f1a` (DONE 7/7; the audit Resolution mechanism+scope - corrected on planning-time evidence after a correctly-BLOCKED - plan defect — the "two+ defects ⇒ fix the upstream artifact" - discipline, not a third patch). No fieldtest (zero - authoring-surface change — reasoned exclusion). Stays briefly - for context; remove once stale (full record in - `git log`). Original decided-shape rationale - retained below for context until pruned. - - **Motivation.** The just-closed `docs-honesty-lint` milestone 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 tier was migrated out of - DESIGN.md at split time and later retired entirely; the - project's history lives in `git log`.) - - 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.md` is the typed ledger - spine: per entry a one-liner + metadata - `{kind, ratifying-test, consumer/lifetime}` + a content link - whose target is polymorphic — a `design/contracts/…` file, a - single-owner `//!` source header (mangling, env, roundtrip, - float, tail-calls, data-model), or a `design/models/…` - whitepaper. INDEX.md is the sole addressable entry point. - Decision-records move out of DESIGN.md; the honesty-lint - audit-trail invariant is repointed in the same milestone. - - **Rejected — do not relitigate.** Quarto / `.qmd` was 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* — the `design/` consumer is an LLM reading raw - files. Executable chunks would reintroduce a second "is the - invariant green?" truth that can diverge from `cargo test` (the - duplicate-source-of-truth failure mode); Quarto `@ref` - cross-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.md` is referenced by name by at - least `bench/check.py` (history-anchor / `design_schema_drift`), - `bench/architect_sweeps.sh` (Sweep 5; exit 2 = "could not find - DESIGN.md"), the reading lists of `ailang-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 runs `audit` - (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: spec `docs/specs/2026-05-19-design-md-rolesplit.md` - (incl. the Boss-adjudicated relocation Appendix; grounding-check - PASS ×2); origin 2026-05-18 chat (DESIGN.md-management - dialogue — six-turn convergence). CLOSED — audited + - drift-resolved; hard gate enforces the honesty spirit. - -- [x] **\[milestone\]** Formal cross-links in the `design/` ledger - (browsable wiki) — CLOSED 2026-05-19. The positive completion - of DESIGN.md → `design/`: informal prose cross-references between - contracts/models are now **formal file-relative Markdown links** - resolved relative to the containing file, gated by RED-first - `design_index_pin.rs` **clause-5** that fails the build on any - body link that does not resolve into the durable tier (`design/` - + `crates/**` + `runtime/**` only — never `docs/`, never a - `#fragment`). clause-5 ∘ clause-3 = complete invariant: every - contract cross-reference is a resolving durable file-link or - clause-3-forbidden history prose. INDEX spine stays - repo-root-relative (registry tier, clause-1 byte-unchanged) — the - move-fragility rationale that drives body prose to file-relative - is absent for the file that never moves. Shipped in one iter - (5/5 tasks): clause-5 with `strip_fences` (toggle on ```/~~~ so a - `](` inside a fence is not treated as a link) + RED-first via - identity-stubbed `strip_fences` synthetic vectors; 7 prose - conversions (8 link tokens — float-semantics:69/100, - embedding-abi:45, memory-model:44/105, scope-boundaries:48/88 - with mixed-referent split into a source link + a Pipeline - cross-file link); clause-6 disposition (b) on the 2 - PROSE_ROUNDTRIP homeless pointers (pointer removed, behavioural - `ail merge-prose` prose preserved); pin-safe positive-half - paragraph in `honesty-rule.md`. - - context: spec `docs/specs/2026-05-19-design-ledger-formal-links.md` - (grounding-check PASS ×3 across two corpus-grounded amendments — - clause-6 + cross-ref definition; clause-5 fence-skip + closed - convert-set enumeration); plan - `docs/plans/design-ledger-formal-links.1.md`; origin this - session's six-turn design conversation following the split close. - CLOSED — audit clean (zero drift, bench trio 0/0/0); no tidy, - no fieldtest (zero authoring-surface change — reasoned exclusion). - -- [ ] **\[milestone\]** Flat array/slice primitive — performance - follow-up to the Embedding ABI arc, *not* a capability gap. - AILang's only sequence is the recursive `List` ADT (one RC cell - per element). The ABI arc resolved chunk-crossing by having the - M5 adapter unroll each `data-server` chunk host-side into per-tick - `(State, Tick) -> State` calls (M4's cons-list crossing was - retired as speculative infra) — so the residual perf question is - no longer "1024-cell cons-chain per chunk" but **host-per-tick-FFI - vs. an eventual batch/flat-array crossing**. M5's friction-harvest - measured the per-tick FFI at **≈ ~206 ns/tick at real EURUSD - volume** (≈ 658 ms / 3.19 M ticks). Open decision: whether a - contiguous array/slice primitive (to amortise that per-tick cost - via a batch crossing) is worth a *language* change — it interacts - with uniqueness inference, RC, and the - structurally-decreasing-recursion totality story, and is out of - the (now-closed) ABI arc's scope. Now decidable on the measured - number, not speculation. - - depends on: Embedding ABI — M5 (shipped; measured ~206 ns/tick - — the justification input now exists). - - context: 2026-05-18 chat (user deferred this to keep the ABI - arc clean); the friction-harvest number recorded in the M5 - audit commit; M4 retirement decision recorded in the M5 closing - commits. - -- [ ] **\[milestone\]** Iteration-totality story — structural + - Int-bounded total recursion with *enforced* non-negativity. - AILang's iteration story stays as-is (structural / tail recursion; - `tail-app` intact). The genuine ambition — make `f(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/`Nat` type 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); the branching-builder - counter-example that surfaced the gap landed in the it.3 iter - commit. - -- [x] **\[milestone\]** Retire `io/print_int` / `io/print_bool` / - `io/print_float` effect-ops + migrate example corpus to `print`. - Shipped 2026-05-14 as iter rpe.1. - - context: shipped in the rpe.1 iter commit. - -- [x] **\[todo\]** Author `examples/prelude.ail` alongside - `examples/prelude.ail.json`. (Satisfied 2026-05-13 by iter - form-a.0 — `examples/prelude.ail` rendered via `ail render`, - 116 lines / 6386 bytes, round-trip-CI green.) - -- [x] **\[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.json` to its - `.ail` sibling via `ail render`, **delete the now-redundant - `.ail.json`**, and regenerate the JSON-AST per `ail parse` at - build / test time. Same for inline JSON-AST blocks in `docs/` - 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 `.ail` source. The JSON-AST is a - build artefact, not a checked-in twin. Tests and benches that - currently glob `*.ail.json` either parse-then-consume or are - rewired to point at `.ail` directly. The round-trip invariant - flips role: today it gates that the two forms agree; afterwards - it gates that `parse` is deterministic. - - Carve-outs that MUST stay JSON-AST (no Form-A counterpart, and - no `.ail` sibling 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.ail` entry 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. - -- [ ] **\[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: `git log --before=2026-05-11 --grep=...` for the - pre-archive-cutoff rationale. - - depends on: Post-22 Prelude — Eq/Ord (shipped 23.5) -- [x] **\[todo\]** `types` / `ctor_index` overlay 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: closed by iter ctt.1 — DESIGN.md §"Env construction" anchors the split decision. -- [x] **\[todo\]** CLI human-mode diagnostic surface for `WorkspaceLoadError`. - Shipped 2026-05-14 as iter cli-diag-human — a new `load_workspace_human` - helper in `crates/ail/src/main.rs` routes 9 non-JSON - `ailang_surface::load_workspace(&path)?` call sites through - `workspace_error_to_diagnostic`, so the bracketed `[code]` prefix is - preserved across `ail check`, `build`, `run`, `emit-ir`, `prose`, - `describe`, `deps`, `diff`, `manifest`. - - context: shipped in the cli-diag-human iter commit. -- [x] **\[todo\]** Retire dead `KindMismatch` arm — `validate_classdefs`'s - `walk_kind_mismatch` path is structurally unreachable through - well-formed schema post-ct.1 (the canonical-form validator catches - the malformed `Type::Con { name: param }` shape earlier). The - enum variant + `walk_kind_mismatch` helper stay as dead-but-defensive - code; a future tidy can delete both. - - context: closed by iter ctt.3 — variant + helper + dispatch + Display arm all deleted; canonical-form-rejection test stays green asserting `BareCrossModuleTypeRef`. -- [x] **\[todo\]** Re-key `Registry.type_def_module` to handle - bare-name-collision-across-modules — `BTreeMap` keyed - by bare type name silently overwrites when two modules each define - `type Foo`; `normalize_type_for_registry` would then collapse `M.Foo` - and `N.Foo` to 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: flagged by the 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: `git log --before=2026-05-11 --grep=...` for the - pre-archive-cutoff rationale. -- [x] **\[milestone\]** Module-qualified class names + type-driven - method dispatch — retired the `MethodNameCollision` workaround; - 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_classes` - inverse index, multi-candidate `ResidualConstraint`, - `resolve_method_dispatch` 5-step rule, `AmbiguousMethodResolution` + - `UnknownClass` diagnostics), and mq.3 (retirement + multi-class E2E - + `class-method-shadowed-by-fn` warning + DESIGN.md sync). Two - libraries can now each declare `class Eq` with their own `eq`; - cross-class method ambiguity is resolved at the call site via - type-driven dispatch with `..` 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: pre-milestone-22 "Boehm transitional" decision — - see commits from that window. -- [ ] **\[feature\]** Closure-pair slab / pool — codegen tweak to - pool the env+code closure pairs instead of one-shot heap allocs. - Bench-gated. -- [ ] **\[todo\]** `FnDef::synthetic` flag — 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. - -- [x] **\[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`+`Diverge` both wired up; - `Term::Do` "effect-handler table at link time") reconciled to the - real flat-closed-set / IO-only / `IndexMap`+codegen-`match` - mechanism, satellite lockstep done, guarded by a 4-test - doc-presence pin. No language/checker/codegen change. - - context: shipped in the effect-doc-honesty iter commit. -- [ ] **\[todo\]** `io/print_float` always-emit-`.0` — surface - printer always emits `.` or `e/E` so re-lex routes to Float; - the runtime printer (`printf("%g\n", v)`) doesn't, so `2.0` - prints as `2` (Int-shaped). Asymmetric. Either switch the - runtime path to a `.0`-fallback printer (matching surface) or - document the `%g` contract in DESIGN.md §"Float semantics" so - the LLM-author knows `io/print_float`'s output is for-humans - not round-trip. - - context: `docs/specs/2026-05-10-fieldtest-floats.md` finding F1. -- [ ] **\[todo\]** Rustdoc warning sweep — `cargo doc --no-deps` - reports 16 pre-existing warnings (15 in `ailang-check`, 1 in - `ailang-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: surfaced in the design-md-consolidation audit close - (2026-05-10). -- [ ] **\[todo\]** `ailang-plan-recon` site-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-module `synth` callers, - loop-recur.tidy implicit, and now remove-mut-var-assign.1 (in-source - `mod tests` fns + a drift-pin fn + 5 orphaned `.ail.json` carve-outs - + a non-enumerated `codegen_import_map_fallback_pin.rs` E0599) **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 only `docs/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. - Tighten `skills/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*). -- [ ] **\[todo\]** `design_schema_drift.rs` fidelity 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: surfaced in the 2026-05-10 audit close. -- [ ] **\[todo\]** Split `BadCrossModuleTypeRef` into 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 )` vs. fix the - type name). In the known-owner branch, list the owner's available - type defs as candidates the way `bare-cross-module-type-ref` - lists candidates from imports. - - context: fieldtest 2026-05-11 — `examples/ct_3*.ail` exhibits both branches with identical-shape diagnostics. -- [ ] **\[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 niladic `run_forever : fn() -> Int` - called `(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's `Term::App` - `args:[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.md` finding F3; - `docs/specs/2026-05-18-fieldtest-loop-recur.md` spec_gap. -- [ ] **\[todo\]** Module-level `(doc …)` diagnostic omits where `doc` - belongs — 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`/`data` defs; an - author can read it and conclude doc strings are unsupported. One-line - tidy: append a hint like "(doc strings attach inside `fn`/`data` - defs, not at module level)". Low cost; verbose-diagnostic-philosophy - gap, not a bug. - - context: `docs/specs/2026-05-18-fieldtest-loop-recur.md` friction. -- [ ] **\[todo\]** Workspace search beyond entry-module's directory — - `load_workspace` only finds sibling `.ail.json` files 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-root` flag on `ail 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. -- [ ] **\[todo\]** `*.bump_s` throughput baseline is stale vs current - hardware — `bench/check.py`'s `throughput.*.bump_s` family (the - fastest, most jitter-prone metrics) reads ~+5–13% over - `bench/baseline.json` on the current machine. Localised at the - iteration-discipline-revert audit (2026-05-16): an interleaved - 3×60-run measurement of `bench_list_sum` bump_s built from the - byte-oracle commit `1ff7e81` shows the *same* ~+11% elevation as - HEAD, and the two bump binaries are `cmp`-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_s` set on current hardware from a known-clean commit and - recalibrate the `bump_s` baseline+tolerance pair (or widen the - tolerance) so the noise floor stops tripping `check.py` exit 1. - Pure bench-harness recalibration; no language change. -- [ ] **\[todo\]** `check.py` RC-latency `*.max_us` is a structural - false-positive at `-n 5` — **distinct** from the `*.bump_s` - staleness above (different metric family, different root cause). - `latency.{explicit,implicit}_at_rc.max_us` is 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 false `REGRESSION` on **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 vs `48e7774` bench binaries - `cmp`-byte-identical, `explicit_at_rc.max_us` collapsed - +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_us` from the - gating set (keep median/p99/p99.9, which are the trustworthy - signal), or raise `-n` substantially 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: the bencher localisation evidence in the - iteration-discipline-revert audit commit. -- [x] **\[todo\]** `check_in_workspace` per-module overlay narrowing — - `crates/ailang-check/src/lib.rs:1234` still clears+rebuilds - `env.ctor_index` per-module; ct.3.2 narrowed the analogous mono - overlay to types-only. The typecheck-side overlay's `env.ctor_index` - half 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: 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. -- [x] **\[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.1 `str_clone` / `int_to_str` / `bool_to_str` plumbing: - runtime C helper (`ailang_str_concat`), `ailang-check` builtin - registration, `ailang-codegen` extern + `lower_app` arm, plus a - fresh `examples/show_user_adt_with_label.ail` corpus fixture - exercising the LLM-natural Show-body shape. - - context: shipped in the str-concat iter commit. - -- [~] **\[milestone\]** Stateful islands — bounded mutation for - streaming workloads (`Stateful a b` + `!Mut` effect + `mut` - syntactic block). Adds a sealed mutable-state layer on top of - the pure core: a `Stateful a b` first-class type whose interior - is mutable, whose exterior is a typed callable with `!Mut` in - 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; `!Mut` needs **no** effect-handler machinery. The - only real code prerequisite the recon found is one hard-coded - assumption (`linearity.rs` walks every `Term::Do` arg as `Borrow`; - `EffectOpSig` has 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) the `arg_modes` finding is recorded as recon - context for the future `!Mut` design, NOT built ahead — it is - first-iteration material of whatever the `!Mut` milestone 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` + `!Mut` annotation 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 existing - `own` / `borrow` mode 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 b` as a first-class type — a sealed callable with a - hidden mutable env, externally a typed callable whose effect - set includes `!Mut`. - - `!Mut` effect, the first non-IO / non-Diverge effect; forces - the effect-handler infrastructure forward. - - `mut` block 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 no - `while`/`for` and this milestone does not introduce one — - repetition stays recursion, exactly as the language has it today - (structural / tail recursion); a `mut` block is a sealed - expression, never a loop over mutable state.) - - `var x = expr` + `assign x expr` AST nodes, legal only inside - `mut`. - - 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 c` as 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." `!Mut` is 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 `var` captures.* 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 or `borrow`-able, - bounds-checking discipline). - - *`runST`-equivalent escape discharge.* Producing a `Stateful` - that legitimately escapes its `mut` block 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` / `assign` are genuine AST - nodes with round-trip-invariant coverage. Surface needs LLM- - utility validation (does the author reach for `var` / `mut` - unprompted?) before implementation. - - *Codegen for in-place struct-field writes.* `Term::ReuseAs` - today lowers ADT in-place rewrite; no direct mutable struct- - field-write path exists. `crates/ailang-codegen/src/escape.rs` - plus the lowering passes need extension. - - *Boundary escape analysis.* "Interior state doesn't leak" is an - escape analysis specifically over `var` / `ref` values; 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.myc` analysis — - 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 produce `docs/specs/-stateful-islands.md` and decide - the effect-handler-prerequisite question. - -## P3 — Ideas - -- [x] **\[todo\]** `compare_primitives_smoke.ail` counterpart. - Satisfied 2026-05-13 by milestone form-a-default-authoring — - `examples/compare_primitives_smoke.ail` is 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_pattern` type-anchoring — - `crates/ailang-codegen/src/lib.rs:1790` still walks every module's - ctor_index by bare ctor name. Plumbing the scrutinee's - qualified `Type::Con` through 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: surfaced in iter ct.3 + ct.4 close (2026-05-11). -- [ ] **\[todo\]** `compare_primitives_smoke` IR-shape assertion — - observe `compare__Int` / `compare__Bool` / `compare__Str` symbols - in the emitted IR. Blocked on `emit-ir` CLI not running mono; - resolution paths include extending the CLI to run mono, using - library APIs directly in e2e.rs, or adding `--dump-ir` to `ail - build`. The E2E stdout assertion already covers correctness; the - IR-shape test would catch refactor regressions that rename - mono symbols. - - context: 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: surfaced in iter 22-tidy.7 (2026-05-10). -- [ ] **\[idea\]** `write_type` `Type::Forall` arm in - `crates/ailang-prose/src/lib.rs` silently 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: surfaced in iter 22-tidy.6 (2026-05-10). -- [ ] **\[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 check` - path (LLM calls back into `ail parse`/`ail check` mid-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` -- [ ] **\[todo\]** Sweep 5 self-match anchor-exclusion — `bench/architect_sweeps.sh` - Sweep 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-honesty-lint audit commit (architect `[medium]` - advisory wart, carry-on). diff --git a/skills/audit/SKILL.md b/skills/audit/SKILL.md index d5ad450..bd05c7e 100644 --- a/skills/audit/SKILL.md +++ b/skills/audit/SKILL.md @@ -1,6 +1,6 @@ --- name: audit -description: Use at milestone close OR when baseline drift is suspected. Runs architect drift review against the design/ ledger (spine design/INDEX.md) plus the three regression scripts (bench/check.py, bench/compile_check.py, bench/cross_lang.py). Mandatory at every milestone close; deferral requires an explicit roadmap entry naming the reason and the re-run date. +description: Use at milestone close OR when baseline drift is suspected. Runs architect drift review against the design/ ledger (spine design/INDEX.md) plus the three regression scripts (bench/check.py, bench/compile_check.py, bench/cross_lang.py). Mandatory at every milestone close; deferral requires an explicit Gitea backlog issue naming the reason and the re-run date. --- # audit — milestone-tidy @@ -17,7 +17,7 @@ iteration of a milestone closes and before the next milestone starts. ## When to Use / Skipping **Mandatory** at every milestone close. Skipping requires an explicit -roadmap entry naming: +Gitea backlog issue naming: - the blocking sibling milestone (if any), - the reason for deferral, - the date the audit will be re-run. @@ -129,7 +129,7 @@ self-resolve. - Bumping baseline without a paired ratify statement in the audit commit body - Treating exit code 2 as a regression to fix - Closing a milestone with drift items in `pending` state -- "We'll re-run after the holidays" without a dated roadmap entry +- "We'll re-run after the holidays" without a dated backlog issue ## Cross-references diff --git a/skills/audit/agents/ailang-architect.md b/skills/audit/agents/ailang-architect.md index 8922410..7ff7bf8 100644 --- a/skills/audit/agents/ailang-architect.md +++ b/skills/audit/agents/ailang-architect.md @@ -62,7 +62,7 @@ If `milestone_scope` is empty, return a structural error and stop. - **Drift against the milestone spec** (if one exists). Does the code match the spec's *Components* and *Data flow* sections? - **Growing debt.** Heuristics where the schema is authoritative, - TODO/FIXME without a roadmap entry or named owner, `#[allow(dead_code)]` + TODO/FIXME without a backlog issue or named owner, `#[allow(dead_code)]` spots that will tip over long-term, magic numbers without named constants in hot paths. - **Consistency across crates.** AST changes that landed in one crate but @@ -93,8 +93,9 @@ If `milestone_scope` is empty, return a structural error and stop. `design/contracts/honesty-rule.md`: a hit is drift unless it is a present-tense correctly-labelled reserved/excluded claim, present-tense design rationale, or a - block-quote commit-body citation. Forward intent is roadmap drift; - document/project history belongs in `git log`, not in `design/`. + block-quote commit-body citation. Forward intent belongs in the + Gitea backlog; document/project history belongs in `git log`, not + in `design/`. - **Lockstep invariants across files.** Two known cross-file pairings must move together; a new arm in one without the matching update in the other ships silently broken (B1 in the Floats fieldtest is the diff --git a/skills/boss/SKILL.md b/skills/boss/SKILL.md index 2a9e5cf..73af73a 100644 --- a/skills/boss/SKILL.md +++ b/skills/boss/SKILL.md @@ -1,6 +1,6 @@ --- name: boss -description: User-invoked only (typed as `/boss`). Activates autonomous orchestrator mode — Claude picks the next iteration from `docs/roadmap.md`, dispatches the appropriate skill, and continues until done-state or genuine bounce-back. Outside `/boss`, the default is interactive collaboration with the user, not autonomous queue execution. +description: User-invoked only (typed as `/boss`). Activates autonomous orchestrator mode — Claude picks the next iteration from the Gitea issue backlog, dispatches the appropriate skill, and continues until done-state or genuine bounce-back. Outside `/boss`, the default is interactive collaboration with the user, not autonomous queue execution. --- # boss — autonomous orchestrator mode @@ -11,14 +11,14 @@ description: User-invoked only (typed as `/boss`). Activates autonomous orchestr Autonomous orchestrator mode is the way Brummel-as-LLM moves the AILang project forward when the user is away. Inside this mode, -Claude reads `docs/roadmap.md`, picks the top item, dispatches the -right skill, integrates the result, and continues to the next item -— until the queue is empty (done-state) or a real design fork +Claude reads the Gitea issue backlog, picks the top item, dispatches +the right skill, integrates the result, and continues to the next +item — until the queue is empty (done-state) or a real design fork forces a bounce-back to the user. Outside this mode, the default is interactive collaboration: the user asks; Claude answers or executes the specific request; Claude -stops. There is no autonomous picking from the roadmap, no +stops. There is no autonomous picking from the backlog, no multi-iter sequence chained off a single user message. This skill exists to make the mode-switch explicit. Without it, @@ -67,12 +67,16 @@ mode. This skill does not restate them. ### Step 1 — Read the queue -`docs/roadmap.md` is the priority-ordered forward queue. Read it -first. The top item is the candidate for the next dispatch. +The Gitea issue backlog is the priority-ordered forward queue. +Browse: http://192.168.178.103:3000/Brummel/AILang/issues. CLI: +`tea issues ls --repo Brummel/AILang --labels prio:p1` walks the +highest-priority bucket first; drop to `prio:p2` / `prio:p3` when +P1 is empty. Read the candidate issue body with `tea issues `. +The top P1 item is the candidate for the next dispatch. -If the queue is empty: skip to Step 5 (done-state). Do not invent -work; an empty queue is a real signal that the milestone closed -and there is nothing left. +If the entire open backlog is empty: skip to Step 5 (done-state). +Do not invent work; an empty queue is a real signal that the +milestone closed and there is nothing left. ### Step 2 — Pick the top item per direction-freedom rules @@ -147,10 +151,11 @@ Bounce back to the user only when: dependency failure, a discovered invariant violation). - The user has explicitly asked for a checkpoint. - **The next item on the queue is a new milestone** — i.e. a - roadmap entry that has no `docs/specs/` file yet and would - require dispatching `brainstorm` to even begin. Continuing - an open milestone (next iter, audit, fieldtest, post-audit - tidy) is autonomous; *starting* a new one is a bounce-back. + backlog issue (typically `kind:milestone`) that has no + `docs/specs/` file yet and would require dispatching `brainstorm` + to even begin. Continuing an open milestone (next iter, audit, + fieldtest, post-audit tidy) is autonomous; *starting* a new one + is a bounce-back. **Why this is different from the other three triggers.** Cross- milestone work is high-context work. A fresh brainstorm alone @@ -162,7 +167,7 @@ Bounce back to the user only when: continuation. A new milestone is therefore the natural checkpoint: stop, surface the candidate, let the user pick the session shape (continue here / spawn fresh / defer / pick a - different roadmap item). + different backlog item). A summary of what shipped is fine and welcome — but in autonomous mode, follow it with the next dispatch, not a @@ -174,7 +179,7 @@ Two states call for a notify; nothing else does: 1. **Done-state.** The autonomous queue is empty — the milestone closed, the audit ratified, and no further iteration is obvious - from the spec or the roadmap (or, in a user-scoped session, + from the spec or the backlog (or, in a user-scoped session, every objective the user named has been completed and there is nothing else queued). A finished sub-goal inside a still-open milestone is *not* done-state. If the next iteration is obvious @@ -186,7 +191,7 @@ Two states call for a notify; nothing else does: freedom" — design fork I cannot resolve, an unexpected invariant violation, an external dependency failure, the user has explicitly asked for a checkpoint, or the next - roadmap item is a new milestone (no spec yet) and starting + backlog item is a new milestone (no spec yet) and starting it would force a fresh `brainstorm`. A user-specified stop trigger ("until X is done, then notify") @@ -244,10 +249,10 @@ actionable ask, not a wrap-up summary. |--------|---------| | "Iter just landed cleanly, let me notify so user can see" | Mid-flow notifications burn user attention without giving them a decision to make. Iter-clean is internal progress, not a notify event. | | "Sub-goal of the milestone is done, that counts as done-state" | Done-state is queue-empty, not sub-goal-complete. If the next iter is obvious and substantive, keep dispatching. | -| "Top of roadmap has two equally good options, I'll just pick one" | If both are substantive and the choice is non-obvious, that's a real fork — bounce back. The cost of a wrong pick (working-tree discard) is higher than the cost of one short ping to the user. | +| "Top of the backlog has two equally good options, I'll just pick one" | If both are substantive and the choice is non-obvious, that's a real fork — bounce back. The cost of a wrong pick (working-tree discard) is higher than the cost of one short ping to the user. | | "User said 'until X then notify', X just completed, notify now" | Check whether X was actually the last actionable thing. If hitting X leaves an open milestone with obvious follow-up, the user's intent was "wake me when there's nothing else to do" — continue. | | "Notify can name the iter code — user will figure out what it means" | No. The notify text is for the user-as-reader who did not watch me work. Iter codes, crate names, function identifiers, type names — all internal, all banned. | -| "The previous milestone closed cleanly and the next roadmap item is obvious — just dispatch `brainstorm` and keep going" | No. Starting a new milestone is itself a bounce-back. A fresh `brainstorm` is high-context work, and I cannot compact my own context — only the user can decide whether the next milestone wants a fresh session or a continuation of this one. The "obviousness" of the candidate is irrelevant; the *cross-milestone hop* is the checkpoint, not the topic choice. | +| "The previous milestone closed cleanly and the next backlog item is obvious — just dispatch `brainstorm` and keep going" | No. Starting a new milestone is itself a bounce-back. A fresh `brainstorm` is high-context work, and I cannot compact my own context — only the user can decide whether the next milestone wants a fresh session or a continuation of this one. The "obviousness" of the candidate is irrelevant; the *cross-milestone hop* is the checkpoint, not the topic choice. | | "It's the same broad area as the milestone I just closed, that's not really a new milestone" | If there is no `docs/specs/<...>.md` file for it yet and it would route through `brainstorm` to get one, it IS a new milestone for this rule's purposes. The rule keys on "needs a fresh spec", not on subjective continuity. | ## Red Flags — STOP @@ -257,7 +262,7 @@ actionable ask, not a wrap-up summary. - About to autonomously dispatch in a session where the user did NOT type `/boss`. - About to send a notify that names a crate, an iter code, or an agent. - About to bounce back at every iter boundary "just to be safe" — that's reactive deference, not direction freedom. -- About to dispatch `brainstorm` on a roadmap item that does not yet have a spec file, without first bouncing back to the user. New milestones never start autonomously. +- About to dispatch `brainstorm` on a backlog issue that does not yet have a spec file, without first bouncing back to the user. New milestones never start autonomously. ## Cross-references @@ -266,8 +271,10 @@ actionable ask, not a wrap-up summary. - **Universal rules:** `CLAUDE.md` — agent role boundaries, commit discipline, design rationale, authority over skills, feature acceptance, TDD-for-bugs, file-role roster. -- **Queue:** `docs/roadmap.md` — priority-ordered forward queue - consumed by Step 1. +- **Queue:** Gitea issues — priority-ordered forward queue + consumed by Step 1. Browse: + http://192.168.178.103:3000/Brummel/AILang/issues; CLI: `tea + issues ls --repo Brummel/AILang --labels prio:p1`. - **Canonical feature-acceptance criterion:** `design/contracts/feature-acceptance.md` — the criterion that gates new features; applied at spec time by `skills/brainstorm`. diff --git a/skills/brainstorm/SKILL.md b/skills/brainstorm/SKILL.md index 8eb8029..5e48242 100644 --- a/skills/brainstorm/SKILL.md +++ b/skills/brainstorm/SKILL.md @@ -242,19 +242,22 @@ interpretation: 1. Delete the just-written spec file from the working tree (`rm docs/specs/.md` — a Bash-level delete on the working tree, NOT `git rm`; the file was never committed). -2. Append a roadmap entry to `docs/roadmap.md` pointing forward to a - future re-brainstorm, under the appropriate priority bucket: +2. Open a Gitea backlog issue pointing forward to a future + re-brainstorm, under the appropriate priority bucket: - ```markdown - - [ ] **[]** - - context: - - depends on: + ```bash + tea issues create --repo Brummel/AILang \ + --title "" \ + --labels "kind:,prio:p2" \ + --description " + + **context:** + **depends on:** " ``` -3. Tell the user the spec was retired and which roadmap entry was - added. The user / Boss commits the roadmap edit (suggested - commit subject: `spec: retire — depends on - `). +3. Tell the user the spec was retired and which Gitea issue was + filed (include the issue number). No commit is needed for the + backlog entry — Gitea is the live store. After the failure-mode procedure runs, the brainstorm session ENDS. There is no Step 8, no Step 9. The idea is parked until the @@ -305,7 +308,7 @@ Hand off carries: | user → `brainstorm` | new milestone request | | `brainstorm` → `ailang-grounding-check` (Step 7.5) | `spec_path` + `iteration_scope` | | `brainstorm` → `planner` (Step 9, on PASS or overridden BLOCK) | path to spec + iteration scope | -| `brainstorm` → roadmap (Step 7.5, on no-override BLOCK) | `depends on:` entry added to `docs/roadmap.md` in the working tree, spec file deleted from the working tree; Boss commits the roadmap edit | +| `brainstorm` → Gitea backlog (Step 7.5, on no-override BLOCK) | new issue opened via `tea issues create` naming the unratified dependency; spec file deleted from the working tree (no commit needed) | ## Common Rationalisations diff --git a/skills/docwriter/SKILL.md b/skills/docwriter/SKILL.md index 272b89a..fdaca04 100644 --- a/skills/docwriter/SKILL.md +++ b/skills/docwriter/SKILL.md @@ -26,7 +26,7 @@ Trigger conditions are any of: - `cargo doc --no-deps 2>&1` shows accumulated warnings across multiple crates after a stability window of several milestones. -- A roadmap entry like "Rustdoc warning sweep" has matured — the +- A backlog issue like "Rustdoc warning sweep" has matured — the surface it targets has not moved for a while. - Onboarding-readability check: navigating `cargo doc --open` for a crate is not self-supporting without the design/ ledger. @@ -86,4 +86,4 @@ iteration; `docwriter` does not self-resolve. Fieldtest can surface bugs or architecture problems that would invalidate the doc work. - **Hand-off target:** orchestrator (me). Findings flow into the - roadmap as candidates for a follow-up tidy iteration. + Gitea backlog as candidates for a follow-up tidy iteration. diff --git a/skills/docwriter/agents/ailang-docwriter.md b/skills/docwriter/agents/ailang-docwriter.md index f03a68c..b10e35f 100644 --- a/skills/docwriter/agents/ailang-docwriter.md +++ b/skills/docwriter/agents/ailang-docwriter.md @@ -89,7 +89,7 @@ YOU NEVER COMMIT. RUSTDOC EDITS LIVE IN THE WORKING TREE; THE BOSS COMMITS. confusing it needs renaming, raise it in your report instead of changing it. - No new `pub` exports. Visibility stays as-is. -- No edits in `docs/` or `design/`. The orchestrator owns the design/ ledger and the roadmap. +- No edits in `docs/` or `design/`. The orchestrator owns the design/ ledger and the Gitea backlog. - Don't paper over broken behaviour with prose — if doc-writing surfaces a real bug (a function whose doc you cannot honestly write because it doesn't actually do what it claims), stop and report it. diff --git a/skills/fieldtest/SKILL.md b/skills/fieldtest/SKILL.md index 2b197e4..53d6e34 100644 --- a/skills/fieldtest/SKILL.md +++ b/skills/fieldtest/SKILL.md @@ -58,7 +58,7 @@ routing table below applies in all cases. **Skipping is not permitted** for: - A milestone that introduced or changed surface syntax, schema, effects, types, modes, or any user-visible diagnostic. -- A milestone whose commit body or roadmap entry claims "LLM author +- A milestone whose commit body or backlog issue claims "LLM author can now write X". `fieldtest` is the gate that empirically substantiates such claims; an unverified claim is drift.