iter design-ledger-formal-links.1 (DONE 5/5): clause-5 hard gate + 7 prose-ref conversions + 2 disposition-(b) homeless removals + honesty-rule positive-half (whole milestone in one iter)

Positive-half completion of the DESIGN.md -> design/ split: design/
body cross-references are now formal, file-relative Markdown links
into the durable tier (design/ or source), and a new in-tree hard
gate (design_index_pin.rs clause-5,
design_body_links_are_durable_and_resolve) walks every
design/contracts/*.md + design/models/*.md, strips fenced code
(strip_fences toggles on ```/~~~ lines so a ](  inside a fence is not
treated as a link), extracts every ](path), and asserts the target
resolves file-relative to a real file under design/-or-crates/-or-
runtime/; never docs/, never an in-file #anchor.

RED-first via identity-stubbed strip_fences (four embedded synthetic
vectors -- first one FAILS); replacing the stub with the real
toggle-on-fence impl turns the test GREEN. clause-5 composes with
clause-3 into the complete invariant the milestone establishes:
every contract cross-reference is EITHER a resolving durable
file-link OR clause-3-forbidden decision-record prose.

Conversions (recon-and-corpus-verified closed set):
  Task 2 (7 prose refs, 8 link tokens):
    float-semantics.md:69    Prelude classes -> [..](typeclasses.md)
    float-semantics.md:100   bare-path -> [Str ABI](str-abi.md)
    embedding-abi.md:45      "Frozen value layout" -> [..](frozen-value-layout.md)  (drop stale "below")
    memory-model.md:44       Data model -> [..](data-model.md)
    memory-model.md:105-106  Method dispatch -> [..](typeclasses.md)  (drop stale "below"; the target heading lives in typeclasses.md:227, not in this file)
    scope-boundaries.md:48   Str ABI -> [..](str-abi.md)
    scope-boundaries.md:88   mixed split: ailang-core::desugar -> source link + Pipeline -> ../models/pipeline.md (drop stale "above")
  Task 3 (2 disposition-(b) homeless removals):
    pipeline.md:60-61            (see docs/PROSE_ROUNDTRIP.md) pointer removed, CLI prose preserved
    authoring-surface.md:178-181 cross-tier pointer clause removed, ail merge-prose sentence preserved
  Task 4: honesty-rule.md positive-half paragraph inserted between L14 and the existing L15-blank-L16; both docs_honesty_pin.rs-pinned phrases byte-identical at L14/L19 (now shifted to L19 -> L25 by the +6 lines).

Out of scope, preserved (asserted independently): every intra-file
"above/below"; embedding-abi.md:51 "frozen value layout below
specifies" (no quoted title, no (see) form); data-model.md
38/66/79/206/226 (in-fence ```jsonc schema annotations -- the inline
analog of the nominal-mention carve-out). INDEX.md and the
decision-records journal byte-unchanged; clauses 1-4 of
design_index_pin.rs source byte-unchanged (the only `-` lines in
the diff are the two-line //! header rewrite Task 1 Step 5 itself
delivers).

Boss-verified independently (not on agent report alone):
  cargo test --workspace               647 passed / 0 failed
                                       (+1 vs pre-milestone 646:
                                        the new clause-5)
  cargo test --test design_index_pin   5 / 5 passed
  cargo test --test docs_honesty_pin   5 / 5 passed (additive
                                       paragraph is pin-safe)
  grep ](.../docs/.../) under design/  zero
  grep ](#)        under design/  zero
  ](-link count under design/          8 (closed convert-set)
  git diff --quiet design/INDEX.md     ok
  git diff --quiet decision-records    ok
  embedding-abi.md:48 pinned phrase    byte-identical

One Concerns item: Task-5 Step-7's plan-predicted "`-` line count = 1"
was actually 2 because Task 1 Step 5 rewrote the //! header 5 -> 8
lines (removing the original L4 + L5, not just L5). Planner self-
review-item-8 miss on my part -- a verification-arithmetic error in
the plan, NOT an implementation defect. The substantive assertion
(clauses 1-4 source byte-unchanged) is fully satisfied; the
implementer correctly flagged it and proceeded. The plan stands as
written; the assertion's `1` should have been `2`. Lesson noted for
future header-rewrite tasks.

Spec: docs/specs/2026-05-19-design-ledger-formal-links.md
(grounding-check PASS x3 across two corpus-grounded amendments --
clause-6 + cross-ref definition; clause-5 fence-skip + closed
convert-set enumeration).

Next: mandatory milestone-close audit (no fieldtest -- zero
authoring-surface change, reasoned exclusion).
This commit is contained in:
2026-05-19 23:31:30 +02:00
parent 36599bedd9
commit 8ad91e7f24
11 changed files with 258 additions and 13 deletions
@@ -0,0 +1,12 @@
{
"iter_id": "design-ledger-formal-links.1",
"date": "2026-05-19",
"mode": "standard",
"outcome": "DONE",
"tasks_total": 5,
"tasks_completed": 5,
"reloops_per_task": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0 },
"review_loops_spec": 0,
"review_loops_quality": 0,
"blocked_reason": null
}
+120 -2
View File
@@ -1,8 +1,11 @@
//! 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/2026-05-19-design-md-rolesplit.md.
//! dangles, a contract loses its ratifying test, docs/DESIGN.md is
//! resurrected, or a design/ body cross-link fails to resolve into
//! the durable tier (clause-5; spec
//! docs/specs/2026-05-19-design-ledger-formal-links.md). Spec for
//! the split: docs/specs/2026-05-19-design-md-rolesplit.md.
use std::fs;
use std::path::PathBuf;
@@ -250,3 +253,118 @@ fn contracts_carry_no_decision_record_prose() {
}
}
}
#[test]
fn design_body_links_are_durable_and_resolve() {
// clause 5 — every inline Markdown link in design/ body prose
// (contracts/ + models/, NOT INDEX.md — the spine is the
// structured registry tier resolved by clause-1, commitment 4)
// resolves, relative to its CONTAINING file, to an existing
// file under design/ or source (crates/** | runtime/**); never
// under docs/; never an in-file #anchor. Fenced code blocks are
// not scanned (a `](` inside ``` is literal text, not a link).
// Composes with clause-3: a surviving cross-reference is a
// resolving durable file-link or it is clause-3-forbidden
// decision-record prose.
// Fenced code (``` … ``` / ~~~ … ~~~) is literal text, not
// Markdown — a `](` inside a fence is NOT a navigable link on
// any renderer. Strip fenced regions before scanning (gate
// correctness: prevents false extraction of code-example byte
// sequences and of non-rendering in-fence links).
fn strip_fences(md: &str) -> String {
let mut out = String::new();
let mut in_fence = false;
for line in md.lines() {
let t = line.trim_start();
if t.starts_with("```") || t.starts_with("~~~") {
in_fence = !in_fence;
continue; // drop the fence marker line itself
}
if !in_fence {
out.push_str(line);
out.push('\n');
}
}
out
}
// link target := first capture of \]\(([^)]+)\)
fn targets(md: &str) -> Vec<String> {
let mut out = Vec::new();
let b = md.as_bytes();
let mut i = 0;
while i + 1 < b.len() {
if b[i] == b']' && b[i + 1] == b'(' {
if let Some(end) = md[i + 2..].find(')') {
out.push(md[i + 2..i + 2 + end].trim().to_string());
}
}
i += 1;
}
out
}
fn is_durable(repo_rel: &str) -> bool {
repo_rel.starts_with("design/")
|| repo_rel.starts_with("crates/")
|| repo_rel.starts_with("runtime/")
}
// RED-first synthetic vectors (proves the gate bites before it
// is pointed at the live tree).
{
let t = targets("see [x](../docs/specs/foo.md) and [y](#sec) and [z](./gone.md)");
assert_eq!(t, vec!["../docs/specs/foo.md", "#sec", "./gone.md"]);
assert!(!is_durable("docs/specs/foo.md")); // durable-tier reject
assert!("#sec".starts_with('#')); // in-file anchor reject
// fenced code is not a link surface (gate correctness)
assert!(targets(&strip_fences("```\nsee [E](e.md)\n```\n")).is_empty());
assert_eq!(targets(&strip_fences("[k](k.md)\n```\n[n](n.md)\n```")), vec!["k.md"]);
}
let bases = ["design/contracts", "design/models"];
for base in bases {
let dir = root().join(base);
for entry in fs::read_dir(&dir).expect("design/ subdir exists") {
let p = entry.unwrap().path();
if p.extension().and_then(|e| e.to_str()) != Some("md") {
continue;
}
let raw = fs::read_to_string(&p).unwrap();
let fname = format!("{base}/{}", p.file_name().unwrap().to_string_lossy());
for tgt in targets(&strip_fences(&raw)) {
if tgt.starts_with("http://")
|| tgt.starts_with("https://")
|| tgt.starts_with("mailto:")
{
continue;
}
let file_part = tgt.split('#').next().unwrap_or(&tgt);
assert!(
!file_part.is_empty(),
"clause-5: in-file #anchor link {tgt:?} in {fname:?} — \
commitment 1 forbids fragments; split the file"
);
let resolved = p.parent().unwrap().join(file_part);
let canon = resolved
.canonicalize()
.unwrap_or_else(|e| panic!(
"clause-5: link {tgt:?} in {fname:?} does not resolve: {e}"
));
let repo_rel = canon
.strip_prefix(root().canonicalize().unwrap())
.unwrap_or(&canon)
.to_string_lossy()
.replace('\\', "/");
assert!(
is_durable(&repo_rel),
"clause-5: link {tgt:?} in {fname:?} targets the \
non-durable tier ({repo_rel:?}); commitment 2 \
permits design/ + crates/ + runtime/ only"
);
}
}
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ exact. The swarm artefact is data-race-free, sanitiser-verified.
The staticlib swarm artefact is **RC-only**:
`ail build --emit=staticlib` rejects `--alloc=gc`/`--alloc=bump`
(the shared Boehm collector is not swarm-safe). The value/record
layout is **frozen as of M3** (see "Frozen value layout" below); the
layout is **frozen as of M3** (see [Frozen value layout](frozen-value-layout.md)); the
ctx-threaded C signature is the M2 shape.
Export parameters are written **bare**: a scalar type carries no
+2 -2
View File
@@ -66,7 +66,7 @@ no `f32` variant. The runtime / codegen contract:
The same libc-`%g` rendering applies to `show 1.5` / `show nan` /
`show inf` via `instance Show Float` (which calls `float_to_str`
internally — see §"Prelude (built-in) classes" for the Show ship).
internally — see [Prelude (built-in) classes](typeclasses.md) for the Show ship).
The NaN-spelling caveat above is observable via `do print x` for
Float-typed `x`; the rendering is libc-version-dependent and
target-libc-specific. AILang does NOT canonicalise Float textual
@@ -97,7 +97,7 @@ LLM-author wants. Use ordering operators (`<`, `>`, ...) and
`float_to_str` (Float → Str) and `int_to_str` (Int → Str) are
fully wired through checker, codegen, and runtime. Both allocate
a fresh heap-Str slab at the call site (see design/contracts/str-abi.md
a fresh heap-Str slab at the call site (see [Str ABI](str-abi.md)
for the dual realisation) and carry `ret_mode: Own` so the let-binder
for the call result is RC-tracked and the slab is freed at scope
close.
+6
View File
@@ -13,6 +13,12 @@ Two things never belong in a contract or model file:
Decision-records are journal content, not ledger content; this is
the honesty rule it holds itself to.
A cross-reference that does belong stays: it is a formal,
file-relative Markdown link into the durable tier (`design/` or
source), enforced by `design_index_pin.rs` clause-5. A reference
that cannot be expressed as such a link is, by that fact, the
history-or-rationale prose the rule above removes.
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
+3 -3
View File
@@ -41,7 +41,7 @@ The form-A surface for fn signatures gains mode wrappers:
Internally, this is *not* a new `Type` variant. Modes are
metadata on `Type::Fn``paramModes` and `retMode` fields run
parallel to `params` and `ret` (see §"Data model" for the JSON
parallel to `params` and `ret` (see [Data model](data-model.md) for the JSON
schema). The substantive reasons for per-position metadata over a
`Type::Borrow` / `Type::Own` variant approach:
@@ -102,8 +102,8 @@ Three schema fields carry class references in this form:
`ClassDef.name` itself stays bare (defining-site context, like
`TypeDef.name`).
Method dispatch is type-driven post-mq.3 (see §"Method dispatch"
below): synth resolves a `Term::Var { name: "show" }` by consulting
Method dispatch is type-driven post-mq.3 (see [Method dispatch](typeclasses.md)):
synth resolves a `Term::Var { name: "show" }` by consulting
the workspace's method-to-candidate-class index, filtering by
argument type (concrete) or by declared constraint (rigid-var), and
routing the residual through the registry at fn-body-end discharge.
+2 -2
View File
@@ -45,7 +45,7 @@ What **is** supported (and used as the smoke test for the pipeline):
`float_to_int_truncate : (Float) -> Int` (saturating, NaN → 0),
`float_to_str : (Float) -> Str`,
`int_to_str : (Int) -> Str` (both allocate a heap-Str slab at
call time and return it with `ret_mode: Own`; see "Str ABI" for
call time and return it with `ret_mode: Own`; see [Str ABI](str-abi.md) for
the dual heap-/static-Str realisation); inspection
`is_nan : (Float) -> Bool` (LLVM
`fcmp uno`); Float bit-pattern constants `nan : Float`,
@@ -85,7 +85,7 @@ What **is** supported (and used as the smoke test for the pipeline):
another `Ctor`, or a literal. The desugar pass flattens
nested Ctor patterns into a chain of let + match and rewrites every
`Pattern::Lit` (top-level or sub-) to a `Term::If` on `==` before
typecheck/codegen — see `ailang-core::desugar` and Pipeline above.
typecheck/codegen — see [desugar](../../crates/ailang-core/src/desugar.rs) and [Pipeline](../models/pipeline.md).
- Literal patterns at top level and inside Ctor sub-patterns (via desugar).
`(pat-lit 0)` and `(pat-ctor Cons (pat-lit 0) _)` both
parse and lower; the rewrite is to `Term::If { cond = (== sv lit) }`,
+2 -2
View File
@@ -177,8 +177,8 @@ human readers. Form (B) inverts the trade-offs:
Critically, **form (B) has no parser**. Form (A) is round-trippable
by construction (Decision 6 constraint 2); form (B) deliberately is
not. Re-integrating prose edits requires an external LLM mediator,
not a compiler pass — see `docs/PROSE_ROUNDTRIP.md` for the
six-step cycle and the prompt template `ail merge-prose` composes.
not a compiler pass — the prompt template `ail merge-prose`
composes the six-step cycle.
Form (B) does not weaken any Decision 6 invariant:
-1
View File
@@ -58,7 +58,6 @@ ail parse <module.ail> — form-A text → canonical JSON-AST
ail prose <module.ail.json> — JSON-AST → form-B (lossy human prose, no parser)
ail merge-prose <m.ail.json> <m.prose.txt>
— compose the LLM-mediator prompt for the prose round-trip
(see docs/PROSE_ROUNDTRIP.md)
ail deps <module.ail.json> — list cross-module references
ail diff <a.ail.json> <b.ail.json> — content-addressed def-level diff
ail workspace <entry.ail.json> — list all modules transitively reachable from entry
@@ -0,0 +1,109 @@
# iter design-ledger-formal-links.1 — formal cross-links + hard-gate clause-5
**Date:** 2026-05-19
**Started from:** 36599be
**Status:** DONE
**Tasks completed:** 5 of 5
## Summary
Positive-half completion of the DESIGN.md → design/ split: `design/`
body cross-references are now formal, file-relative Markdown links
into the durable tier (`design/` or source), and a new in-tree hard
gate (`design_index_pin.rs` clause-5,
`design_body_links_are_durable_and_resolve`) walks every
`design/contracts/*.md` + `design/models/*.md`, strips fenced code,
extracts every `](path)`, and asserts the target resolves
file-relative to a real file under `design/`-or-`crates/`-or-
`runtime/` — never `docs/`, never an in-file `#anchor`. RED-first was
established via four embedded synthetic-vector asserts on an
identity-stubbed `strip_fences`; replacing the stub with the real
toggle-on-fence impl turns the test GREEN. Seven prose cross-refs
were converted to `[label](path)` links (8 link tokens total — the
mixed-referent `scope-boundaries.md:88` split carries two), the two
homeless `(see docs/PROSE_ROUNDTRIP.md)` pointers were resolved via
clause-6 disposition (b) (pointer removed, surrounding behavioural
prose preserved), and a pin-safe positive-half paragraph was inserted
into `honesty-rule.md` after the existing clause-3 paragraph,
explicitly naming `design_index_pin.rs` clause-5 as the gate and
keeping both `docs_honesty_pin.rs`-pinned phrases byte-identical.
`design/INDEX.md` and the decision-records journal are byte-unchanged
(commitment 4 / Acceptance 5). Whole-workspace tests: **647 passed /
0 failed** (+1 from the pre-milestone 646: the new clause-5).
**Composition-invariant assertion** (Acceptance 5; spec
testing-strategy §Composition with clause-3): on the post-milestone
tree, for every `design/contracts/*.md`, clause-3 GREEN ∧ clause-5
GREEN — independently verified by running both tests in the same
suite. Every cross-reference in a contract is therefore either a
resolving durable file-link **or** it is gone (clause-3 would
otherwise have rejected it as decision-record prose). The two
clauses now form the complete invariant the split promised.
## Per-task notes
- iter design-ledger-formal-links.1.1: clause-5 hard gate added to
`crates/ailang-core/tests/design_index_pin.rs` (RED-first via
identity-stubbed `strip_fences`; GREEN after real toggle-on-fence
impl; `//!` header extended one sentence; 5/5 tests pass).
- iter design-ledger-formal-links.1.2: seven prose cross-refs
converted to file-relative `[label](path)` Markdown links
(`float-semantics.md:69, :100`; `embedding-abi.md:45`;
`memory-model.md:44, :105-106`; `scope-boundaries.md:48, :88`
the last splits into two links, source-link + cross-models link).
- iter design-ledger-formal-links.1.3: clause-6 disposition (b)
applied to the two homeless `(see docs/PROSE_ROUNDTRIP.md)`
pointers (`pipeline.md:60-61`, `authoring-surface.md:178-181`) —
pointer removed, present-tense behavioural prose about
`ail merge-prose` and the six-step cycle preserved.
- iter design-ledger-formal-links.1.4: positive-half paragraph
inserted into `honesty-rule.md` between lines 14 and 15 — names
formal links into the durable tier as the surviving
cross-reference form and `design_index_pin.rs` clause-5 as the
gate. Pin-safe (both `docs_honesty_pin.rs`-pinned phrases stay
byte-identical, no clause-3 PHRASE or Sweep-1 anchor introduced).
- iter design-ledger-formal-links.1.5: whole-workspace gate +
acceptance-criteria spot-checks (zero `docs/`-targeting links,
zero `#fragment` links, exactly 8 `](path)` tokens introduced, 5
in-fence refs untouched, INDEX + decision-records journal
byte-unchanged).
## Concerns
- Task 5 Step 7 planner predicted-count discrepancy: the plan
expected exactly **1** removed line in the test-file diff
(interpreting Step 5's `//!` header replacement as a single-line
edit), but the actual diff shows **2** removed lines because Step
5's verbatim before→after rewords lines 4 *and* 5 of the original
`//!` block (5-line block → 8-line block). Clauses 14 source
content (line range 7+ of the file) is byte-unchanged, which is
the load-bearing Acceptance 1; the 2-vs-1 mismatch is purely in
the planner's predicted byte-count of the `//!` header rewording
it itself mandated. Plan-pseudo-vs-reality class (cf.
feedback_plan_pseudo_vs_reality), Step-5 verbatim taking precedence
over Step-7 predicted-count.
## Known debt
- (none — the milestone closes the positive-half side of the
contract/decision-record split; the spec's named acceptance set is
exhaustive and closed; intra-file directional prose remains
explicitly out of scope, with file-split as the documented future
remedy under commitment 1 if a file ever grows enough that
"above"/"below" loses clarity).
## Files touched
- `crates/ailang-core/tests/design_index_pin.rs` (header + appended
clause-5)
- `design/contracts/float-semantics.md` (lines 69, 100)
- `design/contracts/embedding-abi.md` (line 45)
- `design/contracts/memory-model.md` (lines 44, 105-106)
- `design/contracts/scope-boundaries.md` (lines 48, 88)
- `design/contracts/honesty-rule.md` (new paragraph after L14)
- `design/models/pipeline.md` (drop line 61)
- `design/models/authoring-surface.md` (lines 178-181 reworded)
## Stats
`bench/orchestrator-stats/2026-05-19-iter-design-ledger-formal-links.1.json`
+1
View File
@@ -118,3 +118,4 @@
- 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. → 2026-05-19-design-decision-records.md
- 2026-05-19 — audit design-md-rolesplit (milestone close): DRIFT (one tidy iteration) + bench causally-exonerated (baseline pristine). Architect drift_found, relocation byte-faithful (MIXED Decisions / dual-link / source-link / rewritten honesty-rule all match the spec Appendix vs deeffb1; build-atomicity holds; design_index_pin 4/4; honesty-rule.md correct + pins retargeted; agent contracts coherent) — one [medium] spirit-finding: faithfully-migrated decision-record/history prose in design/contracts/{typeclasses,str-abi,scope-boundaries}.md DODGES the 6 literal clause-3 markers (case+wording variance) but IS the relitigation content the split's spirit sends to journals; plus [low] float-semantics.md stale-direction "see Str ABI below". Both routed items adjudicated strippable-doc-archaeology-to-TIDY-not-ratify (the str-abi.md:23 advisory Sweep-1 exit-1 correctly diagnoses real pre-existing history residue, byte-identical DESIGN.md@deeffb1:2062-2065, faithfully migrated — not split-introduced). Bencher: NO-ratify, causally-exonerated DECISIVE on byte-evidence — emitted IR AND final -O2 binaries byte-identical 176821c vs pre-milestone dd5b183 for all 6 check.py firings (sha256+cmp), all ~11 changed code/runtime files audited comment/docstring/diagnostic-string-only, zero IR-path change; the firings are tracked-P2 (*.bump_s staleness, *_at_rc.max_us -n5 tail jitter, *.gc_s Boehm-scan variance — NOT the M5 gc_rss trio); compile_check 24/24 + cross_lang 25/25 pristine corroborate; baseline untouched (identical to M2/M3/M5). Resolution: one tidy iter design-md-rolesplit.tidy — (1) move the history prose to the decision-record journal, (2) fix the stale "below", (3) re-scope architect_sweeps honesty sweeps to design/contracts only (models/ is the explicitly-narrative tier — scanning it for history-anchors is a post-split category error), (4) widen design_index_pin.rs clause-3 to SUBSUME Sweep-1's history-anchor regex over contracts/ (invariant: clause-3 GREEN ⟹ Sweep-1 clean in contracts/ — the hard gate enforces the spirit, closing the literal-marker dodge permanently). No fieldtest (zero authoring-surface change). Milestone closes after the tidy lands Boss-verified. → 2026-05-19-audit-design-md-rolesplit.md
- 2026-05-19 — iter design-md-rolesplit.tidy (DONE 7/7): resolves the milestone-close audit DRIFT (2ba5e16). Gate-first TDD: widened design_index_pin.rs clause-3 to a hand-rolled FAITHFUL Sweep-1 superset — case-sensitive digit-anchored Sweep-1 line anchors (confirmed ZERO across all contracts) + Sweep-1's `^[^/]*` path-EXCLUDED date_anchor (so docs/specs/2026-.. citations are not flagged) + the audit-named decision-record PHRASES (case-insensitive, closing the capital-variance dodge); NO regex dep, the blanket case-insensitive iter-detector REJECTED as unworkable (it conflated the memory-model rule-names "Iter A/B" + ordinary "pre-existing/pre-set/pre-Boehm" with provenance). Sentence-level strip of the faithfully-migrated history/decision-record prose out of 5 contract files (typeclasses/str-abi/scope-boundaries — the audit's spot-check — PLUS roundtrip-invariant.md:73 + data-model.md:149,161, the 2 the exhaustive plan-time scan found the spot-check missed) into docs/journals/2026-05-19-design-decision-records.md, each removed sentence replaced by its present-tense contract equivalent; float-semantics.md stale `(see "Str ABI" below)``(see design/contracts/str-abi.md)`; architect_sweeps.sh honesty sweeps re-scoped design/contracts+design/models → design/contracts only (models/ is the explicitly-narrative tier; scanning it for history-anchors is a post-split category error) + skills/audit/agents/ailang-architect.md lockstep. Invariant established: clause-3 GREEN ⟹ Sweep-1 finds nothing in contracts/. The prior dispatch correctly BLOCKED on a real plan defect (iso_date lacked Sweep-1's path-exclusion → over-fired on legit spec-path citations); per the "two+ defects in one iteration ⇒ fix the upstream artifact, not a third patch" discipline the audit Resolution mechanism+scope were corrected in lockstep (f2cdd67) before re-dispatch. Three docs_honesty_pin pinned-byte runs survived contiguous (str-abi.md:19, typeclasses.md:297, scope-boundaries.md:8 — shifted from :9 by the authorized :5-6 collapse, content byte-untouched). Boss-verified independently: cargo test --workspace 646/0, design_index_pin 4/4 (clause-3 RED→GREEN), architect_sweeps.sh exit 0 "All five sweeps clean" (acceptance criterion 9 met), acceptance grep CLEAN, 3 pins each exactly 1 contiguous match. Zero spec/quality re-loops. This is the FINAL design-md-rolesplit iteration — the milestone (DESIGN.md → design/ ledger role-split) is now functionally complete, audited, drift-resolved, and the in-code hard gate enforces the honesty spirit. → 2026-05-19-iter-design-md-rolesplit.tidy.md
- 2026-05-19 — iter design-ledger-formal-links.1 (DONE 5/5, whole milestone): positive-half completion of the DESIGN.md → design/ split — design/ body cross-references are now formal, file-relative Markdown links `[label](path)` into the durable tier (design/ + crates/** + runtime/**), and a new in-tree hard gate `design_index_pin.rs` **clause-5** (`design_body_links_are_durable_and_resolve`) walks every design/contracts/*.md + design/models/*.md, strips fenced code (`strip_fences` toggles on ```/~~~), extracts every `](path)`, and asserts it resolves file-relative to a real durable file — never docs/, never an in-file #anchor. RED-first via identity-stubbed strip_fences (four embedded synthetic vectors — first FAILS) → real toggle-on-fence impl → GREEN. **clause-5 ∘ clause-3 = complete invariant** the milestone delivers: every contract cross-reference is either a resolving durable file-link OR clause-3-forbidden decision-record prose. Convert-set (recon-and-corpus-verified, closed): 7 prose refs / 8 link tokens — float-semantics:69/100, embedding-abi:45, memory-model:44/105 (the genuine cross-file stale-direction wart: "Method dispatch below" but the heading lives in typeclasses.md:227, not memory-model.md), scope-boundaries:48/88 (mixed-referent split: `ailang-core::desugar` → source link + Pipeline → ../models/pipeline.md). Disposition-(b) on the 2 PROSE_ROUNDTRIP homeless pointers (pipeline.md:61, authoring-surface.md:180) — pointer removed, ail merge-prose behavioural prose preserved (recon proved roundtrip-invariant.md does NOT carry the merge-prose-cycle content; the prior clause-6 sample's "(a) retarget" was thus wrong, corrected in spec amendment 1 to the three-disposition rule). honesty-rule.md positive-half paragraph inserted pin-safe between L14 and L16; both `docs_honesty_pin.rs` phrases byte-identical. Spec went through TWO corpus-grounded amendments before plan-write (grounding-check PASS ×3): (1) recon-driven — clause-6 incomplete + missing navigational/nominal cross-reference definition + OQ2/OQ3 byte-policies; (2) plan-time-corpus-driven — clause-5 fence-skip + the in-fence schema-annotation carve-out (data-model.md 38/66/79/206/226 are inside ```jsonc fences 3087 + 203228, where Markdown links are literal text on every renderer; the inline analog of the nominal-mention carve-out — schema-example documentation, not browsable cross-references). Per the "two+ surfaced ⇒ ground properly once, don't iter-patch" discipline, amendment 2 was the definitive corpus-grounded pass (every convert-set ref's prose-vs-fence status + exact bytes personally verified before amending), not a fourth patch returning later. INDEX-spine sub-fork resolved by user MC during brainstorm Step 2: spine stays repo-root-relative (registry tier is structurally invariant — move-fragility absent), clause-1 byte-unchanged; body uses file-relative (the converged-design path-form decision). Boss-verified independently: `cargo test --workspace` 647/0 (+1: clause-5), `design_index_pin` 5/5, `docs_honesty_pin` 5/5, design/INDEX.md + decision-records journal byte-unchanged, clauses 14 source byte-unchanged (the 2 `-` lines are the two-line //! header rewrite Task 1 Step 5 itself delivers — clauses are #[test] fns, untouched), 0 docs/ link targets, 0 #fragments, 8 `](` link tokens (= the closed convert-set), embedding-abi.md:48 docs_honesty_pin pinned phrase byte-identical. One Concerns item: Task-5 Step-7 plan-predicted `-`-line count was 1, actual 2 — planner self-review-item-8 arithmetic miss on the //! header rewrite (Steps 5 + 7 inconsistent within Task 1+5 about how many lines the header rewrite removes); harmless (substantive assertion *clauses 14 source unchanged* fully holds), recorded as lesson. Next: mandatory milestone-close audit; no fieldtest (zero authoring-surface change — reasoned exclusion). → 2026-05-19-iter-design-ledger-formal-links.1.md