Files
AILang/docs/specs/0004-design-md-consolidation.md
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

12 KiB
Raw Permalink Blame History

DESIGN.md Consolidation — Design Spec

Date: 2026-05-10 Status: Approved — proceeding to plan Authors: Brummel (orchestrator) + Claude

Goal

docs/DESIGN.md (today 2262 lines) mixes three time axes: timeless state ("the language has X"), historical narrative ("Iter 18a added Y, Iter 19b refined Y"), and workflow detail ("maintained by the ailang-docwriter agent"). The mix forces every LLM reader (the ailang-architect agent, the brainstorm skill, any future orchestrator) to filter axis-by-axis on every read — work the document should do once, structurally.

This milestone consolidates DESIGN.md to a single time axis — state plus timeless rationale — and routes the other two axes to their existing canonical sources:

Source Content Time axis
docs/DESIGN.md State + timeless why timeless
docs/JOURNAL.md History, migration, REVERTED, iter-decision corrections, queued options chronological
skills/<name>/SKILL.md + agents Workflow, discipline, agent rosters trigger-bound
crates/ailang-core/src/ast.rs Mirrors DESIGN.md §Data-model in code mirrors DESIGN.md

The milestone is documentation-only. No language semantics change. No new compiler features ship. The single new artefact in code is a schema-drift test (design_schema_drift.rs, sweep 3).

Architecture

Role of DESIGN.md (post-consolidation). DESIGN.md describes exclusively what the language is — schema, semantics, invariants, timeless reasoning for why alternatives are excluded. It contains no development history, no iter tags, no status markers, no migration plans, no REVERTED audit trails, no workflow discipline.

Cross-reference asymmetry. References go primarily into DESIGN.md, rarely out of it:

  • JOURNAL → DESIGN: every iter entry may link to the affected section (existing practice).
  • Skills/agents → DESIGN: ailang-architect reads DESIGN as the drift baseline; brainstorm checks Feature-Acceptance against DESIGN.
  • DESIGN → JOURNAL: only at narrowly defined points where a prohibition's calibration is historical and JOURNAL holds the evidence (e.g. "tracing GC: see JOURNAL bench notes" — as a one-line pointer, not as an embedded data point).
  • DESIGN → skills: not direct; DESIGN does not describe how the language is developed.

Schema SoT inversion. Decision 1 says "source = data, not text"; that makes DESIGN.md §Data-model structurally the schema spec. Today's whenever the two disagree, ast.rs is the source of truth disclaimer inverts: ast.rs gains a module-doc-comment pointing to DESIGN.md §Data-model as the canonical source. A new drift test (analogous to crates/ailang-core/tests/spec_drift.rs) enforces structural agreement between the JSON-schema blocks in DESIGN.md and the variants in ast.rs — the test is the mechanism that makes the inversion load-bearing.

Feature-acceptance criterion (transferred). The criterion is calibrated for language features; this milestone adds none. Transferred form: a consolidated DESIGN.md is load-bearing for ailang-architect (drift-review baseline), brainstorm (Feature-Acceptance gate baseline), and any future LLM that needs to understand the state. Mixing history + state forces every reader into filtering work the document should do once. Consolidation improves correctness (fewer drift opportunities between DESIGN/JOURNAL/skills) and removes redundancy (one SoT per axis instead of three overlapping ones). The criterion applies by analogy.

Components — the four thematic sweeps

Four sweeps, each reviewable against a clear search pattern. Order is chosen so each later sweep operates on a quieter base.

Sweep 1 — Remove history anchors

Mechanical pass; no semantic content changes.

  • All iter tags removed (Iter 14b, Iter 18a, Iter 22a, Family 20, since Iter 13a, …).
  • All date anchors removed (Committed 2026-05-08, 2026-05-09 revision flips, Iter 19b — FnDef.suppress).
  • All status markers removed (Status: shipped, Status: half-retirement, as of 2026-05-09).
  • All bench data-point anchors (60% allocate-path overhead, 4.14× rc/bump, 3.31x vs non-inlinable) either removed or condensed to a one-line JOURNAL pointer — the data point is historical; the prohibition it grounds is timeless.

Acceptance: grep -nE 'Iter [0-9]+[a-z]?|Family [0-9]+|2026-[0-9]{2}-[0-9]{2}|Status: ' docs/DESIGN.md returns nothing (or a deliberate exception is recorded in the JOURNAL entry for this iter).

Sweep 2 — REVERTED + migration plans out

  • Decision 7 (Term::If removal) deleted entirely. Term::If exists in the language; the witness is the Term-schema section.
  • Decision 9 → Decision 10 "Migration plan" (7-point list) removed — migration is complete; the end state is described.
  • Decision 11 "Why mono, not virtual dispatch (the empirically-grounded version)" — correction history (The original rationale implicitly argued … 2026-05-10 micro-benchmark refutes …) condensed to a single "mono enables optimisations vdisp forbids" rationale.
  • "future iter may"-speculations condensed: kept only where they carry a binding prohibition (e.g. "future iter that proposes laziness must prove cycle is collectible" — that is a language constraint). Pure aspirations ("a future Prelude milestone may add Show…") removed.
  • Iter-numbered cross-references in surviving prose ("see Iter 18d18g shipping work") replaced with section-anchored links or removed.

Acceptance: grep -n 'REVERTED\|preserved for the audit trail\|Migration plan\|originally framed\|original rationale' docs/DESIGN.md returns nothing.

