# What's New in AILang

A user-facing changelog. It runs in parallel to the technical
per-iter journals (`docs/journals/`) and is written for the
user-as-reader who did not watch the work happen — no crate names,
no iteration codes, no implementation mechanics.

Each entry corresponds to a done-state notification I sent to the
user when he was away. The text is identical to what arrived on his
phone. New entries are appended at the bottom.

What gets described here is **what changed in the project** — what
is now possible, fixed, or visible. For the internals, see
`docs/journals/INDEX.md` and the per-iter journal files it points at.

---

## 2026-05-11 — implement cycle no longer eats your context

The implement cycle no longer eats your context. From the next time we run it, the whole per-task review loop runs inside a dedicated subagent and sends back a short end-report — typing the chatter into someone else's window, so to speak. Each iter gets its own branch; merging or discarding is your call, and rollbacks become trivial. The 14k-line journal monolith is split into per-iter files with a small index for navigation; the old file is archived. Audit ran clean — no benchmark regressions; a small follow-up sweep fixed four spots where I'd missed stale references to the old layout.

## 2026-05-11 — plan-writing offload + first-run debrief

Plan-writing also offloads its read-heavy phase now — the part where I walk the codebase looking for the right files for a plan. Should feel lighter on the chat side from the next plan onwards. First real test of yesterday's per-task isolation refactor exposed a tool-wiring bug along the way: the Boss-context offload part works (you still see only an end-report at the end), but the per-task fresh-subagent isolation didn't actually fire — all tasks ended up running in one bigger context inside the orchestrator. Diagnosis is queued at the top of the next-up list. A small iter-branch setup wording bug got fixed in the same session. Audit clean, no benchmark regressions.

## 2026-05-11 — implement-cycle correction

Yesterday's note claimed the per-task review loop runs as separate fresh-context phases. That isn't possible — Claude Code does not allow a sub-helper to spawn further sub-helpers, full stop. The project's older "no helper calls another helper" convention turns out to have been a restatement of that platform rule all along, not a local design choice with a documented exception. So the architecture is corrected: the per-task loop still runs offloaded from your chat into one dedicated helper context (the part that does save your chat budget), but the review phases now run as sequential checkpoints inside that helper rather than as separate fresh contexts. The chat-side experience does not change. The fresh-per-phase isolation that the earlier note implied does not exist and never could; honestly scoped now.

## 2026-05-11 — Spec grounding-check

Every design spec now has to pass an independent check before approval. The check reads the spec with no prior context, extracts every claim it makes about how the project already works, and confirms each one against a currently-green test. If even one claim has no test backing it, the spec is discarded and the idea moves to the roadmap until the missing piece ships.

An in-flight design for the eq/ord prelude was retired today because it would have failed this check: a load-bearing claim about how the compiler currently handles polymorphic helpers was never verified, and three implementation attempts on it had stalled. The re-think happens in a separate session once the missing mechanism exists.

## 2026-05-12 — Eq/Ord prelude work back on track

The blocker that stranded yesterday's eq/ord prelude work is fixed. The language now handles polymorphic helper functions that call class methods inside their body — the canonical shape every prelude helper takes — by routing both kinds of specialisation through one unified pass instead of two competing ones. A small fixture (`cmp_max` at three integer values) confirms it end-to-end, and the regression check shows the six existing primitive eq/ord symbols still produce bit-identical output.

Next: the five missing prelude utilities (`ne`, `lt`, `le`, `gt`, `ge`) and their end-to-end tests.

## 2026-05-12 — Eq/Ord prelude finished, milestone closed

The eq/ord prelude milestone is done. `ne`, `lt`, `le`, `gt`, `ge` now ship in the auto-loaded prelude as polymorphic helpers that work on any type with the matching class instance — verified end-to-end at Int, Bool, Str, and at a user-defined type with hand-written instances. The same helpers applied to Float produce a Float-aware error pointing back to the language reference's Float section, instead of the generic "no instance" message.

