feat(schema): introduce Producer node and route ASYNC_CALLS through it#159
Conversation
Add Producer/DECLARES_PRODUCER, flip ASYNC_CALLS to Producer→Route, wire GraphMeta counters, kuzu two-hop async queries, MCP find/resolve producer parity, describe rollups, and PR-C tests (ontology 14 unchanged). Co-authored-by: Cursor <cursoragent@cursor.com>
HumanBean17
left a comment
There was a problem hiding this comment.
Review summary
Solid, plan-aligned PR-C implementation. Schema flip (Producer + DECLARES_PRODUCER + ASYNC_CALLS: Producer → Route), pass5 materialization, downstream two-hop queries, MCP find/resolve, and describe rollups all match plans/PLAN-SCHEMA-V2.md. Assuming tests are green, this is approve with minor follow-ups.
What looks good
- End-to-end wiring in
build_ast_graph.py,java_ontology.py, and regenerateddocs/EDGE-NAVIGATION.md(11 edges); DDL ↔EDGE_SCHEMAstays consistent. - Pass5 mirrors Client: materialize Producer →
DECLARES_PRODUCER→ASYNC_CALLS, sensible dedup keys,GraphMetaproducer counters. - Downstream updated:
find_route_callers,trace_request_flow, impact expansion,pr_analysisall use two-hop async;RouteCalleraddscaller_node_kind="producer"withtopic/broker. - MCP parity:
find(kind="producer"),resolve(hint_kind="producer"), type rollups (DECLARES.DECLARES_PRODUCER,OVERRIDDEN_BY.DECLARES_PRODUCER). - Plan sentinels respected (ontology 14 unchanged; no
Symbol)-[e:ASYNC_CALLS]in production paths).
Should fix before or right after merge
1. MCP tool descriptions still describe a 3-kind world
Literal types were extended, but several LLM-facing strings in server.py were not:
_INSTRUCTIONS: resolve still “symbol/route/client”findkinddescription: noproducerresolvehint_kind: still “all three kinds”describeidhelp: nop:/ producer prefixneighborsidshelp: still symbol/route/client only
These are part of the MCP contract for tool selection — worth updating in this PR or an immediate follow-up.
2. Pass6 async rematch hardcodes client_kind="kafka_send"
HTTP pass6 reconstructs kind from the Client row; async pass6 always uses kafka_send when rebuilding OutgoingCallDecl for matching. For stream_bridge_send producers, pass6 can diverge from pass5 (producer.producer_kind is on ProducerRow). Suggest using producer.producer_kind when producer is present.
3. docs/AGENT-GUIDE.md banner
Still says “PR-C adds Producer…” in future tense — update to present tense post-merge.
Minor / optional
_resolve_producer_candidatesreusesclient_target/client_target_pathResolveReasonvalues for topic lookup — works, but misleading for agents readingreason._producer_idomitsbrokerfrom the hash key; two call sites with same topic + different brokers collapse to one Producer — confirm intentional or add broker to the key.producers_totalis onGraphMetaand incounts_json, but not onGraphMetaOutput/KuzuGraph.meta()top-level return (plan said “if applicable”) — optional polish.
Expected breaking change (documented)
Agents must not use neighbors(method_id, out, ["ASYNC_CALLS"]) anymore; traverse DECLARES_PRODUCER then ASYNC_CALLS. Docs/skills updated; runtime hints deferred to PR-D as scoped.
Recommendation: Approve; address MCP description strings and pass6 producer_kind in this PR or a tiny immediate follow-up.
Update server tool descriptions for the four-kind graph surface; use ProducerRow.producer_kind in pass6 async rematch; fix AGENT-GUIDE v14 banner tense. Co-authored-by: Cursor <cursoragent@cursor.com>
Use p:<hash> in describe id help; add producer_topic resolve reasons; document topic-level _producer_id; lock pass6 async_kind via stream_bridge test. Co-authored-by: Cursor <cursoragent@cursor.com>
Relocate SCHEMA-V2-PROPOSE, PLAN-SCHEMA-V2, and CURSOR-PROMPTS-SCHEMA-V2; update cross-links and PROPOSES-ORDER (PR-D remains under HINTS-V3). Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Producernode,DECLARES_PRODUCER, and flipsASYNC_CALLStoProducer → Route(ontology 14 unchanged; full reprocess still required for v14 graph shape).AsyncCallRow.producer_id), emits edges in pass6/write;GraphMetagainsproducers_total/declares_producer_total/producers_by_kind.find_route_callers,trace_request_flow, impact expansion,pr_analysis; MCPfind(kind="producer")/resolve(hint_kind="producer"); type-level describe rollupsDECLARES.DECLARES_PRODUCERandOVERRIDDEN_BY.DECLARES_PRODUCER.docs/EDGE-NAVIGATION.md(11 edges). PR-D (hints v3) is next — not in this PR.ASYNC_CALLS / Producer grep (this PR’s
*.py/*.mddeltas)build_ast_graph.pyDECLARES_PRODUCER,ASYNC_CALLSFROM Producer, pass5 materialization, pass6 viaproducer_id, GraphMeta countersjava_ontology.pyDECLARES_PRODUCER+ASYNC_CALLSsrc=Producer; post-flip traversalskuzu_queries.pylist_producers;RouteCallerproducer branch (topic/broker)mcp_v2.py/server.pyproducerkind on find/resolve/neighbors schema; nomcp_hints.pypr_analysis.pyplans/PLAN-SCHEMA-V2.mdSentinel checks (zero on diff): no
TPL_NEIGHBORS_WRONG_SUBJECT_KIND/neighbors_empty_hintsimplementation; noSymbol)-[e:ASYNC_CALLS]in production emit/query paths; noONTOLOGY_VERSION = 15.Test plan
.venv/bin/ruff check build_ast_graph.py kuzu_queries.py mcp_v2.py.venv/bin/python -m pytest tests/test_call_edges_e2e.py tests/test_brownfield_clients.py tests/test_mcp_v2.py tests/test_ast_graph_build.py -vrm -rf /tmp/schema-v2-c && .venv/bin/python build_ast_graph.py --source-root tests/fixtures/http_caller_smoke --kuzu-path /tmp/schema-v2-c --verbose.venv/bin/ruff check .PATH=".venv/bin:$PATH" .venv/bin/python -m pytest tests -v(550 passed, 10 skipped)Made with Cursor