Fix get_graph_context reporting an empty graph as "not found"#43
Merged
Conversation
The type/status tally used `CALL { WITH items UNWIND items as i RETURN
i.type as type, count(i) as cnt }`. UNWIND of an empty list yields ZERO
rows, and a correlated CALL subquery returning zero rows eliminates the
outer row — so for a brand-new empty graph the whole query returned no
records and getGraphContext threw "Graph with ID X not found", even
though the Graph node plainly existed.
Return the raw type/status lists from Cypher and tally them in JS
instead. The blockers/recent subqueries were already safe because they
end in `collect(...)` (aggregation always yields one row).
Adds two real-Neo4j contract cases: an empty graph returns zero counts
(not an error), and a populated graph tallies byType/byStatus correctly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
…n error UI counterpart to the get_graph_context empty-graph fix. Verifies that creating a graph with zero work items and opening it renders the "Create Your First Work Item" invitation with no error chrome and no uncaught JS errors. Passes against the live dev stack. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
getGraphContext now returns raw types/statuses lists (tallied in JS) instead of pre-aggregated typeCounts/statusCounts, so the mock driver's canned record must match. Match on the new query (size(items) as nodeCount / as statuses) and return raw label arrays. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
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.
Problem
get_graph_context(MCPGraphService.getGraphContext) threw "Graph with ID X not found" for any graph that had zero work items — even though theGraphnode clearly existed. Found during the skeptical live-app audit: created an empty graph via MCP, thengetGraphContextthrew while a directMATCH (g:Graph {id})confirmed the node was present.Root cause
The type/status tally used a correlated subquery:
UNWINDof an empty list produces zero rows, and aCALLsubquery that returns zero rows eliminates the outer row (correlated-join semantics). So an empty graph collapsed to0records → theif (result.records.length === 0)guard fired → false "not found".The blockers/recent subqueries were already safe because they end in
collect(...), an aggregation that always yields exactly one row.Fix
Return the raw
types/statuseslists from Cypher ([x IN items | x.type]) and tally them in JS. No row-dropping UNWIND, so the graph row always survives.Tests
Two new real-Neo4j contract cases (run in the
MCP Real-Neo4j ContractCI job, gated byRUN_DB_CONTRACT):getGraphContextreturns zero counts (byType/byStatus{}, no blockers/recent), not an error;byType/byStatustally correctly.All 5 contract tests pass against live Neo4j locally.
🤖 Generated with Claude Code