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
65 changes: 65 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,43 @@ guard that would fail before users see multi-hour indexing stalls.

Do not add mutable static caches, shared `StringBuilder` instances, reused `MatchCollection` enumerators, or singleton scanner state to extractor code. If a future extractor needs cross-call memoization, use an explicit thread-safe collection and add a targeted parallel regression test that proves deterministic output under concurrent calls.

### C# top-level synthetic scope contract

C# extractor contract version 13 persists an actionable file-scoped symbol for
compilation units with executable top-level statements. The symbol uses
`kind=function`, `sub_kind=top_level_scope`, and `name=<top-level>`; public
results derive `is_synthetic=true`, qualify the identity as
`<indexed-path>::<top-level>`, and emit an `id:<symbol-id>@g:<generation>`
selector. Selectors are valid only for their active index generation and are
resolved by symbol id, so identical top-level programs in different files do
not share callee identity.

Detection runs after container assignment. It excludes declaration-covered
ranges, imports with any legal whitespace between their C# keywords, comments,
directives, and assembly/module metadata, recognizes
both `using var` and explicitly typed `using Type value = ...` declarations as
executable rather than import directives, then uses the first and last uncovered
executable lines as both source and body bounds.
A top-level local function remains source-declared and containerless; its own
narrower span owns references inside the function, while a synthetic range may
cross it when executable statements occur on both sides. When a local function
and an outside statement share one line, declaration columns retain the local
function while the outside statement belongs to the synthetic scope. Reference extraction
uses the synthetic symbol's persisted id for otherwise containerless calls in
that body. The synthetic scope is not a documented declaration, so an XML-doc
comment before a top-level statement does not attach to it. `outline`,
coordinate `inspect`, and identity-scoped `callees` must
therefore navigate the same row; both CLI and MCP `callees` resolve its selector
by persisted symbol id. Unused-symbol list and count queries exclude this
synthetic entry point because it is executable infrastructure, not removable
dead code. Selector-scoped callee queries fail closed when a readable legacy
schema lacks the persisted source-identity column. If a stored C# extractor version predates this
contract or is missing, and no synthetic row is available, outline reports
`top_level_symbol_support=reindex_required` plus a typed limitation instead of
claiming support. A normal full index re-extracts unchanged C# files before it
stamps this contract, so the documented reindex remediation repairs unstamped
legacy databases without requiring `--rebuild`.

### Symbol Kind Taxonomy

`symbols.kind`, `symbols.container_kind`, and `symbol_references.container_kind` use the public symbol kind taxonomy below. New extractors must register new kind values in `SymbolKindCatalog` before writing them so schema checks, writer validation, CLI filters, and downstream JSON consumers stay aligned.
Expand Down Expand Up @@ -5089,6 +5126,34 @@ regression には、scope rule の focused correctness test と、ユーザー

抽出器コードに mutable な static cache、共有 `StringBuilder` インスタンス、使い回しの `MatchCollection` enumerator、シングルトンの scanner state を追加してはならない。将来の抽出器が呼び出しをまたぐ memoization を必要とする場合は、明示的にスレッドセーフなコレクションを使い、並行呼び出し下でも決定的な出力になることを証明する focused な並列回帰テストを追加する。

### C# top-level synthetic scope 契約

C# extractor contract version 13 は、実行可能な top-level statement を持つ
compilation unit に、操作可能な file-scoped symbol を永続化します。この symbol は
`kind=function`、`sub_kind=top_level_scope`、`name=<top-level>` を使い、公開結果は
`is_synthetic=true`、`<indexed-path>::<top-level>` 形式の qualified identity、
`id:<symbol-id>@g:<generation>` 形式の selector を派生させます。selector は active な
index generation だけで有効で、symbol id により解決するため、異なる file にある同一内容の
top-level program が callee identity を共有することはありません。

検出は container assignment の後に実行します。declaration が覆う range、C# keyword 間に
任意の正当な whitespace を持つ import、comment、directive、assembly/module metadata を除外し、`using var` と明示型の
`using Type value = ...` declaration の両方を import directive ではなく実行可能コードとして認識し、
残った最初と最後の実行可能行を source/body 両方の境界にします。top-level local function は container を持たない source-declared symbol
のままで、その function 内の reference はより狭い自身の span が所有します。両側に実行
statement がある場合、synthetic range は local function をまたぐことがあります。local function と外側の statement が
同じ行にある場合、宣言 column は local function が所有し、外側の statement は synthetic scope が所有します。reference
extraction は、この body 内で従来 container を持たなかった call に synthetic symbol の永続化
id を使います。synthetic scope は documented declaration ではないため、top-level statement
直前の XML-doc comment を自身へ結び付けません。そのため `outline`、座標指定 `inspect`、identity-scoped `callees` は同じ row を
navigate しなければならず、CLI / MCP の両 `callees` が selector を永続化済み symbol id で解決します。
unused-symbol の list / count query は、この synthetic entry point が削除可能な dead code ではなく実行基盤なので除外します。
読み取り可能な legacy schema に永続 source-identity column がない場合、selector-scoped callee query は fail-closed します。
保存済み C# extractor version がこの契約より古いか欠落しており、
synthetic row も無い場合、outline は対応済みと見せず、`top_level_symbol_support=reindex_required` と型付きの
limitation を返します。通常の full index はこの contract を stamp する前に未変更 C# file も再抽出するため、
文書化された reindex remediation は `--rebuild` なしで stamp のない legacy database を修復します。

### シンボル種別分類

