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: 2 additions & 2 deletions DEVELOPER_GUIDE.md

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ cdidx unused --json --by-bucket --max-json-bytes 16384
cdidx map --compact --max-json-bytes 65536
cdidx map --format issue-drafts --limit 10
cdidx search --recipe risky-code --format compact --max-json-bytes 65536
cdidx search --recipe risky-code --format sarif --limit 20
cdidx audit risky-code --format sarif --limit 20 --max-json-bytes 65536
cdidx search --recipe risky-code --format compact --summary-only --json
cdidx search --named-query todo=TODO --named-query fixme=FIXME --format compact --limit 10
cdidx search --named-query todo=TODO --named-query fixme=FIXME --format count --summary-only --json
Expand Down Expand Up @@ -126,6 +126,8 @@ Recipe/audit compact pagination returns an opaque `next_cursor`. Replay it uncha

`audit` delegates recipe execution to the search engine but retains its public command name in usage errors, recovery hints, and generated replay commands. With an explicit `--json`, audit usage errors return versioned command-error objects with `command: "audit"` and omit human-readable `usage`; direct `search` diagnostics retain the `search` identity.

Recipe/audit SARIF accepts `--max-json-bytes` as an exact UTF-8 budget for the complete document, including JSON escaping and the final newline. A complete document that fits is unchanged. Otherwise, cdidx emits schema-valid SARIF by omitting only whole trailing results while preserving the rules and locations for emitted results; run and query properties report source/emitted/omitted counts, the byte-budget strategy, and replay guidance. Byte-budget truncation exits with code `11` unless `--allow-partial` is supplied. If even the zero-result bounded document cannot fit, no SARIF document is written and the usage error reports the minimum required byte count. Without an explicit `--json`, stdout stays empty; explicit JSON error mode may instead emit a versioned command-error object to stdout when that object fits the same cap.

Ad-hoc `search --format issue-drafts` computes `source_total_count`, `returned_count`, `omitted_count`, and `truncated` from the complete filtered population before applying `--first-per-file`, deterministic `--sample`, and the effective `--limit` / `--total-limit`. Guarded searches retain their candidate safety cap instead of attempting an unbounded count; they omit `source_total_count` and expose `source_minimum_count`, `source_total_count_authoritative: false`, and `source_fetch_limit`. Source metadata also records selector values, and the shell-safe replay command preserves every result-changing selector so rerunning it reproduces the same selected evidence.

When the byte cap omits rows, these commands return partial-result exit code `11`; pass `--allow-partial` to opt into exit code `0` while retaining the same terminal metadata. Ordinary `--limit` truncation remains a successful, explicitly described stream. Array and compact outputs keep their documented whole-response behavior; check `cdidx <command> --help` before relying on partial output.
Expand Down Expand Up @@ -590,7 +592,7 @@ cdidx unused --json --by-bucket --max-json-bytes 16384
cdidx map --compact --max-json-bytes 65536
cdidx map --format issue-drafts --limit 10
cdidx search --recipe risky-code --format compact --max-json-bytes 65536
cdidx search --recipe risky-code --format sarif --limit 20
cdidx audit risky-code --format sarif --limit 20 --max-json-bytes 65536
cdidx search --recipe risky-code --format compact --summary-only --json
cdidx search --named-query todo=TODO --named-query fixme=FIXME --format compact --limit 10
cdidx search --named-query todo=TODO --named-query fixme=FIXME --format count --summary-only --json
Expand Down Expand Up @@ -632,6 +634,8 @@ recipe / audit の compact pagination は opaque な `next_cursor` を返しま

`audit` は内部で recipe 実行を search engine へ委譲しますが、usage error、復旧 hint、生成する replay command では公開 command 名を維持します。明示的な `--json` では、audit の usage error は `command: "audit"` を持つ version 付き command-error object を返し、人間向けの `usage` を含めません。直接の `search` diagnostic は `search` identity を維持します。