Sweep 3 — Schema SoT inversion + Data-model hardening

  • From the "Data model" section: all Rust type definitions removed (Type::Fn { params: Vec<Type>, … } etc.) — DESIGN.md specifies JSON schema, not Rust code.
  • The whenever the two disagree, ast.rs is the source of truth disclaimer removed and replaced by a module-doc-comment in ast.rs pointing to DESIGN.md §Data-model.
  • Drift test added: crates/ailang-core/tests/design_schema_drift.rs (analogous to spec_drift.rs) walks exhaustive matches over Term / Pattern / Type / Def / Literal and asserts an anchor for each variant exists in the JSON-schema block in DESIGN.md.
  • A prominent sentence in the Data-model section establishes DESIGN.md as the schema SoT.

Acceptance: cargo test -p ailang-core design_schema_drift green; no Rust type definitions remain in docs/DESIGN.md (grep -E '^\s*(struct|enum|pub )' returns nothing); ast.rs carries the SoT-pointer doc-comment.

Sweep 4 — Workflow / cross-reference cleanup

  • "Project ecosystem" entry agents/ corrected (path is skills/<name>/agents/).
  • "Verification and correctness" section: workflow detail ("Maintained by the ailang-docwriter agent (Iter 13d onward)") removed — the verification contract stays timelessly described; agent assignment belongs to the skills SoT.
  • "What is not (yet) supported": iter anchors removed, "Recently lifted gates" paragraph removed (it is history). Section remains a pure state list.
  • Cross-reference audit: every JOURNAL / skill reference from DESIGN.md examined; only those kept that ground a binding constraint.

Acceptance: every surviving cross-reference has a brief justification (in commit message); no references to now-stale paths.

Data flow — readers of the document

Reader Question DESIGN.md must answer
ailang-architect (audit) "Is the code drifting from the spec?" — DESIGN.md is the baseline.
brainstorm (new milestone) "Does Feature-Acceptance hold? Is there a prohibition that kills this proposal?"
Future LLM (orchestrator successor) "What is the language now? What may I not propose?"
Foreign LLM (zero-shot AILang author) Not directly — that reader uses crates/ailang-core/specs/form_a.md. DESIGN.md is the meta-baseline, not the authoring spec.

The first and third readers are the hardness tests: both are LLMs without a human filter, who need to trust the document without mixing it with JOURNAL or skills inside their context window. If DESIGN.md embeds history, the LLM is forced into filter work the document should not require.

Error handling — drift detection

Three orthogonal mechanisms, each guarding a different drift vector:

  1. design_schema_drift.rs (sweep 3). Closes the ast.rs-vs-DESIGN-schema gap structurally. Every new Term / Pattern / Type / Def variant forces a DESIGN entry, otherwise the build fails.

  2. History-marker check in the audit skill (sweep-1 acceptance promoted to a standing discipline). The ailang-architect agent gains an additional mandatory check: grep -nE 'Iter [0-9]+[a-z]?|Status: |Committed [0-9]{4}-' docs/DESIGN.md must return nothing. The drift report flags any hit as an Iron-Law violation. This is the live-time guard against the "quick, drop an iter tag in DESIGN" reflex.

  3. Discipline note in implement/SKILL.md: a clarification that DESIGN.md edits made during a feature-shipping iter must be phrased timelessly — the iter entry lands in the JOURNAL, the state entry in DESIGN. No new mechanism, but without this clarification the next implementer has two writing targets and no rule for which voice to use, and drift rebuilds.

Testing strategy

Per sweep:

  • Sweep 1, 2, 4: grep-based acceptance against the patterns listed in each sweep. The pattern run on the post-iter file must be empty (or carry an explicit, JOURNAL'd exception).
  • Sweep 3: cargo test -p ailang-core design_schema_drift green. The test is RED-first: the iter starts by adding the test before the schema rewrite, so the GREEN transition is evidence the schema text matches ast.rs.

End-to-end:

  • cargo test --workspace stays green throughout. No language semantics change; if any test breaks, that is a real regression and goes through the debug skill.
  • bench/check.py and bench/compile_check.py stay at 0/0/0 (they don't touch docs, but the milestone-close audit runs them).

No new .ailx fixtures: this milestone has no user-visible surface, so fieldtest is skipped (per skills/README.md: "Standard milestone-close path; skipped only for purely internal milestones").

Acceptance criteria

Per sweep: see four sweeps above.

Across the whole milestone:

  • DESIGN.md has no iter tags, date anchors, status markers (sweep-1 patterns return nothing).
  • DESIGN.md has no REVERTED section (Decision 7 gone), no migration plan.
  • DESIGN.md describes the schema canonically; ast.rs points to DESIGN.md; cargo test design_schema_drift green.
  • ailang-architect agent verifies DESIGN.md hygiene as part of drift review (its iron-law list gains the grep-pattern check).
  • DESIGN.md size as a plausibility check: today 2262 lines — expected post-consolidation 1500-1800 lines, but this is an observation, not a target; an aggressive LOC target would push against substance.
  • One JOURNAL entry per sweep, documenting what was discarded with an anchor example (e.g. "Decision 9 'half-retirement as of 2026-05-09' frame removed; state form: 'RC is canonical, GC is parity oracle, retirement gated on …'").

Negative acceptance (what must not happen):

  • No semantic content of the language is lost (every constraint, every prohibition, every schema form remains; only the historical calibration migrates to JOURNAL).
  • No circular references (DESIGN → JOURNAL → DESIGN for the rationale of a decision; that means the rationale was not formulable timelessly — and forces re-examination).
  • No iter tag slips through (sweep-1 pattern is the sweep acceptance AND the standing drift lint).

Iteration plan (for plan skill)

Four iterations, one per sweep, in the order above. The design_schema_drift.rs test in sweep 3 follows the standard RED-first TDD discipline carried by ailang-implementer. The audit step at milestone close runs the regular audit skill (architect drift review + bench regression suite); the architect's mandatory checks are extended for this milestone with the DESIGN.md-hygiene grep, then that extension is captured in audit/agents/ailang-architect.md so the check survives beyond this milestone.