fix(watch): reconcile both directions on repair, narrow before promoting
Three defects introduced by the previous commit, from review: - the repair path announced only a creation for the rescheduled root, but only the deletion contributes the stored descendants, and watch batches run with reconcile_stale=False. A file deleted while the watch was down kept its rows indefinitely, which is the stale-row divergence of #812/#817. Both events are dispatched now; - the adopt-time budget check promoted the parent — usually the repository root — as soon as the deepest plan did not fit, handing every ignored tree back to the OS. That is the condition #811 is about, so a fix for it must not be able to re-create it. `_affordable_plan` now retries at shallower depths and then at a single recursive watch on the new directory, and only a repository with no free slot at all falls back to promotion; - a failed reschedule inside the repair (ENOSPC from inotify, which is #811's own trigger) still marked the root repaired, leaving `_repaired_roots` with an entry that has no watch. The failure is now reported as a death, so a directory that ended up unwatched cannot pass quietly as repaired. Each has a regression test that fails on the previous commit: "a file deleted during the outage kept its rows", "the repository root was promoted", and "an unwatched directory was reported as repaired". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fHfGDiZedoxjpKzanHri3
T
Tirth Kanani committed
2c8961f40f01126f9a40b4aab58f181fb6a5a77e
Parent: c4c4d70