///|
fn merge_audit(index : DatasetIndex, path : String) -> AuditEntry? {
if index.file_positions.contains(path) {
Some(index.audit([path]).entries[0])
} else {
None
}
}
///|
fn merge_resolution(entry : AuditEntry?) -> ResolvedMetadata? {
match entry {
Some(e) => e.result
None => None
}
}
///|
fn merge_metadata(result : ResolvedMetadata?) -> Json? {
result.map(r => r.report_value())
}
///|
fn merge_field(result : ResolvedMetadata?, key : String) -> Json? {
match result {
Some(r) => r.values.get(key)
None => None
}
}
///|
fn merge_check_scans(
base : DatasetIndex,
left : DatasetIndex,
right : DatasetIndex,
candidate : DatasetIndex,
paths : Array[String],
conflicts : Array[MergeConflict],
resolution~ : MergeResolution?,
) -> Unit raise TraceError {
for path in paths {
let be = merge_audit(base, path)
let le = merge_audit(left, path)
let re = merge_audit(right, path)
let ce = merge_audit(candidate, path)
let prior_count = conflicts.length()
for
(branch, entry) in [
("base", be),
("left", le),
("right", re),
("merged", ce),
] {
if entry is Some(e) && e.error is Some(d) {
merge_conflict(conflicts, UnresolvedMetadata, path, branch~, diagnostics=[
d,
])
}
}
if conflicts.length() != prior_count {
continue
}
let b = merge_resolution(be)
let l = merge_resolution(le)
let r = merge_resolution(re)
let c = merge_resolution(ce)
if c is None {
// A removed scan must not silently erase the other side's provenance or
// effective edit. Even an empty applied source is observable evidence.
if !(resolution is Some(plan) && plan.scan_at(path) is Some(_)) &&
b is Some(_) &&
(
(l is Some(_) && !merge_equal(merge_metadata(b), merge_metadata(l))) ||
(r is Some(_) && !merge_equal(merge_metadata(b), merge_metadata(r)))
) {
merge_conflict(
conflicts,
ScanDeleteEdit,
path,
base?=merge_metadata(b),
left?=merge_metadata(l),
right?=merge_metadata(r),
)
}
continue
}
let keys : Map[String, Bool] = Map([])
for result in [b, l, r, c] {
if result is Some(result) {
for key in result.keys() {
keys[key] = true
}
}
}
for key in sorted_keys(keys) {
let bv = merge_field(b, key)
let lv = merge_field(l, key)
let rv = merge_field(r, key)
let cv = merge_field(c, key)
// Assertions are checked against the resolved candidate before entering
// this pass. They authorize exactly this effective field, never a whole
// scan, another field, or any unresolved historical input.
if resolution is Some(plan) && plan.has_effective(path, key) {
continue
}
// For a newly introduced scan, only snapshots which actually contain it
// establish intent. A change in the other branch may alter its inherited
// values; require review rather than guessing that intent.
let expected = if l is None {
rv
} else if r is None {
lv
} else if merge_equal(lv, rv) {
lv
} else if merge_equal(bv, lv) {
rv
} else if merge_equal(bv, rv) {
lv
} else {
merge_conflict(
conflicts,
EffectiveDiverged,
path,
key~,
base?=bv,
left?=lv,
right?=rv,
merged?=cv,
)
continue
}
if !merge_equal(expected, cv) {
merge_conflict(
conflicts,
InheritanceShadow,
path,
key~,
base?=bv,
left?=lv,
right?=rv,
merged?=cv,
)
}
}
}
}