iter embedding-abi-m1.1 (DONE 7/7): Embedding-ABI M1 — scalar AILang fn callable from C/Rust
Tasks 4-7 on the Boss-Repaired plan, completing the M1 iteration: - Task 4: check-side export-signature gate — CheckError variants ExportNonScalarSignature / ExportHasEffects (codes export-non-scalar-signature / export-has-effects), code() arms, check_fn gate (params->ret->effects, first-violation-wins, unconditional on f.export.is_some()). The clause-3 discriminator in code: effectful/non-scalar exports fail to typecheck. 6/6. - Task 5: codegen Target::StaticLib — Target enum, threaded param, @main/MissingEntryMain gated behind Target::Executable, one external @<sym> forwarder per export to @ail_<module>_<fn> (fn_scalar_sig/llvm_scalar). In-source missing_entry_main_is_error byte-unchanged. Lowering pin 2/2. - Task 6: CLI ail build --emit=staticlib — clap field, Cmd::Build branch, build_staticlib (verbatim build_to prefix + has_export guard + two-archive clang -c/ar rcs tail) + run_cmd. CLI pin 2/2. - Task 7: C-host E2E coherent-stop proof (cc links libembed_backtest_step.a + libailang_rt.a, backtest_step(0,3)=9 / (9,4)=25, s==25, exit 0) + DESIGN.md §"Embedding ABI (M1)" (scalar C ABI, provisional until M3). E2E pin 1/1. Independent Boss verification: E2E 1/1, gate 6/6, full workspace 0 failures, roundtrip_cli + design_schema_drift + spec_drift green, Invariant 1 holds (no new dep in core/codegen/runtime). 3 behaviour- neutral plan pseudo-vs-reality concerns in the journal. Default-exe codegen/runtime path byte-unchanged (check.py firing = tracked-P2 known-noise, audit-adjudicated). INDEX line added. Completes the M1 iteration (impl). Milestone-close audit + fieldtest (surface-touching) are the next pipeline steps.
This commit is contained in:
@@ -2260,6 +2260,30 @@ overlay shape. The asymmetry between the check side and the mono
|
||||
side is by design and is pinned by
|
||||
`crates/ailang-check/tests/duplicate_ctor_pin.rs`.
|
||||
|
||||
## Embedding ABI (M1)
|
||||
|
||||
`ail build --emit=staticlib` compiles a module to a relocatable
|
||||
`lib<entry>.a` (program objects only) plus a separate
|
||||
`libailang_rt.a` (the RC runtime: `rc.c` + `str.c`), with **no**
|
||||
`@main` trampoline and **no** `MissingEntryMain` requirement — a
|
||||
kernel module is a library.
|
||||
|
||||
Each `fn` carrying `(export "<sym>")` (schema: `FnDef.export`) is
|
||||
emitted as an externally-visible C entrypoint `@<sym>` forwarding to
|
||||
the internal `@ail_<module>_<fn>`. The symbol is author-chosen and
|
||||
decoupled from the `ail_<module>_<def>` mangling so a module/fn
|
||||
rename does not move the C symbol.
|
||||
|
||||
The M1 ABI is **scalar-only and provisional until M3**: every
|
||||
parameter and the return type must be `Int` (lowered `i64`) or
|
||||
`Float` (lowered `double`), and the fn's effect set must be empty.
|
||||
These are enforced at `ail check` (`export-non-scalar-signature`,
|
||||
`export-has-effects`) — an effectful or non-scalar export *fails to
|
||||
typecheck*. M1 ships no runtime lifecycle API: the per-thread
|
||||
context parameter that M2 threads through every exported call will
|
||||
change this C signature; do not treat the M1 signature as frozen.
|
||||
The value/record layout freeze is M3.
|
||||
|
||||
## Data model
|
||||
|
||||
The on-disk JSON-AST is what the toolchain hashes, typechecks, and
|
||||
|
||||
@@ -2,38 +2,52 @@
|
||||
|
||||
**Date:** 2026-05-18
|
||||
**Started from:** b0bd7efeaff137af22bb12f5e751260804e770c3
|
||||
**Status:** PARTIAL — Tasks 1–3 committed as a known-good subset
|
||||
(see "Boss resolution" below); plan defect fixed; Tasks 4–7
|
||||
re-dispatched on the corrected plan.
|
||||
**Tasks completed:** 3 of 7 (Tasks 1–3 DONE + committed; Task 4
|
||||
BLOCKED on a Boss plan-defect — fixture module≠stem — before any
|
||||
gate code was written; resolved by Boss + re-dispatched; Tasks
|
||||
5–7 follow in the re-dispatch)
|
||||
(Tasks 1–3 committed at 818177d; Tasks 4–7 re-dispatched from 818177d)
|
||||
**Status:** DONE — all 7 tasks complete. Tasks 1–3 committed
|
||||
(818177d); Tasks 4–7 implemented on the corrected plan and sit
|
||||
unstaged in the working tree. The E2E coherent-stop proof
|
||||
(`embed_e2e.rs`: `cc` link + run, `s == 25`, exit 0) is GREEN.
|
||||
**Tasks completed:** 7 of 7 (Tasks 1–3 DONE + committed; Task 4
|
||||
initially BLOCKED on a Boss plan-defect — fixture module≠stem —
|
||||
resolved by Boss plan Repair [Design-decision 6] + re-dispatch;
|
||||
Tasks 4–7 then completed cleanly on the corrected plan)
|
||||
|
||||
## Summary
|
||||
|
||||
Tasks 1–3 of the Embedding-ABI M1 plan landed cleanly: the CLI
|
||||
build-path `MissingEntryMain` baseline pin (Task 1), the additive
|
||||
The Embedding-ABI M1 iter is complete across all 5 pipeline
|
||||
layers. Tasks 1–3 landed in the first dispatch and were committed
|
||||
(818177d) as a verified known-good subset: the CLI build-path
|
||||
`MissingEntryMain` baseline pin (Task 1), the additive
|
||||
`FnDef.export: Option<String>` schema field threaded across the
|
||||
whole workspace via compile-driven enumeration with a hash-stability
|
||||
golden pin (Task 2), and the Form-A `(export "<sym>")` surface
|
||||
modifier with full parse/print/grammar lockstep and a byte-identical
|
||||
round-trip (Task 3). Task 4 (the check-side export-signature gate)
|
||||
is BLOCKED before any production code: the plan's verbatim gate-pin
|
||||
test (`crates/ailang-check/tests/embed_export_gate.rs`, using
|
||||
`ailang_surface::load_workspace`) is mutually unsatisfiable with the
|
||||
plan's verbatim fixtures, because `load_workspace` hard-enforces
|
||||
`module-name == file-stem` (`crates/ailang-core/src/workspace.rs:182`
|
||||
`ModuleNameMismatch`) while the fixtures (spec-mandated module
|
||||
`backtest` in file `embed_backtest_step.ail`; `bad`/`bad_io`/… in
|
||||
`embed_export_*_rejected.ail`) deliberately diverge module name from
|
||||
filename. This is not an implementer-judgement cross-check (the six
|
||||
named ones were executed where reached) — it is a structural
|
||||
contradiction that ripples across Tasks 4–7 and can only be resolved
|
||||
by a Boss/spec-level decision. Per the Iron Law (`unclear` spec
|
||||
ambiguity → BLOCKED, no implementing on a hunch), the iter stopped.
|
||||
Tasks 1–3 sit clean and green in the working tree; only the
|
||||
deliberately-RED Task 4 pin fails workspace-wide.
|
||||
round-trip (Task 3).
|
||||
|
||||
Task 4 was BLOCKED in the first dispatch on a Boss plan-defect
|
||||
(fixtures declared `module ≠ file-stem`; the loader hard-enforces
|
||||
`module == file-stem` at `workspace.rs:438`). The Boss Repaired the
|
||||
plan (Design-decision 6: fixture `(module …)` == file stem; the
|
||||
C symbol stays `backtest_step` via `(export …)`, demonstrating spec
|
||||
Decision 2's mangling-decoupling) and re-dispatched Tasks 4–7. On
|
||||
the corrected plan all four landed cleanly: the check-side
|
||||
scalar-only + effect-free export gate with two new `CheckError`
|
||||
variants (`export-non-scalar-signature` / `export-has-effects`, the
|
||||
clause-3 discriminator *in code*, Task 4); the codegen
|
||||
`Target::StaticLib` mode suppressing `@main`/`MissingEntryMain` and
|
||||
emitting one external `@<sym>` forwarder per export to
|
||||
`@ail_<module>_<fn>` (Task 5); the CLI `ail build --emit=staticlib`
|
||||
two-archive emit (`libembed_backtest_step.a` + `libailang_rt.a`,
|
||||
Task 6); and the C-host E2E coherent-stop proof — `cc` links both
|
||||
archives, calls `backtest_step(0,3)=9`, `backtest_step(9,4)=25`,
|
||||
the `s == 25` assertion holds, exit 0 (Task 7), plus the DESIGN.md
|
||||
§"Embedding ABI (M1)" current-state subsection. Full workspace
|
||||
green (0 failures); `roundtrip_cli` green; `compile_check.py` /
|
||||
`cross_lang.py` exit 0; `check.py` fires only the tracked P2
|
||||
`*.bump_s` / `*.max_us` known-noise envelope (plan Step 6: audit-
|
||||
adjudicated, not a plan-level gate — the default-executable
|
||||
codegen/runtime path is byte-unchanged). No clean-core dependency
|
||||
added (Invariant 1).
|
||||
|
||||
## Per-task notes
|
||||
|
||||
@@ -70,12 +84,66 @@ deliberately-RED Task 4 pin fails workspace-wide.
|
||||
`(export STRING)?` + prose paragraph. RED verified
|
||||
(`unknown fn attribute \`export\``), then GREEN: round-trip gate
|
||||
byte-identical, surface crate 72/0, ailang-core 111/0. DONE.
|
||||
- iter embedding-abi-m1.1.4: check-side export-signature gate.
|
||||
Wrote the five plan fixtures + the verbatim gate pin; ran it →
|
||||
RED for the WRONG reason (a `ModuleNameMismatch` load failure,
|
||||
not the absence of the gate). BLOCKED — see Blocked detail.
|
||||
No `CheckError` variant, no `code()` arm, no `check_fn` gate
|
||||
written.
|
||||
- iter embedding-abi-m1.1.4 (FIRST dispatch — BLOCKED, audit
|
||||
trail): wrote the five plan fixtures + the verbatim gate pin; ran
|
||||
it → RED for the WRONG reason (a `ModuleNameMismatch` load
|
||||
failure, not the absence of the gate). BLOCKED — see Blocked
|
||||
detail + Boss resolution. No gate production code written; the
|
||||
WIP fixtures + RED test were discarded by the Boss for the
|
||||
re-dispatch.
|
||||
- iter embedding-abi-m1.1.4 (RE-dispatch — DONE): check-side
|
||||
export-signature gate on the corrected plan (Design-decision 6,
|
||||
module==stem). Recreated the five fixtures (module == file stem;
|
||||
`embed_export_float_ok.ail` uses `(app * a b)` — no `*.` head)
|
||||
+ the verbatim gate pin `crates/ailang-check/tests/embed_export_gate.rs`.
|
||||
RED verified for the RIGHT reason (fixtures load cleanly, 4
|
||||
`*_rejected` fail because no gate exists, 2 positives already
|
||||
pass). Added two `CheckError` Error variants
|
||||
(`ExportNonScalarSignature(String,&'static str,String)` /
|
||||
`ExportHasEffects(String,Vec<String>)`) after `ConstHasEffects`,
|
||||
their two `code()` arms, and the gate in `check_fn` after the
|
||||
param/ret well-formedness checks (gate order params→ret→effects,
|
||||
first-violation-wins, unconditional on `f.export.is_some()`).
|
||||
GREEN 6/6; combined fixture fails signature-first. Round-trip +
|
||||
full workspace green. DONE.
|
||||
- iter embedding-abi-m1.1.5: codegen `Target::StaticLib`. Added the
|
||||
`Target` enum next to `AllocStrategy`; threaded `target` through
|
||||
`lower_workspace_inner`; `lower_workspace_with_alloc` /
|
||||
`lower_workspace` pin `Target::Executable`; new public
|
||||
`lower_workspace_staticlib_with_alloc`. Gated the
|
||||
`MissingEntryMain` shape-check + the `@main` trampoline behind
|
||||
`Target::Executable`; the `StaticLib` arm emits one external
|
||||
`define {cret} @<sym>(...)` per `(export …)` fn forwarding to
|
||||
`@ail_<module>_<fn>` via the new `fn_scalar_sig` / `llvm_scalar`
|
||||
helpers. RED→GREEN IR-shape pin (no `@main`, has `@backtest_step`,
|
||||
forwards to `@ail_embed_backtest_step_step`; exe target still
|
||||
`MissingEntryMain`). In-source `missing_entry_main_is_error` pin
|
||||
byte-unchanged; codegen crate 0 failures. DONE_WITH_CONCERNS
|
||||
(the `emit_ir`-routes-via-`lower_workspace` plan note).
|
||||
- iter embedding-abi-m1.1.6: CLI `ail build --emit=staticlib`.
|
||||
Added the `--emit` clap field (`value_parser = ["exe",
|
||||
"staticlib"]`, default `exe`) after `alloc`; branched
|
||||
`Cmd::Build` (`emit == "staticlib"` → `build_staticlib`); added
|
||||
`build_staticlib` (verbatim `build_to:2239–2294` shared prefix +
|
||||
`has_export` guard + `lower_workspace_staticlib_with_alloc` +
|
||||
two-archive `clang -c`/`ar rcs` tail) and the new shared `run_cmd`
|
||||
helper (confirmed no pre-existing equivalent). RED→GREEN CLI pin
|
||||
(`libembed_backtest_step.a` + `libailang_rt.a` produced;
|
||||
export-less module rejected with the zero-export error).
|
||||
Default-exe regression (floats E2E + Task-1 baseline) green.
|
||||
DONE.
|
||||
- iter embedding-abi-m1.1.7: E2E host harness + DESIGN.md
|
||||
§"Embedding ABI (M1)". Wrote `crates/ail/tests/embed/host.c`
|
||||
(spec headline host, verbatim) + `crates/ail/tests/embed_e2e.rs`.
|
||||
E2E GREEN — `cc` links `libembed_backtest_step.a` +
|
||||
`libailang_rt.a`, runs the host, `backtest_step(0,3)=9` /
|
||||
`backtest_step(9,4)=25`, `s == 25` assertion holds, exit 0 (the
|
||||
milestone coherent stop). Added the DESIGN.md §"Embedding ABI
|
||||
(M1)" subsection (verbatim prose, at `##` level for consistency
|
||||
with §"Mangling scheme"). Drift tests 8/8 + 8/8; full workspace
|
||||
0 failures; bench trio per plan Step 6. DONE_WITH_CONCERNS (the
|
||||
dead-`Path`-import correction + the `###`-vs-`##` heading-level
|
||||
resolution).
|
||||
|
||||
## Concerns
|
||||
|
||||
@@ -109,21 +177,94 @@ deliberately-RED Task 4 pin fails workspace-wide.
|
||||
writer. It is path-disjoint from every iter file. Left untouched
|
||||
(roadmap.md is Boss-owned per CLAUDE.md; main HEAD sacrosanct).
|
||||
The Boss must decide independently whether to keep or discard it;
|
||||
it is NOT part of this iter's commit.
|
||||
it is NOT part of this iter's commit. (RESOLVED at Boss
|
||||
re-dispatch: committed separately as Boss roadmap maintenance —
|
||||
see Boss resolution. Not part of the Tasks 4–7 working tree.)
|
||||
- iter embedding-abi-m1.1.5 (plan pseudo-vs-reality, behaviour-
|
||||
neutral): plan Task-5 Step 3(b) third bullet says "`emit_ir`
|
||||
(line 197): its internal `lower_workspace_inner` call passes
|
||||
`Target::Executable`". Reality: `emit_ir` does NOT call
|
||||
`lower_workspace_inner` directly — it calls `lower_workspace`
|
||||
(`codegen lib.rs:214`), which now passes
|
||||
`lower_workspace_inner(ws, AllocStrategy::Gc, Target::Executable)`.
|
||||
The plan's *intent* (the in-source `missing_entry_main_is_error`
|
||||
pin, which calls `emit_ir`, stays byte-unchanged) is delivered
|
||||
transitively and verified GREEN at Task-5 Step 7. Recorded
|
||||
because the plan's literal call-chain description was inaccurate
|
||||
(planner pseudo-vs-reality family); no behavioural deviation.
|
||||
- iter embedding-abi-m1.1.7 (plan-verbatim transcription defect,
|
||||
corrected): the plan's verbatim Task-7 `embed_e2e.rs` imports
|
||||
`std::path::{Path, PathBuf}` but the test body uses only
|
||||
`PathBuf` — a transcribed unused import that raises
|
||||
`unused_imports` on every build. Implementer-mindset judgement:
|
||||
a verbatim copy that introduces a compiler warning is not the
|
||||
plan's intent; reduced to `use std::path::PathBuf;`. Test
|
||||
behaviour byte-identical (E2E still GREEN). Recorded as a
|
||||
deviation from plan-literal text in service of plan intent.
|
||||
- iter embedding-abi-m1.1.7 (plan code-block vs plan prose, design
|
||||
consistency): plan Task-7 Step 4's code block shows the new
|
||||
section as `### Embedding ABI (M1)`, but the same step's prose
|
||||
instruction says "at the same heading level as §"Mangling
|
||||
scheme"" — §"Mangling scheme" is `## ` (level-2) in DESIGN.md.
|
||||
Used `## Embedding ABI (M1)` for structural consistency with the
|
||||
surrounding §"Mangling scheme" / §"Data model" level-2 sections,
|
||||
following the plan's explicit prose directive over its
|
||||
illustrative code-block `#`-count. Section content byte-verbatim.
|
||||
- iter embedding-abi-m1.1 (cross-checks, plan-confirming, no
|
||||
deviation): the six named implementer-judgement cross-checks were
|
||||
executed. (a) `Type::Con` has exactly `{name: String, args:
|
||||
Vec<Type>}` — no mode field; the plan's `matches!` guard is
|
||||
correct. (b) `declared_effs` is already `Vec<String>` (per
|
||||
`lib.rs` `declared_effs.into_iter().collect()`), so the plan's
|
||||
conditional `.into_iter().collect()` conversion did NOT apply —
|
||||
`.clone()` matches `ExportHasEffects(_, Vec<String>)` exactly.
|
||||
(c) `synth::llvm_type` lowers `Int`→`"i64"`, `Float`→`"double"`
|
||||
(`synth.rs:17,21`) — the plan's `llvm_scalar` is an exact mirror
|
||||
for the 2-scalar M1 subset; forwarder `call` types match
|
||||
`@ail_<module>_<fn>`'s emitted signature (also proven by the
|
||||
Task-7 E2E real `cc` link + run). (d) no pre-existing `run_cmd`
|
||||
helper in `main.rs` (only inline `Command::new` blocks) — adding
|
||||
it was correct per the plan. (e) `ailang_core::Def` is crate-root
|
||||
re-exported (`ailang-core lib.rs:76`) — `ailang_core::Def::Fn`
|
||||
valid in `main.rs`. (f) `ailang_surface::load_workspace` +
|
||||
`ailang_check::check_workspace` + `Diagnostic.code: String` are
|
||||
the exact `main.rs:580–581` public symbols. All confirmations of
|
||||
plan assumptions, not contradictions.
|
||||
|
||||
## Known debt
|
||||
|
||||
- Tasks 5 (codegen `Target::StaticLib`), 6 (CLI `--emit=staticlib`),
|
||||
7 (E2E host harness + DESIGN.md §"Embedding ABI (M1)") not reached
|
||||
— they depend on Task 4's gate (Task 5's forwarder loop trusts the
|
||||
gate; Task 6/7 build on the headline fixture). Not touched because
|
||||
the iter is BLOCKED upstream of them; no speculative partial work.
|
||||
- E2E coverage (Phase 3) not written — the iter did not reach
|
||||
completion; the Task 7 host-harness is the milestone's coherent-
|
||||
stop proof and is downstream of the block.
|
||||
- None blocking. The M1 ABI is deliberately scalar-only and
|
||||
provisional until M3 (no `Bool`/`Str`/ADT/record marshalling, no
|
||||
per-thread context lifecycle API); this is reserved-unimplemented
|
||||
scope, labelled in DESIGN.md §"Embedding ABI (M1)", not debt.
|
||||
- `check.py` fires the tracked P2 `*.bump_s` / `*.max_us`
|
||||
known-noise envelope (3 regressed / 2 improved beyond tolerance /
|
||||
58 stable; e.g. `throughput.bench_list_sum.bump_s` +13.95%,
|
||||
`latency.explicit_at_rc.max_us` +60.61%). This iter touched only
|
||||
check-side gating, a codegen `Target` enum (every existing path
|
||||
pinned `Executable`), and CLI dispatch — none on the runtime hot
|
||||
path these metrics measure; the default-executable codegen/runtime
|
||||
path is byte-unchanged (Task-5 Step 7/8 + Task-6 Step 6 confirm).
|
||||
Per plan Step 6 this is milestone-close-`audit`-adjudicated, NOT
|
||||
a plan-level gate. `compile_check.py` / `cross_lang.py` exit 0.
|
||||
- `bench/architect_sweeps.sh` exits 1 both with and without the
|
||||
DESIGN.md edit (pre-existing advisory residue, established
|
||||
carry-on adjudicated at milestone-close `audit`); the new
|
||||
§"Embedding ABI (M1)" introduced no new Wunschdenken / post-
|
||||
mortem phrasing (the "provisional until M3" / "M2 will change"
|
||||
clauses are labelled reserved-unimplemented, which the DESIGN.md
|
||||
honesty rule explicitly permits).
|
||||
|
||||
## Blocked detail
|
||||
|
||||
> **RESOLVED (2026-05-18, re-dispatch).** This block was a
|
||||
> first-dispatch event; it was resolved by the Boss plan Repair
|
||||
> (see "## Boss resolution" below — Design-decision 6, Option 2,
|
||||
> module==stem) and the Tasks 4–7 re-dispatch completed all four
|
||||
> tasks cleanly. The detail below is **preserved verbatim as the
|
||||
> iter's audit trail** and is no longer an open block. Iter status
|
||||
> is DONE.
|
||||
|
||||
**Task:** 4 (check-side export-signature gate)
|
||||
**Reason:** spec-ambiguous (a spec-internal contradiction that
|
||||
rippling-binds Tasks 4–7, surfaced as `unclear` per the per-task
|
||||
@@ -279,6 +420,8 @@ into this iter.
|
||||
|
||||
## Files touched
|
||||
|
||||
### Committed at 818177d (Tasks 1–3, first dispatch)
|
||||
|
||||
Schema / canonical docs:
|
||||
- crates/ailang-core/src/ast.rs (FnDef.export field)
|
||||
- docs/DESIGN.md (fn-JSON "export" line)
|
||||
@@ -296,21 +439,35 @@ Surface modifier (Task 3):
|
||||
- crates/ailang-surface/src/parse.rs (parse_export + parse_fn thread)
|
||||
- crates/ailang-surface/src/print.rs (write_fn_def export block)
|
||||
|
||||
New files (untracked):
|
||||
New files committed at 818177d:
|
||||
- examples/embed_noentry_baseline.ail
|
||||
- examples/embed_backtest_step.ail
|
||||
- examples/embed_backtest_step.ail (corrected to `(module embed_backtest_step)`)
|
||||
- crates/ail/tests/embed_missing_main_baseline.rs
|
||||
- crates/ailang-core/tests/embed_export_hash_stable.rs
|
||||
|
||||
### Tasks 4–7 re-dispatch working tree (UNCOMMITTED — this hand-off)
|
||||
|
||||
Modified (4 source/doc files):
|
||||
- crates/ailang-check/src/lib.rs (2 CheckError variants + 2 code() arms + check_fn gate; +51)
|
||||
- crates/ailang-codegen/src/lib.rs (Target enum + threaded target + forwarder loop + fn_scalar_sig/llvm_scalar; +130/-22)
|
||||
- crates/ail/src/main.rs (--emit clap field + Cmd::Build branch + build_staticlib + run_cmd; +123)
|
||||
- docs/DESIGN.md (new §"Embedding ABI (M1)" subsection; +24)
|
||||
|
||||
New files (untracked, this re-dispatch):
|
||||
- examples/embed_export_str_param_rejected.ail
|
||||
- examples/embed_export_adt_ret_rejected.ail
|
||||
- examples/embed_export_io_rejected.ail
|
||||
- examples/embed_export_effectful_rejected.ail
|
||||
- examples/embed_export_float_ok.ail
|
||||
- crates/ail/tests/embed_missing_main_baseline.rs
|
||||
- crates/ailang-core/tests/embed_export_hash_stable.rs
|
||||
- crates/ailang-check/tests/embed_export_gate.rs (deliberately RED —
|
||||
blocks on the spec contradiction; do NOT commit as-is)
|
||||
- crates/ailang-check/tests/embed_export_gate.rs (GREEN 6/6)
|
||||
- crates/ailang-codegen/tests/embed_staticlib_lowering.rs (GREEN 2/2)
|
||||
- crates/ail/tests/embed_staticlib_cli.rs (GREEN 2/2)
|
||||
- crates/ail/tests/embed/host.c
|
||||
- crates/ail/tests/embed_e2e.rs (GREEN 1/1 — coherent-stop proof)
|
||||
|
||||
NOT iter-authored, present in tree, Boss-decides separately:
|
||||
- docs/roadmap.md (external mid-session modification; path-disjoint)
|
||||
(`docs/roadmap.md` is NOT in this iter's working tree — the
|
||||
first-dispatch external modification was Boss-committed separately
|
||||
as roadmap maintenance, per the Boss resolution.)
|
||||
|
||||
## Stats
|
||||
|
||||
|
||||
@@ -93,3 +93,4 @@
|
||||
- 2026-05-18 — fieldtest remove-mut-var-assign (milestone CLOSE, clean — removal thesis empirically confirmed): post-audit downstream-LLM-author field test of the post-removal Form-A surface. The fieldtester (DESIGN.md + form_a.md + public examples only, never compiler source) wrote 4 FRESH real-world programs an imperative-trained author would instinctively reach for a mutable local for — running sum-of-squares accumulator (`loop`/`recur`, 2 binders → `385`), grade-classification cascade (let-threaded flag through 4 `if` → `4`/`2`/`0`), Horner polynomial straight-line build-up (5 `let acc` shadows → `73`), multi-state bracket-balance scanner threading `(rest,depth,ok)` by tail recursion → `true`/`false`) plus an out-of-tree `mut`-keyword rejection probe. **0 bugs, 0 friction, 0 spec_gap, 4 working**: every task expressed cleanly and correctly on the FIRST try with only `let`/`if`/`loop`/`recur`; all 4 `ail parse|render|parse` byte-identical. The closest-to-friction case (the multi-state machine must restate the full state tuple at every tail-call even when a branch changes one component) was carefully classified `working` not `spec_gap` — that explicit-dataflow cost IS the local-reasoning pillar working as designed, and `mut`'s implicit cross-iteration persistence of un-restated state is precisely the clause-3 failure the removal eliminates; the fieldtester explicitly noted the only conceivable sugar (a record to bundle state) is an orthogonal additive future question, NOT evidence against the removal (refused the scope-creep). The `mut` rejection is fail-closed with an actively-guiding diagnostic that enumerates the surviving term heads incl. `loop`/`recur`/`let` (no tombstone, no-nostalgia, as spec'd). Independent Boss verification: all 4 fixtures re-run → `385`/`4 2 0`/`73`/`true false`, zero `mut`/`var`/`assign` construct tokens in any fixture (a doc-faithful author did not produce the removed construct — the affirmative clause-1 evidence). **Verdict: the removal thesis is confirmed** — `mut` was redundant with `let`/`if`/`loop`/`recur` in 100% of the fresh real tasks; no expressivity lost. **The remove-mut-var-assign milestone is fully ratified and CLOSED**: spec+plan+iter, audit clean (architect `[high]` form_a.md fixed in `.tidy`, bench causally exonerated), fieldtest clean on the removal axis. Fixtures `examples/fieldtest/remove-mut_*.ail` + spec `docs/specs/2026-05-18-fieldtest-remove-mut-var-assign.md`; roadmap P0 flipped `[~]`→`[x]`, WhatsNew.md user-facing entry appended; next queue item (DESIGN.md/docs honesty-lint) is a NEW milestone = a /boss new-milestone bounce-back (not auto-started) → 2026-05-18-fieldtest-remove-mut-var-assign.md
|
||||
- 2026-05-18 — iter docs-honesty-lint.1 (single-iteration milestone, DONE): canonical docs made present-tense-honest. Stripped Wunschdenken (forward intent stated as fact) + non-citation post-mortem/doc-archaeology from `docs/DESIGN.md` (14 corrections: L484 iter-anchor, L503/L1318/L1504/L2027/L2065/L2135 post-mortem, L650 malformed-Wunschdenken, L655 dated-heading, L1513/L1837/L2046/L2519 Wunschdenken, + the Task-4-Step-14 procedural-catch-all FIX at the Form-B prose-projection bullet "was deferred from milestone 22 entirely … A future iter ships" — a soft-wrapped site the spec's illustrative regex would have missed, the procedural enumeration working exactly as designed) + `docs/PROSE_ROUNDTRIP.md` (tool-use/MCP paragraph); genuine forward intent (LLM tool-use/MCP/LSP) relocated to roadmap P3. Codified the two-pronged tense+modality discriminator as a present-tense `### What this document is — and the honesty rule it holds itself to` meta-subsection in DESIGN.md §"Project ecosystem". Anti-regrowth two ways: 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; resolves spec Testing-item 0 + planner self-review item 6 at once) + wrap-robust advisory Sweep 5 in `bench/architect_sweeps.sh` (contiguous-fragment regex, since DESIGN.md is hard-wrapped ~70col) with full sweep-count lockstep (header + "All four"→"All five" tail + `ailang-architect.md` "four"→"five sweeps") + a new `ailang-architect.md` "DESIGN.md honesty drift" bullet citing the meta-subsection. Protected-exception KEEPs preserved + pinned-present (Diverge-reserved, regions-considered-and-rejected, the self-labelled "tiebreaker, not a rationale"); `form_a.md` correctly left untouched/unpinned. One plan-internal DONE_WITH_CONCERNS (Task-1 pin string omitted a `**…**` bold the Task-3 body added; resolved by dropping the non-load-bearing emphasis, pin is the contract) — planner self-review-item-3 calibration note. Independent Boss verification: pin 4/4 GREEN, full `cargo test --workspace` 0 failures (delta = +4 pin tests only), sentinel trio (`design_schema_drift`/`spec_drift`/`schema_coverage`) green, `cargo build --workspace` clean, scope = ONLY THE PIN in `crates/` (zero language/checker/codegen/runtime change, `ail check`/`run`/`build` byte-unchanged by construction). Post-iter sweep residue = only the 3 documented deliberate KEEPs (Sweep-1 L50 doc-roles-pointer date + L2060 true `(iter str-concat)` provenance; Sweep-5 L62 self-referential discriminator-catalogue), EXIT=1 architect-adjudicated-expected. Milestone-close `audit` is the next pipeline step (no fieldtest — zero authoring-surface change). spec `docs/specs/2026-05-18-docs-honesty-lint.md` (grounding-check PASS 10/10), plan `docs/plans/docs-honesty-lint.1.md` → 2026-05-18-iter-docs-honesty-lint.1.md
|
||||
- 2026-05-18 — audit docs-honesty-lint (milestone close, CLEAN — carry-on, NO ratify): scope `928e1c0..e50b400`. Architect `clean`: scope claim exact (zero `crates/**/src/**` + `runtime/`; sole crates/ change the additive RED-first-now-GREEN `docs_honesty_pin.rs`; lockstep pairs untouched), all 14 DESIGN.md corrections genuinely present-tense with the 4 protected KEEPs (`Diverge`-reserved/`Regions`-rejected/`tiebreaker`/`No deriving`) un-stripped, agent-def "four→five" lockstep complete, sweep residue exactly the 3 documented deliberate KEEPs. One `[medium]` standing advisory wart — Sweep 5's regex self-matches the discriminator subsection's own forbidden-phrasing catalogue (DESIGN.md L62) forever (architect-flagged; orchestrator-adjudicated → filed as a P3 todo, NOT a fix iteration — not a new failure mode since the script is advisory-with-residue by design). Bench: `compile_check.py` 0/24 + `cross_lang.py` 0/25 EXIT 0 (cross_lang independently reads the same `bench_list_sum` bump path +5.95% within tol); `check.py` EXIT 1, 3 firings (`bench_list_sum.bump_s` +13.42%, `latency.implicit_at_rc.{p99_9,max}_us` +37.65%/+134.70%). Bencher causal exoneration **decisive**: HEAD vs `5bb7211` vs `de66eb7` — all 5 firing bench binaries `cmp`-byte-identical, `ail` sha256 identical at all three commits ⇒ zero causal mechanism; `*.max_us` = tracked-P2 `-n 5` tail-jitter (4th occurrence on a zero-runtime-change milestone, median/p99 rock-steady), `*.bump_s` = tracked-P2 environmental-anchor-staleness (persistent ~+15%, stale 0.046s anchor). **EXONERATED, NO baseline ratify** (Iron Law forbids ratifying noise; spec forecloses a zero-codegen baseline bump). Two pre-existing standing P2 items kept orchestrator-owned, explicitly NOT bundled into this close (bencher recommendation honoured). Milestone audit **CLEAN**; no fieldtest (zero authoring-surface change — the wrap-robust pin + Sweep 5 ARE the regression coverage). **docs-honesty-lint fully ratified and CLOSED**: spec (grounding-check PASS 10/10) + plan + single iter + audit clean; roadmap P0 flipped `[~]`→`[x]`, WhatsNew.md user-facing entry appended → 2026-05-18-audit-docs-honesty-lint.md
|
||||
- 2026-05-18 — iter embedding-abi-m1.1 (Embedding-ABI M1, DONE across 2 dispatches + a Boss plan Repair): a compiled AILang scalar `fn` is now callable in-process from a C/Rust host. Five pipeline layers shipped: additive `FnDef.export: Option<String>` (serde `default`+`skip_serializing_if`, modelled on `FnDef.doc`, ~85-site compile-driven thread incl. all in-source `#[cfg(test)]`/drift/hash literals, hash-stable golden `b4662aa70839f60b`); Form-A `(export "<sym>")` modifier (parse/print/`form_a.md` lockstep, byte-identical round-trip); check-side scalar-only+effect-free export gate — two new `CheckError` Error variants `export-non-scalar-signature`/`export-has-effects`, params→ret→effects first-violation-wins, unconditional on `f.export.is_some()` (the feature-acceptance clause-3 discriminator *in code*); codegen `Target::StaticLib` (suppresses `@main`+`MissingEntryMain`, emits one external `@<sym>` forwarder per export to `@ail_<module>_<fn>`); CLI `ail build --emit=staticlib` (`build_staticlib`: `libembed_backtest_step.a` program-only + separate `libailang_rt.a`). Coherent stop PROVEN: `embed_e2e.rs` `cc`-links both archives, `backtest_step(0,3)=9`/`(9,4)=25`, `s==25`, exit 0. Task 1 (fixed-first CLI `MissingEntryMain` baseline pin) green before any staticlib code. Process: Task 4 BLOCKED on the first dispatch — a Boss plan-defect (gate/headline fixtures declared `module ≠ file-stem`; the loader hard-enforces `module==stem` at `workspace.rs:438`, so `ail check` panicked on load before the gate). Boss verified, chose **Option 2 over the orchestrator-recommended Option 1** (keep descriptive `embed_*` filenames, rename fixture *modules* to their stems — the C symbol `backtest_step` stays via `(export …)`, *demonstrating* spec Decision 2's mangling-decoupling rather than violating it; archive→`libembed_backtest_step.a`, internal→`@ail_embed_backtest_step_step`, `host.c` unchanged), Repaired the plan (Design-decision 6 + Task-4 module==stem + Task-5/6/7 dependent strings + folded the no-`*.`-Float-head and `content_hash_fn`→`def_hash` concerns), committed Tasks 1–3 as a verified known-good partial (`818177d`), re-dispatched [4,7]. Independent Boss verification post-completion: E2E 1/1, gate 6/6, lowering 2/2, CLI 2/2, full `cargo test --workspace` 0 failures, `roundtrip_cli`+`design_schema_drift`+`spec_drift` green, Invariant 1 holds (no new dep in `ailang-core`/`ailang-codegen`/`runtime`). 3 behaviour-neutral plan pseudo-vs-reality concerns recorded (`emit_ir` routes via `lower_workspace`; dead `Path` import dropped; `##` vs `###` heading). Bench: `compile_check.py`/`cross_lang.py` exit 0; `check.py` exit 1 = tracked-P2 `*.bump_s`/`*.max_us` known-noise (default-exe codegen/runtime byte-unchanged — audit-adjudicated, not a plan gate). spec `docs/specs/2026-05-18-embedding-abi-m1.md` (grounding-check PASS) → plan `docs/plans/embedding-abi-m1.1.md` (Repaired) → commits `818177d` (partial 1–3) + this completion. Milestone-close `audit` then `fieldtest` (surface-touching — `(export …)` is new authoring surface) are the next pipeline steps. → 2026-05-18-iter-embedding-abi-m1.1.md
|
||||
|
||||
Reference in New Issue
Block a user