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
//! 0.8.12 Slice 20 (OPP-2, ADR-0.8.12 §2.2) — Consolidation value-test ($0).
//!
//! Pre-registration: `dev/design/0.8.12-coverage-probe-and-value-test.md` §B. This is the `$0`,
//! LLM-free, deterministic mechanism measurement that feeds the SHIP-ON / STAY-OFF decision recorded
//! in `dev/plans/runs/consolidation-value-test-results.md`.
//!
//! Independent variable: consolidation OFF (accumulate all facts) vs ON (apply the recency verdict via
//! the deterministic stub harness). Dependent variables, measured on edge-FTS retrieval:
//! * PRECISION — for a query term that matches BOTH the stale and the updated fact of an axis, the
//! fraction of returned edges that are the CURRENT (updated) fact. Stale contradictions returned =
//! precision loss.
//! * LOSSINESS — the false-supersede rate: still-valid (updated) facts wrongly hidden. Must be 0.
//!
//! FOOTPRINT / NO-EGRESS (R-CON-3): the harness is the local deterministic recency stub; no network,
//! no LLM, no randomness. The library query path stays CPU-only.
use fathomdb_engine::{ConsolidateAxis, Engine, PreparedWrite};
use rusqlite::Connection;
use tempfile::TempDir;
use fathomdb_schema::SQLITE_SUFFIX;
fn harness_cmd() -> Vec<String> {
let script = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/slice15_consolidate/stub_consolidate_harness.py");
assert!(script.exists(), "consolidate stub harness must exist at {}", script.display());
vec!["python3".to_string(), script.to_string_lossy().to_string()]
}
#[allow(clippy::too_many_arguments)]
/// TC-33: `t_valid` is INTEGER epoch seconds (UTC), not ISO-8601.
fn fact_edge(from: &str, to: &str, logical_id: &str, body: &str, t_valid: i64) -> PreparedWrite {
PreparedWrite::Edge {
kind: "works_for".to_string(),
from: from.to_string(),
to: to.to_string(),
source_id: fathomdb_engine::SourceId::new(format!("doc-{logical_id}"))
.expect("test source id"),
logical_id: Some(logical_id.to_string()),
body: Some(body.to_string()),
t_valid: Some(t_valid),
t_invalid: None,
confidence: Some(0.9),
extractor_model_id: Some("stub-extractor-v1".to_string()),
temporal_fallback: None,
}
}
/// N axes, each: a STALE fact (older t_valid) + an UPDATED fact (newer t_valid). Both bodies share the
/// query term "works" so an unconsolidated edge-FTS query returns BOTH (the stale contradiction leaks).
const SUBJECTS: &[(&str, &str, &str)] = &[
// (subject, stale_org, updated_org)
("bob", "acme", "globex"),
("cara", "initech", "hooli"),
("dan", "umbrella", "wayne"),
("eve", "stark", "wonka"),
("finn", "cyberdyne", "tyrell"),
("gwen", "soylent", "aperture"),
];
fn seed(engine: &Engine) {
let mut writes = Vec::new();
for (subj, stale, updated) in SUBJECTS {
writes.push(fact_edge(
subj,
stale,
&format!("edge-{subj}-stale"),
&format!("{subj} works for {stale}"),
1_546_300_800, // 2019-01-01T00:00:00Z
));
writes.push(fact_edge(
subj,
updated,
&format!("edge-{subj}-updated"),
&format!("{subj} works for {updated}"),
1_640_995_200, // 2022-01-01T00:00:00Z
));
}
engine.write(&writes).expect("seed competing edges");
}
/// Count edge-FTS hits for a term, split into (updated_hits, stale_hits) by matching the logical_id
/// suffix via a join back to canonical_edges.
fn fts_hits(conn: &Connection, term: &str) -> (u64, u64) {
// search_index_edges.write_cursor == canonical_edges.write_cursor. FTS5 MATCH requires the table
// name (not an alias), so match in a subquery and join back by write_cursor.
let count = |suffix: &str| -> u64 {
conn.query_row(
"SELECT COUNT(*) FROM canonical_edges e \
WHERE e.logical_id LIKE ?2 \
AND e.write_cursor IN \
(SELECT write_cursor FROM search_index_edges WHERE search_index_edges MATCH ?1)",
rusqlite::params![term, suffix],
|r| r.get(0),
)
.unwrap()
};
(count("%-updated"), count("%-stale"))
}
#[test]
fn consolidation_removes_stale_contradictions_without_lossiness() {
let dir = TempDir::new().unwrap();
let path = dir.path().join(format!("value{SQLITE_SUFFIX}"));
let opened = Engine::open_without_embedder_for_test(&path).expect("open");
seed(&opened.engine);
let conn = Connection::open(&path).unwrap();
// SCOPE (honest): this measures ACTIVE edge-FTS retrieval IMMEDIATELY after consolidation. It does
// NOT claim durability across an operator `rebuild_projections()` — the Slice-15 fix-2 KNOWN
// LIMITATION means a rebuild re-materialises an invalidated (non-superseded) edge's FTS/vec shadows.
// That fragility is a NAMED blocker-before-default-ON in `consolidation-value-test-results.md` and is
// one reason the value verdict is STAY-OFF. (rebuild_projections is operator-feature-gated and not
// reachable from this default-feature test, so the rebuild path is asserted by code-path analysis +
// the elevated blocker, not exercised here.)
// --- Consolidation OFF (baseline): both stale and updated facts are retrievable. ---
let (off_updated, off_stale) = fts_hits(&conn, "works");
let n = SUBJECTS.len() as u64;
assert_eq!(off_updated, n, "every updated fact retrievable OFF");
assert_eq!(
off_stale, n,
"every stale contradiction ALSO retrievable OFF (the precision problem)"
);
let off_precision = off_updated as f64 / (off_updated + off_stale) as f64;
// --- Consolidation ON: apply the recency verdict for every axis. ---
let cmd = harness_cmd();
let cmd_refs: Vec<&str> = cmd.iter().map(|s| s.as_str()).collect();
let axes: Vec<ConsolidateAxis> = SUBJECTS
.iter()
.map(|(subj, _, _)| ConsolidateAxis {
subject_logical_id: subj.to_string(),
relation: "works_for".to_string(),
})
.collect();
let receipt = opened.engine.consolidate_with_provider(&cmd_refs, &axes).expect("consolidate");
assert_eq!(receipt.edges_invalidated, n, "one stale fact invalidated per axis");
let (on_updated, on_stale) = fts_hits(&conn, "works");
let on_precision = on_updated as f64 / (on_updated + on_stale).max(1) as f64;
// Mechanism: stale contradictions are hidden from retrieval (precision → 1.0) ...
assert_eq!(on_stale, 0, "ON: every stale contradiction is hidden from edge-FTS retrieval");
// ... with ZERO lossiness: every still-valid updated fact is retained.
assert_eq!(
on_updated, n,
"ON: no false-supersede — all updated facts retained (lossiness = 0)"
);
// Print the measured value for the results doc (visible with `cargo test -- --nocapture`).
println!(
"VALUE-TEST n_axes={n} precision_off={off_precision:.3} precision_on={on_precision:.3} \
precision_lift={:.3} stale_off={off_stale} stale_on={on_stale} lossiness={} ",
on_precision - off_precision,
n - on_updated
);
assert!(on_precision > off_precision, "consolidation must lift retrieval precision");
}