diff --git a/docs/specs/2026-05-19-design-ledger-formal-links.md b/docs/specs/2026-05-19-design-ledger-formal-links.md index 3a6a364..5313e2b 100644 --- a/docs/specs/2026-05-19-design-ledger-formal-links.md +++ b/docs/specs/2026-05-19-design-ledger-formal-links.md @@ -93,14 +93,27 @@ not forks): These stay as prose. The remedy for "this file is too big for 'above' to be clear" is commitment 1's file-split — a separate future concern, explicitly NOT this milestone. -- **Homeless references resolve or die.** A prose reference whose - referent has no durable home (e.g. - `design/models/pipeline.md` → `(see docs/PROSE_ROUNDTRIP.md)`) - is retargeted to the durable file that carries the content today - (here: `../contracts/roundtrip-invariant.md`) if one exists, else - deleted as decision-record-class prose (clause-3 already forbids - the relitigation form). Enumerating them is a recon/plan-time - scan, not a spec byte-decision. +- **Homeless references — three dispositions (clause-6), in + priority order.** A cross-reference whose referent has no durable + home is: **(a)** retargeted to the durable `design/`-or-source + file that *actually carries that content* today, if one exists; + else **(b)** the parenthetical pointer is removed while the + surrounding present-tense behavioural prose is preserved verbatim + — the ledger *describes* the behaviour, it does not point into + the non-durable tier; else **(c)** deleted outright **only if the + reference itself is relitigation residue** (clause-3-class). + Recon-confirmed canonical instance: + `design/models/pipeline.md:61` and + `design/models/authoring-surface.md:180`, both + `(see docs/PROSE_ROUNDTRIP.md)`, cite the *prose-mediator cycle / + `ail merge-prose`* — content + `design/contracts/roundtrip-invariant.md` does **not** carry + (that contract is the orthogonal hashing / parse-determinism + invariant). (a) is therefore unavailable and the content is real + current behaviour, not relitigation, so the disposition is + **(b)**: drop the `(see docs/PROSE_ROUNDTRIP.md)` pointer, keep + the surrounding `ail merge-prose` prose intact. Enumerating every + instance is the recon's job; the *policy* is the spec's. - **A cross-*file* `§"Section"` reference becomes a file-link.** `(see §"Data model" …)` pointing at content in *another* file becomes `[Data model](data-model.md)` — the section title may @@ -111,6 +124,49 @@ not forks): file is intra-file directional prose — the bullet above — and is untouched.) +## Scope — what counts as a cross-reference + +The milestone formalises **navigational cross-references**, not +every nominal mention of a file or symbol. The discriminator: + +- **In scope (a cross-reference):** a *navigational pointer* — the + reader is being told to go look elsewhere. Forms: `(see "Title" + …)`, `(see §"Section" …)`, `(see )`, `… as in …`, a + bare in-prose path inside a `(see …)`, or a directional `… + below`/`… above` whose named target is a **different file**. + These convert to file-relative `[label](path)` Markdown links. +- **Out of scope (not a cross-reference):** a *nominal mention* of + a source symbol or path in explanatory prose — "the desugarer + `ailang-core::desugar` lowers loop-recur", "the box layout in + `crates/ail-embed/src/lib.rs`". Naming the implementation is not + pointing the reader at a document to read. Linkifying these would + make the milestone "hyperlink the whole ledger" rather than + "formalise the cross-references" — a different, unrequested + change. They stay as prose. Commitment 2 *permits* a `crates/**` + link target only for the case where a genuine navigational `(see + crates/… )` pointer exists — e.g. `scope-boundaries.md:88` `see + \`ailang-core::desugar\`` converts to + `[desugar](../../crates/ailang-core/src/desugar.rs)` — never for + a nominal mention. + +Two byte-policies the conversion applies (Boss-adjudicated from +recon Open Questions; the planner does not re-open them): + +- **Iter-provenance suffixes are stripped on conversion.** A + reference like `see §"Class names" / mq.1` carries a + clause-3-class iter token. Converting yields + `[Class names](typeclasses.md)` — the ` / mq.1` provenance is + removed (it is exactly what clause-3 forbids; the + clause-3 ∘ clause-5 composition requires its removal, not its + survival riding on a now-formal link). +- **A directional phrase with no quoted title and no `(see …)` + form stays prose.** `embedding-abi.md:51` "the frozen value + layout below specifies" has no title to become a link label and + is not a `(see …)` pointer — descriptive directional prose, left + untouched. (The genuine cross-file pointer for that referent is + the *separate* `embedding-abi.md:45` `(see "Frozen value layout" + below)`, which does convert.) + ## Concrete code shapes ### No authoring surface — the delivered concrete code @@ -261,13 +317,21 @@ design/contracts/embedding-abi.md:45 (informal AND stale-direction - after: … layout is **frozen as of M3** (see [Frozen value layout](frozen-value-layout.md)); … -design/models/pipeline.md:61 (the canonical HOMELESS reference — - points into docs/, the non-durable tier) -- before: … (see docs/PROSE_ROUNDTRIP.md) -- after: … (see [round-trip invariant](../contracts/roundtrip-invariant.md)) - # retargeted to the durable home that carries the - # content; if recon finds no durable home, the clause-6 - # rule deletes it as decision-record-class prose instead +design/models/pipeline.md:61 + design/models/authoring-surface.md:180 + (the canonical HOMELESS references — `(see docs/PROSE_ROUNDTRIP.md)` + into the non-durable tier; recon proved roundtrip-invariant.md + does NOT carry the merge-prose-cycle content ⇒ clause-6 + disposition (b), not a retarget) +- before (shape): … the prompt template `ail merge-prose` + composes (see docs/PROSE_ROUNDTRIP.md). +- after (shape): … the prompt template `ail merge-prose` + composes. + # disposition (b): the (see docs/…) pointer is removed; + # the surrounding present-tense behavioural prose about + # `ail merge-prose` is preserved verbatim. Exact bytes + # (recon-confirmed pipeline.md:60-61, + # authoring-surface.md:180-181) are the planner's per + # the planner Iron Law. ``` ### (c) clause-1 is unchanged (commitment 4, INDEX = spine) @@ -344,12 +408,19 @@ outcome, not a dodge). 2. clause-5 is demonstrably RED-able (the synthetic vector fails if the durable classifier or the anchor check is wrong) and GREEN on the final tree. -3. Every genuine cross-*file* prose reference in `design/contracts/` - and `design/models/` is a file-relative `[label](path)` Markdown +3. Every *navigational* cross-*file* reference (per §"Scope — what + counts as a cross-reference") in `design/contracts/` and + `design/models/` is a file-relative `[label](path)` Markdown link resolving (from its containing file) to an existing - `design/`-or-source file. The float-semantics, embedding-abi, and - pipeline references above are converted exactly as shown (modulo - recon's homeless-home confirmation). + `design/`-or-source file — OR, for a homeless reference, is + disposed per clause-6 (a)/(b)/(c). Nominal source-symbol + mentions are NOT linkified (out of scope). Iter-provenance + suffixes on converted refs are stripped. The recon enumeration + is the authoritative touch-set: float-semantics:100, + float-semantics:69, embedding-abi:45, data-model:38/66/79/206/226, + memory-model:44/105, scope-boundaries:48/88 convert; the two + PROSE_ROUNDTRIP refs take disposition (b); embedding-abi:51 and + every intra-file "above/below" stay prose. 4. No reference in `design/` targets `docs/` (any subtree) or carries a `#fragment`. 5. `design/INDEX.md` and clause-1 are byte-unchanged; the