warning: in the working copy of 'crates/xtask/src/main.rs', LF will be replaced by CRLF the next time Git touches it crates/xtask/src/main.rs | 49 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) warning: in the working copy of 'crates/xtask/src/main.rs', LF will be replaced by CRLF the next time Git touches it diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 7adcdca..3b748b8 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -566,8 +566,7 @@ fn inline_field(table: &str, key: &str) -> Option { let mut from = 0; while let Some(rel) = table[from..].find(key) { let at = from + rel; - let delimited = at == 0 - || matches!(bytes[at - 1], b'{' | b',' | b' ' | b'\t'); + let delimited = at == 0 || matches!(bytes[at - 1], b'{' | b',' | b' ' | b'\t'); if delimited { if let Some(val) = field_after(&table[at..], key) { return Some(val); @@ -821,21 +820,30 @@ fn check_llms_links() { continue; } let target = target.trim_start_matches('/'); - // Site-root assets are placed by `site`; page links map into src/. - let exists = match target { - "llms-full.txt" | "manifest.schema.json" => true, - "install.sh" | "install.ps1" => true, - t => root.join("docs-site/src").join(t).exists(), - }; - if !exists { + if !llms_target_exists(&root, target) { dead.push(target.to_string()); } } + if !dead.is_empty() { eprintln!("xtask check: dead links in docs-site/llms.txt: {dead:?}"); std::process::exit(1); } } +/// Resolve one curated-index target against the artifact that actually produces +/// it. Generated `llms-full.txt` is exercised through its generator; stored +/// root assets must exist at their real source path. +// [impl->REQ-DOCS-5] +fn llms_target_exists(root: &Path, target: &str) -> bool { + match target { + "llms-full.txt" => !llms_full(root).is_empty(), + "manifest.schema.json" => root + .join("crates/spt-runtime/manifest.schema.json") + .is_file(), + "install.sh" | "install.ps1" => root.join(target).is_file(), + t => root.join("docs-site/src").join(t).is_file(), + } +} /// llms-full.txt: the CI-concatenated full export — every page in SUMMARY /// order, fenced with its site path so agents can cite anchors @@ -2077,6 +2085,29 @@ mod docs_token_gate_tests { } } +#[cfg(test)] +mod llms_link_tests { + use super::llms_target_exists; + + // [unit->REQ-DOCS-5] + #[test] + fn stored_root_assets_must_really_exist() { + let root = tempfile::tempdir().expect("temp root"); + assert!( + !llms_target_exists(root.path(), "manifest.schema.json"), + "a missing checked-in schema must red the curated-link gate" + ); + let schema = root.path().join("crates/spt-runtime/manifest.schema.json"); + std::fs::create_dir_all(schema.parent().unwrap()).unwrap(); + std::fs::write(&schema, "{}").unwrap(); + assert!(llms_target_exists(root.path(), "manifest.schema.json")); + + assert!(!llms_target_exists(root.path(), "install.sh")); + std::fs::write(root.path().join("install.sh"), "#!/bin/sh").unwrap(); + assert!(llms_target_exists(root.path(), "install.sh")); + } +} + #[cfg(test)] mod heavy_class_tests { use super::{binds_real_broker_in_tests, filter_classifies};