Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
reviewPR and analyzeImpact now consume LIP's QueryBlastRadiusBatch to supplement SCIP static call graph with embedding-based semantic coupling. One round-trip prefetch for all changed files, gated behind lipSupports. Key invariant: UniqueCallerCount stays SCIP-only so review thresholds never inflate from embedding noise. Semantic callers are additive in SemanticCallerCount and carry a per-caller CouplingTier (static/semantic/ both) so consumers can distinguish certainty levels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e helpers AnalyzeImpact now enriches blast radius with LIP semantic coupling on the same lipSupports gate as reviewPR. Both paths share lip.EntryToExternal and lip.LookupSymbol — the private duplicates in review_blastradius.go are removed. BlastRadiusEnricher.EnrichBatch is now actually used. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CouplingStatic was defined but never referenced — SCIP-only callers go into UniqueCallerCount, not EnrichedCallers. Flagged by ckb review dead-code check on develop. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `renderArchitecture` MCP tool that returns the project's module-level import graph as Mermaid or Graphviz (DOT), ready to paste into IDEs that render Mermaid inline. With `focus` set, returns an undirected BFS neighborhood around the anchor module; without, returns the top-N most-connected nodes. `truncated: true` flags when the node cap kicked in. Wire the tool end-to-end: Go binding `RenderArchitecture` in `internal/cartographer/bridge.go` (+ no-op stub), schema + registration in `internal/mcp/tools.go`, handler in `tool_impls_v86.go`. Vendored `lib.rs` gets a surgical patch (`mod diagram;` + FFI export) and the regenerated `cartographer.h`; new `src/diagram.rs` holds the shared renderer used by CLI and FFI. Fix link-time duplicate-symbol collisions with `go-tree-sitter` under `-tags cartographer`. `make build-cartographer` now runs the vendored `scripts/localize-tree-sitter-symbols.sh` after cargo's release build: it partial-links archive members so Cartographer's internal ts_*/tree_sitter_* references resolve within the archive, then marks those symbols local. cartographer_* FFI exports stay global. Beyond unblocking the build, this prevents a silent memory-corruption class of bug where Cartographer's Rust code could have bound to the consumer's tree-sitter copy at global resolution if the two versions' struct layouts ever drifted. Also relocate `ErrUnavailable` from `bridge_stub.go` into `types.go` so it's visible under both tag variants (the tagged bridge references it unconditionally). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
calculateAggregatedRisk now multiplies the weighted-mean score by 1 + max(BridgeScore)/1000 (capped at 2x) over the graph nodes matching the changed files, so a change landing on a critical architectural path is reported as riskier than the same-shape change in a leaf module. CARTOGRAPHER_STRATEGY.md had already claimed this behaviour — this commit makes it real. The lookup matches files by both Path and ModuleID. If no changed file matches the graph (or the build is without -tags cartographer, where MapProject returns ErrUnavailable), the multiplier is 1.0 and no informational factor is appended — bridge weighting is additive, never punitive when data is missing. A new `bridge_centrality` RiskFactor surfaces in RiskScore.Factors when the multiplier fires. Its Weight is 0 because it applies multiplicatively, not as a weighted-mean input; Value carries the raw max(BridgeScore)/1000 for consumer display. Pure helper bridgeMultiplierFromGraph has 8 subtests covering empty inputs, path/module matching, max-across-files, 2x cap, and path-wins tiebreak. No cartographer build tag needed for the unit test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… query
QueryBlastRadiusBatch now returns *BlastRadiusBatchResult instead of a
bare map, so callers can tell "file not in the LIP index" apart from
"indexed, zero callers" — same on-wire format, new struct wrapper
exposes the not_indexed_uris list the daemon already returns. Callers
in blast_radius.go and review_blastradius.go updated; existing zero-
callers behaviour unchanged.
New QueryBlastRadiusSymbol wraps LIP's v2.3 query_blast_radius_symbol
RPC for direct symbol-URI lookups, sidestepping the batch-and-filter
workaround when the daemon supports it. AnalyzeImpact dispatches to
this path first under lipSupports("query_blast_radius_symbol"), and
falls back to the batch path on older daemons — so old LIP builds
degrade cleanly, new ones skip a round-trip.
BlastRadiusEntry gains a FileURI field mirroring the daemon's response,
so consumers can back-reference symbol→file without reparsing the URI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ize script Vendored diagram.rs was 391 lines behind upstream — syncing pulls in the Overlays feature (cycle borders, layer-violation edge styling, hotspot sizing) so the libcartographer.a that CKB links against produces the same diagrams as the Cartographer CLI. The only vendor-local delta is `at_range: None` stripped from the test edge() fixture, since the vendored api.rs predates GraphEdge.at_range; a NOTE comment marks this for future syncs. All 20 diagram tests pass on the vendored copy. Also fixes a latent bug in localize-tree-sitter-symbols.sh that surfaced when rebuilding from the synced source: the script extracted archive members with `ar x`, but Cargo emits multiple members named parser.o / scanner.o (one per tree-sitter grammar crate), and `ar x` silently clobbers them. After localization the archive ended up with _tree_sitter_c and _tree_sitter_cpp as undefined references, breaking `go build -tags cartographer`. The script now feeds the archive straight to `ld -r` via -force_load (Mach-O) / --whole-archive (ELF), skipping the filesystem extraction entirely so duplicate-named members coexist in combined.o as intended. Verified: go test -tags cartographer -run TestBridgeMultiplierFromGraph links cleanly and passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The vendored Cartographer tree had drifted across 10 .rs files plus Cargo.toml — diagram.rs alone was 391 lines behind. Prior syncs were done file-by-file and kept missing things. Full sync to upstream 3.0.0 closes the gap. FFI surface is purely additive (cartographer_doc_index, cartographer_doc_context, cartographer_query_docs) so CKB's existing Go bindings still link unchanged; the new FFI entry points can get Go bindings in a follow-up when we want to expose doc-graph features through MCP. Upstream's GraphEdge now carries an at_range: Option<Range> field (LIP source position for doc backtick refs) so the vendor-local at_range patch on diagram.rs tests is no longer needed. scripts/sync-cartographer.sh is now the supported path for future syncs — explicit path list rsync from an upstream checkout, so we catch every file the next time upstream changes instead of discovering drift at rebuild time. No local patches are applied; the script will fail loudly if one ever becomes necessary so it's obvious at review time. Verified: all 74 upstream cargo tests pass on the vendored copy; make build-cartographer + go test -tags cartographer link cleanly and the bridge-centrality test passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MCP's cartographer cache is pinned to the current commit hash and regenerated on every startup — not source, shouldn't track. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ApiState::rebuild_graph held the mapped_files lock across its loop and then called resolve_import_target, which re-acquired the same non-reentrant std::sync::Mutex — any repo with a resolvable import deadlocked. diagram and health hung on CKB itself (1093 files) and the Go bridge's cartographer.MapProject blocked under the same condition. Split the resolver: a public method that locks and a private helper that takes the already-held map; rebuild_graph now calls the helper. Fix contributed upstream with a regression test; pulled back into the vendor tree via scripts/sync-cartographer.sh — that sync also brings in the upstream call_graph, diagram_export, and html_export modules along with diagram/main updates from upstream [Unreleased].
Adds FoldExternalStaticItems in internal/impact/enricher.go. Folds LIP's DirectItems / TransitiveItems into SCIP-derived ImpactItem lists, gated on EdgesSource — fold-eligible for tier1 / scip_with_tier1_edges / scip_only, skip for empty. Dedups against existing SCIP callers by (absolute file path, symbol name), filters Phase-4 file-only tails (empty SymbolURI), defaults Distance when LIP omits it. Also plumbs EdgesSource through the LIP client (client.go) and the ExternalBlastRadius adapter (blast_radius.go), and prefers the SCIP- form symbol URI in AnalyzeImpact via the new SCIPSymbolToURI helper so symbols imported from SCIP round-trip cleanly to LIP. This is step 1 of the fold work — the helper and its tests. Step 2 wires it into AnalyzeImpact's item pipeline (before budget truncation) so direct/transitive arrays carry the unioned set. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fetch LIP enrichment up-front in AnalyzeImpact so tier-1 tree-sitter callers fold into result.DirectImpact/TransitiveImpact before budget truncation. Recompute BlastRadius over the unioned set (via new RecomputeBlastRadius) when EdgesSource != empty so UniqueCallerCount/FileCount/RiskLevel reflect LIP's static contribution. Semantic merge via MergeBlastRadius stays in the summary path and reuses the already-fetched external result. Also fix a latent single-symbol CLI gap: convertImpactResponse didn't carry BlastRadius through, so `ckb impact <sym>` always returned blastRadius:null. The diff/changeset path had it; now both paths do. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add RegisterProjectRoot RPC matching LIP v2.3.1 wire shape
({"type":"register_project_root","root":"..."} → DeltaAck) and fire
it from probeHandshake when the daemon advertises support. Once
registered, LIP canonicalises CKB's relative lip://local/<rel>
URIs against the absolute project root via longest-prefix match,
eliminating URI-mismatch bugs of the class hit during the Bug-B
debug cycle.
Feature-gated on HandshakeResult.supported_messages so older daemons
(pre-v2.3.1) skip the call rather than hit UnknownMessage. Empty
repoRoot also short-circuits — test harnesses without a root stay
silent.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors query_blast_radius_symbol for the forward direction. Returns an OutgoingImpactEntry with target_uri, direct_items (callees at distance=1), transitive_items (distance>=2), semantic_items (seeded from the target's embedding), edges_source, and truncated — the same provenance and coupling vocabulary as blast radius so folds can be routed through the shared ExternalBlastRadius pipeline. OutgoingEntryToExternal converts the wire entry to the shared shape with RiskLevel empty — outgoing impact doesn't carry its own classification; CKB will derive one from the unioned callee set when the analyzer path is wired. Adds DirectCallee/TransitiveCallee ImpactKinds so folded items classify correctly once the analyzer fold lands. Analyzer + CLI/MCP surface are deferred until LIP v2.3.3 ships and the wire contract is verified end-to-end. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ounding
Adds a new MCP tool and query engine method that answers "does this bare
symbol name exist in the index?" using a direct WHERE-clause query against
symbols_fts_content, bypassing FTS5 tokenisation entirely. This makes
class methods (saveReport, trackUsage) and object-property declarations
(setApiKey: t.procedure…) reliably findable by bare leaf name — the cases
that caused ~20–30% false-rejection rates in ArchReview's persona-swarm
validator when it used searchSymbols + client-side exact comparison.
Returns { exists, matches, kinds, receivers?, staleIndex? } — a cheap
boolean payload with no locations or ranking noise. Adds a note to the
searchSymbols description pointing callers to symbolExists for
authoritative lookups. Wire into all presets (core + review, refactor,
federation, docs, ops).
Acceptance criteria from the backlog spec all pass (11 tests).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Surfaces LIP v2.3.5's forward call graph ("what does X call?") as a
first-class CKB operation mirroring AnalyzeImpact in the reverse
direction. Requires a daemon advertising query_outgoing_impact;
degrades to an empty response with a provenance warning when the RPC
isn't supported.
- Engine: Engine.AnalyzeOutgoingImpact in internal/query, driven by
the shared LIP fold pipeline via impact.FoldExternalCalleeItems.
- impact: new FoldExternalCalleeItems twin of FoldExternalStaticItems,
both delegating to a shared kind-parameterised fold. Fixed a latent
distance-default bug that treated DirectCallee items as distance=2.
- CLI: ckb impact outgoing <symbolId> with --min-score / --format.
ProvenanceCLI gained a Warnings field so LIP-unavailable surfaces
cleanly in JSON output.
- MCP: analyzeOutgoingImpact tool registered and dispatched.
Tests cover the engine method against a fake daemon, the fold-level
kind tagging and dedup semantics, and the lip→impact seam end-to-end.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
….0.0 Wire LIP v2.3.5's query_outgoing_impact through the engine, CLI (`ckb impact outgoing`), and MCP (`analyzeOutgoingImpact`). Folds LIP tier-1 callees through the same ImpactItem pipeline as the incoming side and surfaces semantic coupling alongside the static graph. Adds `symbolExists` MCP tool as a cheap boolean oracle for LLMs grounding references before citation. Risk score in `analyzeImpact` now picks up bridge centrality from Cartographer (`1 + max(BridgeScore)/1000`, capped at 2.0) so changes on critical architectural paths score higher than leaf-module changes of the same shape. Sync vendored Cartographer to upstream 3.0.0, fix `rebuild_graph` deadlock, fix tree-sitter symbol collisions at link time, add `renderArchitecture` MCP tool with diagram overlays. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CKB Analysis
Risk factors: Large PR with 59 files • High churn: 10975 lines changed • Touches 33 hotspot(s) 👥 Suggested: @lisa.welsch1985@gmail.com (17%), @talantyyr@gmail.com (14%), @lisa@tastehub.io (10%)
🎯 Change Impact Analysis · 🟢 LOW · 48 changed → 0 affected
Symbols changed in this PR:
Recommendations:
💣 Blast radius · 0 symbols · 9 tests · 0 consumersTests that may break:
🔥 Hotspots · 33 volatile files
📦 Modules · 3 at risk
📊 Complexity · 7 violations
💡 Quick wins · 10 suggestions
📚 Stale docs · 197 broken references
Generated by CKB · Run details |
NFR Tests ✅ 39 unchangedComparing PR against main branch (dynamic baseline). Regressions: 0 ✅ Thresholds: WARN ≥ +5% • FAIL ≥ +10% All scenarios
* = new scenario, compared against static baseline |
CKB Review: 🟡 WARN — 51/10059 files (+10975 changes) · 16 modules ·
Top Risks
Findings (23 actionable, 24 informational)
... and 13 more ✂️ Suggested PR Split (14 clusters)
... and 4 more clusters Code Health — 3 degradedDegraded:
^1 File could not be parsed by tree-sitter New files: 5 (avg health: 71) 3 degraded · 0 improved · avg -0.2 Estimated review: not feasible as a single PR (59 files, 10975 lines, 14 clusters) Reviewers: lisa.welsch1985 (17%) · talantyyr (14%) · lisa (10%) |
golangci-lint flagged gofmt drift across the v9.2.0 surface (impact types, MCP tool registration, symbol_exists, etc.). Apply gofmt to all 9 files. scip-go upstream renamed its module path from github.com/sourcegraph/scip-go to github.com/scip-code/scip-go. The release at v0.2.3 declares the new path in go.mod, which makes the old import error out with a version-constraints conflict. Update the install command in ci.yml, cov.yml, and ckb.yml; also update the human-readable hint printed when the indexer is missing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
🟢 Change Impact Analysis
Blast Radius: 0 modules, 0 files, 0 unique callers 📝 Changed Symbols (48)
Recommendations
Generated by CKB |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #221 +/- ##
=======================================
+ Coverage 43.1% 43.3% +0.1%
=======================================
Files 530 534 +4
Lines 81525 82420 +895
=======================================
+ Hits 35200 35749 +549
- Misses 43825 44167 +342
- Partials 2500 2504 +4
Flags with carried forward coverage won't be shown. Click here to find out more. 📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
The test fake daemon recorded incoming requests via a goroutine appending to a shared []map[string]any while the test main goroutine read it through the snap() closure. Race detector caught this on CI (TestAnalyzeOutgoingImpact_HappyPath). Wrap append and read with sync.Mutex; snap() takes the lock around its copy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
analyzeOutgoingImpact— forward call graph (MCP + CLI). Mirror ofanalyzeImpactanswering "what does this symbol call?" — drives off LIP v2.3.5'squery_outgoing_impactRPC, folds through the sameImpactItempipeline, surfaces semantic callees alongside static. Degrades cleanly when LIP is down.symbolExistsMCP tool — exact-match boolean oracle ({exists, kind, location?}) for LLMs grounding references before citation. Cheaper thangetSymbolfor the existence check.analyzeImpact— tree-sitter callers LIP discovers (when scip-go emits no Call roles) become first-class impact items rather than sitting in a parallel summary field. Driven by newBlastRadiusEnricherinterface so incoming/outgoing share one fold pipeline.register_project_rooton LIP handshake — daemon canonicalises file URIs against a known anchor, fixing tier-1 dedup against SCIP results.analyzeImpactnow multiplies the weighted-mean risk by1 + max(BridgeScore)/1000(capped at 2.0) over changed files, so changes on critical architectural paths score higher.rebuild_graphmutex deadlock, fixes tree-sitter symbol collisions at link time, addsrenderArchitectureMCP tool with diagram overlays (cycles, hot nodes, layer violations).Test plan
go test ./...green on developgo test -race ./...(release pipeline runs this)lip-cli 2.3.5: 39 direct / 160 transitive callees onEngine.AnalyzeImpact,edges_source=scip_with_tier1_edges, truncation surfaces correctlyLIP_SOCKETunset,ckb impact outgoingreturns empty result + warning, no errorv9.2.0after merge to trigger GoReleaser → Homebrew tap → npm publish🤖 Generated with Claude Code