From 25d726f3a8b028004d7c4c7c7f225b0d727e0c1c Mon Sep 17 00:00:00 2001 From: Marcello Alarcon Date: Thu, 14 May 2026 10:15:56 -0300 Subject: [PATCH] fix(brain-repo): watcher must observe install_dir, not brain_repo_dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- dashboard/backend/brain_repo/watcher.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dashboard/backend/brain_repo/watcher.py b/dashboard/backend/brain_repo/watcher.py index 4006a6ab..645bbbf2 100644 --- a/dashboard/backend/brain_repo/watcher.py +++ b/dashboard/backend/brain_repo/watcher.py @@ -105,7 +105,11 @@ def start(self) -> None: 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(): self._observer.schedule( self._handler,