Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,8 @@ the query token.

Practical consequence: `impact <ClassName>` on a class-like symbol returns the heuristic file-dependency-hint fallback (with metadata edges) when no member-level callers exist, whereas default `callers <ClassName>` returns only executable edges. Both are correct under their own contracts; counts will not match. To reconcile, run `references <ClassName> --kind attribute` (or `annotation`), or pass an explicitly supported non-default kind to `callers` / `callees`, to surface edges that the default call graph intentionally drops.

For a single C# logical partial family on a current reference-identity contract, impact resolution precedes the physical-file ambiguity guard. `ResolveImpactDefinitions` retains the representative output plus a separately bounded set of every physical family symbol ID and path. `GetTransitiveCallers` queries that ID set as one SQL union root, so candidate rows, callers, cycle nodes, and converging paths are deduplicated before BFS accounting; file-hint fallback resolves member names across every retained family path and excludes all declaration files from dependents. Physical family expansion uses `DefaultImpactPartialFamilyMemberBudget`, reported through `partial_family_member_*`, and never sets the ordinary result `truncated` / `truncated_reason` fields. A stale reference-identity contract keeps symbol-root scope and preserves physical multi-file ambiguity because legacy traversal cannot guarantee the family ID/path union. When the family expansion is capped, CLI count JSON marks the count degraded and non-authoritative, and MCP count-only returns `total: null`. Only equal logical partial keys may enter this path; multiple logical keys, including unrelated same-name namespace or language symbols, retain the established ambiguity result.

`impact --json` and MCP `impact_analysis` expose zero-result diagnostics as structured routing fields. `zero_result_reason` remains the compact terminal reason; `impact_failure_chain` lists failed preconditions or traversal states in order, using values such as `definition_not_found`, `callable_filter_fails`, `multiple_definitions`, `multiple_definition_files`, `graph_unavailable`, `depth_requested_zero`, and `no_callers`. `suggestion_type` classifies the prose `suggestion` as `resolution`, `traversal`, or `precondition`. CLI `impact --strict` exits with `FeatureUnavailable` when the chain contains a resolution or precondition failure, but still treats a genuine `no_callers` traversal result as success.

`definition --json` and MCP `definition` results may include `disambiguator` for C# definitions when existing symbol metadata can distinguish otherwise identical names. Current values include `overload(...)` for method signatures, `partial-class` / `partial-struct` / `partial-interface`, and `extension-method-on(<receiver>)`. Languages without overload or receiver metadata omit the field.
Expand Down Expand Up @@ -6105,6 +6107,8 @@ before/after 合計と理由別の affected / removed 件数を加える。汎

実運用上の帰結: クラスのようなシンボルに対する `impact <ClassName>` は、member-level の caller が存在しない場合 heuristic file-dependency-hint fallback (metadata エッジを含む) を返し、一方の既定 `callers <ClassName>` は実行可能 edge だけを返す。両方とも個々の契約上は正しいが、件数は一致しない。差分を埋めるには `references <ClassName> --kind attribute`(または `annotation`)を使うか、`callers` / `callees` に明示的に対応する非既定 kind を渡し、既定 call graph が意図的に落としている edge を確認する。

reference-identity contract が current な単一の C# 論理 partial family では、impact resolution を物理ファイルの ambiguity guard より先に行います。`ResolveImpactDefinitions` は代表出力に加え、全物理 family の symbol ID / path を独立した上限付き集合として保持します。`GetTransitiveCallers` はその ID 集合を単一 SQL union root として問い合わせるため、candidate row、caller、cycle node、収束 path を BFS の計数前に重複排除します。file-hint fallback は保持した全 family path から member 名を解決し、全 declaration file を依存先候補から除外します。物理 family 展開には `DefaultImpactPartialFamilyMemberBudget` を使い、`partial_family_member_*` で報告し、通常の result 用 `truncated` / `truncated_reason` fields は立てません。reference-identity contract が stale の場合は legacy traversal のため symbol-root metadata を維持します。family 展開が上限に達した count は CLI JSON で degraded / non-authoritative とし、MCP count-only では `total: null` を返します。この経路へ入るのは論理 partial key が同一の場合だけで、無関係な同名 namespace / language symbol を含む複数 logical key は従来どおり ambiguity result を維持します。

`impact --json` と MCP `impact_analysis` は、0 件診断を structured routing field として返します。`zero_result_reason` は端末向けの短い理由のまま残し、`impact_failure_chain` は `definition_not_found`、`callable_filter_fails`、`multiple_definitions`、`multiple_definition_files`、`graph_unavailable`、`depth_requested_zero`、`no_callers` などの失敗前提や traversal 状態を順序付きで列挙します。`suggestion_type` は prose の `suggestion` を `resolution`、`traversal`、`precondition` に分類します。CLI `impact --strict` は chain に resolution / precondition failure が含まれる場合は `FeatureUnavailable` で終了しますが、真正な `no_callers` traversal 結果は成功として扱います。

`definition --json` と MCP `definition` の結果は、既存の symbol metadata で同名定義を区別できる C# 定義に対して `disambiguator` を含む場合があります。現行値は method signature 用の `overload(...)`、`partial-class` / `partial-struct` / `partial-interface`、`extension-method-on(<receiver>)` です。overload や receiver metadata を持たない言語ではこの field を省略します。
Expand Down
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ Use `docs/test-doc-maintenance-plan.md` before moving oversized suites or adding
Deps JSON summary output and json-graph summary rejection share one SQL graph fixture.
Dependency-cycle coverage must prove that the graph budget is independent of the display limit, SCC ranking remains stable when the page size grows, opaque cursors return the next ranked component, mismatched cursor filters fail closed, and graph-budget exhaustion marks totals as non-authoritative.
Impact-cycle coverage must distinguish consecutive same-display-name symbols by canonical source/target IDs, verify their structured shortest-path identities, keep unresolved upstream callers and non-unique resolved overload groups out of only the canonical cycle graph, avoid guessed IDs for ambiguous path roots, aggregate mixed target identities without undercounting, and retain controls for direct singleton recursion and multi-node cycles.
Partial-family impact coverage must keep declarations, implementations, duplicate downstream callers, a member-to-member cycle, an unrelated same-name symbol, and a small instance-scoped family budget in one fixture family. Assert logical-root identity and physical evidence separately, prove stale reference identity does not claim logical traversal, and prove family-member truncation leaves ordinary traversal truncation unset while making count output non-authoritative (`total: null` for MCP). Fixtures that need production-equivalent partial grouping must pass `familyScopeKey` where applicable and stamp both C# hotspot-family and reference-identity readiness.
Exact-symbol dependency coverage reuses the C# source-candidate fixture to prove that a `--limit 1` query can select a symbol beyond the unfiltered candidate window. The repository-scale guard builds 10,001 candidate symbols, runs on non-Windows .NET 8, and keeps query-only work within 2 seconds and 32 MiB of current-thread allocation; fixture construction stays outside the measured interval. Windows retains the lightweight functional pushdown coverage but omits this scale fixture because its bounded full-suite session already runs close to the one-hour timeout.
References stale-SQL-contract count and result envelopes share one downgraded graph fixture.
Callers and callees stale-SQL-contract result envelopes share one downgraded graph fixture.
Expand Down Expand Up @@ -1356,6 +1357,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
filterなしの`languages --json` catalog coverageはcommandを1回だけ実行し、canonical language辞書を1つ構築して、extension、alias、extraction、graph、gap、guidance、exact-filenameの各contractをまとめて検証してください。言語coverageの拡張でcatalog discoveryとserializationを繰り返さないようにします。
option風literalのnamed-query escapingは、definition、graph、symbols、files、inspect、impact command全体で1つのindexed Probe fixtureを再利用してください。
impact cycle の回帰 coverage では、同じ表示名が連続する別 symbol を正規 source/target ID で区別し、構造化 shortest-path identity を検証し、未解決の上流 caller と一意でない resolved overload group を正規 cycle graph からだけ除外し、曖昧な path root に推測 ID を付けず、複数 target identity を過少計上せず集約するとともに、直接 singleton 再帰と複数 node cycle の control を維持してください。
partial-family impact coverage は declaration、implementation、重複する downstream caller、member 間 cycle、無関係な同名 symbol、小さい instance-scoped family budget を 1 つの fixture family にまとめてください。論理 root identity と物理 evidence を別々に assert し、stale な reference identity が logical traversal を名乗らないこと、family-member truncation が通常の traversal truncation を立てず count output を non-authoritative(MCP は `total: null`)にすることを確認します。本番同等の partial grouping が必要な fixture は必要に応じて `InsertIndexedFile` に `familyScopeKey` を渡し、C# hotspot-family と reference-identity の readiness を両方 stamp してください。
複数 named-query の output coverage は、compact projection、rich JSON 互換性、query ごとの limit / truncation、UTF-8 byte cap に1つの indexed fixture を再利用し、serializer mode を直接比較できるようにしてください。
共通 bounded-response coverage は、definition、find、status、hotspots、references、callers / callees、impact、map 全体で1つの graph-ready databaseを再利用してください。cursor と UTF-8 byte-budget の境界 case は別の最小 multi-row fixture にまとめ、family parity のために indexing setup を重複させないでください。outline は、長い signature と Unicode を含む深い階層の focused fixture 1つを使い、最後の改行を含む正確な byte 境界、欠落や重複のない cursor 全 page 走査、最小 budget の diagnostic、上限なし出力の非変更を確認してください。regression coverage では alias と read-only batch dispatch、明示的な definition body projection、inactive な impact collection、authoritative な総件数を持つ map section の row 単位 pagination も確認してください。
adversarial な bounded-response coverage では、parser failure の byte cap、impact definition page の offset、既存 map compact section、map shape control の競合、compact と明示 body の組み合わせ、profile / verbose control record の抽出も固定してください。
Expand Down
35 changes: 35 additions & 0 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,25 @@ dependencies are intentionally part of the graph. Legacy indexes stored those
reads as `call`; they remain readable and keep their historical inclusive behavior
until re-indexed.

