Skip to content

feat(viz): code-graph lands on a connected hub neighbourhood + server-backed file search#29

Merged
sshanzel merged 3 commits into
mainfrom
feat/viz-code-graph-landing
Jun 17, 2026
Merged

feat(viz): code-graph lands on a connected hub neighbourhood + server-backed file search#29
sshanzel merged 3 commits into
mainfrom
feat/viz-code-graph-landing

Conversation

@sshanzel

Copy link
Copy Markdown
Owner

What changed

The code-graph tab dumped the first 800 files (an arbitrary, unreadable black wall) for any sizeable repo — the last viz hairball from the cold-start validation pass. It now lands on a connected hub neighbourhood:

  • collectCode ranks files by coupling degree and grows a connected neighbourhood from the densest hubs (each hub + its neighbours) up to CODE_LANDING_CAP (80). This shows real coupling structure — not 800 dots, and not isolated hubs (top-degree-alone are edgeless, since hubs connect to leaves, not each other). Small repos (≤80 files) still show in full. Note reads "Showing the 80 most-connected files of N — double-click to expand, or search to load any file."
  • New searchFiles (parameterized $q path-CONTAINS, never string-concatenated) + /api/search route so the UI search reaches files outside the landing set. doSearch highlights loaded matches instantly, then debounced-fetches and adds matching files to the graph; double-click then expands their neighbours.
Before After
800-file black wall (arbitrary slice) 80 most-connected files, connected hub-and-spoke, readable paths

Verification

Reviewer (healthy graph): 80 nodes / 293 edges, connected structure, file paths legible. Search verified: daemon → loads daemon.ts/daemon.test.ts (not in the landing set).

Playright renders edgeless (1349 files, 0 import/ref/cochange edges) because its index is the incomplete one from the generated-file Symbol-PK crash — a separate known launch-checklist bug, not this change.

How to test

  • pnpm test:unit (553) — ui.test asserts the search wiring (fetchSearch + /api/search). The Kùzu-backed collectCode is exercised by the manual plex serve E2E (no Kùzu in a .test.ts, ADR-17). pnpm typecheck + pnpm build green.
  • Manual: plex serve → Code graph tab on a real repo → connected hub view; type a non-hub filename → it loads.

Notes

This closes the "seeing the graph" track (all three tabs — Knowledge, Review history, Code graph — now legible). The playright edgeless-index bug (generated-file Symbol PK) remains a separate launch-checklist item.

🤖 Generated with Claude Code

sshanzel and others added 3 commits June 18, 2026 01:12
…-backed file search

The code-graph tab dumped the first 800 files (an arbitrary, unreadable black wall) for any
sizeable repo — the last viz hairball from the cold-start validation pass. Replace it with a
legible landing:

- collectCode ranks files by coupling DEGREE and grows a CONNECTED neighbourhood from the
  densest hubs (each hub + its neighbours) up to CODE_LANDING_CAP (80) — so the landing shows
  real coupling structure, not 800 dots and not (top-degree-alone) isolated hubs. Small repos
  (≤80 files) still show in full. Note: "Showing the 80 most-connected files of N — double-click
  to expand, or search to load any file."
- New searchFiles (parameterized $q path-CONTAINS) + /api/search route so the UI search reaches
  files OUTSIDE the landing set; doSearch highlights loaded matches instantly, then debounced-
  fetches and ADDS matching files to the graph (double-click then expands their neighbours).

Verified on a healthy graph (reviewer: 80 nodes / 293 edges — connected hub-and-spoke, file
paths readable). (Playright renders edgeless because its index is the incomplete one from the
generated-file Symbol-PK crash — a separate known bug, not this change.)

Tests: ui.test asserts the search wiring; the Kùzu-backed collectCode is exercised by the manual
serve E2E (no Kùzu in a .test.ts, ADR-17). 553 unit green; typecheck + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eview)

Address items 1–3 of the Plex review of PR #29 (all in doSearch/fetchSearch):

1. BUG: a stale debounced response re-highlighted against the OLD query — the 250ms debounce
   cancelled the pending timer but not an in-flight fetch, so a slow/out-of-order response faded
   the current matches and added nodes for a superseded query. Now a `searchGen` token is bumped
   on every keystroke; fetchSearch captures its gen and drops the response if `gen !== searchGen`,
   and re-highlights against the CURRENT input (`currentQuery()`), never the captured q.
