Verify convergence with the order-invariant `SetId`: each applied view's local **effective** set-id must equal the remote's, taken from the server view inventory (`GET /refs/views`), which the server folds over each view's effective (own ∪ ancestors) change set. Comparing against the server-computed value — an independent source — catches a dropped or corrupt change that counts/merkle-order alone
(
&self,
repo: &Repository,
remote: &HttpRemote,
views: &HashSet<String>,
)
| 395 | /// corrupt change that counts/merkle-order alone would miss, and is correct |
| 396 | /// for drafts (whose effective set differs from their own set). |
| 397 | async fn verify_convergence( |
| 398 | &self, |
| 399 | repo: &Repository, |
| 400 | remote: &HttpRemote, |
| 401 | views: &HashSet<String>, |
| 402 | ) { |
| 403 | let inventory = match remote.list_view_refs().await { |
| 404 | Ok(inv) => inv, |
| 405 | // Inventory unavailable — skip verification rather than fail the clone. |
| 406 | Err(_) => return, |
| 407 | }; |
| 408 | let remote_set: HashMap<String, String> = inventory |
| 409 | .into_iter() |
| 410 | .filter_map(|v| v.set_id.map(|s| (v.name, s))) |
| 411 | .collect(); |
| 412 | |
| 413 | let mut verified = 0usize; |
| 414 | let mut mismatched = 0usize; |
| 415 | for view in views { |
| 416 | let Some(expected) = remote_set.get(view) else { |
| 417 | continue; // remote reported no set-id for this view |
| 418 | }; |
| 419 | match repo.view_set_id(view) { |
| 420 | Ok(local) if &local.to_base32() == expected => verified += 1, |
| 421 | Ok(local) => { |
| 422 | mismatched += 1; |
| 423 | print_warning(&format!( |
| 424 | "Set-id mismatch for view '{}': local {} != remote {}. \ |
| 425 | The clone may be incomplete or divergent.", |
| 426 | view, |
| 427 | local.to_base32(), |
| 428 | expected |
| 429 | )); |
| 430 | } |
| 431 | Err(e) => print_warning(&format!( |
| 432 | "Could not compute local set-id for view '{}': {}", |
| 433 | view, e |
| 434 | )), |
| 435 | } |
| 436 | } |
| 437 | if mismatched == 0 && verified > 0 { |
| 438 | print_success("Verified: cloned view set-ids match the remote (convergent)"); |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | /// Index a pack's change objects into `base32 hash → bytes` for local save. |
| 443 | fn change_objects_from_pack(pack: &SyncPack) -> HashMap<String, Vec<u8>> { |
no test coverage detected