mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-04 16:56:59 +01:00
fix(fuse,core): key conflict detection on revision id, stop transient-name seals (B69, B70)
B69 — spurious `(sync-conflict)` copies came from `(mtime, size)` being used as a revision identity. The server re-stamps a sealed revision with its own commit time, so the drain diverted a write into a conflict copy of its own base; and `plan_file` classified a no-baseline (local, remote) pair as `Conflict`, forking every pre-existing file on first reconcile. - `Baseline` carries `revision_id` (from the SDK's new `active_revision_id`), captured at write-open and preserved across supersede/rebaseline. `revision_changed` trusts the id and only falls back to `(mtime, size)` for old sidecars. - Planner gains `FilePlan::AdoptBaseline`: equal-size no-baseline pairs are recorded, not conflicted. Divergent sizes stay a real conflict. - New `sweep.rs` (`pdfs-conflict-sweep`, 5-min cadence) removes conflict copies proven identical by size + `content_sha1` and surfaces divergent ones once as an `ActivityKind::Conflict` entry. Never removes what it cannot prove. B70 — browsers downloading into an on-demand mount had their in-flight temps sealed as canonical revisions, exiling the finished file to a conflict copy. `syncignore::is_transient_name` now recognises download/scratch temps, and the on-demand `release`/`rename` paths hold them (`set_create_hold`) instead of sealing until the name is finalized. Workspace deps bumped to proton-sdk/proton-drive-rs 0.2.2 (registry, no patch). Live validation against a real account still pending for both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V8P42asymU158CPnhjRwri
This commit is contained in:
1 parent
6df757006a
commit
bca0fe34bc
19 files changed
+978
-115
No files matched your search
@@ -150,15 +150,23 @@ pub struct StagedWrite {
|
||||
pub based_on: Option<Baseline>,
|
||||
}
|
||||
|
||||
/// The identity of a remote revision, as far as we can observe it: a file whose
|
||||
/// size and mtime both still match the ones a queued change was made against has
|
||||
/// not been rewritten by anyone else in the meantime.
|
||||
/// The identity of a remote revision, as far as we can observe it.
|
||||
///
|
||||
/// `revision_id` is the authoritative identity when present: the server assigns a
|
||||
/// fresh id to every sealed revision, so an unchanged id proves no one rewrote
|
||||
/// the file — even when the server re-stamped its `mtime` on the *same* revision,
|
||||
/// which is the drift that used to cut spurious conflict copies (B16/B25).
|
||||
/// `mtime`/`size` remain the fallback for a baseline recorded before the id was
|
||||
/// observable, or a node read through a surface that does not carry it.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Baseline {
|
||||
pub mtime: i64,
|
||||
pub size: u64,
|
||||
#[serde(default)]
|
||||
pub hash: Option<String>,
|
||||
/// Server revision id this change was made against (`None` if unknown).
|
||||
#[serde(default)]
|
||||
pub revision_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Content cache rooted at a directory, with a sibling pin-registry file.
|
||||
@@ -1873,6 +1881,7 @@ mod tests {
|
||||
mtime: 100,
|
||||
size: 40,
|
||||
hash: None,
|
||||
revision_id: None,
|
||||
}),
|
||||
};
|
||||
let staged = c.stage_write(&meta, &scratch).unwrap();
|
||||
|
||||
Reference in new issue
Block a user