feat(schema, mcp, hints): phantom-receiver/chained sites move to UnresolvedCallSite; include_unresolved; CALLS dedup#185
Conversation
…llSite facet Receiver-failure chained/phantom sites emit UnresolvedCallSite + UNRESOLVED_AT instead of phantom-dst CALLS. neighbors gains include_unresolved interleave, dedup_calls, row_kind, and new hints; describe and unresolved-calls CLI wire up. Co-authored-by: Cursor <cursoragent@cursor.com>
HumanBean17
left a comment
There was a problem hiding this comment.
Critical review (PR-3 / CALLS-NOISE)
Verdict: Direction is right and the core invariant holds, but I would not merge as-is without fixing the sym: ID footgun and adding the plan-mandated describe/CLI tests.
What works well
- Graph split matches the propose: receiver-failure (
chained_receiver, unresolved-receiverphantom) →UnresolvedCallSite+UNRESOLVED_AT; known-external JDK rows stay onCALLSwith preserved receiver-tier strategy. Pass3 + smoke tests lock this in. - MCP behavior is coherent:
include_unresolved↔edge_filtermutual exclusivity is fail-loud; interleave sort(line, byte, resolved-before-unresolved)matches the plan;dedup_callsonly collapses resolved rows. - Ontology cleanup is careful:
phantom/chained_receiverleaveFUZZY_STRATEGY_SETbut stay inBROWNFIELD_RESOLVER_STRATEGY_SETfor HTTP/ASYNC; schema consistency correctly excludesUNRESOLVED_ATfromEDGE_SCHEMAparity.
Blockers (fix before merge)
1. UnresolvedCallSite IDs look like Symbols — describe will mislead agents
UCS ids are {caller_id}:{line}:{byte} where caller_id is sym:…, so UCS ids start with sym:. In interleaved neighbors output they are exposed as NodeRef(id=ucs_id, kind="symbol", …).
_node_kind_from_id treats any sym: prefix as a Symbol. The completed propose says UCS is intentionally not a Symbol node. An agent that follows edge.other.id into describe gets a bogus symbol (usually “no node found”) — wrong affordance on a CALLS-shaped edge.
Suggested fix: dedicated id prefix (ucs: / unresolved:) + new NodeRef.kind, or keep other.id as the caller and put the site id only in attrs (you already have unresolved_call_site_id).
2. Plan-mandated tests are missing
| Planned coverage | Present? |
|---|---|
describe rollup: cap 5 + footer + total |
No — unresolved_call_sites_* never asserted in tests |
java-codebase-rag unresolved-calls list|stats |
No CLI test (manual evidence only) |
VALID_UNRESOLVED_CALL_REASONS for CLI --reason |
No — constant defined but unused |
These guard the operator/debug path (HV8/HV9) that replaces grepping CALLS for phantom/chained_receiver.
Important non-blockers
- GraphMeta pass3 percentages:
phantom_chained/phantom_otherare UCS counts but still divided bystats.total(CALLS rows only) — verbose log line can mislead. Use a denominator that includes UCS or drop percentages. - README ontology section still says “Unresolved targets become phantom nodes” and the edge-types table omits
UNRESOLVED_AT/UnresolvedCallSite— contradicts PR-3 after the re-index callout was updated. - High-fanout hint uses
len(results); with defaultlimit=25, a 57-CALLS method shows “25 CALLS on this method…”. Tests uselimit=500. Consider passing true fan-out or documenting page-local counts. docs/EDGE-NAVIGATION.mduntouched — worth noting UCS is not inEDGE_SCHEMA.
Minor / follow-up
- Duplicate
test_find_callers_no_phantom_chained_strategyintest_kuzu_queries.pyandtest_mcp_v2.py. plans/PLAN-CALLS-NOISE.mdstill “active” while propose is incompleted/.unresolved_counthint only whenlen(origins)==1.
Recommendation
Minimal merge bar: (1) id/kind fix + (2) one describe rollup test + one CLI smoke test. Everything else can be a fast follow-up.
…e CALLS count UnresolvedCallSite ids use ucs: prefix with NodeRef.kind unresolved_call_site so describe is not mis-routed. Add rollup and CLI smoke tests; wire --reason choices; fix pass3 UCS percentage denominator and README graph section. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Thanks for the thorough review — agreed on both blockers and most of the non-blockers. Pushed Blockers (fixed)1. UCS ids looked like Symbols — Agreed this was a real footgun. 2. Missing tests — Added:
Non-blockers (fixed)
Also: removed duplicate Deferred (agree, follow-up)
|
HumanBean17
left a comment
There was a problem hiding this comment.
Critical review (PR-3 / CALLS-NOISE)
Verdict: approve with minor follow-ups. Scope matches plans/PLAN-CALLS-NOISE.md PR-3, CI is green, and the breaking change is documented with solid test coverage. The second commit (ucs: ids, fan-out hint denominator, CLI smoke) addresses real review issues.
What works well
- Graph split — Receiver-failure (
chained_receiver, unresolved-receiver phantom) off phantom-dstCALLSintoUnresolvedCallSite+UNRESOLVED_AT; known-external JDK rows stay onCALLSwithresolved=false. Matches the propose framing. ucs:ids — Avoids mis-parsing embeddedsym:prefixes fromcaller_id:line:byte.- MCP contract — Interleave order
(line, byte, resolved before unresolved),include_unresolved⊥edge_filter,dedup_callspreserving unresolved rows; fan-out hints usecalls_row_count(true graph count), not page size. - Ontology —
FUZZY_STRATEGY_SETtrimmed for CALLS; phantom/chained remain inBROWNFIELD_RESOLVER_STRATEGY_SETfor HTTP/ASYNC.UNRESOLVED_ATexcluded fromEDGE_SCHEMAintest_schema_consistency. - Tests — Plan table scenarios covered; post-build invariant (zero
phantom/chained_receiveronCALLS) is strong.
Suggested follow-ups (non-blocking)
1. describe(id=ucs:…) — fail-safe but not fail-loud (medium)
_resolve_node_kind returns unresolved_call_site for ucs: prefixes, but _load_node_record only handles symbol/route/client/producer; any other kind falls through to the Producer branch, so describe(ucs:…) becomes MATCH (n:Producer) … → generic "No node found".
That avoids mis-routing to Symbol, but agents won’t get the teaching message AGENT-GUIDE promises (“not describable; use caller describe / unresolved-calls”). Consider an early guard in describe_v2 and test_describe_ucs_id_not_describable.
2. README vs AGENT-GUIDE (low)
README graph section says receiver-failure sites are reachable via describe — easy to read as “describe the UCS node”. AGENT-GUIDE is clearer. Suggest: describe(method_id).unresolved_call_sites only.
3. docs/EDGE-NAVIGATION.md (low)
No mention of UnresolvedCallSite or that CALLS no longer carries receiver-failure strategies. Worth a short add for agents using that doc as the edge catalog.
4. Housekeeping when closing the effort
- Propose in
propose/completed/still says Status: under review. plans/PLAN-CALLS-NOISE.mdstill references root propose path / unchecked landing todos — fine until merge, then one cleanup commit.
5. Multi-origin neighbors hints (low)
unresolved_count / calls_row_count for hints only when len(origins) == 1. Multi-origin CALLS won’t get high-fanout / has-unresolved nudges — OK if intentional; one AGENT-GUIDE line if not.
Test gaps (optional hardening)
| Gap | Note |
|---|---|
No describe_v2("ucs:…") test |
Commit message mentions describe routing; only method rollup is tested |
test_hints_neighbors_calls_has_unresolved |
Checks template prefix only, not {k} vs unresolved_count |
dedup_calls + include_unresolved together |
Plan defines ordering; combined path untested |
Operator reminder
Merge requires full re-index at ontology 15. Default neighbors(..., ['CALLS']) row counts will drop on hot methods (expected). edge_filter.exclude_strategies: ['phantom','chained_receiver'] on CALLS becomes a no-op on fresh graphs (harmless).
…ix, tests describe rejects ucs: ids with a teaching message; generator documents UnresolvedCallSite storage; tighten has-unresolved hint and combined dedup+interleave tests. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Round 2 addressed in Done
Still deferred
Ready for merge after re-index reminder stands (ontology 15). |
Summary
chained_receiver, unresolved-receiverphantom) move from phantom-dstCALLSrows toUnresolvedCallSite+UNRESOLVED_AT. Known-receiver-external JDK rows stay onCALLSwithresolved=false.neighborsgainsinclude_unresolved(source-ordered interleave withrow_kind),dedup_calls(collapse identical callees), and mutual exclusivity withedge_filter.TPL_NEIGHBORS_CALLS_HIGH_FANOUT,TPL_NEIGHBORS_CALLS_HAS_UNRESOLVED),describeunresolved rollup (cap 5), andjava-codebase-rag unresolved-calls list|statsCLI.Implements PR-3 from
plans/PLAN-CALLS-NOISE.md. Propose moved topropose/completed/CALLS-NOISE-AND-RESOLUTION-PROPOSE.md.Test plan
.venv/bin/ruff check ..venv/bin/python -m pytest tests -v(668 passed; use.venv/binonPATHfor CLI tests)CALLSwithstrategy in ('phantom','chained_receiver')on fresh bank indexjava-codebase-rag unresolved-calls statsreturns reason buckets (205 sites on bank fixture)Made with Cursor