//! 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, docs/DESIGN.md is //! resurrected, or a design/ body cross-link fails to resolve into //! the durable tier (clause-5; spec //! docs/specs/0046-design-ledger-formal-links.md). Spec for //! the split: docs/specs/0045-design-md-rolesplit.md. use std::fs; use std::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, widened (design-md-rolesplit.tidy, // audit Resolution-4) to a FAITHFUL SUPERSET of // bench/architect_sweeps.sh Sweep-1's history-anchor regex over the // design/contracts/ scope, PLUS the audit-named decision-record // phrases (the deliberate widening that closes the case-variance // dodge the 6 literal markers left open). // // Invariant: clause-3 GREEN ⟹ Sweep-1 finds nothing in design/contracts/. // // Sweep-1 = 'Iter [0-9]+[a-z]?(\.[0-9]+)?|Family [0-9]+ // |^[^/]*2026-[0-9]{2}-[0-9]{2}|\*\*Status: |pre-[0-9]+[a-z]? // |[0-9]+[a-z]? sketch|21\.g' // Faithfulness, per Sweep-1 alternative: // - Iter / Family / pre- / sketch / 21.g / **Status: // → sweep1_line_anchor() reproduces each verbatim, // case-SENSITIVE (grep -E, no -i) — exactly Sweep-1 here, // never narrower. // - ^[^/]*2026-NN-NN → date_anchor() reproduces Sweep-1's // ^[^/]* PATH-EXCLUSION (only the line prefix before the // first '/' is scanned) and generalises 2026→20NN // (⊇ Sweep-1, never narrower). A `docs/specs/2026-..` // citation has '/' before the date ⇒ NOT flagged — faithful // to Sweep-1, no over-fire on legit present-tense spec // cross-refs (the iter-.1 plan defect this repairs). // - PHRASES: literal decision-record idioms (case-insensitive) — // the deliberate widening that closes the capital-variance // dodge ("An earlier draft" vs "an earlier draft"). // // A blanket case-insensitive iter/milestone detector was evaluated // and REJECTED (audit Resolution-4 corrected): it conflates the // memory-model rule-names "Iter A"/"Iter B", and ordinary words // "pre-existing"/"pre-set"/"pre-tail-call", with // provenance stamps — unworkable. faithful-Sweep-1 (the capital-I, // digit-anchored form) already excludes those by construction and // is confirmed ZERO across every contract file; lowercase // `(iter )` provenance is removed by the strip tasks, not by // a fragile hard-gate regex. The load-bearing invariant // (clause-3 GREEN ⟹ Sweep-1 clean in contracts/) holds with // sweep1_line_anchor + date_anchor + PHRASES alone. let dir = root().join("design/contracts"); const PHRASES: &[&str] = &[ "we rejected", "an earlier draft", "earlier draft committed", "why not other", "was retired", "were retired", "rollback plan", "previously all", "deliberately deferred", "new-baseline decision", "amends the above", "out of scope per", "the journal records when", "unchanged from the original draft", ]; // Sweep-1's non-date alternatives, hand-rolled verbatim, case-SENSITIVE // (grep -E without -i), on the raw physical line. fn sweep1_line_anchor(line: &str) -> Option<&'static str> { let kw_digit = |kw: &str| -> bool { let mut from = 0; while let Some(i) = line[from..].find(kw) { let p = from + i + kw.len(); if line[p..].chars().next().map_or(false, |c| c.is_ascii_digit()) { return true; } from = p; } false }; if kw_digit("Iter ") { return Some("Iter "); } if kw_digit("Family ") { return Some("Family "); } if kw_digit("pre-") { return Some("pre-"); } if line.contains("**Status: ") { return Some("**Status:"); } if line.contains("21.g") { return Some("21.g"); } if let Some(s) = line.find(" sketch") { let pre = line[..s].as_bytes(); if pre.last().map_or(false, u8::is_ascii_alphanumeric) && pre.iter().rev() .take_while(|c| c.is_ascii_alphanumeric()) .any(u8::is_ascii_digit) { return Some(" sketch"); } } None } // Sweep-1's `^[^/]*2026-NN-NN`, generalised to 20NN-NN-NN, // PATH-EXCLUDED: scan only the line prefix BEFORE the first '/'. fn date_anchor(line: &str) -> Option { let prefix = line.split('/').next().unwrap_or(line).as_bytes(); for w in prefix.windows(10) { if w[0] == b'2' && w[1] == b'0' && w[2].is_ascii_digit() && w[3].is_ascii_digit() && w[4] == b'-' && w[5].is_ascii_digit() && w[6].is_ascii_digit() && w[7] == b'-' && w[8].is_ascii_digit() && w[9].is_ascii_digit() { return Some(String::from_utf8_lossy(w).into_owned()); } } None } 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 raw = fs::read_to_string(&p).unwrap(); let fname = p.file_name().unwrap().to_string_lossy().into_owned(); let low = norm(&raw).to_lowercase(); for ph in PHRASES { assert!( !low.contains(ph), "clause-3: history phrase {ph:?} in contract {fname:?}" ); } for line in raw.lines() { if let Some(a) = sweep1_line_anchor(line) { panic!("clause-3: Sweep-1 anchor {a:?} in contract {fname:?}: {line:?}"); } if let Some(d) = date_anchor(line) { panic!("clause-3: history date {d:?} in contract {fname:?}: {line:?}"); } } } } #[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 { 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" ); } } } }