Skip to content

fix(dev-tools): log codegraph startup sync as skipped when the daemon owns the index - #1340

Merged
joshjhall merged 4 commits into
mainfrom
fix/codegraph-startup-sync-daemon-lock
Oct 20, 2026
Merged

joshjhall merged 4 commits into
mainfrom
fix/codegraph-startup-sync-daemon-lock

Conversation

@joshjhall

Copy link
Copy Markdown
Owner

Summary

On a fresh boot, /tmp/codegraph-index.log reported:

✗ Failed to sync: Sync could not acquire the file lock ... locked by another process (PID 3714)
[codegraph-index] sync failed (see above); MCP will index on demand

The every-boot hook (55-codegraph-index.sh) starts a detached codegraph sync. The editor's codegraph MCP server starts a second or two later, takes the index lock, and the sync loses. Nothing is actually wrong, because the daemon's file watcher keeps the graph current, but the log reports a failure on most boots.

Change

  • After a failed sync/init, the hook reads daemon.pid (JSON) and checks for a live process whose command line names codegraph. If one is found, it logs sync skipped: codegraph daemon (PID N) owns the index and keeps it synced.
  • The check runs only after the failure, not up front, because the daemon usually appears after the hook has already started.
  • A missing pid file, or a pid that is running but isn't codegraph (stale file, recycled pid), is still logged as a failure.
  • CODEGRAPH_CACHE_DIR / CODEGRAPH_BIN / CODEGRAPH_LOG can now be overridden so the hook can be tested. Defaults are unchanged.

The second commit (chore(memory)) adds the pending .claude/memory/ updates: 11 new memories, 3 updated, and the index. Long lines are wrapped to pass rumdl, and I checked that only whitespace changed.

Testing

  • New behavioral test test_codegraph_index_skips_when_daemon_owns_index runs the real hook with a stub codegraph that always fails. It checks three cases: a live daemon (skip), no daemon (failure), and a running pid that isn't codegraph (failure).
  • Mutation check: with the daemon check forced false in a scratch copy, the new test fails.
  • tests/unit/features/dev-tools.sh: 76/76 pass. shellcheck at warning level and shfmt are clean.
  • Ran the patched hook against the live index in the rebuilt devcontainer. The normal path still logs sync complete.

🤖 Generated with Claude Code

joshjhall and others added 4 commits October 19, 2026 22:21
… owns the index

The every-boot codegraph hook races the editor's MCP server: the server
starts within a second or two of the hook, takes the index lock, and the
detached `codegraph sync` fails with "database is locked". The log then
reported a failure on most boots even though the daemon's file watcher
keeps the graph current.

After a failed op, the hook now checks daemon.pid for a live process whose
command line names codegraph and logs a skip instead. The check runs only
after the failure because the daemon usually appears after the hook has
started. A missing pid file, or a pid that is running but not codegraph
(stale file, recycled pid), is still logged as a failure.

The cache dir, binary and log path can be overridden so the new
behavioral test can drive the hook with a stub codegraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ty lessons

Adds eleven memories from recent golem and review cycles (harness resume
replaying a fake review, full review before merge, follow-ups before
teardown, teardown tripping on scaffolding, merge commits breaking conform
CI, readdir-order CI-only failures, refusal tests reaching real gh, mutation
scratch target dirs, env scrub under the same uid, evidence pending from
published db, heuristic scanners), updates three existing ones, and
re-indexes MEMORY.md. Long lines are wrapped to satisfy rumdl MD013.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rve daemon

Review of the previous commit found two ways it logged a real failure as
"skipped":

- Any failure counted while a daemon was alive, which is the normal state
  seconds after boot. A corrupt index, ENOSPC, or a CLI change would be
  reported as "owns the index and keeps it synced".
- The `*codegraph*` argv match accepted any process that mentions
  codegraph, e.g. `less /tmp/codegraph-index.log` on a recycled pid.

The hook now takes the PID from codegraph's own lock refusal ("locked by
another process (PID N)") rather than daemon.pid, so it names the actual
lock holder, and it requires that PID's argv to be a `codegraph ... serve`
process. Reading /proc/PID/cmdline replaces `kill -0`, which also stops
a daemon owned by another user from failing the check with EPERM.

The test now covers a lock held by the serve daemon (skip), a non-lock
error that mentions the daemon's PID, a holder whose argv merely mentions
codegraph, an unrelated holder, and a dead holder (all failures). A second
test covers init completion and the missing-binary no-op. Mutating each
condition in a scratch copy fails the suite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fake-daemon fixtures from the previous commit ran `bash -c 'sleep 30;
:' ... &` and killed only the bash parents, orphaning each `sleep 30` with
the suite's stdout still open. run_unit_tests.sh captures every suite via
$(...), so it blocked about 30s on this suite in `just test`, pre-commit,
and CI. The fixtures now detach from the suite's stdio and their sleep
children are killed before the parents. The captured run drops from 31s
to 2s.

The daemon match also tightens from `*codegraph*" serve"*` to
`*codegraph.js" serve"*`, the argv codegraph spawns its daemon with
(direct or via the launcher), so `grep codegraph serve` and similar no
longer match. The reader fixture now uses that shape. The hook comment
notes that only `sync` can log a skip: a contended `init` and the
lock-file race report the lock without a PID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joshjhall
joshjhall merged commit eb4ad64 into main Oct 20, 2026
17 checks passed
@joshjhall
joshjhall deleted the fix/codegraph-startup-sync-daemon-lock branch October 20, 2026 04:57
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