When the reference-identity contract is current and every matching C# declaration belongs to one logical partial family, `impact`
uses the family's stable `partial_family_id` as one traversal root and walks the
union of all physical member identities. Callers, file hints, and shortest paths
reached through more than one member are deduplicated; the representative
definition still carries `family_members` as physical evidence. An unrelated
same-name type or member remains ambiguous and is never folded into that family.
With `--with-paths`, the logical root's `path_details` node carries the
representative `definition_path` plus `partial_family_id`.
JSON and MCP responses identify this mode with
`traversal_root_scope: "logical_partial_family"` and
`traversal_partial_family_id`. The `partial_family_member_*` fields report the
eligible physical root count, limit, omitted count, and truncation independently
from the normal result/traversal `truncated` fields. A stale identity contract keeps
`traversal_root_scope: "symbol"` and omits the family-root metadata because the
legacy traversal cannot guarantee the physical-ID union. When the separate family
root limit is reached, CLI count JSON also reports `degraded: true` and
`authoritative_count: false`, while MCP count-only output reports `total: null`;
ordinary traversal `truncated` remains unchanged.

On a current index, cycle detection follows the resolved source/target symbol IDs
on real directed edges. Two distinct methods with the same display name are not a
cycle, while direct recursion is reported as a singleton cycle. JSON caller rows
Expand Down Expand Up @@ -4314,6 +4333,22 @@ member / value read を `member_read` として保存し、callers / callees / i
`call` として保存しているため、引き続き読み取り可能で、再 index するまでは従来の
inclusive な挙動を維持します。