A couple of latent bugs in the type-checker surfaced while testing the natural shape of these helpers (one in the linearity check, one in the polymorphic-specialiser collector) and got fixed in the same pass. The benchmark suite is clean except one sub-millisecond noise-band metric just over the tolerance line — expected given the prelude grew, ratifiable at the next baseline refresh.

Show + `print`-rewire remains the next prelude piece, gated on heap-string runtime support.

## 2026-05-12 — Milestone-close audit: Eq/Ord prelude ratified

Milestone-close audit done. The compile-time regression that surfaced after the prelude grew was localised: it isn't an optimisation bug, it's the cost of typechecking five more helper functions on every workspace check. Ratified — the new typecheck times are now the baseline. The benchmark suite is back to all-green.

One unrelated grammar stub in the language reference (left over from a doc consolidation two days ago) was caught by the audit drift-review and fixed in the same pass.

Milestone 23 is officially closed. Queue is back to user-direction.

## 2026-05-12 — Roundtrip safety net for the two program forms

AILang now ships with a continuous safety net that verifies the two program forms (the structured form and the textual form) stay losslessly interchangeable. Three checks run on every build:

- Every example in the corpus round-trips between the two forms with byte-identical canonical output.
- Every language construct is required to have at least one example exercising it; coverage gaps fail the build.
- The command-line render/parse flow preserves canonical bytes end-to-end, verified by a hash check.

All three pass first time on the current corpus — the two forms are exactly equipotent today, no expressive-power gap between them. This is the prerequisite for the cross-model authoring test that was deferred earlier; the language can now go into that test on solid ground.

## 2026-05-12 — Roundtrip-invariant milestone closed

The roundtrip-safety-net milestone is done. The two program forms — the structured one and the textual one — are now anchored as a named, prominent invariant in the language reference, with five continuous checks enforcing it on every build: byte-identical round-trip in either direction, every language construct exercised by at least one example, and the CLI render/parse flow verified by hash identity. Float literals (NaN, infinities, subnormals) round-trip exactly through the bits-hex encoding — inside the invariant, not an exception.

No language behaviour changed; the corpus already satisfied the property. The milestone made it explicit and locked in against future drift.

Bench all-green. Roadmap is back to user-direction; the Show+print rewire is gated on the heap-string runtime work.

## 2026-05-12 — Cross-model authoring test: first data point

Cross-model authoring test landed. First run (Qwen3-Coder-Next, 4 tasks, two blind cohorts): textual-form cohort 2/4 green at ~half the token cost; structured-form 1/4. Only first-attempt success was textual-form on a print-two-integers task — five lines vs twenty-three. Recorded as a data point in the language reference; single-model scope explicit. Multi-subject expansion queued as next experimental milestone. Milestone closed; queue back to user-direction.

## 2026-05-12 — Cross-model authoring test: second subject added

