perf(graph): few deep traversals instead of 60 shallow (cut log noise further)#45
Merged
Merged
Conversation
…ll request-log noise) The previous fix (1 traverse_graph/seed × up to 60 seeds) still wrote ~60 rows to the request log per graph build. traverse_graph(both, depth N) already returns the whole reachable neighborhood's edges in ONE call, so traversing a handful of relevant roots at depth 5 (gbrain default, cap 10) covers the connected brain in ~8 reads instead of 60 — and for a connected graph it actually surfaces MORE edges per root. Roots capped at 8; same node set (from list_pages) so isolated pages still render. Combined with the 1h cache, the UI's graph reads drop ~15× vs the original get_links+get_backlinks fan-out. Co-Authored-By: Zypher Agent <zypher@corespeed.io>
spinsirr
added a commit
that referenced
this pull request
Jul 1, 2026
The graph rendered as all-isolated dots ("全散了") — every node degree 0,
uniform size, no edges — even though the brain has a dense link graph.
Root cause: #45 picks the deep-traversal roots as
`[...titles.keys()].slice(0, TRAVERSE_ROOTS)`. `titles` is filled
list_pages-first in updated_desc order, so the roots are just the 8
NEWEST pages — which are frequently freshly-created and not yet linked.
A depth-5 traversal from an unlinked page reaches nothing, and the rich
hubs (entities/haas, companies/corespeed) sit at position #9+, excluded
from the roots. Result: 0 edges, deterministically.
- Seed the traversal roots from the seed-query hits (relevance-ranked,
round-robin across queries so each contributes its top hit), which
reliably surface the hubs; fall back to recent pages only to fill
TRAVERSE_ROOTS. On the live brain this restores 0 → 87 edges.
- edgeRows now reports ok/failure instead of collapsing both to []. When
the graph ends up edgeless AND a traversal actually errored, buildGraph
throws so /api/graph returns 502 (uncached) rather than caching a
misleading scattered graph for the full 1h TTL.
- Add a test for the fail-loud path; update AGENTS.md graph bullet (which
still described the pre-#43 get_links implementation).
Co-Authored-By: Zypher Agent <zypher@corespeed.io>
spinsirr
added a commit
that referenced
this pull request
Jul 7, 2026
* fix(graph): traverse from relevant hubs, not the newest pages
The graph rendered as all-isolated dots ("全散了") — every node degree 0,
uniform size, no edges — even though the brain has a dense link graph.
Root cause: #45 picks the deep-traversal roots as
`[...titles.keys()].slice(0, TRAVERSE_ROOTS)`. `titles` is filled
list_pages-first in updated_desc order, so the roots are just the 8
NEWEST pages — which are frequently freshly-created and not yet linked.
A depth-5 traversal from an unlinked page reaches nothing, and the rich
hubs (entities/haas, companies/corespeed) sit at position #9+, excluded
from the roots. Result: 0 edges, deterministically.
- Seed the traversal roots from the seed-query hits (relevance-ranked,
round-robin across queries so each contributes its top hit), which
reliably surface the hubs; fall back to recent pages only to fill
TRAVERSE_ROOTS. On the live brain this restores 0 → 87 edges.
- edgeRows now reports ok/failure instead of collapsing both to []. When
the graph ends up edgeless AND a traversal actually errored, buildGraph
throws so /api/graph returns 502 (uncached) rather than caching a
misleading scattered graph for the full 1h TTL.
- Add a test for the fail-loud path; update AGENTS.md graph bullet (which
still described the pre-#43 get_links implementation).
Co-Authored-By: Zypher Agent <zypher@corespeed.io>
* chore: format admin files left unformatted by #42/#44
biome check has been failing repo-wide since the calibration/admin PRs
landed with unformatted files, so every branch inherits a red CI check.
Formatting-only; no behavior change.
Co-Authored-By: Zypher Agent <zypher@corespeed.io>
* fix(graph): close the fail-loud guard's blind spots + serve stale over 502
Review hardening on top of the hub-roots fix (multi-model review of
this PR):
- Every upstream read feeds ONE failure signal: seed queries and
list_pages now track failures (a total outage used to cache an EMPTY
graph as healthy for the 1h TTL; an all-seed-query failure silently
reverted roots to recency order — the exact regression this PR
fixes). edgeRows treats MCP isError results, non-array payloads, and
edge-row-less arrays (schema drift) as failed reads instead of
"healthy, zero edges".
- The edgeless guard gates on the PRE-filter edge set, so a brain
whose every edge touches a hash-titled page doesn't 502.
- Degraded builds (some reads failed, edges survived) are served but
NOT cached, so a partial graph can't get pinned for the full TTL.
- Rebuilds are single-flighted, and a failed rebuild serves the last
good expired graph stale instead of a 502 — no full-pipeline retry
storm against an already-degraded gbrain.
- The route logs the failure reason before the generic 502.
- Overview renders the link stat as "—" and TopHubs says the data is
unavailable when the graph read failed, instead of a misleading 0.
- Hash-titled mem0 imports no longer consume traversal-root slots.
- Tests: root selection is pinned (reverting to recency-ordered roots
fails the suite — mutation-verified), plus coverage for the
uncached-throw contract, isError, total outage, partial failure,
stale-serve, single-flight, round-robin order, and the route 502.
Co-Authored-By: Zypher Agent <zypher@corespeed.io>
---------
Co-authored-by: Zypher Agent <zypher@corespeed.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The earlier fix still fired ~60
traverse_graphcalls per build (1 shallow call per seed).traverse_graph(both, depth N)returns the whole reachable neighborhood's edges in ONE call, so traverse 8 roots at depth 5 instead → ~8 reads/build (and for a connected graph, more edges per root, not fewer). Same node set (list_pages) so isolated pages still render. ~15× fewer graph reads vs the original get_links+get_backlinks fan-out. typecheck + vitest 75 + build green.