# 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:A–B" 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::>().join(" ") } /// Parse the two pipe-tables out of design/INDEX.md. /// Returns (contracts, models) as rows of trimmed cells. fn index_tables() -> (Vec>, Vec>) { 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 = 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:6–18 (`## Goal`), :19–55 (`## Project ecosystem` intro), :83–92 (`## 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:93–164 - `authoring-surface.md` ← :230–240 + :268–297 + :298–331 (the three contract `###`s of Decision 6 per Appendix; :241–243 and all `### Why…`/`### …does not do`/`### Implementation outline`/`### Form refinements`/`### Empirical addendum` go to Task 4) - `roundtrip-invariant.md` ← :2113–2208 (whole block, 3 `###`s kept) - `memory-model.md` ← :1123–1150 + :1151–1312 + :1313–1351 + :1394–1412 + :1413–1509 (the five binding `###`s per Appendix) - `data-model.md` ← :2377–2615 (whole `## Data model` + 4 `###`s) - `float-semantics.md` ← :2700–2838 **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` ← :1578–1639 + :1753–1823 + :1824–1855 + :1856–1917 + :1918–1964 + :2001–2042 (the six contract `###`s of Decision 11 per Appendix) - `tail-calls.md` ← :731–787 (whole `## Decision 8`) - `frozen-value-layout.md` ← :2334–2376 - `honesty-rule.md` ← **rewritten** (next step — do NOT raw-move :56–82) - `embedding-abi.md` ← :2266–2333 - `str-abi.md` ← :2043–2088 (`### Heap-Str primitives`) + the `**Str ABI.**` paragraph lifted from :2802 - `scope-boundaries.md` ← :2839–3020 (`## What is not (yet) supported`) - `verification.md` ← :2687–2699 Each file starts `# ` 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:56–82. 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` ← :788–852 + :853–913 + :914–977 + :1015–1122 + :1378–1393 (Decision 9/10 narrative `###`s per Appendix) - `typeclasses.md` ← :1536–1577 + :1640–1752 (Decision 11 narrative) - `effects.md` ← :190–204 (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` ← :332–471 + :590–674 (`### Candidate notations` + `### Form (B)` — the `docs_honesty_pin.rs` Form-B placeholder present-anchor retargets here in Task 5) - `pipeline.md` ← :2616–2662 (`## Pipeline`) + :2663–2686 (`## 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`: :165–176, :177–189, :205–213, :214–229, :241–243, :245–267, :472–486, :487–519, :520–536, :537–589, :675–730, :978–1014, :1352–1377, :1510–1519, :1520–1535, :1965–2000, :2089–2112, plus any genuine "why" sentence extracted from the source-link `##`s (`## Mangling scheme` :2209–2218, `## Convention: qualified cross-module references` :2219–2236, `## Env construction` :2237–2265 — 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` 28–37 and `data_model_section_is_bounded` 411–430; 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 28–37) and `fn data_model_section_is_bounded()` (lines 411–430). 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 (15–19) and `norm()` (24–26) 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` (:104–137): 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` (:94–101): reads `docs/PROSE_ROUNDTRIP.md` — **unchanged**. - [ ] **Step 3: Retarget `effect_doc_honesty_pin.rs:21`** `design_md_effect_prose_is_true` (:19–34), 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 2–3; `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 ~872–876, Show branch ~885–893) - 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 41–42: ```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 47–48: ```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 (25–28): ```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 (:199–212) → 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 5–6). - [ ] **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 2–4 = 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 1–12. 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 2–5 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 1–8 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`.