recipe / audit の SARIF は、JSON escape と末尾改行を含む完全な document の正確な UTF-8 budget として `--max-json-bytes` を受け付けます。完全な document が収まる場合、出力は変わりません。収まらない場合は末尾の result だけを1件単位で省略し、出力した result の rule と location を維持した schema-valid SARIF を返します。run / query properties は source / emitted / omitted count、byte-budget strategy、replay guidance を報告します。byte budget による truncation は `--allow-partial` を指定しない限り終了コード `11` を返します。result 0件の bounded document さえ収まらない場合、SARIF document は出力せず、usage error で必要最小 byte 数を報告します。明示的な `--json` がなければ stdout は空のままですが、明示 JSON error mode では version 付き command-error object 自体が同じ cap に収まる場合に stdout へ出力することがあります。

ad-hoc の `search --format issue-drafts` は、filter 済み母集団全体から `source_total_count`、`returned_count`、`omitted_count`、`truncated` を算出してから、`--first-per-file`、決定的な `--sample`、有効な `--limit` / `--total-limit` を適用します。guard 付き検索は非上限 count を試みず candidate safety cap を維持し、`source_total_count` を省略して `source_minimum_count`、`source_total_count_authoritative: false`、`source_fetch_limit` を公開します。source metadata は selector 値も保持し、shell-safe な replay command は結果を変えるすべての selector を維持するため、再実行時に同じ evidence 集合を再現できます。