2. IMPROVEMENT: repeated searches grew the graph unboundedly (every fetch added ≤40 nodes, never
   evicted, re-layouting an ever-larger graph). Search-added nodes now carry a `searched` class and
   the previous batch is evicted before the next is added — the landing + double-click expansions
   are untouched, so growth is bounded.
3. IMPROVEMENT: a 503 set the shared "Repo busy — retrying…" status but never retried (the message
   lied). fetchSearch now actually retries with a bounded backoff (≤5 attempts), gated on the gen so
   a superseded query stops retrying.

Tests: ui.test asserts the gen-guard, the eviction, the current-input re-highlight, and the retry
(string-presence — the client JS has no DOM/cytoscape harness here). Verified at runtime: search
loads a non-hub file, a rapid query switch hits the gen path, no page errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ary (PR #29 review)

Address items 4–5 of the Plex review of PR #29 (collectCode landing):

4. MINOR: the landing note claimed "most-connected files" even on an edgeless graph (0 coupling
   edges → the loop just takes the first N). It now reads "Showing N of M files (no import/co-change
   edges indexed yet) — search to load any file." when there are no edges.
5. MINOR: a hub could land as an isolated dot when the cap was hit right after adding it but before
   any neighbour. The growth loop now skips adding a hub-WITH-neighbours when there's no room left to
   also include a neighbour (a degree-0 file can still fill the final slot — it has no edge to show).

Tests: not unit-testable (collectCode opens Kùzu, ADR-17). Verified manually — the edgeless note
fires on a 0-edge graph, and the connected-landing rendering (reviewer: 80 nodes / 293 edges) is
unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sshanzel

Copy link
Copy Markdown
Owner Author

Plex review feedback addressed — ready for re-review.

The Plex review (run in-session; not posted as GitHub threads) raised 1 bug + 2 improvements + 2 nits. All five are fixed; two flagged risks came back clean.

Item Class Outcome
1. Stale debounced search response re-highlights against the old query bug Fixed in 5ca6f4d: a searchGen token drops stale/out-of-order responses (gen !== searchGen) and re-highlights against the CURRENT input, not the captured query.
2. Repeated searches grow the graph unboundedly improvement Fixed in 5ca6f4d: search-added nodes carry a searched class; the previous batch is evicted before the next is added (landing + expansions untouched).
3. 503 on /api/search showed "retrying…" but never retried improvement Fixed in 5ca6f4d: fetchSearch now actually retries with bounded backoff (≤5), gated on the generation so a superseded query stops.
4. Landing note said "most-connected" even on an edgeless graph minor Fixed in b6826ca: an edgeless graph now reads "Showing N of M files (no import/co-change edges indexed yet) — search to load any file."
5. Last hub at the cap boundary could land as an isolated dot minor Fixed in b6826ca: the growth loop won't add a hub-with-neighbours when there's no room left for a neighbour (a degree-0 file can still fill the final slot).

Verified clean (no change): LIMIT $lim with an int param is supported in kuzu@0.11.3; toLower(...) CONTAINS $q is correctly parameterized (no injection); added nodes flow through the same textContent-only path (XSS holds); included can't exceed the cap.

Tests: items 1–3 — ui.test assertions for the gen-guard, eviction, current-input re-highlight, and retry (the client JS has no DOM/cytoscape harness, so string-presence is the convention here); also verified at runtime (search loads a non-hub file, a rapid query switch exercises the gen path, no page errors). Items 4–5 — collectCode opens Kùzu (not unit-testable, ADR-17); verified manually (edgeless note fires; the connected landing — reviewer: 80 nodes / 293 edges — is unchanged).

Checks: pnpm typecheck, pnpm test:unit (554), pnpm build, client-JS syntax — all green.

No GitHub review threads existed to reply to/resolve (the review was in-session).

@sshanzel sshanzel merged commit 7c45626 into main Jun 17, 2026
1 check passed
@sshanzel sshanzel deleted the feat/viz-code-graph-landing branch June 17, 2026 21:45
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