roadmap: close Embedding ABI — M1 ([~]->[x]); route 3 fieldtest findings

M1 fully ratified and CLOSED: spec (grounding-check PASS) + plan
(Boss-Repaired for the module==stem fixture defect) + iter (818177d
partial+Repair / e406d07 DONE 7/7) + audit 425c4eb CLEAN + fieldtest
6a4e866 thesis-substantiated (0 bugs; clause-1 + clause-3 empirically
confirmed first-try).

3 non-blocking fieldtest findings routed to P1, ahead of M2:
- [todo] form_a.md scalar-parameter mode carve-out — docs-honesty
  tidy (friction + spec_gap#1, shared root: form_a.md's unconditional
  'every param needs own/borrow' misdirects the scalar export
  headline; scalars require bare (con Int)). Pre-existing form_a.md
  defect M1 surfaced. Settled behaviour -> tidy, no brainstorm.
- [feature] ail emit-ir --emit=staticlib — restore the Decision-5
  kernel-IR-readability affordance (add it; not narrow DESIGN.md).

INDEX line added. Next milestone (Embedding ABI — M2) has no spec ->
/boss new-milestone bounce-back.
This commit is contained in:
2026-05-18 15:28:48 +02:00
parent 6a4e8669a3
commit 4bc7eb2e0a
2 changed files with 74 additions and 61 deletions
+73 -61
View File
@@ -129,69 +129,81 @@ work progresses.
## P1 — Next
- [~] **\[milestone\]** Embedding ABI — M1: linkable artifact +
scalar C entrypoint + `main`-free lifecycle. First of a
five-milestone arc (M1M5) that makes a compiled AILang kernel
callable in-process from a concurrent Rust host, so a swarm of
backtests over `data-server`-supplied market data runs each
backtest as an independent single-threaded AILang computation.
- [x] **\[milestone\]** Embedding ABI — M1: linkable artifact +
scalar C entrypoint + `main`-free lifecycle — CLOSED 2026-05-18.
First of the five-milestone arc (M1M5) making a compiled AILang
kernel callable in-process from a concurrent Rust host. Shipped:
additive `FnDef.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*); codegen
`Target::StaticLib` (suppresses `@main`+`MissingEntryMain`, emits
one external `@<sym>` forwarder per export, decoupled from
`ail_<module>_<fn>` mangling per Decision 2); CLI `ail build
--emit=staticlib` (`lib<entry>.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 13 +
Boss plan Repair: a module≠stem fixture defect, resolved Option 2)
+ `e406d07` (DONE 47). 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
`docs/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`
**Motivation (shared by M1M5).** The target deployment of
AILang is financial-data analysis: a host (Rust, owning
`data-server`'s shared zero-copy cache) drives a swarm of
backtests; each backtest is the pure per-chunk fold AILang is
built for (`(State, Chunk) -> State`, the `sum_sq` loop/recur
shape). Today AILang is a whole-program compiler whose only
output channel is `io/print_str` — there is no way to invoke a
compiled AILang function from a host with structured arguments
and a typed return. That missing call surface, not the math, is
the entire blocker. This is a backend/packaging capability, not
a language feature: the language semantics do not change. Its
justification is strategic (this is where the language is meant
to run), not the standard authoring-utility gate — a deliberate,
user-made direction call (2026-05-18 chat).
- [ ] **\[todo\]** form_a.md scalar-parameter mode carve-out — docs-
honesty tidy (M1 fieldtest friction + spec_gap, shared root).
`crates/ailang-core/specs/form_a.md` "Schema invariants" item 1 +
the Pitfalls bullet state an *unconditional* "every `(fn …)` param
MUST be wrapped in `(own T)`/`(borrow T)`; implicit mode is
rejected" — but scalars require **bare** `(con Int)` (`(own (con
Int))``use-after-consume`, `(borrow …)`
`consume-while-borrowed`; bare checks `ok`). The doc the LLM reads
first actively misdirects M1's headline export task into a
body-pointing linearity diagnostic that never names the real cause.
Pre-existing form_a.md defect M1 made acute (the export task is the
first where a careful fresh author follows the mode prose for a new
program). Fix: state the scalar-parameter carve-out symmetrically
with the existing return-type carve-out (form_a.md item 1 +
Pitfalls), and mirror the canonical bare-scalar export-param
spelling in DESIGN.md §"Embedding ABI (M1)". Behaviour is settled
(no language/checker change) → a docs-honesty tidy in the
`docs-honesty-lint` class (anti-regression presence/absence pin),
not a brainstorm milestone. P1 — it undermines the clause-1
authoring ergonomics of the surface the rest of the M2M5 arc
extends, so it precedes M2.
- context: `docs/specs/2026-05-18-fieldtest-embedding-abi-m1.md`
findings [friction] + [spec_gap]#1.
**Invariants (audited at every close in this arc).**
(1) *Clean core*`ailang-core` / `ailang-codegen` / the
runtime gain no `data-server`/finance knowledge and no
dependency on either; the only place AILang and `data-server`
meet is a separate host-side adapter crate (`ail-embed`, M5)
that depends on both while neither depends on it. The `audit`
architect review verifies this each close.
(2) *Single-threaded per computation* — all concurrency is
structural and owned by the host; no AILang value ever crosses
a thread boundary, so non-atomic RC and "no shared mutable
refs" stay intact.
(3) *Native-AOT only* — no interpreter/playground is introduced
(the "emit LLVM → clang -O2" performance pillar is load-bearing
for the swarm).
**M1 scope.** CLI emit-mode producing a relocatable archive
instead of linking an executable; codegen exports an
author-designated `fn` under a stable C symbol with a
C-compatible signature instead of wrapping `main` (today
hard-coded `define i32 @main() { call i8 @ail_<mod>_main() }`,
`crates/ailang-codegen/src/lib.rs:556`); a minimal explicit
lifecycle so the runtime is usable with no `main`-time setup.
Scalar signatures only (`(Int)->Int`, `(Float,Float)->Float`)
— no ADT crosses the boundary yet. Coherent stop: AILang
arithmetic callable from C/Rust, proven by a host harness that
links the `.a`, calls the symbol, asserts the return.
- context: 2026-05-18 chat (`data-server` analysis →
embedding-ABI decomposition). Spec landed + user-approved
2026-05-18: `docs/specs/2026-05-18-embedding-abi-m1.md`
(grounding-check PASS on 3rd dispatch; 7 design decisions
pinned — additive `FnDef.export: Option<String>` /
`(export "<sym>")` mangling-decoupled symbol / `lib<entry>.a`
+ separate `libailang_rt.a` / no runtime lifecycle API /
`--emit=staticlib` suppresses `@main`+`MissingEntryMain` /
scalar+effect-free export gate / Task 1 fixed =
`MissingEntryMain` build-path baseline pin). Plan landed
2026-05-18 `docs/plans/embedding-abi-m1.1.md` (7 tasks; recon
file-map Boss-verified against source; both compile-break
tasks — `FnDef.export` ~95-site thread, `lower_workspace_inner`
`Target` param — scrubbed for self-review-item-7 ordering).
Next: `implement`.
- [ ] **\[feature\]** `ail emit-ir --emit=staticlib` — restore the
Decision-5 IR-readability affordance for kernels (M1 fieldtest
spec_gap). DESIGN.md Decision 5 makes "the compiler emits LLVM IR
as text so the LLM can read what it generated" a load-bearing
author affordance, but `ail emit-ir` has no `--emit=staticlib`
(only `ail build` does), and `emit-ir` on a `main`-free kernel
hits the executable-path `MissingEntryMain` rejection — so the
author cannot read the generated `@<sym>` forwarder for an
exported kernel, the exact thing M1 introduced. Resolution chosen
on the merits: **add** `--emit=staticlib` to `ail emit-ir`
(symmetric with `ail build`, reusing the `Target::StaticLib`
path) — NOT narrow DESIGN.md (narrowing a load-bearing affordance
to dodge a gap is the wrong direction). Scoped feature, no design
fork. P1.
- context: `docs/specs/2026-05-18-fieldtest-embedding-abi-m1.md`
finding [spec_gap]#2.
- [ ] **\[milestone\]** Embedding ABI — M2: per-thread runtime
context + concurrency safety. `ailang_ctx_new()/_free` threaded