design: 20-family tidy-iter — refresh Data model + ecosystem inventory

Architect drift review after Family 20 surfaced four items; (1) and
(2) are doc drift fixed here, (3) and (4) are recorded as acceptable.

DESIGN.md changes:

  - Data model section rewritten from "Data model (MVP)" claiming
    only fn/const exist to "Data model" reflecting all three Def
    kinds. Added the missing schema fields the architect named:
    `tail` flag on app/do, the `seq` / `clone` / `reuse-as` / `letrec`
    terms, `paramModes` / `retMode` on Type::Fn, `suppress` on FnDef,
    `drop-iterative` on TypeDef, `args` on Type::Con, `vars` on
    TypeDef. Each additive field's hash-stable serialisation is
    called out once at the top so individual mentions stay terse.
    `Suppress`, `ParamMode`, `Literal`, `Pattern` get their own
    sub-blocks.
  - Pipeline diagram now shows `--alloc=gc` (links libgc;
    transitional) and `--alloc=rc` (emits ailang_rc_inc / _dec;
    canonical) as two backends sharing the same MIR.
  - Ecosystem inventory gained a "Surface forms" bullet for
    ailang-surface (Iter 14c, lossless Form-A printer/parser) and
    ailang-prose (Family 20, lossy Form-B projection). CLI bullet
    now lists parse, render, prose, merge-prose.

JOURNAL entry records the architect findings, the resolutions for
items (1) and (2), and the acceptable-drift status of (3)
FnDef::synthetic factor-out (defer to next schema-additive
FnDef field) and (4) linearity.rs spurious warning (not
corpus-triggered).

