use crate::tools::RecoverableError;
pub fn guard_not_librarian_managed(path: &str, text: &str) -> Result<(), anyhow::Error> {
if !is_librarian_artifact(text) {
return Ok(());
}
Err(RecoverableError::with_hint(
format!(
"'{}' is a librarian-managed artifact — do not read or edit it directly",
path
),
"Use artifact tools instead:\n\
• Read: artifact(action=\"get\", id=\"<id>\")\n\
• Find: artifact(action=\"find\", semantic=\"<topic>\")\n\
• Edit: artifact(action=\"update\", id=\"<id>\", patch={...})\n\
Full guide: resources/read doc://librarian-guide",
)
.into())
}
pub fn is_librarian_artifact(text: &str) -> bool {
let Some(rest) = text.strip_prefix("---\n") else {
return false;
};
for line in rest.lines() {
if line == "---" {
break;
}
if let Some(val) = line.strip_prefix("id: ") {
let val = val.trim();
return val.len() == 16 && val.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'f'));
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_librarian_artifact() {
let text = "---\nid: 79a6276776a1b5da\nkind: tracker\n---\n# Body\n";
assert!(is_librarian_artifact(text));
}
#[test]
fn ignores_non_frontmatter_file() {
let text = "# Just a heading\nNo frontmatter here.\n";
assert!(!is_librarian_artifact(text));
}
#[test]
fn ignores_wrong_id_length() {
let text = "---\nid: abc123\nkind: spec\n---\n";
assert!(!is_librarian_artifact(text));
}
#[test]
fn ignores_uppercase_hex_id() {
let text = "---\nid: 79A6276776A1B5DA\nkind: tracker\n---\n";
assert!(!is_librarian_artifact(text));
}
#[test]
fn ignores_non_hex_id() {
let text = "---\nid: xxxxxxxxxxxxxxxx\nkind: spec\n---\n";
assert!(!is_librarian_artifact(text));
}
#[test]
fn guard_returns_recoverable_error_for_artifact() {
let text = "---\nid: abc513d3ee0f0b50\nkind: tracker\n---\n";
let err = guard_not_librarian_managed("docs/trackers/foo.md", text).unwrap_err();
let re = err.downcast_ref::<RecoverableError>().unwrap();
assert!(re.message.contains("librarian-managed artifact"));
assert!(re.hint().unwrap().contains("artifact(action="));
}
#[test]
fn guard_passes_for_plain_markdown() {
let text = "# A plain markdown file\nNo frontmatter.\n";
assert!(guard_not_librarian_managed("docs/notes.md", text).is_ok());
}
}