832375f2ac
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.
661 lines
36 KiB
Markdown
661 lines
36 KiB
Markdown
# DESIGN.md → `design/` role-split — Design Spec
|
||
|
||
**Date:** 2026-05-19
|
||
**Status:** Draft — awaiting user spec review
|
||
**Authors:** Brummel (orchestrator) + Claude
|
||
|
||
## Goal
|
||
|
||
`docs/DESIGN.md` is one **3020-line** file doing three different jobs
|
||
for three different consumers with three different lifetimes. The
|
||
line count is the *symptom* of role-conflation, not of mess: the
|
||
just-closed `docs-honesty-lint` milestone ran a full honesty pass and
|
||
DESIGN.md stayed 3020 lines, because honesty-lint operates *within* a
|
||
job and its own audit-trail invariant *mandates retaining* the bulky
|
||
decision-record prose (DESIGN.md Decision 6, lines 241–243: "records
|
||
the *why* … for the audit trail"). You cannot clean your way out of
|
||
conflation; the conflation is the structural defect.
|
||
|
||
Replace `docs/DESIGN.md` with a `design/` directory split on the
|
||
**consumer/lifetime axis** — `design/contracts/` (the hot,
|
||
test-linked invariant set), `design/models/` (one whitepaper per
|
||
model) — with `design/INDEX.md` as the **sole addressable spine**.
|
||
Decision-record prose moves to `docs/journals/`. The split is a
|
||
**clean cut**: `docs/DESIGN.md` is deleted; every named reference is
|
||
repointed in one build-atomic milestone.
|
||
|
||
The three conflated jobs and their distinct consumers:
|
||
|
||
- **Contract** — prescriptive, test-linked invariants (Decision 6's
|
||
binding Form-A constraints, the Roundtrip Invariant, the
|
||
borrow/own binding rules, the frozen value layout). Consumer:
|
||
`architect` (mandatory full read at *every* milestone close),
|
||
`grounding-check` (every spec), the honesty sweep. Wants:
|
||
structured, addressable, test-linked, small, hot. The only job on
|
||
the per-milestone hot path.
|
||
- **Model exposition** — whitepaper-shaped narratives (RC +
|
||
Uniqueness, typeclasses, effects, the authoring-surface rationale).
|
||
Consumer: onboarding (fresh-context LLM, `fieldtester`).
|
||
Irreducible — the code cannot speak the gestalt.
|
||
- **Decision-record / relitigating-guard** — why X was chosen, why
|
||
Y/Z were rejected (region inference, tracing GC, …). Consumer: a
|
||
future `brainstorm`, so it does not re-propose a settled-and-
|
||
rejected idea. This already has a home — `docs/journals/`.
|
||
|
||
Underlying principle: the code is authoritative for *what it does*;
|
||
the spec's irreducible job is *what is promised* plus a pointer to
|
||
the green test that ratifies it.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
design/
|
||
INDEX.md sole addressable spine — a typed two-table ledger
|
||
contracts/ prose-authoritative invariants (the architect hot path)
|
||
feature-acceptance.md authoring-surface.md roundtrip-invariant.md
|
||
memory-model.md typeclasses.md float-semantics.md
|
||
frozen-value-layout.md honesty-rule.md tail-calls.md
|
||
data-model.md embedding-abi.md verification.md
|
||
models/ one whitepaper per model (onboarding path)
|
||
rc-uniqueness.md typeclasses.md effects.md authoring-surface.md pipeline.md
|
||
|
||
docs/journals/2026-05-19-design-decision-records.md relitigation-guard archive
|
||
docs/DESIGN.md DELETED (clean cut)
|
||
```
|
||
|
||
Five structural commitments:
|
||
|
||
1. **Polymorphic INDEX link.** An INDEX row's `link` is *either* a
|
||
`design/` file *or* an authoritative source path. Where code is
|
||
the single source of truth (mangling, env construction,
|
||
qualified-cross-module-ref resolution), there is **no prose
|
||
contract file** — the row points at the source `//!` header and
|
||
names the ratifying test, killing the prose-vs-code second truth.
|
||
`frozen-value-layout` is the deliberate dual-link exception (a
|
||
one-way human commitment *and* a codegen contract → both a prose
|
||
file and a source pointer). The polymorphic disposition is fixed
|
||
per-contract in the Components disposition table below.
|
||
|
||
2. **`###`-subsection is the unit of relocation.** No sentence-
|
||
surgery. Each `###` subsection of DESIGN.md moves whole to
|
||
`contracts/`, `models/`, or the decision-record journal. The
|
||
MIXED `##` Decisions (6/9/10/11) decompose at their existing
|
||
`###` seam, which recon confirmed resolves cleanly.
|
||
|
||
3. **Build-atomic, not just semantically atomic.**
|
||
`crates/ailang-core/tests/design_schema_drift.rs:22` uses
|
||
`include_str!("../../../docs/DESIGN.md")` — a compile-time path.
|
||
The instant `docs/DESIGN.md` is deleted the workspace **does not
|
||
compile** until that `include_str!` is retargeted. The content
|
||
move + the 4-executable retarget + the 2-diagnostic/2-E2E
|
||
retarget + the new pin test land in **one commit**; the tree is
|
||
never half-moved. This is a fail-closed property, not a hazard.
|
||
|
||
4. **The honesty-rule self-repointing resolves the internal
|
||
contradiction.** Two distinct self-referential passages, with
|
||
*different* pin status (grounding-check verified):
|
||
- `### What this document is — and the honesty rule it holds
|
||
itself to` (DESIGN.md:56–82) **is** pinned: `docs_honesty_pin.rs:70`
|
||
pins `"the honesty rule it holds itself to"` and `:72` pins
|
||
`"whether the document asserts something exists, works, or
|
||
changed that does not"` (both inside
|
||
`design_md_present_tense_anchors_present`). This becomes
|
||
`contracts/0007-honesty-rule.md`, **rewritten** so the rule states
|
||
the new home (rationale → `docs/journals/`); those two pins are
|
||
retargeted to the new file *and* the new wording in the same
|
||
atomic change.
|
||
- Decision 6's :242 sentence — *"The rest of this section records
|
||
the why of Decision 6 for the audit trail; the constraints
|
||
listed below describe the surface as shipped."* — is pinned by
|
||
**no test anywhere** (grounding-check grepped `crates/*/tests/`,
|
||
in-source `crates/*/src/`, `effect_doc_honesty_pin.rs`: zero
|
||
matches). It is itself decision-record self-assertion describing
|
||
the *old conflated structure*. The milestone **retires** it: its
|
||
"why of Decision 6" content moves to the decision-record journal;
|
||
the meta-sentence that asserts DESIGN.md retains audit-trail
|
||
prose is not carried forward and needs **no successor pin** —
|
||
code never protected it, and should not, because that sentence
|
||
is exactly the audit-trail self-claim the split removes from the
|
||
contract surface.
|
||
|
||
The internal contradiction (a doc asserting of itself that it
|
||
"records the why for the audit trail" while the milestone moves
|
||
the why out) is closed *by* the milestone: the asserting sentence
|
||
is retired, and the only honesty self-claim that survives —
|
||
"rationale lives in `docs/journals/`" — is the rewritten
|
||
`honesty-rule.md`, which the retargeted `:70,72` pins protect.
|
||
|
||
5. **Clean cut, no stub, no redirect.** `docs/DESIGN.md` is deleted.
|
||
No transitional pointer file (a "see elsewhere" file is itself
|
||
history-pointing — a doc-honesty violation in the milestone that
|
||
exists to enforce doc honesty). Matches the no-deprecation-window
|
||
precedent (mut/var/assign removal) and the current-state-mirror
|
||
discipline.
|
||
|
||
## Concrete code shapes
|
||
|
||
### 1. The delivered artifacts (this is an infra milestone — these are the headline)
|
||
|
||
**`design/INDEX.md`** — the typed two-table ledger. `link` is
|
||
polymorphic; `ratifying-test` is mandatory for `kind=contract`:
|
||
|
||
```markdown
|
||
# AILang Design — Index
|
||
|
||
The sole addressable entry point. Every contract and model is
|
||
reached from here. A contract is a prescriptive, test-linked
|
||
invariant; a model is a whitepaper narrative. `ratifying-test` names
|
||
the green test that proves a contract still holds. `link` is
|
||
polymorphic: a `design/` file, or the authoritative source `//!`
|
||
header when the code is the single source of truth.
|
||
|
||
## Contracts
|
||
| id | consumer / lifetime | ratifying-test | link |
|
||
|----|---------------------|----------------|------|
|
||
| feature-acceptance | brainstorm-gate / stable | skills/brainstorm/SKILL.md Step 4 | contracts/0004-feature-acceptance.md |
|
||
| authoring-surface | LLM author / stable | crates/ailang-surface round_trip.rs | contracts/0001-authoring-surface.md |
|
||
| roundtrip-invariant | every release / stable | crates/ailang-surface round_trip.rs | contracts/0009-roundtrip-invariant.md |
|
||
| memory-model | LLM author / stable | crates/ailang-check/src/uniqueness.rs (in-source mod tests) | contracts/0008-memory-model.md |
|
||
| data-model | LLM author / stable | crates/ailang-core/tests/design_schema_drift.rs | contracts/0002-data-model.md |
|
||
| 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 //! |
|
||
| 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 | contracts/0006-frozen-value-layout.md + runtime/rc.c §layout |
|
||
| float-semantics | LLM author / stable | crates/ail/tests/eq_float_noinstance.rs | contracts/0005-float-semantics.md |
|
||
| typeclasses | LLM author / stable | crates/ail/tests/show_no_instance_e2e.rs | contracts/0013-typeclasses.md |
|
||
| str-abi | runtime ABI / stable | crates/ail/tests/e2e.rs (Str path) | 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) | contracts/0012-tail-calls.md |
|
||
| honesty-rule | architect+grounding / stable | crates/ailang-core/tests/docs_honesty_pin.rs | contracts/0007-honesty-rule.md |
|
||
| embedding-abi | embedding host / stable | crates/ailang-codegen/tests/embed_record_layout_pin.rs | contracts/0003-embedding-abi.md |
|
||
| scope-boundaries | architect+author / stable | crates/ailang-core/tests/effect_doc_honesty_pin.rs | contracts/0010-scope-boundaries.md |
|
||
| verification | architect / stable | bench/architect_sweeps.sh | contracts/0014-verification.md |
|
||
|
||
## Models
|
||
| id | consumer / lifetime | link |
|
||
|----|---------------------|------|
|
||
| rc-uniqueness | onboarding / evolves | models/0004-rc-uniqueness.md |
|
||
| typeclasses | onboarding / evolves | models/0005-typeclasses.md |
|
||
| effects | onboarding / evolves | models/0002-effects.md |
|
||
| authoring-surface | onboarding / evolves | models/0001-authoring-surface.md |
|
||
| pipeline | onboarding / evolves | models/0003-pipeline.md |
|
||
```
|
||
|
||
The `ratifying-test` column above is now **Boss-resolved to exact
|
||
recon-verified paths** (plan-recon confirmed each file exists; the
|
||
`design_index_pin.rs` clause-2 check, widened to accept
|
||
`crates/**/src/*.rs` in-source `#[cfg(test)] mod tests`, requires
|
||
every token to resolve to a real file). The full per-`###`
|
||
relocation map and the adjudication rationale for the three
|
||
ledger additions (`qualified-xref`, `str-abi`, `scope-boundaries`)
|
||
are in the **Appendix — Boss-adjudicated relocation map** at the
|
||
end of this spec; that appendix is the authoritative,
|
||
placeholder-free map the planner consumes.
|
||
|
||
**A sample contract file** — `design/contracts/0005-float-semantics.md`
|
||
(content moved verbatim from DESIGN.md:2700–2838, header re-levelled
|
||
to file root, all decision-record/why-prose stripped to the journal):
|
||
|
||
```markdown
|
||
# Float semantics
|
||
|
||
Float is the IEEE-754 double-precision primitive. Float has **no
|
||
`Eq` and no `Ord` instance by design**: IEEE-754 ordering is partial
|
||
(NaN is unordered), so a total `Eq`/`Ord` would be a lie about the
|
||
type. … [present-tense contract prose only] …
|
||
|
||
`float_to_str` is type-installed; codegen is reserved and not yet
|
||
shipped.
|
||
|
||
Ratified by: `crates/ail/tests/eq_float_noinstance.rs`.
|
||
```
|
||
|
||
**The anti-regrowth guard** — `crates/ailang-core/tests/design_index_pin.rs`
|
||
(the concrete must-fail artifact for an infra milestone — its correct
|
||
behaviour is to go RED the instant the structure re-conflates):
|
||
|
||
```rust
|
||
//! Structural pin for the design/ ledger. Sibling of
|
||
//! docs_honesty_pin.rs. Fails RED the instant the design/ split
|
||
//! re-conflates contract + rationale + narrative, an INDEX row
|
||
//! dangles, a contract loses its ratifying test, or docs/DESIGN.md
|
||
//! is resurrected.
|
||
|
||
// helper: workspace root = CARGO_MANIFEST_DIR/../.. ; norm() =
|
||
// split_whitespace().join(" ") — line-wrap-independent, identical
|
||
// shape to docs_honesty_pin.rs.
|
||
|
||
#[test]
|
||
fn design_md_is_gone() {
|
||
// clause 4 — clean-cut pin
|
||
assert!(!root().join("docs/DESIGN.md").exists(),
|
||
"docs/DESIGN.md was resurrected; the split is clean-cut");
|
||
}
|
||
|
||
#[test]
|
||
fn every_index_link_resolves() {
|
||
// clause 1 — parse design/INDEX.md tables; for each row, the
|
||
// `link` target (design/ file OR source path; the dual-link
|
||
// row's first segment before " + ") exists on disk.
|
||
}
|
||
|
||
#[test]
|
||
fn every_contract_names_a_resolvable_ratifying_test() {
|
||
// clause 2 — every kind=contract row's ratifying-test token
|
||
// resolves to a real file under crates/**/tests, crates/**/src
|
||
// (in-source `#[cfg(test)] mod tests` are first-class ratifiers
|
||
// in this project — see Boss adjudication OQ1/OQ2), bench/, or
|
||
// skills/**/SKILL.md.
|
||
}
|
||
|
||
#[test]
|
||
fn contracts_carry_no_decision_record_prose() {
|
||
// clause 3 — the conflation tripwire. For each
|
||
// design/contracts/*.md, norm() the body and assert it contains
|
||
// none of: "we rejected", "an earlier draft", "Why not other",
|
||
// "was retired in iter", "rollback plan", "previously all".
|
||
}
|
||
```
|
||
|
||
### 2. The one real code change — compiler diagnostic, before → after
|
||
|
||
This is the clause-1 / clause-3 evidence. The pre-existing fixture
|
||
the diagnostic E2E runs (unchanged), the program an LLM author
|
||
writes that **must fail** to typecheck:
|
||
|
||
```scheme
|
||
; examples/eq_float_noinstance.ail
|
||
(module eq_float_noinstance
|
||
(fn main
|
||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||
(params)
|
||
(body (app print (if (app eq 1.0 2.0) 1 0)))))
|
||
```
|
||
|
||
`crates/ailang-check/src/lib.rs:873` (the Float branch):
|
||
|
||
```
|
||
- orderability per IEEE-754); see DESIGN.md §\"Float semantics\".",
|
||
+ orderability per IEEE-754); see design/contracts/0005-float-semantics.md.",
|
||
```
|
||
|
||
`crates/ailang-check/src/lib.rs:888` (the Show branch):
|
||
|
||
```
|
||
- the prelude; see DESIGN.md §\"Prelude (built-in) \
|
||
- classes\". User types declare their own \
|
||
+ the prelude; see design/contracts/0013-typeclasses.md. \
|
||
+ User types declare their own \
|
||
```
|
||
|
||
`crates/ail/tests/eq_float_noinstance.rs:40` — the assertion
|
||
currently passes on `"Float semantics" || "DESIGN"`; both substrings
|
||
vanish, so it updates in lockstep:
|
||
|
||
```rust
|
||
- no_inst.message.contains("Float semantics") || no_inst.message.contains("DESIGN"),
|
||
- "expected NoInstance message to cross-reference DESIGN.md §Float semantics, got: {:?}",
|
||
+ no_inst.message.contains("design/contracts/0005-float-semantics.md"),
|
||
+ "expected NoInstance message to cross-reference the float-semantics contract, got: {:?}",
|
||
```
|
||
|
||
`crates/ail/tests/show_no_instance_e2e.rs:48` — analogous: the
|
||
asserted substring becomes `"design/contracts/0013-typeclasses.md"`.
|
||
|
||
### 3. The four executable retargets (before → after)
|
||
|
||
`bench/architect_sweeps.sh:22-28`:
|
||
|
||
```sh
|
||
- DESIGN="docs/DESIGN.md"
|
||
- [[ ! -f "$DESIGN" ]] && { echo "could not find $DESIGN"; exit 2; }
|
||
+ INDEX="design/INDEX.md"
|
||
+ [[ ! -f "$INDEX" ]] && { echo "could not find $INDEX"; exit 2; }
|
||
```
|
||
|
||
Each `run_sweep` greps the `design/contracts/*.md` + `design/models/*.md`
|
||
set instead of the single file; exit-code contract preserved
|
||
(0 clean / 1 anchor-found / 2 spine-not-found). Sweep 5 (honesty)
|
||
scans all `design/` prose; the verbatim regexes are unchanged.
|
||
|
||
`crates/ailang-core/tests/design_schema_drift.rs:22`:
|
||
|
||
```rust
|
||
- const DESIGN_MD: &str = include_str!("../../../docs/DESIGN.md");
|
||
+ const DATA_MODEL: &str = include_str!("../../../design/contracts/0002-data-model.md");
|
||
```
|
||
|
||
The `data_model_section()` slicer (`## Data model` … `\n## Pipeline`)
|
||
and `data_model_section_is_bounded` are **removed**: the whole file
|
||
is now the data-model contract, so the section-extraction premise
|
||
vanishes — a simplification the split enables. Every
|
||
`section.contains(anchor)` assertion runs against the whole
|
||
`DATA_MODEL` string.
|
||
|
||
`crates/ailang-core/tests/docs_honesty_pin.rs` and
|
||
`effect_doc_honesty_pin.rs`: the `read("docs/DESIGN.md")` calls split
|
||
into reads of the specific `design/` files where each pinned sentence
|
||
now lives. The present/absent pin strings are unchanged **except**
|
||
the two honesty-rule anchors at `docs_honesty_pin.rs:70,72` (`"the
|
||
honesty rule it holds itself to"` / `"whether the document asserts
|
||
something exists, works, or changed that does not"`), which are
|
||
updated to the rewritten `contracts/0007-honesty-rule.md` wording in
|
||
lockstep with that file. The Decision-6 `:242` audit-trail sentence
|
||
is pinned by no test (verified) and is retired to the decision-record
|
||
journal, not retargeted — there is nothing to repoint, by design.
|
||
|
||
### 4. Agent reading-list rewrite (representative before → after)
|
||
|
||
`skills/audit/agents/ailang-architect.md:30`:
|
||
|
||
```
|
||
- 2. `docs/DESIGN.md` — the canonical specification. Drift is measured against
|
||
+ 2. `design/INDEX.md` — the typed contract ledger and sole spine.
|
||
+ Walk the Contracts table; drift is measured against each row's
|
||
+ `link` target (a `design/contracts/` file or the source `//!`
|
||
+ it names). `design/models/` is context, not a drift surface.
|
||
```
|
||
|
||
The other ~11 reading-list bullets
|
||
(`grounding-check`, `fieldtester`, `debugger`, `bencher`, `tester`,
|
||
`implementer`, `implement-orchestrator`, `spec-reviewer`,
|
||
`quality-reviewer`, `plan-recon`, `docwriter`) are rewritten to their
|
||
role: grounding-check and architect read `contracts/`; fieldtester
|
||
reads `INDEX.md` + `models/` (no-edit limit preserved, repointed);
|
||
bencher reads `models/0004-rc-uniqueness.md` (Decision-9/Boehm narrative);
|
||
the rest point at `design/INDEX.md` as the spine.
|
||
|
||
## Components
|
||
|
||
The per-contract disposition (fixes the polymorphic link, planner
|
||
does not re-decide it):
|
||
|
||
| Contract | Disposition | Rationale |
|
||
|----------|-------------|-----------|
|
||
| feature-acceptance | prose file | gate text, prose-authoritative |
|
||
| authoring-surface | prose file | binding Form-A constraints, prose-stated |
|
||
| roundtrip-invariant | prose file | the invariant statement is prose |
|
||
| memory-model | prose file | Decision 10 `### Language-design constraints (binding)` + `### Schema additions` + `### Codegen contract`; binding, prose-stated |
|
||
| data-model | prose file | the wire schema an author must produce is a *promise* (prose-authoritative); `design_schema_drift.rs` `include_str!`s it |
|
||
| float-semantics | prose file | author-facing; the diagnostic points here |
|
||
| typeclasses | prose file | coherence/dispatch rules + prelude classes; the Show diagnostic points here |
|
||
| tail-calls | prose file | the propagation rule is prose-stated, check-ratified |
|
||
| frozen-value-layout | prose file **+** source link | one-way human commitment AND codegen contract — deliberate dual-link |
|
||
| honesty-rule | prose file | rewritten; resolves the internal contradiction |
|
||
| embedding-abi | prose file | the M3-frozen ABI contract, author + host facing |
|
||
| verification | prose file | the cross-cycle verification contract |
|
||
| mangling | **source link only** | codegen behaviour; prose would duplicate code; `eq_ord_e2e.rs` ratifies |
|
||
| env-construction | **source link only** | codegen behaviour; `duplicate_ctor_pin.rs` ratifies |
|
||
|
||
Models (always prose whitepapers): `rc-uniqueness` (Decision 10
|
||
narrative + Decision 9 Boehm rationale), `typeclasses` (resolution /
|
||
monomorphisation narrative), `effects` (Decision 3 narrative),
|
||
`authoring-surface` (notation rationale, candidate notations,
|
||
empirical addendum), `pipeline` (Pipeline + CLI).
|
||
|
||
Decision-record archive — `docs/journals/2026-05-19-design-decision-records.md`:
|
||
the `### Why not other memory models`, `### What this Decision
|
||
deliberately does not do` (×N), `### Empirical addendum`,
|
||
`### First choice and rollback plan`, and every "considered and
|
||
rejected" passage, moved whole at `###` granularity. The journals
|
||
`INDEX.md` gets the one-line pointer per project convention.
|
||
|
||
## Data flow
|
||
|
||
- **Architect, milestone close:** reads `design/INDEX.md` → walks
|
||
the Contracts table → for each row reads the `link` target →
|
||
measures drift against it. `architect_sweeps.sh` scans the
|
||
`design/` prose set; exit codes unchanged.
|
||
- **grounding-check, per spec:** reads `design/INDEX.md` → the
|
||
contract rows the spec's assumptions touch → composes.
|
||
- **LLM author, NoInstance:** the diagnostic names
|
||
`design/contracts/0005-float-semantics.md` (or `…/typeclasses.md`) →
|
||
opens exactly that contract → self-corrects.
|
||
- **Future brainstorm tempted to re-propose region inference:** the
|
||
"why rejected" prose is in
|
||
`docs/journals/2026-05-19-design-decision-records.md`, reachable
|
||
from the journals INDEX — not in any contract file.
|
||
- **`design_index_pin.rs`, every `cargo test`:** parses INDEX.md →
|
||
asserts all links resolve, all contracts name a resolvable
|
||
ratifying-test, no contract carries decision-record prose,
|
||
`docs/DESIGN.md` is absent.
|
||
|
||
## Error handling
|
||
|
||
All failure modes fail closed:
|
||
|
||
- INDEX row → missing target ⇒ `design_index_pin.rs`
|
||
`every_index_link_resolves` RED.
|
||
- A `contracts/` file regrows "we rejected"/"Why not other"/… ⇒
|
||
`contracts_carry_no_decision_record_prose` RED (the conflation
|
||
tripwire — the milestone's reason to exist, enforced in code).
|
||
- `docs/DESIGN.md` resurrected ⇒ `design_md_is_gone` RED.
|
||
- A contract names a ratifying-test that does not resolve ⇒
|
||
`every_contract_names_a_resolvable_ratifying_test` RED.
|
||
- `architect_sweeps.sh` cannot find `design/INDEX.md` ⇒ exit 2
|
||
(preserved "infra missing" semantics, repointed).
|
||
- Content move lands without the `include_str!` retarget ⇒
|
||
`cargo build` fails. This is the build-atomic fail-closed
|
||
property; the planner sequences the single landing build-green.
|
||
- **Recon-undercount countermeasure (acceptance gate).** The
|
||
milestone's acceptance includes a tree-wide
|
||
`grep -rIn 'DESIGN\.md'` over *all file types*
|
||
(`bench/ skills/ crates/ runtime/ ail-embed/ examples/ docs/
|
||
CLAUDE.md`) returning **only** the append-only history docs
|
||
(`docs/journals/`, `docs/specs/`, `docs/plans/`,
|
||
`docs/roadmap.md`, `docs/WhatsNew.md`, `docs/journal-archive.md`)
|
||
— zero live references in code, scripts, agent files, or
|
||
comments. Recon proved the carrier's file-type list
|
||
(`*.md *.rs *.py *.sh *.toml`) silently misses `.c`/`.h`/`.ail`;
|
||
the gate is unfiltered (`grep -rIn`, no `--include`) and any
|
||
claimed-absent path is `ls`-verified. This is the
|
||
fourth-recurrence recon-undercount class made an explicit gate.
|
||
|
||
## Testing strategy
|
||
|
||
- **RED-first spine:** `design_index_pin.rs` (the 4 clauses above)
|
||
is written first; RED until `design/` exists, is consistent, and
|
||
`docs/DESIGN.md` is gone; GREEN when the split is complete and
|
||
faithful.
|
||
- **Retarget, not rewrite:** `design_schema_drift.rs`,
|
||
`docs_honesty_pin.rs`, `effect_doc_honesty_pin.rs` keep their
|
||
*property* (the schema/honesty invariant stays documented); only
|
||
the path/anchor moves. `design_schema_drift.rs` additionally
|
||
*simplifies* (the `## Data model`/`## Pipeline` slicer is removed
|
||
— the file boundary now bounds the section).
|
||
- **Lockstep E2Es:** `eq_float_noinstance.rs`,
|
||
`show_no_instance_e2e.rs` updated with the diagnostic strings;
|
||
they continue to assert the author-affordance (a correct,
|
||
resolvable pointer).
|
||
- **Whole-suite GREEN:** `cargo test` workspace-wide must be green
|
||
post-split (the `include_str!` retarget + all path moves
|
||
consistent). Build-atomicity makes a half-move a compile failure,
|
||
not a silent-wrong state.
|
||
- **Bench unaffected:** recon confirmed the bench harness
|
||
(`bench/check.py`, `compile_check.py`, `cross_lang.py`,
|
||
`run.sh`) has zero `DESIGN.md` references; only
|
||
`architect_sweeps.sh` (audit-time, not bench-time) opens it.
|
||
Generated IR is byte-identical (no codegen change — the
|
||
diagnostic *string* is not in the IR). Any bench firing is the
|
||
tracked P2 noise and is causally exonerable by byte-identical-IR.
|
||
- **Audit, mandatory at milestone close:** architect drift review
|
||
against the *new* `design/` (the architect's own reading list is
|
||
one of the rewritten artifacts — the audit validates the
|
||
structure it now reads); bencher causal exoneration as usual.
|
||
- **No fieldtest:** zero authoring-surface change. The
|
||
diagnostic-string change is a doc-pointer, not a language or
|
||
authoring-surface change. (Recorded explicitly so the post-audit
|
||
step is not skipped by omission but by reasoned exclusion.)
|
||
|
||
## Acceptance criteria
|
||
|
||
1. `docs/DESIGN.md` does not exist; `design/INDEX.md`,
|
||
`design/contracts/*.md`, `design/models/*.md`, and
|
||
`docs/journals/2026-05-19-design-decision-records.md` exist and
|
||
are internally consistent.
|
||
2. Every `###` subsection of the former DESIGN.md is accounted for
|
||
in exactly one destination (contract / model / decision-record);
|
||
no content is silently dropped.
|
||
3. `design/INDEX.md` Contracts table: every `link` resolves, every
|
||
row names a resolvable `ratifying-test`. Models table: every
|
||
`link` resolves.
|
||
4. `crates/ailang-core/tests/design_index_pin.rs` is GREEN with all
|
||
four clauses; it was demonstrably RED before the split landed.
|
||
5. `design_schema_drift.rs`, `docs_honesty_pin.rs`,
|
||
`effect_doc_honesty_pin.rs` are GREEN against the new files;
|
||
their protected properties are unchanged.
|
||
6. The compiler emits `design/contracts/0005-float-semantics.md` /
|
||
`design/contracts/0013-typeclasses.md` in the two NoInstance
|
||
diagnostics; `eq_float_noinstance.rs` and `show_no_instance_e2e.rs`
|
||
assert the new pointer and are GREEN.
|
||
7. `cargo test` workspace-wide is GREEN; `cargo build` is clean.
|
||
8. Tree-wide `grep -rIn 'DESIGN\.md'` (no `--include`) returns
|
||
matches **only** in the append-only history docs; zero live
|
||
references in code, scripts, agent files, SKILL bodies,
|
||
`CLAUDE.md`, `skills/README.md`, or comments.
|
||
9. `bench/architect_sweeps.sh` runs against `design/`, exits 0 on
|
||
the clean tree, and its exit-2 path triggers on a missing
|
||
`design/INDEX.md`.
|
||
10. The ~12 agent reading lists, the 5 SKILL.md bodies,
|
||
`CLAUDE.md`, and `skills/README.md` name the new spine; no agent
|
||
contract still instructs reading a file that does not exist.
|
||
11. The milestone landed in a build-atomic shape (no commit leaves
|
||
the workspace non-compiling).
|
||
12. Every `##`/`###` of the former DESIGN.md maps to exactly one
|
||
destination in the Appendix table; the three ledger additions
|
||
(`qualified-xref`, `str-abi`, `scope-boundaries`) have INDEX
|
||
rows and resolvable ratifiers; the `crates/ailang-codegen/src/lib.rs:103`
|
||
"Iter 13b" dangling cite is rewritten to drop the unresolvable
|
||
reference (keeping it would itself violate the honesty rule).
|
||
|
||
## Appendix — Boss-adjudicated relocation map (authoritative, placeholder-free)
|
||
|
||
This appendix supersedes any ambiguity in §Components. It is the
|
||
map the planner consumes. Every `##`/`###` of DESIGN.md (3020
|
||
lines; no `## Decision 7` — numbering gap, not drift) has exactly
|
||
one destination. `D` = `docs/journals/2026-05-19-design-decision-records.md`
|
||
(decision-record archive). `IX` = `design/INDEX.md` preamble.
|
||
|
||
**Bucketing principle.** *Contract* = prescriptive + obeyed/checked
|
||
by an author, the architect, or a green test (binding, schema,
|
||
enforcement, honesty-pinned, present-tense scope claim). *Model* =
|
||
explanatory narrative; reading it is optional for correctness; no
|
||
test pins it. *Decision-record* = why-X-chosen / why-Y-rejected /
|
||
"deliberately does not do" / rollback / empirical addendum /
|
||
how-the-doc-reached-its-wording.
|
||
|
||
| `##` / `###` | Lines | Destination |
|
||
|---|---|---|
|
||
| `## Goal` | 6–18 | IX preamble |
|
||
| `## Project ecosystem` (intro) | 19–55 | IX preamble |
|
||
| ` ### What this document is — honesty rule` | 56–82 | `contracts/0007-honesty-rule.md` (**rewritten**; pins `docs_honesty_pin.rs:70,72`) |
|
||
| `## Project language: English` | 83–92 | IX preamble |
|
||
| `## Feature-acceptance criterion` | 93–164 | `contracts/0004-feature-acceptance.md` |
|
||
| `## Decision 1: source = data` | 165–176 | D |
|
||
| `## Decision 2: content-addressed` | 177–189 | D |
|
||
| `## Decision 3: pure core + effects` | 190–204 | `models/0002-effects.md` (pins `effect_doc_honesty_pin.rs` present-anchors — pin reads this file) |
|
||
| `## Decision 4: HM + refinements` | 205–213 | D |
|
||
| `## Decision 5: emit LLVM IR as text` | 214–229 | D |
|
||
| `## Decision 6` intro | 230–240 | `contracts/0001-authoring-surface.md` |
|
||
| ` (Decision 6 :241–243 audit-trail sentence)` | 241–243 | D (retired, no successor pin — §Architecture-4) |
|
||
| ` ### Why this is opening up` | 245–267 | D |
|
||
| ` ### Architectural pin: data structure is SoT` | 268–297 | `contracts/0001-authoring-surface.md` |
|
||
| ` ### Constraints (hard, in priority order)` | 298–331 | `contracts/0001-authoring-surface.md` |
|
||
| ` ### Candidate notations` | 332–471 | `models/0001-authoring-surface.md` |
|
||
| ` ### First choice and rollback plan` | 472–486 | D |
|
||
| ` ### Implementation outline` | 487–519 | D |
|
||
| ` ### What this Decision deliberately does not do` | 520–536 | D |
|
||
| ` ### Form refinements during implementation` | 537–589 | D |
|
||
| ` ### Form (B) — human prose projection` | 590–674 | `models/0001-authoring-surface.md` (the Form-B placeholder present-anchor in `docs_honesty_pin.rs` re-points here) |
|
||
| ` ### Empirical addendum` | 675–730 | D |
|
||
| `## Decision 8: explicit verified tail calls` | 731–787 | `contracts/0012-tail-calls.md` |
|
||
| `## Decision 9` intro | 788–852 | `models/0004-rc-uniqueness.md` |
|
||
| ` ### Per-fn arena via stack alloca` | 853–913 | `models/0004-rc-uniqueness.md` |
|
||
| `## Decision 10` intro | 914–977 | `models/0004-rc-uniqueness.md` |
|
||
| ` ### Why not other memory models` | 978–1014 | D |
|
||
| ` ### The LLM-aware sharpening` | 1015–1122 | `models/0004-rc-uniqueness.md` |
|
||
| ` ### Language-design constraints (binding)` | 1123–1150 | `contracts/0008-memory-model.md` |
|
||
| ` ### Schema additions` | 1151–1312 | `contracts/0008-memory-model.md` |
|
||
| ` ### Advisory diagnostics` | 1313–1351 | `contracts/0008-memory-model.md` |
|
||
| ` ### Why advisory + suppress instead of inference` | 1352–1377 | D |
|
||
| ` ### Inference algorithm` | 1378–1393 | `models/0004-rc-uniqueness.md` |
|
||
| ` ### Codegen contract` | 1394–1412 | `contracts/0008-memory-model.md` |
|
||
| ` ### Mode metadata is load-bearing for codegen` | 1413–1509 | `contracts/0008-memory-model.md` |
|
||
| ` ### Adjacent extensions for mutability (out of scope)` | 1510–1519 | D |
|
||
| ` ### What this Decision deliberately does not do` | 1520–1535 | D |
|
||
| `## Decision 11` intro | 1536–1577 | `models/0005-typeclasses.md` |
|
||
| ` ### Form-A schema (JSON authoring surface)` | 1578–1639 | `contracts/0013-typeclasses.md` |
|
||
| ` ### Resolution and monomorphisation` | 1640–1752 | `models/0005-typeclasses.md` |
|
||
| ` ### Cross-module references in synthesised bodies` | 1753–1823 | `contracts/0013-typeclasses.md` (pins `codegen_import_map_fallback_pin.rs:2`, `polyfn_dot_qualified_branch_pin.rs:2`) |
|
||
| ` ### Defaults and superclasses` | 1824–1855 | `contracts/0013-typeclasses.md` |
|
||
| ` ### Diagnostic categories` | 1856–1917 | `contracts/0013-typeclasses.md` |
|
||
| ` ### Method dispatch` | 1918–1964 | `contracts/0013-typeclasses.md` |
|
||
| ` ### What the typeclass design explicitly does NOT support` | 1965–2000 | D |
|
||
| ` ### Prelude (built-in) classes` | 2001–2042 | `contracts/0013-typeclasses.md` (pins `show_no_instance_e2e.rs:47`; Show diagnostic target) |
|
||
| ` ### Heap-Str primitives` | 2043–2088 | `contracts/0011-str-abi.md` (ledger addition — see below) |
|
||
| ` ### What this decision does NOT commit to` | 2089–2112 | D |
|
||
| `## Roundtrip Invariant` (+ 3 `###`s 2152–2208) | 2113–2208 | `contracts/0009-roundtrip-invariant.md` (whole block kept together — pins `round_trip.rs:10,72`) |
|
||
| `## Mangling scheme` | 2209–2218 | **source-link only** (no prose file): behaviour → dropped (code is SoT); any "why" sentence → D |
|
||
| `## Convention: qualified cross-module references` | 2219–2236 | **source-link only** `qualified-xref` (ledger addition): behaviour → dropped; rationale → D |
|
||
| `## Env construction` | 2237–2265 | **source-link only** (no prose file): behaviour → dropped (code is SoT); any "why" sentence → D |
|
||
| `## Embedding ABI` intro | 2266–2333 | `contracts/0003-embedding-abi.md` (pins `docs_honesty_pin.rs:135`) |
|
||
| ` ### Frozen value layout (M3 — one-way commitment)` | 2334–2376 | `contracts/0006-frozen-value-layout.md` + source-link `runtime/rc.c §layout` (dual; pins `embed_record_layout_pin.rs:1`) |
|
||
| `## Data model` (+ 4 `###`s) | 2377–2615 | `contracts/0002-data-model.md` (whole; `design_schema_drift.rs` `include_str!`s it) |
|
||
| `## Pipeline` | 2616–2662 | `models/0003-pipeline.md` |
|
||
| `## CLI` | 2663–2686 | `models/0003-pipeline.md` |
|
||
| `## Verification and correctness (across cycles)` | 2687–2699 | `contracts/0014-verification.md` |
|
||
| `## Float semantics` | 2700–2838 | `contracts/0005-float-semantics.md` (the inline `**Str ABI.**` para at 2802 is **moved to `contracts/0011-str-abi.md`** — the one sentence-level exception, justified below) |
|
||
| `## What is not (yet) supported` | 2839–3020 | `contracts/0010-scope-boundaries.md` (ledger addition — present-tense, honesty-pinned by `effect_doc_honesty_pin.rs:28`) |
|
||
|
||
### Ledger additions — rationale (the brainstorm's 12-list under-counted)
|
||
|
||
Plan-recon's exhaustive live-xref sweep proved three genuine,
|
||
distinct, currently-referenced contracts the 12-row first pass
|
||
missed. Forcing them into ill-fitting existing files would
|
||
re-create the conflation this milestone exists to end; the
|
||
ledger's purpose is per-contract addressability, so a genuine
|
||
distinct contract earns a row.
|
||
|
||
- **`qualified-xref`** (13th, source-link only). `## Convention:
|
||
qualified cross-module references` is code-SoT per §Architecture
|
||
commitment 1 ("qualified-cross-module-ref resolution"). No prose
|
||
file; INDEX row links the resolution `//!`; ratifier
|
||
`codegen_import_map_fallback_pin.rs`. `crates/ail/src/main.rs:1393`
|
||
retargets to this row.
|
||
- **`str-abi`** (14th, prose + source-link). `### Heap-Str
|
||
primitives` (2043–2088) + the inline `**Str ABI.**` para (2802)
|
||
are one runtime-ABI contract, SoT `runtime/str.c`. Three live
|
||
xrefs name `§"Str ABI"`/`§"Heap-Str primitives"`
|
||
(`runtime/str.c:172,198`, `crates/ail/tests/e2e.rs:2843`) — they
|
||
would dangle with no destination. The 2802 para is the **single
|
||
sanctioned sentence-level move** (it is one inline bold-paragraph,
|
||
not a `###`; leaving it in `float-semantics.md` would mis-file a
|
||
Str contract under Float). Recorded as the explicit, bounded
|
||
exception to §Architecture commitment 2.
|
||
- **`scope-boundaries`** (15th, prose). `## What is not (yet)
|
||
supported` is present-tense scope assertion, honesty-pinned by
|
||
`effect_doc_honesty_pin.rs:28` (absent-string `"the built-in IO
|
||
and Diverge ops"`). A present-tense "what the language does not
|
||
do, now" claim is a contract (a checked promise), not a
|
||
decision-record; the pin already reads it, so its ratifier is
|
||
`effect_doc_honesty_pin.rs`.
|
||
|
||
Net ledger: **15 contracts** (12 spec + 3 additions), 5 models,
|
||
one decision-record journal. The `design_index_pin.rs` clause-2
|
||
resolution set is widened to accept `crates/**/src/*.rs` so the
|
||
in-source `memory-model` (`uniqueness.rs`) and `tail-calls`
|
||
(`lib.rs tail_call_in_non_tail_position_is_rejected`) ratifiers
|
||
resolve honestly rather than being mapped to a wrong tests/-level
|
||
file.
|
||
|
||
### OQ7 — the dangling "Iter 13b" cite
|
||
|
||
`crates/ailang-codegen/src/lib.rs:103` cites "Iter 13b notes in
|
||
`DESIGN.md`" — that prose was relocated out of DESIGN.md long ago;
|
||
no forward target exists in the tree. Per the honesty rule a
|
||
reference to non-existent content is itself a violation. The
|
||
comment is rewritten to drop the cite (state the behaviour
|
||
directly; no `design/` or journal pointer, because the referenced
|
||
notes no longer exist anywhere — inventing a pointer would be
|
||
fiction). This is the one reference in bucket (e) that is *deleted,
|
||
not retargeted*.
|