`symbols.kind`、`symbols.container_kind`、`symbol_references.container_kind` は
Expand Down
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ Candidate-ordered parallel-index recovery tests must prove that the fatal result
do not allocate production-sized 50k/20k inputs to test these contracts (#4620).
- Broad extractor `*CompletesWithinPracticalBudget` runaway guards run only on the primary `net8.0` test target. Keep focused functional extractor tests cross-target, but do not duplicate the large-fixture budget guards across every target framework unless the guard is specifically proving a target-framework-specific contract.
- C# reflection-name extraction coverage keeps literal, constant-concatenation, dynamic, comment, and string-decoy cases in one source fixture so those parser boundaries share one symbol/reference pass.
- C# top-level synthetic-scope coverage (#5164) keeps the 10-line entry-point, local-function ownership including an outside call on the same line, typed using declarations, bounded extraction, legal-whitespace import directives, and all import/metadata/comment/directive/type/explicit-`Main` negatives in focused extractor fixtures. CLI reader fixtures own coordinate selection, cross-file selector isolation, caller/callee round-tripping, legacy source-identity fail-closed behavior, script-scope identity parity, compact output, stale-contract guidance, and unused list/count exclusion; the MCP assertion owns selector-to-`callees` round-tripping as well as transport naming parity. Keep full plus incremental no-op/change/add/rename/delete/no-op persistence and unstamped-C# upgrade re-extraction in `IndexCommandRunnerIssue5164Tests.cs` so lifecycle coverage uses real index reconciliation instead of direct database fixtures.
- C# BOM extraction keeps a simple leading-BOM import fixture plus one mixed-newline fixture that simultaneously covers leading and mid-file BOM handling across CRLF, bare CR, and LF boundaries; do not repeat separate extraction passes for newline subsets already present in the mixed fixture.
- C# lambda-capture coverage keeps positive enclosing-local capture, parameter shadowing, and same-named-method isolation in one source fixture; a single capture assertion proves the negative regions did not leak.
- C# static-lambda declaration regression coverage keeps stateful, typed/untyped, explicit-return, both async-modifier orders, Unicode/escaped-identifier, multiline, nested, and argument-position forms in one extractor pass. Preserve real static members/local functions, including generic, constructor, explicit-interface, and verbatim-type-name forms, and an assigned-lambda range/container assertion in that fixture, plus one CLI `symbols` corpus fixture for phantom-name checks (#4830).
Expand Down Expand Up @@ -1685,6 +1686,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
は高負荷な C# reference extraction に対する広めの runaway guard です。C# warmup は `CI=true` かつ `net8.0` test assembly の場合だけ、各 guard が fixture 構築と stopwatch 計測より前に呼ぶ `Lazy` gate により test process ごとに1回実行します。どちらの guard も含まない shard は extraction と強制 GC の固定 warmup cost を負いません。module initializer では hook discovery の delay、persistent worker PID/thread、persistent descendant PID/process の environment 処理をこの順序のまま eager に維持してください。warmup は最後に強制 GC を行うため、この2 guard だけを専用 non-parallel collection に保ち、巨大な `ReferenceExtractorTests` partial class 全体を non-parallel にしないでください。budget は benchmark 閾値ではなく回帰 tripwire として扱い、焦点を絞った最適化根拠がない限り noisy CI に十分な余裕を残してください。
- extractor の広い `*CompletesWithinPracticalBudget` runaway guard は primary の `net8.0` test target だけで実行します。focused な extractor 機能テストは cross-target のまま維持しますが、その guard が target-framework 固有の契約を証明する場合を除き、大規模 fixture の budget guard をすべての target framework で重複実行しないでください。
- C# reflection-name 抽出 coverage は、literal、定数連結、dynamic、comment、string decoy を1つの source fixture にまとめ、これらの parser boundary で1回の symbol/reference pass を共有します。
- C# top-level synthetic scope の coverage (#5164) は、10行の entry point、同じ行の外側 call を含む local-function ownership、typed using declaration、bounded extraction、正当な whitespace を持つ import directive、import / metadata / comment / directive / type / explicit `Main` の全 negative を focused extractor fixture に維持します。CLI reader fixture は座標選択、file 間の selector 分離、caller/callee round-trip、legacy source-identity の fail-closed behavior、script-scope identity parity、compact 出力、stale-contract guidance、unused list/count からの除外を担当し、MCP の assertion は transport の命名 parity に加えて selector から `callees` への round-trip を担当します。full と incremental の no-op / change / add / rename / delete / no-op 永続化、および stamp のない C# upgrade の再抽出は `IndexCommandRunnerIssue5164Tests.cs` に維持し、direct database fixture ではなく実際の index reconciliation で lifecycle を検証してください。
- C# BOM 抽出は、単純な先頭 BOM import fixture と、CRLF・bare CR・LF 境界で先頭/mid-file BOM を同時に扱う1つの混在改行 fixture を維持します。混在 fixture に含まれる改行 subset ごとに抽出 pass を重複させないでください。
- C# lambda capture coverage は、外側 local の正例、parameter shadowing、同名 method 間の分離を1つの source fixture にまとめます。capture が1件だけである assertion により、negative region からの漏れも同時に検証します。
- C# static lambda の宣言回帰 coverage は、stateful、型あり/型なし、明示的戻り値型、両方の async modifier 順、Unicode/escape 識別子、複数行、入れ子、引数位置の各形式を1回の extractor pass にまとめます。同じ fixture で generic、constructor、明示的 interface、verbatim 型名を含む本物の static member / local function と、代入済み lambda の range / container assertion を維持し、phantom 名の確認には CLI `symbols` corpus fixture を1つ追加します(#4830)。
Expand Down
Loading
Loading