@@ -4,6 +4,132 @@ All notable changes to CKB will be documented in this file.
44
55## [ Unreleased]
66
7+ ## [ 9.2.0] - 2026-04-25
8+
9+ ### Added
10+
11+ - ** ` analyzeOutgoingImpact ` — forward call graph** (MCP + CLI) — mirror
12+ of ` analyzeImpact ` answering * "what does this symbol call?"* instead of
13+ * "who calls it?"* . New ` Engine.AnalyzeOutgoingImpact ` drives off LIP
14+ v2.3.5's ` query_outgoing_impact ` RPC, folds the result through the same
15+ ` ImpactItem ` pipeline as the incoming side (with ` direct-callee ` /
16+ ` transitive-callee ` kinds), and surfaces semantically coupled callees
17+ alongside the static graph. Degrades cleanly when LIP isn't running:
18+ the response is empty with a provenance warning, never an error.
19+ Surfaces include ` ckb impact outgoing <symbolId> ` (with ` --min-score `
20+ for the semantic threshold), the ` analyzeOutgoingImpact ` MCP tool, and
21+ a new ` ProvenanceCLI.Warnings ` field so LIP-degradation messages reach
22+ JSON consumers.
23+ - ** ` symbolExists ` MCP tool** — exact-match boolean oracle that returns
24+ ` {exists, kind, location?} ` for a fully-qualified symbol ID. Built for
25+ LLMs to ground references * before* they cite them in code, without
26+ spending tokens on a 20-result ` searchSymbols ` payload. Cheaper than
27+ ` getSymbol ` for the "does this thing actually exist" check.
28+ - ** LIP enrichment folds into ` analyzeImpact ` ** — tier-1 tree-sitter
29+ callers that LIP discovers (when ` scip-go ` emits no ` Call ` roles, e.g.
30+ Go method dispatch) are now folded into the same ` directImpact ` /
31+ ` transitiveImpact ` lists as SCIP's own results, deduplicated by
32+ ` (file, name) ` . Driven by a new ` BlastRadiusEnricher ` interface so the
33+ fold path is the single source of truth for both incoming and outgoing
34+ impact analysis. Items LIP marks ` edges_source=empty ` are skipped (LIP
35+ signalling no static evidence); ` tier1 ` , ` scip_with_tier1_edges ` , and
36+ ` scip_only ` all fold the same way. Risk score now picks up
37+ semantic-coupling signals via the same enricher pipeline.
38+ - ** ` register_project_root ` on LIP handshake** — Engine startup now
39+ registers the repo root with the daemon so LIP canonicalises file URIs
40+ against a known anchor, matching the v2.3.1 contract. Eliminates the
41+ URI-shape drift that previously caused tier-1 callers to dedup
42+ incorrectly against SCIP results.
43+
44+ ### Changed
45+
46+ - ** ` analyzeImpact ` risk score now weighted by bridge centrality** —
47+ ` calculateAggregatedRisk ` multiplies the weighted-mean score by
48+ ` 1 + max(BridgeScore)/1000 ` (capped at 2.0) over the changed files, so a
49+ change landing on a critical architectural path (high betweenness) is
50+ reported as riskier than the same-shape change in a leaf module. Implements
51+ the behaviour that ` CARTOGRAPHER_STRATEGY.md ` had already documented but
52+ the code was not actually doing. Bridge lookups match by both ` Path ` and
53+ ` ModuleID ` ; if no changed file matches the graph, the multiplier is 1.0
54+ and no informational factor is appended. Only runs when the binary was
55+ built with ` -tags cartographer ` (graph is a no-op otherwise). A new
56+ ` bridge_centrality ` informational factor surfaces in ` RiskScore.Factors `
57+ when the multiplier fires; its ` Weight ` is 0 because it applies
58+ multiplicatively, not as a weighted-mean input.
59+
60+ ### Cartographer
61+
62+ - ** Vendored Cartographer fully synced to upstream 3.0.0** — the
63+ vendored tree under ` third_party/cartographer/mapper-core/cartographer/ `
64+ was 391 lines behind on ` diagram.rs ` alone, and 10 ` .rs ` files plus
65+ ` Cargo.toml ` had drifted. Full sync brings in doc-node graph support
66+ (` cartographer_doc_index ` , ` cartographer_doc_context ` , ` cartographer_query_docs `
67+ FFI entry points — Go bindings can be added as a follow-up),
68+ LIP-style ` Range ` / ` at_range ` on ` GraphEdge ` , PascalCase bare-identifier
69+ resolution for doc backtick refs, and the overlays feature on diagrams.
70+ New ` scripts/sync-cartographer.sh ` is now the supported path for future
71+ syncs — rsync-based, explicit path list, emits next-step commands. No
72+ local patches needed against upstream.
73+ - ** Diagram overlays in ` renderArchitecture ` / ` ckb diagram ` ** — the
74+ vendored ` diagram.rs ` was synced from upstream Cartographer, so the
75+ Mermaid/DOT output now decorates the base import graph with
76+ architectural signals: cycle members get a thick red border (pivots
77+ dashed), cycle-internal edges a heavy red arrow, layer violations pick
78+ up per-type dashed/dotted edge styling, and hot nodes
79+ (` hotspot_score ≥ 70 ` ) get an orange border plus DOT size scaling.
80+ Mermaid is border-only for hot nodes (no sizing primitive). Cycle red
81+ takes precedence over hot orange on the same node — architectural
82+ signal wins over performance signal.
83+ - ** ` renderArchitecture ` MCP tool** — returns the project's module-level
84+ import graph as Mermaid or Graphviz (DOT), ready to paste into IDEs
85+ that render Mermaid inline (Cursor, Claude Desktop, VS Code markdown
86+ preview, GitHub). With ` focus ` set, returns an undirected BFS
87+ neighborhood around the anchor module to ` depth ` (default 2); without,
88+ returns the top-N most-connected nodes (default cap 40). Response
89+ includes ` truncated: true ` when the node cap kicked in. Backed by the
90+ new ` cartographer_render_architecture ` FFI export; CLI and MCP outputs
91+ are produced by the same shared renderer.
92+ - Go binding ` cartographer.RenderArchitecture() ` in ` internal/cartographer/bridge.go ` (+ no-op stub for the no-tag build).
93+
94+ ### Fixed
95+
96+ - ** Vendored Cartographer ` rebuild_graph ` deadlock** — upstream
97+ ` ApiState::rebuild_graph ` held the ` mapped_files ` Mutex across its
98+ loop and then called ` resolve_import_target ` , which re-acquired the
99+ same non-reentrant ` std::sync::Mutex ` . Any project with a resolvable
100+ import deadlocked — the ` cartographer diagram ` / ` cartographer health `
101+ CLIs hung, and the Go bridge's ` cartographer.MapProject ` would block
102+ any time CKB fed it a repo with imports. Fixed in the vendored tree
103+ (and contributed back upstream) by splitting the resolver: a public
104+ method that locks, and a private helper that takes the already-held
105+ map; ` rebuild_graph ` now calls the helper. Discovered during
106+ end-to-end smoke testing against CKB itself (1093 files). Regression
107+ test added upstream.
108+ - ** ` localize-tree-sitter-symbols.sh ` dropped grammar C parsers** — the
109+ script extracted archive members via ` ar x ` , which silently clobbers
110+ files when multiple members share a name. Cargo emits a ` parser.o `
111+ and ` scanner.o ` per grammar crate (tree-sitter-c, -cpp, -rust, -go,
112+ etc.), so ` ar x ` left only the * last* grammar's C parser on disk,
113+ producing a localized archive missing ` _tree_sitter_c ` / ` _tree_sitter_cpp ` .
114+ The script now feeds the archive directly to ` ld -r ` with
115+ ` -force_load ` (Mach-O) / ` --whole-archive ` (ELF), which pulls every
116+ member in without touching the filesystem. The ` rust_tree_sitter ` C
117+ ABI refs to ` _tree_sitter_c ` and ` _tree_sitter_cpp ` now resolve
118+ inside the combined object as expected.
119+ - ** Tree-sitter symbol collisions at link time** — ` libcartographer.a `
120+ previously exported its bundled tree-sitter runtime and grammar
121+ symbols, which collided with ` go-tree-sitter ` when building CKB with
122+ ` -tags cartographer ` (` ld: 246 duplicate symbols ` ). ` make build-cartographer `
123+ now post-processes the archive via
124+ ` scripts/localize-tree-sitter-symbols.sh ` (vendored under
125+ ` third_party/cartographer/mapper-core/cartographer/scripts/ ` ), which
126+ partial-links archive members into one combined object and localizes
127+ ` ts_* ` / ` tree_sitter_* ` . ` cartographer_* ` FFI exports stay global.
128+ Beyond the duplicate-symbol error, this also rules out a silent
129+ memory-corruption class of bug where Cartographer's Rust code could
130+ have bound to the consumer's tree-sitter copy at global resolution
131+ time if the two versions' struct layouts ever drifted.
132+
7133## [ 9.1.0] - 2026-04-16
8134
9135### Added
0 commit comments