///|
/// Checked baseline comparison retaining origin and complete source snapshots.
pub struct ArchiveDelta {
baseline : ReviewArchive
current : ReviewArchive
files : Array[FileDelta]
}
///|
/// Reject project/tool/rule/database differences and changed context on every
/// common path occurrence before applying the legacy exact multiset algorithm.
/// File additions/removals/reordering remain supported. Duplicate paths pair by
/// occurrence; no rename or semantic-equivalence inference is performed.
pub fn compare_archives(
baseline : ReviewArchive,
current : ReviewArchive,
) -> Result[ArchiveDelta, String] {
if baseline.origin.to_json() != current.origin.to_json() {
return Err(
"Incompatible archive origin: project, tool version, rule version and database must all match; regenerate both reviews with matching settings",
)
}
if current.origin.database != "postgresql-18" {
return Err("Archive comparison supports only postgresql-18")
}
if baseline.batch.initial_lock_timeout_ms !=
current.batch.initial_lock_timeout_ms {
return Err(
"Incompatible initial session timeout; regenerate both reviews with matching settings",
)
}
let paths : Map[String, Array[Migration]] = Map([])
for file in baseline.batch.files {
let input = file.migration
match paths.get(input.path) {
Some(queue) => queue.push(input)
None => paths[input.path] = [input]
}
}
let cursors : Map[String, Int32] = Map([])
for file in current.batch.files {
let input = file.migration
let cursor = cursors.get(input.path).unwrap_or(0)
if paths.get(input.path) is Some(queue) &&
queue.get(cursor) is Some(previous) {
if migration_context(previous) != migration_context(input) {
return Err(
"Incompatible execution/timeout context at \{input.path} occurrence \{cursor}; regenerate both reviews with matching settings",
)
}
}
cursors[input.path] = cursor + 1
}
let delta = match compare_batches(baseline.batch, current.batch) {
Ok(delta) => delta
Err(e) => return Err(e)
}
Ok({
baseline: { origin: baseline.origin, batch: delta.baseline, },
current: { origin: current.origin, batch: delta.current, },
files: delta.files,
})
}
///|
fn ArchiveDelta::legacy_delta(self : ArchiveDelta) -> BatchDelta {
{
baseline: self.baseline.batch,
current: self.current.batch,
files: self.files,
}
}
///|
pub fn ArchiveDelta::exit_code(self : ArchiveDelta) -> Int32 {
self.legacy_delta().exit_code()
}
///|
pub fn ArchiveDelta::to_text(self : ArchiveDelta) -> String {
"Checked archive origin: " +
self.current.origin.to_json().stringify() +
"\n" +
self.legacy_delta().to_text()
}
///|
pub fn ArchiveDelta::to_json(self : ArchiveDelta) -> Json {
let data = self.legacy_delta().to_json()
if data is Object(root) {
root["format_version"] = Json(2)
root["baseline"] = self.baseline.to_json()
root["current"] = self.current.to_json()
}
data
}