Cross-model authoring test now has a second subject. Ran CodeLlama alongside Qwen on the same four tasks, fresh runs both. Both models point the same way: textual form is cheaper than structured form on tokens (61–80% of structured form's cost across the two models) and reaches working code at least as often (Qwen ties on this run; CodeLlama strictly dominates 2/4 vs 0/4). Three of four first-attempt successes across the two models are textual. A feedback-asymmetry bug surfaced during planning — the structured form was silently losing its underlying parse error on the way back to the model — and got fixed in the same milestone, so both subjects ran with the fix in place. Not a universal verdict yet (would need three or more models with repetitions), but the second data point points the same way as the first. Milestone closed; queue back to user-direction.

## 2026-05-12 — Strings produced at runtime now release cleanly

`int_to_str`, `float_to_str`, and similar built-in primitives that produce a freshly allocated string at runtime now participate in reference counting like every other heap value. A string passed into a print call is now treated as borrowed, not consumed, so it is freed exactly once when it leaves scope. Earlier programs that converted a number to a string and printed it leaked the string buffer at program exit; that no longer happens.

A side effect: a function parameter declared `(own T)` whose only in-body use was passing it into a print call will now correctly be flagged as over-strict — that annotation should be relaxed to `(borrow T)` (or removed). No current example programs are affected.

## 2026-05-12 — Same-named types across modules no longer collide

Two modules in one workspace can each declare a type with the same bare name (for example, both declaring `type Foo`) and carry their own type-class instances — both now register under their owning modules and stay distinct. Before this round, one declaration silently overwrote the other in an internal index and the loser's instance tripped a misleading "duplicate instance" error.

Internal housekeeping in the same round: a structurally unreachable validation path was removed, and a previously implicit design decision about the type checker's overlay structure was written down.

## 2026-05-13 — Two libraries can each declare their own type class

A workspace can now have two libraries each declaring `class Show` (or `class Eq`, `class Ord`, …) with their own method, and both can ship instances for overlapping types. Before this round, the loader rejected the workspace the moment two classes anywhere declared the same method name. A workspace-global ban that was never load-bearing for correctness — just a workaround making bare method calls unambiguous.

The replacement is type-driven dispatch at the call site. When `show 42` is reached and only one class in scope declares `show`, the call resolves automatically. When two do, the checker first narrows by the argument's type (only one class might have an instance for `Int`); if that still leaves more than one, it reports the ambiguity with the candidate class names and asks the author to disambiguate via `<module>.<Class>.show 42`. A class method that happens to share a name with a free function is handled the same way: the free function wins by the existing precedence rule, but the author gets a warning so an accidental shadow doesn't pass silently.

This unblocks the deferred prelude rewire — the prelude is free to ship its own `class Show` now that it no longer collides with the 14 test fixtures that historically declared a user-class named `Show`.

The new dispatch model is now anchored in the language reference as a named subsection; the related class-reference fields (`InstanceDef.class`, `Constraint.class`, `SuperclassRef.class`) follow the same bare-for-same-module / `<module>.<Class>`-for-cross-module rule that type names already follow.

Bench all-green; the noise envelope on a tail-latency metric continues for the sixth consecutive audit and remains baseline-pristine pending a clear signal-vs-variance call.

Queue back to user-direction: the prelude-rewire milestone is ready for a fresh design pass against the new dispatch model.

## 2026-05-13 — Show and print

AILang now ships `show` and `print` in the prelude. `show x` produces a Str representation for Int, Bool, Str, and Float (Float is included because textual representation is well-defined modulo libc's NaN spelling, whereas Eq/Ord deliberately exclude Float). `print x` is a polymorphic helper that formats x via show and writes to stdout — it works on any type Show has been declared for, including user-defined ones via `instance Show MyType`.

Calling print on a type without a Show instance is rejected at typecheck with a Show-aware diagnostic pointing at the prelude documentation.

The per-type `io/print_int`, `io/print_bool`, `io/print_float` operators stay for now; new code is expected to use `print`. A future milestone migrates the existing example corpus.

Bench continues on the same noise envelope observed across the last ten audits — baseline pristine.

Queue back to user-direction: the next roadmap item is that corpus migration, which retires the per-type print operators.

## 2026-05-13 — Form A is now the authoring surface

`.ail` is now the form you read, edit, and check in. The JSON-AST counterpart is still the canonical hashable representation, but it is no longer something you look at or maintain by hand — the tools derive it from `.ail` whenever they need it. About a hundred example programs that previously existed as JSON-AST were converted to `.ail` and the JSON files were deleted; only eight stay as `.ail.json` (seven negative-test fixtures whose subject matter cannot be expressed in `.ail`, plus the prelude, which is loaded at compile time and depends on internal plumbing that lands in a later milestone).

If you were used to opening a `.ail.json` file to see what a program looks like, you now open the `.ail` sibling instead.

## 2026-05-13 — Three follow-ups from the Form-A field test

Post-fieldtest follow-up complete; three iterations landed back-to-back.

- `ail check` now catches unbound variables inside instance method bodies. Before this, the typecheck step silently passed the program and the error only surfaced at build time as a degraded internal-error diagnostic with no source location or symbol hint.

- The Form-A authoring spec now documents the typeclass surface — class declarations, instance declarations, and constraints on polymorphic functions — so a downstream LLM author can write typeclass programs from the spec alone, without having to mine the example corpus to reverse-engineer the grammar.

- New `str_concat` primitive for combining two strings. The natural Show-MyType body shape (`"Item " ++ int_to_str x`-style labelled output) is now expressible; previously every such instance had to either drop the prefix or punt entirely.

Queue back to user-direction: two next-milestone candidates queued on the roadmap — retiring the per-type `io/print_int|bool|float` operators in favour of polymorphic `print` (about eighty-six fixtures to migrate), or moving the prelude embed to Form-A as compile-time source (resolves the one remaining `.ail.json` carve-out that exists for architectural reasons rather than subject-matter reasons).

## 2026-05-13 — Documentation and drift-test hygiene

Two internal cleanups while you were away. Compiler documentation builds without warnings now — twenty-three stale cross-references between docs and code were repaired. And the test that guards DESIGN.md against drifting out of sync with the schema is now stricter — it scans only the schema section, so an anchor that happens to appear somewhere else in the document can no longer mask a missing entry in the canonical reference.

## 2026-05-14 — Compiler now builds clean under `cargo clippy`

Sixty-one linter warnings across the whole compiler workspace are gone — the project now builds clean under `cargo clippy --workspace --all-targets`. Most were documentation: multi-line comments that the linter misread as bullet lists, and orphan doc-blocks left over from the recent test relocations. A handful were idiomatic refactors (`.expect_err` instead of `.err().expect()`, dropped redundant closures, collapsed nested pattern matches, two manual `Default` impls replaced by `#[derive(Default)]`). Three places kept the original code with an inline `#[allow]` and a one-line reason, where the linter's suggestion would have lost meaning. All tests stay green, the documentation build stays warning-free, and all three benchmark scripts pass at the existing baselines — confirming the sweep touched no semantics.

## 2026-05-14 — Print is now the only way (and two related bug fixes)

The per-type print operators are retired. `print` (polymorphic, ships in the prelude) is now the only way to print a value of a primitive type — the older `print_int` / `print_bool` / `print_float` operators have been removed from the compiler, and every example program in the corpus is migrated. The byte-channel primitive that emits a string directly remains as the one surviving direct-output operation; everything else routes through `print` via the `Show` class.

Two compiler bugs surfaced during the migration and were fixed before the retirement landed. First, calling `print` with a class-method-call expression as its argument (for example `print (eq 1 2)`) crashed during code generation — the compiler was mis-aligned by one slot when resolving the class constraint, and the inner `eq` was being mis-rewritten as a `show` call. The fix straightens the slot accounting at every polymorphic free-function call site. Second, `print` was leaking one heap-allocated string per call under reference-counting mode — the let-binder for the rendered text inside `print`'s body was not being recognised as trackable, so its scope-close drop never fired. The fix annotates the prelude `Show` method correctly and stops a type-rewriting helper from silently stripping mode metadata during substitution.

Plus one CLI polish item that the field test from the last cycle had flagged: `ail check` and eight other subcommands now show the same `[error-code]` prefix in their text output that the JSON mode has always shown — so a failed import, a module cycle, a schema mismatch, all arrive on the human path with the same diagnostic code that scripted consumers were already using. Before this fix the text path used a different formatter that dropped the code; now both paths share one source.

All tests green. Compiler builds clean under both the linter and the documentation builder. Benchmark scripts all pass at the existing baselines.
