Commit Graph

16 Commits

Author SHA1 Message Date
Brummel 682b935ba3 experiment(cma): annotated-paren format helps Qwen — cracks the bracket wall (refs #68)
Tests the user's hypothesis: if no human reads the surface, lift the paren-
counting burden. Format 4 = annotated parens, every paren carries its nesting
depth. Discipline: the format has no ail parser, so the converter is round-trip
verified (parse-identity on known-good demos) before judging any model output.

Result: it helps. Plain Form-A 6/8 -> format 4 7/8 on the same ablation ladder.
The depth annotation cracks the bracket-balance wall that broke L4. At the
hardest level (L7 SMA) Qwen produced perfectly balanced brackets through the
deepest nesting AND correct SMA logic; the only remaining issue was a construct
quirk (it treats seq as variadic, but AILang seq is binary). Proof the blocks
were right: Qwen's exact logic with a manual binary-seq fix runs and emits the
exact expected SMA output.

Pushing further (format 4 + explicit seq-binary hint) fixed the seq nesting but
L7 still failed on two MODEL-behaviour limits, not encoding: it simplified the
logic, and fell into a closing-token repetition tail (hundreds of #0) ). The
tail is paren-driven, so the natural next test is a bracket-free format
(indent / keyword-delimited) with no closing token to loop on — a deliberate
next step needing its own verified converter. Synthesis in format-findings.md.
2026-06-02 18:30:24 +02:00
Brummel da99ebaba8 experiment(cma): ablation finds WHY Qwen fails at Form-A — two distinct walls (refs #68)
Try-and-error ablation, minimal few-shot context, single shot per level, a
ladder L0 (fn returns 42) to L7 (full SMA). Two ladders: base few-shot that
only destructures, then one that also constructs (term-ctor).

Finding: Qwen is NOT generally incapable. With minimal correct context it
writes 6/8 tasks green, including ADTs, match, recursive fns, and Series use.
The failures are two specific walls:

- Wall 1 (cheap): unfamiliar constructs. It built lists with (app Cons ...) —
  calling the ctor like a function — because it had only seen match, never
  term-ctor. Adding ONE term-ctor example flipped L3 and L5 to green and
  removed the Cons error. The model generalises a construct from one example.

- Wall 2 (hard): paren/nesting discipline at depth. The two that stay red
  (L4, L7) fail purely on bracketing, not knowledge. In L4 the recursive
  function is flawless; main closes a 4x-nested term-ctor value one paren
  early so the let body slides inside it — total paren count is BALANCED
  (43/43), the parens are just misplaced. Green/red tracks nesting depth, not
  feature. Examples do not fix it. This is the same weakness the full-SMA
  probes hit (run 2 had correct logic, died on brackets; run 3's long context
  tipped it into a seq-repetition loop).

Takeaway: the bottleneck is the fully-parenthesised surface at depth, not the
semantics. Natural next test: the .ail.json authoring form, which removes
human paren-counting. Driver qwen_ablation.py; ladders in qwen-ablation-min.md
and qwen-ablation-ctor.md; synthesis in qwen-ablation.md.
2026-06-02 18:09:31 +02:00
Brummel 8b7e683cc9 experiment(cma): SMA probe run 3 — full grammar+spec+lib makes Qwen degenerate (refs #68)
Third run of the SMA authoring probe, this time with Qwen fully equipped: a
distilled complete Form-A construct grammar (with explicit arity/paren rules),
the mini-spec, and the verbatim Series library source. Hypothesis: the formal
grammar clears the bracket failures of runs 1-2. It did the opposite.

With ~80k prompt tokens the model degenerated into an identical pathological
(seq (seq (seq ...))) tower every turn (321 open parens vs 10 close,
byte-identical across all 6 turns, indentation exploding). Doubling max_tokens
to confirm it was not mere truncation produced HTTP 413 (request too large) —
more budget yields an even larger degenerate output, confirming degeneration.

Verdict (n=1 model): Qwen3-Coder-Next wrote no working SMA in any of three
configurations; more reference material made it WORSE, not better (the lean
run 2 got the algorithm right, the fully-equipped run 3 looped); it never
converged from ail-check feedback in any run; all failures are Form-A
bracket-shape errors, never semantics. Driver + raw logs updated.
2026-06-02 17:49:23 +02:00
Brummel 577bb6be43 experiment(cma): SMA authoring probe against Qwen3-Coder-Next (refs #68)
Probe whether a foreign model can write the Series SMA worked example in
AILang Form-A from the mini-spec + Series API alone. Two live runs, neither
reached green, but a clean progression:

- Run 1 (stock API doc): 6 byte-identical turns, blocked on (app new ...) —
  Qwen treats the  term head as an ordinary function.
- Run 2 (new clarified as a term head): clears that; ownership threading
  comes out idiomatically right (nested let s = Series.push s v), but
  S-expression bracketing breaks (push sees 4 args, not 2).

Cross-cutting: Qwen clears a hurdle only with per-quirk guidance and never
converges from the ail check diagnostic (same failure repeated all 6 turns
in both runs); the failures are Form-A bracket-shape errors, not semantic.
n=1 model, single session. Driver: sma_probe.py; raw logs sma-probe-run{1,2}.md.
Live IONOS run, with consent.
2026-06-02 17:31:35 +02:00
Brummel 29625e7262 feat(cma): revive cross-model harness corpus to current language (refs #68)
The cma authoring-form harness corpus had gone dead against the language
as it evolved since May. The plan modelled it as merely schema-dead
(missing param_modes/ret_mode); it was also drift-dead in the example
BODIES. Fixed in place, with `ail check` + both test suites as the oracle:

- Schema: param_modes/ret_mode completed on every fn type; existing
  borrow annotations preserved (data_with_match's borrow over List).
- Symbol drift: `<`/`==` -> `lt`/`eq` (operator-routing); the removed
  `io/print_int` op -> print_str(int_to_str n) followed by a newline
  print, preserving the trailing newline the references' expected_stdout
  needs.
- Ownership/ADT restructures: data_simple's reuse-as now wraps the
  source in a match arm (ctor must be statically visible);
  data_with_match's count_via_letrec + local go switched borrow->own
  (consume-while-borrowed under the tightened ownership analysis;
  head_or_zero still exercises borrow over the boxed List).
- param_modes_all rewritten to own (Int) + borrow over a boxed ADT --
  (borrow Int) is now a borrow-over-value error.
- Two new author-facing examples (loop_sum: Loop/Recur; new_rawbuf: New)
  cover the Term variants that landed since May.
- spec_completeness.rs: drop the deleted ParamMode::Implicit; cover
  Loop/Recur/New; allowlist the non-authorable Term::Intrinsic out.
- spec.md section 4 rewritten to own/borrow (mandatory, no implicit)
  with the borrow-over-value rule; rendered/ regenerated.
- mock_full_run fixture's t3 turn-2 program migrated so the harness
  score assertions hold; usage fields untouched.

Both render/ and harness/ cargo test suites green in mock mode; no live
IONOS call. Run the harness budget/reference tests with AIL_BIN pointing
at target/debug/ail (ail is not on PATH in the test env).
2026-06-02 17:08:30 +02:00
Brummel 832375f2ac convention: counter-prefix file naming across docs/specs/, docs/plans/, design/contracts/, design/models/
All 176 files in the four accumulating directories now use a
zero-padded 4-digit counter prefix that reflects creation order
(`NNNN-slug.md`). The counter is assigned per directory in strict
git-log creation order; ties broken alphabetically by original name.
The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is
dropped — the date is recoverable from git log and the counter
carries the ordering.

A file's counter is stable for the life of the file: never reassigned,
never reused, never compacted. Deleted files retire their counter;
subsequent files do not fill the gap. This is the property that lets
cross-references stay literal — refs use the full filename including
the counter (`design/contracts/0007-honesty-rule.md`) so they grep
cleanly and resolve directly without a glob step.

313 cross-references updated across .md/.rs/.toml/.c/.json files
(test pins, include_str! paths, design-INDEX entries, baseline notes,
runtime C comments, inter-contract markdown links incl. bare basename
and `../models/foo.md` forms).

CLAUDE.md gets a new "File-naming convention" section spelling out
the rule and rationale. skills/brainstorm/SKILL.md and
skills/planner/SKILL.md updated so new spec/plan creation produces
counter-prefixed names from the start.

The full test suite (cargo test --workspace) passes.
2026-05-28 13:31:31 +02:00
Brummel 4fc65ccb99 iter schema-camelcase-fix.1 (DONE 4/4): paramTypes/retType → param-types/ret-type — closes #30
`Term::Lam`'s two camelCase JSON tags become kebab-case, matching
the convention every other compound-key tag in the AST schema
already follows. After this iter the canonical JSON has zero
camelCase outliers.

## Schema swap (atomic, Task 2)

- `crates/ailang-core/src/ast.rs:492,494` — two
  `#[serde(rename)]` strings: `"paramTypes" → "param-types"`,
  `"retType" → "ret-type"`. Rust field names unchanged.
- `crates/ailang-core/src/workspace.rs:1925-1926` — in-source
  JSON literal in the `ct1_validator_walks_lam_embedded_types`
  test.
- `design/contracts/data-model.md:142-147` — fenced JSON block
  in the canonical data-model contract. Honesty-Rule touch-point:
  the contract document must describe the actual present-state
  schema.
- `examples/test_loop_binder_captured_by_lambda.ail.json` and
  `experiments/2026-05-12-cross-model-authoring/master/examples/fn_with_lambda.ail.json`
  — the two `.ail.json` fixtures whose canonical-JSON embeds
  the renamed tags.

The five files moved together within one task because `Term::Lam`
has no `#[serde(default)]` on `param_tys` / `ret_ty` — a
renamed-away key is a hard deserialise error. Splitting the swap
would have left the workspace untestable mid-step.

## RED → GREEN pin (Tasks 1, 2)

`crates/ailang-core/tests/design_schema_drift.rs` gains
`lam_serialises_with_kebab_keys`: pins that `serde_json::to_value(&Term::Lam{...})`
emits `"param-types"` / `"ret-type"` AND does not emit the old
camelCase keys. Companion: the existing
`design_md_anchors_every_term_variant` test now also asserts the
kebab anchors appear inside `data-model.md`'s `lam` fenced block.
Both confirmed RED on entry, GREEN after Task 2.

## Rustdoc honesty pass (Task 3)

Three pure-prose edits keep production rustdoc consistent with
the new schema vocabulary: `crates/ailang-core/src/ast.rs:8` (the
module-level rename enumeration), `crates/ailang-surface/src/parse.rs:81`
(prose mention of `lam`'s carry), `crates/ailang-check/src/lib.rs:1707`
(InstanceMethod routing helper rustdoc). No compile or test
consequence — Honesty-Rule maintenance.

## Plan-pseudo-vs-reality finding: under-audited hash blast radius

The brainstorm spec audited `crates/ailang-core/tests/hash_pin.rs`
exhaustively (5 pinned modules, zero `(lam ...)` occurrences,
"no hash refresh required"). It missed
`crates/ailang-surface/tests/prelude_module_hash_pin.rs` — a
separate hash-pin file in a different crate that pins `prelude.ail`,
which contains 11 `(lam ...)` forms. The prelude module hash
drifted (`6d0577ff0d4e50ac` → `562a03fc57e7e017`); the implementer
refreshed it with a Honesty-Rule provenance comment matching the
precedent set in commit `26fb345`. Form-A is unchanged — only the
canonical-JSON byte stream differs, which is exactly what the
rename targets. The spec-side learning is: schema-rename
brainstorms must walk *every* test crate for hash-pin files, not
just the home crate of the AST.

## Why this shape, and not the alternatives

- *`params-ty` / `ret-ty` (Rust-field-name vibe)* — rejected. The
  AST JSON schema follows its own kebab/single-word convention,
  not Rust field names. The other multi-word tag (`reuse-as`) is
  kebab; abbreviating `params-ty` mixes singular+plural and has
  no precedent.
- *Inline typed params as a sub-tag* (e.g. `params: [{name, type}, ...]`)
  — rejected. Stronger semantic locality, but it changes schema
  topology rather than tag spelling. Out of scope for a camelCase
  correction; would have re-pinned far more than this milestone.
- *Bundle with #27 (arith-rename)* — rejected. #27 carries four
  open brainstorm questions (mod vs rem, neg vs sub 0, Num class,
  deprecation window) and is structurally a separate milestone.
  Each gets one re-pin wave with its own rationale; no churn
  saving from bundling.

## Honest call on the feature-acceptance gate

Clause 1 (LLM author naturally uses the new form) is the weakest
of the three. Direct empirical evidence is absent — the 2026-05-21
naming-A/B run measured a different axis. The argument is
indirect: a future LLM author generalises from the rest of the
schema ("compound keys are kebab"), and the two camelCase
outliers are precisely the sites where that generalisation
diverged from reality. Clause 2 (redundancy reduction) and
Clause 3 (no semantic surface touched) are direct.

## Forbidden touches verified untouched

`docs/plans/*.md` historic plans (which embed old tag names in
example JSON), `experiments/2026-05-12-cross-model-authoring/master/spec.md`,
`experiments/.../rendered/*.md`, and `experiments/.../runs/**` —
all left as frozen historical artefacts per Honesty-Rule
analogue (describe state at time of writing, not present state).
Verified via `git diff --name-only HEAD` (Task 4 Step 4).

## Verification

- `cargo test --workspace`: all test groups OK, 0 failed,
  2 ignored (pre-existing).
- `cargo test -p ailang-surface --test round_trip`: GREEN
  (Form-A unchanged invariant).
- New schema-shape pin and the extended data-model anchor walk:
  GREEN after Task 2.
- Negative grep across `crates/`, `examples/`, `design/`,
  `runtime/`: the only remaining `paramTypes` / `retType`
  occurrences in checked-in code are the load-bearing
  negative-assertion strings inside the new pin (intentional —
  they are what makes the pin RED-able on regression).
- Stats: `bench/orchestrator-stats/2026-05-21-iter-schema-camelcase-fix.json`
  — 4/4 tasks DONE, no re-loops, no review-loops.

closes #30
2026-05-21 12:57:06 +02:00
Brummel b85d498d03 doc: fix Form-A ctor drift in cross-model-authoring spec — closes #28
The master spec at experiments/2026-05-12-cross-model-authoring/
master/spec.md taught two wrong Form-A keywords:

- Term position: `(ctor TYPE-NAME CTOR-NAME ARG*)` — parser
  rejects this; the canonical keyword is `term-ctor`. The bare
  `(ctor ...)` is reserved for the inside of `(data ...)`
  definitions only.
- Pattern position: `(ctor CTOR-NAME SUBPAT*)` — the canonical
  pattern keyword is `pat-ctor`.

The JSON section was already correct (canonical schema tag IS
"t": "ctor", per ast.rs:471). Only the AIL section had drifted.

Empirically caught by the Qwen3-Coder naming-A/B run on 2026-05-21
(experiments/2026-05-21-naming-ab/runs/r1/), where every
t4_count_zeros output produced `(ctor List Nil)` in term position
and failed `ail check` 100 % across all three cohorts — a
constant tax independent of the naming variable under test.

Re-rendered rendered/ail.md from the patched master via
xmodel-render. rendered/json.md unaffected.

closes #28
2026-05-21 11:54:48 +02:00
Brummel 5bd148a607 fieldtest: naming A/B against Qwen3-Coder — refactor not justified
Three-cohort harness against IONOS-hosted Qwen3-Coder-Next, testing
whether application-head tag (`app` vs `apply` vs `call`) affects
LLM authoring success. Cohorts share lambda/constructor/typecon tag
renamings (the non-discriminator changes); only the head differs.

Result: 100 % cohort-treue — Qwen writes whatever the spec teaches,
no measurable natural preference. Pipeline pass-rate (classic 1/8,
apply 0/8, call 1/8) is cohort-independent. The four task failures
are general Form-A friction, not naming-related. Refactor not
justified per the feature-acceptance gate.

Tracked harness:
- 2026-05-12-cross-model-authoring/rename-spec.py — regex tag
  rewriter for the two non-classic spec variants
- 2026-05-21-naming-ab/run.py, reprocess.py — three-cohort runner
  + post-processing with disjoint-discriminator counting and
  module-name-matched temp dirs

Generated artefacts (runs/, rendered/ail-{renamed,call}.md) are
gitignored — regeneratable from rename-spec.py + run.py.

Side-effects filed against current spec/schema bugs surfaced during
the run:
- refs #28  spec teaches (ctor X) for term position; parser requires
            (term-ctor X) — 100 % t4 failure across cohorts
- refs #29  io/print_str appends newline (de facto println);
            spec now documents the behavior, code question still open
- refs #30  schema camelCase outlier: paramTypes/retType in Term::Lam

Spec patch in rendered/ail.md:
- replaces stale io/print_int references with io/print_str (bitrot
  from the print-builtin consolidation)
- documents io/print_str's trailing-newline behavior
- corrects the prelude claim about int_to_str (IS in prelude)
2026-05-21 11:49:04 +02:00
Brummel 72e54f4fd3 iter ext-rename: .ailx → .ail across the live toolchain
The surface-form file extension changes from .ailx to .ail. AILang's
authoring surface now uses the same .ail stem as its canonical JSON
form (.ail.json), giving the language a single coherent extension
family: .ail is the LLM-authored Form A, .ail.json is the canonical
JSON-AST Form B.

Scope (touched):
- 61 example renames examples/**/*.ailx → .ail (git mv)
- 1 rename experiments/.../rendered/ailx.md → ail.md
- 35 content-edited live-toolchain files (crates/, docs/DESIGN.md,
  docs/roadmap.md, docs/PROSE_ROUNDTRIP.md, skills/, bench/reference/*.c,
  experiment crates under experiments/.../{render,harness,master})
- Experiment-crate cohort rename Cohort::Ailx → Cohort::Ail,
  Form::Ailx → Form::Ail, per_cohort/ailx → per_cohort/ail,
  {form-only: ailx} → {form-only: ail}, ```ailx → ```ail

Out of scope (deliberately untouched, to preserve honest history):
- docs/journal-archive.md (content-frozen per CLAUDE.md)
- docs/journals/, docs/specs/, docs/plans/, bench/orchestrator-stats/
- experiments/.../runs/ (frozen LLM-output artefacts; models actually
  saw .ailx — renaming would falsify the experimental record)

Verification: cargo build/test --workspace green; experiment crate
cargo test green; bench/check.py + compile_check.py + cross_lang.py
all 0-regressed; negative grep for ailx|Ailx|AILX outside the
out-of-scope paths returns zero matches.

Opens immediate follow-up: roadmap.md P2 todo `ail check`/build/run
accept .ail extension — after this rename, .ail is canonical
authoring surface but the CLI still produces a misleading JSON-parse
error on `ail check foo.ail`. That's the next iter.
2026-05-12 14:20:27 +02:00
Brummel 65a4f0aa16 iter ms.2: Qwen retroactive re-run + first CodeLlama-13b-Instruct run + DESIGN.md §Decision-6 addendum extended to two subjects
Two live IONOS harness invocations with the ms.1 fix in place:

  - Qwen/Qwen3-Coder-Next   → runs/2026-05-12-080864/  (RUN_STATUS=ok)
  - meta-llama/CodeLlama-13b-Instruct-hf
                            → runs/2026-05-12-9197fd/  (RUN_STATUS=ok;
                              2/8 JSON cells terminated as api_failure
                              on turn 1 zero-token — transient IONOS
                              terminal error, disclosed in addendum)

Per-cell results (reached/4, prompt tokens, completion tokens):

  Qwen      JSON     1/4   182,378   14,972
  Qwen      AILX     1/4   110,575    3,474
  CodeLlama JSON     0/4   116,015    2,711   [2 cells api_failure]
  CodeLlama AILX     2/4    93,017    2,234

Both subjects agree on direction: AILX cohort cheaper on prompt
tokens (Qwen 61%, CodeLlama 80% of JSON-cohort spend) and on
completion tokens (Qwen 23%, CodeLlama 82%); AILX reached-green
≥ JSON reached-green for each subject. Three of four
first-attempt-green cells across the two subjects are AILX.
Failure classes split symmetric to form: JSON cohorts fail at
typecheck, AILX cohorts at parse — each form's
front-of-pipeline check.

DESIGN.md §"Decision 6 / Empirical addendum (2026-05-12)"
replaced: 2-column single-subject view → 4-column two-subject
view, framing paragraph reports direction agreement and the
api_failure / Qwen-rerun-noise anomalies, scope paragraph
updated to 'two subjects, n=1 each, deterministic; not a
verdict — a universal claim would need ≥3 subjects with
statistical robustness'.

Roadmap P3 'Multi-subject expansion' entry removed; scoped
goal met for two subjects.

Milestone token spend: prompt 501,985 + completion 23,391
= 525,376.
2026-05-12 13:29:15 +02:00
Brummel 614fd8bc93 iter ms.1: pipeline.rs format!("check: {e}") → {e:#} preserves anyhow Caused-by chain in JSON-cohort feedback
Inline pinning test in pipeline.rs constructs the same chain
shape module_name_from_json produces on serde-parse failure
(leaf wrapped with "parsing JSON in <path>" context) and
asserts both layers survive the formatter. RED→GREEN against
the property, not against production line bytes — for a
two-character fix, extracting a helper just for testability
would be over-engineering.

The strip_locations regex collapses \nCaused by: chains; the
{:#} alternate Display joins with ': ' on one line, so the
collapser is a no-op on the fixed output. AILX cohort
unaffected — only the harness-side anyhow path (module
rename pre-check) was dropping cause information.

Harness suite: 14/14 green (was 13/13 + 1 new pin).
2026-05-12 13:28:48 +02:00
Brummel 94d6963995 audit-cma: close milestone Cross-model authoring-form test
Architect drift_found, both [low]:
- INDEX backfill for commit 90512d5 (brainstorm Step 7.5 SKILL.md
  edit + roadmap P1 todo removed without a paired INDEX mirror).
- README "Total 8 passed" understated the actual 13/13 sweep.

Both fixed inline (mechanical, ≤30 LOC) per CLAUDE.md trivial-edits
carve-out; no implementer dispatch.

Bench: all three scripts exit 0, 0 regressed, 5 unexplained
latency.explicit_at_rc improvements not coupled to milestone work
(no in-workspace crate touched). Baseline left pristine — future
audits will reveal whether the improvements hold.

All 9 spec acceptance criteria green. Milestone closed clean.
2026-05-12 12:20:30 +02:00
Brummel e91e31aadb iter cma.3: live Qwen3-Coder-Next run + DESIGN.md §Decision-6 empirical addendum + milestone close
Milestone "Cross-model authoring-form test" closed. Live IONOS run
against Qwen/Qwen3-Coder-Next executed at temperature=0, max-turns=5,
token-budget=500000. Raw dataset under runs/2026-05-12-df7531/:
RUN_STATUS=ok, scores.csv with 8 rows (4 tasks × 2 cohorts),
summary.md, plus 156 per-turn raw artefacts (request/response/program/
stderr/stdout) preserved for any future analysis.

Headline numbers:
- AILX cohort: 2/4 green, 1/4 first-attempt, ~95k prompt + ~2.6k completion
- JSON cohort: 1/4 green, 0/4 first-attempt, ~192k prompt + ~15k completion
- Only first-attempt success was AILX on t3_main_prints (~5 lines of
  tagged s-expr vs ~23 lines of structured JSON for the JSON cohort's
  turn-1 attempt that needed correction).
- Per spec, single subject + single deterministic run = data point,
  not verdict.

DESIGN.md §"Decision 6: authoring surface" gains an "Empirical
addendum (2026-05-12)" subsection: 6-row metric table, illustrative
t3 contrast, explicit single-subject scope note pointing at the
roadmap follow-up entry for multi-subject expansion.

Roadmap: P2 entry "Cross-model authoring-form test" removed (this
journal is the convention's one-line mirror); P3 entry
"Multi-subject expansion (cross-model authoring-form follow-up)"
added with the run dir named as baseline.

Milestone artefacts span three iters (cma.1 master mini-spec +
renderer; cma.2 harness + tasks + reference solutions; cma.3 this
live run + DESIGN.md addendum + close).
2026-05-12 12:16:32 +02:00
Brummel fe1fb6b4f0 iter cma.2: harness binary + 4 tasks + reference solutions + 4 integration tests
Sibling standalone Cargo crate `harness/` under
experiments/2026-05-12-cross-model-authoring/ (out-of-workspace
idiom carried forward from cma.1 verbatim). Six modules:
strip_locations (regex pass for form-asymmetric location info,
calibrated against five real `ail check`/`ail parse` stderr
captures), pipeline (subprocess wrapper for parse|check|build +
5s-timeout exec; preflight on ail+clang), ionos (blocking reqwest
client + retry policy per spec), mock (canned-response loader),
scoring (CSV + summary.md), tasks (definition struct + loader).
main.rs ties them into the per-(cohort,task) loop with budget
accounting and per-turn artefact recording.

Four MVP tasks land with reference solutions that compile, build,
and execute green through the actual ail+clang pipeline:
t1_add_three (chained `+` + io/print_int), t2_length (polymorphic
List + recursion), t3_main_prints (minimal IO module), t4_count_zeros
(prelude Eq Int + branched if). Reference solutions stay in canonical
AILang form — param_modes is omitted when every parameter is the
Implicit default, consistent with the existing examples/ corpus.

13/13 tests green: 5 lib unit (strip_locations) + 5 integration
(strip_locations against verbatim captured fixtures) + 1
verify_references (drives every reference through the real
ail+clang pipeline) + 1 mock_full_run (full eight-row sweep with
mixed green-on-turn-2 + turn-limit cycles) + 1 budget_abort
(synthetic budget exhaustion with budget_abort rows + run_status).

Two implementer-phase repairs beyond the plan, both small and
surfaced in the iter journal Concerns:
1. pipeline.rs renames the program file to `<module-name>.ail.json`
   between parse and check because `ail check` enforces filename
   stem == module name (compiler contract the plan did not anticipate).
2. main.rs fills synthetic budget_abort rows for tasks the outer
   loop never reached so scores.csv preserves the expected eight-row
   shape on budget exhaustion.

One plan/text mismatch carried over: README "Total 8 passed" reflects
the plan's four-suite count; actual sweep produces 13. Doc-fix
candidate for cma.3.

cma.3 (live IONOS run + DESIGN.md addendum + roadmap edits) remains
out of scope.
2026-05-12 12:06:34 +02:00
Brummel a8c29d130b iter cma.1: master mini-spec + render binary for cross-model authoring experiment
New top-level experiments/2026-05-12-cross-model-authoring/ (out of
root Cargo workspace; nested-crate standalone via empty [workspace]
table per Cargo idiom). The renderer projects one canonical
master/spec.md into two form-specific files (rendered/json.md and
rendered/ailx.md) by walking three directive forms ({form-only:
json}, {form-only: ailx}, {example: <id>}) and emitting per-example
fenced blocks sourced from 13 curated .ail.json fixtures.

Four test gates green (10/10 total):
- splitter_unit (7) — directive parser, malformed inputs panic
- spec_completeness (1) — AST-variant visitor lifted verbatim from
  schema_coverage.rs; 34/34 variants covered by the curated subset
- example_roundtrip (1) — every fixture roundtrips through
  ailang_surface::{print, parse} to identical canonical bytes
- token_balance (1) — form-only block totals balanced to 3.22% under
  tiktoken-rs::cl100k_base (gate is ±5%)

Six of the 34 variants did not have a dedicated fixture topic in the
plan and were absorbed into the closest existing fixture per the
plan's Step 4.14 escape hatch (Let/Clone → fn_calls_prelude; LetRec
→ data_with_match; If → match_literal_pattern; ReuseAs →
data_simple; Const → floats). Surfaced as a journal note, not a
plan revision.

Two ancillary additions vs. plan, both structural Cargo necessities,
spec-compatible: render/Cargo.toml carries an empty [workspace] table
so the nested crate refuses parent-workspace discovery, and
render/.gitignore drops /target + Cargo.lock. Both surfaced inline
in the per-iter journal's Concerns section.

cma.2 (harness) and cma.3 (live IONOS run + DESIGN.md addendum +
journal + roadmap edits) remain out of scope per the spec.
2026-05-12 11:43:10 +02:00