Skip to content

CS-11062: protect local edits in boxel realm watch start#4844

Open
FadhlanR wants to merge 1 commit into
mainfrom
cs-11062-make-realm-watch-avoid-overwriting-local-changes
Open

CS-11062: protect local edits in boxel realm watch start#4844
FadhlanR wants to merge 1 commit into
mainfrom
cs-11062-make-realm-watch-avoid-overwriting-local-changes

Conversation

@FadhlanR
Copy link
Copy Markdown
Contributor

@FadhlanR FadhlanR commented May 15, 2026

Summary

  • boxel realm watch start no longer silently overwrites local edits. When the local copy of a remotely-changed file diverges from .boxel-sync.json, the watcher skips the download (or unlink), logs ⚠ skipped <file>: local diverges from sync manifest …, and keeps polling.
  • A new --overwrite-local flag restores the previous unconditional mirror behavior.
  • Skipped files keep their old lastKnownMtimes so the warning re-fires every poll until the user reconciles via boxel realm sync … (e.g. --prefer-newest) or reruns watch with --overwrite-local.

How

  • Divergence gate lives in RealmWatcher.flushPending so both first-tick (tickAll) and steady-state polls hit one code path. Per-flush, the manifest is loaded once and reused across all checks in that flush.
  • FlushResult gains skipped: string[]; logFlush prints one yellow ⚠ skipped … line per file.
  • watchRealms threads overwriteLocal from CLI → RealmWatcher constructor.
  • No changes to sync-manifest.ts / sync-logic.ts / realm-sync-base.tscomputeFileHash / loadManifest are reused.
  • .boxel-history checkpoint creation is now skipped on fully-skipped flushes (changes.length === 0); applied flushes still snapshot as before.

Tests added (in packages/boxel-cli/tests/integration/realm-watch.test.ts)

  • skips download when the local file diverges from the sync manifest
  • overwrites diverged local files when overwriteLocal is enabled
  • skips first-run downloads when local files exist at remote paths and no manifest
  • downloads when the local file still matches the manifest hash
  • does not delete a locally-edited file when the remote disappears
  • deletes the local file when the remote disappears and the local matches the manifest
  • keeps re-detecting a skipped divergence on subsequent polls until resolved

Test plan

  • CI runs packages/boxel-cli integration suite green (it wasn't run locally — needs Synapse + realm-server up).
  • Manual smoke against a real realm: sync a dir, edit a file locally, change the same file remotely (e.g. via UI), run watch start → expect the yellow ⚠ skipped … line and the local file untouched.
  • Same setup with --overwrite-local → expect the local file replaced and no skipped line.
  • Delete .boxel-sync.json from a populated dir, run watch start → expect every existing file to skip with a warning on the first poll; non-overlapping remote files still pulled.
  • Reconcile with boxel realm sync --prefer-newest → re-run watch and confirm the warning stops.

Notes

  • Plugin plugin.json version bump is intentionally deferred to the final pre-merge commit.
  • Skill prose in plugin/skills/realm-sync/SKILL.md documents both the new default and the "run boxel realm pull first when seeding a pre-populated directory" caveat (otherwise every file looks diverged on first poll).

🤖 Generated with Claude Code

Flip the default so the watcher skips a remote-driven download (or unlink)
when the local file's hash diverges from `.boxel-sync.json`, instead of
silently overwriting. Pass `--overwrite-local` to opt back into the old
unconditional mirror behavior.

Skipped files keep their old `lastKnownMtimes` so the warning re-fires on
every poll until the user reconciles via `boxel realm sync …` or reruns
with `--overwrite-local`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FadhlanR FadhlanR marked this pull request as ready for review May 15, 2026 10:12
@FadhlanR FadhlanR requested a review from a team May 15, 2026 10:12
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f8063d966

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +213 to +215
const manifest = this.overwriteLocal
? null
: await loadManifest(this.options.localDir);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Ignore manifests from other realms before divergence checks

Treating any .boxel-sync.json as the divergence baseline can silently bypass the new local-edit protection when the manifest belongs to a different realm. In that case, localDivergesFromManifest may see a matching hash and allow overwrite/delete, even though this watch session has no valid sync baseline for this realm. initialize() already guards remoteMtimes with a realm URL match, so flushPending() should similarly discard mismatched manifests (or pass null) before hash comparisons to avoid unintended local data loss.

Useful? React with 👍 / 👎.

@habdelra habdelra requested a review from Copilot May 15, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant