1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Dead-code tolerated module-wide: this source-provenance classifier lands
// ahead of the hit/pack serializers that will attach it (and the field-policy
// inclusion in lib.rs). Downstream bead .7.4 (moved-workspace and
// stale-source fixture suite) consumes these types.
#![allow(dead_code)]
//! Source existence and archive provenance for hits and packs (bead
//! cass-fleet-resilience-20260608-uojcg.7.2).
//!
//! The 2026-06-08 report found stale `source_path` values: a hit's indexed
//! path may no longer back a live file, yet agents overtrust it. A result
//! must say whether its `source_path` currently exists, whether the content
//! is archive-only (backed by the DB, not a file), which source produced it,
//! and whether a path mapping was applied — so an agent knows whether it can
//! open the file or must read from the archive.
//!
//! This module derives that provenance from explicit signals, so the five
//! cases the report calls out — a local existing file, a deleted/moved file,
//! a remote mirror, a source-pruned archive row, and a path-mapped row — are
//! unit-testable without a filesystem or DB. The hit/pack struct fields and
//! field-policy (minimal/summary/custom) inclusion are the integration step;
//! this is the pure, reusable core. All enums serialize as snake_case and
//! the projected fields are redaction-friendly (ids and host labels only).
use serde::{Deserialize, Serialize};
/// The dominant provenance story for a result, strongest-evidence first.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum ProvenanceKind {
/// A local `source_path` that currently exists on disk.
LocalPresent,
/// A local `source_path` recorded in the index but no longer on disk
/// (deleted or moved); content survives only in the archive.
LocalMissing,
/// Backed by a remote source/mirror identified by `origin_host`.
RemoteMirror,
/// The originating source was pruned; only the archive DB row remains.
ArchiveOnlyPruned,
/// A path mapping was applied to resolve the source_path (e.g.
/// macOS↔Linux or a relocated checkout).
PathMapped,
}
/// Signals a hit/pack carries about its origin. The serializer populates
/// these from the row + a (cheap, cached) existence probe.
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ProvenanceSignals {
/// The indexed source path, if any.
pub source_path: Option<String>,
/// Whether `source_path` (after any mapping) currently exists.
pub file_exists: bool,
/// The source id that produced the row; `None` when the source was
/// pruned.
pub source_id: Option<i64>,
/// Origin host label for remote sources; `None` for local.
pub origin_host: Option<String>,
/// Whether the source is local (vs a remote mirror).
pub is_local_source: bool,
/// Whether the content is present as an archive DB row.
pub archive_row_present: bool,
/// Whether a path mapping was applied to resolve `source_path`.
pub path_mapping_applied: bool,
}
impl ProvenanceSignals {
/// Whether a live (non-archive) source still backs this row.
fn has_live_source(&self) -> bool {
self.source_path.is_some() && self.source_id.is_some()
}
/// Derive the provenance projection a hit/pack should expose.
pub(crate) fn provenance(&self) -> SourceProvenance {
// Pruned source: only the archive row remains. Dominates, because
// there is no live backing to open regardless of other flags.
let kind = if self.archive_row_present && !self.has_live_source() {
ProvenanceKind::ArchiveOnlyPruned
} else if self.path_mapping_applied {
ProvenanceKind::PathMapped
} else if !self.is_local_source {
ProvenanceKind::RemoteMirror
} else if self.file_exists {
ProvenanceKind::LocalPresent
} else {
ProvenanceKind::LocalMissing
};
// The live source exists when a file backs it now (mapped path
// included); a pruned/archive-only row never has a live source.
let source_exists = match kind {
ProvenanceKind::ArchiveOnlyPruned => false,
_ => self.file_exists,
};
// Archive-only when the content is in the archive but no live file
// backs it.
let archive_only = self.archive_row_present && !source_exists;
SourceProvenance {
source_exists,
archive_only,
source_id: self.source_id,
origin_host: self.origin_host.clone(),
path_mapped: self.path_mapping_applied,
kind,
}
}
}
/// The redaction-friendly provenance fields attached to a hit/pack.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct SourceProvenance {
/// Whether the `source_path` currently backs a live file.
pub source_exists: bool,
/// Whether the content is available only from the archive DB.
pub archive_only: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_id: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub origin_host: Option<String>,
/// Whether a path mapping was applied to resolve the source.
pub path_mapped: bool,
pub kind: ProvenanceKind,
}
impl SourceProvenance {
/// Whether an agent can open the result's file directly (vs needing to
/// read it from the archive via `cass view`).
pub(crate) fn is_openable_file(&self) -> bool {
self.source_exists
}
}
#[cfg(test)]
mod tests {
use super::*;
fn local_present() -> ProvenanceSignals {
ProvenanceSignals {
source_path: Some("/home/u/proj/session.jsonl".to_string()),
file_exists: true,
source_id: Some(7),
origin_host: None,
is_local_source: true,
archive_row_present: true,
path_mapping_applied: false,
}
}
#[test]
fn enums_serialize_as_snake_case() {
assert_eq!(
serde_json::to_string(&ProvenanceKind::ArchiveOnlyPruned).unwrap(),
"\"archive_only_pruned\""
);
}
#[test]
fn local_existing_file_is_openable_and_not_archive_only() {
let p = local_present().provenance();
assert_eq!(p.kind, ProvenanceKind::LocalPresent);
assert!(p.source_exists);
assert!(!p.archive_only);
assert!(p.is_openable_file());
assert_eq!(p.source_id, Some(7));
}
#[test]
fn deleted_or_moved_file_is_archive_only_and_not_openable() {
let mut s = local_present();
s.file_exists = false; // file gone, but still a known source + archive row
let p = s.provenance();
assert_eq!(p.kind, ProvenanceKind::LocalMissing);
assert!(!p.source_exists);
assert!(p.archive_only, "content survives only in the archive");
assert!(!p.is_openable_file());
}
#[test]
fn remote_mirror_is_classified_by_origin_host() {
let s = ProvenanceSignals {
source_path: Some("/srv/data/session.jsonl".to_string()),
file_exists: true,
source_id: Some(12),
origin_host: Some("mac-mini-old".to_string()),
is_local_source: false,
archive_row_present: true,
path_mapping_applied: false,
};
let p = s.provenance();
assert_eq!(p.kind, ProvenanceKind::RemoteMirror);
assert_eq!(p.origin_host.as_deref(), Some("mac-mini-old"));
assert!(p.source_exists);
assert!(!p.archive_only);
}
#[test]
fn source_pruned_archive_row_is_archive_only() {
let s = ProvenanceSignals {
source_path: None, // source pruned
file_exists: false,
source_id: None,
origin_host: None,
is_local_source: true,
archive_row_present: true,
path_mapping_applied: false,
};
let p = s.provenance();
assert_eq!(p.kind, ProvenanceKind::ArchiveOnlyPruned);
assert!(!p.source_exists);
assert!(p.archive_only);
assert!(p.source_id.is_none());
}
#[test]
fn path_mapped_row_records_the_mapping() {
let mut s = local_present();
s.path_mapping_applied = true;
let p = s.provenance();
assert_eq!(p.kind, ProvenanceKind::PathMapped);
assert!(p.path_mapped);
// A successfully mapped path that exists is still openable.
assert!(p.source_exists);
}
#[test]
fn pruned_dominates_path_mapping() {
// Even if a mapping was attempted, a pruned source with only an
// archive row is archive-only (nothing live to open).
let s = ProvenanceSignals {
source_path: None,
file_exists: false,
source_id: None,
origin_host: None,
is_local_source: true,
archive_row_present: true,
path_mapping_applied: true,
};
assert_eq!(s.provenance().kind, ProvenanceKind::ArchiveOnlyPruned);
}
#[test]
fn provenance_round_trips_through_json() {
let p = local_present().provenance();
let json = serde_json::to_string(&p).unwrap();
assert!(json.contains("\"source_exists\":true"));
assert!(json.contains("\"kind\":\"local_present\""));
assert!(json.contains("\"path_mapped\":false"));
let parsed: SourceProvenance = serde_json::from_str(&json).unwrap();
assert_eq!(parsed, p);
}
}