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).
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
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)
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.