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
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ Use `docs/test-doc-maintenance-plan.md` before moving oversized suites or adding
Reference-identity write coverage uses per-column SQLite audit triggers around one self-resolving reference. It requires a stable rerun to write no source, resolution, self, or mutual rows; corrupts all four phases; aborts target resolution to prove the earlier source update rolls back; then requires exactly one repair write per phase and another stable zero-write rerun.
Reusable-stat snapshot semantics keep one valid row beside two rows from the same stale extractor language plus NULL, text, integer, and invalid-timestamp stat storage, so malformed-row filtering and cached stale-language rejection remain one contract.
Graph-kind regressions keep default canonical `call` / `instantiate` / `subscribe` output, raw-kind output, and explicit non-default kind access in the same seeded fixture so filtering and projection cannot drift apart.
Caller-ranking coverage keeps the large count-over-path-category case, primary-recipe ties, multi-path filtering, test exclusion, and offset page reconstruction in one seeded `DbReaderTests` fixture. CLI human/JSON and MCP pagination assertions reuse compact two- or three-caller fixtures and require the structured ranking recipe to match the ordering applied before pagination (#4881).
Query-only regression fixtures run representative `status`, `search`, and `files` commands against a checkpointed WAL database copied without sidecars and assert that the database, `-wal`, and `-shm` artifact set plus persistent pragmas remain unchanged. Separate fixtures prove that committed hot-WAL content, empty-to-hot transitions, checkpoint resets, cross-database dependency targets, and long-lived LSP refreshes use cleaned-up generation-validated private snapshots without touching source sidecars. Cross-database coverage also pins disposal ordering and snapshot-directory cleanup, while injected persistent copy failures pin the non-retrying `query_only_snapshot_copy_failed` taxonomy; interrupted-batch readiness demotion is covered separately through explicit `Repair` intent.
`DatabasePermissionPolicyTests.cs` injects a file-mode provider so unsupported and access-denied Unix mode operations remain deterministic and cross-platform while proving both best-effort diagnostics and strict remediation failures.
`DbSchemaConstraintTests.cs` also locks schema constraints to `SymbolKindCatalog` and required file foreign keys so DB readiness checks fail when code enums and SQLite CHECK clauses drift.
Expand Down Expand Up @@ -1095,6 +1096,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
reference identity writeのcoverageは、self-resolving reference 1件に列別SQLite audit triggerを設定します。安定rerunでsource・resolution・self・mutual rowのwriteが0、全4 phaseをcorruptした後にtarget resolutionを中断して先行source updateもrollback、復旧時はphaseごとにちょうど1 write、その後の安定rerunは再び0 writeであることを必須とします。
再利用 stat snapshot の意味論は、有効な1行、同じ stale extractor 言語の2行、NULL / text / integer / 不正 timestamp の stat storage を同居させ、malformed row の除外と stale-language 判定の false cache を1つの契約として固定します。
graph kind の回帰では、既定 canonical `call` / `instantiate` / `subscribe` 出力、raw-kind 出力、明示的な非既定 kind access を同じ seed 済み fixture にまとめ、filtering と projection のずれを検出します。
caller ranking の coverage では、count と path category に大差がある場合、primary recipe の同順位、複数 path filter、test 除外、offset page の再構成を1つの seed 済み `DbReaderTests` fixture にまとめます。CLI の human / JSON と MCP pagination の assertion は2~3 caller の小さな fixture を再利用し、structured ranking recipe が pagination 前に適用した順序と一致することを必須とします (#4881)。
query-only の回帰 fixture では sidecar なしで copy した checkpoint 済み WAL database に対して代表的な `status`、`search`、`files` command を実行し、database、`-wal`、`-shm` の artifact set と永続 pragma が変化しないことを検証します。別の fixture では committed hot-WAL content、empty-to-hot transition、checkpoint reset、cross-database dependency target、長時間 LSP refresh が、source sidecar に触れず cleanup される generation 検証済み private snapshot を使うことを固定します。cross-database coverage は dispose 順序と snapshot directory cleanup も固定し、注入した永続的 copy failure は retry されない `query_only_snapshot_copy_failed` taxonomy を固定します。interrupted batch の readiness demotion は明示的な `Repair` intent の別テストで固定します。
`DatabasePermissionPolicyTests.cs` は file-mode provider を注入し、unsupported / access-denied な Unix mode 操作を deterministic かつ cross-platform に保ちながら、best-effort diagnostic と strict remediation failure の両方を検証します。
`DbSchemaConstraintTests.cs` は DB readiness check が code enum と SQLite CHECK 句の drift を検出できるよう、schema constraint と `SymbolKindCatalog`、必須 file foreign key の同期も固定します。
Expand Down
6 changes: 3 additions & 3 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ By default, `callers` and `callees` return only executable call, construction, a

C# indexing retains receiver- and type-qualified calls even when their member name is common, including `int.Parse`, LINQ `Where` / `Select` / `ToList`, and instance `Read` / `Write` calls. Bare-name `references`, `callers`, and `callees` queries keep resolved qualified calls in the default result while suppressing only unresolved qualified common-name calls as noise. Use `--include-qualified-common-calls` (or MCP `includeQualifiedCommonCalls: true`) when you need those unresolved rows too; an explicit qualified query such as `references int.Parse --exact` is already treated as an intentional completeness request.

`callers` and `callees` rank results by weighted structural importance by default: `instantiate` edges count as `3.0`, direct `call` edges as `1.0`, and event `subscribe` edges as `0.1`. This keeps factory or composition-root constructor use from being buried under noisy event subscriptions. Use `--rank-by count` to restore raw `reference_count` ordering, or `--rank-by kind` to group `instantiate`, `call`, then `subscribe` before count. JSON rows keep the raw `reference_count` and add `reference_kind_counts` plus `reference_weight_score` so consumers can re-rank without losing the source counts; MCP structured rows expose the same data as `referenceKindCounts` and `referenceWeightScore`.
`callers` and `callees` rank results by an explicit primary recipe. `weighted` (the default) orders by `reference_weight_score DESC` and then `reference_count DESC`, where `instantiate=3.0`, direct `call=1.0`, and event `subscribe=0.1`. `--rank-by count` makes raw `reference_count DESC` the true primary key, and `--rank-by kind` uses `instantiate`, `call`, `generic_type_argument`, `subscribe`, then other kinds before `reference_count DESC`. Only rows tied on that primary recipe use, in order, exact-case match, exact-name match, path category (`production`, `test`, `documentation`), path, first line, first column, language, container kind, container name, symbol name, and reference kind. Test or documentation paths therefore never override the requested primary rank; `--exclude-tests` removes test rows instead of merely demoting them. CLI JSON exposes this contract as `query_context.rank_by` and `query_context.ranking_recipe`, while MCP exposes `rankBy` and `rankingRecipe`; each recipe contains the complete machine-readable `precedence` array used before pagination. JSON rows also keep raw `reference_count`, `reference_kind_counts`, and `reference_weight_score` (`referenceCount`, `referenceKindCounts`, and `referenceWeightScore` in MCP).

Grouped `callees` rows preserve the earliest precise call site separately from the aggregate `reference_count`. CLI JSON exposes its 1-based `first_line`, nullable `first_column`, and persisted physical-token `first_length`; MCP uses the corresponding `firstLine`, `firstColumn`, and `firstLength` fields. This keeps resolved constructor-chain calls on their actual `base`, `super`, or `this` token. Compact and quickfix output use the same 1-based column, SARIF carries the same token-sized region, and LSP converts it to a zero-based, non-empty token range. If every contributing legacy reference lacks a column, the column remains `null`, quickfix reports column `0`, SARIF omits `endColumn`, and LSP returns a zero-width range at the start of the retained source line. If a migrated row retains its column but has no persisted span length, SARIF still omits `endColumn` and LSP returns a zero-width range at that column instead of inventing a token width.

Expand Down Expand Up @@ -2057,7 +2057,7 @@ same source location.
| `--prefix` | `search` | Opt into FTS5 prefix-phrase expansion for every token in the query. Without this flag the literal-safe path quotes each token as a strict FTS5 phrase, so a bare `search 計算` only matches the token `計算` and not `計算する` (unicode61 keeps adjacent CJK codepoints as one token). Appending `*` to a single token (`search 計算*`) opts in for that token only; `--prefix` opts in for the whole query. Cannot be combined with `--exact` / `--exact-substring` / `--token-boundary` (those bypass FTS5 entirely). |
| `--exact-name` | `symbols`, `definition`, `references`, `callers`, `callees`, `inspect` | Preferred explicit name for symbol-name exactness: NFKC + Unicode CaseFold exact equality (`Ä` / `ä`, `Run` / `Run`, ligatures, sharp-S, and Greek final sigma collapse). Unicode CaseFold remains locale-invariant, so Turkish dotted `İ` is still distinct from plain `i`. For C#, pass the canonical extracted name (`operator +`, `operator checked +`, `explicit operator Money`, `implicit operator decimal`, `Item`) rather than source keywords like `this` / `explicit`. Falls back to ASCII `COLLATE NOCASE` while the DB still contains stale fold metadata; prefer `cdidx backfill-fold`, or use a plain `cdidx index .` if it rewrites or purges every stale row, otherwise `--rebuild`. `status --json` exposes `fold_ready` and `csharp_symbol_name_ready` so AI clients can tell which path is active. When a read-only legacy DB is missing the fallback exact-match indexes, human-readable output warns and CLI JSON / MCP `structuredContent` expose degraded-state metadata. |
| `--kind <kind>` | `definition`, `references`, `callers`, `callees`, `symbols`, `inspect`, `outline`, `hotspots`, `unused`, `validate` | Filter by kind (case-insensitive; `--kind FUNCTION` is treated as `--kind function`). `outline` also accepts comma-separated symbol kinds, such as `--kind function,class`. `definition` / `symbols` / `inspect` / `outline` / `hotspots` / `unused` use symbol kinds (`function`, `lambda`, `async_function`, `generator`, `async_generator`, `test.method`, `class`, `struct`, `interface`, `protocol`, `enum`, `property`, `event`, `delegate`, `namespace`, `import`); `references` accepts all indexed reference kinds (`call`, `instantiate`, `subscribe`, `attribute`, `annotation`, `type_reference`, `type_tag`); `callers` / `callees` accept only the call-graph kinds (`call`, `instantiate`, `subscribe`) and reject non-call-graph kinds (`--kind attribute` / `--kind annotation` / `--kind type_reference` / `--kind type_tag`) with a usage error — metadata rows are attributed to the enclosing body-range symbol rather than the annotated target, `type_reference` rows are compile-time type-position edges (declaration types, generic constraints, `is`/`as`/`instanceof`, XML-doc `cref`), and `type_tag` rows describe JavaScript/TypeScript discriminant narrowing rather than runtime calls, so `callers` / `callees` cannot answer these kinds correctly; use `references --kind attribute` / `references --kind annotation` / `references --kind type_reference` / `references --kind type_tag` instead. `inspect` filters the definition candidates and primary file context while keeping graph evidence keyed to the queried symbol name. `references` defaults to every indexed reference kind so metadata usages remain visible, while `callers` / `callees` / `hotspots` / `impact` default to the call-graph kinds only (`call`, `instantiate`, `subscribe`) and exclude metadata edges (`attribute`, `annotation`, `type_reference`, `type_tag`). Identical constructor `call` + `instantiate` rows at one physical site still collapse; `validate` uses issue kinds such as `bom` |
| `--rank-by <weighted\|count\|kind>` | `callers`, `callees` | Choose the caller/callee ranking model. `weighted` is the default and scores `instantiate=3.0`, `call=1.0`, `subscribe=0.1`; `count` sorts by raw `reference_count`; `kind` groups by reference kind first, then count. |
| `--rank-by <weighted\|count\|kind>` | `callers`, `callees` | Choose the primary caller/callee ranking recipe. `weighted` orders by weighted score then count; `count` orders by raw `reference_count`; `kind` orders by kind priority then count. Only ties use exact-case/name relevance, production/test/documentation path category, and stable path/location/name fields. JSON/MCP ranking recipes publish the complete precedence applied before pagination. |
| `--body` | `definition`, `references`, `callers`, `callees`, `impact`, `inspect` | Include reconstructed body content or capped graph-location excerpts |
| `--count` | `search`, `definition`, `references`, `callers`, `callees`, `symbols`, `files`, `find`, `impact`, `unused`, `hotspots` | Return only counts. `search` / `definition` / `references` / `callers` / `callees` / `symbols` / `files` / `find` / `unused` / `hotspots` ignore `--limit` and return authoritative totals; only `impact` still reports the visible page count and may truncate with `--limit` (with `--json`: a single count object; commands that expose file counts add `files`) |
| `--group-partials` | `definition`, `symbols`, `inspect` | Collapse actual C# `partial` declarations with the same qualified family identity into logical families. Off by default; unrelated non-partial types remain physical rows. Each grouped result keeps a stable representative and exposes its physical declaration count through `definition_sites`; grouped count JSON includes `logical_count`, `physical_count`, and `physical_file_count`. Audit sorts use per-family maximum rank metrics. `inspect` supports this only for symbol queries, not positional paths or `--path` / `--line` coordinates. |
Expand Down Expand Up @@ -4977,7 +4977,7 @@ cdidx callees AddToGitExclude --exclude-tests

C# の indexing は member 名が一般的な場合でも、`int.Parse`、LINQ の `Where` / `Select` / `ToList`、instance の `Read` / `Write` など、receiver または型で修飾された call を保持します。無修飾名による `references`、`callers`、`callees` query の既定結果では、解決済みの修飾 call を維持し、未解決の修飾付き一般名 call だけを noise として除外します。未解決 row も必要な場合は `--include-qualified-common-calls`(MCP では `includeQualifiedCommonCalls: true`)を使ってください。`references int.Parse --exact` のような明示的な修飾 query は、それ自体を completeness の指定として扱います。

`callers` と `callees` は既定で構造的重要度の weighted 順に並びます。`instantiate` は `3.0`、直接 `call` は `1.0`、event `subscribe` は `0.1` として数えるため、factory や composition root の constructor 利用が大量の event subscription に埋もれにくくなります。従来どおり生の `reference_count` で並べたい場合は `--rank-by count`、reference kind を優先して `instantiate`、`call`、`subscribe` の順でまとめたい場合は `--rank-by kind` を使ってください。JSON の各行は生の `reference_count` を維持し、`reference_kind_counts` と `reference_weight_score` も追加で返します。MCP structured row では同じ情報を `referenceKindCounts` と `referenceWeightScore` として返すため、consumer 側で再ランキングできます。
`callers` と `callees` は、明示的な primary recipe で結果を並べます。既定の `weighted` は `reference_weight_score DESC`、次に `reference_count DESC` の順で、`instantiate=3.0`、直接 `call=1.0`、event `subscribe=0.1` として計算します。`--rank-by count` では生の `reference_count DESC` が真の primary key になり、`--rank-by kind` では `instantiate`、`call`、`generic_type_argument`、`subscribe`、その他の kind の順を優先してから `reference_count DESC` を適用します。この primary recipe で同順位の場合だけ、完全な大小文字一致、完全な名前一致、path category(`production`、`test`、`documentation`)、path、最初の行、最初の列、language、container kind、container name、symbol name、reference kind の順で tie-break します。そのため test / documentation path が指定した primary rank を上書きすることはなく、`--exclude-tests` は test 行を単に降格するのではなく除外します。CLI JSON はこの契約を `query_context.rank_by` と `query_context.ranking_recipe`、MCP は `rankBy` と `rankingRecipe` で公開し、各 recipe の machine-readable な `precedence` 配列には pagination 前に適用した全順序が入ります。JSON row は生の `reference_count`、`reference_kind_counts`、`reference_weight_score` も保持し、MCP では `referenceCount`、`referenceKindCounts`、`referenceWeightScore` として返します。

集約された `callees` 行は、集約値の `reference_count` とは別に、最初の精密な call site を保持します。CLI JSON は 1-based の `first_line`、nullable な `first_column`、永続化された物理 token 幅の `first_length` を返し、MCP は対応する `firstLine`、`firstColumn`、`firstLength` を使います。そのため、解決後の constructor-chain call も実際の `base`、`super`、`this` token を指します。compact / quickfix も同じ 1-based 列を使い、SARIF は同じ token 幅の region、LSP は 0-based の非空 token range に変換します。寄与する legacy reference の全てで列が欠けている場合は列を `null` のまま保ち、quickfix は列 `0`、SARIF は `endColumn` を省略し、LSP は保持した source line の先頭に zero-width range を返します。移行済み row に列はあるものの永続化 span 長がない場合も、SARIF は `endColumn` を省略し、LSP はその列に zero-width range を返すため、token 幅を捏造しません。

Expand Down
19 changes: 19 additions & 0 deletions changelog.d/unreleased/4881.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
category: fixed
issues:
- 4881
affected:
- src/CodeIndex/Database/DbReader.GraphQueries.cs
- src/CodeIndex/Models/QueryResults.cs
- src/CodeIndex/Cli/QueryCommandRunner.ResultEnvelopes.cs
- src/CodeIndex/Mcp/McpToolHandlers.Graph.cs
- USER_GUIDE.md
---

## English

- **Caller and callee ranking now honors the selected primary recipe (#4881)** — `--rank-by count` uses raw reference count before source/test/documentation path preferences, all ranking modes use deterministic tie-breakers before pagination, and CLI JSON plus MCP responses publish the complete applied ranking recipe.

## 日本語

- **caller / callee ranking が選択した primary recipe を優先するようになりました (#4881)** — `--rank-by count` は source / test / documentation の path 優先度より先に生の reference count を適用し、すべての ranking mode は pagination 前に決定的な tie-breaker を使います。CLI JSON と MCP response は、適用した ranking recipe 全体も公開します。
Loading
Loading