propose: schema-v2 — edges connect the nodes the edge is about (HTTP_CALLS, ASYNC_CALLS, Producer node, Edge Navigation Schema)#151
Conversation
…ion 21) The callee side is already symmetric for HTTP and async: @KafkaListener methods are the Route's method_fqn, reachable via EXPOSES(Symbol→Route), exactly mirroring @GetMapping. Producer node exists only because kafkaTemplate.send(...) is a call expression with no first-class method identity — listener methods don't have that problem. - §5 out-of-scope row rewritten: 'no annotation yet' → 'no navigation gap' - Decision 21 added explicitly locking the asymmetry - §8 risk row updated to reference Decision 21 - Appendix B records second-round grilling outcome No change to PR count (4), UC count (23), or edge count (11).
|
Update — Decision 21: no Consumer node Grilled during the propose-review pass: should the callee-side mirror the caller-side Conclusion: no. The callee side is already symmetric. Changes (one commit, force-push not needed — fast-forward):
No change to PR count (4), UC count (23), or edge count (11). Ready for review-1 when you have cycles. |
HumanBean17
left a comment
There was a problem hiding this comment.
Verdict
Approve the direction; hold implementation until a few contract gaps are closed.
The core diagnosis matches the codebase: HTTP_CALLS / ASYNC_CALLS are Symbol → Route while Client already exists and is only reachable via DECLARES_CLIENT — exactly the “empty neighbors from the node you’re holding” failure mode. Folding async in (not HTTP-only) and Decision 21 (no Consumer node) are well argued.
What works well
- Principle-first framing (“edges connect the nodes whose data the edge is about”).
- PR-A before DDL flips (
EDGE_SCHEMA+ generated doc against current schema). - No dual-edge / alias policy (matches repo rules).
- UC tables are concrete and testable (UC1, UC5–7, UC14–15, UC18; UC6/15 “declared but unresolved” on caller-side nodes).
- Appendix B traceability for HTTP-only → HTTP+async revision.
Must fix before implementation
1. Re-index / ontology_version callout missing
Per repo rules, graph-shape changes need an explicit subsection: bump ontology_version (currently 13), README “Re-index required”, full rebuild. Don’t leave this implied by “4 PRs”.
2. brownfield_sourced vs FUZZY_STRATEGY_SET (internal contradiction)
Decision §7.9 ties brownfield_sourced to FUZZY_STRATEGY_SET, but hints-v2 treats codebase_client, layer_b_ann, etc. as non-fuzzy primary paths — and HTTP/async edges routinely use those strategies. Appendix A marks HTTP_CALLS / ASYNC_CALLS as brownfield_sourced=True. Lock semantics before PR-A (rename flag, widen set, or split fuzzy_strategy_capable vs annotation-sourced).
3. find_route_callers / trace_request_flow / impact-analysis not in scope tables
kuzu_queries.py still has Symbol -[:HTTP_CALLS|ASYNC_CALLS]-> Route in find_route_callers, trace_request_flow, and impact-analysis expansion (~L1335). PR-B/C list pr_analysis, mcp_v2, server.py but not an explicit decision for:
- Does
find_route_callersreturn Client/Producer ids, or join viaDECLARES_*and keep returning declaring Symbol? - What happens to
CallerInfo.caller_symbol_id?
Without this, PR-B risks a half-migrated query layer.
4. Type-level describe rollups unspecified
Today only DECLARES.DECLARES_CLIENT and DECLARES.EXPOSES are composed for type symbols. After the flip, methods lose direct HTTP_CALLS out-edges; types never had them. UC10 fixes describe(client) but class-level describe loses cross-service signal unless you add e.g. DECLARES.DECLARES_PRODUCER (and optionally composed HTTP/async). Specify in PR-B/C or accept the regression explicitly.
5. HINTS-V3-PROPOSE.md referenced but missing
PR-D / UC2, UC3, UC17, UC22 depend on it. Add a stub in this PR, fold a minimal v3 section here, or mark PR-D blocked until v3 propose exists.
6. plans/PLAN-SCHEMA-V2.md not in this PR
Fine for propose-only; block merge on plan + CURSOR-PROMPTS-* before PR-A (grep-enumeration contract in §8).
7. Producer DDL vs AsyncProducerHint
Proposed target_topic + topic vs hint’s topic only; Client has path / path_template / path_regex. Lock field names against AsyncProducerHint + pass6 join keys in §3.2 now; validate templates in PR-C.
8. §3.4 pass label
Clients/producers are materialized in pass5_imperative_edges, not pass4 (pass4 = routes/EXPOSES).
Medium priority
| Gap | Note |
|---|---|
find(kind="producer") / resolve(hint_kind="producer") |
VALID_PRODUCER_KINDS exists; without MCP parity agents only reach producers via known method + DECLARES_PRODUCER. |
| Docs sweep | README, docs/AGENT-GUIDE.md, exploration skill still teach Symbol → Route. Add PR row in B+C. |
| GraphMeta | Mention producers_total / declares_producer_total alongside clients_total. |
| UC9 | pr_analysis uses HTTP_CALLS|ASYNC_CALLS — mention both in the UC row. |
| §7 count | Appendix B says “16 → 20” decisions; §7 has 21 items. |
Framing questions (my answers)
- UC8/UC16 extra hop (3→4) — Acceptable for v2 if PR-D ships composite-traversal hints; materialized convenience edges are premature.
cardinality— Keep (informational, cheap, useful for docs/future invariants).- Producer 1:1 with Client — Don’t lock field parity; lock names against
AsyncProducerHintnow, validate templates in PR-C. - Bundle HINTS-V3? — Split is fine (like hints-v2), but don’t schedule PR-D until
HINTS-V3-PROPOSE.mdexists — v2 graph without v3 hints is a footgun (UC3).
Pre-merge checklist for this propose
- Schema / re-index subsection
-
brownfield_sourcedsemantics vs hints v2 - Downstream API table (
find_route_callers,trace_request_flow, impact analysis,CallerInfo) - Type-level describe rollups decision
- Fix pass5 reference in §3.4
- HINTS-V3 stub or PR-D blocked
- Producer field names aligned with
AsyncProducerHint
Happy to iterate on the propose text if you want these folded in before PLAN-SCHEMA-V2.
Major items (must-fix): - §3.6: re-index requirement + ONTOLOGY_VERSION 13→14 bump (PR-A) + GraphMeta counters (PR-C) + README/AGENT-GUIDE references - §3.7: downstream API contract decisions for find_route_callers, trace_request_flow, impact-analysis expansion. External API stable, internal Cypher grows one hop. (Decisions 22, 23, 24.) - §3.8: type-level describe rollups — DECLARES.DECLARES_PRODUCER added; composed DECLARES.HTTP_CALLS / DECLARES.ASYNC_CALLS deliberately not added. (Decision 25.) - §3.9: MCP find(kind=producer) / resolve(hint_kind=producer) parity. (Decision 26.) - §3.10: docs sweep per-PR with grep enumeration. (Decision 27.) - §3.11: brownfield_sourced → brownfield_resolver_sourced with new BROWNFIELD_RESOLVER_STRATEGY_SET (union of FUZZY_STRATEGY_SET and annotation/primary-path strategies). Closes hints-v2 contradiction. Decision 9 updated, Appendix A flags renamed. (Decision 28.) - §3.4 corrected: pass4 → pass5_imperative_edges. - §3.2 Producer fields re-grounded in AsyncProducerHint + AsyncCallRow. target_topic + HTTP-specific fields removed; direction added. - PLAN/CURSOR-PROMPTS as merge gate for PR-A. (Decision 29.) - PR-D explicitly gated on HINTS-V3-PROPOSE.md existing. (Decision 30.) Medium: - UC9 row mentions both HTTP_CALLS and ASYNC_CALLS in pr_analysis query. - TL;DR migration bullet expanded with the new PR scope. - Appendix B Review-1 application section added. Cardinals (still consistent): - 4 PRs · 23 UCs · 11 edges · 32 decisions (was 21).
|
Review-1 applied — commit Must-fix items1. Re-index /
|
| Item | Status |
|---|---|
find(kind="producer") / resolve(hint_kind="producer") |
Applied — §3.9, Decision 26. PR-C scope. |
| Docs sweep (README, AGENT-GUIDE, exploration skill) | Applied — §3.10, Decision 27. PR-B handles HTTP, PR-C handles async, each via grep enumeration. |
GraphMeta producers_total / declares_producer_total |
Applied — §3.6 item 4, Decision 32. PR-C scope. |
| UC9 mentions both edges | Applied — UC9 row now reads HTTP_CALLS|ASYNC_CALLS on both pre-v2 and post-v2 sides. |
| §7 count drift (16 → 20 → now 32) | Appendix B updated; Decisions count line added at end of §7. |
Framing answers — agree
- UC8/UC16 extra hop: agreed, acceptable for v2 if PR-D ships composite hints; materialized views remain out of scope (§5 row unchanged).
cardinality: kept (informational, cheap, useful for future invariants and the generated doc).- Producer 1:1 with Client: agreed — §3.2 now explicitly states Producer is not field-for-field with Client; grounded in real data sources.
- Bundle HINTS-V3?: agreed split, agreed not to schedule PR-D until v3 propose exists (Decision 30 locks this as a hard gate).
Cardinals after this revision
- 4 PRs · 23 UCs · 11 edges · 32 decisions (was 21). All match across TL;DR, §6, §7.
- Decisions 22–32 added.
- 6 new §3 subsections (§3.6–§3.11), §3.12 is the renumbered hints-v3 preview.
Pre-merge checklist (re-checked)
- Schema / re-index subsection — §3.6
-
brownfield_sourcedsemantics — §3.11, Decision 28, renamed - Downstream API table — §3.7
- Type-level describe rollups decision — §3.8, Decision 25
- Fix pass5 reference in §3.4
- HINTS-V3 stub or PR-D blocked — PR-D blocked (Decision 30); v3 propose to be drafted next
- Producer field names aligned with
AsyncProducerHint— §3.2 rewritten
Ready for review-2 when you have cycles. If you want me to draft HINTS-V3-PROPOSE.md before the next review pass, say the word.
Breaking changes allowed (no active users) reconfirmed. Review-1's 'external API stable across v2' framing on \xc2\xa73.7 / Decisions 22\xe2\x80\x9324 was self-imposed compatibility ceremony \xe2\x80\x94 not principled, and actively working against the v2 principle (edges connect the nodes whose data the edge is about). Applied: - \xc2\xa73.7: APIs return the caller-side node (Client or Producer), not the declaring Symbol. CallerInfo is renamed and reshaped to RouteCaller with caller_node_id, caller_node_kind, declaring_symbol_id (back-ref), plus caller-side metadata pulled from the node. - Decision 22 rewritten: RouteCaller replaces CallerInfo; old shape removed; no back-compat alias. - Decision 23 rewritten: trace_request_flow output surfaces the Client/Producer hop directly. UC5 visibility is now first-class in API output, not hidden behind a join. - Decision 24 rewritten: impact-analysis output gains caller-side node id alongside each route. - PR-B test summary updated to reference the reshaped RouteCaller. - Appendix B note added. Decisions count unchanged (32). PR/UC/edge counts unchanged.
|
Follow-up — breaking-changes-allowed correction (commit Reconfirmed: no active users, no real users in the wild. Review-1's §3.7 framing ("external API stable across v2") was self-imposed compatibility ceremony I added under a soft reading of "breaking changes allowed." That framing actively worked against the v2 principle ("edges connect the nodes whose data the edge is about"), because the data answering "who calls this route?" lives on the Client/Producer, not on the Symbol. Reverted to the principled shape:
No change to PR count (4), UC count (23), edge count (11), decision count (32). The change is one principle correction propagated through three locked decisions and the test summary. |
Draft propose. Locks the schema fix for the May 16 cross-service trace pain and applies the same fix to async — the half-modeling bug exists in both channels (HTTP has a Client node the edge bypasses; async has no producer node at all). Both ship in v2 so the canonical Edge Navigation Schema isn't published with a known asymmetry.
What this propose decides
HTTP_CALLSmoves fromSymbol → RoutetoClient → Route.ASYNC_CALLSmoves fromSymbol → RoutetoProducer → Route. NewProducernode mirrorsClient.DECLARES_PRODUCER(Symbol → Producer)parallelsDECLARES_CLIENT.EDGE_SCHEMA: dict[str, EdgeSpec]lands injava_ontology.py(same ontology home pattern asFUZZY_STRATEGY_SET).docs/EDGE-NAVIGATION.mdis generated fromEDGE_SCHEMA. CI fails on hand-edit or DDL/ontology disagreement.EDGE_SCHEMAin PR-D; the v3 design itself lives in a separateHINTS-V3-PROPOSE.md.Migration — 4 PRs
EDGE_SCHEMA+ doc generator + CI invariants. No DDL flips yet — schema-as-source-of-truth lands first.HTTP_CALLSendpoints in DDL + pass6 + all callers + tests.Producernode +DECLARES_PRODUCER+ flipASYNC_CALLSendpoints. Includes producer-side parallels of brownfield tests.EDGE_SCHEMA.Out of scope (explicitly)
AsyncConsumernode — no@CodebaseConsumerannotation exists; open follow-up if one is added.NODE_SCHEMA/ multi-target Client/Producer modeling — all separate proposes.Cardinals
DECLARES_PRODUCER).Revision history
First draft was HTTP-only and scoped out async on the grounds that "no AsyncClient analog node exists." That was wrong —
@CodebaseProduceralready exists in the annotation set (ast_java.py:180) and produces metadata that is currently lost on the edge. Same half-modeling bug as HTTP, one stage earlier. Async fix folded in; framing lifted to the principle. Full traceability in Appendix B.Framing questions for reviewers
cardinalityis informational only (kuzu doesn't enforce). Worth keeping, or trim to keepEdgeSpecminimal?Producerfield shape mirrorsClient1:1. Should it be reviewed in PR-C against actualAsyncProducerHintdata, or are the obvious analogs (target_topic↔target_service,topic↔path,broker↔method) good enough to lock here?cc @HumanBean17