///|
/// Compare revision content while ignoring the local sequence field, which
/// is derived from append position. A common prefix must agree in every
/// semantically relevant field, including tombstones and valid endpoints.
fn same_revision_claim(left : Revision, right : Revision) -> Bool {
left.key == right.key &&
left.valid.start == right.valid.start &&
left.valid.end == right.valid.end &&
left.known_at == right.known_at &&
left.value == right.value
}
///|
/// Reconcile a full remote archive with local state. If one log is an exact
/// prefix of the other, return the longer log as a detached local ledger.
/// Divergent shared history is rejected at the first differing sequence.
/// This operation provides content consistency, not cryptographic integrity;
/// transport authentication and durable transaction ordering belong to callers.
pub fn Ledger::reconcile(
self : Ledger,
remote : Ledger,
) -> Ledger raise TemporalError {
let common = if self.revisions.length() < remote.revisions.length() {
self.revisions.length()
} else {
remote.revisions.length()
}
for index = 0; index < common; index = index + 1 {
if !same_revision_claim(self.revisions[index], remote.revisions[index]) {
raise DivergentHistory(index~)
}
}
let winner = if self.revisions.length() >= remote.revisions.length() {
self
} else {
remote
}
if winner.revisions.length() > self.maximum {
raise TooManyRevisions(maximum=self.maximum)
}
let revisions = winner.revisions.copy()
{
revisions,
index: build_index(revisions),
latest_time: winner.latest_time,
maximum: self.maximum,
}
}
///|
/// Return the first divergent position if the archives disagree, or `None`
/// when either archive is a prefix of the other.
pub fn Ledger::first_divergence(self : Ledger, other : Ledger) -> Int32? {
let common = if self.revisions.length() < other.revisions.length() {
self.revisions.length()
} else {
other.revisions.length()
}
for index = 0; index < common; index = index + 1 {
if !same_revision_claim(self.revisions[index], other.revisions[index]) {
return Some(index)
}
}
None
}
///|
/// Whether this ledger's entire sequence is an exact prefix of `other`.
pub fn Ledger::is_prefix_of(self : Ledger, other : Ledger) -> Bool {
self.revisions.length() <= other.revisions.length() &&
self.first_divergence(other) is None
}