byte cap により行を省略した場合、これらのコマンドは partial-result 終了コード `11` を返します。同じ終端 metadata を維持したまま終了コード `0` を明示的に許容するには `--allow-partial` を指定します。通常の `--limit` による切り詰めは、理由が明示された成功 stream のままです。array / compact 出力は文書化済みの whole-response 挙動を維持します。部分出力へ依存する前に `cdidx <command> --help` を確認してください。
Expand Down
4 changes: 2 additions & 2 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ Use `docs/test-doc-maintenance-plan.md` before moving oversized suites or adding
Validate JSON, compact, count, and SARIF pagination/severity coverage shares one mixed informational/actionable fixture so authoritative totals, limited rows, SARIF levels, and actionability metadata cannot drift across formats; keep missing-`file_issues` degradation coverage in a separate legacy-schema fixture because availability is a distinct mutable state.
Command-specific output format coverage uses a command/format matrix that checks both parser acceptance and the matching usage line; recognized shared formats without a command implementation need a separate usage-error assertion.
Ad-hoc search SARIF completion coverage shares one fixture across complete, 1-of-126 limited, facet-filtered occurrence-expanded limited, bounded guarded, empty, and synthetically merged multi-run documents. Assert source/emitted/omitted counts and source-count authority in SARIF result units, applied limits, conservative truncation, null cursor state, raw-FTS and option-like-query replay commands, guard-preserving replay, and unchanged rule/location/severity fields on every run.
Recipe SARIF coverage must assert bounded result counts, `recipe/query` rule identity, source locations, severity mapping, confidence, conservative truncation metadata, and stable `fingerprints.cdidx/v1` values across identical runs.
Recipe SARIF coverage must assert bounded result counts, `recipe/query` rule identity, source locations, severity mapping, confidence, conservative truncation metadata, and stable `fingerprints.cdidx/v1` values across identical runs. Byte-budget coverage must count the complete UTF-8 stdout including JSON escaping and the final newline, exercise exact-fit and one-byte-under boundaries, Unicode, empty and multi-query runs, an individually oversized result, captured/redirected stdout, and replay metadata. Every successful output must parse as complete SARIF, omit only whole results, retain matching rules and locations, and stay within the requested cap. Below-minimum failures must emit no SARIF; non-explicit JSON failures leave stdout empty, while explicit `--json` may emit a bounded versioned error object. Also cover counting-writer measurement and replay recovery when the complete size exceeds the maximum accepted byte cap.
MCP schema-origin coverage keeps identical audit phrases in `McpToolCatalog.cs` top-level tool descriptions, concatenated description segments, nested schema-property prose, and executable C# in one indexed fixture; assert explicit `schema_description` search metadata and the recipe's JSON, SARIF, and issue-draft outputs so origin filtering cannot drift across projections.
Recipe row-selection coverage reuses one multi-file, multi-chunk fixture across aggregate JSON, compact JSON, NDJSON, and issue-draft source metadata. Assert emitted/matched/omitted counts, `selection_reason` / `selection_omitted_count`, first-per-file path uniqueness, selector-preserving replay commands, suppressed raw cursors when a later limit truncates selected rows, and rejection of incoming cursors with either selector. A separate candidate-window fixture must exceed the default low-limit fetch envelope and prove that `--sample <n>` observes at least its requested candidate target; validate rejected selectors for non-row recipe shapes without opening a database.
Unused default-suppression row, JSON count, summary-only, and text count envelopes, including the `--all` count control, share one unused-symbol fixture.
Expand Down Expand Up @@ -1177,7 +1177,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
validate の JSON、compact、count、SARIF における pagination / severity coverage は、informational finding と actionable finding が混在する1つの fixture を共有し、authoritative な総件数、limited row、SARIF level、actionability metadata が format 間で drift しないことを検証してください。`file_issues` 欠落時の degradation coverage は availability が独立した mutable state なので、別の legacy-schema fixture に分けてください。
コマンド別の出力形式 coverage は command / format matrix で parser の受理と対応する usage line の両方を検証してください。共通 parser が認識してもコマンド側に実装がない形式には、別途 usage error の assertion が必要です。
ad-hoc search SARIF の completion coverage は complete、1-of-126 の limited、facet filter 付き occurrence 展開後の limited、bounded guard、empty、合成した multi-run document で1つの fixture を共有します。SARIF result 単位の source / emitted / omitted count と source count の確定性、適用済み limit、保守的な truncation、null cursor state、raw FTS と option のような query の replay command、guard を保持する replay、および各 run で rule / location / severity field が不変であることを検証してください。
Recipe SARIF coverage では、上限付き result count、`recipe/query` rule identity、source location、severity mapping、confidence、保守的な truncation metadata、同一 run 間で安定する `fingerprints.cdidx/v1` を検証してください。
Recipe SARIF coverage では、上限付き result count、`recipe/query` rule identity、source location、severity mapping、confidence、保守的な truncation metadata、同一 run 間で安定する `fingerprints.cdidx/v1` を検証してください。byte-budget coverage では JSON escape と末尾改行を含む完全な UTF-8 stdout を数え、exact-fit と1 byte不足の境界、Unicode、空 run と複数 query の run、単体で oversized な result、capture / redirect した stdout、replay metadata を扱ってください。成功した出力はすべて完全な SARIF として parse でき、result を1件単位でのみ省略し、対応する rule / location を維持し、要求 cap 以下でなければなりません。最小値未満の失敗では SARIF を出力せず、明示 JSON でない失敗は stdout を空にし、明示的な `--json` では上限内の version 付き error object を出力できることも検証してください。counting writer による計測と、完全な size が受理可能な最大 byte cap を超える場合の replay recovery も扱ってください。
MCP schema-origin coverage では、同一の audit phrase を `McpToolCatalog.cs` の top-level tool description、連結された description segment、nested schema property の prose、実行可能な C# に置いた1つの indexed fixture を共有し、明示的な `schema_description` 検索 metadata と recipe の JSON、SARIF、issue-draft 出力を検証して、projection 間で origin filter が drift しないようにしてください。
recipe row-selection coverage は aggregate JSON、compact JSON、NDJSON、issue-draft の source metadata で1つの multi-file / multi-chunk fixture を共有します。emitted / matched / omitted count、`selection_reason` / `selection_omitted_count`、first-per-file の path uniqueness、selector を保持する replay command、後続 limit が選択済み row を truncate する場合の raw cursor 抑止、両 selector と受け取った cursor の併用拒否を検証してください。別の candidate-window fixture では既定の low-limit fetch envelope を超え、`--sample <n>` が少なくとも要求 candidate 数を観測することを証明し、row を持たない recipe shape での selector 拒否は database を開かずに確認してください。
unused default-suppressionのrow、JSON count、summary-only、text count envelopeは、`--all` count controlも含めて1つのunused-symbol fixtureを共有してください。
Expand Down
22 changes: 22 additions & 0 deletions changelog.d/unreleased/4903.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
category: fixed
issues:
- 4903
affected:
- src/CodeIndex/Cli/CliFlagSchema.cs
- src/CodeIndex/Cli/QueryCommandRunner.Sarif.cs
- src/CodeIndex/Cli/QueryCommandRunner.SearchRecipes.cs
- src/CodeIndex/Cli/QueryCommandRunner.SearchResults.cs
- tests/CodeIndex.Tests/QueryCommandRunnerAuditSarifIssue4903Tests.cs
- README.md
- DEVELOPER_GUIDE.md
- TESTING_GUIDE.md
---