Pure documentation iter — no code changes. 288 workspace tests
unchanged and green.
This commit is contained in:
2026-05-08 23:47:48 +02:00
parent 72626fa94f
commit c79f7e2f00
2 changed files with 288 additions and 31 deletions
+126 -3
View File
@@ -9638,6 +9638,129 @@ that always works without a tool-use-capable client.
### Family / arc state
20f closes the prose-roundtrip arc for now. JOURNAL queue is
empty again. Tidy iter for 20a / b / d / e / f together can wait
until the next family closes — the architect drift-review
discipline applies as before.
empty again. The 20-family tidy-iter follows immediately per
CLAUDE.md ("the tidy-iter is non-optional, every named family
closes with one"); the previous note here ("can wait") was
incorrect and has been superseded by the actual tidy below.
## 2026-05-08 — 20-family tidy-iter (DESIGN.md refresh)
### Why
Per CLAUDE.md, every named iter family closes with a tidy-iter:
run `ailang-architect`, resolve each item (fix the drift, ratify
in DESIGN.md, or record in JOURNAL why it is acceptable). Family
20 — 20a, 20b, 20d, 20e, 20f — added a whole new surface
(`ailang-prose`), a CLI subcommand pair (`ail prose` /
`ail merge-prose`), an embedded Form-A spec, and the drift-test
trip-wire. The architect surfaced four items.
### Architect findings (verbatim, abridged)
1. **`docs/DESIGN.md` "Data model (MVP)" block stale** —
missing: `tail` flag on `app`/`do`, `seq`, `clone`,
`reuse-as`, `let-rec`, `paramModes`/`retMode` on `fn`,
`suppress` on `FnDef`, `drop_iterative` on `TypeDef`,
`Type::Con.args`, `TypeDef.vars`. Pipeline diagram still
said "links libgc" only — did not mention `--alloc=rc`.
The deferral was already noted in 19a-arc tidy.
2. **Project ecosystem inventory missing `ailang-surface` and
`ailang-prose`** — the section's own rule says new tools
are added "as soon as they are established"; both crates
are well past that threshold (14c and 20a respectively).
`ail prose` and `ail merge-prose` were also missing from
the CLI bullet.
3. **`FnDef { suppress: vec![] }` synthesis fan-out at 45
sites** — `ailang-codegen` plus `ailang-core::desugar`
alone has 16. 19a-arc tidy noted 7 and deferred. Each
schema-additive `FnDef` / `Type::Fn` field hits every site;
a `FnDef::synthetic(...)` constructor is the absorbing fix.
4. **`linearity.rs` known debt (L117125)** — deeply-nested
match on a sub-binder produces a spurious
`over-strict-mode` warning. Not fired by current corpus;
module doc records the gap. Acceptable.
### Resolutions
**(1) and (2)** — fixed in this tidy. `docs/DESIGN.md`:
- **Data model section rewritten end-to-end.** Was titled
"Data model (MVP)" with stale `MVP only fn and const`; now
"Data model" reflecting that all three kinds (`fn`, `const`,
`type`) are real surface forms. Added every additive field
documented in `crates/ailang-core/src/ast.rs` with the
schema-additive `skip_serializing_if` rationale called out
once at the top so each individual mention can stay terse.
The `Suppress`, `ParamMode`, `Literal`, and `Pattern`
sub-schemas now have their own blocks.
- **Pipeline diagram extended.** Now shows `--alloc=gc` (links
libgc; transitional) and `--alloc=rc` (emits
`ailang_rc_inc` / `_dec`; canonical) as two backends sharing
the same MIR. The 18a18d additions (`Term::Clone`,
`Term::ReuseAs`) get a sentence pointing at where they
materialise under `--alloc=rc`.
- **Ecosystem inventory** gained a "Surface forms" bullet
between Language core and CLI, naming `ailang-surface`
(Iter 14c) as the lossless Form-A printer/parser fixed by
Decision 6 with `parse ∘ print = id` as gating contract,
and `ailang-prose` (Family 20) as the lossy Form-B
projection with no parser whose re-integration goes through
`docs/PROSE_ROUNDTRIP.md`. The CLI bullet now lists
`parse`, `render`, `prose`, `merge-prose`.
**(3) `FnDef::synthetic(...)` constructor** — *deferred, not
addressed in this tidy.* Reason: the right factor-out shape is
not yet obvious. Most existing call sites differ on more than
just `suppress` — they have to compute `params`, build a
`Type::Fn`, etc. — so a one-arg constructor saves nothing; the
useful constructor is roughly `FnDef::new(name, ty, params,
body)` with `doc: None, suppress: vec![]` defaults. That is a
real change in 45 sites and should land as its own iter when the
schema next grows a `FnDef` field (forcing the touch anyway).
Recorded in the JOURNAL queue.
**(4) `linearity.rs` sub-binder spurious warning** —
*acceptable, recorded.* The warning fires on a synthetic shape
that the current corpus does not produce; module doc names the
gap; an actual customer-impact trigger would warrant a fix, not
preemptive work. Status quo holds.
### Acceptable drift summary
- `FnDef::synthetic(...)` factor-out — deferred until the next
schema-additive `FnDef` field (rationale: existing fan-out
pattern works, change is large but mechanical, and the cost
is amortised by piggybacking on the next forced touch).
- `linearity.rs` deeply-nested-match-on-sub-binder spurious
warning — accepted (not corpus-triggered; cost of fix
exceeds cost of the false positive at this scale).
### What this tidy does NOT do
- No code changes. Pure documentation iter.
- No new tests. Existing 288 workspace tests stay green.
- No DESIGN.md content removed. The pre-tidy "Data model (MVP)"
block is replaced rather than amended because it had grown
factually incorrect; the historical context lives in
`git log` and in the iter-by-iter JOURNAL entries that
introduced each schema field.
### JOURNAL queue (post-tidy)
- **`FnDef::synthetic(...)` factor-out** — to be done when the
next schema-additive `FnDef` field forces the touch anyway.
- **Deferred richer integration paths** (from 20f): tool-use
schemas, MCP server, LSP. All additive over the static-prompt
round-trip; pick when prioritised.
- **Boehm retirement**`--alloc=gc` is transitional;
`--alloc=rc` is canonical. Boehm-side scaffolding to be
removed once the rc backend covers the full corpus.
- **Family 21+** (typeclasses, polymorphic ADTs at runtime,
pattern-binding generalisation) — long-horizon language work.
### Family / arc state
The 20-family is now formally closed with this tidy. Codebase
is in good form: no architecturally load-bearing drift, all
tests green, two minor items recorded as acceptable. The next
iter can be a feature pick from the queue.