use super::*;
#[derive(Debug, Clone)]
pub(crate) struct SlugChange {
pub(crate) line: usize,
pub(crate) from: Option<String>,
pub(crate) to: Option<String>,
}
#[derive(Debug, Default)]
pub(crate) struct BindingFacts {
pub(crate) changes: Vec<SlugChange>,
pub(crate) first_slug_line: Option<usize>,
pub(crate) first_slug_utc: Option<String>,
pub(crate) plan_ref_lines: Vec<usize>,
}
impl BindingFacts {
pub(crate) fn no_slug(&self) -> bool {
self.first_slug_line.is_none()
}
}
fn line_mentions_plan_reference(line: &[u8]) -> bool {
static REF: std::sync::LazyLock<memchr::memmem::Finder<'static>> =
std::sync::LazyLock::new(|| memchr::memmem::Finder::new(b"plan_file_reference"));
REF.find(line).is_some()
}
pub(crate) fn binding_facts(path: &Path) -> Result<BindingFacts> {
let mut out = BindingFacts::default();
let Some(mmap) = mmap_bytes(path)? else {
return Ok(out);
};
let bytes: &[u8] = &mmap;
let mut current: Option<String> = None;
for (idx, line) in bytes.split(|&b| b == b'\n').enumerate() {
let line_no = idx + 1;
if line_mentions_plan_reference(line) && is_plan_reference(line) {
out.plan_ref_lines.push(line_no);
}
if !crate::parse::line_has_slug_key(line) {
continue;
}
let Some(f) = crate::parse::lineage_fields(line) else {
continue;
};
let Some(slug) = f.slug else {
continue;
};
if out.first_slug_line.is_none() {
out.first_slug_line = Some(line_no);
out.first_slug_utc = f.timestamp;
}
if current.as_deref() != Some(slug.as_str()) {
out.changes.push(SlugChange {
line: line_no,
from: current.clone(),
to: Some(slug.clone()),
});
current = Some(slug);
}
}
Ok(out)
}
fn is_plan_reference(line: &[u8]) -> bool {
let Ok(Some(rec)) = crate::parse::parse_line(line) else {
return false;
};
rec.attachment_value().is_some_and(|att| {
att.get("type").and_then(serde_json::Value::as_str) == Some("plan_file_reference")
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum SlugVsFile {
Before,
After,
Same,
Unknown(&'static str),
}
impl SlugVsFile {
pub(crate) fn token(self) -> &'static str {
match self {
SlugVsFile::Before => "before",
SlugVsFile::After => "after",
SlugVsFile::Same => "same",
SlugVsFile::Unknown(_) => "unknown",
}
}
pub(crate) fn reason(self) -> Option<&'static str> {
match self {
SlugVsFile::Unknown(r) => Some(r),
_ => None,
}
}
}
pub(crate) fn plan_file_created_ms(plan_file: &str) -> std::result::Result<i64, &'static str> {
let md = std::fs::metadata(plan_file).map_err(|_| "the plan file is not on disk")?;
let created = md
.created()
.map_err(|_| "this platform records no file birth time")?;
let since = created
.duration_since(std::time::UNIX_EPOCH)
.map_err(|_| "the file's birth time precedes the epoch")?;
i64::try_from(since.as_millis()).map_err(|_| "the file's birth time is out of range")
}
pub(crate) fn slug_vs_plan_file(first_slug_utc: Option<&str>, plan_file: &str) -> SlugVsFile {
let Some(raw) = first_slug_utc else {
return SlugVsFile::Unknown("no slug-carrying record has a timestamp");
};
let Some(slug_ms) = crate::timez::epoch_ms(raw) else {
return SlugVsFile::Unknown("the slug record's timestamp is unparseable");
};
match plan_file_created_ms(plan_file) {
Err(why) => SlugVsFile::Unknown(why),
Ok(file_ms) => match slug_ms.cmp(&file_ms) {
std::cmp::Ordering::Less => SlugVsFile::Before,
std::cmp::Ordering::Greater => SlugVsFile::After,
std::cmp::Ordering::Equal => SlugVsFile::Same,
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write as _;
static N: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
fn tmp(name: &str, body: &str) -> PathBuf {
let p = std::env::temp_dir().join(format!(
"csift-planfacts-{}-{}-{name}",
std::process::id(),
N.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
));
let mut f = std::fs::File::create(&p).unwrap();
f.write_all(body.as_bytes()).unwrap();
p
}
#[test]
fn an_empty_transcript_yields_the_default_facts() {
let p = tmp("empty.jsonl", "");
let f = binding_facts(&p).unwrap();
std::fs::remove_file(&p).ok();
assert!(f.changes.is_empty());
assert_eq!(f.first_slug_line, None);
assert!(f.plan_ref_lines.is_empty());
assert!(f.no_slug());
}
#[test]
fn a_torn_slug_line_neither_mints_nor_ends_a_run() {
let p = tmp(
"torn.jsonl",
concat!(
r#"{"type":"user","timestamp":"2026-06-07T05:00:00.000Z","slug":"quiet-harbor-relay"}"#,
"\n",
r#"{"type":"user","slug":"quiet-harbor-relay","message":{"role":"us"#,
"\n",
r#"{"type":"user","timestamp":"2026-06-07T05:02:00.000Z","slug":"quiet-harbor-relay"}"#,
"\n",
),
);
let f = binding_facts(&p).unwrap();
std::fs::remove_file(&p).ok();
assert_eq!(f.changes.len(), 1, "one mint, no spurious second change");
assert_eq!(f.changes[0].line, 1);
assert_eq!(f.first_slug_line, Some(1));
}
#[test]
fn the_plan_reference_needle_is_selective_on_its_own() {
assert!(line_mentions_plan_reference(
br#"{"attachment":{"type":"plan_file_reference"}}"#
));
assert!(
!line_mentions_plan_reference(
br#"{"type":"user","message":{"role":"user","content":"hi"}}"#
),
"an ordinary record must be skipped before the parse"
);
assert!(
!line_mentions_plan_reference(br#"{"attachment":{"type":"plan_mode"}}"#),
"the OTHER plan attachment is not this one"
);
}
#[test]
fn a_torn_line_carrying_the_attachment_literal_is_not_a_plan_reference() {
let p = tmp(
"tornref.jsonl",
"{\"type\":\"attachment\",\"attachment\":{\"type\":\"plan_file_reference\",\"conte\n",
);
let f = binding_facts(&p).unwrap();
std::fs::remove_file(&p).ok();
assert!(f.plan_ref_lines.is_empty());
}
#[test]
fn an_unparseable_slug_timestamp_reads_unknown_with_its_reason() {
let v = slug_vs_plan_file(Some("not-a-time"), "/nonexistent/plan.md");
assert_eq!(v.token(), "unknown");
assert_eq!(
v.reason(),
Some("the slug record's timestamp is unparseable")
);
}
#[test]
fn an_equal_instant_reads_same() {
let p = tmp("same.md", "# the plan\n");
let path = p.to_str().unwrap().to_string();
match plan_file_created_ms(&path) {
Ok(created) => {
let iso = jiff::Timestamp::from_millisecond(created)
.expect("an in-range instant")
.to_string();
let v = slug_vs_plan_file(Some(&iso), &path);
std::fs::remove_file(&p).ok();
assert_eq!(v, SlugVsFile::Same, "iso {iso} vs created {created}");
assert_eq!(v.token(), "same");
assert_eq!(v.reason(), None);
}
Err(why) => {
let v = slug_vs_plan_file(Some("2020-06-07T05:00:00.000Z"), &path);
std::fs::remove_file(&p).ok();
assert_eq!(why, "this platform records no file birth time");
assert_eq!(v, SlugVsFile::Unknown(why));
assert_eq!(v.token(), "unknown");
assert_eq!(v.reason(), Some(why));
}
}
}
}