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
+33 -4
View File
@@ -42,10 +42,39 @@ it measurably improves correctness or removes redundancy.
| `runtime/` | C glue around the RC runtime | | `runtime/` | C glue around the RC runtime |
| `bench/` | Regression harnesses (`check.py`, `compile_check.py`, `cross_lang.py`) and the throughput-and-latency runner (`run.sh`); `bench/reference/` holds the hand-C corpus for cross-language ratios | | `bench/` | Regression harnesses (`check.py`, `compile_check.py`, `cross_lang.py`) and the throughput-and-latency runner (`run.sh`); `bench/reference/` holds the hand-C corpus for cross-language ratios |
| `examples/` | AILang fixtures used by tests and benches | | `examples/` | AILang fixtures used by tests and benches |
| `design/` | The canonical contract ledger — `design/INDEX.md` (sole addressable spine: a typed Contracts + Models table), `design/contracts/` (prose-authoritative test-linked invariants), `design/models/` (onboarding whitepapers) | | `design/` | The canonical contract ledger — `design/INDEX.md` (sole addressable spine: a typed Contracts + Models table), `design/contracts/` (prose-authoritative test-linked invariants), `design/models/` (onboarding whitepapers). Files under `contracts/` and `models/` follow the counter-prefix convention (see "File-naming convention" below). |
| `docs/` | Specs and plans — `docs/specs/` (per-milestone design specs), `docs/plans/` (per-iteration plans), `PROSE_ROUNDTRIP.md`. Project history lives in `git log`; the forward queue lives in Gitea issues (see "Roles" section below). | | `docs/` | Specs and plans — `docs/specs/` (per-milestone design specs), `docs/plans/` (per-iteration plans), `PROSE_ROUNDTRIP.md`. Files under `specs/` and `plans/` follow the counter-prefix convention (see "File-naming convention" below). Project history lives in `git log`; the forward queue lives in Gitea issues (see "Roles" section below). |
| `skills/` | Project-local skill definitions and their agents. See `skills/README.md` for the skill table, agent roster, and discovery layout. | | `skills/` | Project-local skill definitions and their agents. See `skills/README.md` for the skill table, agent roster, and discovery layout. |
## File-naming convention
Four directories accumulate files over the life of the project and
use a zero-padded counter prefix that reflects creation order:
- `docs/specs/NNNN-slug.md`
- `docs/plans/NNNN-slug.md`
- `design/contracts/NNNN-slug.md`
- `design/models/NNNN-slug.md`
The counter is 4-digit, zero-padded, assigned per directory in
strict creation order. A new file takes the next-higher counter for
its directory. A file's counter is **stable for the life of the
file** — never reassigned, never reused, never compacted. If a file
is deleted, its counter is retired; subsequent files do not fill the
gap. This is the property that lets cross-references stay literal.
Slugs are the short identity (`honesty-rule`, `skill-system-buildout`).
Cross-references include the full filename with counter
(`design/contracts/0007-honesty-rule.md`) so they grep cleanly and
resolve directly without a glob step. The convention forbids
renumbering precisely so refs do not need to chase moving prefixes.
The backfill on 2026-05-28 assigned counters by git-log creation
timestamp (alphabetical by original name on ties) and stripped the
old `YYYY-MM-DD-` prefix from `docs/specs/` and `docs/plans/`
the date is recoverable from git log and the counter carries the
ordering.
## Skill system ## Skill system
Day-to-day discipline lives under `skills/<name>/SKILL.md`; see Day-to-day discipline lives under `skills/<name>/SKILL.md`; see
@@ -176,7 +205,7 @@ The test for whether a feature ships is whether an LLM author
naturally produces code that uses it AND whether the feature naturally produces code that uses it AND whether the feature
measurably improves correctness or removes redundancy. Aesthetic measurably improves correctness or removes redundancy. Aesthetic
appeal does not count; neither does human ergonomics. Full criterion appeal does not count; neither does human ergonomics. Full criterion
lives in `design/contracts/feature-acceptance.md` and is lives in `design/contracts/0004-feature-acceptance.md` and is
applied as a gate by `skills/brainstorm/SKILL.md` during spec writing. applied as a gate by `skills/brainstorm/SKILL.md` during spec writing.
## Bug fixes — TDD, always ## Bug fixes — TDD, always
@@ -211,7 +240,7 @@ not retroactively renamed.
`ailang-architect` checks the code against during drift review. `ailang-architect` checks the code against during drift review.
A contract describes only the actual present state; forward intent A contract describes only the actual present state; forward intent
goes to the Gitea backlog, history and rationale to `git log` goes to the Gitea backlog, history and rationale to `git log`
(see `design/contracts/honesty-rule.md`). (see `design/contracts/0007-honesty-rule.md`).
- **`git log`** is the project history. Iter and audit commit - **`git log`** is the project history. Iter and audit commit
bodies carry the *why* — alternatives considered and rejected, bodies carry the *why* — alternatives considered and rejected,
+1 -1
View File
@@ -10,7 +10,7 @@ members = [
] ]
# `ail-embed/` is intentionally NOT a member: it depends on the # `ail-embed/` is intentionally NOT a member: it depends on the
# external `../libs/data-server` and is the sole data-server↔AILang # external `../libs/data-server` and is the sole data-server↔AILang
# meeting point (Invariant 1, docs/specs/2026-05-19-embedding-abi-m5.md). # meeting point (Invariant 1, docs/specs/0044-embedding-abi-m5.md).
# Adding it here would couple the compiler workspace to a sibling dir. # Adding it here would couple the compiler workspace to a sibling dir.
[workspace.package] [workspace.package]
+1 -1
View File
@@ -3,7 +3,7 @@
# auto-absorb this nested package. This is cargo's documented # auto-absorb this nested package. This is cargo's documented
# mechanism for a deliberately workspace-excluded crate and keeps # mechanism for a deliberately workspace-excluded crate and keeps
# `ail-embed` out of the AILang dependency graph entirely # `ail-embed` out of the AILang dependency graph entirely
# (Invariant 1, docs/specs/2026-05-19-embedding-abi-m5.md). # (Invariant 1, docs/specs/0044-embedding-abi-m5.md).
[workspace] [workspace]
[package] [package]
+3 -3
View File
@@ -1,7 +1,7 @@
//! Lean embedding of an AILang M3-frozen staticlib kernel into a //! Lean embedding of an AILang M3-frozen staticlib kernel into a
//! Rust host. The Rust analogue of the audited C host //! Rust host. The Rust analogue of the audited C host
//! `crates/ail/tests/embed/tick_roundtrip.c`: same frozen value //! `crates/ail/tests/embed/tick_roundtrip.c`: same frozen value
//! layout (design/contracts/frozen-value-layout.md), same //! layout (design/contracts/0006-frozen-value-layout.md), same
//! `own`-mode contract. ZERO `data_server`/finance knowledge. //! `own`-mode contract. ZERO `data_server`/finance knowledge.
use std::ffi::c_void; use std::ffi::c_void;
@@ -32,7 +32,7 @@ impl Ctx {
Self(unsafe { ailang_ctx_new() }) Self(unsafe { ailang_ctx_new() })
} }
/// `State` box, frozen layout (design/contracts/frozen-value-layout.md): /// `State` box, frozen layout (design/contracts/0006-frozen-value-layout.md):
/// payload `8 + 2*8` = 24 bytes — tag:i64@0, acc:f64@8, n:i64@16. /// payload `8 + 2*8` = 24 bytes — tag:i64@0, acc:f64@8, n:i64@16.
/// `ailang_rc_alloc` sets the `p-8` rc header to 1 and zeroes the /// `ailang_rc_alloc` sets the `p-8` rc header to 1 and zeroes the
/// payload, so the tag write of 0 is the single-ctor tag. /// payload, so the tag write of 0 is the single-ctor tag.
@@ -88,7 +88,7 @@ impl Kernel {
} }
/// Folds `prices` via the kernel and returns `(Σ px, count)`. /// Folds `prices` via the kernel and returns `(Σ px, count)`.
/// `own` discipline (design/contracts/frozen-value-layout.md): each `Tick` is freshly /// `own` discipline (design/contracts/0006-frozen-value-layout.md): each `Tick` is freshly
/// `ailang_rc_alloc`'d and consumed by the kernel; `st` is /// `ailang_rc_alloc`'d and consumed by the kernel; `st` is
/// consumed and replaced by the return each step; only the final /// consumed and replaced by the return each step; only the final
/// return is host-`dec`'d. /// return is host-`dec`'d.
+1 -1
View File
@@ -2,7 +2,7 @@
"version": 1, "version": 1,
"captured": "2026-05-20", "captured": "2026-05-20",
"captured_via": "bench/run.sh -n 5", "captured_via": "bench/run.sh -n 5",
"note": "Baseline for bench/check.py regression detection. The language-invariant thresholds (rc/bump <= 1.3x throughput, p99/median <= 5x latency) are NOT the regression-check tolerances; the per-metric tolerances below are tuned to absorb run-to-run noise on a quiet developer machine. To update after an intentional change, re-run bench/run.sh and replace the values, recording the reason in the commit body that ships the baseline bump. The latency arms gate only on median / p99 / p99_over_median \u2014 max_us and p99_9_us were removed on the 2026-05-20 recapture (Gitea #15 / #16) because tail-of-distribution latency metrics are dominated by OS-level jitter (THP defrag, scheduler preemption, IRQ load), not allocator behaviour, and produced 3+ consecutive false-positive REGRESSION rows on byte-identical no-op milestones. See docs/specs/2026-05-20-bench-harness-recalibration.md.", "note": "Baseline for bench/check.py regression detection. The language-invariant thresholds (rc/bump <= 1.3x throughput, p99/median <= 5x latency) are NOT the regression-check tolerances; the per-metric tolerances below are tuned to absorb run-to-run noise on a quiet developer machine. To update after an intentional change, re-run bench/run.sh and replace the values, recording the reason in the commit body that ships the baseline bump. The latency arms gate only on median / p99 / p99_over_median \u2014 max_us and p99_9_us were removed on the 2026-05-20 recapture (Gitea #15 / #16) because tail-of-distribution latency metrics are dominated by OS-level jitter (THP defrag, scheduler preemption, IRQ load), not allocator behaviour, and produced 3+ consecutive false-positive REGRESSION rows on byte-identical no-op milestones. See docs/specs/0047-bench-harness-recalibration.md.",
"throughput": { "throughput": {
"bench_list_sum": { "bench_list_sum": {
"bump_s": { "bump_s": {
+2 -2
View File
@@ -1098,7 +1098,7 @@ fn workspace_error_to_diagnostic(
// typeclass-coherence diagnostics emitted from // typeclass-coherence diagnostics emitted from
// `workspace::build_registry`. The codes follow the // `workspace::build_registry`. The codes follow the
// diagnostic-categories section of // diagnostic-categories section of
// `design/contracts/typeclasses.md`. // `design/contracts/0013-typeclasses.md`.
W::OrphanInstance { W::OrphanInstance {
class, class,
type_repr, type_repr,
@@ -1568,7 +1568,7 @@ fn walk_term(
/// Adds the variable bindings introduced by a pattern to `scope` and /// Adds the variable bindings introduced by a pattern to `scope` and
/// returns the names that were freshly inserted (so the caller can roll /// returns the names that were freshly inserted (so the caller can roll
/// them back). MVP-restricted: nested ctor patterns only contain /// them back). MVP-restricted: nested ctor patterns only contain
/// `Var`/`Wild` — see design/contracts/data-model.md. /// `Var`/`Wild` — see design/contracts/0002-data-model.md.
fn bind_pattern( fn bind_pattern(
p: &ailang_core::ast::Pattern, p: &ailang_core::ast::Pattern,
scope: &mut std::collections::HashSet<String>, scope: &mut std::collections::HashSet<String>,
@@ -1,5 +1,5 @@
//! Pin for the iter-24.3 codegen `import_map`-fallback path //! Pin for the iter-24.3 codegen `import_map`-fallback path
//! (design/contracts/typeclasses.md, "Cross-module references in //! (design/contracts/0013-typeclasses.md, "Cross-module references in
//! synthesised bodies" invariant 2). //! synthesised bodies" invariant 2).
//! //!
//! Property protected: post-mono synthesised body cross-module //! Property protected: post-mono synthesised body cross-module
+1 -1
View File
@@ -2742,7 +2742,7 @@ fn str_clone_drop_balances_rc_stats() {
/// input bytes; RC stats account for three heap-Str slabs (one /// input bytes; RC stats account for three heap-Str slabs (one
/// from int_to_str, two from str_clone) and three matching frees. /// from int_to_str, two from str_clone) and three matching frees.
/// Pins the "uniform consumer ABI" claim from /// Pins the "uniform consumer ABI" claim from
/// design/contracts/str-abi.md — str_clone only reads len + bytes + /// design/contracts/0011-str-abi.md — str_clone only reads len + bytes +
/// NUL, never the rc_header. /// NUL, never the rc_header.
#[test] #[test]
fn str_clone_cross_realisation_uniform_abi() { fn str_clone_cross_realisation_uniform_abi() {
+1 -1
View File
@@ -1,6 +1,6 @@
/* Embedding-ABI M3 record round-trip C host (own + borrow via a /* Embedding-ABI M3 record round-trip C host (own + borrow via a
* compile-time -DBORROW switch). Frozen value layout * compile-time -DBORROW switch). Frozen value layout
* (design/contracts/frozen-value-layout.md): * (design/contracts/0006-frozen-value-layout.md):
* p - 8 .. p uint64_t refcount header (set to 1 by ailang_rc_alloc) * p - 8 .. p uint64_t refcount header (set to 1 by ailang_rc_alloc)
* p + 0 int64_t constructor tag (single ctor → 0) * p + 0 int64_t constructor tag (single ctor → 0)
* p + 8 IEEE-754 double field 0 = Float acc * p + 8 IEEE-754 double field 0 = Float acc
+1 -1
View File
@@ -3,7 +3,7 @@
* only ever push a *scalar* per-tick sample; this host pushes a * only ever push a *scalar* per-tick sample; this host pushes a
* single-ctor all-scalar *record* `Tick` as the per-call payload — * single-ctor all-scalar *record* `Tick` as the per-call payload —
* the actual minimal data-server binding shape. Frozen value layout * the actual minimal data-server binding shape. Frozen value layout
* (design/contracts/frozen-value-layout.md): * (design/contracts/0006-frozen-value-layout.md):
* *
* State (24-byte payload): * State (24-byte payload):
* p - 8 .. p uint64_t refcount header (set to 1 by ailang_rc_alloc) * p - 8 .. p uint64_t refcount header (set to 1 by ailang_rc_alloc)
+2 -2
View File
@@ -2,7 +2,7 @@
//! //!
//! Property protected: a polymorphic Eq/Ord helper invoked at Float //! Property protected: a polymorphic Eq/Ord helper invoked at Float
//! fires `no-instance` (since Float has neither Eq nor Ord instance //! fires `no-instance` (since Float has neither Eq nor Ord instance
//! per design/contracts/float-semantics.md) AND the diagnostic message //! per design/contracts/0005-float-semantics.md) AND the diagnostic message
//! cross-references the canonical float-semantics contract so the //! cross-references the canonical float-semantics contract so the
//! LLM author immediately learns the partial-Float story rather //! LLM author immediately learns the partial-Float story rather
//! than seeing a bare "no instance" message. //! than seeing a bare "no instance" message.
@@ -38,7 +38,7 @@ fn eq_at_float_fires_float_aware_noinstance() {
// Cross-ref to the float-semantics contract — the LLM author should // Cross-ref to the float-semantics contract — the LLM author should
// be pointed at the canonical explanation of partial Float orderability. // be pointed at the canonical explanation of partial Float orderability.
assert!( assert!(
no_inst.message.contains("design/contracts/float-semantics.md"), no_inst.message.contains("design/contracts/0005-float-semantics.md"),
"expected NoInstance message to cross-reference the float-semantics contract, got: {:?}", "expected NoInstance message to cross-reference the float-semantics contract, got: {:?}",
no_inst.message no_inst.message
); );
+2 -2
View File
@@ -7,8 +7,8 @@
//! invoked as `(app greet)`. //! invoked as `(app greet)`.
//! //!
//! Two independent fieldtest specs flagged the same gap: //! Two independent fieldtest specs flagged the same gap:
//! `docs/specs/2026-05-15-fieldtest-mut-local.md` F3 and //! `docs/specs/0030-fieldtest-mut-local.md` F3 and
//! `docs/specs/2026-05-18-fieldtest-loop-recur.md` spec_gap. The //! `docs/specs/0035-fieldtest-loop-recur.md` spec_gap. The
//! Form-A surface refusing nullary calls had no schema backing — //! Form-A surface refusing nullary calls had no schema backing —
//! `Term::App.args` is `[Term...]` (zero-or-more), so the parser //! `Term::App.args` is `[Term...]` (zero-or-more), so the parser
//! guard was an unbacked rule. //! guard was an unbacked rule.
@@ -1,5 +1,5 @@
//! Pin for the iter-24.3 FreeFnCall constraint-residual-push //! Pin for the iter-24.3 FreeFnCall constraint-residual-push
//! invariant (design/contracts/typeclasses.md, "Cross-module //! invariant (design/contracts/0013-typeclasses.md, "Cross-module
//! references in synthesised bodies" invariant 3). //! references in synthesised bodies" invariant 3).
//! //!
//! Property protected: bare-name references to polymorphic free fns //! Property protected: bare-name references to polymorphic free fns
+4 -4
View File
@@ -2,7 +2,7 @@
//! //!
//! Property protected: calling `print` on a function type fires the //! Property protected: calling `print` on a function type fires the
//! `no-instance` diagnostic with a Show-aware message that //! `no-instance` diagnostic with a Show-aware message that
//! cross-references design/contracts/typeclasses.md, so the //! cross-references design/contracts/0013-typeclasses.md, so the
//! LLM author immediately learns which types ship with built-in Show //! LLM author immediately learns which types ship with built-in Show
//! and how to declare their own instance for a user type. //! and how to declare their own instance for a user type.
@@ -40,11 +40,11 @@ fn print_on_fn_type_fires_show_aware_no_instance() {
no_inst.message no_inst.message
); );
// Must cross-reference design/contracts/typeclasses.md — that's // Must cross-reference design/contracts/0013-typeclasses.md — that's
// the canonical contract naming which types ship with Show. // the canonical contract naming which types ship with Show.
assert!( assert!(
no_inst.message.contains("design/contracts/typeclasses.md"), no_inst.message.contains("design/contracts/0013-typeclasses.md"),
"expected design/contracts/typeclasses.md cross-reference, got message: {:?}", "expected design/contracts/0013-typeclasses.md cross-reference, got message: {:?}",
no_inst.message no_inst.message
); );
} }
+1 -1
View File
@@ -39,7 +39,7 @@
//! - `module-cycle` — workspace loader (Iter 5b, in the CLI path) //! - `module-cycle` — workspace loader (Iter 5b, in the CLI path)
//! - `module-name-mismatch` — workspace loader (Iter 5b, in the CLI path) //! - `module-name-mismatch` — workspace loader (Iter 5b, in the CLI path)
//! - `module-hash-mismatch` — workspace loader (Iter 5b, in the CLI path) //! - `module-hash-mismatch` — workspace loader (Iter 5b, in the CLI path)
//! - `tail-call-not-in-tail-position` (see `design/contracts/tail-calls.md`) //! - `tail-call-not-in-tail-position` (see `design/contracts/0012-tail-calls.md`)
//! - `use-after-consume` — `ctx`: `{"binder": "<n>"}` (Iter 18c.2); //! - `use-after-consume` — `ctx`: `{"binder": "<n>"}` (Iter 18c.2);
//! carries non-empty [`Diagnostic::suggested_rewrites`] showing how to //! carries non-empty [`Diagnostic::suggested_rewrites`] showing how to
//! spell the fix in form-A AILang. //! spell the fix in form-A AILang.
+9 -9
View File
@@ -446,7 +446,7 @@ pub enum CheckError {
/// An `(export …)` fn has a parameter or return type that is not /// An `(export …)` fn has a parameter or return type that is not
/// a permitted embedding-ABI type. The embedding ABI is frozen as /// a permitted embedding-ABI type. The embedding ABI is frozen as
/// of M3 (design/contracts/embedding-abi.md): /// of M3 (design/contracts/0003-embedding-abi.md):
/// `Int`/`Float` or a single-constructor record of those; every /// `Int`/`Float` or a single-constructor record of those; every
/// other shape (multi-ctor sums, `Str`/`List`/nested-record /// other shape (multi-ctor sums, `Str`/`List`/nested-record
/// fields) is rejected at typecheck (the feature-acceptance /// fields) is rejected at typecheck (the feature-acceptance
@@ -556,7 +556,7 @@ pub enum CheckError {
/// a `Term::App { tail: true, .. }` or /// a `Term::App { tail: true, .. }` or
/// `Term::Do { tail: true, .. }` was found in a non-tail position. /// `Term::Do { tail: true, .. }` was found in a non-tail position.
/// Code: `tail-call-not-in-tail-position`. See `design/contracts/tail-calls.md`. /// Code: `tail-call-not-in-tail-position`. See `design/contracts/0012-tail-calls.md`.
#[error("call marked `tail` is not in tail position")] #[error("call marked `tail` is not in tail position")]
TailCallNotInTailPosition, TailCallNotInTailPosition,
@@ -858,7 +858,7 @@ impl CheckError {
} }
// Float-aware addendum on `NoInstance`. When the // Float-aware addendum on `NoInstance`. When the
// unresolved class is `Eq` or `Ord` AND the type is `Float`, // unresolved class is `Eq` or `Ord` AND the type is `Float`,
// append a cross-reference to design/contracts/float-semantics.md so // append a cross-reference to design/contracts/0005-float-semantics.md so
// the LLM author learns the partial-Float story immediately // the LLM author learns the partial-Float story immediately
// rather than seeing a bare "no instance" message. Float has // rather than seeing a bare "no instance" message. Float has
// neither Eq nor Ord by design (partial orderability per // neither Eq nor Ord by design (partial orderability per
@@ -874,7 +874,7 @@ impl CheckError {
orderability per IEEE-754); use float_eq / float_lt \ orderability per IEEE-754); use float_eq / float_lt \
(and siblings float_ne / float_le / float_gt / float_ge) \ (and siblings float_ne / float_le / float_gt / float_ge) \
for explicit IEEE-aware comparison. \ for explicit IEEE-aware comparison. \
See design/contracts/float-semantics.md.", See design/contracts/0005-float-semantics.md.",
d.message d.message
); );
} else if class == "prelude.Show" { } else if class == "prelude.Show" {
@@ -883,12 +883,12 @@ impl CheckError {
// a function type (`print f` where f is bare-fn-typed) // a function type (`print f` where f is bare-fn-typed)
// or a user type the LLM-author forgot to give an // or a user type the LLM-author forgot to give an
// instance for. Cross-references // instance for. Cross-references
// design/contracts/typeclasses.md so the author learns // design/contracts/0013-typeclasses.md so the author learns
// which types ship with built-in Show immediately. // which types ship with built-in Show immediately.
d.message = format!( d.message = format!(
"{} — `print` and `show` require a Show instance. \ "{} — `print` and `show` require a Show instance. \
Built-in Show ships for Int, Bool, Str, Float in \ Built-in Show ships for Int, Bool, Str, Float in \
the prelude; see design/contracts/typeclasses.md. \ the prelude; see design/contracts/0013-typeclasses.md. \
User types declare their own \ User types declare their own \
`instance prelude.Show <T>` in the type's defining \ `instance prelude.Show <T>` in the type's defining \
module per the typeclass design coherence.", module per the typeclass design coherence.",
@@ -2643,10 +2643,10 @@ fn constraint_type_matches(declared: &Type, residual: &Type) -> bool {
/// verifies that every `Term::App { tail: true, .. }` and /// verifies that every `Term::App { tail: true, .. }` and
/// `Term::Do { tail: true, .. }` actually sits in tail position, per /// `Term::Do { tail: true, .. }` actually sits in tail position, per
/// the explicit-tail-call contract /// the explicit-tail-call contract
/// (`design/contracts/tail-calls.md`). /// (`design/contracts/0012-tail-calls.md`).
/// ///
/// `is_tail` is the tail-context flag for the term currently being /// `is_tail` is the tail-context flag for the term currently being
/// visited. The propagation rules (from design/contracts/tail-calls.md): /// visited. The propagation rules (from design/contracts/0012-tail-calls.md):
/// ///
/// - The body of a fn / Lam is visited with `is_tail = true`. /// - The body of a fn / Lam is visited with `is_tail = true`.
/// - `Match { scrutinee, arms }`: the scrutinee is **not** in tail /// - `Match { scrutinee, arms }`: the scrutinee is **not** in tail
@@ -6031,7 +6031,7 @@ mod tests {
/// Floats milestone post-fieldtest B1 (RED): pattern-matching on a /// Floats milestone post-fieldtest B1 (RED): pattern-matching on a
/// `Literal::Float` literal must be hard-rejected at typecheck via /// `Literal::Float` literal must be hard-rejected at typecheck via
/// `CheckError::FloatPatternNotAllowed` per /// `CheckError::FloatPatternNotAllowed` per
/// design/contracts/float-semantics.md — even when the match arm reaches `check` through /// design/contracts/0005-float-semantics.md — even when the match arm reaches `check` through
/// the *full* check pipeline (which runs `desugar_module` first). /// the *full* check pipeline (which runs `desugar_module` first).
/// ///
/// The existing `reject_float_pattern_in_match` test in /// The existing `reject_float_pattern_in_match` test in
+2 -2
View File
@@ -85,7 +85,7 @@ impl<'a> Emitter<'a> {
out.push_str(" %is_null = icmp eq ptr %p, null\n"); out.push_str(" %is_null = icmp eq ptr %p, null\n");
out.push_str(" br i1 %is_null, label %ret, label %live\n"); out.push_str(" br i1 %is_null, label %ret, label %live\n");
out.push_str("live:\n"); out.push_str("live:\n");
// FROZEN ABI (embedding boundary) — see design/contracts/embedding-abi.md. // FROZEN ABI (embedding boundary) — see design/contracts/0003-embedding-abi.md.
out.push_str(" %tag = load i64, ptr %p, align 8\n"); out.push_str(" %tag = load i64, ptr %p, align 8\n");
let n_ctors = td.ctors.len(); let n_ctors = td.ctors.len();
@@ -111,7 +111,7 @@ impl<'a> Emitter<'a> {
if lty != "ptr" { if lty != "ptr" {
continue; continue;
} }
// FROZEN ABI (embedding boundary) — see design/contracts/embedding-abi.md. // FROZEN ABI (embedding boundary) — see design/contracts/0003-embedding-abi.md.
let off = 8 + (j as i64) * 8; let off = 8 + (j as i64) * 8;
let addr_id = local; let addr_id = local;
local += 1; local += 1;
+3 -3
View File
@@ -174,7 +174,7 @@ pub enum Target {
/// published via `@__ail_tls_ctx` around the unchanged internal /// published via `@__ail_tls_ctx` around the unchanged internal
/// call. The ctx-threaded C signature is the M2 shape; the /// call. The ctx-threaded C signature is the M2 shape; the
/// value/record layout is frozen as of M3 /// value/record layout is frozen as of M3
/// (design/contracts/frozen-value-layout.md). /// (design/contracts/0006-frozen-value-layout.md).
StaticLib, StaticLib,
} }
@@ -687,7 +687,7 @@ fn llvm_scalar(t: &Type) -> &'static str {
// M3: any other Type::Con reaching an (export) signature is, // M3: any other Type::Con reaching an (export) signature is,
// by the Task-2 export gate, a single-ctor scalar record; // by the Task-2 export gate, a single-ctor scalar record;
// it crosses the C ABI as a bare `ptr` // it crosses the C ABI as a bare `ptr`
// (design/contracts/frozen-value-layout.md — payload pointer). // (design/contracts/0006-frozen-value-layout.md — payload pointer).
Type::Con { .. } => "ptr", Type::Con { .. } => "ptr",
_ => "i64", _ => "i64",
} }
@@ -2813,7 +2813,7 @@ impl<'a> Emitter<'a> {
/// allocates an `Ordering` ctor per call via the /// allocates an `Ordering` ctor per call via the
/// `compare__Int` → `match` path, which surfaces as a /// `compare__Int` → `match` path, which surfaces as a
/// `bench_closure_chain` regression. See /// `bench_closure_chain` regression. See
/// `design/contracts/prelude-classes.md` for the full surface /// `design/contracts/0017-prelude-classes.md` for the full surface
/// and the Int-only asymmetry rationale. /// and the Int-only asymmetry rationale.
fn try_emit_primitive_instance_body( fn try_emit_primitive_instance_body(
&mut self, &mut self,
+1 -1
View File
@@ -105,7 +105,7 @@ impl<'a> Emitter<'a> {
compiled.push((v, vty)); compiled.push((v, vty));
} }
// FROZEN ABI (embedding boundary) — // FROZEN ABI (embedding boundary) —
// design/contracts/frozen-value-layout.md. size = 8 + n*8, tag@0, fields@8+i*8. // design/contracts/0006-frozen-value-layout.md. size = 8 + n*8, tag@0, fields@8+i*8.
let size_bytes = 8 + (compiled.len() * 8) as i64; let size_bytes = 8 + (compiled.len() * 8) as i64;
let p = self.fresh_ssa(); let p = self.fresh_ssa();
// pick allocator based on escape analysis. `alloca` // pick allocator based on escape analysis. `alloca`
@@ -1,4 +1,4 @@
//! FROZEN ABI byte-pin — see design/contracts/frozen-value-layout.md. //! FROZEN ABI byte-pin — see design/contracts/0006-frozen-value-layout.md.
//! Pins the heap (@ailang_rc_alloc) box layout a boundary-crossing //! Pins the heap (@ailang_rc_alloc) box layout a boundary-crossing
//! single-ctor scalar record takes: size = 8 + n*8, tag i64 @ offset //! single-ctor scalar record takes: size = 8 + n*8, tag i64 @ offset
//! 0, fields i64-strided from offset 8. Goes RED if codegen moves an //! 0, fields i64-strided from offset 8. Goes RED if codegen moves an
@@ -45,7 +45,7 @@ fn staticlib_emits_forwarder_no_main() {
/// M3: a single-ctor scalar record param/ret crosses the embedding /// M3: a single-ctor scalar record param/ret crosses the embedding
/// C boundary as a bare `ptr` (the frozen payload pointer — /// C boundary as a bare `ptr` (the frozen payload pointer —
/// design/contracts/frozen-value-layout.md). The M2 forwarder body /// design/contracts/0006-frozen-value-layout.md). The M2 forwarder body
/// is byte-unchanged: leading `ptr %ctx`, TLS save/store/restore, the /// is byte-unchanged: leading `ptr %ctx`, TLS save/store/restore, the
/// internal `@ail_<module>_<fn>` call carrying no ctx arg and no /// internal `@ail_<module>_<fn>` call carrying no ctx arg and no
/// aggregate calling convention (no `sret`/`byval` — a record is a /// aggregate calling convention (no `sret`/`byval` — a record is a
+2 -2
View File
@@ -86,7 +86,7 @@ externally-callable entrypoint (Embedding ABI M1). The symbol is
author-chosen and decoupled from the internal `ail_<module>_<def>` author-chosen and decoupled from the internal `ail_<module>_<def>`
mangling. M1 requires the fn's parameter and return types to be mangling. M1 requires the fn's parameter and return types to be
scalar (`Int`/`Float`) and its effect set to be empty — see scalar (`Int`/`Float`) and its effect set to be empty — see
design/contracts/embedding-abi.md. design/contracts/0003-embedding-abi.md.
`suppress` clauses silence advisory diagnostics for this def. The `suppress` clauses silence advisory diagnostics for this def. The
`code` MUST be one of the registered codes (today: `over-strict-mode`). `code` MUST be one of the registered codes (today: `over-strict-mode`).
@@ -324,7 +324,7 @@ Notes:
both enforced at typecheck (`recur-arity-mismatch`, both enforced at typecheck (`recur-arity-mismatch`,
`recur-not-in-tail-position`). `loop`/`recur` make no termination `recur-not-in-tail-position`). `loop`/`recur` make no termination
claim: a `loop` with no non-`recur` exit runs forever. See claim: a `loop` with no non-`recur` exit runs forever. See
`docs/specs/2026-05-17-loop-recur.md`. `docs/specs/0034-loop-recur.md`.
## Patterns ## Patterns
+9 -9
View File
@@ -1,6 +1,6 @@
//! AST nodes for the AILang language. //! AST nodes for the AILang language.
//! //!
//! **The canonical schema lives in `design/contracts/data-model.md`**; //! **The canonical schema lives in `design/contracts/0002-data-model.md`**;
//! this module is the Rust-side projection of it. When the two drift, //! this module is the Rust-side projection of it. When the two drift,
//! `crates/ailang-core/tests/design_schema_drift.rs` fires. //! `crates/ailang-core/tests/design_schema_drift.rs` fires.
//! //!
@@ -208,7 +208,7 @@ pub struct FnDef {
/// embedding boundary. Codegen's `Target::StaticLib` mode /// embedding boundary. Codegen's `Target::StaticLib` mode
/// additionally emits an externally-visible C entrypoint /// additionally emits an externally-visible C entrypoint
/// `@<sym>` (signature frozen as of M3 — /// `@<sym>` (signature frozen as of M3 —
/// design/contracts/embedding-abi.md) forwarding /// design/contracts/0003-embedding-abi.md) forwarding
/// to `@ail_<module>_<fn>`. The symbol is author-chosen and /// to `@ail_<module>_<fn>`. The symbol is author-chosen and
/// decoupled from the `ail_<module>_<def>` mangling so the /// decoupled from the `ail_<module>_<def>` mangling so the
/// M3-frozen ABI survives module/fn refactors. /// M3-frozen ABI survives module/fn refactors.
@@ -256,7 +256,7 @@ pub struct Suppress {
} }
/// A typeclass declaration (narrative in /// A typeclass declaration (narrative in
/// `design/contracts/typeclasses.md`). /// `design/contracts/0013-typeclasses.md`).
/// ///
/// Single-parameter, multi-method, optional-default, optional-superclass /// Single-parameter, multi-method, optional-default, optional-superclass
/// typeclass. The `param` is a single string — multi-param classes are /// typeclass. The `param` is a single string — multi-param classes are
@@ -326,7 +326,7 @@ pub struct ClassMethod {
} }
/// An instance declaration (narrative in /// An instance declaration (narrative in
/// `design/contracts/typeclasses.md`). /// `design/contracts/0013-typeclasses.md`).
/// ///
/// `class` is the name of the class being instantiated. `type_` is the /// `class` is the name of the class being instantiated. `type_` is the
/// concrete type expression the class is applied to — never the class /// concrete type expression the class is applied to — never the class
@@ -360,7 +360,7 @@ pub struct InstanceMethod {
} }
/// A class constraint on a polymorphic function (narrative in /// A class constraint on a polymorphic function (narrative in
/// `design/contracts/typeclasses.md`). `(class, type)` pair where /// `design/contracts/0013-typeclasses.md`). `(class, type)` pair where
/// `class` is a class name and `type` is a `Type` expression — /// `class` is a class name and `type` is a `Type` expression —
/// typically a single `Type::Var` (e.g. `(Eq, a)` for /// typically a single `Type::Var` (e.g. `(Eq, a)` for
/// `Eq a => ...`). Concrete-type constraints are legal schema-wise /// `Eq a => ...`). Concrete-type constraints are legal schema-wise
@@ -412,7 +412,7 @@ pub enum Term {
/// `args` are evaluated left-to-right. /// `args` are evaluated left-to-right.
/// ///
/// `tail` marks this call as occurring in tail position (see /// `tail` marks this call as occurring in tail position (see
/// `design/contracts/tail-calls.md`). When set, codegen lowers /// `design/contracts/0012-tail-calls.md`). When set, codegen lowers
/// the call as `musttail call`. The flag defaults to `false` and /// the call as `musttail call`. The flag defaults to `false` and
/// is omitted during canonical-JSON serialisation when unset, so /// is omitted during canonical-JSON serialisation when unset, so
/// pre-tail-flag fixtures keep bit-identical hashes. /// pre-tail-flag fixtures keep bit-identical hashes.
@@ -548,7 +548,7 @@ pub enum Term {
/// loop-carried SSA / phi form is produced by `clang -O2` /// loop-carried SSA / phi form is produced by `clang -O2`
/// mem2reg (NOT hand-emitted phi). No totality claim — an /// mem2reg (NOT hand-emitted phi). No totality claim — an
/// infinite loop is legal. See /// infinite loop is legal. See
/// `docs/specs/2026-05-17-loop-recur.md`. /// `docs/specs/0034-loop-recur.md`.
Loop { Loop {
binders: Vec<LoopBinder>, binders: Vec<LoopBinder>,
body: Box<Term>, body: Box<Term>,
@@ -707,7 +707,7 @@ pub enum Type {
/// every entry is `Implicit`; `ret_mode` is omitted when it is /// every entry is `Implicit`; `ret_mode` is omitted when it is
/// `Implicit`, so pre-mode-annotation fixtures hash /// `Implicit`, so pre-mode-annotation fixtures hash
/// bit-identically. Full contract in /// bit-identically. Full contract in
/// `design/contracts/memory-model.md`. /// `design/contracts/0008-memory-model.md`.
Fn { Fn {
params: Vec<Type>, params: Vec<Type>,
#[serde(default, skip_serializing_if = "all_implicit")] #[serde(default, skip_serializing_if = "all_implicit")]
@@ -780,7 +780,7 @@ impl Type {
} }
/// Per-parameter / return mode marker on a [`Type::Fn`]. Full /// Per-parameter / return mode marker on a [`Type::Fn`]. Full
/// contract lives in `design/contracts/memory-model.md`. /// contract lives in `design/contracts/0008-memory-model.md`.
/// ///
/// `Implicit` is the legacy state for fn-types that were constructed /// `Implicit` is the legacy state for fn-types that were constructed
/// before the borrow/own surface annotations existed. Semantically, /// before the borrow/own surface annotations existed. Semantically,
+2 -2
View File
@@ -1090,12 +1090,12 @@ fn is_flat(p: &Pattern) -> bool {
/// Builds the equality-test AST node for a literal pattern. Lowers /// Builds the equality-test AST node for a literal pattern. Lowers
/// `(pat-lit <lit>)` to `(if (eq sv <lit>) <body> <fall_k>)`. The /// `(pat-lit <lit>)` to `(if (eq sv <lit>) <body> <fall_k>)`. The
/// emitted `eq` resolves via prelude.Eq's class-method dispatch /// emitted `eq` resolves via prelude.Eq's class-method dispatch
/// (per design/contracts/method-dispatch.md) — Int/Bool/Str/Unit /// (per design/contracts/0016-method-dispatch.md) — Int/Bool/Str/Unit
/// patterns all route through the corresponding primitive instance. /// patterns all route through the corresponding primitive instance.
/// ///
/// Float-Literal patterns are hard-rejected at typecheck /// Float-Literal patterns are hard-rejected at typecheck
/// (`CheckError::FloatPatternNotAllowed`, per /// (`CheckError::FloatPatternNotAllowed`, per
/// design/contracts/float-semantics.md) before this fn is reached, /// design/contracts/0005-float-semantics.md) before this fn is reached,
/// so the `eq`-dispatch never encounters Float at runtime; the /// so the `eq`-dispatch never encounters Float at runtime; the
/// Float arm of the match below remains for AST-level totality. /// Float arm of the match below remains for AST-level totality.
/// ///
+1 -1
View File
@@ -108,7 +108,7 @@ pub type Result<T> = std::result::Result<T, Error>;
pub const SCHEMA: &str = "ailang/v0"; pub const SCHEMA: &str = "ailang/v0";
/// Complete LLM-targeted specification of Form-A — the canonical /// Complete LLM-targeted specification of Form-A — the canonical
/// authoring surface (see `design/contracts/authoring-surface.md`). /// authoring surface (see `design/contracts/0001-authoring-surface.md`).
/// Embedded verbatim into any prompt that asks an LLM to produce or /// Embedded verbatim into any prompt that asks an LLM to produce or
/// edit AILang code; in particular, `ail merge-prose` includes it in /// edit AILang code; in particular, `ail merge-prose` includes it in
/// the round-trip prompt template. The string is the raw bytes of /// the round-trip prompt template. The string is the raw bytes of
+2 -2
View File
@@ -4,8 +4,8 @@
//! dangles, a contract loses its ratifying test, docs/DESIGN.md is //! dangles, a contract loses its ratifying test, docs/DESIGN.md is
//! resurrected, or a design/ body cross-link fails to resolve into //! resurrected, or a design/ body cross-link fails to resolve into
//! the durable tier (clause-5; spec //! the durable tier (clause-5; spec
//! docs/specs/2026-05-19-design-ledger-formal-links.md). Spec for //! docs/specs/0046-design-ledger-formal-links.md). Spec for
//! the split: docs/specs/2026-05-19-design-md-rolesplit.md. //! the split: docs/specs/0045-design-md-rolesplit.md.
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
+20 -20
View File
@@ -1,6 +1,6 @@
//! Drift detection between ast.rs and `design/contracts/data-model.md`. //! Drift detection between ast.rs and `design/contracts/0002-data-model.md`.
//! //!
//! `design/contracts/data-model.md` is the canonical schema //! `design/contracts/0002-data-model.md` is the canonical schema
//! source-of-truth. Every AST enum (`Term`, `Pattern`, `Type`, `Def`, //! source-of-truth. Every AST enum (`Term`, `Pattern`, `Type`, `Def`,
//! `Literal`, `ParamMode`) must have a JSON-schema anchor (e.g. //! `Literal`, `ParamMode`) must have a JSON-schema anchor (e.g.
//! `"t": "lit"`, `"k": "fn"`) present in that document. These tests //! `"t": "lit"`, `"k": "fn"`) present in that document. These tests
@@ -9,7 +9,7 @@
//! The exhaustive `match` per enum is the load-bearing mechanism: adding a //! The exhaustive `match` per enum is the load-bearing mechanism: adding a
//! new variant without a matching arm fails compilation before the test runs. //! new variant without a matching arm fails compilation before the test runs.
//! Once the variant is matched, the test asserts the anchor is present in //! Once the variant is matched, the test asserts the anchor is present in
//! `design/contracts/data-model.md`. The whole file is the data-model //! `design/contracts/0002-data-model.md`. The whole file is the data-model
//! contract, so the file boundary now bounds the section — the former //! contract, so the file boundary now bounds the section — the former
//! `## Data model` … `## Pipeline` slicer is no longer needed (the split //! `## Data model` … `## Pipeline` slicer is no longer needed (the split
//! gave the section its own file). //! gave the section its own file).
@@ -19,7 +19,7 @@ use ailang_core::ast::{
InstanceMethod, Literal, Pattern, ParamMode, Suppress, Term, Type, TypeDef, InstanceMethod, Literal, Pattern, ParamMode, Suppress, Term, Type, TypeDef,
}; };
const DATA_MODEL: &str = include_str!("../../../design/contracts/data-model.md"); const DATA_MODEL: &str = include_str!("../../../design/contracts/0002-data-model.md");
/// Scoped substring match: returns `true` iff `anchor` appears inside a /// Scoped substring match: returns `true` iff `anchor` appears inside a
/// fenced code block (``` or ~~~) of `md`. Info-string `jsonc` / `json` / /// fenced code block (``` or ~~~) of `md`. Info-string `jsonc` / `json` /
@@ -47,7 +47,7 @@ fn anchor_in_jsonc_block(md: &str, anchor: &str) -> bool {
} }
/// Every `Term` variant must have its JSON-schema anchor present in /// Every `Term` variant must have its JSON-schema anchor present in
/// design/contracts/data-model.md. An LLM author cannot produce a term variant /// design/contracts/0002-data-model.md. An LLM author cannot produce a term variant
/// whose `"t"` tag is absent from the canonical schema document. /// whose `"t"` tag is absent from the canonical schema document.
#[test] #[test]
fn design_md_anchors_every_term_variant() { fn design_md_anchors_every_term_variant() {
@@ -182,8 +182,8 @@ fn design_md_anchors_every_term_variant() {
}; };
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing anchor `{anchor}` for a Term variant — \ "design/contracts/0002-data-model.md is missing anchor `{anchor}` for a Term variant — \
add it to design/contracts/data-model.md" add it to design/contracts/0002-data-model.md"
); );
} }
@@ -194,14 +194,14 @@ fn design_md_anchors_every_term_variant() {
for anchor in [r#""param-types""#, r#""ret-type""#] { for anchor in [r#""param-types""#, r#""ret-type""#] {
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing Term::Lam kebab-key anchor `{anchor}` — \ "design/contracts/0002-data-model.md is missing Term::Lam kebab-key anchor `{anchor}` — \
check the `lam` fenced JSON block" check the `lam` fenced JSON block"
); );
} }
} }
/// Every `Pattern` variant must have its JSON-schema anchor present in /// Every `Pattern` variant must have its JSON-schema anchor present in
/// design/contracts/data-model.md. Missing anchors mean an LLM cannot produce /// design/contracts/0002-data-model.md. Missing anchors mean an LLM cannot produce
/// the corresponding pattern form. /// the corresponding pattern form.
#[test] #[test]
fn design_md_anchors_every_pattern_variant() { fn design_md_anchors_every_pattern_variant() {
@@ -224,13 +224,13 @@ fn design_md_anchors_every_pattern_variant() {
}; };
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing anchor `{anchor}` for a Pattern variant" "design/contracts/0002-data-model.md is missing anchor `{anchor}` for a Pattern variant"
); );
} }
} }
/// Every `Type` variant must have its JSON-schema anchor present in /// Every `Type` variant must have its JSON-schema anchor present in
/// design/contracts/data-model.md. The `"k"` discriminator is load-bearing for /// design/contracts/0002-data-model.md. The `"k"` discriminator is load-bearing for
/// the codegen and typechecker; an LLM must know all four forms. /// the codegen and typechecker; an LLM must know all four forms.
#[test] #[test]
fn design_md_anchors_every_type_variant() { fn design_md_anchors_every_type_variant() {
@@ -257,13 +257,13 @@ fn design_md_anchors_every_type_variant() {
}; };
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing anchor `{anchor}` for a Type variant" "design/contracts/0002-data-model.md is missing anchor `{anchor}` for a Type variant"
); );
} }
} }
/// Every `Literal` variant must have its JSON-schema anchor present in /// Every `Literal` variant must have its JSON-schema anchor present in
/// design/contracts/data-model.md. The `"kind"` discriminator identifies the /// design/contracts/0002-data-model.md. The `"kind"` discriminator identifies the
/// literal type; an LLM cannot produce a literal it hasn't seen in the /// literal type; an LLM cannot produce a literal it hasn't seen in the
/// schema. /// schema.
#[test] #[test]
@@ -286,13 +286,13 @@ fn design_md_anchors_every_literal_variant() {
}; };
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing anchor `{anchor}` for a Literal variant" "design/contracts/0002-data-model.md is missing anchor `{anchor}` for a Literal variant"
); );
} }
} }
/// Every `Def` kind must have its JSON-schema anchor present in /// Every `Def` kind must have its JSON-schema anchor present in
/// design/contracts/data-model.md. All five kinds (`fn`, `const`, `type`, /// design/contracts/0002-data-model.md. All five kinds (`fn`, `const`, `type`,
/// `class`, `instance`) must be documented so an LLM can write /// `class`, `instance`) must be documented so an LLM can write
/// any kind of top-level definition. /// any kind of top-level definition.
#[test] #[test]
@@ -358,13 +358,13 @@ fn design_md_anchors_every_def_kind() {
}; };
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing anchor `{anchor}` for a Def kind" "design/contracts/0002-data-model.md is missing anchor `{anchor}` for a Def kind"
); );
} }
} }
/// Every `ParamMode` variant must have its serialized string form present /// Every `ParamMode` variant must have its serialized string form present
/// in design/contracts/data-model.md. The mode annotations are load-bearing for /// in design/contracts/0002-data-model.md. The mode annotations are load-bearing for
/// ownership checking; an LLM author must know all three forms. /// ownership checking; an LLM author must know all three forms.
#[test] #[test]
fn design_md_anchors_every_parammode_variant() { fn design_md_anchors_every_parammode_variant() {
@@ -382,7 +382,7 @@ fn design_md_anchors_every_parammode_variant() {
}; };
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing anchor `{anchor}` for a ParamMode variant" "design/contracts/0002-data-model.md is missing anchor `{anchor}` for a ParamMode variant"
); );
} }
} }
@@ -502,7 +502,7 @@ fn lam_serialises_with_kebab_keys() {
); );
} }
/// Nested struct key anchors must be present in design/contracts/data-model.md. /// Nested struct key anchors must be present in design/contracts/0002-data-model.md.
/// These keys appear inside `Suppress`, `ClassMethod`, `InstanceMethod`, /// These keys appear inside `Suppress`, `ClassMethod`, `InstanceMethod`,
/// and `Type::Forall` — they are not discriminators but they ARE part /// and `Type::Forall` — they are not discriminators but they ARE part
/// of the canonical JSON schema and must remain documented. /// of the canonical JSON schema and must remain documented.
@@ -534,7 +534,7 @@ fn design_md_anchors_nested_struct_keys() {
for anchor in anchors { for anchor in anchors {
assert!( assert!(
anchor_in_jsonc_block(DATA_MODEL, anchor), anchor_in_jsonc_block(DATA_MODEL, anchor),
"design/contracts/data-model.md is missing nested-struct-key anchor `{anchor}`" "design/contracts/0002-data-model.md is missing nested-struct-key anchor `{anchor}`"
); );
} }
} }
+23 -23
View File
@@ -28,25 +28,25 @@ fn norm(s: &str) -> String {
/// The `design/` prose set the absent-pins span after the role-split /// The `design/` prose set the absent-pins span after the role-split
/// (these pins formerly scanned the single canonical design doc): the /// (these pins formerly scanned the single canonical design doc): the
/// RC + bump memory-model narrative /// RC + bump memory-model narrative
/// (`models/rc-uniqueness.md`), float semantics /// (`models/0004-rc-uniqueness.md`), float semantics
/// (`contracts/float-semantics.md`), the typeclass contract incl. /// (`contracts/0005-float-semantics.md`), the typeclass contract incl.
/// prelude classes & "does NOT commit to" /// prelude classes & "does NOT commit to"
/// (`contracts/typeclasses.md`), the effects model /// (`contracts/0013-typeclasses.md`), the effects model
/// (`models/effects.md`), and the authoring-surface notation model /// (`models/0002-effects.md`), and the authoring-surface notation model
/// (`models/authoring-surface.md`). A swept Wunschdenken / /// (`models/0001-authoring-surface.md`). A swept Wunschdenken /
/// doc-archaeology string must be absent from **all** of them, so the /// doc-archaeology string must be absent from **all** of them, so the
/// reads are joined and a single absence assertion covers the set. /// reads are joined and a single absence assertion covers the set.
fn design_corpus() -> String { fn design_corpus() -> String {
[ [
read("design/models/rc-uniqueness.md"), read("design/models/0004-rc-uniqueness.md"),
read("design/contracts/float-semantics.md"), read("design/contracts/0005-float-semantics.md"),
read("design/contracts/typeclasses.md"), read("design/contracts/0013-typeclasses.md"),
read("design/contracts/method-dispatch.md"), read("design/contracts/0016-method-dispatch.md"),
read("design/contracts/prelude-classes.md"), read("design/contracts/0017-prelude-classes.md"),
read("design/contracts/language-constraints.md"), read("design/contracts/0015-language-constraints.md"),
read("design/models/effects.md"), read("design/models/0002-effects.md"),
read("design/models/authoring-surface.md"), read("design/models/0001-authoring-surface.md"),
read("design/models/prose-projection.md"), read("design/models/0006-prose-projection.md"),
] ]
.join("\n") .join("\n")
} }
@@ -103,13 +103,13 @@ fn design_md_present_tense_anchors_present() {
// ever lived in the (now-removed) decision-records annex are // ever lived in the (now-removed) decision-records annex are
// dropped — anything the design/ ledger truly needs lives in // dropped — anything the design/ ledger truly needs lives in
// design/contracts/ or design/models/. // design/contracts/ or design/models/.
let honesty = norm(&read("design/contracts/honesty-rule.md")); let honesty = norm(&read("design/contracts/0007-honesty-rule.md"));
let scope = norm(&read("design/contracts/scope-boundaries.md")); let scope = norm(&read("design/contracts/0010-scope-boundaries.md"));
let memory = norm(&read("design/contracts/memory-model.md")); let memory = norm(&read("design/contracts/0008-memory-model.md"));
let str_abi = norm(&read("design/contracts/str-abi.md")); let str_abi = norm(&read("design/contracts/0011-str-abi.md"));
let prelude_classes = norm(&read("design/contracts/prelude-classes.md")); let prelude_classes = norm(&read("design/contracts/0017-prelude-classes.md"));
// the discriminator meta-subsection -> contracts/honesty-rule.md // the discriminator meta-subsection -> contracts/0007-honesty-rule.md
assert!(honesty.contains("the honesty rule it holds itself to"), assert!(honesty.contains("the honesty rule it holds itself to"),
"honesty-rule.md must carry the discriminator meta-subsection heading"); "honesty-rule.md must carry the discriminator meta-subsection heading");
assert!(honesty.contains("whether the document asserts something exists, works, or changed that does not"), assert!(honesty.contains("whether the document asserts something exists, works, or changed that does not"),
@@ -144,7 +144,7 @@ fn form_a_scalar_param_carveout_present_and_old_rule_absent() {
// (planner Step-5 item 6: line-wrap is structurally discharged, // (planner Step-5 item 6: line-wrap is structurally discharged,
// the substrings need not be contiguous in the .md source). // the substrings need not be contiguous in the .md source).
let f = norm(FORM_A_SPEC); let f = norm(FORM_A_SPEC);
let d = norm(&read("design/contracts/embedding-abi.md")); let d = norm(&read("design/contracts/0003-embedding-abi.md"));
// --- ABSENT: the four old unconditional phrasings must be gone --- // --- ABSENT: the four old unconditional phrasings must be gone ---
assert!(!f.contains("Mode annotations on every `(fn ...)` parameter."), assert!(!f.contains("Mode annotations on every `(fn ...)` parameter."),
@@ -166,7 +166,7 @@ fn form_a_scalar_param_carveout_present_and_old_rule_absent() {
assert!(f.contains("Putting a mode on a scalar parameter."), assert!(f.contains("Putting a mode on a scalar parameter."),
"form_a.md Pitfalls must carry the inverse pitfall — over-wrapping a scalar (site 4)"); "form_a.md Pitfalls must carry the inverse pitfall — over-wrapping a scalar (site 4)");
// --- PRESENT: the design/contracts/embedding-abi.md mirror --- // --- PRESENT: the design/contracts/0003-embedding-abi.md mirror ---
assert!(d.contains("Export parameters are written **bare**: a scalar type carries no `own`/`borrow` mode"), assert!(d.contains("Export parameters are written **bare**: a scalar type carries no `own`/`borrow` mode"),
"design/contracts/embedding-abi.md must mirror the canonical bare-scalar export-param rule"); "design/contracts/0003-embedding-abi.md must mirror the canonical bare-scalar export-param rule");
} }
@@ -25,23 +25,23 @@ fn norm(s: &str) -> String {
#[test] #[test]
fn design_md_effect_prose_is_true() { fn design_md_effect_prose_is_true() {
// Effect prose -> design/models/effects.md; the // Effect prose -> design/models/0002-effects.md; the
// "the built-in IO and Diverge ops" absent-pin's home // "the built-in IO and Diverge ops" absent-pin's home
// `## What is not (yet) supported` -> design/contracts/scope-boundaries.md. // `## What is not (yet) supported` -> design/contracts/0010-scope-boundaries.md.
let d = norm(&[read("design/models/effects.md"), let d = norm(&[read("design/models/0002-effects.md"),
read("design/contracts/scope-boundaries.md")].join("\n")); read("design/contracts/0010-scope-boundaries.md")].join("\n"));
// fiction absent // fiction absent
assert!(!d.contains("row-polymorphic"), assert!(!d.contains("row-polymorphic"),
"design/: the effect row is NOT row-polymorphic (no EffectRow / row var exists)"); "design/: the effect row is NOT row-polymorphic (no EffectRow / row var exists)");
assert!(!d.contains("`IO` and `Diverge` (for infinite"), assert!(!d.contains("`IO` and `Diverge` (for infinite"),
"design/: `Diverge` is not a wired-up MVP effect"); "design/: `Diverge` is not a wired-up MVP effect");
assert!(!d.contains("the built-in IO and Diverge ops"), assert!(!d.contains("the built-in IO and Diverge ops"),
"design/contracts/scope-boundaries.md: there is no built-in Diverge op"); "design/contracts/0010-scope-boundaries.md: there is no built-in Diverge op");
// corrected anchors present // corrected anchors present
assert!(d.contains("flat, unordered, closed set of effect names"), assert!(d.contains("flat, unordered, closed set of effect names"),
"design/models/effects.md Decision 3 must describe the real (flat set-equality) effect model"); "design/models/0002-effects.md Decision 3 must describe the real (flat set-equality) effect model");
assert!(d.contains("`Diverge` (for non-termination) is reserved"), assert!(d.contains("`Diverge` (for non-termination) is reserved"),
"design/models/effects.md Decision 3 must state Diverge is reserved/unimplemented"); "design/models/0002-effects.md Decision 3 must state Diverge is reserved/unimplemented");
} }
#[test] #[test]
+1 -1
View File
@@ -15,7 +15,7 @@
//! effects, `clone`, `reuse-as`, doc strings, type annotations on //! effects, `clone`, `reuse-as`, doc strings, type annotations on
//! signatures and lambdas, the `tail` flag) stays visible. //! signatures and lambdas, the `tail` flag) stays visible.
//! //!
//! See `design/contracts/authoring-surface.md` for the prose-surface //! See `design/contracts/0001-authoring-surface.md` for the prose-surface
//! invariants this crate must respect. //! invariants this crate must respect.
//! //!
//! # Public API //! # Public API
+1 -1
View File
@@ -4,7 +4,7 @@
//! [`ailang_core::ast::Module`] values. The JSON-AST in `ailang-core` //! [`ailang_core::ast::Module`] values. The JSON-AST in `ailang-core`
//! remains the canonical, hashable, content-addressed source of truth; //! remains the canonical, hashable, content-addressed source of truth;
//! form (A) is the AI-authoring projection optimised for token-efficient //! form (A) is the AI-authoring projection optimised for token-efficient
//! production by LLMs (see `design/contracts/authoring-surface.md`). //! production by LLMs (see `design/contracts/0001-authoring-surface.md`).
//! //!
//! ## Modules //! ## Modules
//! //!
+1 -1
View File
@@ -76,7 +76,7 @@
//! ``` //! ```
//! //!
//! Notes on the form (the binding constraints are in //! Notes on the form (the binding constraints are in
//! design/contracts/authoring-surface.md): //! design/contracts/0001-authoring-surface.md):
//! //!
//! - The `lam` form carries `param-types`, a `ret` type, and an //! - The `lam` form carries `param-types`, a `ret` type, and an
//! optional `effects` clause. The AST stores them per-lambda and //! optional `effects` clause. The AST stores them per-lambda and
+1 -1
View File
@@ -125,7 +125,7 @@ fn write_type_def(out: &mut String, td: &TypeDef, level: usize) {
} }
// `(drop-iterative)` annotation. Printed last (after // `(drop-iterative)` annotation. Printed last (after
// every ctor) so the canonical form lands consistent with the // every ctor) so the canonical form lands consistent with the
// design/contracts/data-model.md example. Omitted when `drop_iterative == false`. // design/contracts/0002-data-model.md example. Omitted when `drop_iterative == false`.
if td.drop_iterative { if td.drop_iterative {
out.push('\n'); out.push('\n');
indent(out, level + 1); indent(out, level + 1);
@@ -23,7 +23,7 @@ fn prelude_ail_json_does_not_exist_on_disk() {
re-introduced this file, you must also: (a) remove this pin, \ re-introduced this file, you must also: (a) remove this pin, \
(b) restore the §C4 (b) entry in carve_out_inventory.rs, \ (b) restore the §C4 (b) entry in carve_out_inventory.rs, \
(c) revert the §C4 (b) status marker in \ (c) revert the §C4 (b) status marker in \
docs/specs/2026-05-13-form-a-default-authoring.md, and \ docs/specs/0025-form-a-default-authoring.md, and \
(d) record the rationale in the commit body." (d) record the rationale in the commit body."
); );
} }
+2 -2
View File
@@ -7,7 +7,7 @@
//! //!
//! 1. `parse_is_deterministic_over_every_ail_fixture` — pins //! 1. `parse_is_deterministic_over_every_ail_fixture` — pins
//! **parse-determinism** (property 1 of the post-form-a Roundtrip //! **parse-determinism** (property 1 of the post-form-a Roundtrip
//! Invariant, design/contracts/roundtrip-invariant.md). For every //! Invariant, design/contracts/0009-roundtrip-invariant.md). For every
//! well-formed `.ail` text `t`, `parse(t)` produces the same //! well-formed `.ail` text `t`, `parse(t)` produces the same
//! canonical bytes every invocation. The parser is a pure //! canonical bytes every invocation. The parser is a pure
//! function of input — no randomness, no time dependence, no //! function of input — no randomness, no time dependence, no
@@ -69,7 +69,7 @@ fn list_ail_fixtures() -> Vec<PathBuf> {
} }
/// Pins **idempotency-under-print** (property 2 of the post-form-a /// Pins **idempotency-under-print** (property 2 of the post-form-a
/// Roundtrip Invariant, design/contracts/roundtrip-invariant.md): for every /// Roundtrip Invariant, design/contracts/0009-roundtrip-invariant.md): for every
/// well-formed `.ail` text `t`, the composition `parse → print → parse` /// well-formed `.ail` text `t`, the composition `parse → print → parse`
/// is idempotent on the AST. /// is idempotent on the AST.
/// ///
+25 -25
View File
@@ -36,7 +36,7 @@ evolving in lockstep with the language:
- **Surface forms** (`crates/ailang-surface`, `crates/ailang-prose`): - **Surface forms** (`crates/ailang-surface`, `crates/ailang-prose`):
the LLM-facing renderings of a module. `ailang-surface` the LLM-facing renderings of a module. `ailang-surface`
is the lossless Form-A printer/parser — the canonical is the lossless Form-A printer/parser — the canonical
[authoring surface](contracts/authoring-surface.md), with a [authoring surface](contracts/0001-authoring-surface.md), with a
round-trip property `parse ∘ print = id` gating every release. `ailang-prose` round-trip property `parse ∘ print = id` gating every release. `ailang-prose`
is the lossy Form-B projection — human-readable prose for review and is the lossy Form-B projection — human-readable prose for review and
edit, with no parser; re-integration goes through the edit, with no parser; re-integration goes through the
@@ -78,34 +78,34 @@ is the default.
## Contracts ## Contracts
| id | consumer / lifetime | ratifying-test | link | | id | consumer / lifetime | ratifying-test | link |
|----|---------------------|----------------|------| |----|---------------------|----------------|------|
| feature-acceptance | brainstorm-gate / stable | skills/brainstorm/SKILL.md | design/contracts/feature-acceptance.md | | feature-acceptance | brainstorm-gate / stable | skills/brainstorm/SKILL.md | design/contracts/0004-feature-acceptance.md |
| authoring-surface | LLM author / stable | crates/ailang-surface/tests/round_trip.rs | design/contracts/authoring-surface.md | | authoring-surface | LLM author / stable | crates/ailang-surface/tests/round_trip.rs | design/contracts/0001-authoring-surface.md |
| roundtrip-invariant | every release / stable | crates/ailang-surface/tests/round_trip.rs | design/contracts/roundtrip-invariant.md | | roundtrip-invariant | every release / stable | crates/ailang-surface/tests/round_trip.rs | design/contracts/0009-roundtrip-invariant.md |
| language-constraints | LLM author / stable | crates/ailang-check/src/uniqueness.rs (in-source mod tests) | design/contracts/language-constraints.md | | language-constraints | LLM author / stable | crates/ailang-check/src/uniqueness.rs (in-source mod tests) | design/contracts/0015-language-constraints.md |
| memory-model | LLM author / stable | crates/ailang-check/src/uniqueness.rs (in-source mod tests) | design/contracts/memory-model.md | | memory-model | LLM author / stable | crates/ailang-check/src/uniqueness.rs (in-source mod tests) | design/contracts/0008-memory-model.md |
| data-model | LLM author / stable | crates/ailang-core/tests/design_schema_drift.rs | design/contracts/data-model.md | | data-model | LLM author / stable | crates/ailang-core/tests/design_schema_drift.rs | design/contracts/0002-data-model.md |
| mangling | codegen / stable | crates/ail/tests/eq_ord_e2e.rs | crates/ailang-codegen/src/lib.rs //! | | mangling | codegen / stable | crates/ail/tests/eq_ord_e2e.rs | crates/ailang-codegen/src/lib.rs //! |
| env-construction | codegen / stable | crates/ailang-check/tests/duplicate_ctor_pin.rs | crates/ailang-codegen/src/lib.rs //! | | env-construction | codegen / stable | crates/ailang-check/tests/duplicate_ctor_pin.rs | crates/ailang-codegen/src/lib.rs //! |
| qualified-xref | codegen / stable | crates/ail/tests/codegen_import_map_fallback_pin.rs | crates/ail/src/main.rs //! | | qualified-xref | codegen / stable | crates/ail/tests/codegen_import_map_fallback_pin.rs | crates/ail/src/main.rs //! |
| frozen-value-layout | embedding ABI / one-way-frozen| crates/ailang-codegen/tests/embed_record_layout_pin.rs | design/contracts/frozen-value-layout.md + runtime/rc.c §layout | | frozen-value-layout | embedding ABI / one-way-frozen| crates/ailang-codegen/tests/embed_record_layout_pin.rs | design/contracts/0006-frozen-value-layout.md + runtime/rc.c §layout |
| float-semantics | LLM author / stable | crates/ail/tests/eq_float_noinstance.rs | design/contracts/float-semantics.md | | float-semantics | LLM author / stable | crates/ail/tests/eq_float_noinstance.rs | design/contracts/0005-float-semantics.md |
| typeclasses | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | design/contracts/typeclasses.md | | typeclasses | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | design/contracts/0013-typeclasses.md |
| method-dispatch | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | design/contracts/method-dispatch.md | | method-dispatch | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | design/contracts/0016-method-dispatch.md |
| prelude-classes | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | design/contracts/prelude-classes.md | | prelude-classes | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | design/contracts/0017-prelude-classes.md |
| str-abi | runtime ABI / stable | crates/ail/tests/e2e.rs (Str path) | design/contracts/str-abi.md + runtime/str.c §heap-Str | | str-abi | runtime ABI / stable | crates/ail/tests/e2e.rs (Str path) | design/contracts/0011-str-abi.md + runtime/str.c §heap-Str |
| tail-calls | codegen / stable | crates/ailang-check/src/lib.rs (in-source tail_call_in_non_tail_position_is_rejected) | design/contracts/tail-calls.md | | tail-calls | codegen / stable | crates/ailang-check/src/lib.rs (in-source tail_call_in_non_tail_position_is_rejected) | design/contracts/0012-tail-calls.md |
| honesty-rule | architect+grounding / stable | crates/ailang-core/tests/docs_honesty_pin.rs | design/contracts/honesty-rule.md | | honesty-rule | architect+grounding / stable | crates/ailang-core/tests/docs_honesty_pin.rs | design/contracts/0007-honesty-rule.md |
| embedding-abi | embedding host / stable | crates/ailang-codegen/tests/embed_record_layout_pin.rs | design/contracts/embedding-abi.md | | embedding-abi | embedding host / stable | crates/ailang-codegen/tests/embed_record_layout_pin.rs | design/contracts/0003-embedding-abi.md |
| scope-boundaries | architect+author / stable | crates/ailang-core/tests/effect_doc_honesty_pin.rs | design/contracts/scope-boundaries.md | | scope-boundaries | architect+author / stable | crates/ailang-core/tests/effect_doc_honesty_pin.rs | design/contracts/0010-scope-boundaries.md |
| verification | architect / stable | bench/architect_sweeps.sh | design/contracts/verification.md | | verification | architect / stable | bench/architect_sweeps.sh | design/contracts/0014-verification.md |
## Models ## Models
| id | consumer / lifetime | link | | id | consumer / lifetime | link |
|----|---------------------|------| |----|---------------------|------|
| rc-uniqueness | onboarding / evolves | design/models/rc-uniqueness.md | | rc-uniqueness | onboarding / evolves | design/models/0004-rc-uniqueness.md |
| typeclasses | onboarding / evolves | design/models/typeclasses.md | | typeclasses | onboarding / evolves | design/models/0005-typeclasses.md |
| effects | onboarding / evolves | design/models/effects.md | | effects | onboarding / evolves | design/models/0002-effects.md |
| authoring-surface | onboarding / evolves | design/models/authoring-surface.md | | authoring-surface | onboarding / evolves | design/models/0001-authoring-surface.md |
| prose-projection | onboarding / evolves | design/models/prose-projection.md | | prose-projection | onboarding / evolves | design/models/0006-prose-projection.md |
| pipeline | onboarding / evolves | design/models/pipeline.md | | pipeline | onboarding / evolves | design/models/0003-pipeline.md |
| kernel-extensions | onboarding / evolves (design accepted 2026-05-28; impl in progress) | design/models/kernel-extensions.md | | kernel-extensions | onboarding / evolves (design accepted 2026-05-28; impl in progress) | design/models/0007-kernel-extensions.md |
@@ -18,7 +18,7 @@ the same time, leaving only diagnostic helpers (`type_to_string`,
The textual surface is **not** a replacement for the JSON-AST. It is The textual surface is **not** a replacement for the JSON-AST. It is
one projection among potentially many. Concretely: one projection among potentially many. Concretely:
- The [JSON-AST](data-model.md) keeps its role as the canonical, hashable, content- - The [JSON-AST](0002-data-model.md) keeps its role as the canonical, hashable, content-
addressed representation of a module. All hashing, content- addressed representation of a module. All hashing, content-
addressing, cross-module references, and typecheck/codegen input addressing, cross-module references, and typecheck/codegen input
flow through the JSON-AST. **No new hashable form is introduced.** flow through the JSON-AST. **No new hashable form is introduced.**
@@ -55,7 +55,7 @@ the AST and remain projection-agnostic.
shape. The full bijection between `.ail.json` and `.ail` (both shape. The full bijection between `.ail.json` and `.ail` (both
directions, BLAKE3-stable hashing, Float-bits-hex encoding, directions, BLAKE3-stable hashing, Float-bits-hex encoding,
workspace-CI enforcement points) is anchored as the top-level workspace-CI enforcement points) is anchored as the top-level
[Roundtrip Invariant](roundtrip-invariant.md) — this constraint [Roundtrip Invariant](0009-roundtrip-invariant.md) — this constraint
records that the surface-design choice must satisfy that records that the surface-design choice must satisfy that
invariant; the invariant itself lives at top level because the invariant; the invariant itself lives at top level because the
property is load-bearing on the language identity, not on this property is load-bearing on the language identity, not on this
@@ -28,10 +28,10 @@ contract is what makes growing the schema cheap.
are real surface forms. Class and type cross-module references are real surface forms. Class and type cross-module references
(canonical-form rule, qualified `<module>.<Class>` / (canonical-form rule, qualified `<module>.<Class>` /
`<module>.<TypeName>`) follow the scoping rule in `<module>.<TypeName>`) follow the scoping rule in
[memory model](memory-model.md); the `class`/`instance` schema [memory model](0008-memory-model.md); the `class`/`instance` schema
narrative — defaults, superclasses, diagnostics — lives in narrative — defaults, superclasses, diagnostics — lives in
[typeclasses](typeclasses.md). Exported `fn` defs interact with [typeclasses](0013-typeclasses.md). Exported `fn` defs interact with
[embedding ABI](embedding-abi.md). [embedding ABI](0003-embedding-abi.md).
```jsonc ```jsonc
// fn (the unit that gets a content hash) // fn (the unit that gets a content hash)
@@ -65,7 +65,7 @@ narrative — defaults, superclasses, diagnostics — lives in
"drop-iterative": true // opt-in; omitted when false (hash-stable when omitted) "drop-iterative": true // opt-in; omitted when false (hash-stable when omitted)
} }
// class (typeclass declaration; narrative in contracts/typeclasses.md) // class (typeclass declaration; narrative in contracts/0013-typeclasses.md)
{ "kind": "class", { "kind": "class",
"name": "<id>", // class name (e.g. "Show") "name": "<id>", // class name (e.g. "Show")
"param": "<id>", // single class parameter, kind * "param": "<id>", // single class parameter, kind *
@@ -80,7 +80,7 @@ narrative — defaults, superclasses, diagnostics — lives in
"doc": "<optional string>" "doc": "<optional string>"
} }
// instance (typeclass instance; narrative in contracts/typeclasses.md) // instance (typeclass instance; narrative in contracts/0013-typeclasses.md)
{ "kind": "instance", { "kind": "instance",
"class": "<id>", // class being instantiated; canonical form (bare for same-module, "<module>.<Class>" for cross-module) "class": "<id>", // class being instantiated; canonical form (bare for same-module, "<module>.<Class>" for cross-module)
"type": Type, // concrete type expression (never the class param) "type": Type, // concrete type expression (never the class param)
@@ -165,7 +165,7 @@ narrative — defaults, superclasses, diagnostics — lives in
// non-`recur` branch. Strictly additive (no `skip_serializing_if`; // non-`recur` branch. Strictly additive (no `skip_serializing_if`;
// pre-existing fixtures hash bit-identically — none carry the tag). // pre-existing fixtures hash bit-identically — none carry the tag).
// No totality claim — an infinite loop is legal. See // No totality claim — an infinite loop is legal. See
// `docs/specs/2026-05-17-loop-recur.md`. // `docs/specs/0034-loop-recur.md`.
{ "t": "loop", { "t": "loop",
"binders": [ { "name": "<id>", "type": Type, "init": Term }, ... ], "binders": [ { "name": "<id>", "type": Type, "init": Term }, ... ],
"body": Term } "body": Term }
@@ -179,7 +179,7 @@ narrative — defaults, superclasses, diagnostics — lives in
``` ```
In the MVP, `do` is only a direct call to a built-in effect op (no In the MVP, `do` is only a direct call to a built-in effect op (no
handler); the effect system is described in [effects](../models/effects.md). handler); the effect system is described in [effects](../models/0002-effects.md).
A `lam` term constructs an anonymous function value; free A `lam` term constructs an anonymous function value; free
variables of its body are captured from the enclosing scope. variables of its body are captured from the enclosing scope.
@@ -188,7 +188,7 @@ ordinary local scope plus a positional `loop_stack`, and codegen
lowers them as entry-block allocas. Capturing a `loop` binder into a lowers them as entry-block allocas. Capturing a `loop` binder into a
lambda body is rejected at typecheck via lambda body is rejected at typecheck via
`CheckError::LoopBinderCapturedByLambda`. See `CheckError::LoopBinderCapturedByLambda`. See
`docs/specs/2026-05-17-loop-recur.md`. `docs/specs/0034-loop-recur.md`.
**`Literal`**: **`Literal`**:
@@ -215,7 +215,7 @@ Patterns are linear: each pattern variable may appear at most once.
The `Type::Con.name` canonical-form rule (bare for same-module / The `Type::Con.name` canonical-form rule (bare for same-module /
primitives, qualified `<module>.<TypeName>` for cross-module) lives primitives, qualified `<module>.<TypeName>` for cross-module) lives
in [memory model](memory-model.md); `Type::Fn`'s parameter-mode in [memory model](0008-memory-model.md); `Type::Fn`'s parameter-mode
metadata is defined and gated there as well. metadata is defined and gated there as well.
```jsonc ```jsonc
@@ -228,7 +228,7 @@ metadata is defined and gated there as well.
// in the typechecker (unify, occurs, apply) keeps working. // in the typechecker (unify, occurs, apply) keeps working.
// `paramModes` omitted when every entry is "implicit"; `retMode` // `paramModes` omitted when every entry is "implicit"; `retMode`
// omitted when "implicit" (hash-stable when omitted). Full mode // omitted when "implicit" (hash-stable when omitted). Full mode
// contract lives in contracts/memory-model.md. // contract lives in contracts/0008-memory-model.md.
{ "k": "fn", { "k": "fn",
"params": [Type...], "params": [Type...],
"paramModes": [ParamMode...], "paramModes": [ParamMode...],
@@ -239,7 +239,7 @@ metadata is defined and gated there as well.
{ "k": "var", "name": "<id>" } { "k": "var", "name": "<id>" }
// Top-level polymorphism only. `constraints` carries class // Top-level polymorphism only. `constraints` carries class
// constraints (narrative in contracts/typeclasses.md); omitted when // constraints (narrative in contracts/0013-typeclasses.md); omitted when
// empty (hash-stable when omitted). // empty (hash-stable when omitted).
{ "k": "forall", { "k": "forall",
"vars": ["<id>"...], "vars": ["<id>"...],
@@ -248,7 +248,7 @@ metadata is defined and gated there as well.
``` ```
**`ParamMode`** (full contract in **`ParamMode`** (full contract in
[memory model](memory-model.md)): [memory model](0008-memory-model.md)):
``` ```
"implicit" — unannotated / back-compat. Treated as `own` by the typechecker. "implicit" — unannotated / back-compat. Treated as `own` by the typechecker.
@@ -260,8 +260,8 @@ metadata is defined and gated there as well.
unannotated fixtures continue to serialize without the mode wrapper and keep their unannotated fixtures continue to serialize without the mode wrapper and keep their
canonical-JSON hash. The full mode contract (codegen consequences, canonical-JSON hash. The full mode contract (codegen consequences,
the over-strict-mode lint, the `Suppress` mechanism) lives in the over-strict-mode lint, the `Suppress` mechanism) lives in
[memory model](memory-model.md); the four language-design [memory model](0008-memory-model.md); the four language-design
preconditions that make RC sound live in preconditions that make RC sound live in
[language constraints](language-constraints.md). [language constraints](0015-language-constraints.md).
Ratified by: `crates/ailang-core/tests/design_schema_drift.rs`. Ratified by: `crates/ailang-core/tests/design_schema_drift.rs`.
@@ -44,12 +44,12 @@ The staticlib swarm artefact is **RC-only**:
stub is leak-only and not swarm-safe; `--alloc=gc` no longer stub is leak-only and not swarm-safe; `--alloc=gc` no longer
exists as a CLI value — see the Boehm-retirement iter). The exists as a CLI value — see the Boehm-retirement iter). The
value/record value/record
layout is **frozen as of M3** (see [Frozen value layout](frozen-value-layout.md)); the layout is **frozen as of M3** (see [Frozen value layout](0006-frozen-value-layout.md)); the
ctx-threaded C signature is the M2 shape. ctx-threaded C signature is the M2 shape.
Export parameters are written **bare**: a scalar type carries no Export parameters are written **bare**: a scalar type carries no
`own`/`borrow` mode (a single-constructor record export parameter, `own`/`borrow` mode (a single-constructor record export parameter,
by contrast, carries `own`/`borrow` — see [memory model](memory-model.md) by contrast, carries `own`/`borrow` — see [memory model](0008-memory-model.md)
for the full ownership contract; the for the full ownership contract; the
frozen value layout below specifies how that contract lands at the C ABI). The frozen value layout below specifies how that contract lands at the C ABI). The
canonical M1 export shape: canonical M1 export shape:
@@ -30,7 +30,7 @@ A proposed feature ships only if all three hold:
question is whether the construct re-opens a class of mistakes question is whether the construct re-opens a class of mistakes
(iterated-mutable-state reasoning, silently-unbounded recursion, (iterated-mutable-state reasoning, silently-unbounded recursion,
reference cycles) that a foundational invariant — see reference cycles) that a foundational invariant — see
[language constraints](language-constraints.md) — closes. If it does, [language constraints](0015-language-constraints.md) — closes. If it does,
it is cut even when 1 and 2 hold — *or* it must be reshaped until it is cut even when 1 and 2 hold — *or* it must be reshaped until
the bug class is structurally impossible rather than merely the bug class is structurally impossible rather than merely
discouraged. A documentation note is not a reshape; the discouraged. A documentation note is not a reshape; the
@@ -44,7 +44,7 @@ A proposed feature ships only if all three hold:
built without a documented-unenforced precondition*, pass all built without a documented-unenforced precondition*, pass all
three — and the fact that the 2026-05 attempt could not (it three — and the fact that the 2026-05 attempt could not (it
forced a silent-divergence precondition; see forced a silent-divergence precondition; see
`docs/specs/2026-05-16-iteration-discipline-revert.md`) is itself `docs/specs/0032-iteration-discipline-revert.md`) is itself
the bug-class-reintroduction discriminator working as intended. the bug-class-reintroduction discriminator working as intended.
This is the positive complement to the CLAUDE.md rule that This is the positive complement to the CLAUDE.md rule that
@@ -12,7 +12,7 @@ no `f32` variant. The runtime / codegen contract:
fmul / fdiv double`, `fneg double`. Float comparison goes through fmul / fdiv double`, `fneg double`. Float comparison goes through
the named prelude fns `float_eq` / `float_ne` / `float_lt` / the named prelude fns `float_eq` / `float_ne` / `float_lt` /
`float_le` / `float_gt` / `float_ge` (Float has no Eq/Ord instance `float_le` / `float_gt` / `float_ge` (Float has no Eq/Ord instance
— see [Prelude (built-in) classes](prelude-classes.md)); each fn — see [Prelude (built-in) classes](0017-prelude-classes.md)); each fn
lowers to a single `fcmp` instruction (`oeq` / `une` / `olt` / lowers to a single `fcmp` instruction (`oeq` / `une` / `olt` /
`ole` / `ogt` / `oge` respectively) via the codegen intercept `ole` / `ogt` / `oge` respectively) via the codegen intercept
`try_emit_primitive_instance_body`, with the `alwaysinline` `try_emit_primitive_instance_body`, with the `alwaysinline`
@@ -73,7 +73,7 @@ no `f32` variant. The runtime / codegen contract:
The same libc-`%g` rendering applies to `show 1.5` / `show nan` / The same libc-`%g` rendering applies to `show 1.5` / `show nan` /
`show inf` via `instance Show Float` (which calls `float_to_str` `show inf` via `instance Show Float` (which calls `float_to_str`
internally — see [Prelude (built-in) classes](prelude-classes.md) for the Show ship). internally — see [Prelude (built-in) classes](0017-prelude-classes.md) for the Show ship).
The NaN-spelling caveat above is observable via `do print x` for The NaN-spelling caveat above is observable via `do print x` for
Float-typed `x`; the rendering is libc-version-dependent and Float-typed `x`; the rendering is libc-version-dependent and
target-libc-specific. AILang does NOT canonicalise Float textual target-libc-specific. AILang does NOT canonicalise Float textual
@@ -91,15 +91,15 @@ use case appears.
**Form-A serialisation:** Float literals carry the IEEE-754 **Form-A serialisation:** Float literals carry the IEEE-754
bit pattern as a 16-character lowercase hex string in the canonical bit pattern as a 16-character lowercase hex string in the canonical
JSON: `{"kind":"float","bits":"<16-hex>"}` (see JSON: `{"kind":"float","bits":"<16-hex>"}` (see
[Data model](data-model.md) for the literal schema). Routing through the [Data model](0002-data-model.md) for the literal schema). Routing through the
JSON *string* path (not `serde_json::Number`) preserves bit JSON *string* path (not `serde_json::Number`) preserves bit
stability across `serde_json` versions and lets NaN / ±Inf stability across `serde_json` versions and lets NaN / ±Inf
round-trip through Form-A — JSON numbers cannot represent them. round-trip through Form-A — JSON numbers cannot represent them.
This bits-hex encoding is what keeps Floats inside the This bits-hex encoding is what keeps Floats inside the
[Roundtrip Invariant](roundtrip-invariant.md). [Roundtrip Invariant](0009-roundtrip-invariant.md).
**Pattern matching:** `Pattern::Lit` on `Literal::Float` (see **Pattern matching:** `Pattern::Lit` on `Literal::Float` (see
[Data model](data-model.md) for the pattern schema) is hard- [Data model](0002-data-model.md) for the pattern schema) is hard-
rejected at typecheck (`CheckError::FloatPatternNotAllowed`). IEEE rejected at typecheck (`CheckError::FloatPatternNotAllowed`). IEEE
semantics make Float patterns semantically dubious — NaN never semantics make Float patterns semantically dubious — NaN never
matches via `float_eq` (its `fcmp oeq` lowering is `false` for matches via `float_eq` (its `fcmp oeq` lowering is `false` for
@@ -109,7 +109,7 @@ Use the explicit comparison fns (`float_lt`, `float_gt`, ...) and
`float_to_str` (Float → Str) and `int_to_str` (Int → Str) are `float_to_str` (Float → Str) and `int_to_str` (Int → Str) are
fully wired through checker, codegen, and runtime. Both allocate fully wired through checker, codegen, and runtime. Both allocate
a fresh heap-Str slab at the call site (see [Str ABI](str-abi.md) a fresh heap-Str slab at the call site (see [Str ABI](0011-str-abi.md)
for the dual realisation) and carry `ret_mode: Own` so the let-binder for the dual realisation) and carry `ret_mode: Own` so the let-binder
for the call result is RC-tracked and the slab is freed at scope for the call result is RC-tracked and the slab is freed at scope
close. close.
@@ -4,7 +4,7 @@
For a single-constructor `data T` whose `n` fields are each `Int` For a single-constructor `data T` whose `n` fields are each `Int`
or `Float`, a value of `T` crossing the or `Float`, a value of `T` crossing the
[embedding C boundary](embedding-abi.md) is a [embedding C boundary](0003-embedding-abi.md) is a
bare payload pointer `p`: bare payload pointer `p`:
| bytes | content | | bytes | content |
@@ -29,7 +29,7 @@ offsets above. A raw `malloc` is a contract violation:
header at `p - 8` initialised to `1`. header at `p - 8` initialised to `1`.
**Ownership follows the declared mode** (the **Ownership follows the declared mode** (the
[Mode metadata is load-bearing for codegen](memory-model.md) [Mode metadata is load-bearing for codegen](0008-memory-model.md)
contract, as the C ABI): a `(own (con contract, as the C ABI): a `(own (con
T))` parameter transfers ownership in — the kernel consumes it T))` parameter transfers ownership in — the kernel consumes it
(Iter-B drop-at-return); the host MUST NOT touch or `dec` it after (Iter-B drop-at-return); the host MUST NOT touch or `dec` it after
@@ -3,16 +3,16 @@
The four language-design constraints that make RC sound without a The four language-design constraints that make RC sound without a
cycle-collector backstop (strict evaluation, no recursive value cycle-collector backstop (strict evaluation, no recursive value
bindings, no shared mutable refs, acyclic ADTs) live in bindings, no shared mutable refs, acyclic ADTs) live in
[language constraints](language-constraints.md); this file covers [language constraints](0015-language-constraints.md); this file covers
the schema additions, advisory diagnostics, and codegen contract the schema additions, advisory diagnostics, and codegen contract
that build on them. that build on them.
## Schema additions ## Schema additions
**Parameter modes on `Type::Fn`** (see [Data model](data-model.md) **Parameter modes on `Type::Fn`** (see [Data model](0002-data-model.md)
for the schema-level definition of `Type::Fn`). for the schema-level definition of `Type::Fn`).
The form-A surface (see [authoring surface](authoring-surface.md)) The form-A surface (see [authoring surface](0001-authoring-surface.md))
for fn signatures gains mode wrappers: for fn signatures gains mode wrappers:
``` ```
@@ -22,7 +22,7 @@ for fn signatures gains mode wrappers:
Internally, this is *not* a new `Type` variant. Modes are Internally, this is *not* a new `Type` variant. Modes are
metadata on `Type::Fn``paramModes` and `retMode` fields run metadata on `Type::Fn``paramModes` and `retMode` fields run
parallel to `params` and `ret` (see [Data model](data-model.md) for the JSON parallel to `params` and `ret` (see [Data model](0002-data-model.md) for the JSON
schema). The substantive reasons for per-position metadata over a schema). The substantive reasons for per-position metadata over a
`Type::Borrow` / `Type::Own` variant approach: `Type::Borrow` / `Type::Own` variant approach:
@@ -33,7 +33,7 @@ schema). The substantive reasons for per-position metadata over a
`(con List (borrow Int))` — syntactically possible, semantically `(con List (borrow Int))` — syntactically possible, semantically
meaningless (you cannot separately own/borrow a list element meaningless (you cannot separately own/borrow a list element
from the list it lives in). The from the list it lives in). The
[canonical-schema principle](data-model.md) is "schema = data, [canonical-schema principle](0002-data-model.md) is "schema = data,
schema permits exactly what is meaningful"; per-position schema permits exactly what is meaningful"; per-position
metadata is the option that holds that line. metadata is the option that holds that line.
- **Compositional clarity.** A `Type` value's identity should - **Compositional clarity.** A `Type` value's identity should
@@ -85,7 +85,7 @@ Three schema fields carry class references in this form:
`TypeDef.name`). `TypeDef.name`).
Method dispatch is type-driven (see Method dispatch is type-driven (see
[Method dispatch](method-dispatch.md)): [Method dispatch](0016-method-dispatch.md)):
synth resolves a `Term::Var { name: "show" }` by consulting synth resolves a `Term::Var { name: "show" }` by consulting
the workspace's method-to-candidate-class index, filtering by the workspace's method-to-candidate-class index, filtering by
argument type (concrete) or by declared constraint (rigid-var), and argument type (concrete) or by declared constraint (rigid-var), and
@@ -150,7 +150,7 @@ until the fixture intentionally adopts the feature.
**`FnDef.suppress`.** The `suppress` field on `FnDef` carries a **`FnDef.suppress`.** The `suppress` field on `FnDef` carries a
list of advisory-diagnostic suppress entries; each entry has a list of advisory-diagnostic suppress entries; each entry has a
`code` (the diagnostic being suppressed) and a `because` (a `code` (the diagnostic being suppressed) and a `because` (a
mandatory non-empty reason). See [Data model](data-model.md) for mandatory non-empty reason). See [Data model](0002-data-model.md) for
the canonical schema. the canonical schema.
Form-A surface: `(suppress (code "...") (because "..."))` clause Form-A surface: `(suppress (code "...") (because "..."))` clause
@@ -4,8 +4,8 @@
Every well-formed AILang module has a canonical `.ail.json` Every well-formed AILang module has a canonical `.ail.json`
representation (the hashable, content-addressed representation (the hashable, content-addressed
[JSON-AST](data-model.md)) and a hand-authored `.ail` representation [JSON-AST](0002-data-model.md)) and a hand-authored `.ail` representation
(Form A, the [authoring projection](authoring-surface.md)). The (Form A, the [authoring projection](0001-authoring-surface.md)). The
JSON-AST is derived from `.ail` in-process by consumers that need JSON-AST is derived from `.ail` in-process by consumers that need
it; the round-trip is now the *property* of that derivation, not it; the round-trip is now the *property* of that derivation, not
the byte-level agreement of two on-disk forms. the byte-level agreement of two on-disk forms.
@@ -47,7 +47,7 @@ approximation. The canonical encoding is
`{"kind":"float","bits":"<16-lowercase-hex>"}` and the surface `{"kind":"float","bits":"<16-lowercase-hex>"}` and the surface
emits the same bits-hex string. NaN, ±Inf, signed zero, and subnormals all emits the same bits-hex string. NaN, ±Inf, signed zero, and subnormals all
round-trip exactly because the JSON-number path is bypassed (see round-trip exactly because the JSON-number path is bypassed (see
[Float semantics](float-semantics.md), "Form-A serialisation"). [Float semantics](0005-float-semantics.md), "Form-A serialisation").
Floats are not an exception to the invariant — the bits-hex Floats are not an exception to the invariant — the bits-hex
encoding is the mechanism that keeps them *inside* it. encoding is the mechanism that keeps them *inside* it.
@@ -85,7 +85,7 @@ never by relaxing the test.
### Why this is anchored at top level ### Why this is anchored at top level
The invariant is a property of the language identity, not of any The invariant is a property of the language identity, not of any
one surface-design choice. The [authoring surface](authoring-surface.md) one surface-design choice. The [authoring surface](0001-authoring-surface.md)
introduces the `.ail` surface and lists round-trip-as-property as introduces the `.ail` surface and lists round-trip-as-property as
one of its constraints, but the property is load-bearing for every one of its constraints, but the property is load-bearing for every
downstream concern that treats the two forms as exchangeable: downstream concern that treats the two forms as exchangeable:
@@ -5,12 +5,12 @@
Snapshot of the current boundary. Snapshot of the current boundary.
- No effect handlers — only the built-in `IO` op (`io/print_str`); - No effect handlers — only the built-in `IO` op (`io/print_str`);
the effect system is described in [effects](../models/effects.md). the effect system is described in [effects](../models/0002-effects.md).
`Diverge` is a reserved effect name with no op and no codegen. `Diverge` is a reserved effect name with no op and no codegen.
- No refinements / SMT escalation. - No refinements / SMT escalation.
- No HM inference inside bodies. Top-level def types are explicit; - No HM inference inside bodies. Top-level def types are explicit;
polymorphism is opt-in via `Type::Forall { vars, body }` (see polymorphism is opt-in via `Type::Forall { vars, body }` (see
[Data model](data-model.md)). Inside a body, lambdas check [Data model](0002-data-model.md)). Inside a body, lambdas check
monomorphically against their declared type. monomorphically against their declared type.
- Polymorphic fns must be **directly called** at the use site. - Polymorphic fns must be **directly called** at the use site.
Passing a polymorphic fn as a value (`let f = id in f(42)`) is Passing a polymorphic fn as a value (`let f = id in f(42)`) is
@@ -20,11 +20,11 @@ Snapshot of the current boundary.
- No recursive `let` for non-fn values. Plain `let x = … in …` only - No recursive `let` for non-fn values. Plain `let x = … in …` only
sees `x` inside the body, not inside its own RHS — recursive value sees `x` inside the body, not inside its own RHS — recursive value
bindings would break the bindings would break the
[acyclicity invariant](language-constraints.md). Recursive [acyclicity invariant](0015-language-constraints.md). Recursive
*fn* bindings are supported via `Term::LetRec` (`{ "t": "letrec", *fn* bindings are supported via `Term::LetRec` (`{ "t": "letrec",
... }`); the desugar pass lifts most occurrences to a synthetic ... }`); the desugar pass lifts most occurrences to a synthetic
top-level fn, with `lift_letrecs` finishing the residue after top-level fn, with `lift_letrecs` finishing the residue after
typecheck (see [pipeline](../models/pipeline.md)). typecheck (see [pipeline](../models/0003-pipeline.md)).
- No visibility rules in imports. Every top-level def of an imported module - No visibility rules in imports. Every top-level def of an imported module
is reachable; there is no `pub` / `priv`. is reachable; there is no `pub` / `priv`.
@@ -34,7 +34,7 @@ What **is** supported (and used as the smoke test for the pipeline):
- `if`, `let`, function calls, recursion. - `if`, `let`, function calls, recursion.
- Effects on function signatures, with `do op(args)` for direct effect - Effects on function signatures, with `do op(args)` for direct effect
ops (`io/print_str`). The polymorphic `print` (see ops (`io/print_str`). The polymorphic `print` (see
[prelude classes](prelude-classes.md)) is the canonical output [prelude classes](0017-prelude-classes.md)) is the canonical output
path for non-Str values. path for non-Str values.
- **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`) of type - **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`) of type
`forall a. (a, a) -> a` (codegen-restricted to `{Int, Float}`); `forall a. (a, a) -> a` (codegen-restricted to `{Int, Float}`);
@@ -47,7 +47,7 @@ What **is** supported (and used as the smoke test for the pipeline):
`float_to_int_truncate : (Float) -> Int` (saturating, NaN → 0), `float_to_int_truncate : (Float) -> Int` (saturating, NaN → 0),
`float_to_str : (Float) -> Str`, `float_to_str : (Float) -> Str`,
`int_to_str : (Int) -> Str` (both allocate a heap-Str slab at `int_to_str : (Int) -> Str` (both allocate a heap-Str slab at
call time and return it with `ret_mode: Own`; see [Str ABI](str-abi.md) for call time and return it with `ret_mode: Own`; see [Str ABI](0011-str-abi.md) for
the dual heap-/static-Str realisation); inspection the dual heap-/static-Str realisation); inspection
`is_nan : (Float) -> Bool` (LLVM `is_nan : (Float) -> Bool` (LLVM
`fcmp uno`); Float bit-pattern constants `nan : Float`, `fcmp uno`); Float bit-pattern constants `nan : Float`,
@@ -69,7 +69,7 @@ What **is** supported (and used as the smoke test for the pipeline):
ctor; every primitive instance body carries the ctor; every primitive instance body carries the
`alwaysinline` attribute so the call folds at every use site. `alwaysinline` attribute so the call folds at every use site.
Float has no Eq / Ord instance (see Float has no Eq / Ord instance (see
[Float semantics](float-semantics.md)); explicit comparison [Float semantics](0005-float-semantics.md)); explicit comparison
is via the named fns `float_eq` / `float_ne` / `float_lt` / is via the named fns `float_eq` / `float_ne` / `float_lt` /
`float_le` / `float_gt` / `float_ge`, each lowering to a `float_le` / `float_gt` / `float_ge`, each lowering to a
single `fcmp` with the matching predicate. `float_ne` uses single `fcmp` with the matching predicate. `float_ne` uses
@@ -92,7 +92,7 @@ What **is** supported (and used as the smoke test for the pipeline):
`Pattern::Lit` (top-level or sub-) to a `Term::If` on `eq` (the `Pattern::Lit` (top-level or sub-) to a `Term::If` on `eq` (the
class method `prelude.Eq.eq`) before typecheck/codegen — see class method `prelude.Eq.eq`) before typecheck/codegen — see
[desugar](../../crates/ailang-core/src/desugar.rs) and [desugar](../../crates/ailang-core/src/desugar.rs) and
[Pipeline](../models/pipeline.md). [Pipeline](../models/0003-pipeline.md).
- Literal patterns at top level and inside Ctor sub-patterns (via desugar). - Literal patterns at top level and inside Ctor sub-patterns (via desugar).
`(pat-lit 0)` and `(pat-ctor Cons (pat-lit 0) _)` both `(pat-lit 0)` and `(pat-ctor Cons (pat-lit 0) _)` both
parse and lower; the rewrite is to `Term::If { cond = (eq sv lit) }`, parse and lower; the rewrite is to `Term::If { cond = (eq sv lit) }`,
@@ -100,7 +100,7 @@ What **is** supported (and used as the smoke test for the pipeline):
primitive Eq instance is authorable. The primitive instances primitive Eq instance is authorable. The primitive instances
cover `Int` / `Bool` / `Str` / `Unit`; `Float` lit-patterns are cover `Int` / `Bool` / `Str` / `Unit`; `Float` lit-patterns are
hard-rejected at typecheck (`CheckError::FloatPatternNotAllowed`, hard-rejected at typecheck (`CheckError::FloatPatternNotAllowed`,
see [float-semantics](float-semantics.md)). `(pat-lit "hi")` over see [float-semantics](0005-float-semantics.md)). `(pat-lit "hi")` over
a `Str` scrutinee is exercised by `examples/eq_demo.ail.json`. a `Str` scrutinee is exercised by `examples/eq_demo.ail.json`.
- **Imports + qualified cross-module references** via dotted names. - **Imports + qualified cross-module references** via dotted names.
Extends to **types and constructors**: a foreign Extends to **types and constructors**: a foreign
@@ -109,7 +109,7 @@ What **is** supported (and used as the smoke test for the pipeline):
inside that scrutinee. Std-library demos (`examples/std_*_demo.ail.json`) inside that scrutinee. Std-library demos (`examples/std_*_demo.ail.json`)
exercise this end-to-end. exercise this end-to-end.
- **AI-authoring text surface, form (A)** (see - **AI-authoring text surface, form (A)** (see
[authoring surface](authoring-surface.md)). The `ailang-surface` [authoring surface](0001-authoring-surface.md)). The `ailang-surface`
crate parses `.ail` form-A text into a canonical crate parses `.ail` form-A text into a canonical
`ailang-core::ast::Module` and prints any module back as form-A `ailang-core::ast::Module` and prints any module back as form-A
text. `ail render` and `ail describe` use it as the text. `ail render` and `ail describe` use it as the
@@ -117,7 +117,7 @@ What **is** supported (and used as the smoke test for the pipeline):
identity (text → AST → JSON → AST → text) is gated by identity (text → AST → JSON → AST → text) is gated by
`ailang-surface/tests/round_trip.rs` over every shipped fixture. `ailang-surface/tests/round_trip.rs` over every shipped fixture.
- **Memory management via reference counting + uniqueness inference** - **Memory management via reference counting + uniqueness inference**
(see [RC + uniqueness](../models/rc-uniqueness.md)), with (see [RC + uniqueness](../models/0004-rc-uniqueness.md)), with
**per-fn arena via stack `alloca` for non-escaping allocations** **per-fn arena via stack `alloca` for non-escaping allocations**
layered on top. Every ADT box, lambda env, and closure pair layered on top. Every ADT box, lambda env, and closure pair
allocates either via `@ailang_rc_alloc` (escaping; RC-managed allocates either via `@ailang_rc_alloc` (escaping; RC-managed
@@ -125,7 +125,7 @@ What **is** supported (and used as the smoke test for the pipeline):
`alloca` (non-escaping; freed at fn return). The decision is `alloca` (non-escaping; freed at fn return). The decision is
made by an escape-analysis pre-pass over the fn body — see the made by an escape-analysis pre-pass over the fn body — see the
"Per-fn arena via stack `alloca`" subsection of "Per-fn arena via stack `alloca`" subsection of
[RC + uniqueness](../models/rc-uniqueness.md). The per-fn-arena [RC + uniqueness](../models/0004-rc-uniqueness.md). The per-fn-arena
path is exercised end-to-end by path is exercised end-to-end by
`examples/escape_local_demo.ail.json`. `examples/escape_local_demo.ail.json`.
- **First-class function references.** A top-level fn name (or - **First-class function references.** A top-level fn name (or
@@ -13,14 +13,14 @@ and backed by a `runtime/str.c` C helper.
- `int_to_str : (borrow Int) -> Str` — decimal rendering - `int_to_str : (borrow Int) -> Str` — decimal rendering
of an `Int`. Backs `Show Int` in the of an `Int`. Backs `Show Int` in the
[prelude](prelude-classes.md). [prelude](0017-prelude-classes.md).
- `bool_to_str : (borrow Bool) -> Str``"true"`/`"false"`. - `bool_to_str : (borrow Bool) -> Str``"true"`/`"false"`.
Backs `Show Bool` in the [prelude](prelude-classes.md). Backs `Show Bool` in the [prelude](0017-prelude-classes.md).
- `float_to_str : (borrow Float) -> Str` - `float_to_str : (borrow Float) -> Str`
type-installed; codegen is reserved and not yet shipped. type-installed; codegen is reserved and not yet shipped.
- `str_clone : (borrow Str) -> Str` — allocates a fresh - `str_clone : (borrow Str) -> Str` — allocates a fresh
heap-Str copy of the input's bytes. Backs `Show Str` in the heap-Str copy of the input's bytes. Backs `Show Str` in the
[prelude](prelude-classes.md). [prelude](0017-prelude-classes.md).
- `str_concat : (borrow Str, borrow Str) -> Str` — combines two `Str` - `str_concat : (borrow Str, borrow Str) -> Str` — combines two `Str`
values into a single owned `Str`. values into a single owned `Str`.
General-purpose; commonly used in Show bodies for labelled output General-purpose; commonly used in Show bodies for labelled output
@@ -34,7 +34,7 @@ instance body that wants to combine fragments.
Primitive output for `Str` values goes through `io/print_str` Primitive output for `Str` values goes through `io/print_str`
directly; values of other primitive types route through the directly; values of other primitive types route through the
polymorphic `print` helper (see [prelude classes](prelude-classes.md)), polymorphic `print` helper (see [prelude classes](0017-prelude-classes.md)),
which feeds the heap-Str result of `show x` into `io/print_str`. which feeds the heap-Str result of `show x` into `io/print_str`.
Equality on `Str` dispatches via `prelude.Eq.eq` (Str instance, Equality on `Str` dispatches via `prelude.Eq.eq` (Str instance,
@@ -70,7 +70,7 @@ implicit trailing newline (Gitea #29; the earlier `@puts` lowering
appended a newline per call). appended a newline per call).
The heap-Str realisation participates in standard RC (see The heap-Str realisation participates in standard RC (see
[memory model](memory-model.md)): the [memory model](0008-memory-model.md)): the
`rc_header` slot eight bytes before the `len` field is managed `rc_header` slot eight bytes before the `len` field is managed
by `ailang_rc_alloc` / `ailang_rc_inc` / `ailang_rc_dec` exactly by `ailang_rc_alloc` / `ailang_rc_inc` / `ailang_rc_dec` exactly
like any other RC-allocated cell. The static-Str realisation has like any other RC-allocated cell. The static-Str realisation has
@@ -13,7 +13,7 @@ Solution: explicit, verified tail calls.
- **AST.** `Term::App { fn, args, tail: bool }` and - **AST.** `Term::App { fn, args, tail: bool }` and
`Term::Do { op, args, tail: bool }` (see `Term::Do { op, args, tail: bool }` (see
[Data model](data-model.md)) gain a `tail` flag, [Data model](0002-data-model.md)) gain a `tail` flag,
serde-defaulting to `false` so existing fixtures load with serde-defaulting to `false` so existing fixtures load with
`tail: false` and their hashes stay bit-identical. `tail: false` and their hashes stay bit-identical.
- **Typecheck.** A new pass `verify_tail_positions(fn_body)` - **Typecheck.** A new pass `verify_tail_positions(fn_body)`
@@ -39,7 +39,7 @@ Solution: explicit, verified tail calls.
`tail: true` set on the resulting term. EBNF gains 2 lines; `tail: true` set on the resulting term. EBNF gains 2 lines;
total production count goes from ~28 to ~30, still inside total production count goes from ~28 to ~30, still inside
the constraint-1 budget (see the constraint-1 budget (see
[authoring surface](authoring-surface.md)). [authoring surface](0001-authoring-surface.md)).
**What this does NOT promise.** Per the tail-call survey of existing fixtures, **What this does NOT promise.** Per the tail-call survey of existing fixtures,
many existing recursive calls are *not* in tail position many existing recursive calls are *not* in tail position
@@ -2,16 +2,16 @@
The schema, registry, and diagnostic contract for the typeclass The schema, registry, and diagnostic contract for the typeclass
layer. The resolution/monomorphisation whitepaper lives at layer. The resolution/monomorphisation whitepaper lives at
[models/typeclasses](../models/typeclasses.md); the call-site [models/typeclasses](../models/0005-typeclasses.md); the call-site
lookup rule at [method dispatch](method-dispatch.md); the built-in lookup rule at [method dispatch](0016-method-dispatch.md); the built-in
classes the prelude ships at [prelude classes](prelude-classes.md). classes the prelude ships at [prelude classes](0017-prelude-classes.md).
## Form-A schema (the JSON authoring surface) ## Form-A schema (the JSON authoring surface)
Three additive schema extensions; no existing module becomes invalid. Three additive schema extensions; no existing module becomes invalid.
The canonical schema for `ClassDef`, `InstanceDef`, and the The canonical schema for `ClassDef`, `InstanceDef`, and the
`FnDef.type` constraints field lives in `FnDef.type` constraints field lives in
[Data model](data-model.md); this section is the typeclass-layer [Data model](0002-data-model.md); this section is the typeclass-layer
narrative. narrative.
**`ClassDef`** — top-level definition kind, declares a class: **`ClassDef`** — top-level definition kind, declares a class:
@@ -75,7 +75,7 @@ exactly as for any free function.
## Cross-module references in synthesised bodies ## Cross-module references in synthesised bodies
The unified mono pass (see The unified mono pass (see
[models/typeclasses](../models/typeclasses.md) for the [models/typeclasses](../models/0005-typeclasses.md) for the
resolution/monomorphisation algorithm) synthesises mono symbols for resolution/monomorphisation algorithm) synthesises mono symbols for
polymorphic free fns and class-method instances in the symbol's polymorphic free fns and class-method instances in the symbol's
owner module — e.g. `print__Int` lives in `prelude` (because `print` owner module — e.g. `print__Int` lives in `prelude` (because `print`
@@ -84,7 +84,7 @@ is defined in the prelude), but a user-ADT call site
whose body references `show_user_adt.show__IntBox` (the user whose body references `show_user_adt.show__IntBox` (the user
instance lives in the user-defining module per the instance lives in the user-defining module per the
orphan-free-coherence rule documented in orphan-free-coherence rule documented in
[models/typeclasses](../models/typeclasses.md)). The synthesised [models/typeclasses](../models/0005-typeclasses.md)). The synthesised
body crosses a module boundary the source template did not. body crosses a module boundary the source template did not.
Three invariants make this work: Three invariants make this work:
@@ -218,7 +218,7 @@ wording is fixed; the categories and their triggers are:
Cross-class method sharing is structurally legal; ambiguity surfaces Cross-class method sharing is structurally legal; ambiguity surfaces
at the call site via `AmbiguousMethodResolution` or, for class-fn at the call site via `AmbiguousMethodResolution` or, for class-fn
name overlap, via the `class-method-shadowed-by-fn` warning. See name overlap, via the `class-method-shadowed-by-fn` warning. See
[Method dispatch](method-dispatch.md). [Method dispatch](0016-method-dispatch.md).
**Class-schema diagnostics** (validation of class declarations): **Class-schema diagnostics** (validation of class declarations):
@@ -259,6 +259,6 @@ There is no `AmbiguousInstance` diagnostic at the registry level —
coherence (`DuplicateInstance` at registry build, W2) makes coherence (`DuplicateInstance` at registry build, W2) makes
per-`(class, type)` ambiguity structurally impossible. Cross-class per-`(class, type)` ambiguity structurally impossible. Cross-class
method ambiguity is a separate concern resolved at the call site method ambiguity is a separate concern resolved at the call site
via `AmbiguousMethodResolution` (see [Method dispatch](method-dispatch.md)). via `AmbiguousMethodResolution` (see [Method dispatch](0016-method-dispatch.md)).
Ratified by: `crates/ail/tests/show_no_instance_e2e.rs`. Ratified by: `crates/ail/tests/show_no_instance_e2e.rs`.
@@ -5,7 +5,7 @@
1. **Snapshot tests** for the pretty-printer and IR emit. The diff makes 1. **Snapshot tests** for the pretty-printer and IR emit. The diff makes
regressions visible immediately. regressions visible immediately.
2. **Property tests** for the JSON ↔ pretty-print 2. **Property tests** for the JSON ↔ pretty-print
[roundtrip](roundtrip-invariant.md). [roundtrip](0009-roundtrip-invariant.md).
3. **End-to-end tests** for `examples/` with expected program output. 3. **End-to-end tests** for `examples/` with expected program output.
4. **Hash stability**: a test ensures the same def always produces the same 4. **Hash stability**: a test ensures the same def always produces the same
hash. hash.
@@ -5,11 +5,11 @@
The four constraints below are necessary preconditions for RC to The four constraints below are necessary preconditions for RC to
be sound and complete *without* a cycle-collector backstop. They be sound and complete *without* a cycle-collector backstop. They
are not new — AILang already satisfies all four — but the are not new — AILang already satisfies all four — but the
[memory model](memory-model.md) makes them load-bearing rather [memory model](0008-memory-model.md) makes them load-bearing rather
than incidental: than incidental:
1. **Strict evaluation.** Every `Term::App` (see 1. **Strict evaluation.** Every `Term::App` (see
[Data model](data-model.md)) argument is fully [Data model](0002-data-model.md)) argument is fully
evaluated before the call. No laziness, no thunks. (Already evaluated before the call. No laziness, no thunks. (Already
true.) true.)
2. **No recursive value bindings.** `(let x EXPR ...)` evaluates 2. **No recursive value bindings.** `(let x EXPR ...)` evaluates
@@ -31,11 +31,11 @@ proposal proves the cycle is collectible by an extension (e.g.
linear ownership). linear ownership).
These constraints are the precondition for the These constraints are the precondition for the
[memory model](memory-model.md): a sound RC implementation without [memory model](0008-memory-model.md): a sound RC implementation without
a cycle-collector backstop requires the reference graph to be a a cycle-collector backstop requires the reference graph to be a
DAG, which constraint 4 establishes from 13. They are also the DAG, which constraint 4 establishes from 13. They are also the
load-bearing structural reason behind several rejections under the load-bearing structural reason behind several rejections under the
[feature-acceptance](feature-acceptance.md) bug-class-reintroduction [feature-acceptance](0004-feature-acceptance.md) bug-class-reintroduction
discriminator (notably iterated-mutable-state reasoning). discriminator (notably iterated-mutable-state reasoning).
Ratified by: `crates/ailang-check/src/uniqueness.rs` (in-source mod tests). Ratified by: `crates/ailang-check/src/uniqueness.rs` (in-source mod tests).
@@ -3,8 +3,8 @@
## Method dispatch ## Method dispatch
The class-method resolution rule that pairs with the The class-method resolution rule that pairs with the
[typeclasses](typeclasses.md) contract; the `Show`/`Eq`/`Ord` instances [typeclasses](0013-typeclasses.md) contract; the `Show`/`Eq`/`Ord` instances
the rule dispatches against live in [prelude classes](prelude-classes.md). the rule dispatches against live in [prelude classes](0017-prelude-classes.md).
Dispatch is two-mode: Dispatch is two-mode:
@@ -12,7 +12,7 @@ Dispatch is two-mode:
constraint set): the constraint names the class via the qualified constraint set): the constraint names the class via the qualified
`Constraint.class` field (canonical form: bare for same-module, `Constraint.class` field (canonical form: bare for same-module,
`<module>.<Class>` for cross-module; see `<module>.<Class>` for cross-module; see
[memory model](memory-model.md) for the canonical-form rule). [memory model](0008-memory-model.md) for the canonical-form rule).
Synth's residual carries the class name directly; Synth's residual carries the class name directly;
constraint-discharge at fn-body-end matches against the workspace constraint-discharge at fn-body-end matches against the workspace
registry by `(class, type_hash)` key. registry by `(class, type_hash)` key.
@@ -3,7 +3,7 @@
## Prelude (built-in) classes ## Prelude (built-in) classes
The prelude ships the `Ordering` ADT, the `Eq` and `Ord` The prelude ships the `Ordering` ADT, the `Eq` and `Ord`
[classes](typeclasses.md), primitive `Eq Int/Bool/Str/Unit` and [classes](0013-typeclasses.md), primitive `Eq Int/Bool/Str/Unit` and
`Ord Int/Bool/Str` instances, and the five polymorphic free-fn `Ord Int/Bool/Str` instances, and the five polymorphic free-fn
helpers `ne`/`lt`/`le`/`gt`/`ge`. The primitive `Eq` / `Ord` helpers `ne`/`lt`/`le`/`gt`/`ge`. The primitive `Eq` / `Ord`
instance bodies are placeholder lambdas in `examples/prelude.ail`; instance bodies are placeholder lambdas in `examples/prelude.ail`;
@@ -35,12 +35,12 @@ maintenance; the symmetric extensions are mechanical when the
first such workload appears. first such workload appears.
Float has neither `Eq` nor `Ord` instance per [Float semantics]( Float has neither `Eq` nor `Ord` instance per [Float semantics](
float-semantics.md); a polymorphic helper invoked at Float fires 0005-float-semantics.md); a polymorphic helper invoked at Float fires
`NoInstance` at typecheck with a Float-aware diagnostic that names `NoInstance` at typecheck with a Float-aware diagnostic that names
the explicit `float_eq` / `float_lt` alternatives and the explicit `float_eq` / `float_lt` alternatives and
cross-references this section. The lookup machinery that turns a cross-references this section. The lookup machinery that turns a
`show x` call site into the right monomorphic instance is `show x` call site into the right monomorphic instance is
documented in [method dispatch](method-dispatch.md). documented in [method dispatch](0016-method-dispatch.md).
Float comparison is a separate surface: the six monomorphic prelude Float comparison is a separate surface: the six monomorphic prelude
fns `float_eq` / `float_ne` / `float_lt` / `float_le` / `float_gt` fns `float_eq` / `float_ne` / `float_lt` / `float_le` / `float_gt`
@@ -57,15 +57,15 @@ primitive `Show Int`, `Show Bool`, `Show Str`, `Show Float`
instances. Float **is** included in Show (unlike Eq/Ord) — IEEE-754 instances. Float **is** included in Show (unlike Eq/Ord) — IEEE-754
makes structural equality and total ordering semantically dubious, makes structural equality and total ordering semantically dubious,
but textual representation of a Float is well-defined modulo the but textual representation of a Float is well-defined modulo the
NaN-spelling caveat in [Float semantics](float-semantics.md). Each NaN-spelling caveat in [Float semantics](0005-float-semantics.md). Each
`Show <T>` instance body is a single-application lambda invoking the `Show <T>` instance body is a single-application lambda invoking the
corresponding runtime primitive (`int_to_str`, `bool_to_str`, corresponding runtime primitive (`int_to_str`, `bool_to_str`,
`str_clone`, `float_to_str`; see [Str ABI](str-abi.md) for the `str_clone`, `float_to_str`; see [Str ABI](0011-str-abi.md) for the
heap-Str primitives); no codegen intercept is required. The heap-Str primitives); no codegen intercept is required. The
polymorphic helper `print : forall a. Show a => a -> () !IO` has body polymorphic helper `print : forall a. Show a => a -> () !IO` has body
`\x -> let s = show x in do io/print_str s` (explicit let-binder for `\x -> let s = show x in do io/print_str s` (explicit let-binder for
heap-Str RC discipline per the Str carve-out in heap-Str RC discipline per the Str carve-out in
[Str ABI](str-abi.md)). The let-binder is [Str ABI](0011-str-abi.md)). The let-binder is
structurally pinned by `crates/ail/tests/print_mono_body_shape.rs`. structurally pinned by `crates/ail/tests/print_mono_body_shape.rs`.
Routing through `print` is the path for non-`Str` primitives; Routing through `print` is the path for non-`Str` primitives;
`io/print_str` is the only built-in direct-output effect-op. `io/print_str` is the only built-in direct-output effect-op.
@@ -63,7 +63,7 @@ Bool literals (`true`, `false`) and unit (`(lit-unit)`) are
disambiguated by parser context, not by lex. Comparison and disambiguated by parser context, not by lex. Comparison and
equality are class methods (`eq` / `compare`) and named fns equality are class methods (`eq` / `compare`) and named fns
(`float_eq` / `float_lt` / etc.), not operators — see (`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`, Every AST node form has a unique head keyword (`module`, `data`,
`fn`, `forall`, `fn-type`, `con`, `var`, `app`, `lam`, `match`, `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. designing a uniform form from scratch.
The chosen form is (A), shipped as the `ailang-surface` crate (see 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 canonical JSON-AST it round-trips against is documented in
[Data model](../contracts/data-model.md), and the round-trip [Data model](../contracts/0002-data-model.md), and the round-trip
property itself in [Roundtrip Invariant](../contracts/roundtrip-invariant.md). property itself in [Roundtrip Invariant](../contracts/0009-roundtrip-invariant.md).
For the prose projection used for human review (Form B), see 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 — flat, unordered, closed set of effect names, unified by set-equality —
there is no effect row variable; a signature lists exactly the effects 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` 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 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`). 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 `Diverge` (for non-termination) is reserved as an effect name but is
unimplemented — no op, no codegen, no checker injection — in the same unimplemented — no op, no codegen, no checker injection — in the same
sense the refinements layer is reserved as a future extension without sense the refinements layer is reserved as a future extension without
present-day surface (see 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 This is the most important LLM property: when I read a function, I can trust
its signature without reading the body. its signature without reading the body.
@@ -18,7 +18,7 @@
Two allocator backends share the same MIR. `--alloc=rc` is the Two allocator backends share the same MIR. `--alloc=rc` is the
canonical backend committed to in 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 the typechecker enforces `(own)` / `(borrow)` modes, codegen emits
`ailang_rc_inc` / `_dec` calls at the points dictated by linearity, `ailang_rc_inc` / `_dec` calls at the points dictated by linearity,
and `Term::Clone` / `Term::ReuseAs` materialise into actual rc-bumps 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 The text projections the CLI moves between are documented in
[authoring surface](../contracts/authoring-surface.md) (Form-A, [authoring surface](../contracts/0001-authoring-surface.md) (Form-A,
round-trippable) and [prose projection](prose-projection.md) round-trippable) and [prose projection](0006-prose-projection.md)
(Form-B, lossy, no parser); `ail build --emit=staticlib` produces (Form-B, lossy, no parser); `ail build --emit=staticlib` produces
the layout fixed in [embedding ABI](../contracts/embedding-abi.md) the layout fixed in [embedding ABI](../contracts/0003-embedding-abi.md)
plus [frozen value layout](../contracts/frozen-value-layout.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 canonical position is "RC + inference" sharpened with the five
LLM-author mechanisms below. A corpus committed to one memory LLM-author mechanisms below. A corpus committed to one memory
model is expensive to switch — the commitment lives in the model is expensive to switch — the commitment lives in the
contracts ([memory-model](../contracts/memory-model.md), contracts ([memory-model](../contracts/0008-memory-model.md),
[language-constraints](../contracts/language-constraints.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 is reference counting with static uniqueness inference **and
explicit LLM-author annotations on fn signatures**, in the lineage explicit LLM-author annotations on fn signatures**, in the lineage
of Lean 4 / Roc / Koka. The RC pipeline tracks the bump-allocator 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 reference value with ±15% tolerance) and are excluded from the
linear/tree 1.3× regression gate; the closure-chain corpus has linear/tree 1.3× regression gate; the closure-chain corpus has
its own ±15% band until a slab/pool optimisation ships. The 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, unchanged; what is scoped is the *quantitative* regression band,
not the choice of memory model. not the choice of memory model.
@@ -166,7 +166,7 @@ guess.
**(2) Linear-by-default consumption with explicit `(clone X)`** **(2) Linear-by-default consumption with explicit `(clone X)`**
(the `Term::Clone` schema entry lives in (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 In bodies, every binder is consumed by exactly one `own`-mode
use. If the LLM writes: use. If the LLM writes:
@@ -241,7 +241,7 @@ compiles, but what the compiler tells the author when it doesn't.
## Inference algorithm ## 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 pre-codegen pass over the elaborated module. For each `Term` node that produces or binds a
boxed value, the pass computes a uniqueness flag: boxed value, the pass computes a uniqueness flag:
@@ -1,17 +1,17 @@
# Typeclasses — resolution and monomorphisation whitepaper # Typeclasses — resolution and monomorphisation whitepaper
The schema-and-diagnostics contract for typeclasses lives in The schema-and-diagnostics contract for typeclasses lives in
[typeclasses](../contracts/typeclasses.md); the call-site lookup [typeclasses](../contracts/0013-typeclasses.md); the call-site lookup
rule in [method dispatch](../contracts/method-dispatch.md); the rule in [method dispatch](../contracts/0016-method-dispatch.md); the
built-in classes shipped in the prelude in 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 covers the design choices and the resolution / monomorphisation
algorithm. algorithm.
## The design — Haskell-lite, monomorphised, coherent ## The design — Haskell-lite, monomorphised, coherent
**The design pass for typeclasses. Codified after the **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 was committed; the criterion is the explicit basis for the choices
below.** below.**
@@ -56,7 +56,7 @@ types) is one an LLM author does not unprompted produce.
**Constraint collection (per function body).** During typechecking **Constraint collection (per function body).** During typechecking
of a body, each method call generates a residual constraint of shape of a body, each method call generates a residual constraint of shape
`<Class> <Type>` (the schema for these lives in `<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. contain type variables.
After local typechecking, residual constraints are checked against After local typechecking, residual constraints are checked against
the function's declared constraints (modulo α-conversion and modulo 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 point — is a static error, not a runtime one. This is the
LLVM-friendly form and is consistent with the performance LLVM-friendly form and is consistent with the performance
commitment of the 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 second textual projection of the AST: `ailang-prose`, a one-way
projection from `Module → human-readable text`. It is **not** an projection from `Module → human-readable text`. It is **not** an
authoring surface; it is the "display" projection that the 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: architectural pin explicitly anticipated:
> *"Future projections are explicitly anticipated: a visual / > *"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. lambdas, the `tail` flag — all preserved verbatim.
Critically, **form (B) has no parser**. Form (A) is round-trippable 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 form (B) deliberately is not. Re-integrating prose edits requires an
external LLM mediator, not a compiler pass — the prompt template external LLM mediator, not a compiler pass — the prompt template
`ail merge-prose` composes the six-step cycle. `ail merge-prose` composes the six-step cycle.
Form (B) does not weaken any 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, hashable artefact. Prose is not hashed, not content-addressed,
not load-bearing for any cross-module reference. not load-bearing for any cross-module reference.
- Form (A) remains the canonical authoring surface. Foreign LLMs - 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 The CLI gains `ail prose <m.ail.json>` (the deterministic
projection) and `ail merge-prose <m.ail.json> <edited.prose.txt>` projection) and `ail merge-prose <m.ail.json> <edited.prose.txt>`
(the mediator-prompt composer); both are listed under (the mediator-prompt composer); both are listed under
[pipeline](pipeline.md). [pipeline](0003-pipeline.md).
## Form-A spec embedding ## 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 implementation-level detail. As each milestone closes, sections of
this whitepaper transition from forward-looking design to this whitepaper transition from forward-looking design to
present-state description, per the present-state description, per the
[honesty-rule](../contracts/honesty-rule.md). [honesty-rule](../contracts/0007-honesty-rule.md).
## The problem ## The problem
@@ -232,7 +232,7 @@ kernel-tier modules (the stub, future Series, future Matrix)
become auto-injected through the same path. become auto-injected through the same path.
Class-method dispatch (a separate mechanism — see 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 orthogonal: the dispatch is about how method calls are
resolved; the auto-import is about which names are in scope. 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 push-only mutation surface — gated by the `Series` effect — does
not reintroduce the iterated-mutable-state bug class that the not reintroduce the iterated-mutable-state bug class that the
`mut`/`var`/`assign` removal addressed (clause 3 — see `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). discussion).
The same three-clause check applies to *each future kernel 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 - **Classes / method dispatch.** Orthogonal. Type-scoped
namespacing accesses *top-level defs* in a type's home module; 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. resolves *class method calls* by type-driven instance lookup.
Both can coexist on the same type — e.g. `Series` could Both can coexist on the same type — e.g. `Series` could
someday have a `Show` instance (class method `show` dispatches 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 - **Heap-Str ABI.** The Series runtime borrows the heap-Str
RC-pointer-to-opaque-struct pattern (see 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`, `ptr` from the compiler's view; dedicated `_new`, `_drop`,
and operation symbols in C; RC header in the struct prefix. and operation symbols in C; RC header in the struct prefix.
@@ -623,14 +623,14 @@ above is the only commitment.
## Cross-references ## Cross-references
- **Feature-acceptance gate** applied to each kernel extension: - **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** (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** (this whitepaper's STATUS contract):
[honesty-rule](../contracts/honesty-rule.md). [honesty-rule](../contracts/0007-honesty-rule.md).
- **Reference design** for Series storage layout: - **Reference design** for Series storage layout:
`/home/brummel/dev/RustAst/src/ast/rtl/series/` (external Rust `/home/brummel/dev/RustAst/src/ast/rtl/series/` (external Rust
project; not in this repo). 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` (prep milestone); future `docs/specs/YYYY-MM-DD-series.md`
(Series milestone, written after prep closes). (Series milestone, written after prep closes).
@@ -1,6 +1,6 @@
# Skill System Build-out — Implementation Plan # Skill System Build-out — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-skill-system.md` > **Parent spec:** `docs/specs/0001-skill-system.md`
> >
> **Discipline:** Skill construction follows TDD per > **Discipline:** Skill construction follows TDD per
> `superpowers:writing-skills` (RED → GREEN → REFACTOR with subagent > `superpowers:writing-skills` (RED → GREEN → REFACTOR with subagent
@@ -748,8 +748,8 @@ Insert at the bottom (after the latest existing entry):
## 2026-05-09 — Milestone 22c: skill system live ## 2026-05-09 — Milestone 22c: skill system live
The five-skill development pipeline shipped today. Spec at The five-skill development pipeline shipped today. Spec at
`docs/specs/2026-05-09-skill-system.md`; build-out plan at `docs/specs/0001-skill-system.md`; build-out plan at
`docs/plans/2026-05-09-skill-system-buildout.md`. Five `SKILL.md` `docs/plans/0001-skill-system-buildout.md`. Five `SKILL.md`
files under `skills/<name>/`, six agents migrated to files under `skills/<name>/`, six agents migrated to
`skills/<name>/agents/`, `CLAUDE.md` split into orchestrator-identity `skills/<name>/agents/`, `CLAUDE.md` split into orchestrator-identity
and skill-pointers, `.claude/agents/` symlinks installed, this entry and skill-pointers, `.claude/agents/` symlinks installed, this entry
@@ -1,6 +1,6 @@
# 22b.2 — Typecheck Arms — Implementation Plan # 22b.2 — Typecheck Arms — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` > **Parent spec:** `docs/specs/0002-22-typeclasses.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# Iteration 22b.3 — Monomorphisation Pass — Implementation Plan # Iteration 22b.3 — Monomorphisation Pass — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` > **Parent spec:** `docs/specs/0002-22-typeclasses.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# 22b.4a — Form-A parser+printer arms for ClassDef/InstanceDef + spec amendment # 22b.4a — Form-A parser+printer arms for ClassDef/InstanceDef + spec amendment
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` > **Parent spec:** `docs/specs/0002-22-typeclasses.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -55,7 +55,7 @@ arbitrary polymorphic top-levels.
- Modify: `crates/ailang-surface/tests/round_trip.rs` — removes the - Modify: `crates/ailang-surface/tests/round_trip.rs` — removes the
`test_22b1_*` / `test_22b2_*` / `test_22b3_*` filter clauses; lets `test_22b1_*` / `test_22b2_*` / `test_22b3_*` filter clauses; lets
the gate exercise every fixture. the gate exercise every fixture.
- Modify: `docs/specs/2026-05-09-22-typeclasses.md` — appends an - Modify: `docs/specs/0002-22-typeclasses.md` — appends an
"Amendments" section recording the 22b.4a / 22b.4b split, the "Amendments" section recording the 22b.4a / 22b.4b split, the
Form-A vs Form-B terminology fix, the `__` separator decision, and Form-A vs Form-B terminology fix, the `__` separator decision, and
the 22c-and-beyond impact. the 22c-and-beyond impact.
@@ -1157,7 +1157,7 @@ git commit -m "iter 22b.4a.5: retire round-trip skip-list for class/instance fix
## Task 6: Spec amendment ## Task 6: Spec amendment
**Files:** **Files:**
- Modify: `docs/specs/2026-05-09-22-typeclasses.md` — append an - Modify: `docs/specs/0002-22-typeclasses.md` — append an
"Amendments" section. "Amendments" section.
- Modify: `docs/DESIGN.md` — locate Decision 11 §"Resolution and - Modify: `docs/DESIGN.md` — locate Decision 11 §"Resolution and
monomorphisation" (DESIGN.md mono-symbol naming subsection) and monomorphisation" (DESIGN.md mono-symbol naming subsection) and
@@ -1165,7 +1165,7 @@ git commit -m "iter 22b.4a.5: retire round-trip skip-list for class/instance fix
- [ ] **Step 6.1: Append the spec amendments section** - [ ] **Step 6.1: Append the spec amendments section**
Open `docs/specs/2026-05-09-22-typeclasses.md`. Append at end of Open `docs/specs/0002-22-typeclasses.md`. Append at end of
file: file:
```markdown ```markdown
@@ -1270,7 +1270,7 @@ the right home for naming-convention micro-decisions.)
- [ ] **Step 6.3: Commit** - [ ] **Step 6.3: Commit**
``` ```
git add docs/specs/2026-05-09-22-typeclasses.md docs/DESIGN.md git add docs/specs/0002-22-typeclasses.md docs/DESIGN.md
git commit -m "iter 22b.4a.6: spec + DESIGN amendments — 22b.4 split, terminology fix, '__' separator" git commit -m "iter 22b.4a.6: spec + DESIGN amendments — 22b.4 split, terminology fix, '__' separator"
``` ```
@@ -1,6 +1,6 @@
# 22c — User-class e2e fixture # 22c — User-class e2e fixture
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` > **Parent spec:** `docs/specs/0002-22-typeclasses.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -354,7 +354,7 @@ done — there is nothing left to wire.
22b.4b (Prelude for primitives) dropped from milestone scope; 22c's 22b.4b (Prelude for primitives) dropped from milestone scope; 22c's
fixture re-scoped to vocabulary AILang already has (no `++`, no fixture re-scoped to vocabulary AILang already has (no `++`, no
named-field record syntax, no top-level polymorphic `print`). See named-field record syntax, no top-level polymorphic `print`). See
`docs/specs/2026-05-09-22-typeclasses.md` "Amendments" §"22b.4b `docs/specs/0002-22-typeclasses.md` "Amendments" §"22b.4b
dropped" and §"22c scope tightened". dropped" and §"22c scope tightened".
**Milestone-22 acceptance check:** **Milestone-22 acceptance check:**
@@ -1,6 +1,6 @@
# 22-tidy — DESIGN.md and spec drift after milestone-22 close # 22-tidy — DESIGN.md and spec drift after milestone-22 close
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` (already > **Parent spec:** `docs/specs/0002-22-typeclasses.md` (already
> amended for the 22b.4b drop and 22c rescope). > amended for the 22b.4b drop and 22c rescope).
> >
> **Trigger:** `audit` skill found drift between `docs/DESIGN.md` > **Trigger:** `audit` skill found drift between `docs/DESIGN.md`
@@ -26,7 +26,7 @@ as the gate.
- Modify: `docs/DESIGN.md:1725-1766` — rewrite §"Prelude (built-in) - Modify: `docs/DESIGN.md:1725-1766` — rewrite §"Prelude (built-in)
classes" and §"What this decision does NOT commit to" to match classes" and §"What this decision does NOT commit to" to match
the 22b.4b-deferral + `__` separator decisions. the 22b.4b-deferral + `__` separator decisions.
- Modify: `docs/specs/2026-05-09-22-typeclasses.md:50-56` — split - Modify: `docs/specs/0002-22-typeclasses.md:50-56` — split
the 22b.4 components-table row into 22b.4a (shipped) + 22b.4b the 22b.4 components-table row into 22b.4a (shipped) + 22b.4b
(post-22); mark 22c shipped. (post-22); mark 22c shipped.
- Modify: `crates/ailang-prose/src/lib.rs:80-101` — update the - Modify: `crates/ailang-prose/src/lib.rs:80-101` — update the
@@ -90,7 +90,7 @@ case for primitive `Show` is weak (LLM-natural form is `int_to_str
x`, not `show x` through a single-instance class). The user-class x`, not `show x` through a single-instance class). The user-class
end-to-end path is the milestone's typeclass acceptance gate end-to-end path is the milestone's typeclass acceptance gate
(22c's `class Foo a` + `data IntBox` + `instance Foo IntBox` (22c's `class Foo a` + `data IntBox` + `instance Foo IntBox`
fixture); see `docs/specs/2026-05-09-22-typeclasses.md` fixture); see `docs/specs/0002-22-typeclasses.md`
"Amendments" §"22b.4b dropped" for the substantive rationale. "Amendments" §"22b.4b dropped" for the substantive rationale.
A future milestone may add a Prelude when concrete LLM-author code A future milestone may add a Prelude when concrete LLM-author code
@@ -151,7 +151,7 @@ git commit -m "iter 22-tidy.1: DESIGN.md — reconcile Decision 11 with mileston
## Task 2: Spec components-table drift ## Task 2: Spec components-table drift
**Files:** `docs/specs/2026-05-09-22-typeclasses.md` lines 50-56. **Files:** `docs/specs/0002-22-typeclasses.md` lines 50-56.
The Components table still has the original 22b.4 row (Prelude + The Components table still has the original 22b.4 row (Prelude +
Form-B + retire) which the amendments section supersedes. Reader Form-B + retire) which the amendments section supersedes. Reader
@@ -179,7 +179,7 @@ remains as-is — it's still historically accurate.)
### Step 2.2 — Commit ### Step 2.2 — Commit
```bash ```bash
git add docs/specs/2026-05-09-22-typeclasses.md git add docs/specs/0002-22-typeclasses.md
git commit -m "iter 22-tidy.2: spec — components table reflects 22b.4a/b split + 22c shipped" git commit -m "iter 22-tidy.2: spec — components table reflects 22b.4a/b split + 22c shipped"
``` ```
@@ -1,6 +1,6 @@
# Env-construction unify — Implementation Plan # Env-construction unify — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-10-env-construction-unify.md` > **Parent spec:** `docs/specs/0003-env-construction-unify.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -630,8 +630,8 @@ Tasks:
(preserves pre-refactor fail-fast behaviour without re-mutating (preserves pre-refactor fail-fast behaviour without re-mutating
the shared env). the shared env).
Spec: `docs/specs/2026-05-10-env-construction-unify.md`. Plan: Spec: `docs/specs/0003-env-construction-unify.md`. Plan:
`docs/plans/2026-05-10-env-construction-unify.md`. Tests: pin test `docs/plans/0007-env-construction-unify.md`. Tests: pin test
green, the three RED tests green, the three RED tests
(`typeclass_22c`, `mono_recursive_fn`, `mono_xmod_qualified_ref`) (`typeclass_22c`, `mono_recursive_fn`, `mono_xmod_qualified_ref`)
remain green, full workspace test suite green, bench gates 0/0/0. remain green, full workspace test suite green, bench gates 0/0/0.
@@ -1,6 +1,6 @@
# 22-tidy primitive-name-set consolidation — Implementation Plan # 22-tidy primitive-name-set consolidation — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` (milestone 22, closed 2026-05-09) > **Parent spec:** `docs/specs/0002-22-typeclasses.md` (milestone 22, closed 2026-05-09)
> >
> **Audit anchor:** `docs/JOURNAL.md` 2026-05-09 entry "Iteration 22-tidy: DESIGN.md and spec drift after milestone-22 close" → "Carried debt" → primitive-name-set consolidation. > **Audit anchor:** `docs/JOURNAL.md` 2026-05-09 entry "Iteration 22-tidy: DESIGN.md and spec drift after milestone-22 close" → "Carried debt" → primitive-name-set consolidation.
> >
@@ -1,6 +1,6 @@
# 22-tidy.5 strict duplicate-clause detection — Implementation Plan # 22-tidy.5 strict duplicate-clause detection — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` (milestone 22, closed 2026-05-09) > **Parent spec:** `docs/specs/0002-22-typeclasses.md` (milestone 22, closed 2026-05-09)
> >
> **Carried-debt anchor:** `docs/JOURNAL.md` 2026-05-09 entry "Iteration 22-tidy" → "Strict duplicate-clause detection in `parse_fn` / `parse_data` / `parse_const` (sibling parsers to the 22b.4a additions). The asymmetry is documented; promoting siblings to the strict pattern is queued." > **Carried-debt anchor:** `docs/JOURNAL.md` 2026-05-09 entry "Iteration 22-tidy" → "Strict duplicate-clause detection in `parse_fn` / `parse_data` / `parse_const` (sibling parsers to the 22b.4a additions). The asymmetry is documented; promoting siblings to the strict pattern is queued."
> >
@@ -1,6 +1,6 @@
# 22-tidy.6 Form-B prose printer arms for ClassDef + InstanceDef — Implementation Plan # 22-tidy.6 Form-B prose printer arms for ClassDef + InstanceDef — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` (milestone 22, closed 2026-05-09) > **Parent spec:** `docs/specs/0002-22-typeclasses.md` (milestone 22, closed 2026-05-09)
> >
> **Carried-debt anchor:** `docs/JOURNAL.md` 2026-05-09 entry "Iteration 22-tidy" → "Form-B (prose) printer arms for ClassDef / InstanceDef. One-way, not gating." > **Carried-debt anchor:** `docs/JOURNAL.md` 2026-05-09 entry "Iteration 22-tidy" → "Form-B (prose) printer arms for ClassDef / InstanceDef. One-way, not gating."
> >
@@ -1,6 +1,6 @@
# 22-tidy.7 strict-clause helper consolidation — Implementation Plan # 22-tidy.7 strict-clause helper consolidation — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-09-22-typeclasses.md` (milestone 22, closed 2026-05-09) > **Parent spec:** `docs/specs/0002-22-typeclasses.md` (milestone 22, closed 2026-05-09)
> >
> **Trigger:** 22-tidy.5 JOURNAL entry observation that the duplicate-clause check pattern now appears at 17 sites across the parser (10 from 22b.4a + 8 from 22-tidy.5; the JOURNAL entry's "18 sites" was an off-by-one — re-grep confirms 17). 17 × ~12 LOC of identical structure is past the tipping point for the "three similar lines beats a premature abstraction" rule. > **Trigger:** 22-tidy.5 JOURNAL entry observation that the duplicate-clause check pattern now appears at 17 sites across the parser (10 from 22b.4a + 8 from 22-tidy.5; the JOURNAL entry's "18 sites" was an off-by-one — re-grep confirms 17). 17 × ~12 LOC of identical structure is past the tipping point for the "three similar lines beats a premature abstraction" rule.
> >
@@ -1,6 +1,6 @@
# design-md-consolidation iter 1 — sweep 1: history anchors # design-md-consolidation iter 1 — sweep 1: history anchors
> **Parent spec:** `docs/specs/2026-05-10-design-md-consolidation.md` > **Parent spec:** `docs/specs/0004-design-md-consolidation.md`
> §"Sweep 1 — Remove history anchors" > §"Sweep 1 — Remove history anchors"
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
@@ -250,11 +250,11 @@ Edit:
- [ ] **Step 8: Decision 11 §"Prelude" (line 1753)** - [ ] **Step 8: Decision 11 §"Prelude" (line 1753)**
Edit: Edit:
- old: `fixture); see `docs/specs/2026-05-09-22-typeclasses.md`` - old: `fixture); see `docs/specs/0002-22-typeclasses.md``
- new: `fixture); see `docs/specs/22-typeclasses.md`` - new: `fixture); see `docs/specs/22-typeclasses.md``
NOTE: this step renames the spec-file reference. The actual file NOTE: this step renames the spec-file reference. The actual file
`docs/specs/2026-05-09-22-typeclasses.md` exists on disk; sweep 1 `docs/specs/0002-22-typeclasses.md` exists on disk; sweep 1
does NOT rename the file (that would lose git history). Instead, does NOT rename the file (that would lose git history). Instead,
the in-text reference is left as the date-prefixed actual filename the in-text reference is left as the date-prefixed actual filename
because it points to a real file. **Revert this step** if the because it points to a real file. **Revert this step** if the
@@ -262,7 +262,7 @@ filename on disk uses the date prefix.
Verify before editing: Verify before editing:
```bash ```bash
ls docs/specs/2026-05-09-22-typeclasses.md ls docs/specs/0002-22-typeclasses.md
``` ```
If the file exists with the date prefix, KEEP the reference and If the file exists with the date prefix, KEEP the reference and
@@ -296,7 +296,7 @@ grep -nE '2026-[0-9]{2}-[0-9]{2}' docs/DESIGN.md
``` ```
Expected: empty, OR exactly one line — the spec-file path Expected: empty, OR exactly one line — the spec-file path
`docs/specs/2026-05-09-22-typeclasses.md` (if the file on disk `docs/specs/0002-22-typeclasses.md` (if the file on disk
uses that prefix). Record this in the JOURNAL exception list. uses that prefix). Record this in the JOURNAL exception list.
- [ ] **Step 12: Commit** - [ ] **Step 12: Commit**
@@ -410,7 +410,7 @@ grep -nE 'Iter [0-9]+[a-z]?(\.[0-9]+)?' docs/DESIGN.md
Expected: empty output, OR the date-prefixed spec-file reference Expected: empty output, OR the date-prefixed spec-file reference
from Task 3 Step 11 (the path from Task 3 Step 11 (the path
`docs/specs/2026-05-09-22-typeclasses.md` does not match this iter `docs/specs/0002-22-typeclasses.md` does not match this iter
pattern, so the exception list need not grow here). pattern, so the exception list need not grow here).
- [ ] **Step 5: Commit** - [ ] **Step 5: Commit**
@@ -498,7 +498,7 @@ grep -nE 'Iter [0-9]+[a-z]?(\.[0-9]+)?|Family [0-9]+|^[^/]*2026-[0-9]{2}-[0-9]{2
``` ```
Expected: empty, OR up to one line (the Expected: empty, OR up to one line (the
`docs/specs/2026-05-09-22-typeclasses.md` path from Task 3 Step 11, `docs/specs/0002-22-typeclasses.md` path from Task 3 Step 11,
*if* the file on disk has that prefix). The leading `^[^/]*` in the *if* the file on disk has that prefix). The leading `^[^/]*` in the
date regex pre-filters paths that begin with `docs/specs/`. date regex pre-filters paths that begin with `docs/specs/`.
@@ -533,7 +533,7 @@ Append to `docs/JOURNAL.md` (after the last entry):
## 2026-05-10 — Iteration design-md-consolidation 1: history-anchor sweep ## 2026-05-10 — Iteration design-md-consolidation 1: history-anchor sweep
First iteration of the milestone defined in First iteration of the milestone defined in
`docs/specs/2026-05-10-design-md-consolidation.md`. Sweep 1 closes `docs/specs/0004-design-md-consolidation.md`. Sweep 1 closes
the "history anchors in DESIGN.md" item: every iter tag, family the "history anchors in DESIGN.md" item: every iter tag, family
tag, date anchor, status marker, and historical bench data-point tag, date anchor, status marker, and historical bench data-point
that anchored the document to a specific moment is removed. that anchored the document to a specific moment is removed.
@@ -565,7 +565,7 @@ Specific anchor examples discarded (representative):
(bench notes in JOURNAL).` (bench notes in JOURNAL).`
Deliberate exceptions to the sweep-1 grep pattern (if any): Deliberate exceptions to the sweep-1 grep pattern (if any):
- `docs/specs/2026-05-09-22-typeclasses.md` — date-prefixed spec - `docs/specs/0002-22-typeclasses.md` — date-prefixed spec
filename, kept verbatim because the on-disk file uses that filename, kept verbatim because the on-disk file uses that
prefix and renaming would lose git history. Record only. prefix and renaming would lose git history. Record only.
@@ -1,6 +1,6 @@
# design-md-consolidation iter 2 — sweep 2: REVERTED + migration plans + correction history + future speculations # design-md-consolidation iter 2 — sweep 2: REVERTED + migration plans + correction history + future speculations
> **Parent spec:** `docs/specs/2026-05-10-design-md-consolidation.md` > **Parent spec:** `docs/specs/0004-design-md-consolidation.md`
> §"Sweep 2 — REVERTED + migration plans out". > §"Sweep 2 — REVERTED + migration plans out".
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
@@ -682,7 +682,7 @@ Append to `docs/JOURNAL.md`. Template:
## 2026-05-10 — Iteration design-md-consolidation 2: REVERTED + migration + correction history + future speculations ## 2026-05-10 — Iteration design-md-consolidation 2: REVERTED + migration + correction history + future speculations
Second iteration of the milestone defined in Second iteration of the milestone defined in
`docs/specs/2026-05-10-design-md-consolidation.md`. Sweep 2 closes `docs/specs/0004-design-md-consolidation.md`. Sweep 2 closes
the "REVERTED + migration plans + correction history + future the "REVERTED + migration plans + correction history + future
speculations" item: the audit-trail preservation of Decision 7, speculations" item: the audit-trail preservation of Decision 7,
the 7-point Decision 10 Migration plan, the Decision 9 the 7-point Decision 10 Migration plan, the Decision 9
@@ -1,6 +1,6 @@
# design-md-consolidation iter 3 — sweep 3: schema SoT inversion + data-model hardening # design-md-consolidation iter 3 — sweep 3: schema SoT inversion + data-model hardening
> **Parent spec:** `docs/specs/2026-05-10-design-md-consolidation.md` > **Parent spec:** `docs/specs/0004-design-md-consolidation.md`
> §"Sweep 3 — Schema SoT inversion + Data-model hardening". > §"Sweep 3 — Schema SoT inversion + Data-model hardening".
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
@@ -860,7 +860,7 @@ Template (adjust specifics to actual outcome):
## 2026-05-10 — Iteration design-md-consolidation 3: schema SoT inversion + data-model hardening ## 2026-05-10 — Iteration design-md-consolidation 3: schema SoT inversion + data-model hardening
Third iteration of the milestone defined in Third iteration of the milestone defined in
`docs/specs/2026-05-10-design-md-consolidation.md`. Sweep 3 `docs/specs/0004-design-md-consolidation.md`. Sweep 3
inverts the schema source-of-truth between `docs/DESIGN.md` inverts the schema source-of-truth between `docs/DESIGN.md`
§"Data model" and `crates/ailang-core/src/ast.rs`: DESIGN.md is §"Data model" and `crates/ailang-core/src/ast.rs`: DESIGN.md is
canonical, `ast.rs` is the projection, and a new drift test canonical, `ast.rs` is the projection, and a new drift test
@@ -1,6 +1,6 @@
# design-md-consolidation iter 4 — sweep 4: workflow / cross-reference cleanup # design-md-consolidation iter 4 — sweep 4: workflow / cross-reference cleanup
> **Parent spec:** `docs/specs/2026-05-10-design-md-consolidation.md` > **Parent spec:** `docs/specs/0004-design-md-consolidation.md`
> §"Sweep 4 — Workflow / cross-reference cleanup". > §"Sweep 4 — Workflow / cross-reference cleanup".
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
@@ -488,7 +488,7 @@ DESIGN.md line count and any cross-reference inventory specifics):
## 2026-05-10 — Iteration design-md-consolidation 4: workflow / cross-reference cleanup ## 2026-05-10 — Iteration design-md-consolidation 4: workflow / cross-reference cleanup
Fourth and final iteration of the milestone defined in Fourth and final iteration of the milestone defined in
`docs/specs/2026-05-10-design-md-consolidation.md`. Sweep 4 `docs/specs/0004-design-md-consolidation.md`. Sweep 4
closes the "workflow / cross-reference cleanup" item: the closes the "workflow / cross-reference cleanup" item: the
stale `agents/` ecosystem entry is replaced with a `Skills` stale `agents/` ecosystem entry is replaced with a `Skills`
entry pointing to `skills/<name>/agents/`; the workflow-detail entry pointing to `skills/<name>/agents/`; the workflow-detail
@@ -646,7 +646,7 @@ Edit `docs/roadmap.md`:
becomes a state-only specification across four thematic sweeps becomes a state-only specification across four thematic sweeps
(history anchors out, migration plans out, schema-SoT inversion + (history anchors out, migration plans out, schema-SoT inversion +
data-model hardening, workflow / cross-reference cleanup). data-model hardening, workflow / cross-reference cleanup).
- context: `docs/specs/2026-05-10-design-md-consolidation.md` - context: `docs/specs/0004-design-md-consolidation.md`
- sub-entries: - sub-entries:
- [x] Sweep 1 — remove history anchors - [x] Sweep 1 — remove history anchors
- [x] Sweep 2 — REVERTED + migration plans out - [x] Sweep 2 — REVERTED + migration plans out
@@ -660,7 +660,7 @@ Edit `docs/roadmap.md`:
(history anchors out, REVERTED + migration plans out, (history anchors out, REVERTED + migration plans out,
schema-SoT inversion + data-model hardening, workflow / schema-SoT inversion + data-model hardening, workflow /
cross-reference cleanup). Closed 2026-05-10. cross-reference cleanup). Closed 2026-05-10.
- context: `docs/specs/2026-05-10-design-md-consolidation.md`, - context: `docs/specs/0004-design-md-consolidation.md`,
JOURNAL milestone-close entry of same date. JOURNAL milestone-close entry of same date.
``` ```
@@ -1,6 +1,6 @@
# Floats Iteration 1 — Schema Layer (Implementation Plan) # Floats Iteration 1 — Schema Layer (Implementation Plan)
> **Parent spec:** `docs/specs/2026-05-10-floats.md` (committed > **Parent spec:** `docs/specs/0005-floats.md` (committed
> `e37366f`, approved 2026-05-10) > `e37366f`, approved 2026-05-10)
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
@@ -1,6 +1,6 @@
# Floats Iteration 2 — Surface Layer (Implementation Plan) # Floats Iteration 2 — Surface Layer (Implementation Plan)
> **Parent spec:** `docs/specs/2026-05-10-floats.md` (committed > **Parent spec:** `docs/specs/0005-floats.md` (committed
> `e37366f`, approved 2026-05-10) — sections A2 and the > `e37366f`, approved 2026-05-10) — sections A2 and the
> `crates/ailang-surface/` Components subsection. > `crates/ailang-surface/` Components subsection.
> >
@@ -1,6 +1,6 @@
# Floats Iteration 3 — Typecheck + Builtins (Implementation Plan) # Floats Iteration 3 — Typecheck + Builtins (Implementation Plan)
> **Parent spec:** `docs/specs/2026-05-10-floats.md` (committed > **Parent spec:** `docs/specs/0005-floats.md` (committed
> `e37366f`, approved 2026-05-10) — section A3 + the > `e37366f`, approved 2026-05-10) — section A3 + the
> `crates/ailang-check/` Components subsection. > `crates/ailang-check/` Components subsection.
> >
@@ -1,6 +1,6 @@
# Floats Iteration 4 — Codegen + Runtime (Implementation Plan) # Floats Iteration 4 — Codegen + Runtime (Implementation Plan)
> **Parent spec:** `docs/specs/2026-05-10-floats.md` (committed > **Parent spec:** `docs/specs/0005-floats.md` (committed
> `e37366f`, approved 2026-05-10) — sections A3 (codegen-side > `e37366f`, approved 2026-05-10) — sections A3 (codegen-side
> dispatch), A4 (conversions), A5 (determinism), and the > dispatch), A4 (conversions), A5 (determinism), and the
> `crates/ailang-codegen/` + `runtime/` Components subsections. > `crates/ailang-codegen/` + `runtime/` Components subsections.
@@ -1,6 +1,6 @@
# Floats Iteration 5 — Prose + DESIGN.md + Milestone Close (Implementation Plan) # Floats Iteration 5 — Prose + DESIGN.md + Milestone Close (Implementation Plan)
> **Parent spec:** `docs/specs/2026-05-10-floats.md` (committed > **Parent spec:** `docs/specs/0005-floats.md` (committed
> `e37366f`, approved 2026-05-10) — section A5 (determinism > `e37366f`, approved 2026-05-10) — section A5 (determinism
> contract) + the `crates/ailang-prose/` Components subsection. > contract) + the `crates/ailang-prose/` Components subsection.
> >
@@ -1,6 +1,6 @@
# ct.1 — Canonical Type Names: Validator + Migration — Implementation Plan # ct.1 — Canonical Type Names: Validator + Migration — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-10-canonical-type-names.md` (Components row ct.1) > **Parent spec:** `docs/specs/0007-canonical-type-names.md` (Components row ct.1)
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# Iteration ct.2: Typechecker Cleanup — Implementation Plan # Iteration ct.2: Typechecker Cleanup — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-10-canonical-type-names.md` > **Parent spec:** `docs/specs/0007-canonical-type-names.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1011,7 +1011,7 @@ allows — see `skills/audit/SKILL.md`).
- [ ] **Step C2: Confirm the four obsolete mechanisms catalogue** - [ ] **Step C2: Confirm the four obsolete mechanisms catalogue**
After ct.2 closes, two of the four mechanisms named in After ct.2 closes, two of the four mechanisms named in
`docs/specs/2026-05-10-canonical-type-names.md` ct.1 JOURNAL `docs/specs/0007-canonical-type-names.md` ct.1 JOURNAL
entry are gone: entry are gone:
- ✅ `Pattern::Ctor` imports-fallback (was lib.rs:2486-2521). - ✅ `Pattern::Ctor` imports-fallback (was lib.rs:2486-2521).
- ✅ `Term::Ctor` synth imports-fallback (was lib.rs:1979-2025). - ✅ `Term::Ctor` synth imports-fallback (was lib.rs:1979-2025).
@@ -1,6 +1,6 @@
# Iteration ct.3: Codegen + Mono Cleanup — Implementation Plan # Iteration ct.3: Codegen + Mono Cleanup — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-10-canonical-type-names.md` > **Parent spec:** `docs/specs/0007-canonical-type-names.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# Iteration ct.4: Milestone Close — Implementation Plan # Iteration ct.4: Milestone Close — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-10-canonical-type-names.md` > **Parent spec:** `docs/specs/0007-canonical-type-names.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -828,7 +828,7 @@ policy. No new regressions vs. baseline.
- [ ] **Step C2: Confirm all acceptance criteria from the spec** - [ ] **Step C2: Confirm all acceptance criteria from the spec**
Verify each item in `docs/specs/2026-05-10-canonical-type-names.md` Verify each item in `docs/specs/0007-canonical-type-names.md`
§ "Acceptance criteria": § "Acceptance criteria":
1. ✅ `load_workspace` validates every `Type::Con` (ct.1). 1. ✅ `load_workspace` validates every `Type::Con` (ct.1).
@@ -1,6 +1,6 @@
# Orchestrator-Refactor — Implementation Plan # Orchestrator-Refactor — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-11-implement-orchestrator-agent.md` > **Parent spec:** `docs/specs/0008-implement-orchestrator-agent.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# Iteration pr.1 — Plan-recon Subagent — Implementation Plan # Iteration pr.1 — Plan-recon Subagent — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-11-plan-recon-subagent.md` > **Parent spec:** `docs/specs/0009-plan-recon-subagent.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -455,7 +455,7 @@ Replace with:
during Step 1 when the milestone enters code territory the Boss during Step 1 when the milestone enters code territory the Boss
has not recently read; this is opt-in and not part of the standard has not recently read; this is opt-in and not part of the standard
process. Rationale: brainstorm's recon phase is interwoven with process. Rationale: brainstorm's recon phase is interwoven with
the user Q&A — see `docs/specs/2026-05-11-plan-recon-subagent.md` the user Q&A — see `docs/specs/0009-plan-recon-subagent.md`
for the full reasoning. for the full reasoning.
``` ```
@@ -1,6 +1,6 @@
# Audit / fieldtest / docwriter cadence restructure — Implementation Plan # Audit / fieldtest / docwriter cadence restructure — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-11-audit-fieldtest-docwriter-cadence.md` > **Parent spec:** `docs/specs/0012-audit-fieldtest-docwriter-cadence.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` to run this plan. Steps use `- [ ]` checkboxes for tracking. > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# gc.1 — Grounding-Check Agent — Implementation Plan # gc.1 — Grounding-Check Agent — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-11-brainstorm-grounding-check.md` > **Parent spec:** `docs/specs/0013-brainstorm-grounding-check.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -410,7 +410,7 @@ Current (lines 213-219):
during Step 1 when the milestone enters code territory the Boss during Step 1 when the milestone enters code territory the Boss
has not recently read; this is opt-in and not part of the standard has not recently read; this is opt-in and not part of the standard
process. Rationale: brainstorm's recon phase is interwoven with process. Rationale: brainstorm's recon phase is interwoven with
the user Q&A — see `docs/specs/2026-05-11-plan-recon-subagent.md` the user Q&A — see `docs/specs/0009-plan-recon-subagent.md`
for the full reasoning. for the full reasoning.
``` ```
@@ -420,14 +420,14 @@ Replace with:
- **Private agent:** `skills/brainstorm/agents/ailang-grounding-check.md` - **Private agent:** `skills/brainstorm/agents/ailang-grounding-check.md`
— dispatched in Step 7.5 as a hard-gate. The agent reads the spec — dispatched in Step 7.5 as a hard-gate. The agent reads the spec
with fresh context and reports PASS / BLOCK / INFRA_ERROR. See with fresh context and reports PASS / BLOCK / INFRA_ERROR. See
`docs/specs/2026-05-11-brainstorm-grounding-check.md` for the `docs/specs/0013-brainstorm-grounding-check.md` for the
design rationale. design rationale.
- **Ad-hoc dispatch.** The Boss MAY also ad-hoc dispatch - **Ad-hoc dispatch.** The Boss MAY also ad-hoc dispatch
`skills/planner/agents/ailang-plan-recon.md` during Step 1 when `skills/planner/agents/ailang-plan-recon.md` during Step 1 when
the milestone enters code territory the Boss has not recently the milestone enters code territory the Boss has not recently
read; this is opt-in and not part of the standard process. read; this is opt-in and not part of the standard process.
Rationale: brainstorm's recon phase is interwoven with the user Rationale: brainstorm's recon phase is interwoven with the user
Q&A — see `docs/specs/2026-05-11-plan-recon-subagent.md` for the Q&A — see `docs/specs/0009-plan-recon-subagent.md` for the
full reasoning. full reasoning.
``` ```
@@ -1,6 +1,6 @@
# Iter 23.4 — Mono-Pass Unification — Implementation Plan # Iter 23.4 — Mono-Pass Unification — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-11-23-eq-ord-prelude.md` (commit 841d65d, re-grounded 2026-05-11 against main HEAD 51da9fa, PASS) > **Parent spec:** `docs/specs/0014-23-eq-ord-prelude.md` (commit 841d65d, re-grounded 2026-05-11 against main HEAD 51da9fa, PASS)
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` to run this plan. Steps use `- [ ]` checkboxes for tracking. The implementer does NOT commit — work accumulates in the working tree; the Boss commits the iter at the end. > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` to run this plan. Steps use `- [ ]` checkboxes for tracking. The implementer does NOT commit — work accumulates in the working tree; the Boss commits the iter at the end.
@@ -1267,11 +1267,11 @@ The implement orchestrator's terminal Phase 4 (journal write) includes a "Bench"
## Hand-off ## Hand-off
This plan is written to the working tree at `docs/plans/2026-05-11-iter-23.4.md` (uncommitted). The Boss reviews and commits when handing off to `implement` (suggested commit subject: `plan: 23.4 mono-pass unification`). This plan is written to the working tree at `docs/plans/0033-iter-23.4.md` (uncommitted). The Boss reviews and commits when handing off to `implement` (suggested commit subject: `plan: 23.4 mono-pass unification`).
Hand-off to `implement` carries: Hand-off to `implement` carries:
- `plan_path`: `docs/plans/2026-05-11-iter-23.4.md` - `plan_path`: `docs/plans/0033-iter-23.4.md`
- `iter_id`: `23.4` - `iter_id`: `23.4`
- `task_range`: full (Tasks 111) - `task_range`: full (Tasks 111)
- Notes for the orchestrator-agent: - Notes for the orchestrator-agent:
@@ -43,7 +43,7 @@ or any on-disk fixture (including the prelude).
**Out of scope:** **Out of scope:**
- The five prelude free fns themselves (`ne`/`lt`/`le`/`gt`/`ge`). - The five prelude free fns themselves (`ne`/`lt`/`le`/`gt`/`ge`).
They land in iter 23.4 unchanged from the existing They land in iter 23.4 unchanged from the existing
`docs/plans/2026-05-11-iter-23.4.md`. `docs/plans/0033-iter-23.4.md`.
- Any modification to `examples/prelude.ail.json`. - Any modification to `examples/prelude.ail.json`.
- Any new diagnostic for the hypothetical multi-implicit-import - Any new diagnostic for the hypothetical multi-implicit-import
ambiguity case. ambiguity case.
@@ -1,6 +1,6 @@
# Iter 23.5 — Prelude free fns + E2E — Implementation Plan # Iter 23.5 — Prelude free fns + E2E — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-11-23-eq-ord-prelude.md` > **Parent spec:** `docs/specs/0014-23-eq-ord-prelude.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. No > to run this plan. Steps use `- [ ]` checkboxes for tracking. No
@@ -1224,7 +1224,7 @@ Same command as Step 1. Confirm empty output. (This is the "RED" state.)
- [ ] **Step 3: Write minimal implementation** - [ ] **Step 3: Write minimal implementation**
Edit `docs/DESIGN.md`. After line 1702 (the line ending with Edit `docs/DESIGN.md`. After line 1702 (the line ending with
`"... see `docs/specs/2026-05-09-22-typeclasses.md` 'Amendments' for the substantive rationale."`), `"... see `docs/specs/0002-22-typeclasses.md` 'Amendments' for the substantive rationale."`),
insert two blank lines and the following paragraph block: insert two blank lines and the following paragraph block:
```markdown ```markdown
@@ -1409,7 +1409,7 @@ record per-script exit codes in the `Stats` section.
## Handoff ## Handoff
Plan file: `docs/plans/2026-05-12-iter-23.5.md`. Plan file: `docs/plans/0035-iter-23.5.md`.
Hand off to `skills/implement` with: this plan path. Boss commits the Hand off to `skills/implement` with: this plan path. Boss commits the
plan with subject `plan: iter 23.5 prelude free fns + E2E — 8 tasks` plan with subject `plan: iter 23.5 prelude free fns + E2E — 8 tasks`
@@ -1,6 +1,6 @@
# rt.1 — Roundtrip Invariant Audit Tests — Implementation Plan # rt.1 — Roundtrip Invariant Audit Tests — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-12-roundtrip-invariant.md` > **Parent spec:** `docs/specs/0015-roundtrip-invariant.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# Iter boss — Implementation Plan # Iter boss — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-12-boss-skill.md` > **Parent spec:** `docs/specs/0016-boss-skill.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# cma.1 — Implementation Plan # cma.1 — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-12-cross-model-authoring-form-test.md` > **Parent spec:** `docs/specs/0017-cross-model-authoring-form-test.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -74,7 +74,7 @@ Empirical measurement of whether `.ail.json` or `.ailx` is the form a
foreign LLM author reaches for and succeeds with. Single subject for foreign LLM author reaches for and succeeds with. Single subject for
v1: Qwen3-Coder-Next via IONOS. Two blind cohorts; same four tasks. v1: Qwen3-Coder-Next via IONOS. Two blind cohorts; same four tasks.
Parent spec: `docs/specs/2026-05-12-cross-model-authoring-form-test.md`. Parent spec: `docs/specs/0017-cross-model-authoring-form-test.md`.
## Layout ## Layout
@@ -1,6 +1,6 @@
# cma.2 — Implementation Plan # cma.2 — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-12-cross-model-authoring-form-test.md` > **Parent spec:** `docs/specs/0017-cross-model-authoring-form-test.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.
@@ -1,6 +1,6 @@
# ms.1 — Pipeline anyhow-chain preservation — Implementation Plan # ms.1 — Pipeline anyhow-chain preservation — Implementation Plan
> **Parent spec:** `docs/specs/2026-05-12-multi-subject-codellama.md` > **Parent spec:** `docs/specs/0018-multi-subject-codellama.md`
> >
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` > **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking. > to run this plan. Steps use `- [ ]` checkboxes for tracking.

Some files were not shown because too many files have changed in this diff Show More