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.
This commit is contained in:
2026-05-28 13:31:31 +02:00
parent 7b8596cef0
commit 832375f2ac
227 changed files with 785 additions and 751 deletions
@@ -63,7 +63,7 @@ Bool literals (`true`, `false`) and unit (`(lit-unit)`) are
disambiguated by parser context, not by lex. Comparison and
equality are class methods (`eq` / `compare`) and named fns
(`float_eq` / `float_lt` / etc.), not operators — see
[Prelude classes](../contracts/prelude-classes.md).
[Prelude classes](../contracts/0017-prelude-classes.md).
Every AST node form has a unique head keyword (`module`, `data`,
`fn`, `forall`, `fn-type`, `con`, `var`, `app`, `lam`, `match`,
@@ -144,10 +144,10 @@ params, `<>` for type args). Formalising it crisply is harder than
designing a uniform form from scratch.
The chosen form is (A), shipped as the `ailang-surface` crate (see
[authoring surface](../contracts/authoring-surface.md)); the
[authoring surface](../contracts/0001-authoring-surface.md)); the
canonical JSON-AST it round-trips against is documented in
[Data model](../contracts/data-model.md), and the round-trip
property itself in [Roundtrip Invariant](../contracts/roundtrip-invariant.md).
[Data model](../contracts/0002-data-model.md), and the round-trip
property itself in [Roundtrip Invariant](../contracts/0009-roundtrip-invariant.md).
For the prose projection used for human review (Form B), see
[prose projection](prose-projection.md).
[prose projection](0006-prose-projection.md).
@@ -7,15 +7,15 @@ function type: `(Int) -> Int ![IO]`. The effect set is a
flat, unordered, closed set of effect names, unified by set-equality —
there is no effect row variable; a signature lists exactly the effects
its body may perform. The schema-level effect-set field on `Type::Fn`
is documented in [Data model](../contracts/data-model.md); what is
is documented in [Data model](../contracts/0002-data-model.md); what is
currently in scope vs. excluded lives in
[scope boundaries](../contracts/scope-boundaries.md).
[scope boundaries](../contracts/0010-scope-boundaries.md).
In the MVP only the effect `IO` is wired up (its sole op is `io/print_str`).
`Diverge` (for non-termination) is reserved as an effect name but is
unimplemented — no op, no codegen, no checker injection — in the same
sense the refinements layer is reserved as a future extension without
present-day surface (see
[scope boundaries](../contracts/scope-boundaries.md)).
[scope boundaries](../contracts/0010-scope-boundaries.md)).
This is the most important LLM property: when I read a function, I can trust
its signature without reading the body.
@@ -18,7 +18,7 @@
Two allocator backends share the same MIR. `--alloc=rc` is the
canonical backend committed to in the
[memory model](../contracts/memory-model.md) and the CLI default;
[memory model](../contracts/0008-memory-model.md) and the CLI default;
the typechecker enforces `(own)` / `(borrow)` modes, codegen emits
`ailang_rc_inc` / `_dec` calls at the points dictated by linearity,
and `Term::Clone` / `Term::ReuseAs` materialise into actual rc-bumps
@@ -73,8 +73,8 @@ ail run <module> — build + execute (tempdir), passthro
```
The text projections the CLI moves between are documented in
[authoring surface](../contracts/authoring-surface.md) (Form-A,
round-trippable) and [prose projection](prose-projection.md)
[authoring surface](../contracts/0001-authoring-surface.md) (Form-A,
round-trippable) and [prose projection](0006-prose-projection.md)
(Form-B, lossy, no parser); `ail build --emit=staticlib` produces
the layout fixed in [embedding ABI](../contracts/embedding-abi.md)
plus [frozen value layout](../contracts/frozen-value-layout.md).
the layout fixed in [embedding ABI](../contracts/0003-embedding-abi.md)
plus [frozen value layout](../contracts/0006-frozen-value-layout.md).
@@ -73,10 +73,10 @@ RC's costs are bounded and analysable per program point; the
canonical position is "RC + inference" sharpened with the five
LLM-author mechanisms below. A corpus committed to one memory
model is expensive to switch — the commitment lives in the
contracts ([memory-model](../contracts/memory-model.md),
[language-constraints](../contracts/language-constraints.md)).
contracts ([memory-model](../contracts/0008-memory-model.md),
[language-constraints](../contracts/0015-language-constraints.md)).
**Choice.** AILang's canonical [memory model](../contracts/memory-model.md)
**Choice.** AILang's canonical [memory model](../contracts/0008-memory-model.md)
is reference counting with static uniqueness inference **and
explicit LLM-author annotations on fn signatures**, in the lineage
of Lean 4 / Roc / Koka. The RC pipeline tracks the bump-allocator
@@ -110,7 +110,7 @@ baseline records its rc/bump ratio as the `rc_over_bump`
reference value with ±15% tolerance) and are excluded from the
linear/tree 1.3× regression gate; the closure-chain corpus has
its own ±15% band until a slab/pool optimisation ships. The
[memory model](../contracts/memory-model.md)'s RC commitment is
[memory model](../contracts/0008-memory-model.md)'s RC commitment is
unchanged; what is scoped is the *quantitative* regression band,
not the choice of memory model.
@@ -166,7 +166,7 @@ guess.
**(2) Linear-by-default consumption with explicit `(clone X)`**
(the `Term::Clone` schema entry lives in
[Data model](../contracts/data-model.md)).
[Data model](../contracts/0002-data-model.md)).
In bodies, every binder is consumed by exactly one `own`-mode
use. If the LLM writes:
@@ -241,7 +241,7 @@ compiles, but what the compiler tells the author when it doesn't.
## Inference algorithm
Post-typecheck, post-`lift_letrecs` (see [pipeline](pipeline.md)),
Post-typecheck, post-`lift_letrecs` (see [pipeline](0003-pipeline.md)),
pre-codegen pass over the elaborated module. For each `Term` node that produces or binds a
boxed value, the pass computes a uniqueness flag:
@@ -1,17 +1,17 @@
# Typeclasses — resolution and monomorphisation whitepaper
The schema-and-diagnostics contract for typeclasses lives in
[typeclasses](../contracts/typeclasses.md); the call-site lookup
rule in [method dispatch](../contracts/method-dispatch.md); the
[typeclasses](../contracts/0013-typeclasses.md); the call-site lookup
rule in [method dispatch](../contracts/0016-method-dispatch.md); the
built-in classes shipped in the prelude in
[prelude classes](../contracts/prelude-classes.md). This file
[prelude classes](../contracts/0017-prelude-classes.md). This file
covers the design choices and the resolution / monomorphisation
algorithm.
## The design — Haskell-lite, monomorphised, coherent
**The design pass for typeclasses. Codified after the
[Feature-acceptance criterion](../contracts/feature-acceptance.md)
[Feature-acceptance criterion](../contracts/0004-feature-acceptance.md)
was committed; the criterion is the explicit basis for the choices
below.**
@@ -56,7 +56,7 @@ types) is one an LLM author does not unprompted produce.
**Constraint collection (per function body).** During typechecking
of a body, each method call generates a residual constraint of shape
`<Class> <Type>` (the schema for these lives in
[Data model](../contracts/data-model.md)) where `<Type>` may still
[Data model](../contracts/0002-data-model.md)) where `<Type>` may still
contain type variables.
After local typechecking, residual constraints are checked against
the function's declared constraints (modulo α-conversion and modulo
@@ -163,4 +163,4 @@ for instance, because a constraint remains unresolved at the entry
point — is a static error, not a runtime one. This is the
LLVM-friendly form and is consistent with the performance
commitment of the
[RC + uniqueness memory model](../contracts/memory-model.md).
[RC + uniqueness memory model](../contracts/0008-memory-model.md).
@@ -6,7 +6,7 @@ AILang ships a
second textual projection of the AST: `ailang-prose`, a one-way
projection from `Module → human-readable text`. It is **not** an
authoring surface; it is the "display" projection that the
[authoring surface](../contracts/authoring-surface.md)'s
[authoring surface](../contracts/0001-authoring-surface.md)'s
architectural pin explicitly anticipated:
> *"Future projections are explicitly anticipated: a visual /
@@ -36,15 +36,15 @@ human readers. Form (B) inverts the trade-offs:
lambdas, the `tail` flag — all preserved verbatim.
Critically, **form (B) has no parser**. Form (A) is round-trippable
by construction (see [roundtrip invariant](../contracts/roundtrip-invariant.md));
by construction (see [roundtrip invariant](../contracts/0009-roundtrip-invariant.md));
form (B) deliberately is not. Re-integrating prose edits requires an
external LLM mediator, not a compiler pass — the prompt template
`ail merge-prose` composes the six-step cycle.
Form (B) does not weaken any
[authoring surface](../contracts/authoring-surface.md) invariant:
[authoring surface](../contracts/0001-authoring-surface.md) invariant:
- The [JSON-AST](../contracts/data-model.md) remains the only
- The [JSON-AST](../contracts/0002-data-model.md) remains the only
hashable artefact. Prose is not hashed, not content-addressed,
not load-bearing for any cross-module reference.
- Form (A) remains the canonical authoring surface. Foreign LLMs
@@ -58,7 +58,7 @@ Form (B) does not weaken any
The CLI gains `ail prose <m.ail.json>` (the deterministic
projection) and `ail merge-prose <m.ail.json> <edited.prose.txt>`
(the mediator-prompt composer); both are listed under
[pipeline](pipeline.md).
[pipeline](0003-pipeline.md).
## Form-A spec embedding
@@ -8,7 +8,7 @@ whole; the per-milestone specs in `docs/specs/` carry the
implementation-level detail. As each milestone closes, sections of
this whitepaper transition from forward-looking design to
present-state description, per the
[honesty-rule](../contracts/honesty-rule.md).
[honesty-rule](../contracts/0007-honesty-rule.md).
## The problem
@@ -232,7 +232,7 @@ kernel-tier modules (the stub, future Series, future Matrix)
become auto-injected through the same path.
Class-method dispatch (a separate mechanism — see
[method dispatch](../contracts/method-dispatch.md)) is
[method dispatch](../contracts/0016-method-dispatch.md)) is
orthogonal: the dispatch is about how method calls are
resolved; the auto-import is about which names are in scope.
@@ -516,7 +516,7 @@ of off-by-one and warmup-handling bugs (clause 2); the bounded
push-only mutation surface — gated by the `Series` effect — does
not reintroduce the iterated-mutable-state bug class that the
`mut`/`var`/`assign` removal addressed (clause 3 — see
`docs/specs/2026-05-28-kernel-extension-mechanics.md`'s clause-3
`docs/specs/0052-kernel-extension-mechanics.md`'s clause-3
discussion).
The same three-clause check applies to *each future kernel
@@ -578,7 +578,7 @@ here so the spec can quote the position:
- **Classes / method dispatch.** Orthogonal. Type-scoped
namespacing accesses *top-level defs* in a type's home module;
class-method dispatch (see [method dispatch](../contracts/method-dispatch.md))
class-method dispatch (see [method dispatch](../contracts/0016-method-dispatch.md))
resolves *class method calls* by type-driven instance lookup.
Both can coexist on the same type — e.g. `Series` could
someday have a `Show` instance (class method `show` dispatches
@@ -598,7 +598,7 @@ here so the spec can quote the position:
- **Heap-Str ABI.** The Series runtime borrows the heap-Str
RC-pointer-to-opaque-struct pattern (see
[str-abi](../contracts/str-abi.md)). Same pattern: opaque
[str-abi](../contracts/0011-str-abi.md)). Same pattern: opaque
`ptr` from the compiler's view; dedicated `_new`, `_drop`,
and operation symbols in C; RC header in the struct prefix.
@@ -623,14 +623,14 @@ above is the only commitment.
## Cross-references
- **Feature-acceptance gate** applied to each kernel extension:
[feature-acceptance](../contracts/feature-acceptance.md).
[feature-acceptance](../contracts/0004-feature-acceptance.md).
- **Method dispatch** (orthogonal to type-scoped namespacing):
[method-dispatch](../contracts/method-dispatch.md).
[method-dispatch](../contracts/0016-method-dispatch.md).
- **Honesty rule** (this whitepaper's STATUS contract):
[honesty-rule](../contracts/honesty-rule.md).
[honesty-rule](../contracts/0007-honesty-rule.md).
- **Reference design** for Series storage layout:
`/home/brummel/dev/RustAst/src/ast/rtl/series/` (external Rust
project; not in this repo).
- **Per-milestone specs:** `docs/specs/2026-05-28-kernel-extension-mechanics.md`
- **Per-milestone specs:** `docs/specs/0052-kernel-extension-mechanics.md`
(prep milestone); future `docs/specs/YYYY-MM-DD-series.md`
(Series milestone, written after prep closes).