Conversation
Skeptical sweep of all routes (desktop + phone) found every page logged
a console error: '503 /mcp/status'. The MCP server is an OPTIONAL
subsystem (we already gray out AI & Agents when it's offline), but the
server's /mcp/status proxy returned 503 when MCP was unreachable — and
browsers log failed resource loads (5xx) to the console regardless of
try/catch, so it was unavoidable noise site-wide (2 console errors per
page load).
Fix: return 200 with { connected: false, status: 'offline' } for the
offline case. The client already treats connected:false as offline, so
behavior is unchanged — just no more console error. Verified: /mcp/status
now 200, and /, /settings, /backend load with 0 console errors (was 2).
Regression guard: user-smoke now fails on ANY 5xx from our own origin
during the session and sweeps the main routes — this class of bug was
invisible because the gate never checked non-GraphQL responses.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Fix get_graph_context reporting an empty graph as "not found"
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>
* Add smoke guard: a brand-new empty graph shows its empty-state, not an 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>
* Update mock-neo4j for the new get_graph_context query shape
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>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two real, AI-reachable bugs in the clone_graph MCP tool: 1. ParameterMissing(teamId): Neo4j does not persist null-valued properties, so a graph created without a teamId has NO teamId property. cloneGraph read it back as `undefined` and passed it straight to the driver, which rejects undefined param values — so clone threw for essentially every graph created via the API. Coalesce teamId (and type/isShared/settings defensively) to non-undefined values. 2. Edge types silently collapsed to DEPENDS_ON: the edge-clone query matched every relationship type but hard-coded `CREATE (a)-[:DEPENDS_ON ...]->(b)`, rewriting BLOCKS / RELATES_TO / CONTAINS / PART_OF into DEPENDS_ON on clone. Use apoc.create.relationship(newW, type(r), ...) to preserve the real type (APOC 5.x ships with the project's Neo4j). Adds a real-Neo4j contract case: clone a graph with BLOCKS + RELATES_TO edges and assert all nodes copy and both edge types survive. The existing mock unit tests passed through both bugs — they can't reproduce real-DB param/relationship-type behavior, which is exactly why the contract test exists. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
docker-publish.yml used `type=sha,prefix={{branch}}-`, but on a
pull_request event the metadata-action `{{branch}}` placeholder is empty,
so the computed tag became `ghcr.io/...:-<sha>` — an invalid reference
that failed every build-and-push job on PRs targeting main (blocking the
develop→main promotion / prod image pipeline). Use a static `sha-` prefix
so the tag is valid on branch pushes, tags, and PRs alike.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
…ans) (#47) The core "humans and AI as peers on one graph" promise was broken: MCP create_edge wrote a DIRECT Neo4j relationship (a)-[:TYPE]->(b), but the GraphQL server and web UI model edges as Edge NODES joined via EDGE_SOURCE / EDGE_TARGET. Proven live: an MCP-created edge produced 0 rows in the GraphQL `edges` query, so edges an AI created were invisible in the web UI (and human/web-created Edge nodes were invisible to every MCP read, which only traversed direct rels). The two layers were fully bifurcated. This migrates the ENTIRE MCP edge surface onto the canonical Edge-node model the server already uses: - Writes: createEdge, executeBulkCreateEdge (MERGE an Edge node + EDGE_SOURCE/EDGE_TARGET, idempotent); deleteEdge, executeBulkDeleteEdge (DETACH DELETE the Edge node). - Reads: getNodeDetails relationships, getGraphContext (edge count + blockers), getGraphDetails, browseGraph 'dependencies', cloneGraph edge clone — all traverse Edge nodes now. - Analytics: analyzeGraphHealth, getPriorityInsights, getBottlenecks, getContributorPriorities swap direct-rel patterns for Edge-node ones. - Variable-length: findPath and detectCycles use Neo4j 5 quantified path patterns / EDGE_SOURCE|EDGE_TARGET traversal and project back to WorkItem nodes + edge types (verified live: path A->C type DEPENDS_ON, cycle A->B->C->A len 3). Tests: new real-Neo4j contract case asserts an MCP-created edge is a web-visible Edge node (and NOT a stray direct rel), and that deleteEdge removes it. cloneGraph contract case now verifies via Edge nodes. Mock driver updated for the new relationships query + count(newE). Full CI-mode unit suite (305) green; contract suite (7) green. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
The build-stack job assembled the multi-image stack manifest from a
`${GITHUB_SHA::8}` tag that the build-and-push job never pushes, so it
failed on every PR (e.g. the develop→main promotion). Use a tag that is
actually published: `pr-<number>` on pull_request events (matches
metadata-action's type=ref,event=pr), `latest` on main, the branch name
on other branch pushes, and a `sha-<short>` fallback that matches the
type=sha tag.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
…ity with web) (#49) * create_node: attach to a graph via graph_id (orphan nodes were invisible) Node-level twin of the edge parity fix (#47). The web lists nodes per-graph (workItems where graph.id = currentGraph), but MCP create_node had no graph_id parameter and never created a BELONGS_TO relationship, so every node an AI created was orphaned and shown in NO graph view. This also undermined the edge fix: an AI's nodes never appeared, so neither did the edges between them. Add an optional graph_id to the create_node tool + CreateNodeArgs; when present, MATCH the graph and MERGE (n)-[:BELONGS_TO]->(g). A graph_id that matches no graph returns a clean error instead of silently creating an unattached node. Omitting graph_id stays backward-compatible. Real-Neo4j contract test covers all three: attached (BELONGS_TO + shows in get_graph_context), and unknown graph_id errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * create_node: write canonical WorkItem fields the web reads MCP node creation also used non-canonical property names the GraphQL server/web schema don't read: priorityComputed (vs priorityComp), sphericalRadius/Theta/Phi (vs radius/theta/phi), and it never set positionX/Y/Z or priority at all. So AI-created nodes showed priority 0 at the origin in the web, and MCP was internally inconsistent (createNode + browseGraph used priorityComputed while updateNode and the priority/bottleneck analytics used priorityComp — updates were invisible to browse-by-priority and vice versa). Standardize createNode and executeBulkCreateNode on the canonical schema fields (positionX/Y/Z, radius, theta, phi, priority, priorityComp) while keeping the MCP-internal priorityExec/Indiv/Comm decomposition, and fix browseGraph by_priority to read priorityComp. Contract test now also asserts the canonical fields are set and no legacy priorityComputed remains. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- 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.
Promotes three verified, independently-merged bug fixes from
developtomain. All found during a skeptical live-app audit and each guarded by a test the mock-only suites missed./mcp/statusno longer returns 503 (→ site-wide console error) when MCP is offline, which is a normal state.get_graph_contextno longer reports an existing empty graph as "not found" (empty-listUNWINDdropped the result row).clone_graphno longer throwsParameterMissing(teamId)for null-teamId graphs, and preserves each edge's real type instead of collapsing everything toDEPENDS_ON.Each PR is green on the full dev-stack gate (unit, real-Neo4j MCP contract, smoke gate, perf, showcase).
🤖 Generated with Claude Code