fix(brain-repo): watcher must observe install_dir, not brain_repo_dir#81
Open
mt-alarcon wants to merge 1 commit into
Open
Conversation
The Brain Repo file watcher was scheduling its filesystem observers on
paths under `brain_repo_dir/{memory,workspace,customizations,config-safe}` —
the SYNC TARGET. Those paths only change when `job_runner` runs `copytree`
to mirror the install, which the sync itself triggers. The user's actual
edits to `install_dir/{memory,workspace,...}` were never observed, so
`_sync_fn` never fired and auto-sync silently went dormant.
Symptoms in production (mt-alarcon install, 2026-05-14):
- Last auto-commit on the brain repo was from the previous day even
though hours of edits had accumulated in the working tree.
- `git status` on the brain repo destination always reported "clean"
until a manual sync_force ran.
- No "BrainRepoWatcher started" log entry was missing — the observer
started normally but on the wrong paths.
- When the same Python module was loaded twice (e.g. dev reloaders),
watchdog raised `RuntimeError: Cannot add watch ... already scheduled`
because the destination paths overlapped with already-registered
observers on the SAME process.
Fix: schedule the observer on `self._install_dir / rel_path` instead.
This matches the constructor's documented contract — `install_dir` is the
workspace root where the user edits, `brain_repo_dir` is the mirror.
One-line semantic fix; no API change, no migration needed.
Verified locally: created `memory/.watcher_test.md` in the working tree,
auto-sync committed to the brain repo in ~36s (30s debounce + ~6s
commit/push).
Reviewer's guide (collapsed on small PRs)Reviewer's GuideBrainRepoWatcher now correctly observes the install_dir (user-edited source workspace) instead of the brain_repo_dir (sync destination), restoring automatic sync triggering on user edits without changing any external APIs or schemas. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
3 tasks
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.
Summary
BrainRepoWatcher.start()was scheduling itswatchdogobservers onbrain_repo_dir/{memory,workspace,customizations,config-safe}(the sync target), not oninstall_dir/...(the source where users actually edit).job_runner.copytreemodified the destination — i.e. when a sync was already in progress — so external edits to the working tree never enqueued a sync.self._brain_repo_dir→self._install_diron line 108 ofdashboard/backend/brain_repo/watcher.py.Symptoms before the fix
Reproduced on a production install (mt-alarcon, 2026-05-14):
git statusondashboard/data/brain-repos/evo-nexus-brainalways reported "clean" untilsync_forceran manually.BrainRepoWatcher startedlog line was missing — the observer started normally, just on the wrong paths.watchdograisedRuntimeError: Cannot add watch ... already scheduledbecause the destination paths overlapped with previously-registered observers in the same process.Why the original code looked correct
The constructor docs and field names already imply the right contract:
The
_install_dirfield is even passed to_ChangeHandler(line 100), but the loop a few lines below uses_brain_repo_dir. Likely an early copy-paste from the sync code path that mutates the destination — never caught because the observer does fire when the mirror writes, so a manualsync_forcelooks like it works.The fix
watched_any = False for rel_path in WATCH_PATHS: - watch_target = self._brain_repo_dir / rel_path + # Watch the SOURCE (install_dir / working tree) — that's where the user + # actually edits files. Pre-fix this pointed at brain_repo_dir, which is + # the SYNC TARGET and only changes when copytree runs (no useful signal), + # so auto-sync never fired for user edits. + watch_target = self._install_dir / rel_path if watch_target.exists():No API change, no migration, no schema touch.
Test plan
launchctl kickstart -k gui/$(id -u)/com.mta.evonexus).echo test > <install>/memory/.watcher_test.md.auto: file watcher synccommit landed in the brain repo within ~36 s and was pushed to origin.git rmthe sentinel from the brain repo (sync is one-way / copy-only, so deletions in the source don't propagate — separate issue, not addressed here).Notes for reviewers
copytreewithdirs_exist_ok=True, no--delete). Removing files from the working tree does not propagate to the brain repo — that's a separate behavior worth a follow-up but unrelated to this fix.RuntimeError: already scheduledtraceback was a symptom of the wrong path, not a separate bug. Once the observer points at the correct source paths, the conflict disappears (the destination paths are no longer registered).Summary by Sourcery
Bug Fixes: