Files
AILang/docs/plans/0093-design-md-rolesplit.1.md
Brummel 832375f2ac convention: counter-prefix file naming across docs/specs/, docs/plans/, design/contracts/, design/models/
All 176 files in the four accumulating directories now use a
zero-padded 4-digit counter prefix that reflects creation order
(`NNNN-slug.md`). The counter is assigned per directory in strict
git-log creation order; ties broken alphabetically by original name.
The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is
dropped — the date is recoverable from git log and the counter
carries the ordering.

A file's counter is stable for the life of the file: never reassigned,
never reused, never compacted. Deleted files retire their counter;
subsequent files do not fill the gap. This is the property that lets
cross-references stay literal — refs use the full filename including
the counter (`design/contracts/0007-honesty-rule.md`) so they grep
cleanly and resolve directly without a glob step.

313 cross-references updated across .md/.rs/.toml/.c/.json files
(test pins, include_str! paths, design-INDEX entries, baseline notes,
runtime C comments, inter-contract markdown links incl. bare basename
and `../models/foo.md` forms).

CLAUDE.md gets a new "File-naming convention" section spelling out
the rule and rationale. skills/brainstorm/SKILL.md and
skills/planner/SKILL.md updated so new spec/plan creation produces
counter-prefixed names from the start.

The full test suite (cargo test --workspace) passes.
2026-05-28 13:31:31 +02:00

796 lines
34 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DESIGN.md → `design/` role-split — Implementation Plan (iter 1, the whole milestone)
> **Parent spec:** `docs/specs/0045-design-md-rolesplit.md`
> (incl. the authoritative **Appendix — Boss-adjudicated relocation
> map**; grounding-check PASS ×2).
>
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking.
**Goal:** Replace the 3020-line `docs/DESIGN.md` with the `design/`
ledger (`INDEX.md` + 15 `contracts/` + 5 `models/`), move
decision-records to a journal, retarget every live reference, and
ship the RED-first `design_index_pin.rs` anti-regrowth guard — in a
build-atomic shape.
**Architecture:** The spec Appendix table is the per-`##`/`###`
relocation map (line ranges → destination); this plan executes it.
Build-atomicity is achieved *by task ordering*: `design/contracts/0002-data-model.md`
is created (Task 2) and `design_schema_drift.rs`'s `include_str!`
retargeted to it (Task 5) **before** `docs/DESIGN.md` is deleted
(Task 9), so the workspace compiles at every task boundary. The
single milestone commit is the Boss's; tasks are review units, not
commits.
**Tech Stack:** Markdown (`design/`), Rust tests
(`crates/ailang-core/tests/`, `crates/ail/tests/`), `crates/ailang-check/src/lib.rs`
(2 diagnostic strings — the only logic edit), `bench/architect_sweeps.sh`,
skill/agent Markdown.
**Authoritative map:** every "move DESIGN.md:AB" below is the spec
Appendix row for that range. The Appendix is placeholder-free; this
plan does not restate the 70-row table — it cites it. Re-levelling
rule (all moved prose): the source `##`/`###` heading becomes the
file's `#` H1 (or `##` for a subsection under a file's single H1);
no content edits except (a) heading level, (b) `honesty-rule.md` is
*rewritten* per spec §Architecture-4, (c) the OQ7 cite deletion.
---
## Task 1: RED-first `design_index_pin.rs` (the anti-regrowth spine)
**Files:**
- Create: `crates/ailang-core/tests/design_index_pin.rs`
- [ ] **Step 1: Write the 4-clause guard test**
```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. Spec: docs/specs/0045-design-md-rolesplit.md.
use std::fs;
use std::path::{Path, PathBuf};
fn root() -> PathBuf {
PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/../../"))
}
fn read(rel: &str) -> String {
fs::read_to_string(root().join(rel))
.unwrap_or_else(|e| panic!("read {rel}: {e}"))
}
fn norm(s: &str) -> String {
s.split_whitespace().collect::<Vec<_>>().join(" ")
}
/// Parse the two pipe-tables out of design/INDEX.md.
/// Returns (contracts, models) as rows of trimmed cells.
fn index_tables() -> (Vec<Vec<String>>, Vec<Vec<String>>) {
let idx = read("design/INDEX.md");
let mut contracts = Vec::new();
let mut models = Vec::new();
let mut section = "";
for line in idx.lines() {
let t = line.trim();
if t.starts_with("## Contracts") {
section = "c";
continue;
}
if t.starts_with("## Models") {
section = "m";
continue;
}
if !t.starts_with('|') {
continue;
}
let cells: Vec<String> = t
.trim_matches('|')
.split('|')
.map(|c| c.trim().to_string())
.collect();
// skip header + separator rows
if cells.iter().any(|c| c.starts_with("---")) {
continue;
}
if cells.first().map(|c| c.as_str()) == Some("id") {
continue;
}
match section {
"c" => contracts.push(cells),
"m" => models.push(cells),
_ => {}
}
}
(contracts, models)
}
/// A link cell may be a design/ path, a source path, a dual-link
/// "A + B", or carry a trailing "(in-source ...)" / "§..." note.
/// Resolve to the first concrete path token and check it exists.
fn link_target_exists(cell: &str) -> bool {
let first = cell.split(" + ").next().unwrap_or(cell).trim();
// strip a trailing parenthetical or §-note
let path = first
.split(" (")
.next()
.unwrap_or(first)
.split(" §")
.next()
.unwrap_or(first)
.trim()
.trim_end_matches("//!")
.trim();
!path.is_empty() && root().join(path).exists()
}
#[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
let (contracts, models) = index_tables();
assert!(contracts.len() >= 15, "expected >=15 contract rows, got {}", contracts.len());
assert!(models.len() >= 5, "expected >=5 model rows, got {}", models.len());
for row in contracts.iter().chain(models.iter()) {
let link = row.last().expect("row has a link cell");
assert!(
link_target_exists(link),
"INDEX link does not resolve: {:?} (row {:?})",
link,
row
);
}
}
#[test]
fn every_contract_names_a_resolvable_ratifying_test() {
// clause 2 — ratifying-test token resolves to a real file under
// crates/**/tests, crates/**/src (in-source #[cfg(test)] mod
// tests are first-class ratifiers — spec OQ1/OQ2), bench/, or
// skills/**/SKILL.md.
let (contracts, _) = index_tables();
for row in &contracts {
// columns: id | consumer/lifetime | ratifying-test | link
let rt = &row[2];
// take the path token (before any " (" note)
let path = rt.split(" (").next().unwrap_or(rt).trim();
assert!(
root().join(path).exists(),
"ratifying-test does not resolve to a real file: {:?} (contract {:?})",
path,
row[0]
);
}
}
#[test]
fn contracts_carry_no_decision_record_prose() {
// clause 3 — the conflation tripwire.
let dir = root().join("design/contracts");
let markers = [
"we rejected",
"an earlier draft",
"Why not other",
"was retired in iter",
"rollback plan",
"previously all",
];
for entry in fs::read_dir(&dir).expect("design/contracts/ exists") {
let p = entry.unwrap().path();
if p.extension().and_then(|e| e.to_str()) != Some("md") {
continue;
}
let body = norm(&fs::read_to_string(&p).unwrap());
for m in &markers {
assert!(
!body.contains(m),
"decision-record marker {:?} found in contract {:?} — re-conflation",
m,
p.file_name().unwrap()
);
}
}
}
```
- [ ] **Step 2: Run to verify it is RED**
Run: `cargo test -p ailang-core --test design_index_pin 2>&1 | tail -20`
Expected: FAIL — `design_md_is_gone` fails ("was resurrected"; DESIGN.md
still present) and `every_index_link_resolves` / the others panic on
`read design/INDEX.md: ... No such file`. The test **file compiles**
(build stays green); only the assertions are RED. This is the
required RED-first state.
---
## Task 2: `design/INDEX.md` + the 15 `design/contracts/*.md`
**Files:**
- Create: `design/INDEX.md`
- Create: `design/contracts/{feature-acceptance,authoring-surface,roundtrip-invariant,memory-model,data-model,float-semantics,typeclasses,tail-calls,frozen-value-layout,honesty-rule,embedding-abi,str-abi,scope-boundaries,verification}.md`
(14 prose files; `mangling`, `env-construction`, `qualified-xref`
are source-link-only — **no file**, INDEX rows only)
- [ ] **Step 1: Write `design/INDEX.md`**
Use the spec §"Concrete code shapes" item 1 INDEX block **verbatim**
(it already carries the corrected 15-row Contracts table incl.
`qualified-xref`, `str-abi`, `scope-boundaries`, and the 5-row
Models table). Header preamble = the spec's INDEX preamble text
PLUS, per spec Appendix OQ6, a short "## Project framing"
sub-section absorbing DESIGN.md:618 (`## Goal`), :1955
(`## Project ecosystem` intro), :8392 (`## Project language:
English`) — moved whole, re-levelled to `###` under the preamble.
- [ ] **Step 2: Run the INDEX-shape assertion**
Run: `cargo test -p ailang-core --test design_index_pin every_index_link_resolves 2>&1 | tail -5`
Expected: still FAIL, but now past the parse (panics on a contract
file not yet existing, not on "read design/INDEX.md"). Confirms
INDEX.md parses and has ≥15 contract / ≥5 model rows.
- [ ] **Step 3: Create the 14 prose contract files (one per Appendix contract row)**
For each file below, concatenate the cited DESIGN.md line ranges
**from the spec Appendix table**, re-level the top heading to `#`,
and route every `### …` the Appendix tags `D` to Task 4 (NOT into
this file). Files and their Appendix-sourced ranges:
- `feature-acceptance.md` ← DESIGN.md:93164
- `authoring-surface.md` ← :230240 + :268297 + :298331 (the three
contract `###`s of Decision 6 per Appendix; :241243 and all
`### Why…`/`### …does not do`/`### Implementation outline`/`###
Form refinements`/`### Empirical addendum` go to Task 4)
- `roundtrip-invariant.md` ← :21132208 (whole block, 3 `###`s kept)
- `memory-model.md` ← :11231150 + :11511312 + :13131351 + :13941412
+ :14131509 (the five binding `###`s per Appendix)
- `data-model.md` ← :23772615 (whole `## Data model` + 4 `###`s)
- `float-semantics.md` ← :27002838 **except** the inline
`**Str ABI.**` paragraph at :2802 (that one para → `str-abi.md`,
the single sanctioned sentence-level move per Appendix OQ4)
- `typeclasses.md` ← :15781639 + :17531823 + :18241855 + :18561917
+ :19181964 + :20012042 (the six contract `###`s of Decision 11
per Appendix)
- `tail-calls.md` ← :731787 (whole `## Decision 8`)
- `frozen-value-layout.md` ← :23342376
- `honesty-rule.md`**rewritten** (next step — do NOT raw-move :5682)
- `embedding-abi.md` ← :22662333
- `str-abi.md` ← :20432088 (`### Heap-Str primitives`) + the
`**Str ABI.**` paragraph lifted from :2802
- `scope-boundaries.md` ← :28393020 (`## What is not (yet) supported`)
- `verification.md` ← :26872699
Each file starts `# <Title>` and ends with a line
`Ratified by: <the INDEX ratifying-test path for this contract>.`
- [ ] **Step 4: Write the rewritten `design/contracts/0007-honesty-rule.md`**
Do NOT raw-move DESIGN.md:5682. Rewrite so the rule names the new
home. The two `docs_honesty_pin.rs:70,72` anchors MUST appear as
**contiguous substrings** (planner item-6 contiguity — no soft-wrap
splitting them):
```markdown
# The honesty rule this ledger holds itself to
`design/` describes what AILang **is now**: schema, semantics,
invariants, runtime contracts. It is present-tense by construction.
Two things never belong in a contract or model file:
- **Forward intent** ("planned / will back / on the path to") — that
lives in `docs/roadmap.md`.
- **History and rationale** ("an earlier draft said / previously /
why X was chosen / why Y was rejected / retired in iter Z") — that
lives in `docs/journals/`. Decision-records are journal content,
not ledger content; this is the honesty rule it holds itself to.
The single legitimate exception is a present-tense reserved or
deliberately-excluded claim that is explicitly and correctly
labelled. The discriminator is not whether a sentence mentions past
or future, but whether the document asserts something exists, works, or changed that does not.
Ratified by: `crates/ailang-core/tests/docs_honesty_pin.rs`.
```
(The two pinned phrases — `the honesty rule it holds itself to` and
`whether the document asserts something exists, works, or changed
that does not` — each sit on a single physical line above; `norm()`
in `docs_honesty_pin.rs` is whitespace-tolerant but contiguity is
kept anyway to satisfy the raw-`grep` advisory sweep.)
- [ ] **Step 5: Verify clause-3 (no decision-record prose leaked into contracts)**
Run: `cargo test -p ailang-core --test design_index_pin contracts_carry_no_decision_record_prose 2>&1 | tail -5`
Expected: PASS (every `###` the Appendix tags `D` was routed to
Task 4, not into these files). If a marker fires, a `### Why…`
subsection was wrongly included — move it to the Task 4 journal.
---
## Task 3: the 5 `design/models/*.md` whitepapers
**Files:**
- Create: `design/models/{rc-uniqueness,typeclasses,effects,authoring-surface,pipeline}.md`
- [ ] **Step 1: Create the 5 model files (Appendix model-tagged ranges)**
- `rc-uniqueness.md` ← :788852 + :853913 + :914977 + :10151122
+ :13781393 (Decision 9/10 narrative `###`s per Appendix)
- `typeclasses.md` ← :15361577 + :16401752 (Decision 11 narrative)
- `effects.md` ← :190204 (Decision 3 — the
`effect_doc_honesty_pin.rs` present-anchors live here; that pin's
read retargets to this file in Task 5)
- `authoring-surface.md` ← :332471 + :590674 (`### Candidate
notations` + `### Form (B)` — the `docs_honesty_pin.rs` Form-B
placeholder present-anchor retargets here in Task 5)
- `pipeline.md` ← :26162662 (`## Pipeline`) + :26632686 (`## CLI`)
Each starts `# <Title>`. Models carry no `Ratified by:` line (no
test pins a model — clause 2 is contracts-only).
- [ ] **Step 2: Verify models resolve in INDEX**
Run: `cargo test -p ailang-core --test design_index_pin every_index_link_resolves 2>&1 | tail -5`
Expected: closer to PASS — model links now resolve; remaining
failures are only source-link contract rows whose targets already
exist (`runtime/str.c`, `crates/ailang-codegen/src/lib.rs`, …) so
this should now PASS for all 20 link rows. If it still fails, the
failing row's link path is mistyped in INDEX.md — fix the INDEX
cell.
---
## Task 4: decision-record journal + journals INDEX pointer
**Files:**
- Create: `docs/journals/2026-05-19-design-decision-records.md`
- Modify: `docs/journals/INDEX.md` (append one pointer line)
- [ ] **Step 1: Create the relitigation-guard archive**
Concatenate, in DESIGN.md order, every range the spec Appendix tags
`D`: :165176, :177189, :205213, :214229, :241243, :245267,
:472486, :487519, :520536, :537589, :675730, :9781014,
:13521377, :15101519, :15201535, :19652000, :20892112, plus
any genuine "why" sentence extracted from the source-link `##`s
(`## Mangling scheme` :22092218, `## Convention: qualified
cross-module references` :22192236, `## Env construction`
:22372265 — per Appendix, behaviour sentences are *dropped* as
code-is-SoT; only rationale sentences move here).
Header:
```markdown
# Design decision-records — relitigation guard (migrated 2026-05-19)
Why-X-chosen / why-Y-rejected / deliberately-does-not-do / rollback
/ empirical-addendum prose, migrated out of the former
`docs/DESIGN.md` by the design-md-rolesplit milestone. A future
brainstorm reads this so it does not re-propose a settled-and-
rejected idea. Order preserved from the source. This file is
append-only history; it is NOT a contract surface.
```
- [ ] **Step 2: Append the journals INDEX pointer**
Append to `docs/journals/INDEX.md` (newest-last, one line):
```
- 2026-05-19 — design-decision-records (migration): relitigation-guard archive — every why/rejected/does-not-do/rollback/empirical ### moved out of the former docs/DESIGN.md by the design-md-rolesplit milestone. Companion to spec 2026-05-19-design-md-rolesplit.
```
- [ ] **Step 3: Verify acceptance criterion 2 (nothing dropped)**
Run: `python3 - <<'EOF'
import re
src=open("docs/DESIGN.md").read().splitlines()
heads=[(i+1,l) for i,l in enumerate(src) if re.match(r'^#{2,3} ',l)]
print(len(heads),"headings in DESIGN.md;",
"expect every line range covered by spec Appendix")
EOF`
Expected: prints the heading count; cross-check by eye that every
`##`/`###` appears in exactly one of Task 2/3/4 (the Appendix is the
checklist). This is a human-verifiable completeness gate, not an
automated assertion (the automated guarantee is clause-3 +
acceptance grep in Task 9).
---
## Task 5: retarget the three doc-reading tests (GREEN against `design/`)
**Files:**
- Modify: `crates/ailang-core/tests/design_schema_drift.rs:22` (+ remove `data_model_section` 2837 and `data_model_section_is_bounded` 411430; repoint 7 anchor tests)
- Modify: `crates/ailang-core/tests/docs_honesty_pin.rs` (the `read("docs/DESIGN.md")` calls + the :70/:72 anchors)
- Modify: `crates/ailang-core/tests/effect_doc_honesty_pin.rs:21`
- [ ] **Step 1: Retarget `design_schema_drift.rs`**
Line 22, exact before → after:
```rust
- const DESIGN_MD: &str = include_str!("../../../docs/DESIGN.md");
+ const DATA_MODEL: &str = include_str!("../../../design/contracts/0002-data-model.md");
```
Delete `fn data_model_section()` (lines 2837) and
`fn data_model_section_is_bounded()` (lines 411430). In the 7
anchor tests (`design_md_anchors_every_term_variant` :43,
`…pattern…` :185, `…type…` :214, `…literal…` :248, `…def_kind`
:277, `…parammode…` :348, `…nested_struct_keys` :373) replace every
`data_model_section()` call with the const `DATA_MODEL`. Update the
module rustdoc (:1,3,11) "DESIGN.md §Data model" → "design/contracts/0002-data-model.md".
- [ ] **Step 2: Retarget `docs_honesty_pin.rs` per-sentence home**
The `read()` helper (1519) and `norm()` (2426) are unchanged.
Replace each `read("docs/DESIGN.md")` with a read of the design/
file where that test's pinned strings now live (per spec Appendix):
- `design_md_has_no_wunschdenken` (:30) and
`design_md_has_no_doc_archaeology` (:51): absent-pins span
Boehm/float/typeclasses/effects/Form-B — read the concatenation
of `design/models/0004-rc-uniqueness.md`, `design/contracts/0005-float-semantics.md`,
`design/contracts/0013-typeclasses.md`, `design/models/0002-effects.md`,
`design/models/0001-authoring-surface.md` (absent-pins must be absent
from all → join the reads).
- `design_md_present_tense_anchors_present` (:68): split per anchor
to its home file; **:70** `"the honesty rule it holds itself to"`
and **:72** `"whether the document asserts something exists,
works, or changed that does not"` → read `design/contracts/0007-honesty-rule.md`;
the Form-B placeholder anchor (:90 area) → `design/models/0001-authoring-surface.md`;
the remaining present-anchors → their Appendix home file.
- `form_a_scalar_param_carveout_present_and_old_rule_absent`
(:104137): the `FORM_A_SPEC` read is unchanged; the
`read("docs/DESIGN.md")` at :112 → `design/contracts/0003-embedding-abi.md`
(the `:135` pin `Export parameters are written **bare**` lives
in `## Embedding ABI`, Appendix → embedding-abi.md).
- `prose_roundtrip_md_has_no_wunschdenken` (:94101): reads
`docs/PROSE_ROUNDTRIP.md` — **unchanged**.
- [ ] **Step 3: Retarget `effect_doc_honesty_pin.rs:21`**
`design_md_effect_prose_is_true` (:1934), line 21:
```rust
- let d = read("docs/DESIGN.md");
+ let d = norm(&[read("design/models/0002-effects.md"),
+ read("design/contracts/0010-scope-boundaries.md")].join("\n"));
```
(Decision 3 effect prose → `models/0002-effects.md`; the
`"the built-in IO and Diverge ops"` absent-pin's home
`## What is not (yet) supported` → `contracts/0010-scope-boundaries.md`.
Adjust the existing `norm()` usage in the test so the join is
normalised once; keep every pinned string assertion unchanged.)
- [ ] **Step 4: Verify the three tests GREEN (DESIGN.md still present)**
Run: `cargo test -p ailang-core --test design_schema_drift --test docs_honesty_pin --test effect_doc_honesty_pin 2>&1 | tail -15`
Expected: PASS for all three (they now read `design/` files which
exist from Tasks 23; `docs/DESIGN.md` still on disk but no longer
read by these tests). `cargo build --workspace` still green
(`include_str!` now points at the existing `design/contracts/0002-data-model.md`).
---
## Task 6: retarget the 2 diagnostics + 2 E2Es (lockstep)
**Files:**
- Modify: `crates/ailang-check/src/lib.rs` (Float branch ~872876, Show branch ~885893)
- Modify: `crates/ail/tests/eq_float_noinstance.rs:41-42`
- Modify: `crates/ail/tests/show_no_instance_e2e.rs:47-48`
- [ ] **Step 1: Retarget the Float-branch diagnostic**
`crates/ailang-check/src/lib.rs` Float branch, exact:
```rust
- orderability per IEEE-754); see DESIGN.md §\"Float semantics\".",
+ orderability per IEEE-754); see design/contracts/0005-float-semantics.md.",
```
- [ ] **Step 2: Retarget the Show-branch diagnostic (contiguity-safe)**
`crates/ailang-check/src/lib.rs` Show branch. The path
`design/contracts/0013-typeclasses.md` MUST contain no interior literal
whitespace and must not be split by a `\`-continuation in a way
that injects a space (Rust `\`-continuation strips the newline +
leading indent, so keep the full path token on one physical source
line). Exact:
```rust
- 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 \
```
(Runtime string becomes `…the prelude; see design/contracts/0013-typeclasses.md. User types declare their own …` — the path is one contiguous run; the E2E `contains("design/contracts/0013-typeclasses.md")` holds.)
- [ ] **Step 3: Retarget the two E2E assertions (lockstep)**
`crates/ail/tests/eq_float_noinstance.rs` lines 4142:
```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` lines 4748:
```rust
- no_inst.message.contains("Prelude (built-in) classes"),
- "expected DESIGN.md §Prelude (built-in) classes cross-reference, got message: {:?}",
+ no_inst.message.contains("design/contracts/0013-typeclasses.md"),
+ "expected design/contracts/0013-typeclasses.md cross-reference, got message: {:?}",
```
Also update the module-rustdoc / comment lines in both E2E files
(`eq_float_noinstance.rs:5,38`, `show_no_instance_e2e.rs:5,43-45`)
that name "DESIGN.md §…" → the new contract path.
- [ ] **Step 4: Verify the lockstep E2Es GREEN**
Run: `cargo test -p ail --test eq_float_noinstance --test show_no_instance_e2e 2>&1 | tail -10`
Expected: PASS — each asserts the new contiguous pointer substring.
(Both filters resolve: `eq_float_noinstance` has
`eq_at_float_fires_float_aware_noinstance`; `show_no_instance_e2e`
has its Show-noinstance test — verified present in the tree.)
---
## Task 7: retarget `bench/architect_sweeps.sh`
**Files:**
- Modify: `bench/architect_sweeps.sh:22,25-28,34` (+ the 5 `run_sweep` scan target)
- [ ] **Step 1: Repoint the spine + guard**
```sh
- DESIGN="docs/DESIGN.md"
+ INDEX="design/INDEX.md"
+ DESIGN_GLOB="design/contracts design/models"
```
Guard (2528):
```sh
- if [[ ! -f "$DESIGN" ]]; then
- echo "architect_sweeps: $DESIGN not found (run from repo root)" >&2
+ if [[ ! -f "$INDEX" ]]; then
+ echo "architect_sweeps: $INDEX not found (run from repo root)" >&2
exit 2
fi
```
- [ ] **Step 2: Repoint the grep target (multi-file scan)**
Line 34, before → after (recursive over the design/ prose set;
sweep regexes themselves **unchanged** per spec §3):
```sh
- matches=$(grep -nE "$pattern" "$DESIGN" || true)
+ matches=$(grep -rnE "$pattern" $DESIGN_GLOB || true)
```
Exit-code contract preserved: 0 = all sweeps clean, 1 = an anchor
matched, 2 = `design/INDEX.md` not found.
- [ ] **Step 3: Verify exit-0 clean and exit-2 on missing spine**
Run: `bash bench/architect_sweeps.sh; echo "exit=$?"`
Expected: prints the per-sweep lines and `exit=0` (the migrated
`design/` prose is honest — no wunschdenken/post-mortem; if Sweep 5
fires, a moved file kept a stripped-prose marker → fix the file,
not the sweep).
Run: `mv design/INDEX.md /tmp/IX.bak; bash bench/architect_sweeps.sh; echo "exit=$?"; mv /tmp/IX.bak design/INDEX.md`
Expected: `architect_sweeps: design/INDEX.md not found` and `exit=2`.
---
## Task 8: retarget buckets (b)(c)(d)(e) — agent lists, SKILL bodies, CLAUDE.md, README, comment xrefs
**Files (from plan-recon's exhaustive 5-bucket set):**
- Modify (b) ~12 agent files: `skills/audit/agents/ailang-architect.md`, `skills/audit/agents/ailang-bencher.md`, `skills/brainstorm/agents/ailang-grounding-check.md`, `skills/debug/agents/ailang-debugger.md`, `skills/docwriter/agents/ailang-docwriter.md`, `skills/fieldtest/agents/ailang-fieldtester.md`, `skills/implement/agents/ailang-implementer.md`, `skills/implement/agents/ailang-implement-orchestrator.md`, `skills/implement/agents/ailang-quality-reviewer.md`, `skills/implement/agents/ailang-spec-reviewer.md`, `skills/implement/agents/ailang-tester.md`, `skills/planner/agents/ailang-plan-recon.md`
- Modify (c) 5 SKILL bodies: `skills/audit/SKILL.md`, `skills/brainstorm/SKILL.md`, `skills/docwriter/SKILL.md`, `skills/fieldtest/SKILL.md`, `skills/boss/SKILL.md`
- Modify (d) `CLAUDE.md`, `skills/README.md`
- Modify (e) code/C/.ail comment xrefs (full list below)
- [ ] **Step 1: Rewrite the architect reading-list bullet (the representative)**
`skills/audit/agents/ailang-architect.md:30`, exact:
```
- 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.
```
Also `ailang-architect.md:73,81,83,118,123` (the `architect_sweeps.sh`
exit-2 / Sweep-5 references): replace "DESIGN.md" with
"design/INDEX.md" and keep the exit-2 / sweep semantics text
(Task 7 preserved them).
- [ ] **Step 2: Rewrite the remaining (b) agent reading lists to role**
Per spec §4: `grounding-check` (`:34`) and architect read
`design/contracts/`; `fieldtester` (`:41`, no-edit limit `:255`
preserved) reads `design/INDEX.md` + `design/models/`; `bencher`
(`:38`) reads `design/models/0004-rc-uniqueness.md` (Decision-9/Boehm
narrative); `debugger` (`:29`), `tester` (`:26`), `implementer`
(`:30`), `implement-orchestrator` (`:35`), `spec-reviewer` (`:34`),
`quality-reviewer` (`:32`), `plan-recon` (`:34,72,147`),
`docwriter` (`:35` + the 8 other refs) → name `design/INDEX.md` as
the spine. Replace every literal `docs/DESIGN.md` token in these
files; preserve each bullet's role descriptor.
- [ ] **Step 3: Rewrite (c) SKILL bodies + (d) CLAUDE.md / README**
Replace every live `docs/DESIGN.md` reference in
`skills/{audit,brainstorm,docwriter,fieldtest,boss}/SKILL.md` and
`skills/README.md` with `design/INDEX.md` (or the specific
`design/contracts/<x>.md` where the prose names a section, e.g.
`boss/SKILL.md:284` "Canonical feature-acceptance criterion" →
`design/contracts/0004-feature-acceptance.md`). `CLAUDE.md`: `:45`
code-layout table row, the `## Roles of docs/DESIGN.md …` heading
and its paragraph (:199212) → rewrite to describe the `design/`
ledger (DESIGN = current-state mirror discipline preserved, just
re-homed); `:78,178` inline refs → `design/INDEX.md`.
- [ ] **Step 4: Retarget (e) code/C/.ail comment xrefs + OQ7 deletion**
Replace `DESIGN.md §"X"` → the Appendix destination
(`design/contracts/<x>.md` or `design/models/<x>.md`) in: `ail-embed/src/lib.rs:4,35,91`
(drop the DESIGN.md line-number cites — `→ design/contracts/0006-frozen-value-layout.md`);
`crates/ailang-check/src/lib.rs:449,861,882,2647,6336`;
`crates/ailang-check/tests/duplicate_ctor_pin.rs:4` (→ env-construction
source-link note); `crates/ailang-codegen/src/drop.rs:88,114`,
`lib.rs:178,685`, `match_lower.rs:107`;
`crates/ailang-codegen/tests/embed_record_layout_pin.rs:1`,
`embed_staticlib_lowering.rs:47`; `crates/ailang-core/src/ast.rs:3`
(→ `design/contracts/0002-data-model.md`), `:211`;
`crates/ailang-surface/src/lib.rs:7`, `parse.rs:78,81`,
`print.rs:128`; `crates/ailang-surface/tests/round_trip.rs:10,72`
(→ `design/contracts/0009-roundtrip-invariant.md`);
`crates/ail/src/main.rs:1393` (→ qualified-xref source-link),
`:1572`; `crates/ail/tests/codegen_import_map_fallback_pin.rs:2`,
`polyfn_dot_qualified_branch_pin.rs:2` (→
`design/contracts/0013-typeclasses.md`), `e2e.rs:2843` (→
`design/contracts/0011-str-abi.md`), `eq_ord_e2e.rs:89,110` (→ mangling
source-link), `embed/record_roundtrip.c:2`, `embed/tick_roundtrip.c:6`
(→ `design/contracts/0006-frozen-value-layout.md`);
`examples/fieldtest/floats_3_safe_division.ail:19`,
`floats_4_float_to_str_reach.ail:6` (→
`design/contracts/0005-float-semantics.md`); `runtime/rc.c:41` (→
`design/contracts/0006-frozen-value-layout.md`), `runtime/str.c:172,198`
(→ `design/contracts/0011-str-abi.md`);
`crates/ailang-core/specs/form_a.md:89`.
**OQ7 — delete, not retarget:** `crates/ailang-codegen/src/lib.rs:103`
"Iter 13b notes in `DESIGN.md`" — rewrite the comment to state the
behaviour directly and **drop the cite entirely** (no `design/` or
journal pointer; the referenced notes exist nowhere — a pointer
would be fiction, itself an honesty-rule violation).
- [ ] **Step 5: Verify build still green (doc/comment-only task)**
Run: `cargo build --workspace 2>&1 | tail -3`
Expected: `Finished` (this task edits only Markdown + comments +
docstrings; no logic). `docs/DESIGN.md` still present here.
---
## Task 9: the clean cut — delete `docs/DESIGN.md` + whole-tree gate
**Files:**
- Delete: `docs/DESIGN.md`
- [ ] **Step 1: Delete the file**
Run: `git rm -q docs/DESIGN.md && echo deleted`
Expected: `deleted`. (`git rm` stages the deletion; the Boss owns
the final commit shape — this only removes it from the working
tree + index, no commit.)
- [ ] **Step 2: Workspace build gate (build-atomicity proof)**
Run: `cargo build --workspace 2>&1 | tail -3`
Expected: `Finished …` with **0 errors**. This proves
build-atomicity: the only compile-time consumer
(`design_schema_drift.rs` `include_str!`) was retargeted in Task 5
to the now-existing `design/contracts/0002-data-model.md`, so deleting
`docs/DESIGN.md` does not break the build.
- [ ] **Step 3: Whole-suite GREEN incl. the design_index_pin spine**
Run: `cargo test --workspace 2>&1 | tail -25`
Expected: all green. Specifically `design_index_pin`'s four tests
now ALL pass: `design_md_is_gone` (DESIGN.md deleted),
`every_index_link_resolves`, `every_contract_names_a_resolvable_ratifying_test`,
`contracts_carry_no_decision_record_prose`. `design_schema_drift`,
`docs_honesty_pin`, `effect_doc_honesty_pin`, `eq_float_noinstance`,
`show_no_instance_e2e` green (Tasks 56).
- [ ] **Step 4: Acceptance-gate grep (recon-undercount countermeasure)**
Run: `grep -rIn 'DESIGN\.md' . --exclude-dir=.git --exclude-dir=target | grep -vE '^\./docs/(journals/|specs/|plans/|roadmap\.md|WhatsNew\.md|journal-archive\.md)|^\./bench/orchestrator-stats/' | grep -v 'design-md-rolesplit' || echo "CLEAN: zero live DESIGN.md references"`
Expected: `CLEAN: zero live DESIGN.md references`. Any line printed
is a missed live reference (code/script/agent/comment) — retarget
it (Task 8 bucket) before the milestone is done. The exclude list
is exactly the spec acceptance-criterion-8 append-only history set;
the `design-md-rolesplit` filter drops this milestone's own
spec/plan/journal self-references.
- [ ] **Step 5: architect_sweeps clean on the final tree**
Run: `bash bench/architect_sweeps.sh; echo "exit=$?"`
Expected: `exit=0` (all five sweeps clean against the migrated
`design/` prose — the honesty discipline survived the move).
---
## Self-review (planner Step 5)
1. **Spec coverage:** Task 1 = §"Concrete code shapes" pin; Tasks
24 = the Appendix relocation map (every `##`/`###`); Task 5 =
§3 test retargets; Task 6 = §2 diagnostics; Task 7 = §3
architect_sweeps; Task 8 = §4 agent/contract rewrites + bucket
(e); Task 9 = §"Clean cut" + acceptance criteria 112. Every
spec section has a task. ✓
2. **Placeholder scan:** no TBD/TODO/"similar to"/"add appropriate".
"Concatenate the Appendix-cited ranges" is an exact executable
instruction (the Appendix is the placeholder-free byte map). ✓
3. **Type/path consistency:** `DATA_MODEL` const name consistent
(Task 5 def ↔ Task 5 anchor-test use); `design/contracts/<x>.md`
paths consistent across Tasks 2/5/6/8 and INDEX.md; ratifier
paths match the grounding-PASS'd INDEX. ✓
4. **Step granularity:** each step is one file-group action /
one Run; the largest (Task 2 Step 3 = 14 files) is one mechanical
move-per-file pass, each file 25 min. ✓
5. **No commit steps:** none. Task 9 uses `git rm` (stages a
deletion in the working tree; the Boss commits the iter). ✓
6. **Pin/replacement contiguity:** Task 2 Step 4 keeps the two
`docs_honesty_pin.rs:70,72` phrases each on one physical line;
Task 6 Step 2 keeps `design/contracts/0013-typeclasses.md` a
whitespace-free contiguous token across the `\`-continuation
(the recurring grep/line-wrap family — scrubbed). ✓
7. **Compile-gate vs deferred-caller:** the only compile-time
coupling is `design_schema_drift.rs` `include_str!`
`docs/DESIGN.md` deletion. Task 5 retargets the `include_str!`
to the already-created `design/contracts/0002-data-model.md` (Task 2)
**before** Task 9 deletes the file. No task's build/test gate
depends on a step a later task performs: Tasks 18 keep
`docs/DESIGN.md` on disk, so every intermediate `cargo build` is
green; Task 9's gate is the first (and only) that requires the
deletion, and by then its sole consumer was moved. The plan is
build-atomic by construction, not by a monster task. ✓
8. **Verification filter strings resolve:** Task 1/2/3/5 use
`--test design_index_pin` / `--test design_schema_drift` /
`--test docs_honesty_pin` / `--test effect_doc_honesty_pin`
(files created/existing — resolve). Task 6 `--test
eq_float_noinstance --test show_no_instance_e2e` resolve
(existing). Task 9 Step 3 uses the **unfiltered** `cargo test
--workspace` (no filter to mis-resolve) + a named-test
expectation. Task 9 Step 4 grep is unfiltered (`-rIn`, no
`--include`) per the recon-undercount countermeasure with an
explicit `CLEAN:` sentinel so "nothing matched" cannot
masquerade. ✓
Plan is placeholder-free and build-atomic. Hand off to `implement`.