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 @@ -1163,6 +1163,10 @@ Different graph entry points walk different `reference_kind` subsets by design.

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 `callers <ClassName>` returns the call-graph subset (without metadata). Both are correct under their own contracts; counts will not match. To reconcile, run `references <ClassName> --kind attribute` (or `annotation`) to surface the metadata-only edges that the call-graph commands intentionally drop.

`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.

## Cloud Claude Code bootstrap (no .NET SDK)

> **Maintainers / authorized operators only** — see [MAINTAINERS.md](MAINTAINERS.md). End users can skip this section.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ downgrading `cdidx`.
| Area | What cdidx provides |
|---|---|
| Search surfaces | CLI-first output for humans and machines; full-text, symbol, reference, caller/callee, dependency, map, inspect, and excerpt commands. `search`, `definition`, `references`, `callers`, `callees`, `find`, and `validate` support `--format count|compact|csv|tsv|lsp|qf|sarif` for token-budgeted agents, scripts, editors, and CI reports. |
| Definition and impact diagnostics | `definition --json` includes C# `disambiguator` hints for overloads, partial types, and extension receivers when indexed metadata can distinguish them. `impact --json` and MCP `impact_analysis` include `impact_failure_chain` and `suggestion_type` for zero-result routing; `impact --strict` exits non-zero when resolution or graph preconditions are unmet. |
| Ranking and filters | Public/exported symbol matches rank ahead of protected, internal, and private matches. Use `--no-visibility-rank` for legacy order, and `--visibility` / `--exclude-visibility` with `symbols`, `definition`, `unused`, and `hotspots`. Query defaults can be adjusted with `CDIDX_DEFAULT_LIMIT`, `CDIDX_DEFAULT_SNIPPET_LINES`, and `CDIDX_DEFAULT_MAX_LINE_WIDTH`; explicit CLI flags still win. |
| Project scoping | `.sln` / `.csproj`-aware <code>--project &lt;name&#124;path&gt;</code> filters for indexing and queries, plus `--solution <path>` when a workspace has multiple solution files. |
| MCP integration | MCP server support for AI clients such as Claude Code, Cursor, and Windsurf, including tools, indexed-file resources, starter prompts, schema constraints for local argument validation, `mimeType` on text content blocks, logging, a structured `ping` health result, HTTP `GET /healthz`, opt-in HTTP `/events` keep-alive notifications, a compatibility server-side `notifications/initialized` ready signal on stdio or HTTP `/events` streams, and `Language support:` descriptions sourced from the same registries as `cdidx languages`. Tool schemas reject unknown arguments with `-32602`, advertise `x-stability`, and use snake_case structured JSON keys to match the CLI JSON contract. |
Expand Down Expand Up @@ -386,6 +387,7 @@ upgrade / downgrade 後はインストール済み補完 script を再生成し
| 分野 | 内容 |
|---|---|
| 検索面 | CLI-first の人間向け / 機械処理向け出力。全文検索、シンボル、参照、caller/callee、依存関係、map、inspect、excerpt コマンドを提供します。 |
| definition / impact 診断 | `definition --json` は C# overload、partial type、extension receiver を区別できる場合に `disambiguator` を返します。`impact --json` と MCP `impact_analysis` は 0 件時の経路判断用に `impact_failure_chain` と `suggestion_type` を返し、`impact --strict` は解決または graph の前提条件が満たされない場合に非 0 で終了します。 |
| 順位と filter | public/exported なシンボル一致を protected、internal、private より優先します。従来順は `--no-visibility-rank`、可視性の include / exclude は `symbols`、`definition`、`unused`、`hotspots` の `--visibility` / `--exclude-visibility` で指定できます。query 既定値は `CDIDX_DEFAULT_LIMIT`、`CDIDX_DEFAULT_SNIPPET_LINES`、`CDIDX_DEFAULT_MAX_LINE_WIDTH` で調整でき、明示 CLI flag が常に優先されます。 |
| project scope | `.sln` / `.csproj` を使った <code>--project &lt;name&#124;path&gt;</code> filter で index と query を .NET project 配下へ絞り込めます。workspace に solution が複数ある場合は `--solution <path>` を指定します。 |
| MCP 連携 | Claude Code、Cursor、Windsurf などの AI クライアント向け MCP server。tools、インデックス済みファイル resources、starter prompts、ローカル引数検証用の schema constraints、text content block の `mimeType`、logging、構造化された `ping` health result、HTTP `GET /healthz`、opt-in の HTTP `/events` keep-alive notification、stdio または HTTP `/events` stream 上の互換性用 server-side `notifications/initialized` ready signal、`cdidx languages` と同じ言語レジストリ由来の `Language support:` 説明を提供します。Tool schema は未知の引数を `-32602` で拒否し、`x-stability` を公開し、CLI JSON contract と一致する snake_case の structured JSON key を使います。 |
Expand Down
17 changes: 17 additions & 0 deletions changelog.d/unreleased/1638.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: changed
issues:
- 1638
affected:
- src/CodeIndex/Database/DbSymbolReader.cs
- src/CodeIndex/Models/QueryResults.cs
- tests/CodeIndex.Tests/DbReaderTests.cs
---

## English

- **Definition JSON now includes C# disambiguator hints (#1638)** — `definition` results include overload, partial type, and extension receiver hints when indexed C# metadata can distinguish otherwise identical names.

## 日本語

- **definition JSON が C# disambiguator hint を返すようになりました (#1638)** — `definition` は、インデックス済み C# metadata で同名定義を区別できる場合に overload、partial type、extension receiver の hint を返します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/2002.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: changed
issues:
- 2002
affected:
- src/CodeIndex/Database/DbReader.GraphQueries.cs
- src/CodeIndex/Cli/QueryCommandRunner.cs
- src/CodeIndex/Mcp/McpToolHandlers.cs
---

## English

- **Impact zero-result JSON now exposes structured failure routing (#2002)** — `impact` now emits `impact_failure_chain` and `suggestion_type` for zero results, and `impact --strict` exits non-zero when resolution or graph preconditions fail.

## 日本語

- **impact の 0 件 JSON が構造化された失敗経路を返すようになりました (#2002)** — `impact` は 0 件時に `impact_failure_chain` と `suggestion_type` を返し、`impact --strict` は解決または graph の前提条件失敗で非 0 終了します。
1 change: 1 addition & 0 deletions src/CodeIndex/Cli/CliFlagSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ private static IReadOnlyList<CliFlag> BuildAll()
new() { Name = "--raw-kinds", Description = "Show raw reference kinds instead of logical graph kinds", Commands = Set(RawKindsCommands) },
new() { Name = "--count", Description = "Count only", Commands = Set(CountCommands) },
new() { Name = "--strict-not-found", Description = "Return exit code 2 when a valid query has zero rows", Commands = Set(StrictNotFoundCommands) },
new() { Name = "--strict", Description = "Return exit code 4 when impact preconditions are unmet", Commands = Set("impact") },
new() { Name = "--since", ValuePlaceholder = "<datetime>", Description = "Filter by modified-since timestamp", Commands = Set(SinceCommands) },
new() { Name = "--bytes", Description = "Show raw byte counts in human output", Commands = Set(ByteFormatCommands) },
new() { Name = "--min-entrypoint-confidence", ValuePlaceholder = "<0.0..1.0>", Description = "Map: omit entrypoint candidates below this confidence", Commands = Set(EntrypointConfidenceCommands) },
Expand Down
34 changes: 31 additions & 3 deletions src/CodeIndex/Cli/QueryCommandRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ private sealed record StatusReadinessField(
"--body",
"--count",
"--strict-not-found",
"--strict",
"--no-dedup",
"--no-visibility-rank",
"--exact",
Expand Down Expand Up @@ -3220,6 +3221,7 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
zeroPayload["definitions"] = JsonSerializer.SerializeToNode(analysis.Definitions, CliJsonSerializerContextFactory.Create(jsonOptions).ListSymbolResult);
if (analysis.ZeroResultReason != null)
zeroPayload["zero_result_reason"] = analysis.ZeroResultReason;
AddImpactFailureJsonFields(zeroPayload, analysis, jsonOptions);
if (analysis.Suggestion != null)
zeroPayload["suggestion"] = analysis.Suggestion;
AddSqlGraphContractJsonFields(zeroPayload, sqlGraphSignal);
Expand All @@ -3233,7 +3235,7 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
WriteImpactResolutionHint(analysis);
WriteGraphSupportHint(options.Lang);
}
return CommandExitCodes.Success;
return StrictImpactExitCode(options, analysis, CommandExitCodes.Success);
}

if (options.CountOnly)
Expand Down Expand Up @@ -3263,6 +3265,7 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
AddImpactTerminationJsonFields(payload, analysis, jsonOptions);
if (analysis.ZeroResultReason != null)
payload["zero_result_reason"] = analysis.ZeroResultReason;
AddImpactFailureJsonFields(payload, analysis, jsonOptions);
if (analysis.Suggestion != null)
payload["suggestion"] = analysis.Suggestion;
if (!analysis.GraphTableAvailable)
Expand Down Expand Up @@ -3314,6 +3317,7 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
zeroPayload["definitions"] = JsonSerializer.SerializeToNode(analysis.Definitions, CliJsonSerializerContextFactory.Create(jsonOptions).ListSymbolResult);
if (analysis.ZeroResultReason != null)
zeroPayload["zero_result_reason"] = analysis.ZeroResultReason;
AddImpactFailureJsonFields(zeroPayload, analysis, jsonOptions);
if (analysis.Suggestion != null)
zeroPayload["suggestion"] = analysis.Suggestion;
AddSqlGraphContractJsonFields(zeroPayload, sqlGraphSignal);
Expand All @@ -3330,7 +3334,7 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
WriteGraphSupportHint(options.Lang);
WriteDegradedGraphZeroResult(reader, "callers", json: false, graphAvailable: reader._hasReferencesTable, jsonOptions);
}
return ZeroResultExitCode(options);
return StrictImpactExitCode(options, analysis, ZeroResultExitCode(options));
}

if (options.CountOnly)
Expand Down Expand Up @@ -3397,6 +3401,7 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
payload["truncated_reason"] = analysis.TruncatedReason;
if (analysis.Suggestion != null)
payload["suggestion"] = analysis.Suggestion;
AddImpactFailureJsonFields(payload, analysis, jsonOptions);
AddSqlGraphContractJsonFields(payload, sqlGraphSignal);
AddImpactOptionWarnings(payload, options);
Console.WriteLine(payload.ToJsonString(jsonOptions));
Expand Down Expand Up @@ -3445,10 +3450,27 @@ public static int RunImpact(string[] cmdArgs, JsonSerializerOptions jsonOptions)
else
Console.Error.WriteLine($"\n({confirmedCount} callers across {confirmedFileCount} files, max depth {maxDepth}{truncNote})");
}
return CommandExitCodes.Success;
return StrictImpactExitCode(options, analysis, CommandExitCodes.Success);
});
}

private static void AddImpactFailureJsonFields(JsonObject payload, ImpactAnalysisResult analysis, JsonSerializerOptions jsonOptions)
{
if (analysis.ImpactFailureChain is { Count: > 0 })
payload["impact_failure_chain"] = JsonSerializer.SerializeToNode(analysis.ImpactFailureChain, CliJsonSerializerContextFactory.Create(jsonOptions).ListString);
if (analysis.SuggestionType != null)
payload["suggestion_type"] = analysis.SuggestionType;
}

private static int StrictImpactExitCode(QueryCommandOptions options, ImpactAnalysisResult analysis, int defaultExitCode)
{
if (!options.Strict || analysis.ImpactFailureChain is not { Count: > 0 })
return defaultExitCode;
return analysis.ImpactFailureChain.Any(code => code != "no_callers")
? CommandExitCodes.FeatureUnavailable
: defaultExitCode;
}

private static void AddImpactTerminationJsonFields(JsonObject payload, ImpactAnalysisResult analysis, JsonSerializerOptions jsonOptions)
{
payload["termination_reason"] = analysis.TerminationReason;
Expand Down Expand Up @@ -4610,6 +4632,7 @@ public static QueryCommandOptions ParseArgs(
bool limitExplicit = false;
bool snippetLinesExplicit = false;
bool maxLineWidthExplicit = false;
bool strict = false;
var rankMode = ReferenceRankMode.Weighted;
var extraNames = new List<string>();
bool impactDeprecatedDepthUsed = false;
Expand Down Expand Up @@ -4859,6 +4882,9 @@ void WarnIfDuplicateSingleValueOption(string canonicalName, string newValue)
case "--strict-not-found":
strictNotFound = true;
break;
case "--strict":
strict = true;
break;
case "--by-bucket":
break;
case "--all":
Expand Down Expand Up @@ -5277,6 +5303,7 @@ void WarnIfDuplicateSingleValueOption(string canonicalName, string newValue)
IncludeGenerated = includeGenerated,
CountOnly = countOnly,
StrictNotFound = strictNotFound,
Strict = strict,
Since = since,
NoDedup = noDedup,
NoVisibilityRank = noVisibilityRank,
Expand Down Expand Up @@ -7906,6 +7933,7 @@ public sealed class QueryCommandOptions
public bool IncludeGenerated { get; init; }
public bool CountOnly { get; init; }
public bool StrictNotFound { get; init; }
public bool Strict { get; init; }
public DateTime? Since { get; init; }
public bool NoDedup { get; init; }
public bool NoVisibilityRank { get; init; }
Expand Down
Loading
Loading