# iter cma.1 — Master mini-spec + renderer for the cross-model authoring experiment

**Date:** 2026-05-12
**Started from:** fd6efdbc
**Status:** DONE
**Tasks completed:** 9 of 9

## Summary

Stands up the master mini-spec source and the renderer binary under a
new top-level `experiments/2026-05-12-cross-model-authoring/` tree
that lives outside the root Cargo workspace. The renderer projects
one form-agnostic `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 from 13 curated `.ail.json`
fixtures. Four test gates land green: a 7-test splitter unit suite,
a `spec_completeness` test borrowing the AST-variant visitor verbatim
from `crates/ailang-core/tests/schema_coverage.rs` (34/34 variants
observed across the curated subset), an `example_roundtrip` test
mirroring the surface roundtrip contract, and a `token_balance` test
that gates form-only block tokens to ±5% under `tiktoken-rs::cl100k_base`
(final ratio: json=1800, ailx=1742, ratio 3.22%). Two follow-on iters
(cma.2: harness, cma.3: live IONOS run + DESIGN.md addendum) are out
of scope per the spec.

## Per-task notes

- cma.1.1: Bootstrap experiment dir + Cargo skeleton — created
  `experiments/.../{README.md,render/Cargo.toml,render/src/main.rs}`
  plus the four target directories. Spec-pinned dependency paths
  resolve `ailang-core` and `ailang-surface` via relative
  `../../../crates/...` references.
- cma.1.2: Directive splitter (TDD) — 7 unit tests RED first, then
  implementation; added a `[lib]` target so the integration tests
  can reach `xmodel_render::splitter`. GREEN on first impl run.
- cma.1.3: spec_completeness test — visitor + EXPECTED_VARIANTS
  list lifted verbatim from `crates/ailang-core/tests/schema_coverage.rs`;
  only `examples_dir()` body and the test name changed. Confirmed RED
  on the empty master/examples/ directory (failure mode: "no .ail.json
  fixtures found").
- cma.1.4: 13 curated `.ail.json` fixtures (one per file as planned).
  The plan's 13 fixture topics naturally covered 28 of the 34 AST
  variants; the remaining 6 (Def::Const, Term::Let, Term::LetRec,
  Term::If, Term::Clone, Term::ReuseAs) were folded into existing
  fixtures per the plan's Step 4.14 instruction ("Extend the fixture
  closest in scope … do not weaken the test"). Concrete absorptions:
  Let + Clone into `fn_calls_prelude`; LetRec into `data_with_match`
  (as a recursive `count_via_letrec` helper); If into
  `match_literal_pattern` (as a `sign_if` helper); ReuseAs into
  `data_simple` (the `wrap_one` body uses `(reuse-as src ...)`);
  Const into `floats` (a `const pi : Float = 3.14`). All 34 variants
  green on first run.
- cma.1.5: example_roundtrip test — verbatim from plan; all 13
  fixtures roundtrip through `ailang_surface::print` and
  `ailang_surface::parse` to the same canonical bytes on first
  implementation run.
- cma.1.6: master/spec.md — 13 sections of form-agnostic prose with
  parallel JSON/AILX form-only blocks in §2-5, §7, §9, §10 plus the
  prelude table in §11 (no form-only there; the table itself is the
  content). Section §11's prelude tabulation reflects the live
  `crates/ailang-check/src/builtins.rs` symbol set: `+`, `-`, `*`,
  `/`, `%`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `not`, `neg`,
  `int_to_float`, `float_to_int_truncate`, `float_to_str`, `is_nan`,
  `nan`/`inf`/`neg_inf`, `__unreachable__`, plus the effect ops
  `io/print_{int,bool,str,float}`. `int_to_str` is explicitly named
  as OUT (heap-Str ABI milestone).
- cma.1.7: Wire renderer end-to-end — examples.rs and main.rs filled
  in verbatim from the plan. Renderer ran clean on first invocation;
  json.md (33409 bytes) and ailx.md (23964 bytes) emit with the
  expected 13 fenced blocks each (and zero of the wrong fence type).
- cma.1.8: token_balance test — first run reported json=1800,
  ailx=1692, ratio 6.00% (above the 5% threshold). One substantive
  AILX-side extension to §4 (mode annotations) added authoring
  guidance on `over-strict-mode` and hash stability under future
  default shifts; final ratio json=1800, ailx=1742, 3.22%. The
  rebalancing is content, not filler.
- cma.1.9: Final render + full sweep — `cargo test --manifest-path
  experiments/.../render/Cargo.toml` ends with 10 passed; 0 failed
  across four test suites; `git status` shows the entire experiment
  tree as untracked.

## Concerns

- Task 1: Cargo's automatic workspace discovery hits the root
  manifest, so the experiment crate refuses to build on its own. The
  fix is the standard Cargo idiom for a nested-but-out-of-workspace
  crate: add an empty `[workspace]` table to the experiment's
  `Cargo.toml`. The plan did not enumerate this; I added it with a
  comment pointing at the spec authority (§Architecture lines 90-95)
  for the standalone constraint. Boss should confirm this is the
  intended mechanism vs. e.g. adding the experiment to a
  `workspace.exclude` list in the root manifest (the spec is explicit
  that the root Cargo.toml is not touched, which the chosen mechanism
  respects).
- Task 1 ancillary: a `.gitignore` was added under
  `experiments/.../render/` ignoring `/target` and `Cargo.lock`. Not
  enumerated in the plan but a structural necessity to keep cargo's
  build output and lockfile out of the repo. Boss can keep, replace
  with a top-level rule, or move to the root `.gitignore`.

## Known debt

- None surfaced inside the iter. Two named deferrals remain out of
  scope (cma.2 harness, cma.3 live run + DESIGN.md addendum), per
  the spec.

## Files touched

27 new files, all under `experiments/2026-05-12-cross-model-authoring/`:

- `README.md`
- `master/spec.md`
- `master/examples/*.ail.json` × 13
- `render/Cargo.toml`
- `render/.gitignore`
- `render/src/{main,lib,splitter,examples}.rs`
- `render/tests/{splitter_unit,spec_completeness,example_roundtrip,token_balance}.rs`
- `rendered/json.md`
- `rendered/ailx.md`

`git diff --name-only HEAD | wc -l`: 0 (untracked tree; use
`git status --porcelain --untracked-files=all experiments/...` to
enumerate).

## Stats

`bench/orchestrator-stats/2026-05-12-iter-cma.1.json`
