feat(codegraph): per-workspace CodeGraph indexing, hardened + isolated behind a feature seam #47
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/codegraph"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds CodeGraph so the agent gets a
codegraph_exploreMCP tool — call paths and impact in one query instead of grep/read loops.This PR was rewritten. The original design (first commit, kept for attribution) silently answered every session from the main branch. Review found seven defects; the six commits after it fix them and extract CodeGraph behind a generic feature seam. Review the net diff, not the first commit.
The bug, and the one idea that fixes it
codegraph resolves its project by walking up from cwd to the first valid
.codegraph/. Session worktrees live at/workspace/.nexus/worktrees/<name>— under/workspace. So an index at/workspacewas found by every worktree that lacked one, and the agent got main's call graph while sitting on a feature branch.I tried every way to pin the root —
serve --mcp --path, the MCProotUri, a real.gitboundary, an empty.codegraph/placeholder. All four fail; it walks up regardless. So the fix isn't a guard, it's a placement:The seed lives at
.nexus/codegraph-seed/— a sibling ofworktrees/, not an ancestor. Every failure mode collapses from wrong answers to no answers, which is what makes backgrounding the build safe.Defects fixed (all verified in a real container against the real binary)
/workspaceindex hijacked every worktree/workspacenever holds an indexcp -rof a live DB — andcpexits 0 on garbagesqlite3 VACUUM INTO→integrity_check: okunhealthyfor the whole build (14.6s/374 files, minutes on a big repo)daemon.pid/sockcopied into every worktreecodegraph.dblogger.debug— dropped underNODE_ENV=productionwarn+ a 60s timeout.nexus/rowsA session created while the seed is still building gets a blank but valid index: it stops the walk and self-builds its own branch (verified with a branch-only canary). Correct, not merely safe.
Isolation
CodeGraph lives entirely in
server/codegraph/+worker/addons/codegraph/. Production core names the flag (codegraph_enabled— a column, a DTO field, a checkbox) and nothing else: no paths, no commands, no imports. Enforced by a grep in the plan, and the TS/shell literals are coupled by a meta-test that fails (never skips) if either side moves.Removing CodeGraph = delete two directories, one registry line, one Dockerfile line.
Honest framing — a deliverable, not a nicety
I measured its call-edge accuracy against the TypeScript compiler over 136 exported functions: 96.5% precision, 85.7% recall. Two systematic, silent defects, each reproduced in a 6-line fixture:
await fn<T>(...)produces no edge at all. Notfn<T>(), notawait fn()— only the combination. That's idiomatic TS: 35 call sites in this repo.a.b.method()binds by bare name to any module-level function of that name, in files the caller never imports. Repo-wide, 22% of cross-file call edges have no import backing (a DB migration "calling" a Svelte component, via Kysely'scol.check()).Neither is flagged — a wrong edge looks exactly as authoritative as a right one, under a heading that reads "Blast radius — what depends on these." At 85.7% recall, an agent trusting an empty result is wrong about one time in seven.
So
default-CLAUDE.mdnow tells the agent it is a hint, not an oracle: never read "no callers found" as proof; verify with grep ortscbefore deleting or re-signing anything. Shipping the tool without this would be shipping a confident liar.Both defects have upstream reproductions ready to file.
Upgrade note ⚠️
Workspaces spawned from a pre-hardening worker image must be recreated, not restarted. The old entrypoint rebuilds
/workspace/.codegraphon every boot;createSessiondisarms it once, but a restart brings it back.Also fixed on the way
worker/*.test.shran nowhere. They now run in CI — and the two needing the real binary run inside the built image, before the push, so an image can't be published before the tests that would reject it.mark_degradedused>(truncate), so a second writer would clobber the secrets reason. Now appends.CODEGRAPH_TELEMETRY=0baked in; version pinned to 1.4.1.Test plan
pnpm test— 607 pass (up from 565);lint+typecheckcleanworker/*.test.shpass, on the host and inside the built imagedocker build --target base— codegraph 1.4.1, sqlite3, blank templateinitialized: true, fileCount: 0integrity_check: ok, no daemon files; seed has 0.nexus/rows; kill mid-build → reboot rebuilds; a no-seed session self-builds its own branch50359b08d06ad618e472feat(codegraph): per-workspace CodeGraph indexing for agent sessionsto feat(codegraph): per-workspace CodeGraph indexing, hardened + isolated behind a feature seamView command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.