roadmap: Embedding ABI arc — M1–M5 (P1) + deferred array primitive (P2)
The data-server-driven goal: a compiled AILang kernel callable in-process from a concurrent Rust host so a backtest swarm runs each backtest as an independent single-threaded computation. Decomposed into five chronologically-bounded milestones (M1 linkable artifact+scalar entrypoint, M2 per-thread ctx+concurrency safety, M3 frozen value layout+ADT crossing, M4 List-ADT sequence crossing, M5 ail-embed adapter+swarm fieldtest), each its own full brainstorm->plan->implement->audit cycle. Shared motivation + three audited invariants (clean core / single-threaded per computation / native-AOT-only) carried on the M1 entry. The flat array/slice primitive is recorded P2 as a measured performance follow-up gated on M5's fieldtest, not a capability gap — keeping the ABI arc's scope clean. Decision made in the 2026-05-18 data-server analysis chat; no spec yet (brainstorm produces M1's spec at start).
This commit is contained in:
+130
@@ -129,6 +129,119 @@ work progresses.
|
|||||||
|
|
||||||
## P1 — Next
|
## P1 — Next
|
||||||
|
|
||||||
|
- [ ] **\[milestone\]** Embedding ABI — M1: linkable artifact +
|
||||||
|
scalar C entrypoint + `main`-free lifecycle. First of a
|
||||||
|
five-milestone arc (M1–M5) 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.
|
||||||
|
|
||||||
|
**Motivation (shared by M1–M5).** 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).
|
||||||
|
|
||||||
|
**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). No spec yet; brainstorm
|
||||||
|
produces `docs/specs/<date>-embedding-abi-m1.md` at M1 start.
|
||||||
|
|
||||||
|
- [ ] **\[milestone\]** Embedding ABI — M2: per-thread runtime
|
||||||
|
context + concurrency safety. `ailang_ctx_new()/_free` threaded
|
||||||
|
through every call; neutralise the two process-global hazards
|
||||||
|
the runtime read surfaced — the non-atomic
|
||||||
|
`g_rc_alloc_count` / `g_rc_free_count` counters + `atexit`
|
||||||
|
stats hook (`runtime/rc.c:86–98`), and the allocator backing
|
||||||
|
(toward pure per-thread RC, no shared Boehm collector; aligns
|
||||||
|
with the standing P2 "Boehm full retirement" todo). Still
|
||||||
|
scalar-only so any failure is attributable to concurrency, not
|
||||||
|
marshalling. IO-at-the-boundary (`io/print_str` via a
|
||||||
|
per-instance sink) explicitly deferred here: pure
|
||||||
|
`(State,Chunk)->State` kernels have no effects; revisit only
|
||||||
|
if a logging kernel appears — deliberately not a separate
|
||||||
|
roadmap entry, by feature-acceptance discipline. Coherent stop:
|
||||||
|
swarm-safe scalar kernels, tsan-clean under N threads.
|
||||||
|
- depends on: Embedding ABI — M1.
|
||||||
|
- context: 2026-05-18 chat; runtime hazard read
|
||||||
|
(`runtime/rc.c` global stats + `atexit`).
|
||||||
|
|
||||||
|
- [ ] **\[milestone\]** Embedding ABI — M3: frozen value layout +
|
||||||
|
single ADT/record crossing + RC ownership contract. Host
|
||||||
|
constructs a single-ctor record (Int/Float fields), passes it,
|
||||||
|
the kernel returns a record the host reads and frees; the RC
|
||||||
|
ownership-transfer contract at the call boundary is specified
|
||||||
|
and the `rc_header`/ADT-box layout documented as a *frozen*
|
||||||
|
ABI. Sequenced after M2 — a one-way stability commitment, so
|
||||||
|
the frozen ABI must already include the ctx parameter shape
|
||||||
|
(substantive ordering reason, not effort). Covers the `State`
|
||||||
|
value crossing in/out. Coherent stop: a record in/out with
|
||||||
|
alloc==free across many calls.
|
||||||
|
- depends on: Embedding ABI — M2.
|
||||||
|
- context: 2026-05-18 chat. `runtime/rc.c`'s header already
|
||||||
|
anticipates this ("The ABI defined here is stable … unless
|
||||||
|
the layout itself shifts").
|
||||||
|
|
||||||
|
- [ ] **\[milestone\]** Embedding ABI — M4: sequence crossing via
|
||||||
|
the existing `List` ADT. Host builds a `List Record` per chunk;
|
||||||
|
`(State, List Record) -> State` callable end-to-end. Pure
|
||||||
|
ABI/marshalling, no language change — applies M3's frozen
|
||||||
|
layout repeatedly. Makes the real fold runnable over real
|
||||||
|
chunks. The array-vs-cons-list performance question (1024 RC
|
||||||
|
cons-cells per chunk on the hot path) is deliberately *not* in
|
||||||
|
scope here — capability now, performance as a separate later
|
||||||
|
non-ABI milestone (P2 below), keeping the user's "focus on the
|
||||||
|
ABI, ignore the array gap" cut. Coherent stop:
|
||||||
|
`(State, List M1) -> State` runs.
|
||||||
|
- depends on: Embedding ABI — M3.
|
||||||
|
- context: 2026-05-18 chat.
|
||||||
|
|
||||||
|
- [ ] **\[milestone\]** Embedding ABI — M5: `ail-embed` adapter +
|
||||||
|
`data-server` wiring + thread-swarm backtest (fieldtest
|
||||||
|
target). The host-side adapter crate (sole meeting point of
|
||||||
|
`data-server` and AILang, per Invariant 1) wires
|
||||||
|
`data-server`'s `while let next_chunk` loop to the AILang
|
||||||
|
kernel via the ABI; an actual small backtest runs over a
|
||||||
|
thread swarm. Natural `fieldtest` milestone: existence proof
|
||||||
|
of the whole goal + friction harvest feeding the
|
||||||
|
array-primitive decision. Coherent stop: the goal itself.
|
||||||
|
- depends on: Embedding ABI — M4.
|
||||||
|
- context: 2026-05-18 chat.
|
||||||
|
|
||||||
- [x] **\[milestone\]** Heap-`Str` ABI — runtime infrastructure for
|
- [x] **\[milestone\]** Heap-`Str` ABI — runtime infrastructure for
|
||||||
malloc-backed, refcounted `Str` values alongside the existing
|
malloc-backed, refcounted `Str` values alongside the existing
|
||||||
static `@.str_*` globals. Today the `Str` path is static-only
|
static `@.str_*` globals. Today the `Str` path is static-only
|
||||||
@@ -165,6 +278,23 @@ work progresses.
|
|||||||
|
|
||||||
## P2 — Medium-term
|
## P2 — Medium-term
|
||||||
|
|
||||||
|
- [ ] **\[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); marshalling a 1024-record chunk across the
|
||||||
|
embedding boundary builds a 1024-cell cons-chain per chunk on a
|
||||||
|
multi-GB hot path (Embedding ABI M4 ships the capability this
|
||||||
|
way). A contiguous array/slice primitive would remove that, but
|
||||||
|
it is a *language* change (interacts with uniqueness inference,
|
||||||
|
RC, and the structurally-decreasing-recursion totality story)
|
||||||
|
and is explicitly out of the ABI arc's scope. Sequenced after
|
||||||
|
M5 so the decision is driven by M5's fieldtest measurements,
|
||||||
|
not speculation.
|
||||||
|
- depends on: Embedding ABI — M5 (for the measured
|
||||||
|
justification).
|
||||||
|
- context: 2026-05-18 chat (user deferred this explicitly to
|
||||||
|
keep the ABI arc clean).
|
||||||
|
|
||||||
- [ ] **\[milestone\]** Iteration-totality story — structural +
|
- [ ] **\[milestone\]** Iteration-totality story — structural +
|
||||||
Int-bounded total recursion with *enforced* non-negativity.
|
Int-bounded total recursion with *enforced* non-negativity.
|
||||||
AILang's iteration story stays as-is (structural / tail recursion;
|
AILang's iteration story stays as-is (structural / tail recursion;
|
||||||
|
|||||||
Reference in New Issue
Block a user