Repository navigation
Conversation
Two classes of local-only file are currently uploaded and replicated to every machine. .lock: Claude Code writes a zero-byte lock per task directory (tasks/<id>/.lock). A lock represents a process holding a resource on one machine; replicated elsewhere it is indistinguishable from a lock genuinely held there, and it long outlives the process that made it. Observed: 12 of them, the oldest about four weeks old, syncing across three machines. .conflict.<timestamp>: handleConflict writes the remote copy next to the original, which is inside a synced directory, so the recovery artifact is itself uploaded. Each replica can then be re-detected on another machine and spawn further artifacts. Observed: 92 accumulated in about a week, including five copies of one snapshot minted by successive pulls. Both are now excluded unconditionally, ahead of the user's exclude patterns, because neither has any meaning on another machine under any configuration. The .conflict pattern is anchored on the exact <yyyymmdd>-<hhmmss> format this tool generates rather than matching .conflict. loosely. That matters: an already-tracked file becoming excluded is reported as a deletion and pruned from the bucket on the next push, so a loose pattern would silently delete a user file named e.g. notes.conflict.md from remote storage. Tests pin both directions. Migration note for existing users: the first push after upgrading prunes any already-uploaded locks and conflict artifacts from the bucket. Local copies are untouched. Fixes tawanorg#71 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
|
Folding this into #77 rather than keeping it separate. The remaining fixes turned out not to be independent — the diverged-transcript merge builds directly on #77's resolver, and both it and the desktop-records feature need the same Closing in favour of #77. Happy to re-split any subset if you would rather review them separately. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #71. Independent of #77 — different function, no shared symbols, either can merge first.
The problem
Two classes of local-only file are uploaded and replicated to every machine.
.lock— Claude Code writes a zero-byte lock per task directory (tasks/<id>/.lock). A lock represents a process holding a resource on one machine. Replicated elsewhere it carries no pid, no hostname, nothing: it is indistinguishable from a lock genuinely held there, and it outlives the process that created it by weeks. Across three synced machines we had 12 of them in the bucket, the oldest about four weeks old..conflict.<timestamp>—handleConflictwrites the remote copy next to the original:That path is inside a synced directory, so the recovery artifact is itself uploaded. Each replica can then be re-detected on another machine and produce further artifacts. We accumulated 92 in about a week, including five copies of the same snapshot for one file, minted by successive pulls.
The fix
Unconditional and ahead of the user's patterns, because neither file has meaning on another machine under any configuration. This also sidesteps the globstar matching in #43 — no pattern needs to be written or matched.
Why the regex is anchored
It matches only the
<yyyymmdd>-<hhmmss>formathandleConflictwrites, not any name containing.conflict..This is the load-bearing detail. Excluding a path that is already tracked in state makes the next push report it as a deletion and prune it from the bucket. A loose
*.conflict.*would therefore remotely delete a user file callednotes.conflict.md. The tests pin both directions:notes.conflict.md,my.conflict.2026.txt, a truncated timestamp,package.lock, and.lockfileall stay; the real artifacts go.Migration note
The first push after upgrading prunes already-uploaded locks and conflict artifacts from the bucket. Local copies are untouched — this is cleanup, not data loss, but it is worth a line in release notes since the remote objects do disappear. In our fleet it removed 12 lock files and the stale conflict artifacts in one push.
Scope and tests
1 file changed in
internal/sync/, +18 lines, plus a new test file.go vet ./...andgo test ./...green on Linux/ext4.TestIsExcludedSkipsPerMachineDebris— both classes excluded; 8 near-miss names explicitly keptTestIsExcludedStillHonorsUserPatterns— userexcludeconfig still appliesTestPushSkipsDebrisFiles— end-to-end: only the transcript reaches the bucket, and the local.lockis still on disk afterwardsHappy to adjust the naming or fold the two classes into separate predicates if you prefer.