Files
AILang/docs/specs/0045-design-md-rolesplit.md
T
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

36 KiB
Raw Blame History

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 241243: "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 axisdesign/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:5682) 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:

# 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 filedesign/contracts/0005-float-semantics.md (content moved verbatim from DESIGN.md:27002838, header re-levelled to file root, all decision-record/why-prose stripped to the journal):

# 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 guardcrates/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):

//! 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:

; 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:

-   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:

- 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:

- 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 618 IX preamble
## Project ecosystem (intro) 1955 IX preamble
### What this document is — honesty rule 5682 contracts/0007-honesty-rule.md (rewritten; pins docs_honesty_pin.rs:70,72)
## Project language: English 8392 IX preamble
## Feature-acceptance criterion 93164 contracts/0004-feature-acceptance.md
## Decision 1: source = data 165176 D
## Decision 2: content-addressed 177189 D
## Decision 3: pure core + effects 190204 models/0002-effects.md (pins effect_doc_honesty_pin.rs present-anchors — pin reads this file)
## Decision 4: HM + refinements 205213 D
## Decision 5: emit LLVM IR as text 214229 D
## Decision 6 intro 230240 contracts/0001-authoring-surface.md
(Decision 6 :241243 audit-trail sentence) 241243 D (retired, no successor pin — §Architecture-4)
### Why this is opening up 245267 D
### Architectural pin: data structure is SoT 268297 contracts/0001-authoring-surface.md
### Constraints (hard, in priority order) 298331 contracts/0001-authoring-surface.md
### Candidate notations 332471 models/0001-authoring-surface.md
### First choice and rollback plan 472486 D
### Implementation outline 487519 D
### What this Decision deliberately does not do 520536 D
### Form refinements during implementation 537589 D
### Form (B) — human prose projection 590674 models/0001-authoring-surface.md (the Form-B placeholder present-anchor in docs_honesty_pin.rs re-points here)
### Empirical addendum 675730 D
## Decision 8: explicit verified tail calls 731787 contracts/0012-tail-calls.md
## Decision 9 intro 788852 models/0004-rc-uniqueness.md
### Per-fn arena via stack alloca 853913 models/0004-rc-uniqueness.md
## Decision 10 intro 914977 models/0004-rc-uniqueness.md
### Why not other memory models 9781014 D
### The LLM-aware sharpening 10151122 models/0004-rc-uniqueness.md
### Language-design constraints (binding) 11231150 contracts/0008-memory-model.md
### Schema additions 11511312 contracts/0008-memory-model.md
### Advisory diagnostics 13131351 contracts/0008-memory-model.md
### Why advisory + suppress instead of inference 13521377 D
### Inference algorithm 13781393 models/0004-rc-uniqueness.md
### Codegen contract 13941412 contracts/0008-memory-model.md
### Mode metadata is load-bearing for codegen 14131509 contracts/0008-memory-model.md
### Adjacent extensions for mutability (out of scope) 15101519 D
### What this Decision deliberately does not do 15201535 D
## Decision 11 intro 15361577 models/0005-typeclasses.md
### Form-A schema (JSON authoring surface) 15781639 contracts/0013-typeclasses.md
### Resolution and monomorphisation 16401752 models/0005-typeclasses.md
### Cross-module references in synthesised bodies 17531823 contracts/0013-typeclasses.md (pins codegen_import_map_fallback_pin.rs:2, polyfn_dot_qualified_branch_pin.rs:2)
### Defaults and superclasses 18241855 contracts/0013-typeclasses.md
### Diagnostic categories 18561917 contracts/0013-typeclasses.md
### Method dispatch 19181964 contracts/0013-typeclasses.md
### What the typeclass design explicitly does NOT support 19652000 D
### Prelude (built-in) classes 20012042 contracts/0013-typeclasses.md (pins show_no_instance_e2e.rs:47; Show diagnostic target)
### Heap-Str primitives 20432088 contracts/0011-str-abi.md (ledger addition — see below)
### What this decision does NOT commit to 20892112 D
## Roundtrip Invariant (+ 3 ###s 21522208) 21132208 contracts/0009-roundtrip-invariant.md (whole block kept together — pins round_trip.rs:10,72)
## Mangling scheme 22092218 source-link only (no prose file): behaviour → dropped (code is SoT); any "why" sentence → D
## Convention: qualified cross-module references 22192236 source-link only qualified-xref (ledger addition): behaviour → dropped; rationale → D
## Env construction 22372265 source-link only (no prose file): behaviour → dropped (code is SoT); any "why" sentence → D
## Embedding ABI intro 22662333 contracts/0003-embedding-abi.md (pins docs_honesty_pin.rs:135)
### Frozen value layout (M3 — one-way commitment) 23342376 contracts/0006-frozen-value-layout.md + source-link runtime/rc.c §layout (dual; pins embed_record_layout_pin.rs:1)
## Data model (+ 4 ###s) 23772615 contracts/0002-data-model.md (whole; design_schema_drift.rs include_str!s it)
## Pipeline 26162662 models/0003-pipeline.md
## CLI 26632686 models/0003-pipeline.md
## Verification and correctness (across cycles) 26872699 contracts/0014-verification.md
## Float semantics 27002838 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 28393020 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 (20432088) + 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.