Files
codegraph/__tests__
Colby MchenryandClaude Opus 5.5 b2a84873ed fix(daemon): a long sync of another project no longer gets the shared daemon killed (#2793)
Root cause: the daemon arms its liveness watchdog with its own project's
index files (codegraph.db + -wal), and since PR #1231 a silent timeout
defers the kill while those files advance. But the daemon also writes every
other project a session opens with projectPath: the project lifecycle takes
that project's writer lock, starts its watcher and runs the catch-up sync,
all storing on the main thread. A long synchronous stretch of such a sync
left the daemon's own files still, so the watchdog read it as a wedge and
SIGKILLed a healthy daemon mid-sync; the next session reattached the project
and the cycle repeated. A proxy serving in-process, armed with no files at
all, had the same blind spot for its own project.

Fix: addWatchdogProgressPaths() lets a process add files to its watchdog at
runtime. The project lifecycle adds a project's db and -wal the moment this
process becomes the project's writer, and drops them after it closes the
project, so only indexes this process writes count, never one another
process owns. Each change re-arms the watchdog with a new child whose argv
carries the whole list; the old child is stopped after the new one starts.
Added files take effect at once (a sync may block the loop right after);
dropped ones wait a turn, so a server releasing its projects on the way out
re-arms once or not at all. A message over the heartbeat pipe was tried
first and dropped: Node's Writable holds a second write while one is still
in flight, so the -wal line of a db + -wal registration never reached the
child before a block that followed in the same tick (4 of 4 runs).

Validation:
- New __tests__/liveness-watchdog-projects.test.ts (11 cases, real watchdog
  child, lowered timeout): main's source 9 fail / 2 pass (the two guards),
  fix 11 pass. The lifecycle case arms the watchdog for project A, attaches
  B through the project lifecycle and stores into B's index on the main
  thread for 3s: killed at ~1s on main, runs to completion with the fix.
- 8 mutations, each failed at least one case: no lifecycle registration,
  registration before the writer-lock check, no drop on release, no re-arm on
  add, no re-arm on drop, old child not stopped, drops re-armed at once,
  adds deferred.
- Real daemon on Windows (watchdog timeout 5s, daemon keyed on a 2-file
  project, second project excalidraw 1d4dc2c with all 687 TS files edited,
  attached with codegraph_status projectPath), 3 interleaved rounds:
  main killed 3/3 about 13s after attaching B ("Main thread unresponsive
  for ~5s"), leaving B with 27,698 edges and 72,534 pending refs; the fix
  survived 3/3 through 7.8-9.3s main-thread blocks and finished B (61,120
  edges, 0 pending), and 3/3 again on the final build (9.7-9.9s blocks).

Fixes #2404

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 09:04:05 +00:00
..