reference-identity contract が current で、一致する C# declaration がすべて 1 つの論理 partial family に属する場合、`impact` は
安定した `partial_family_id` を 1 つの traversal root として使い、全物理 member identity
の和集合を辿ります。複数 member から到達する caller、file hint、shortest path は重複排除し、
代表 definition の `family_members` には物理 evidence を残します。無関係な同名 type / member
は曖昧なままで、この family へ統合しません。JSON / MCP response はこの mode を
`traversal_root_scope: "logical_partial_family"` と `traversal_partial_family_id` で示します。
`--with-paths` では論理 root の `path_details` node に代表 `definition_path` と
`partial_family_id` も含めます。
`partial_family_member_*` fields は物理 root 候補の件数、上限、省略件数、truncation
を通常の result / traversal 用 `truncated` fields とは独立して報告します。identity contract
が stale の場合、legacy traversal は物理 ID の和集合を保証できないため
`traversal_root_scope: "symbol"` のままとし、family-root metadata を省略します。独立した
family root 上限に達した count JSON は CLI で `degraded: true` と
`authoritative_count: false`、MCP count-only で `total: null` を返しますが、通常の traversal
用 `truncated` は変更しません。

current index では、cycle 判定は実在する有向辺の解決済み source/target symbol ID を
辿ります。表示名が同じ別 method は cycle にせず、直接再帰は singleton cycle として
報告します。JSON の caller row は `caller_symbol_id` と、callee を一意に解決できる場合は
Expand Down
27 changes: 27 additions & 0 deletions changelog.d/unreleased/5060.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
category: fixed
issues:
- 5060
affected:
- src/CodeIndex/Database/DbReader.GraphQueries.cs
- src/CodeIndex/Models/QueryResults.cs
- src/CodeIndex/Cli/QueryCommandRunner.Dependencies.cs
- src/CodeIndex/Mcp/McpToolHandlers.ImpactAnalysis.cs
- tests/CodeIndex.Tests/DbReaderImpactTests.cs
- tests/CodeIndex.Tests/QueryCommandRunnerImpactTests.cs
- tests/CodeIndex.Tests/QueryCommandRunnerTests.cs
- tests/CodeIndex.Tests/golden/impact.json
- tests/CodeIndex.Tests/McpServerTests.cs
- tests/CodeIndex.Tests/McpServerToolsCallTests.cs
- USER_GUIDE.md
- DEVELOPER_GUIDE.md
- TESTING_GUIDE.md
---

## English

- **Impact analysis now traverses one logical partial family as a single root (#5060; follow-up to #4309, #4566, and #3932)** — On current reference identity, C# partial declarations and implementations contribute their union of physical graph identities without triggering `multiple_definition_files`, including genuine caller-free partial methods; callers, file hints, cycles, and converging paths are deduplicated while definitions retain physical-member evidence. Stale identity preserves physical multi-file ambiguity, and unrelated same-name symbols remain on safe ambiguity paths. Machine-readable output reports the separately bounded family-member expansion without conflating it with ordinary traversal truncation, and capped count output is explicitly non-authoritative.

## 日本語

- **impact analysis が 1 つの論理 partial family を単一 root として traversal するよう修正しました (#5060、#4309、#4566、#3932 の follow-up)** — current な reference identity では、caller が存在しない真正な partial method を含め、C# の partial declaration / implementation が物理 graph identity の和集合を提供し、`multiple_definition_files` で停止しません。definition に物理 member evidence を残しつつ、caller、file hint、cycle、収束 path を重複排除します。stale identity は物理的な multi-file ambiguity を維持し、無関係な同名 symbol も安全な ambiguity 経路を保ちます。machine-readable output は上限付き family-member 展開を通常の traversal truncation と混同せず個別に報告し、上限に達した count output は明示的に non-authoritative とします。
Loading
Loading