## English

- **Audit and recipe SARIF now honor exact JSON byte budgets (#4903)** — `--max-json-bytes` measures the complete UTF-8 SARIF document, including JSON escaping and the final newline, with a counting writer before materializing the selected prefix. When the full report does not fit, cdidx emits schema-valid SARIF by omitting only whole trailing results and records source/emitted/omitted counts, the byte-budget strategy, and executable replay guidance while preserving emitted rules and locations. A budget below the minimum complete zero-result document emits no partial SARIF; explicit `--json` may return a bounded versioned error object.

## 日本語

- **audit / recipe の SARIF が正確な JSON byte budget を守るようになりました (#4903)** — `--max-json-bytes` は、JSON escape と末尾改行を含む完全な UTF-8 SARIF document を counting writer で計測してから、選択した prefix だけを materialize します。report 全体が収まらない場合は、末尾の result だけを1件単位で省略し、出力済みの rule / location を維持した schema-valid SARIF を返します。source / emitted / omitted count、byte-budget strategy、実行可能な replay guidance も記録し、result 0件の完全な document の最小値にも満たない budget では partial SARIF を出力しません。明示的な `--json` では上限内の version 付き error object を返すことがあります。
2 changes: 1 addition & 1 deletion src/CodeIndex/Cli/CliFlagSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ private static IReadOnlyList<CliFlag> BuildAll()
new() { Name = "--env-domain", ValuePlaceholder = "<domain>", Description = "Doctor full environment inventory: filter by exact domain", PrimaryCommands = Set("doctor") },
new() { Name = "--env-category", ValuePlaceholder = "<category>", Description = "Doctor full environment inventory: filter by exact category", PrimaryCommands = Set("doctor") },
new() { Name = "--env-sensitivity", ValuePlaceholder = "<sensitivity>", Description = "Doctor full environment inventory: filter by exact sensitivity", PrimaryCommands = Set("doctor") },
new() { Name = "--max-json-bytes", ValuePlaceholder = "<n>", Description = "Bound emitted JSON bytes; bounded high-volume responses truncate projected rows with paging metadata", PrimaryCommands = Set("search", "definition", "find", "status", "references", "callers", "callees", "excerpt", "inspect", "outline", "impact", "recipes", "audit", "map", "files", "symbols", "deps", "hotspots", "languages", "unused", "doctor") },
new() { Name = "--max-json-bytes", ValuePlaceholder = "<n>", Description = "Bound emitted JSON bytes; bounded responses omit whole rows with recovery metadata, including schema-valid audit SARIF", PrimaryCommands = Set("search", "definition", "find", "status", "references", "callers", "callees", "excerpt", "inspect", "outline", "impact", "recipes", "audit", "map", "files", "symbols", "deps", "hotspots", "languages", "unused", "doctor") },
new() { Name = "--next-steps", Description = "Search: print inspect/excerpt follow-up commands for top hits", PrimaryCommands = Set("search") },
new() { Name = "--exclude-comments", Description = "Search: suppress comment-only matches after origin classification", PrimaryCommands = Set("search") },
new() { Name = "--exclude-strings", Description = "Search: suppress string, regex, and help-text matches after origin classification", PrimaryCommands = Set("search") },
Expand Down
Loading
Loading