Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 71 additions & 6 deletions src-tauri/src/pyramid/stale_helpers_upper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3704,12 +3704,7 @@ async fn apply_supersession_manifest(
}
};
let conn = super::db::open_pyramid_connection(Path::new(&db))?;
conn.execute(
"UPDATE pyramid_file_hashes
SET hash = ?1, last_ingested_at = datetime('now')
WHERE slug = ?2 AND file_path = ?3",
rusqlite::params![hash, slug_owned, path_owned],
)?;
super::db::set_file_content_hash(&conn, &slug_owned, &path_owned, &hash)?;
Ok(())
})
.await
Expand Down Expand Up @@ -5279,6 +5274,8 @@ mod tests {
ChangeManifest, ChildSwap, ContentUpdates, DecisionOp, ManifestValidationError, TermOp,
TopicOp,
};
use crate::pyramid::understanding_rebuild::rebuild_pyramid_node_metadata_from_store;
use crate::pyramid::understanding_store::understanding_root_from_conn;
use rusqlite::{params, Connection};
use std::sync::Arc;
use tempfile::NamedTempFile;
Expand Down Expand Up @@ -6637,6 +6634,25 @@ mod tests {
);

let db_path_str = db_file.path().to_str().unwrap().to_string();
{
let conn_seed_ids = open_pyramid_db(db_file.path()).expect("reopen db for ids seed");
conn_seed_ids
.execute(
"UPDATE pyramid_file_hashes
SET node_ids = ?3
WHERE slug = ?1 AND file_path = ?2",
params![
slug,
file_path_str,
serde_json::to_string(&vec![
"L0-targeted".to_string(),
node_id.to_string()
])
.unwrap(),
],
)
.expect("seed multi-node file hash references");
}

// Load the node context against the post-edit file. This verifies
// load_supersession_node_context pulls the source file for L0
Expand Down Expand Up @@ -6741,6 +6757,55 @@ mod tests {
stored_hash, post_edit_hash,
"pyramid_file_hashes.hash should be rewritten to the post-edit hash so the watcher stops re-firing"
);
let stored_node_ids: String = conn_verify
.query_row(
"SELECT node_ids FROM pyramid_file_hashes WHERE slug = ?1 AND file_path = ?2",
params![slug, file_path_str],
|row| row.get(0),
)
.expect("load post-apply node_ids");
let parsed_node_ids: Vec<String> =
serde_json::from_str(&stored_node_ids).expect("node_ids json");
assert_eq!(
parsed_node_ids,
vec!["L0-targeted".to_string(), node_id.to_string()],
"change-manifest hash rewrite must preserve existing file_hash node_ids"
);

let root = understanding_root_from_conn(&conn_verify).expect("test DB has store root");
let mirrored_manifest = crate::pyramid::understanding_store::read_all_node_metadata_records(
&root,
)
.expect("read node-metadata log")
.into_iter()
.any(|rec| {
rec.kind == "change_manifest"
&& rec.slug == slug
&& rec.key == format!("{node_id}|2")
&& rec.op == "upsert"
});
assert!(
mirrored_manifest,
"apply path must mirror the change-manifest row before rebuild"
);
crate::pyramid::db::backfill_node_metadata_to_store(&conn_verify)
.expect("backfill fixture metadata so rebuild gate can run");
conn_verify
.execute("DELETE FROM pyramid_change_manifests", [])
.expect("clear change-manifest projection");
let rebuilt =
rebuild_pyramid_node_metadata_from_store(&root, &conn_verify).expect("rebuild metadata");
assert!(
rebuilt > 0,
"node-metadata rebuild should restore mirrored change-manifest rows"
);
let manifests = get_change_manifests_for_node(&conn_verify, slug, node_id)
.expect("load rebuilt change manifests");
assert_eq!(manifests.len(), 1, "change manifest should rebuild from store");
assert_eq!(
manifests[0].build_version, 2,
"rebuilt manifest should preserve post-apply build_version"
);
}

/// Fix pass test 2: manifest-generation failure must NOT fall back to
Expand Down