diff --git a/CHANGELOG.md b/CHANGELOG.md index a686fb0..8bc8331 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- manual-bbで検出したbaseline参照、抑制YAML・不正期限、policy数値検証、readiness ID・warn_only、emit検証・SARIF、共通help、Viewerのversion表示を修正した。filter_low=falseの評価漏れも対照テストで修正した([Task Seed 20260911-05](docs/tasks/20260911-05-manual-bb-fixes.md))。 +- v1のpartial_warning_thresholdを予約設定として仕様化し、入力完全性・allow_partialによる判定、warn_onlyの境界、rename表現を明記した。READMEのimportからexportまでの手順を同期した([Readiness入力仕様](docs/specs/readiness-input-contract.md))。 - policyの既知項目を解析済みYAMLから読み取り、書式による判定不一致とWindowsパスの切り詰めを修正する。同梱policyのID・件数上限を正式なキーへ整合する([Task Seed 20260911-04](docs/tasks/20260911-04-policy-yaml-sections.md))。 - partial policyを1行・複数行YAMLで同じように読み取り、不正な型をpolicyエラーとして拒否する([Task Seed 20260911-03](docs/tasks/20260911-03-partial-yaml.md))。 - 補助文書のpolicy例を理由付きの個別調整へ更新し、設定確認とGitHub/npmの配布状態を同期した([Task Seed 20260911-02](docs/tasks/20260911-02-readiness-diff-followups.md))。 diff --git a/CHECKLISTS.md b/CHECKLISTS.md index 2045819..def4e08 100644 --- a/CHECKLISTS.md +++ b/CHECKLISTS.md @@ -31,6 +31,12 @@ code-to-gate運用時のチェックリスト集。 ## Pull Request / Review +### manual-bb失敗の再検収 + +- baseline明示参照の競合、抑制path/期限のYAML同値性と不正日付、policyの空/負数/小数を正常対照と照合する。 +- readinessの同時刻run ID、warn_onlyの終了コードと不正入力拒否、SARIF/all生成、未知emit、global help、HTML versionを確認する。 +- [Readiness入力仕様](docs/specs/readiness-input-contract.md)のpartial 12通りを検証し、105ケースの証跡と修正差分の自動coverageでGateを再評価する。 + ### 2026-09-10 改修の検収 - 精度reviewは入力bytes・repo・commit・finding IDとevidenceを照合し、AI/未判定を人手精度合格にしない diff --git a/CLAUDE.md b/CLAUDE.md index aae5831..27526e8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -96,6 +96,8 @@ All artifacts use stable schemas in `schemas/`: ## Policy System +manual-bbの入力契約は[Readiness入力仕様](docs/specs/readiness-input-contract.md)に定義する。v1のpartial_warning_thresholdは予約値、warn_onlyは品質判定の終了コードのみ変更する。baselineの明示参照、独立readinessのID、抑制期限とYAML同値性は[Task 20260911-05](docs/tasks/20260911-05-manual-bb-fixes.md)で検収する。 + Policies are YAML files. See `docs/policy-guide.md` for the public guide. Common fields: diff --git a/GUARDRAILS.md b/GUARDRAILS.md index 339aea2..238dca0 100644 --- a/GUARDRAILS.md +++ b/GUARDRAILS.md @@ -33,6 +33,7 @@ code-to-gate運用時に守るべき原則と振る舞いを体系化する。 - 例外設計:既存 errors 階層に合わせ、再試行可否を区別する。 - 入力不完全は指摘件数と別の条件・理由・推奨操作で説明し、partial許可policyでも完全な解析と表示しない。 - partial設定はYAMLの書式ではなく解析後の値と型で判断し、不正な型を既定値で隠さずpolicyエラーにする。 +- v1で未定義の欠落割合をfinding件数から作らない。partial_warning_thresholdは予約値として検証し、完全性を変更しない。baselineの明示参照を別ファイルへ置き換えない。 - policyの既知項目は解析済みYAMLから読む。真偽値の末尾コメントで判定を変えず、文字列のコロン・空白・引用符の解釈をYAMLライブラリへ委ねる。同梱policyは実loaderで意図した設定値を確認する。 - diffの削除は入力欠落と区別し、残存importerの影響範囲と実際の読み取り失敗に対するpartial判定を維持する。 - 後方互換:CLI/JSON 出力は互換性を維持し、破壊的変更は明示的フラグで段階移行する。Schema version `ctg/v1` を遵守。 diff --git a/README.md b/README.md index b3b9cf7..927c6e7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Language: English | [日本語](README_JA.md) | Before a PR | [`analyze`](docs/cli-reference.md#analyze) or [`diff`](docs/cli-reference.md#diff) | Review points and changed-scope evidence | | QA planning | [`analyze`](docs/cli-reference.md#analyze) | Candidate tests in `test-seeds.json` | | Before a release | [`analyze`](docs/cli-reference.md#analyze), then `readiness` | Policy evaluation in `release-readiness.json` | -| CI result aggregation | [`import`](docs/cli-reference.md#import), then [`export`](docs/cli-reference.md#export) SARIF | Existing tool results and `results.sarif`; external tools are not run by these commands | +| CI result aggregation | [`import`](docs/cli-reference.md#import), `analyze --from-imports`, then [`export`](docs/cli-reference.md#export) SARIF | Existing tool results and `results.sarif`; use the same output directory for import and analyze | ## Current Distribution Status @@ -103,7 +103,14 @@ code-to-gate viewer --from .qh --out public/index.html --hosted ``` `import` consumes results that another tool has already produced; it does not -execute that tool. Use the imported artifacts as input to the relevant export. +execute that tool. Import and analyze must use the same output directory so that +analyze can read and validate the import manifest: + +```bash +code-to-gate import sarif ./external-results.sarif --repo-root ./my-repo --out .qh +code-to-gate analyze ./my-repo --from-imports --emit all --out .qh +code-to-gate export sarif --from .qh --out results.sarif +``` ## Limits and expectations diff --git a/README_EN.md b/README_EN.md index 3641bf2..ce770f3 100644 --- a/README_EN.md +++ b/README_EN.md @@ -14,7 +14,7 @@ seeds, SARIF, and release-readiness evidence. | Before a PR | [`analyze`](docs/cli-reference.md#analyze) or [`diff`](docs/cli-reference.md#diff) | Review points and changed-scope evidence | | QA planning | [`analyze`](docs/cli-reference.md#analyze) | Candidate tests in `test-seeds.json` | | Before a release | [`analyze`](docs/cli-reference.md#analyze), then `readiness` | Policy evaluation in `release-readiness.json` | -| CI result aggregation | [`import`](docs/cli-reference.md#import), then [`export`](docs/cli-reference.md#export) SARIF | Existing tool results and `results.sarif`; external tools are not run by these commands | +| CI result aggregation | [`import`](docs/cli-reference.md#import), `analyze --from-imports`, then [`export`](docs/cli-reference.md#export) SARIF | Existing tool results and `results.sarif`; use the same output directory for import and analyze | ## Distribution Status @@ -93,7 +93,14 @@ code-to-gate export evidence-dag --from .qh --out .qh/evidence-dag.json ``` `import` consumes results that another tool has already produced; it does not -execute that tool. Use the imported artifacts as input to the relevant export. +execute that tool. Import and analyze must use the same output directory so that +analyze can read and validate the import manifest: + +```bash +code-to-gate import sarif ./external-results.sarif --repo-root ./my-repo --out .qh +code-to-gate analyze ./my-repo --from-imports --emit all --out .qh +code-to-gate export sarif --from .qh --out results.sarif +``` ## Limits and expectations diff --git a/README_JA.md b/README_JA.md index beb76f6..3426710 100644 --- a/README_JA.md +++ b/README_JA.md @@ -24,6 +24,14 @@ finding は **review-required candidate** であり、確定済み脆弱性や 指摘が妥当なら修正・追加テストへ進み、誤検知や意図した設計なら理由を記録します。 外部解析ツールの結果を取り込む場合、そのツールの実行は別途必要です。 +既存のSARIFを取り込む場合は、importとanalyzeに同じ出力先を指定します。analyzeがimport manifestを検証してfindingsへ統合した後、exportします。 + +```bash +code-to-gate import sarif ./external-results.sarif --repo-root ./my-repo --out .qh +code-to-gate analyze ./my-repo --from-imports --emit all --out .qh +code-to-gate export sarif --from .qh --out results.sarif +``` + ## 公開状態 | チャネル | 状態 | diff --git a/docs/TASKS.md b/docs/TASKS.md index f8481a5..e80a417 100644 --- a/docs/TASKS.md +++ b/docs/TASKS.md @@ -65,6 +65,8 @@ next_review_due: YYYY-MM-DD ## 5. 登録済み Task Seeds +- [20260911-05-manual-bb-fixes](tasks/20260911-05-manual-bb-fixes.md) — manual-bbの10件修正、partial仕様確定、105ケース再検収 + - [20260910-01-ledger-sync](tasks/20260910-01-ledger-sync.md) — 改修台帳・文書同期(技術検収済み) - [20260910-02-precision-review](tasks/20260910-02-precision-review.md) — 実 repo 精度レビューの機能(技術検収済み、人手判定は別途) - [20260910-03-release-prep](tasks/20260910-03-release-prep.md) — 1.6.0 次版準備(ローカル検証済み、公開は別途) diff --git a/docs/acceptance/AC-20260911-05-manual-bb-fixes.md b/docs/acceptance/AC-20260911-05-manual-bb-fixes.md new file mode 100644 index 0000000..3573155 --- /dev/null +++ b/docs/acceptance/AC-20260911-05-manual-bb-fixes.md @@ -0,0 +1,55 @@ +--- +intent_id: INT-MANUAL-BB-FIXES +owner: code-to-gate-team +status: active +last_reviewed_at: 2026-09-11 +next_review_due: 2026-10-11 +--- + +# manual-bb失敗修正の検収 + +[Task Seed](../tasks/20260911-05-manual-bb-fixes.md)のローカル検収を完了した。**同じ105ケースを再実行し、105成功・失敗0・保留0。manual-bb native standard GateはGo。** PRのCI・main反映は対応PRで追跡する。変更はUnreleased、公開versionは1.6.0のままとする。 + +## 修正と仕様 + +修正前はmain `2fe6b2e0ec7a8d255cd5f29f6454580eb9664fdb`で95成功・9失敗・1保留。既知5件と新規5件(表示不整合を含む)の不具合を確認していた。 + +- baseline: 明示されたfindings参照を優先し、参照先がない場合は別の隣接ファイルへ置換しない。参照を持たない旧形式は互換を維持。 +- suppression: YAMLの引用・コメント・flow形式を統一。不正構文の部分採用を廃止し、不正期限と実在しない日付は適用しない。 +- policy: 空ID・version、不正な数値の型・値域・整数条件を検証。filter_low=falseの閾値未満findingも通常評価へ渡す。 +- readiness: 同時刻の独立実行IDを分離。warn_onlyは品質判定の終了コードだけを0にし、blocked status・条件・入力エラーを維持。 +- CLI/Viewer: 不正emitの拒否、SARIF生成、公開コマンドの共通help、artifact由来のversion表示を修正。 +- [Readiness入力仕様](../specs/readiness-input-contract.md): partial_warning_thresholdはv1では予約値。欠落割合の分子・母数がないため推定せず、completenessとallow_partialで判定する。PART-004で12組合せを検証。renameのv1表現とREADMEのimport→analyze→exportも同期。 + +元の10件に加え、関連するfilter_low=falseの不一致1件を解消した。既存POL-017へ対照を追加したため、ケース数は105を維持した。 + +## 公開経路の再検収 + +| 対象 | 成功/全数 | +|---|---:| +| 基本CLI・Viewer(実ブラウザを含む) | 32/32 | +| 既知不具合の再現・対照 | 5/5 | +| policy・抑制・baseline・partial・artifact | 41/41 | +| diff・import・export・agent連携 | 27/27 | + +条件IDだけでなく終了コードとstatusを検証する。未対応拡張子のdiffではcompleteness=partialとauditのブロック理由を照合した。PART-004はcomplete/partial × allow_partial=false/true × threshold=0/0.2/1を実行した。 + +Chromeで初期表示とヘッダー・フッターのv1.6.0を確認し、実ブラウザの検索0件/1件、finding詳細、Graph、Test Seedsを操作した。スクリーンショットも保存・目視確認した。localhost補助サーバーのfavicon 404以外にconsole errorはなかった。 + +## 自動検証とGate + +- build・lint・typecheck: 成功。 +- 通常テスト: 3,859成功、既存skip 4。Tree-sitter: 63成功。保守: 15成功。 +- 通常coverage: 1,970成功、既存skip 4。Statements 88.74%、Branches 80.60%、Functions 94.86%、Lines 89.66%。4項目とも80%条件を満たした。 +- 変更行coverage: 185/205行、90.24%。変更されたruntimeの実行行をIstanbul statement startsと差分で照合した。コメント・削除行は除外し、通常coverageの全体率を転用していない。追加対象1,049成功、skip 1。 +- package smoke: fresh buildしたtgzを隔離先へインストールし、CLI・SDK・agent・analyze・Viewer・precision-review・diffを検証して成功。初回の依存取得待ちを停止し、ネットワーク許可下で再実行した。 +- native standard Gate: Go。P0 15/15、P1 27/27、必須観点100%。未解決不具合0、waiverなし。runtime schemaによる114 artifactの検証エラー0。 +- 文書参照・配布状態・roadmap drift・Birdseye再生成/check・git diff --checkを確認。 + +## 証跡と適用範囲 + +証跡は同一workspaceの`code-to-gate-manual-bb-fix-20260911/`に保存。`report.md`、`cases.md`、`defects.json`、`artifacts/`、`environment.json`、`changed-line-coverage.json`、各実行のargv/cwd/stdout/stderrと成果物を含む。修正前の`code-to-gate-manual-bb-20260911/`は上書きしていない。 + +Build ID: `ctg-bb-f902a0135a79ee77117a`。ソースSHA256は外部`environment.json`に固定し、再検収・変更行coverage・package検証後もソースとcompiled CLIの不変を照合した。Node v24.11.0 / Windowsで実行。 + +これはagentによる公開CLI・ブラウザの検収で、人間によるUX承認とは区別する。対象はWindowsローカル・非LLMの主要フローであり、全OS・全言語の検出精度を保証するものではない。 diff --git a/docs/birdseye/BIRDSEYE.md b/docs/birdseye/BIRDSEYE.md index 732d3b0..2d1de8e 100644 --- a/docs/birdseye/BIRDSEYE.md +++ b/docs/birdseye/BIRDSEYE.md @@ -1,13 +1,13 @@ # Birdseye repository map -生成ID: `birdseye-d2d6a58ca24118dd` +生成ID: `birdseye-33377e4a68abbf61` この資産はseedと、そのseedから直接参照される実在のローカルfileだけを対象にした小範囲の案内です。node_modules、dist、.qh、.git、fixtures、外部importは辿りません。 -- node: 122 -- edge: 143 -- cap: 122 -- sourceHash: `d2d6a58ca24118ddf3a0d478678780097e237750650eaf95fb27a5263ced5d50` +- node: 126 +- edge: 150 +- cap: 126 +- sourceHash: `33377e4a68abbf61f80023f69517e2fb1e42d99686c457e49c71f20912344de8` ## 使い方 diff --git a/docs/birdseye/caps/.ctg.policy.yaml.2d4a1e58.json b/docs/birdseye/caps/.ctg.policy.yaml.2d4a1e58.json index d48d6bd..90ec311 100644 --- a/docs/birdseye/caps/.ctg.policy.yaml.2d4a1e58.json +++ b/docs/birdseye/caps/.ctg.policy.yaml.2d4a1e58.json @@ -10,5 +10,5 @@ "deps_in": [], "tests": [], "sourceHash": "e598cbb1e8537cb1bd082ad2c48437571a4a704f3bba21a0a1fbc06fe617bf32", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/CHANGELOG.md.06572a96.json b/docs/birdseye/caps/CHANGELOG.md.06572a96.json index fda05d2..aeadc83 100644 --- a/docs/birdseye/caps/CHANGELOG.md.06572a96.json +++ b/docs/birdseye/caps/CHANGELOG.md.06572a96.json @@ -10,6 +10,7 @@ "docs/acceptance/AC-20260910-15-release-1.6.0.md", "docs/distribution-status.md", "docs/releases/v1.6.0.md", + "docs/specs/readiness-input-contract.md", "docs/tasks/20260910-01-ledger-sync.md", "docs/tasks/20260910-02-precision-review.md", "docs/tasks/20260910-03-release-prep.md", @@ -24,13 +25,14 @@ "docs/tasks/20260911-01-human-readme.md", "docs/tasks/20260911-02-readiness-diff-followups.md", "docs/tasks/20260911-03-partial-yaml.md", - "docs/tasks/20260911-04-policy-yaml-sections.md" + "docs/tasks/20260911-04-policy-yaml-sections.md", + "docs/tasks/20260911-05-manual-bb-fixes.md" ], "deps_in": [ "CHECKLISTS.md", "README.md" ], "tests": [], - "sourceHash": "ca3ccf2b46c5a23014e1d1bcf45f8a69cd50e1390be3f91474f3a83150ef1523", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "085399754ede262f006112f943ffe028eec2388023a60c14ca674920977d80ae", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/CHECKLISTS.md.c3da629e.json b/docs/birdseye/caps/CHECKLISTS.md.c3da629e.json index 34ab987..3fc99bd 100644 --- a/docs/birdseye/caps/CHECKLISTS.md.c3da629e.json +++ b/docs/birdseye/caps/CHECKLISTS.md.c3da629e.json @@ -13,12 +13,13 @@ "docs/quality-evidence-os-spec.md", "docs/Release_Checklist.md", "docs/security/Security_Review_Checklist.md", + "docs/specs/readiness-input-contract.md", "docs/TASKS.md", "GUARDRAILS.md", "orchestration/quality-evidence-os-implementation.md" ], "deps_in": [], "tests": [], - "sourceHash": "7290d53f40310b4e7e95b0f24ec0f7d2ad20685af25fd59058e59698f2c17cdf", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "1265613c0628ef8a0c69ac9e2cc7217b4e5d2db6fc6e779edeab29661ad91714", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/CLAUDE.md.6ebdb617.json b/docs/birdseye/caps/CLAUDE.md.6ebdb617.json index 9014165..aa5e83d 100644 --- a/docs/birdseye/caps/CLAUDE.md.6ebdb617.json +++ b/docs/birdseye/caps/CLAUDE.md.6ebdb617.json @@ -11,14 +11,16 @@ "docs/precision-review.md", "docs/run-identity.md", "docs/severity-tuning.md", + "docs/specs/readiness-input-contract.md", "docs/specs/SPEC-26-custom-severity.md", "docs/tasks/20260910-04-birdseye.md", - "docs/tasks/20260910-05-severity-tuning.md" + "docs/tasks/20260910-05-severity-tuning.md", + "docs/tasks/20260911-05-manual-bb-fixes.md" ], "deps_in": [ "CHECKLISTS.md" ], "tests": [], - "sourceHash": "3497438a4a9d9d6469a0b23a6a4c0abf62797eeb802d3b7a0d93eb70afd9d057", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "7c5f5ad3ce66ea9a0be9fc5a248e7092315d95a1242a0ab0a05e83076ff7bc79", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/GUARDRAILS.md.dceca4b6.json b/docs/birdseye/caps/GUARDRAILS.md.dceca4b6.json index f7832c7..135382b 100644 --- a/docs/birdseye/caps/GUARDRAILS.md.dceca4b6.json +++ b/docs/birdseye/caps/GUARDRAILS.md.dceca4b6.json @@ -9,6 +9,6 @@ "CHECKLISTS.md" ], "tests": [], - "sourceHash": "ec3d4d6e2dd230943d49519a46e848b08e79044c6cfa673cf611b06cdaa87a50", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "467d8fe7c8ee762726b43619e91d09959bf9ca27d35c58e83b0d3aa405ba8e4c", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/README.md.b3356305.json b/docs/birdseye/caps/README.md.b3356305.json index 994d99c..a768f93 100644 --- a/docs/birdseye/caps/README.md.b3356305.json +++ b/docs/birdseye/caps/README.md.b3356305.json @@ -18,6 +18,6 @@ ], "deps_in": [], "tests": [], - "sourceHash": "cb2f12bb9c700e0a8651922029fc38437a9b0b8dc0fc14c090f20af969acaaa6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "b42afa1524db12e32599264b2eab94b29ab91b81fca1a670059d0e1d902b037f", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/README_JA.md.f271b369.json b/docs/birdseye/caps/README_JA.md.f271b369.json index 62db91e..5a1c72f 100644 --- a/docs/birdseye/caps/README_JA.md.f271b369.json +++ b/docs/birdseye/caps/README_JA.md.f271b369.json @@ -9,6 +9,6 @@ "README.md" ], "tests": [], - "sourceHash": "e6be7c74da7c2584f1301f7372d92577a8881b6e5a598c590fc94354b481d924", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "615b31bd1ded9799ebbcc2d966fc5573cb21624c4921f69c3804f3a98ba272b7", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.ADR.README.md.0468bb03.json b/docs/birdseye/caps/docs.ADR.README.md.0468bb03.json index 2901ecf..dcb0785 100644 --- a/docs/birdseye/caps/docs.ADR.README.md.0468bb03.json +++ b/docs/birdseye/caps/docs.ADR.README.md.0468bb03.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "72a7c2a87a44a36ec81ef6b4306281f658373607fb4e179390fb14f1ac3fefb4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.Release_Checklist.md.6185103b.json b/docs/birdseye/caps/docs.Release_Checklist.md.6185103b.json index a8bd843..1510512 100644 --- a/docs/birdseye/caps/docs.Release_Checklist.md.6185103b.json +++ b/docs/birdseye/caps/docs.Release_Checklist.md.6185103b.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "1069801dd55d4652788eedaec13918003aeac8d59717922a54193f688f02e9f7", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.TASKS.md.8519adad.json b/docs/birdseye/caps/docs.TASKS.md.8519adad.json index bb191c8..9646ab7 100644 --- a/docs/birdseye/caps/docs.TASKS.md.8519adad.json +++ b/docs/birdseye/caps/docs.TASKS.md.8519adad.json @@ -9,6 +9,6 @@ "CHECKLISTS.md" ], "tests": [], - "sourceHash": "052d9d2cb2c0e8440cf8cc135dcdbc512b2194718dc2917515c453bf3273ec68", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "fd2d8a506c2cdfced9ac55e0e75b4fcb8ee6ec67d53b18e0ab9a650b171bd450", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.acceptance.AC-20260910-02-precision-review.md.0a6af0d7.json b/docs/birdseye/caps/docs.acceptance.AC-20260910-02-precision-review.md.0a6af0d7.json index dde1d7a..0fc6b91 100644 --- a/docs/birdseye/caps/docs.acceptance.AC-20260910-02-precision-review.md.0a6af0d7.json +++ b/docs/birdseye/caps/docs.acceptance.AC-20260910-02-precision-review.md.0a6af0d7.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "e2a19c116bc5a9abcdbaed0fa37b467968da9f84c25b57d9482d7398ec3b65a6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.acceptance.AC-20260910-06-maintenance.md.f139681a.json b/docs/birdseye/caps/docs.acceptance.AC-20260910-06-maintenance.md.f139681a.json index 1e64354..21f4117 100644 --- a/docs/birdseye/caps/docs.acceptance.AC-20260910-06-maintenance.md.f139681a.json +++ b/docs/birdseye/caps/docs.acceptance.AC-20260910-06-maintenance.md.f139681a.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "cb63f053c6cb7fcc9bf3897153fe9da0102b92cc7f24b9eba1cc35e2d36c7b8b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.acceptance.AC-20260910-12-follow-up.md.b6a9b379.json b/docs/birdseye/caps/docs.acceptance.AC-20260910-12-follow-up.md.b6a9b379.json index bf4025c..2057096 100644 --- a/docs/birdseye/caps/docs.acceptance.AC-20260910-12-follow-up.md.b6a9b379.json +++ b/docs/birdseye/caps/docs.acceptance.AC-20260910-12-follow-up.md.b6a9b379.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "27c18c30b231ea19aed5bb433cc4ccefe53e70d9be85df3e4857dcd7a2f609a4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.acceptance.AC-20260910-14-ci-integration.md.d0d02354.json b/docs/birdseye/caps/docs.acceptance.AC-20260910-14-ci-integration.md.d0d02354.json index 05029e8..d23b7da 100644 --- a/docs/birdseye/caps/docs.acceptance.AC-20260910-14-ci-integration.md.d0d02354.json +++ b/docs/birdseye/caps/docs.acceptance.AC-20260910-14-ci-integration.md.d0d02354.json @@ -11,5 +11,5 @@ ], "tests": [], "sourceHash": "9a4ed75d254862a75d71acc796a90d05681b04671866b25ca483c4c55a24b371", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.acceptance.AC-20260910-15-release-1.6.0.md.191462f2.json b/docs/birdseye/caps/docs.acceptance.AC-20260910-15-release-1.6.0.md.191462f2.json index 94e5d76..3a3e967 100644 --- a/docs/birdseye/caps/docs.acceptance.AC-20260910-15-release-1.6.0.md.191462f2.json +++ b/docs/birdseye/caps/docs.acceptance.AC-20260910-15-release-1.6.0.md.191462f2.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "e08c95fbe35461b056a995ecb945cfd4ae8e835076a852797db4951f22841ac2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.cli-reference.md.d5d8360d.json b/docs/birdseye/caps/docs.cli-reference.md.d5d8360d.json index 0049d7b..7a8c169 100644 --- a/docs/birdseye/caps/docs.cli-reference.md.d5d8360d.json +++ b/docs/birdseye/caps/docs.cli-reference.md.d5d8360d.json @@ -9,6 +9,6 @@ "README.md" ], "tests": [], - "sourceHash": "571621c5914fe5fb0a4094f2761d78a71c52a30c8e4c29d7ebe5a0cf43875f66", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "bcabe8108b7926b26c4d5c1e341aa9859b98142d219e86a1473af31a2af1ee52", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.distribution-status.md.7c82a2f3.json b/docs/birdseye/caps/docs.distribution-status.md.7c82a2f3.json index 28593ff..11bb805 100644 --- a/docs/birdseye/caps/docs.distribution-status.md.7c82a2f3.json +++ b/docs/birdseye/caps/docs.distribution-status.md.7c82a2f3.json @@ -11,5 +11,5 @@ ], "tests": [], "sourceHash": "acc90979086979069844edb7b7a70fd281608a3437f02175daae3a098f157a82", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.integrations.md.98423805.json b/docs/birdseye/caps/docs.integrations.md.98423805.json index 547eebf..9cb3f7a 100644 --- a/docs/birdseye/caps/docs.integrations.md.98423805.json +++ b/docs/birdseye/caps/docs.integrations.md.98423805.json @@ -15,5 +15,5 @@ ], "tests": [], "sourceHash": "39d4398638ba48974e034db741619449581e498c8fbfecde15970b819a52cddb", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.plugin-development.md.f86abbd7.json b/docs/birdseye/caps/docs.plugin-development.md.f86abbd7.json index 7b64da2..ec3294e 100644 --- a/docs/birdseye/caps/docs.plugin-development.md.f86abbd7.json +++ b/docs/birdseye/caps/docs.plugin-development.md.f86abbd7.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "971f433e3f2b84145ac6e112dd8693e351e3428f087f1c09164cd56d24374f89", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.policy-guide.md.294e87e0.json b/docs/birdseye/caps/docs.policy-guide.md.294e87e0.json index 9f63bbe..6827387 100644 --- a/docs/birdseye/caps/docs.policy-guide.md.294e87e0.json +++ b/docs/birdseye/caps/docs.policy-guide.md.294e87e0.json @@ -9,6 +9,6 @@ "README.md" ], "tests": [], - "sourceHash": "d56d388f3c794725b093f41eaf6daa829e2a14433d23d0a4c5fa29ea442c05a4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "3342b9559ffcd72b700e08160b79a869f29a4212fb57d1c2411d58171f10bb90", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.precision-review.md.2d78a86b.json b/docs/birdseye/caps/docs.precision-review.md.2d78a86b.json index da2246f..e50dcd7 100644 --- a/docs/birdseye/caps/docs.precision-review.md.2d78a86b.json +++ b/docs/birdseye/caps/docs.precision-review.md.2d78a86b.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "8366da73e8d334d4733ea7b15d944ad80548043543fb3035ea43045ba8c6f0be", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.quality-evidence-os-expansion-ideas.md.43bffbc2.json b/docs/birdseye/caps/docs.quality-evidence-os-expansion-ideas.md.43bffbc2.json index e67ffa5..3a2e7f3 100644 --- a/docs/birdseye/caps/docs.quality-evidence-os-expansion-ideas.md.43bffbc2.json +++ b/docs/birdseye/caps/docs.quality-evidence-os-expansion-ideas.md.43bffbc2.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "089fb7b77c52af0903512fc7cf7f25089a4cfd2fda700285a1e6b04006e84464", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.quality-evidence-os-requirements.md.50e55101.json b/docs/birdseye/caps/docs.quality-evidence-os-requirements.md.50e55101.json index 94b9f36..fb164b8 100644 --- a/docs/birdseye/caps/docs.quality-evidence-os-requirements.md.50e55101.json +++ b/docs/birdseye/caps/docs.quality-evidence-os-requirements.md.50e55101.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "ba0df900f803101a2384a74c70d0bf07b1d6a6c19c9887282a7ad4c0ab9526b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.quality-evidence-os-spec.md.9124ece5.json b/docs/birdseye/caps/docs.quality-evidence-os-spec.md.9124ece5.json index c563edd..ddd9e1d 100644 --- a/docs/birdseye/caps/docs.quality-evidence-os-spec.md.9124ece5.json +++ b/docs/birdseye/caps/docs.quality-evidence-os-spec.md.9124ece5.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "6a71b6bbb02d55872135e95e22f8537c3fbd9e7d62c714883189cd300ae3805d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.quickstart.md.988a5392.json b/docs/birdseye/caps/docs.quickstart.md.988a5392.json index 596ff07..fa69f1b 100644 --- a/docs/birdseye/caps/docs.quickstart.md.988a5392.json +++ b/docs/birdseye/caps/docs.quickstart.md.988a5392.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "46fed513f86d121f58895a057e9fe55c184f0e57996a99b60f0d207b0e177673", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.releases.v1.6.0.md.1834bf67.json b/docs/birdseye/caps/docs.releases.v1.6.0.md.1834bf67.json index 88e5411..c8ce135 100644 --- a/docs/birdseye/caps/docs.releases.v1.6.0.md.1834bf67.json +++ b/docs/birdseye/caps/docs.releases.v1.6.0.md.1834bf67.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "48a17a45ad0c05a734b4e0f119b4ffbe08d996316c27b66a5907a8056b36d388", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.run-identity.md.fab417c4.json b/docs/birdseye/caps/docs.run-identity.md.fab417c4.json index 830fe15..05cfcc2 100644 --- a/docs/birdseye/caps/docs.run-identity.md.fab417c4.json +++ b/docs/birdseye/caps/docs.run-identity.md.fab417c4.json @@ -9,6 +9,6 @@ "CLAUDE.md" ], "tests": [], - "sourceHash": "00d7564332b54a10d573ebbdcbf8c4560563bbb66b972fa47a67c5ffb8bf313f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "7f6ba13dbce7ddbd782977b2c6f788b07c42387d36e71dc22ff169e9f36428e7", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.security-gate.md.f5244ab0.json b/docs/birdseye/caps/docs.security-gate.md.f5244ab0.json index 8bacc14..e25f494 100644 --- a/docs/birdseye/caps/docs.security-gate.md.f5244ab0.json +++ b/docs/birdseye/caps/docs.security-gate.md.f5244ab0.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "95858445632021e5ddf779d429168aa4827a6ef5cfebff14285b9bb8b6359168", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.security.Security_Review_Checklist.md.f023a01f.json b/docs/birdseye/caps/docs.security.Security_Review_Checklist.md.f023a01f.json index bf1233d..d5e9a8a 100644 --- a/docs/birdseye/caps/docs.security.Security_Review_Checklist.md.f023a01f.json +++ b/docs/birdseye/caps/docs.security.Security_Review_Checklist.md.f023a01f.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "a12e368479cf46a042d7ae7b04edf9205238b9e8ed5cbeca85331b076c620acc", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.severity-tuning.md.6c588e6a.json b/docs/birdseye/caps/docs.severity-tuning.md.6c588e6a.json index c5f2915..484d2e3 100644 --- a/docs/birdseye/caps/docs.severity-tuning.md.6c588e6a.json +++ b/docs/birdseye/caps/docs.severity-tuning.md.6c588e6a.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "02b724772a9817cfa8f2e7edf1a2da06afb0f8967c5a53c484569b901eb77ec8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.specs.SPEC-26-custom-severity.md.368deb68.json b/docs/birdseye/caps/docs.specs.SPEC-26-custom-severity.md.368deb68.json index c7609d7..04b9b5c 100644 --- a/docs/birdseye/caps/docs.specs.SPEC-26-custom-severity.md.368deb68.json +++ b/docs/birdseye/caps/docs.specs.SPEC-26-custom-severity.md.368deb68.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "f7254dc2656f0f693ebf6f96e22b04981c932ca7cc8888f4382e7fe95d78942c", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.specs.readiness-input-contract.md.21b8d190.json b/docs/birdseye/caps/docs.specs.readiness-input-contract.md.21b8d190.json new file mode 100644 index 0000000..63047bb --- /dev/null +++ b/docs/birdseye/caps/docs.specs.readiness-input-contract.md.21b8d190.json @@ -0,0 +1,16 @@ +{ + "schema": "birdseye/cap/v1", + "id": "docs/specs/readiness-input-contract.md", + "role": "dependency", + "summary": "Readiness入力・警告・実行識別の仕様", + "public_api": [], + "deps_out": [], + "deps_in": [ + "CHANGELOG.md", + "CHECKLISTS.md", + "CLAUDE.md" + ], + "tests": [], + "sourceHash": "e5094db3168880d8a66af4f831dbc92ba868e2fd8b3823ea850d630beeeac769", + "generation_id": "birdseye-33377e4a68abbf61" +} diff --git a/docs/birdseye/caps/docs.tasks.20260910-01-ledger-sync.md.594633b9.json b/docs/birdseye/caps/docs.tasks.20260910-01-ledger-sync.md.594633b9.json index 3c5f3a9..2b6148e 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-01-ledger-sync.md.594633b9.json +++ b/docs/birdseye/caps/docs.tasks.20260910-01-ledger-sync.md.594633b9.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "94bb31f87e5afbe72d2f09703c5c3b84fc4245228e7d073afc7a0295680f3b50", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-02-precision-review.md.81603b28.json b/docs/birdseye/caps/docs.tasks.20260910-02-precision-review.md.81603b28.json index 1fee8a9..9844575 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-02-precision-review.md.81603b28.json +++ b/docs/birdseye/caps/docs.tasks.20260910-02-precision-review.md.81603b28.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "4096f63f242f95a0052b49ba2d589813a363dc40734cfa2e8fa6c11e3bffeda1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-03-release-prep.md.7b0d89dc.json b/docs/birdseye/caps/docs.tasks.20260910-03-release-prep.md.7b0d89dc.json index b3ecc62..7856500 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-03-release-prep.md.7b0d89dc.json +++ b/docs/birdseye/caps/docs.tasks.20260910-03-release-prep.md.7b0d89dc.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "25d7225b6d8bfcf330bb465b787f738bb6df335f3fc67d484abab781f1102b95", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-04-birdseye.md.d868a6ea.json b/docs/birdseye/caps/docs.tasks.20260910-04-birdseye.md.d868a6ea.json index cd3a45d..8ff87d2 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-04-birdseye.md.d868a6ea.json +++ b/docs/birdseye/caps/docs.tasks.20260910-04-birdseye.md.d868a6ea.json @@ -11,5 +11,5 @@ ], "tests": [], "sourceHash": "cdbe3a7a66633b31f275fbe701756949dc7133ae4fc3fc07441dfdc94d026403", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-05-severity-tuning.md.050c359a.json b/docs/birdseye/caps/docs.tasks.20260910-05-severity-tuning.md.050c359a.json index 2ab2862..0388d9e 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-05-severity-tuning.md.050c359a.json +++ b/docs/birdseye/caps/docs.tasks.20260910-05-severity-tuning.md.050c359a.json @@ -11,5 +11,5 @@ ], "tests": [], "sourceHash": "b2b298338654d3d3026d0475d436e282baa2ec0edcc0a4b792f3321fe4f6d53a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-07-ci-maintenance.md.1efb06be.json b/docs/birdseye/caps/docs.tasks.20260910-07-ci-maintenance.md.1efb06be.json index ec854eb..f992c43 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-07-ci-maintenance.md.1efb06be.json +++ b/docs/birdseye/caps/docs.tasks.20260910-07-ci-maintenance.md.1efb06be.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "e82c74d94bc31254c144dc03a9a46e638ac516b9d17afab93b29799669c43572", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-08-run-identity.md.116677b7.json b/docs/birdseye/caps/docs.tasks.20260910-08-run-identity.md.116677b7.json index ce411f1..df4afdc 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-08-run-identity.md.116677b7.json +++ b/docs/birdseye/caps/docs.tasks.20260910-08-run-identity.md.116677b7.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "f047e844ceee28c35c56c7a6b85c644188843c91676f8f319607bbd12c9f070b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-09-diff-severity.md.2c574c05.json b/docs/birdseye/caps/docs.tasks.20260910-09-diff-severity.md.2c574c05.json index 0ebbcb4..409dc80 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-09-diff-severity.md.2c574c05.json +++ b/docs/birdseye/caps/docs.tasks.20260910-09-diff-severity.md.2c574c05.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "aa3dd0e0c6be22bc66bbbcb03932e5cbed1b8c571bd7c178fe79be2355b2338f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-10-precision-workbench.md.595c47c0.json b/docs/birdseye/caps/docs.tasks.20260910-10-precision-workbench.md.595c47c0.json index 75eed56..faec881 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-10-precision-workbench.md.595c47c0.json +++ b/docs/birdseye/caps/docs.tasks.20260910-10-precision-workbench.md.595c47c0.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "d46f660cba4819c6a5eac830359357c8f365dd2409043b00103c1e7da1e1a8ab", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-11-severity-report.md.a91b9b8f.json b/docs/birdseye/caps/docs.tasks.20260910-11-severity-report.md.a91b9b8f.json index f182bdd..4928a79 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-11-severity-report.md.a91b9b8f.json +++ b/docs/birdseye/caps/docs.tasks.20260910-11-severity-report.md.a91b9b8f.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "ba07475fa9b20d29098f88b5df641cc68bd816416a78cda7803e796d05b8a2c8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260910-12-release-1.6.0.md.8f53b201.json b/docs/birdseye/caps/docs.tasks.20260910-12-release-1.6.0.md.8f53b201.json index 4318283..5d95382 100644 --- a/docs/birdseye/caps/docs.tasks.20260910-12-release-1.6.0.md.8f53b201.json +++ b/docs/birdseye/caps/docs.tasks.20260910-12-release-1.6.0.md.8f53b201.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "13df45d8e795a6169bc740fc403599428f79c35102b895c565d3797ce5958a73", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260911-01-human-readme.md.3b2d7f9c.json b/docs/birdseye/caps/docs.tasks.20260911-01-human-readme.md.3b2d7f9c.json index 339e35c..3f855ad 100644 --- a/docs/birdseye/caps/docs.tasks.20260911-01-human-readme.md.3b2d7f9c.json +++ b/docs/birdseye/caps/docs.tasks.20260911-01-human-readme.md.3b2d7f9c.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "84c122973c48b41acf97bd9fadfff28ae267bdf9c7927cc31d3cb1ac83c6857a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260911-02-readiness-diff-followups.md.aa62438b.json b/docs/birdseye/caps/docs.tasks.20260911-02-readiness-diff-followups.md.aa62438b.json index 04955fa..65ae18c 100644 --- a/docs/birdseye/caps/docs.tasks.20260911-02-readiness-diff-followups.md.aa62438b.json +++ b/docs/birdseye/caps/docs.tasks.20260911-02-readiness-diff-followups.md.aa62438b.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "223f7e9e44b262b2b450df25f52fe6eb6ddb163666c91c1ebe07ad05583936f0", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260911-03-partial-yaml.md.c29e74b8.json b/docs/birdseye/caps/docs.tasks.20260911-03-partial-yaml.md.c29e74b8.json index 47c2916..55afdab 100644 --- a/docs/birdseye/caps/docs.tasks.20260911-03-partial-yaml.md.c29e74b8.json +++ b/docs/birdseye/caps/docs.tasks.20260911-03-partial-yaml.md.c29e74b8.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "21d59a5adea79664b501d3cab84ffcd2074c541fb80acd05bcbbb4be8d58ca00", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260911-04-policy-yaml-sections.md.c9b814ee.json b/docs/birdseye/caps/docs.tasks.20260911-04-policy-yaml-sections.md.c9b814ee.json index 396d142..44c58d1 100644 --- a/docs/birdseye/caps/docs.tasks.20260911-04-policy-yaml-sections.md.c9b814ee.json +++ b/docs/birdseye/caps/docs.tasks.20260911-04-policy-yaml-sections.md.c9b814ee.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "0db4e04b305c97d60075b23f67d34ad37993c8479996308fde2b3cd762bf9bee", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/docs.tasks.20260911-05-manual-bb-fixes.md.e52c8561.json b/docs/birdseye/caps/docs.tasks.20260911-05-manual-bb-fixes.md.e52c8561.json new file mode 100644 index 0000000..7033aac --- /dev/null +++ b/docs/birdseye/caps/docs.tasks.20260911-05-manual-bb-fixes.md.e52c8561.json @@ -0,0 +1,15 @@ +{ + "schema": "birdseye/cap/v1", + "id": "docs/tasks/20260911-05-manual-bb-fixes.md", + "role": "dependency", + "summary": "manual-bbの失敗修正と未確定仕様の確定", + "public_api": [], + "deps_out": [], + "deps_in": [ + "CHANGELOG.md", + "CLAUDE.md" + ], + "tests": [], + "sourceHash": "8a159ba8598ea6d8557d836931bc885e342d46270046a7af1706585e5001e2a1", + "generation_id": "birdseye-33377e4a68abbf61" +} diff --git a/docs/birdseye/caps/docs.troubleshooting.md.373ebedf.json b/docs/birdseye/caps/docs.troubleshooting.md.373ebedf.json index f9e3a16..c0fc814 100644 --- a/docs/birdseye/caps/docs.troubleshooting.md.373ebedf.json +++ b/docs/birdseye/caps/docs.troubleshooting.md.373ebedf.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "b10d632688429d4b23186696d2f271a3ace97c2d2a342a88d7fcd37c3c406c83", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/governance.policy.yaml.e07e5077.json b/docs/birdseye/caps/governance.policy.yaml.e07e5077.json index 786f5cb..8e68142 100644 --- a/docs/birdseye/caps/governance.policy.yaml.e07e5077.json +++ b/docs/birdseye/caps/governance.policy.yaml.e07e5077.json @@ -10,5 +10,5 @@ "deps_in": [], "tests": [], "sourceHash": "0983f100271ecd79dd56e5e9f5ecbeb648c4e8000f64cf568c85d47e6b8d714b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/orchestration.quality-evidence-os-implementation.md.f0809670.json b/docs/birdseye/caps/orchestration.quality-evidence-os-implementation.md.f0809670.json index 26010ac..971c392 100644 --- a/docs/birdseye/caps/orchestration.quality-evidence-os-implementation.md.f0809670.json +++ b/docs/birdseye/caps/orchestration.quality-evidence-os-implementation.md.f0809670.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "60b070819f5a09fe4ac6ddba8595ebb0b7f2bbe349df156dbbc275a830cf4147", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.go-tree-sitter-adapter.ts.91a8b58f.json b/docs/birdseye/caps/src.adapters.go-tree-sitter-adapter.ts.91a8b58f.json index a37dec7..e530461 100644 --- a/docs/birdseye/caps/src.adapters.go-tree-sitter-adapter.ts.91a8b58f.json +++ b/docs/birdseye/caps/src.adapters.go-tree-sitter-adapter.ts.91a8b58f.json @@ -18,5 +18,5 @@ "src/adapters/__tests__/go-tree-sitter-adapter.test.ts" ], "sourceHash": "f1a15198d4bba0f7202d61e315b72e8cc7b97a6056b170ada197dd29ef63ff24", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.js-adapter.ts.6ad91ba1.json b/docs/birdseye/caps/src.adapters.js-adapter.ts.6ad91ba1.json index 57c4132..3fff91a 100644 --- a/docs/birdseye/caps/src.adapters.js-adapter.ts.6ad91ba1.json +++ b/docs/birdseye/caps/src.adapters.js-adapter.ts.6ad91ba1.json @@ -14,5 +14,5 @@ "src/adapters/__tests__/js-adapter.test.ts" ], "sourceHash": "1f5b5ed041aa221d02770e665cdbdafe1e6c47d3e1037f22218c443ccd09282a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.node-services.ts.286a59fd.json b/docs/birdseye/caps/src.adapters.node-services.ts.286a59fd.json index 94b21a2..6207f4a 100644 --- a/docs/birdseye/caps/src.adapters.node-services.ts.286a59fd.json +++ b/docs/birdseye/caps/src.adapters.node-services.ts.286a59fd.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "47a9f94de6e6c0457d096825269ec57f305a5f4cf0288f349af4b4685a4923e0", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.parser-registry.ts.b4dbc7a2.json b/docs/birdseye/caps/src.adapters.parser-registry.ts.b4dbc7a2.json index 1c5d2ee..3fb9ffc 100644 --- a/docs/birdseye/caps/src.adapters.parser-registry.ts.b4dbc7a2.json +++ b/docs/birdseye/caps/src.adapters.parser-registry.ts.b4dbc7a2.json @@ -29,5 +29,5 @@ "src/adapters/__tests__/parser-registry.test.ts" ], "sourceHash": "706011edc8dc137e2a8b688c05c48e0b522cf52ecbf4048c21fc866ec9b0fb95", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.py-adapter.ts.e3ceda63.json b/docs/birdseye/caps/src.adapters.py-adapter.ts.e3ceda63.json index d29234a..4cae4d9 100644 --- a/docs/birdseye/caps/src.adapters.py-adapter.ts.e3ceda63.json +++ b/docs/birdseye/caps/src.adapters.py-adapter.ts.e3ceda63.json @@ -15,5 +15,5 @@ "src/adapters/__tests__/py-adapter.test.ts" ], "sourceHash": "06a08e3fa54da053974d489ad3f4d883e9d6f52d45ce12746502249bdaba4255", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.py-tree-sitter-adapter.ts.6986beaf.json b/docs/birdseye/caps/src.adapters.py-tree-sitter-adapter.ts.6986beaf.json index fa4f9cb..2d80285 100644 --- a/docs/birdseye/caps/src.adapters.py-tree-sitter-adapter.ts.6986beaf.json +++ b/docs/birdseye/caps/src.adapters.py-tree-sitter-adapter.ts.6986beaf.json @@ -18,5 +18,5 @@ "src/adapters/__tests__/py-tree-sitter-adapter.test.ts" ], "sourceHash": "69777afd9d76822c4cac97104265f820be74204b18b201d388751d9286c30304", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.rb-adapter.ts.183f73ec.json b/docs/birdseye/caps/src.adapters.rb-adapter.ts.183f73ec.json index 86b9a93..c43fb47 100644 --- a/docs/birdseye/caps/src.adapters.rb-adapter.ts.183f73ec.json +++ b/docs/birdseye/caps/src.adapters.rb-adapter.ts.183f73ec.json @@ -14,5 +14,5 @@ "src/adapters/__tests__/rb-adapter.test.ts" ], "sourceHash": "7ff1976c6962aa5d9a1b79a008a64d820fae2743cc0f86401415416a91f5c08a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.rb-tree-sitter-adapter.ts.7b7c067c.json b/docs/birdseye/caps/src.adapters.rb-tree-sitter-adapter.ts.7b7c067c.json index f0caf75..f18b777 100644 --- a/docs/birdseye/caps/src.adapters.rb-tree-sitter-adapter.ts.7b7c067c.json +++ b/docs/birdseye/caps/src.adapters.rb-tree-sitter-adapter.ts.7b7c067c.json @@ -18,5 +18,5 @@ "src/adapters/__tests__/rb-tree-sitter-adapter.test.ts" ], "sourceHash": "9d4d7b1a846dba4469374c1a7b5687ce05c65f9464e6451bc05f7c9fc5da2ca2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.regex-language-adapter.ts.f14d6d2a.json b/docs/birdseye/caps/src.adapters.regex-language-adapter.ts.f14d6d2a.json index f3c97fc..e9b840a 100644 --- a/docs/birdseye/caps/src.adapters.regex-language-adapter.ts.f14d6d2a.json +++ b/docs/birdseye/caps/src.adapters.regex-language-adapter.ts.f14d6d2a.json @@ -15,5 +15,5 @@ "src/adapters/__tests__/regex-language-adapter.test.ts" ], "sourceHash": "ed66f94b80e743f5e1f33b89b2c9548c1d4fc431244773f0dd948c0ca6b6af19", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.rs-tree-sitter-adapter.ts.0282d361.json b/docs/birdseye/caps/src.adapters.rs-tree-sitter-adapter.ts.0282d361.json index 9f9895e..414d25e 100644 --- a/docs/birdseye/caps/src.adapters.rs-tree-sitter-adapter.ts.0282d361.json +++ b/docs/birdseye/caps/src.adapters.rs-tree-sitter-adapter.ts.0282d361.json @@ -18,5 +18,5 @@ "src/adapters/__tests__/rs-tree-sitter-adapter.test.ts" ], "sourceHash": "133363bd94b24556f0e559e89386f75a2731a1de8601d0c5ef47bc6ea45d73b8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.tree-sitter-initializer.ts.f63a8860.json b/docs/birdseye/caps/src.adapters.tree-sitter-initializer.ts.f63a8860.json index 4c586cc..b81205c 100644 --- a/docs/birdseye/caps/src.adapters.tree-sitter-initializer.ts.f63a8860.json +++ b/docs/birdseye/caps/src.adapters.tree-sitter-initializer.ts.f63a8860.json @@ -23,5 +23,5 @@ ], "tests": [], "sourceHash": "f83ee08b3f4971f3881c521cd95adcee6f5d88770edf49548dd3233a11db8d5a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.adapters.ts-adapter.ts.d063679e.json b/docs/birdseye/caps/src.adapters.ts-adapter.ts.d063679e.json index d1e7f1d..6fb56e8 100644 --- a/docs/birdseye/caps/src.adapters.ts-adapter.ts.d063679e.json +++ b/docs/birdseye/caps/src.adapters.ts-adapter.ts.d063679e.json @@ -14,5 +14,5 @@ "src/adapters/__tests__/ts-adapter.test.ts" ], "sourceHash": "437b6b0153ebd8a9d6ef3f3cc2edf18af4dc2a12494c2c970aba040ff00eab01", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.application.context.ts.e96fed93.json b/docs/birdseye/caps/src.application.context.ts.e96fed93.json index 9c032fc..99310b6 100644 --- a/docs/birdseye/caps/src.application.context.ts.e96fed93.json +++ b/docs/birdseye/caps/src.application.context.ts.e96fed93.json @@ -13,5 +13,5 @@ ], "tests": [], "sourceHash": "62d7b80de02c7a60d9c949bdaac57c541af4d4645a228f08835a852f8ce31759", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.application.rule-evaluator.ts.b8a66427.json b/docs/birdseye/caps/src.application.rule-evaluator.ts.b8a66427.json index 1ccda95..a4b8c15 100644 --- a/docs/birdseye/caps/src.application.rule-evaluator.ts.b8a66427.json +++ b/docs/birdseye/caps/src.application.rule-evaluator.ts.b8a66427.json @@ -16,5 +16,5 @@ "src/application/__tests__/rule-evaluator.test.ts" ], "sourceHash": "4d73e84f57d825045d671f3a3dff2eef2f340cb1915f09d0371ed755c4dfce9f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cache.index.ts.548fc051.json b/docs/birdseye/caps/src.cache.index.ts.548fc051.json index f4acdf6..74e294f 100644 --- a/docs/birdseye/caps/src.cache.index.ts.548fc051.json +++ b/docs/birdseye/caps/src.cache.index.ts.548fc051.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "284492164b80003538fd82a019f7d4416ccbb5deabda3a8e3b71a11b4d364f97", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.analyze.ts.dcb44679.json b/docs/birdseye/caps/src.cli.analyze.ts.dcb44679.json index 57762c7..c75a587 100644 --- a/docs/birdseye/caps/src.cli.analyze.ts.dcb44679.json +++ b/docs/birdseye/caps/src.cli.analyze.ts.dcb44679.json @@ -31,6 +31,7 @@ "src/reporters/llm-enrichment.ts", "src/reporters/markdown-reporter.ts", "src/reporters/raw-findings-reporter.ts", + "src/reporters/sarif-reporter.ts", "src/reporters/self-analysis-debt-reporter.ts", "src/reporters/test-seed-generator.ts", "src/reporters/yaml-reporter.ts", @@ -44,6 +45,6 @@ "src/cli/__tests__/analyze-imports-security.test.ts", "src/cli/__tests__/analyze.test.ts" ], - "sourceHash": "88b060789f31af41c7c225259a0b4dbc4842a64cc2ba0cf4cf7670622fc1494f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "8bedcb160eed9bf6eafa85a99660eb23e7ce53b285d967536cb8d4b6cd4fbade", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.exit-codes.ts.b1518d64.json b/docs/birdseye/caps/src.cli.exit-codes.ts.b1518d64.json index 29249d4..26daebd 100644 --- a/docs/birdseye/caps/src.cli.exit-codes.ts.b1518d64.json +++ b/docs/birdseye/caps/src.cli.exit-codes.ts.b1518d64.json @@ -24,5 +24,5 @@ "src/cli/__tests__/exit-codes.test.ts" ], "sourceHash": "a1245cc568a34a36e1a07912760588d6a23591bf09b17089c58854a3d5504bc4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.import-consumer.ts.acce18d5.json b/docs/birdseye/caps/src.cli.import-consumer.ts.acce18d5.json index 29fde94..5ab66e7 100644 --- a/docs/birdseye/caps/src.cli.import-consumer.ts.acce18d5.json +++ b/docs/birdseye/caps/src.cli.import-consumer.ts.acce18d5.json @@ -16,5 +16,5 @@ "src/cli/__tests__/import-consumer.test.ts" ], "sourceHash": "24460e24c90268486eb00245c1d0c50087b6f2225305050b8c8fcbba63173466", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.intake-artifact.ts.ed77b4f6.json b/docs/birdseye/caps/src.cli.intake-artifact.ts.ed77b4f6.json index cd7df20..5cf75eb 100644 --- a/docs/birdseye/caps/src.cli.intake-artifact.ts.ed77b4f6.json +++ b/docs/birdseye/caps/src.cli.intake-artifact.ts.ed77b4f6.json @@ -14,5 +14,5 @@ ], "tests": [], "sourceHash": "98504b8ceea65018d2ecd1cb1afe140b8464d1c6b47855b959bdef54d7147155", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.output.ts.5a5e76d7.json b/docs/birdseye/caps/src.cli.output.ts.5a5e76d7.json index d89012b..7e7d645 100644 --- a/docs/birdseye/caps/src.cli.output.ts.5a5e76d7.json +++ b/docs/birdseye/caps/src.cli.output.ts.5a5e76d7.json @@ -15,5 +15,5 @@ ], "tests": [], "sourceHash": "3af8abcfc832b27aa77d3fd100d998696bbd68250725eb29cc9901eea3537e49", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.readiness.ts.1650193f.json b/docs/birdseye/caps/src.cli.readiness.ts.1650193f.json index ab654b6..fca1274 100644 --- a/docs/birdseye/caps/src.cli.readiness.ts.1650193f.json +++ b/docs/birdseye/caps/src.cli.readiness.ts.1650193f.json @@ -18,7 +18,8 @@ "src/reporters/index.ts", "src/reporters/raw-findings-reporter.ts", "src/self-analysis/suppression-summary.ts", - "src/types/artifacts.ts" + "src/types/artifacts.ts", + "src/utils/run-id.ts" ], "deps_in": [], "tests": [ @@ -26,6 +27,6 @@ "src/cli/__tests__/readiness-policy-yaml.test.ts", "src/cli/__tests__/readiness.test.ts" ], - "sourceHash": "5c0762332c963710d33b2e82bb312c3cedb5a7ac25601a10e2635ccbce6077b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "1421bacb00652e57872dd74bfcbf82e29b4f212ed40c89639a5bedc77a619f57", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.scan.ts.46daf9fd.json b/docs/birdseye/caps/src.cli.scan.ts.46daf9fd.json index ca8d61a..3b85174 100644 --- a/docs/birdseye/caps/src.cli.scan.ts.46daf9fd.json +++ b/docs/birdseye/caps/src.cli.scan.ts.46daf9fd.json @@ -21,5 +21,5 @@ "src/cli/__tests__/scan.test.ts" ], "sourceHash": "f4e626c2704ee6af9e6ef9fd827c0c609b1b415efc1eaf431f8eb7fa63d3e19d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.cli.schema-validate.ts.72f9f1dd.json b/docs/birdseye/caps/src.cli.schema-validate.ts.72f9f1dd.json index 96a3dae..8b6f39c 100644 --- a/docs/birdseye/caps/src.cli.schema-validate.ts.72f9f1dd.json +++ b/docs/birdseye/caps/src.cli.schema-validate.ts.72f9f1dd.json @@ -20,5 +20,5 @@ "src/cli/__tests__/schema-validate.test.ts" ], "sourceHash": "6ec467ba0020c2b044e0f388f23a41d8999ebf70dbb57a5613541845b1dcbb8c", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.config.policy-evaluator.ts.692ff63a.json b/docs/birdseye/caps/src.config.policy-evaluator.ts.692ff63a.json index 88d05fb..e6f564d 100644 --- a/docs/birdseye/caps/src.config.policy-evaluator.ts.692ff63a.json +++ b/docs/birdseye/caps/src.config.policy-evaluator.ts.692ff63a.json @@ -29,6 +29,6 @@ "tests": [ "src/config/__tests__/policy-evaluator.test.ts" ], - "sourceHash": "011bb48ba42144f108f887ca9afa761c11341d4a7cf8e1ec3bc84a320a5aee79", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "7a513c8f175bbc68ddc4eb395e204d71dea78143bc630755f24349bd56abda11", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.config.policy-loader.ts.0cddccdb.json b/docs/birdseye/caps/src.config.policy-loader.ts.0cddccdb.json index 83ef2b0..c2d059a 100644 --- a/docs/birdseye/caps/src.config.policy-loader.ts.0cddccdb.json +++ b/docs/birdseye/caps/src.config.policy-loader.ts.0cddccdb.json @@ -29,6 +29,6 @@ "tests": [ "src/config/__tests__/policy-loader.test.ts" ], - "sourceHash": "1f264282521330e32232ef8118024e54ac7e891f7ba75c06665da8ca69069503", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "df06d641236c6295bf0da8b1001367dfb8f9910f3182bba3c3bbccde7440ceae", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.config.policy-types.ts.3e527503.json b/docs/birdseye/caps/src.config.policy-types.ts.3e527503.json index e530dde..925ec00 100644 --- a/docs/birdseye/caps/src.config.policy-types.ts.3e527503.json +++ b/docs/birdseye/caps/src.config.policy-types.ts.3e527503.json @@ -23,6 +23,6 @@ "src/config/severity-resolver.ts" ], "tests": [], - "sourceHash": "aabbd5785b83fbcd9a2f6fbb51ac4fdd2a3281e21e97cc025ed89db7bb9596a8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "0771768c6fb46dd0e3151781cfae47d70b2ae912c818aafb7582f40048069833", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.config.policy-yaml-parser.ts.9661e594.json b/docs/birdseye/caps/src.config.policy-yaml-parser.ts.9661e594.json index 3912fe4..ce223d9 100644 --- a/docs/birdseye/caps/src.config.policy-yaml-parser.ts.9661e594.json +++ b/docs/birdseye/caps/src.config.policy-yaml-parser.ts.9661e594.json @@ -15,6 +15,6 @@ "tests": [ "src/config/__tests__/policy-yaml-parser.test.ts" ], - "sourceHash": "8ce4fa244b8407d4c614ca7cf23b115331eb17dfa2ebd3db86104079de133d85", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "2d33b2ca2262913216201cf54d0d67708f16c21bc6605e77808aba6175bed0c1", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.config.severity-resolver.ts.4f6c0ec0.json b/docs/birdseye/caps/src.config.severity-resolver.ts.4f6c0ec0.json index 41f8dfd..e94db8e 100644 --- a/docs/birdseye/caps/src.config.severity-resolver.ts.4f6c0ec0.json +++ b/docs/birdseye/caps/src.config.severity-resolver.ts.4f6c0ec0.json @@ -21,5 +21,5 @@ "src/config/__tests__/severity-resolver.test.ts" ], "sourceHash": "bbd3cbafa841452b9b1688183e0cc5b297bf281a7f9e6e6b894cf475aae7d8b8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.core.database-analyzer.ts.ef83db92.json b/docs/birdseye/caps/src.core.database-analyzer.ts.ef83db92.json index 5a05943..a7fcf9c 100644 --- a/docs/birdseye/caps/src.core.database-analyzer.ts.ef83db92.json +++ b/docs/birdseye/caps/src.core.database-analyzer.ts.ef83db92.json @@ -23,5 +23,5 @@ "src/core/__tests__/database-analyzer.test.ts" ], "sourceHash": "bc976ab1550e7c19d4261cba7216a08cf3416874048f84efe80072e006180ed7", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.core.evidence-utils.ts.0a8f2cb4.json b/docs/birdseye/caps/src.core.evidence-utils.ts.0a8f2cb4.json index 4795890..aa1ed6f 100644 --- a/docs/birdseye/caps/src.core.evidence-utils.ts.0a8f2cb4.json +++ b/docs/birdseye/caps/src.core.evidence-utils.ts.0a8f2cb4.json @@ -14,5 +14,5 @@ ], "tests": [], "sourceHash": "c9a5c9f4a974bd31ebeca156d5a0861ebcea0c22ae7a5067fcef335df5e14924", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.core.file-utils.ts.e924d65d.json b/docs/birdseye/caps/src.core.file-utils.ts.e924d65d.json index 35bbb82..350412a 100644 --- a/docs/birdseye/caps/src.core.file-utils.ts.e924d65d.json +++ b/docs/birdseye/caps/src.core.file-utils.ts.e924d65d.json @@ -27,5 +27,5 @@ "src/core/__tests__/file-utils.test.ts" ], "sourceHash": "e41ffb8a106b1a144181bf56f6b08ef1c6029da9f25c5344f7314d93c5bbf7c1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.core.repo-graph-builder.ts.092f146e.json b/docs/birdseye/caps/src.core.repo-graph-builder.ts.092f146e.json index fa6b029..24aca6f 100644 --- a/docs/birdseye/caps/src.core.repo-graph-builder.ts.092f146e.json +++ b/docs/birdseye/caps/src.core.repo-graph-builder.ts.092f146e.json @@ -25,5 +25,5 @@ "src/core/__tests__/repo-graph-builder.test.ts" ], "sourceHash": "e8acb1e7136dd7c5ecafa6faa49066af7897788cc87f24950e47dbeb78911f0e", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.historical.ratchet-gate.ts.be8657ce.json b/docs/birdseye/caps/src.historical.ratchet-gate.ts.be8657ce.json index d1a829d..eb94de0 100644 --- a/docs/birdseye/caps/src.historical.ratchet-gate.ts.be8657ce.json +++ b/docs/birdseye/caps/src.historical.ratchet-gate.ts.be8657ce.json @@ -15,7 +15,9 @@ "deps_in": [ "src/cli/readiness.ts" ], - "tests": [], - "sourceHash": "498d1a9f2893deb6fe9bf43397c3975b94e918413452fe3b22d13f3f0ea158bd", - "generation_id": "birdseye-d2d6a58ca24118dd" + "tests": [ + "src/historical/__tests__/ratchet-gate.test.ts" + ], + "sourceHash": "a94ebf53604e3fa4dffaf886161b1c36dd677077c49370a2d681aee771bd80fb", + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.llm.providers.index.ts.84190b45.json b/docs/birdseye/caps/src.llm.providers.index.ts.84190b45.json index 144a767..f1f9ce4 100644 --- a/docs/birdseye/caps/src.llm.providers.index.ts.84190b45.json +++ b/docs/birdseye/caps/src.llm.providers.index.ts.84190b45.json @@ -15,5 +15,5 @@ ], "tests": [], "sourceHash": "e49b33a184bd46c2fe4a999d151377fcecf0ae1e1add354fd6c7580770cb3921", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.llm.providers.provider-health.ts.27e7d61b.json b/docs/birdseye/caps/src.llm.providers.provider-health.ts.27e7d61b.json index a70f82f..9ef850d 100644 --- a/docs/birdseye/caps/src.llm.providers.provider-health.ts.27e7d61b.json +++ b/docs/birdseye/caps/src.llm.providers.provider-health.ts.27e7d61b.json @@ -18,5 +18,5 @@ ], "tests": [], "sourceHash": "7e04da292a374bdcc88ca0fd7d2f64f933bd82d7c4ad2463adb8690804c5d414", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.llm.types.ts.fb6f6c77.json b/docs/birdseye/caps/src.llm.types.ts.fb6f6c77.json index f59230d..aa9b8c5 100644 --- a/docs/birdseye/caps/src.llm.types.ts.fb6f6c77.json +++ b/docs/birdseye/caps/src.llm.types.ts.fb6f6c77.json @@ -19,5 +19,5 @@ ], "tests": [], "sourceHash": "fbb1a2bffafd873a5a9e55eb1c22c3d8c8abedd440760cdcf8b64ec84c9ffe67", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.parallel.index.ts.5b6be68e.json b/docs/birdseye/caps/src.parallel.index.ts.5b6be68e.json index fe13d01..51f05c5 100644 --- a/docs/birdseye/caps/src.parallel.index.ts.5b6be68e.json +++ b/docs/birdseye/caps/src.parallel.index.ts.5b6be68e.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "62aa1ca60588ed8ec48d6050b00b49fb1a5f7c40fc97c273286160aa1d48b531", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.audit-writer.ts.b6e59e36.json b/docs/birdseye/caps/src.reporters.audit-writer.ts.b6e59e36.json index c0c91a0..79a2c7a 100644 --- a/docs/birdseye/caps/src.reporters.audit-writer.ts.b6e59e36.json +++ b/docs/birdseye/caps/src.reporters.audit-writer.ts.b6e59e36.json @@ -15,5 +15,5 @@ "src/reporters/__tests__/audit-writer.test.ts" ], "sourceHash": "d57b9f4cd878e6052bcc6bb582e2759e8289f296f9f617fb548713690f65c8ef", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.index.ts.ed3613c5.json b/docs/birdseye/caps/src.reporters.index.ts.ed3613c5.json index ff56394..0486fc7 100644 --- a/docs/birdseye/caps/src.reporters.index.ts.ed3613c5.json +++ b/docs/birdseye/caps/src.reporters.index.ts.ed3613c5.json @@ -10,5 +10,5 @@ ], "tests": [], "sourceHash": "d7e10e907609fa9cc1012e74a02c4b5466e1befe9c51ea7ee05e6279744ae28f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.invariant-generator.ts.1f18aad4.json b/docs/birdseye/caps/src.reporters.invariant-generator.ts.1f18aad4.json index c087a40..21a0e30 100644 --- a/docs/birdseye/caps/src.reporters.invariant-generator.ts.1f18aad4.json +++ b/docs/birdseye/caps/src.reporters.invariant-generator.ts.1f18aad4.json @@ -15,5 +15,5 @@ "src/reporters/__tests__/invariant-generator.test.ts" ], "sourceHash": "c320d32d4db226e2c26db57b33a45c257bd7d9c45de6f89829688ff6a5a215a1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.json-reporter.ts.ee833bf0.json b/docs/birdseye/caps/src.reporters.json-reporter.ts.ee833bf0.json index b58d896..5809c17 100644 --- a/docs/birdseye/caps/src.reporters.json-reporter.ts.ee833bf0.json +++ b/docs/birdseye/caps/src.reporters.json-reporter.ts.ee833bf0.json @@ -12,5 +12,5 @@ "src/reporters/__tests__/json-reporter.test.ts" ], "sourceHash": "a924feab7a3d13ada6dbc0cd291a34c9fa091c14a1666191434e4e6c8ca28994", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.llm-enrichment.ts.00e5ad08.json b/docs/birdseye/caps/src.reporters.llm-enrichment.ts.00e5ad08.json index 32146c1..9eee39f 100644 --- a/docs/birdseye/caps/src.reporters.llm-enrichment.ts.00e5ad08.json +++ b/docs/birdseye/caps/src.reporters.llm-enrichment.ts.00e5ad08.json @@ -14,5 +14,5 @@ "src/reporters/__tests__/llm-enrichment.test.ts" ], "sourceHash": "5ff4cda73ca808a067f13ef232c9533ca8d4e1dac9e8fc271700858f2feb99b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.markdown-reporter.ts.9af0243b.json b/docs/birdseye/caps/src.reporters.markdown-reporter.ts.9af0243b.json index d37baea..e72fd8b 100644 --- a/docs/birdseye/caps/src.reporters.markdown-reporter.ts.9af0243b.json +++ b/docs/birdseye/caps/src.reporters.markdown-reporter.ts.9af0243b.json @@ -15,5 +15,5 @@ "src/reporters/__tests__/markdown-reporter.test.ts" ], "sourceHash": "27cf59a73aff27ac70c85ea59505acc69e05fee07ab0ccdcde971327295e20b4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.raw-findings-reporter.ts.2ab3ec7c.json b/docs/birdseye/caps/src.reporters.raw-findings-reporter.ts.2ab3ec7c.json index 2406acf..ed11298 100644 --- a/docs/birdseye/caps/src.reporters.raw-findings-reporter.ts.2ab3ec7c.json +++ b/docs/birdseye/caps/src.reporters.raw-findings-reporter.ts.2ab3ec7c.json @@ -15,5 +15,5 @@ ], "tests": [], "sourceHash": "ed5e6e2a84c0dc246fe6b30d6b13ac27fcde535f7b66269806fa33f0ea73533c", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.sarif-reporter.ts.abe1f20a.json b/docs/birdseye/caps/src.reporters.sarif-reporter.ts.abe1f20a.json new file mode 100644 index 0000000..19f65fc --- /dev/null +++ b/docs/birdseye/caps/src.reporters.sarif-reporter.ts.abe1f20a.json @@ -0,0 +1,29 @@ +{ + "schema": "birdseye/cap/v1", + "id": "src/reporters/sarif-reporter.ts", + "role": "dependency", + "summary": "SarifArtifactLocation, SarifLocation, SarifLog, SarifMessage の公開API", + "public_api": [ + "SarifArtifactLocation", + "SarifLocation", + "SarifLog", + "SarifMessage", + "SarifPhysicalLocation", + "SarifRegion", + "SarifResult", + "SarifRule", + "SarifRun", + "SarifTool", + "SarifToolDriver", + "generateFullSarifReport" + ], + "deps_out": [], + "deps_in": [ + "src/cli/analyze.ts" + ], + "tests": [ + "src/reporters/__tests__/sarif-reporter.test.ts" + ], + "sourceHash": "1eac55bd7f4c1502bdc2e2dcd85ee708b413dbbcf7c4293a386b623d990a13e5", + "generation_id": "birdseye-33377e4a68abbf61" +} diff --git a/docs/birdseye/caps/src.reporters.self-analysis-debt-reporter.ts.c4f1963a.json b/docs/birdseye/caps/src.reporters.self-analysis-debt-reporter.ts.c4f1963a.json index c8195b2..889317d 100644 --- a/docs/birdseye/caps/src.reporters.self-analysis-debt-reporter.ts.c4f1963a.json +++ b/docs/birdseye/caps/src.reporters.self-analysis-debt-reporter.ts.c4f1963a.json @@ -14,5 +14,5 @@ ], "tests": [], "sourceHash": "ae0027ea479d450bad9fb2f5c557611f9899332e9d8fd2ac0ce64c52251318d5", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.test-seed-generator.ts.b2a7a8ee.json b/docs/birdseye/caps/src.reporters.test-seed-generator.ts.b2a7a8ee.json index 0deed4c..b29aefd 100644 --- a/docs/birdseye/caps/src.reporters.test-seed-generator.ts.b2a7a8ee.json +++ b/docs/birdseye/caps/src.reporters.test-seed-generator.ts.b2a7a8ee.json @@ -15,5 +15,5 @@ "src/reporters/__tests__/test-seed-generator.test.ts" ], "sourceHash": "aba32b8a8d425983f9356d472716c17a6bdd19b0ec4584ded3d8f7ad03d4e4fb", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.reporters.yaml-reporter.ts.efc347af.json b/docs/birdseye/caps/src.reporters.yaml-reporter.ts.efc347af.json index 932f922..95a6759 100644 --- a/docs/birdseye/caps/src.reporters.yaml-reporter.ts.efc347af.json +++ b/docs/birdseye/caps/src.reporters.yaml-reporter.ts.efc347af.json @@ -15,5 +15,5 @@ "src/reporters/__tests__/yaml-reporter.test.ts" ], "sourceHash": "3a6819325b76498927d94423eaebc66e8b224e1ac50495611cdc67978f3390c9", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.circular-dependency.ts.bceddaa2.json b/docs/birdseye/caps/src.rules.circular-dependency.ts.bceddaa2.json index 5cebd4a..be9421c 100644 --- a/docs/birdseye/caps/src.rules.circular-dependency.ts.bceddaa2.json +++ b/docs/birdseye/caps/src.rules.circular-dependency.ts.bceddaa2.json @@ -14,5 +14,5 @@ "src/rules/__tests__/circular-dependency.test.ts" ], "sourceHash": "1b874bc49fcc83c530b75b2e91c0c77386fd9df46eec59dcba26946074d85308", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.client-trusted-price.ts.c59aeb06.json b/docs/birdseye/caps/src.rules.client-trusted-price.ts.c59aeb06.json index bc0b157..b046be1 100644 --- a/docs/birdseye/caps/src.rules.client-trusted-price.ts.c59aeb06.json +++ b/docs/birdseye/caps/src.rules.client-trusted-price.ts.c59aeb06.json @@ -14,5 +14,5 @@ "src/rules/__tests__/client-trusted-price.test.ts" ], "sourceHash": "d6e918f7d778e198929081e849aeac8ae3789373fc35dbcbc9071375912706b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.db-destructive-ops.ts.c002e59f.json b/docs/birdseye/caps/src.rules.db-destructive-ops.ts.c002e59f.json index 62edf6d..a32e163 100644 --- a/docs/birdseye/caps/src.rules.db-destructive-ops.ts.c002e59f.json +++ b/docs/birdseye/caps/src.rules.db-destructive-ops.ts.c002e59f.json @@ -14,5 +14,5 @@ "src/rules/__tests__/db-destructive-ops.test.ts" ], "sourceHash": "6fa2f753ad1f2b625329eb55253fb8b506920e9e2c0854a28a8701ab13ffb2af", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.db-migration-ops.ts.bc143588.json b/docs/birdseye/caps/src.rules.db-migration-ops.ts.bc143588.json index 90324e2..4b2f52a 100644 --- a/docs/birdseye/caps/src.rules.db-migration-ops.ts.bc143588.json +++ b/docs/birdseye/caps/src.rules.db-migration-ops.ts.bc143588.json @@ -14,5 +14,5 @@ "src/rules/__tests__/db-migration-ops.test.ts" ], "sourceHash": "f831b483d7dabf3c36645ef9fca402306935ab8bff8f9e0c736dc500a6a2a5ee", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.db-schema-change.ts.cb6b166e.json b/docs/birdseye/caps/src.rules.db-schema-change.ts.cb6b166e.json index d6885c2..c6183e6 100644 --- a/docs/birdseye/caps/src.rules.db-schema-change.ts.cb6b166e.json +++ b/docs/birdseye/caps/src.rules.db-schema-change.ts.cb6b166e.json @@ -14,5 +14,5 @@ "src/rules/__tests__/db-schema-change.test.ts" ], "sourceHash": "295eea4652dd25b65547d22019f1f17f7498e7bfef189da516babdb6f1288869", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.debt-marker.ts.16a50ec7.json b/docs/birdseye/caps/src.rules.debt-marker.ts.16a50ec7.json index 0698475..cf79c46 100644 --- a/docs/birdseye/caps/src.rules.debt-marker.ts.16a50ec7.json +++ b/docs/birdseye/caps/src.rules.debt-marker.ts.16a50ec7.json @@ -14,5 +14,5 @@ "src/rules/__tests__/debt-marker.test.ts" ], "sourceHash": "f894997cf4f7050a46931d91c3e8f543d251b16853ab7c6bfd65b86e47536ff1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.deprecated-api.ts.5c32f42a.json b/docs/birdseye/caps/src.rules.deprecated-api.ts.5c32f42a.json index 805febc..e370eb9 100644 --- a/docs/birdseye/caps/src.rules.deprecated-api.ts.5c32f42a.json +++ b/docs/birdseye/caps/src.rules.deprecated-api.ts.5c32f42a.json @@ -14,5 +14,5 @@ "src/rules/__tests__/deprecated-api.test.ts" ], "sourceHash": "0c14a4880a4e3888048f542e88f37cd5b66dc2d7ebd883c8c115ece93a019c92", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.env-direct-access.ts.ccd07ba1.json b/docs/birdseye/caps/src.rules.env-direct-access.ts.ccd07ba1.json index 9707bc4..b9316a0 100644 --- a/docs/birdseye/caps/src.rules.env-direct-access.ts.ccd07ba1.json +++ b/docs/birdseye/caps/src.rules.env-direct-access.ts.ccd07ba1.json @@ -14,5 +14,5 @@ "src/rules/__tests__/env-direct-access.test.ts" ], "sourceHash": "e6560a170b2ecb86fc00b88acf4e56596d9f89044a0f2332da001ac07cd4cf9a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.hardcoded-secret.ts.57685f48.json b/docs/birdseye/caps/src.rules.hardcoded-secret.ts.57685f48.json index f9f83aa..98116e3 100644 --- a/docs/birdseye/caps/src.rules.hardcoded-secret.ts.57685f48.json +++ b/docs/birdseye/caps/src.rules.hardcoded-secret.ts.57685f48.json @@ -14,5 +14,5 @@ "src/rules/__tests__/hardcoded-secret.test.ts" ], "sourceHash": "7d9efaf6ed46da16b042037cb064d4410578a22a2d27d886c7f47c911b176b93", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.index.ts.322e2e2b.json b/docs/birdseye/caps/src.rules.index.ts.322e2e2b.json index fae8fc3..726a9fe 100644 --- a/docs/birdseye/caps/src.rules.index.ts.322e2e2b.json +++ b/docs/birdseye/caps/src.rules.index.ts.322e2e2b.json @@ -44,5 +44,5 @@ "src/rules/__tests__/index.test.ts" ], "sourceHash": "064ea7edaf026afc462c5d0a0eb526316b7cd7875e15197ba9586420eeef8532", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.large-module.ts.948c83e5.json b/docs/birdseye/caps/src.rules.large-module.ts.948c83e5.json index 0bcf57e..cbde728 100644 --- a/docs/birdseye/caps/src.rules.large-module.ts.948c83e5.json +++ b/docs/birdseye/caps/src.rules.large-module.ts.948c83e5.json @@ -14,5 +14,5 @@ "src/rules/__tests__/large-module.test.ts" ], "sourceHash": "542fd7bee7745deb6d5ba2318147bcf87fdd921aecbd997c5822a7225743a012", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.missing-input-sanitization.ts.b9adf577.json b/docs/birdseye/caps/src.rules.missing-input-sanitization.ts.b9adf577.json index 34baee9..c32a011 100644 --- a/docs/birdseye/caps/src.rules.missing-input-sanitization.ts.b9adf577.json +++ b/docs/birdseye/caps/src.rules.missing-input-sanitization.ts.b9adf577.json @@ -14,5 +14,5 @@ "src/rules/__tests__/missing-input-sanitization.test.ts" ], "sourceHash": "8d3c11b90259818375266c8da77ec2d81a69879c53f7af4e8f2ac83286d0b1a6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.missing-rate-limit.ts.571d00df.json b/docs/birdseye/caps/src.rules.missing-rate-limit.ts.571d00df.json index 95844ef..89d4425 100644 --- a/docs/birdseye/caps/src.rules.missing-rate-limit.ts.571d00df.json +++ b/docs/birdseye/caps/src.rules.missing-rate-limit.ts.571d00df.json @@ -14,5 +14,5 @@ "src/rules/__tests__/missing-rate-limit.test.ts" ], "sourceHash": "8704c442bb60ed671dd251b5b554763595dbe414cbb6aecce536be269dc65f37", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.missing-server-validation.ts.674cd1e7.json b/docs/birdseye/caps/src.rules.missing-server-validation.ts.674cd1e7.json index 6733c4f..1dafeec 100644 --- a/docs/birdseye/caps/src.rules.missing-server-validation.ts.674cd1e7.json +++ b/docs/birdseye/caps/src.rules.missing-server-validation.ts.674cd1e7.json @@ -14,5 +14,5 @@ "src/rules/__tests__/missing-server-validation.test.ts" ], "sourceHash": "5fd6a3c38afb600adcded3d17f79ec46549fb58c6381323f51a6fd0d70b2567d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.raw-sql.ts.d03b2216.json b/docs/birdseye/caps/src.rules.raw-sql.ts.d03b2216.json index 67f57ca..1d9af85 100644 --- a/docs/birdseye/caps/src.rules.raw-sql.ts.d03b2216.json +++ b/docs/birdseye/caps/src.rules.raw-sql.ts.d03b2216.json @@ -14,5 +14,5 @@ "src/rules/__tests__/raw-sql.test.ts" ], "sourceHash": "91cd4dae2b6fd4f8cba89506c707c0acd0eddcfa8e9ec5d235318e3407b66cb1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.suppression-debt.ts.e945b433.json b/docs/birdseye/caps/src.rules.suppression-debt.ts.e945b433.json index 23716d3..9ebf854 100644 --- a/docs/birdseye/caps/src.rules.suppression-debt.ts.e945b433.json +++ b/docs/birdseye/caps/src.rules.suppression-debt.ts.e945b433.json @@ -14,5 +14,5 @@ "src/rules/__tests__/suppression-debt.test.ts" ], "sourceHash": "268d091a971d6693b1e43d5b9716ce666c719c3298e452940950bc450ef4069d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.try-catch-swallow.ts.49915afc.json b/docs/birdseye/caps/src.rules.try-catch-swallow.ts.49915afc.json index 4a9db4d..6c06a1e 100644 --- a/docs/birdseye/caps/src.rules.try-catch-swallow.ts.49915afc.json +++ b/docs/birdseye/caps/src.rules.try-catch-swallow.ts.49915afc.json @@ -14,5 +14,5 @@ "src/rules/__tests__/try-catch-swallow.test.ts" ], "sourceHash": "09c7c6fe35124c97003e19dacad9f1a548e862539118dfda7ccd9a197bcb2d16", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.unsafe-delete.ts.6ae85c1e.json b/docs/birdseye/caps/src.rules.unsafe-delete.ts.6ae85c1e.json index 9cffd29..956dd4a 100644 --- a/docs/birdseye/caps/src.rules.unsafe-delete.ts.6ae85c1e.json +++ b/docs/birdseye/caps/src.rules.unsafe-delete.ts.6ae85c1e.json @@ -14,5 +14,5 @@ "src/rules/__tests__/unsafe-delete.test.ts" ], "sourceHash": "e7f32e68bb820ef13f88a94615e2209a764e0719165196fb2b0a364482921f17", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.unsafe-redirect.ts.6c21da82.json b/docs/birdseye/caps/src.rules.unsafe-redirect.ts.6c21da82.json index d2384ef..533c0c8 100644 --- a/docs/birdseye/caps/src.rules.unsafe-redirect.ts.6c21da82.json +++ b/docs/birdseye/caps/src.rules.unsafe-redirect.ts.6c21da82.json @@ -14,5 +14,5 @@ "src/rules/__tests__/unsafe-redirect.test.ts" ], "sourceHash": "784d78d32c435c46157688879ce6afdfecb34c595c2f0a467a2acc0f00e0eeb6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.untested-critical-path.ts.6ec606a5.json b/docs/birdseye/caps/src.rules.untested-critical-path.ts.6ec606a5.json index 39b4a67..c6e8a5e 100644 --- a/docs/birdseye/caps/src.rules.untested-critical-path.ts.6ec606a5.json +++ b/docs/birdseye/caps/src.rules.untested-critical-path.ts.6ec606a5.json @@ -14,5 +14,5 @@ "src/rules/__tests__/untested-critical-path.test.ts" ], "sourceHash": "e3d129dbc7456f72d13820008f07c057cdd2f105a762049443dd00321a84723b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.rules.weak-auth-guard.ts.83f1e3ac.json b/docs/birdseye/caps/src.rules.weak-auth-guard.ts.83f1e3ac.json index 880558a..c62d08a 100644 --- a/docs/birdseye/caps/src.rules.weak-auth-guard.ts.83f1e3ac.json +++ b/docs/birdseye/caps/src.rules.weak-auth-guard.ts.83f1e3ac.json @@ -14,5 +14,5 @@ "src/rules/__tests__/weak-auth-guard.test.ts" ], "sourceHash": "3aa59f53d09dd7fcc54139359a72bd27a88337b3f0530c42b927d9472dfc5b71", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.self-analysis.suppression-summary.ts.61ee0d9d.json b/docs/birdseye/caps/src.self-analysis.suppression-summary.ts.61ee0d9d.json index 52abd3c..dbc479e 100644 --- a/docs/birdseye/caps/src.self-analysis.suppression-summary.ts.61ee0d9d.json +++ b/docs/birdseye/caps/src.self-analysis.suppression-summary.ts.61ee0d9d.json @@ -17,5 +17,5 @@ "src/self-analysis/__tests__/suppression-summary.test.ts" ], "sourceHash": "2ed7f9eb636d2c45b65a26cac6befafbbdb1b59845ca7f89bba2e6e73d5411ce", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.types.artifacts.ts.1d71db34.json b/docs/birdseye/caps/src.types.artifacts.ts.1d71db34.json index 5447421..78dc982 100644 --- a/docs/birdseye/caps/src.types.artifacts.ts.1d71db34.json +++ b/docs/birdseye/caps/src.types.artifacts.ts.1d71db34.json @@ -29,5 +29,5 @@ ], "tests": [], "sourceHash": "ba57806c7cc0073951eaf32161f9c12c5e64a7da13147bdcd050f95d067429c4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.types.contracts.ts.6048fd51.json b/docs/birdseye/caps/src.types.contracts.ts.6048fd51.json index 43a2757..c197b4f 100644 --- a/docs/birdseye/caps/src.types.contracts.ts.6048fd51.json +++ b/docs/birdseye/caps/src.types.contracts.ts.6048fd51.json @@ -22,5 +22,5 @@ ], "tests": [], "sourceHash": "7a820f95adcf4d199c12e754676cc4d1fcea4c4735feacce95f6a01205abf8d8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.types.graph.ts.a49f9e2b.json b/docs/birdseye/caps/src.types.graph.ts.a49f9e2b.json index ed373d8..7fe0af1 100644 --- a/docs/birdseye/caps/src.types.graph.ts.a49f9e2b.json +++ b/docs/birdseye/caps/src.types.graph.ts.a49f9e2b.json @@ -23,5 +23,5 @@ ], "tests": [], "sourceHash": "65517cdf7234a79335e58ab9919153d7154b525e090f47d75fe8335b471c2b21", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.types.rule-options.ts.bf439b98.json b/docs/birdseye/caps/src.types.rule-options.ts.bf439b98.json index fa3676a..e8d1512 100644 --- a/docs/birdseye/caps/src.types.rule-options.ts.bf439b98.json +++ b/docs/birdseye/caps/src.types.rule-options.ts.bf439b98.json @@ -14,5 +14,5 @@ ], "tests": [], "sourceHash": "76d6d3ee6888fa2523549e7deffb09112693911c978db9a9d743b802071ac3b8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" } diff --git a/docs/birdseye/caps/src.utils.run-id.ts.e485d2c3.json b/docs/birdseye/caps/src.utils.run-id.ts.e485d2c3.json new file mode 100644 index 0000000..421ee4b --- /dev/null +++ b/docs/birdseye/caps/src.utils.run-id.ts.e485d2c3.json @@ -0,0 +1,20 @@ +{ + "schema": "birdseye/cap/v1", + "id": "src/utils/run-id.ts", + "role": "dependency", + "summary": "UniqueRunIdOptions, createUniqueRunId の公開API", + "public_api": [ + "UniqueRunIdOptions", + "createUniqueRunId" + ], + "deps_out": [], + "deps_in": [ + "src/cli/readiness.ts" + ], + "tests": [ + "src/utils/__tests__/run-id-integration.test.ts", + "src/utils/__tests__/run-id.test.ts" + ], + "sourceHash": "51e85e7cba0084f138cfdee8fbb9f1c272f52afee04109700fd64069d2bfabf3", + "generation_id": "birdseye-33377e4a68abbf61" +} diff --git a/docs/birdseye/hot.json b/docs/birdseye/hot.json index a9694b7..9e9cb0f 100644 --- a/docs/birdseye/hot.json +++ b/docs/birdseye/hot.json @@ -1,8 +1,8 @@ { "schema": "birdseye/hot/v1", - "generated_at": "birdseye-d2d6a58ca24118dd", - "generation_id": "birdseye-d2d6a58ca24118dd", - "sourceHash": "d2d6a58ca24118ddf3a0d478678780097e237750650eaf95fb27a5263ced5d50", + "generated_at": "birdseye-33377e4a68abbf61", + "generation_id": "birdseye-33377e4a68abbf61", + "sourceHash": "33377e4a68abbf61f80023f69517e2fb1e42d99686c457e49c71f20912344de8", "hot_nodes": [ ".ctg/policy.yaml", "GUARDRAILS.md", diff --git a/docs/birdseye/index.json b/docs/birdseye/index.json index 6e7276b..2a7cced 100644 --- a/docs/birdseye/index.json +++ b/docs/birdseye/index.json @@ -1,8 +1,8 @@ { "schema": "birdseye/v1", - "generated_at": "birdseye-d2d6a58ca24118dd", - "generation_id": "birdseye-d2d6a58ca24118dd", - "sourceHash": "d2d6a58ca24118ddf3a0d478678780097e237750650eaf95fb27a5263ced5d50", + "generated_at": "birdseye-33377e4a68abbf61", + "generation_id": "birdseye-33377e4a68abbf61", + "sourceHash": "33377e4a68abbf61f80023f69517e2fb1e42d99686c457e49c71f20912344de8", "scope": { "kind": "seed+local-one-hop", "required_seeds": [ @@ -40,733 +40,757 @@ "role": "policy", "caps": "docs/birdseye/caps/.ctg.policy.yaml.2d4a1e58.json", "sourceHash": "e598cbb1e8537cb1bd082ad2c48437571a4a704f3bba21a0a1fbc06fe617bf32", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "CHANGELOG.md": { "role": "history", "caps": "docs/birdseye/caps/CHANGELOG.md.06572a96.json", - "sourceHash": "ca3ccf2b46c5a23014e1d1bcf45f8a69cd50e1390be3f91474f3a83150ef1523", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "085399754ede262f006112f943ffe028eec2388023a60c14ca674920977d80ae", + "generation_id": "birdseye-33377e4a68abbf61" }, "CHECKLISTS.md": { "role": "checklist", "caps": "docs/birdseye/caps/CHECKLISTS.md.c3da629e.json", - "sourceHash": "7290d53f40310b4e7e95b0f24ec0f7d2ad20685af25fd59058e59698f2c17cdf", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "1265613c0628ef8a0c69ac9e2cc7217b4e5d2db6fc6e779edeab29661ad91714", + "generation_id": "birdseye-33377e4a68abbf61" }, "CLAUDE.md": { "role": "context", "caps": "docs/birdseye/caps/CLAUDE.md.6ebdb617.json", - "sourceHash": "3497438a4a9d9d6469a0b23a6a4c0abf62797eeb802d3b7a0d93eb70afd9d057", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "7c5f5ad3ce66ea9a0be9fc5a248e7092315d95a1242a0ab0a05e83076ff7bc79", + "generation_id": "birdseye-33377e4a68abbf61" }, "GUARDRAILS.md": { "role": "policy", "caps": "docs/birdseye/caps/GUARDRAILS.md.dceca4b6.json", - "sourceHash": "ec3d4d6e2dd230943d49519a46e848b08e79044c6cfa673cf611b06cdaa87a50", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "467d8fe7c8ee762726b43619e91d09959bf9ca27d35c58e83b0d3aa405ba8e4c", + "generation_id": "birdseye-33377e4a68abbf61" }, "README.md": { "role": "overview", "caps": "docs/birdseye/caps/README.md.b3356305.json", - "sourceHash": "cb2f12bb9c700e0a8651922029fc38437a9b0b8dc0fc14c090f20af969acaaa6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "b42afa1524db12e32599264b2eab94b29ab91b81fca1a670059d0e1d902b037f", + "generation_id": "birdseye-33377e4a68abbf61" }, "README_JA.md": { "role": "dependency", "caps": "docs/birdseye/caps/README_JA.md.f271b369.json", - "sourceHash": "e6be7c74da7c2584f1301f7372d92577a8881b6e5a598c590fc94354b481d924", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "615b31bd1ded9799ebbcc2d966fc5573cb21624c4921f69c3804f3a98ba272b7", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/ADR/README.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.ADR.README.md.0468bb03.json", "sourceHash": "72a7c2a87a44a36ec81ef6b4306281f658373607fb4e179390fb14f1ac3fefb4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/Release_Checklist.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.Release_Checklist.md.6185103b.json", "sourceHash": "1069801dd55d4652788eedaec13918003aeac8d59717922a54193f688f02e9f7", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/TASKS.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.TASKS.md.8519adad.json", - "sourceHash": "052d9d2cb2c0e8440cf8cc135dcdbc512b2194718dc2917515c453bf3273ec68", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "fd2d8a506c2cdfced9ac55e0e75b4fcb8ee6ec67d53b18e0ab9a650b171bd450", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/acceptance/AC-20260910-02-precision-review.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.acceptance.AC-20260910-02-precision-review.md.0a6af0d7.json", "sourceHash": "e2a19c116bc5a9abcdbaed0fa37b467968da9f84c25b57d9482d7398ec3b65a6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/acceptance/AC-20260910-06-maintenance.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.acceptance.AC-20260910-06-maintenance.md.f139681a.json", "sourceHash": "cb63f053c6cb7fcc9bf3897153fe9da0102b92cc7f24b9eba1cc35e2d36c7b8b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/acceptance/AC-20260910-12-follow-up.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.acceptance.AC-20260910-12-follow-up.md.b6a9b379.json", "sourceHash": "27c18c30b231ea19aed5bb433cc4ccefe53e70d9be85df3e4857dcd7a2f609a4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/acceptance/AC-20260910-14-ci-integration.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.acceptance.AC-20260910-14-ci-integration.md.d0d02354.json", "sourceHash": "9a4ed75d254862a75d71acc796a90d05681b04671866b25ca483c4c55a24b371", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/acceptance/AC-20260910-15-release-1.6.0.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.acceptance.AC-20260910-15-release-1.6.0.md.191462f2.json", "sourceHash": "e08c95fbe35461b056a995ecb945cfd4ae8e835076a852797db4951f22841ac2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/cli-reference.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.cli-reference.md.d5d8360d.json", - "sourceHash": "571621c5914fe5fb0a4094f2761d78a71c52a30c8e4c29d7ebe5a0cf43875f66", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "bcabe8108b7926b26c4d5c1e341aa9859b98142d219e86a1473af31a2af1ee52", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/distribution-status.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.distribution-status.md.7c82a2f3.json", "sourceHash": "acc90979086979069844edb7b7a70fd281608a3437f02175daae3a098f157a82", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/integrations.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.integrations.md.98423805.json", "sourceHash": "39d4398638ba48974e034db741619449581e498c8fbfecde15970b819a52cddb", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/plugin-development.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.plugin-development.md.f86abbd7.json", "sourceHash": "971f433e3f2b84145ac6e112dd8693e351e3428f087f1c09164cd56d24374f89", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/policy-guide.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.policy-guide.md.294e87e0.json", - "sourceHash": "d56d388f3c794725b093f41eaf6daa829e2a14433d23d0a4c5fa29ea442c05a4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "3342b9559ffcd72b700e08160b79a869f29a4212fb57d1c2411d58171f10bb90", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/precision-review.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.precision-review.md.2d78a86b.json", "sourceHash": "8366da73e8d334d4733ea7b15d944ad80548043543fb3035ea43045ba8c6f0be", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/quality-evidence-os-expansion-ideas.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.quality-evidence-os-expansion-ideas.md.43bffbc2.json", "sourceHash": "089fb7b77c52af0903512fc7cf7f25089a4cfd2fda700285a1e6b04006e84464", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/quality-evidence-os-requirements.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.quality-evidence-os-requirements.md.50e55101.json", "sourceHash": "ba0df900f803101a2384a74c70d0bf07b1d6a6c19c9887282a7ad4c0ab9526b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/quality-evidence-os-spec.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.quality-evidence-os-spec.md.9124ece5.json", "sourceHash": "6a71b6bbb02d55872135e95e22f8537c3fbd9e7d62c714883189cd300ae3805d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/quickstart.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.quickstart.md.988a5392.json", "sourceHash": "46fed513f86d121f58895a057e9fe55c184f0e57996a99b60f0d207b0e177673", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/releases/v1.6.0.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.releases.v1.6.0.md.1834bf67.json", "sourceHash": "48a17a45ad0c05a734b4e0f119b4ffbe08d996316c27b66a5907a8056b36d388", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/run-identity.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.run-identity.md.fab417c4.json", - "sourceHash": "00d7564332b54a10d573ebbdcbf8c4560563bbb66b972fa47a67c5ffb8bf313f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "7f6ba13dbce7ddbd782977b2c6f788b07c42387d36e71dc22ff169e9f36428e7", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/security-gate.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.security-gate.md.f5244ab0.json", "sourceHash": "95858445632021e5ddf779d429168aa4827a6ef5cfebff14285b9bb8b6359168", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/security/Security_Review_Checklist.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.security.Security_Review_Checklist.md.f023a01f.json", "sourceHash": "a12e368479cf46a042d7ae7b04edf9205238b9e8ed5cbeca85331b076c620acc", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/severity-tuning.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.severity-tuning.md.6c588e6a.json", "sourceHash": "02b724772a9817cfa8f2e7edf1a2da06afb0f8967c5a53c484569b901eb77ec8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/specs/SPEC-26-custom-severity.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.specs.SPEC-26-custom-severity.md.368deb68.json", "sourceHash": "f7254dc2656f0f693ebf6f96e22b04981c932ca7cc8888f4382e7fe95d78942c", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" + }, + "docs/specs/readiness-input-contract.md": { + "role": "dependency", + "caps": "docs/birdseye/caps/docs.specs.readiness-input-contract.md.21b8d190.json", + "sourceHash": "e5094db3168880d8a66af4f831dbc92ba868e2fd8b3823ea850d630beeeac769", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-01-ledger-sync.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-01-ledger-sync.md.594633b9.json", "sourceHash": "94bb31f87e5afbe72d2f09703c5c3b84fc4245228e7d073afc7a0295680f3b50", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-02-precision-review.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-02-precision-review.md.81603b28.json", "sourceHash": "4096f63f242f95a0052b49ba2d589813a363dc40734cfa2e8fa6c11e3bffeda1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-03-release-prep.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-03-release-prep.md.7b0d89dc.json", "sourceHash": "25d7225b6d8bfcf330bb465b787f738bb6df335f3fc67d484abab781f1102b95", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-04-birdseye.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-04-birdseye.md.d868a6ea.json", "sourceHash": "cdbe3a7a66633b31f275fbe701756949dc7133ae4fc3fc07441dfdc94d026403", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-05-severity-tuning.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-05-severity-tuning.md.050c359a.json", "sourceHash": "b2b298338654d3d3026d0475d436e282baa2ec0edcc0a4b792f3321fe4f6d53a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-07-ci-maintenance.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-07-ci-maintenance.md.1efb06be.json", "sourceHash": "e82c74d94bc31254c144dc03a9a46e638ac516b9d17afab93b29799669c43572", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-08-run-identity.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-08-run-identity.md.116677b7.json", "sourceHash": "f047e844ceee28c35c56c7a6b85c644188843c91676f8f319607bbd12c9f070b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-09-diff-severity.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-09-diff-severity.md.2c574c05.json", "sourceHash": "aa3dd0e0c6be22bc66bbbcb03932e5cbed1b8c571bd7c178fe79be2355b2338f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-10-precision-workbench.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-10-precision-workbench.md.595c47c0.json", "sourceHash": "d46f660cba4819c6a5eac830359357c8f365dd2409043b00103c1e7da1e1a8ab", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-11-severity-report.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-11-severity-report.md.a91b9b8f.json", "sourceHash": "ba07475fa9b20d29098f88b5df641cc68bd816416a78cda7803e796d05b8a2c8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260910-12-release-1.6.0.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260910-12-release-1.6.0.md.8f53b201.json", "sourceHash": "13df45d8e795a6169bc740fc403599428f79c35102b895c565d3797ce5958a73", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260911-01-human-readme.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260911-01-human-readme.md.3b2d7f9c.json", "sourceHash": "84c122973c48b41acf97bd9fadfff28ae267bdf9c7927cc31d3cb1ac83c6857a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260911-02-readiness-diff-followups.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260911-02-readiness-diff-followups.md.aa62438b.json", "sourceHash": "223f7e9e44b262b2b450df25f52fe6eb6ddb163666c91c1ebe07ad05583936f0", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260911-03-partial-yaml.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260911-03-partial-yaml.md.c29e74b8.json", "sourceHash": "21d59a5adea79664b501d3cab84ffcd2074c541fb80acd05bcbbb4be8d58ca00", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/tasks/20260911-04-policy-yaml-sections.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.tasks.20260911-04-policy-yaml-sections.md.c9b814ee.json", "sourceHash": "0db4e04b305c97d60075b23f67d34ad37993c8479996308fde2b3cd762bf9bee", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" + }, + "docs/tasks/20260911-05-manual-bb-fixes.md": { + "role": "dependency", + "caps": "docs/birdseye/caps/docs.tasks.20260911-05-manual-bb-fixes.md.e52c8561.json", + "sourceHash": "8a159ba8598ea6d8557d836931bc885e342d46270046a7af1706585e5001e2a1", + "generation_id": "birdseye-33377e4a68abbf61" }, "docs/troubleshooting.md": { "role": "dependency", "caps": "docs/birdseye/caps/docs.troubleshooting.md.373ebedf.json", "sourceHash": "b10d632688429d4b23186696d2f271a3ace97c2d2a342a88d7fcd37c3c406c83", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "governance/policy.yaml": { "role": "governance", "caps": "docs/birdseye/caps/governance.policy.yaml.e07e5077.json", "sourceHash": "0983f100271ecd79dd56e5e9f5ecbeb648c4e8000f64cf568c85d47e6b8d714b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "orchestration/quality-evidence-os-implementation.md": { "role": "dependency", "caps": "docs/birdseye/caps/orchestration.quality-evidence-os-implementation.md.f0809670.json", "sourceHash": "60b070819f5a09fe4ac6ddba8595ebb0b7f2bbe349df156dbbc275a830cf4147", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/go-tree-sitter-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.go-tree-sitter-adapter.ts.91a8b58f.json", "sourceHash": "f1a15198d4bba0f7202d61e315b72e8cc7b97a6056b170ada197dd29ef63ff24", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/js-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.js-adapter.ts.6ad91ba1.json", "sourceHash": "1f5b5ed041aa221d02770e665cdbdafe1e6c47d3e1037f22218c443ccd09282a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/node-services.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.node-services.ts.286a59fd.json", "sourceHash": "47a9f94de6e6c0457d096825269ec57f305a5f4cf0288f349af4b4685a4923e0", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/parser-registry.ts": { "role": "adapter", "caps": "docs/birdseye/caps/src.adapters.parser-registry.ts.b4dbc7a2.json", "sourceHash": "706011edc8dc137e2a8b688c05c48e0b522cf52ecbf4048c21fc866ec9b0fb95", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/py-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.py-adapter.ts.e3ceda63.json", "sourceHash": "06a08e3fa54da053974d489ad3f4d883e9d6f52d45ce12746502249bdaba4255", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/py-tree-sitter-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.py-tree-sitter-adapter.ts.6986beaf.json", "sourceHash": "69777afd9d76822c4cac97104265f820be74204b18b201d388751d9286c30304", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/rb-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.rb-adapter.ts.183f73ec.json", "sourceHash": "7ff1976c6962aa5d9a1b79a008a64d820fae2743cc0f86401415416a91f5c08a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/rb-tree-sitter-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.rb-tree-sitter-adapter.ts.7b7c067c.json", "sourceHash": "9d4d7b1a846dba4469374c1a7b5687ce05c65f9464e6451bc05f7c9fc5da2ca2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/regex-language-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.regex-language-adapter.ts.f14d6d2a.json", "sourceHash": "ed66f94b80e743f5e1f33b89b2c9548c1d4fc431244773f0dd948c0ca6b6af19", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/rs-tree-sitter-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.rs-tree-sitter-adapter.ts.0282d361.json", "sourceHash": "133363bd94b24556f0e559e89386f75a2731a1de8601d0c5ef47bc6ea45d73b8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/tree-sitter-initializer.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.tree-sitter-initializer.ts.f63a8860.json", "sourceHash": "f83ee08b3f4971f3881c521cd95adcee6f5d88770edf49548dd3233a11db8d5a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/adapters/ts-adapter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.adapters.ts-adapter.ts.d063679e.json", "sourceHash": "437b6b0153ebd8a9d6ef3f3cc2edf18af4dc2a12494c2c970aba040ff00eab01", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/application/context.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.application.context.ts.e96fed93.json", "sourceHash": "62d7b80de02c7a60d9c949bdaac57c541af4d4645a228f08835a852f8ce31759", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/application/rule-evaluator.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.application.rule-evaluator.ts.b8a66427.json", "sourceHash": "4d73e84f57d825045d671f3a3dff2eef2f340cb1915f09d0371ed755c4dfce9f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cache/index.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.cache.index.ts.548fc051.json", "sourceHash": "284492164b80003538fd82a019f7d4416ccbb5deabda3a8e3b71a11b4d364f97", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/analyze.ts": { "role": "entrypoint", "caps": "docs/birdseye/caps/src.cli.analyze.ts.dcb44679.json", - "sourceHash": "88b060789f31af41c7c225259a0b4dbc4842a64cc2ba0cf4cf7670622fc1494f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "8bedcb160eed9bf6eafa85a99660eb23e7ce53b285d967536cb8d4b6cd4fbade", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/exit-codes.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.cli.exit-codes.ts.b1518d64.json", "sourceHash": "a1245cc568a34a36e1a07912760588d6a23591bf09b17089c58854a3d5504bc4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/import-consumer.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.cli.import-consumer.ts.acce18d5.json", "sourceHash": "24460e24c90268486eb00245c1d0c50087b6f2225305050b8c8fcbba63173466", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/intake-artifact.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.cli.intake-artifact.ts.ed77b4f6.json", "sourceHash": "98504b8ceea65018d2ecd1cb1afe140b8464d1c6b47855b959bdef54d7147155", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/output.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.cli.output.ts.5a5e76d7.json", "sourceHash": "3af8abcfc832b27aa77d3fd100d998696bbd68250725eb29cc9901eea3537e49", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/readiness.ts": { "role": "entrypoint", "caps": "docs/birdseye/caps/src.cli.readiness.ts.1650193f.json", - "sourceHash": "5c0762332c963710d33b2e82bb312c3cedb5a7ac25601a10e2635ccbce6077b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "1421bacb00652e57872dd74bfcbf82e29b4f212ed40c89639a5bedc77a619f57", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/scan.ts": { "role": "entrypoint", "caps": "docs/birdseye/caps/src.cli.scan.ts.46daf9fd.json", "sourceHash": "f4e626c2704ee6af9e6ef9fd827c0c609b1b415efc1eaf431f8eb7fa63d3e19d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/cli/schema-validate.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.cli.schema-validate.ts.72f9f1dd.json", "sourceHash": "6ec467ba0020c2b044e0f388f23a41d8999ebf70dbb57a5613541845b1dcbb8c", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/config/policy-evaluator.ts": { "role": "config", "caps": "docs/birdseye/caps/src.config.policy-evaluator.ts.692ff63a.json", - "sourceHash": "011bb48ba42144f108f887ca9afa761c11341d4a7cf8e1ec3bc84a320a5aee79", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "7a513c8f175bbc68ddc4eb395e204d71dea78143bc630755f24349bd56abda11", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/config/policy-loader.ts": { "role": "config", "caps": "docs/birdseye/caps/src.config.policy-loader.ts.0cddccdb.json", - "sourceHash": "1f264282521330e32232ef8118024e54ac7e891f7ba75c06665da8ca69069503", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "df06d641236c6295bf0da8b1001367dfb8f9910f3182bba3c3bbccde7440ceae", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/config/policy-types.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.config.policy-types.ts.3e527503.json", - "sourceHash": "aabbd5785b83fbcd9a2f6fbb51ac4fdd2a3281e21e97cc025ed89db7bb9596a8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "0771768c6fb46dd0e3151781cfae47d70b2ae912c818aafb7582f40048069833", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/config/policy-yaml-parser.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.config.policy-yaml-parser.ts.9661e594.json", - "sourceHash": "8ce4fa244b8407d4c614ca7cf23b115331eb17dfa2ebd3db86104079de133d85", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "2d33b2ca2262913216201cf54d0d67708f16c21bc6605e77808aba6175bed0c1", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/config/severity-resolver.ts": { "role": "config", "caps": "docs/birdseye/caps/src.config.severity-resolver.ts.4f6c0ec0.json", "sourceHash": "bbd3cbafa841452b9b1688183e0cc5b297bf281a7f9e6e6b894cf475aae7d8b8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/core/database-analyzer.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.core.database-analyzer.ts.ef83db92.json", "sourceHash": "bc976ab1550e7c19d4261cba7216a08cf3416874048f84efe80072e006180ed7", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/core/evidence-utils.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.core.evidence-utils.ts.0a8f2cb4.json", "sourceHash": "c9a5c9f4a974bd31ebeca156d5a0861ebcea0c22ae7a5067fcef335df5e14924", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/core/file-utils.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.core.file-utils.ts.e924d65d.json", "sourceHash": "e41ffb8a106b1a144181bf56f6b08ef1c6029da9f25c5344f7314d93c5bbf7c1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/core/repo-graph-builder.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.core.repo-graph-builder.ts.092f146e.json", "sourceHash": "e8acb1e7136dd7c5ecafa6faa49066af7897788cc87f24950e47dbeb78911f0e", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/historical/ratchet-gate.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.historical.ratchet-gate.ts.be8657ce.json", - "sourceHash": "498d1a9f2893deb6fe9bf43397c3975b94e918413452fe3b22d13f3f0ea158bd", - "generation_id": "birdseye-d2d6a58ca24118dd" + "sourceHash": "a94ebf53604e3fa4dffaf886161b1c36dd677077c49370a2d681aee771bd80fb", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/llm/providers/index.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.llm.providers.index.ts.84190b45.json", "sourceHash": "e49b33a184bd46c2fe4a999d151377fcecf0ae1e1add354fd6c7580770cb3921", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/llm/providers/provider-health.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.llm.providers.provider-health.ts.27e7d61b.json", "sourceHash": "7e04da292a374bdcc88ca0fd7d2f64f933bd82d7c4ad2463adb8690804c5d414", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/llm/types.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.llm.types.ts.fb6f6c77.json", "sourceHash": "fbb1a2bffafd873a5a9e55eb1c22c3d8c8abedd440760cdcf8b64ec84c9ffe67", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/parallel/index.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.parallel.index.ts.5b6be68e.json", "sourceHash": "62aa1ca60588ed8ec48d6050b00b49fb1a5f7c40fc97c273286160aa1d48b531", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/audit-writer.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.audit-writer.ts.b6e59e36.json", "sourceHash": "d57b9f4cd878e6052bcc6bb582e2759e8289f296f9f617fb548713690f65c8ef", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/index.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.index.ts.ed3613c5.json", "sourceHash": "d7e10e907609fa9cc1012e74a02c4b5466e1befe9c51ea7ee05e6279744ae28f", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/invariant-generator.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.invariant-generator.ts.1f18aad4.json", "sourceHash": "c320d32d4db226e2c26db57b33a45c257bd7d9c45de6f89829688ff6a5a215a1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/json-reporter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.json-reporter.ts.ee833bf0.json", "sourceHash": "a924feab7a3d13ada6dbc0cd291a34c9fa091c14a1666191434e4e6c8ca28994", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/llm-enrichment.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.llm-enrichment.ts.00e5ad08.json", "sourceHash": "5ff4cda73ca808a067f13ef232c9533ca8d4e1dac9e8fc271700858f2feb99b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/markdown-reporter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.markdown-reporter.ts.9af0243b.json", "sourceHash": "27cf59a73aff27ac70c85ea59505acc69e05fee07ab0ccdcde971327295e20b4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/raw-findings-reporter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.raw-findings-reporter.ts.2ab3ec7c.json", "sourceHash": "ed5e6e2a84c0dc246fe6b30d6b13ac27fcde535f7b66269806fa33f0ea73533c", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" + }, + "src/reporters/sarif-reporter.ts": { + "role": "dependency", + "caps": "docs/birdseye/caps/src.reporters.sarif-reporter.ts.abe1f20a.json", + "sourceHash": "1eac55bd7f4c1502bdc2e2dcd85ee708b413dbbcf7c4293a386b623d990a13e5", + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/self-analysis-debt-reporter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.self-analysis-debt-reporter.ts.c4f1963a.json", "sourceHash": "ae0027ea479d450bad9fb2f5c557611f9899332e9d8fd2ac0ce64c52251318d5", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/test-seed-generator.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.test-seed-generator.ts.b2a7a8ee.json", "sourceHash": "aba32b8a8d425983f9356d472716c17a6bdd19b0ec4584ded3d8f7ad03d4e4fb", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/reporters/yaml-reporter.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.reporters.yaml-reporter.ts.efc347af.json", "sourceHash": "3a6819325b76498927d94423eaebc66e8b224e1ac50495611cdc67978f3390c9", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/circular-dependency.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.circular-dependency.ts.bceddaa2.json", "sourceHash": "1b874bc49fcc83c530b75b2e91c0c77386fd9df46eec59dcba26946074d85308", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/client-trusted-price.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.client-trusted-price.ts.c59aeb06.json", "sourceHash": "d6e918f7d778e198929081e849aeac8ae3789373fc35dbcbc9071375912706b2", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/db-destructive-ops.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.db-destructive-ops.ts.c002e59f.json", "sourceHash": "6fa2f753ad1f2b625329eb55253fb8b506920e9e2c0854a28a8701ab13ffb2af", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/db-migration-ops.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.db-migration-ops.ts.bc143588.json", "sourceHash": "f831b483d7dabf3c36645ef9fca402306935ab8bff8f9e0c736dc500a6a2a5ee", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/db-schema-change.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.db-schema-change.ts.cb6b166e.json", "sourceHash": "295eea4652dd25b65547d22019f1f17f7498e7bfef189da516babdb6f1288869", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/debt-marker.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.debt-marker.ts.16a50ec7.json", "sourceHash": "f894997cf4f7050a46931d91c3e8f543d251b16853ab7c6bfd65b86e47536ff1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/deprecated-api.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.deprecated-api.ts.5c32f42a.json", "sourceHash": "0c14a4880a4e3888048f542e88f37cd5b66dc2d7ebd883c8c115ece93a019c92", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/env-direct-access.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.env-direct-access.ts.ccd07ba1.json", "sourceHash": "e6560a170b2ecb86fc00b88acf4e56596d9f89044a0f2332da001ac07cd4cf9a", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/hardcoded-secret.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.hardcoded-secret.ts.57685f48.json", "sourceHash": "7d9efaf6ed46da16b042037cb064d4410578a22a2d27d886c7f47c911b176b93", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/index.ts": { "role": "registry", "caps": "docs/birdseye/caps/src.rules.index.ts.322e2e2b.json", "sourceHash": "064ea7edaf026afc462c5d0a0eb526316b7cd7875e15197ba9586420eeef8532", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/large-module.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.large-module.ts.948c83e5.json", "sourceHash": "542fd7bee7745deb6d5ba2318147bcf87fdd921aecbd997c5822a7225743a012", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/missing-input-sanitization.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.missing-input-sanitization.ts.b9adf577.json", "sourceHash": "8d3c11b90259818375266c8da77ec2d81a69879c53f7af4e8f2ac83286d0b1a6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/missing-rate-limit.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.missing-rate-limit.ts.571d00df.json", "sourceHash": "8704c442bb60ed671dd251b5b554763595dbe414cbb6aecce536be269dc65f37", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/missing-server-validation.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.missing-server-validation.ts.674cd1e7.json", "sourceHash": "5fd6a3c38afb600adcded3d17f79ec46549fb58c6381323f51a6fd0d70b2567d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/raw-sql.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.raw-sql.ts.d03b2216.json", "sourceHash": "91cd4dae2b6fd4f8cba89506c707c0acd0eddcfa8e9ec5d235318e3407b66cb1", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/suppression-debt.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.suppression-debt.ts.e945b433.json", "sourceHash": "268d091a971d6693b1e43d5b9716ce666c719c3298e452940950bc450ef4069d", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/try-catch-swallow.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.try-catch-swallow.ts.49915afc.json", "sourceHash": "09c7c6fe35124c97003e19dacad9f1a548e862539118dfda7ccd9a197bcb2d16", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/unsafe-delete.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.unsafe-delete.ts.6ae85c1e.json", "sourceHash": "e7f32e68bb820ef13f88a94615e2209a764e0719165196fb2b0a364482921f17", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/unsafe-redirect.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.unsafe-redirect.ts.6c21da82.json", "sourceHash": "784d78d32c435c46157688879ce6afdfecb34c595c2f0a467a2acc0f00e0eeb6", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/untested-critical-path.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.untested-critical-path.ts.6ec606a5.json", "sourceHash": "e3d129dbc7456f72d13820008f07c057cdd2f105a762049443dd00321a84723b", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/rules/weak-auth-guard.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.rules.weak-auth-guard.ts.83f1e3ac.json", "sourceHash": "3aa59f53d09dd7fcc54139359a72bd27a88337b3f0530c42b927d9472dfc5b71", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/self-analysis/suppression-summary.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.self-analysis.suppression-summary.ts.61ee0d9d.json", "sourceHash": "2ed7f9eb636d2c45b65a26cac6befafbbdb1b59845ca7f89bba2e6e73d5411ce", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/types/artifacts.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.types.artifacts.ts.1d71db34.json", "sourceHash": "ba57806c7cc0073951eaf32161f9c12c5e64a7da13147bdcd050f95d067429c4", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/types/contracts.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.types.contracts.ts.6048fd51.json", "sourceHash": "7a820f95adcf4d199c12e754676cc4d1fcea4c4735feacce95f6a01205abf8d8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/types/graph.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.types.graph.ts.a49f9e2b.json", "sourceHash": "65517cdf7234a79335e58ab9919153d7154b525e090f47d75fe8335b471c2b21", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" }, "src/types/rule-options.ts": { "role": "dependency", "caps": "docs/birdseye/caps/src.types.rule-options.ts.bf439b98.json", "sourceHash": "76d6d3ee6888fa2523549e7deffb09112693911c978db9a9d743b802071ac3b8", - "generation_id": "birdseye-d2d6a58ca24118dd" + "generation_id": "birdseye-33377e4a68abbf61" + }, + "src/utils/run-id.ts": { + "role": "dependency", + "caps": "docs/birdseye/caps/src.utils.run-id.ts.e485d2c3.json", + "sourceHash": "51e85e7cba0084f138cfdee8fbb9f1c272f52afee04109700fd64069d2bfabf3", + "generation_id": "birdseye-33377e4a68abbf61" } }, "edges": [ @@ -790,6 +814,10 @@ "CHANGELOG.md", "docs/releases/v1.6.0.md" ], + [ + "CHANGELOG.md", + "docs/specs/readiness-input-contract.md" + ], [ "CHANGELOG.md", "docs/tasks/20260910-01-ledger-sync.md" @@ -850,6 +878,10 @@ "CHANGELOG.md", "docs/tasks/20260911-04-policy-yaml-sections.md" ], + [ + "CHANGELOG.md", + "docs/tasks/20260911-05-manual-bb-fixes.md" + ], [ "CHECKLISTS.md", "CHANGELOG.md" @@ -882,6 +914,10 @@ "CHECKLISTS.md", "docs/security/Security_Review_Checklist.md" ], + [ + "CHECKLISTS.md", + "docs/specs/readiness-input-contract.md" + ], [ "CHECKLISTS.md", "docs/TASKS.md" @@ -918,6 +954,10 @@ "CLAUDE.md", "docs/severity-tuning.md" ], + [ + "CLAUDE.md", + "docs/specs/readiness-input-contract.md" + ], [ "CLAUDE.md", "docs/specs/SPEC-26-custom-severity.md" @@ -930,6 +970,10 @@ "CLAUDE.md", "docs/tasks/20260910-05-severity-tuning.md" ], + [ + "CLAUDE.md", + "docs/tasks/20260911-05-manual-bb-fixes.md" + ], [ "README.md", "CHANGELOG.md" @@ -1106,6 +1150,10 @@ "src/cli/analyze.ts", "src/reporters/raw-findings-reporter.ts" ], + [ + "src/cli/analyze.ts", + "src/reporters/sarif-reporter.ts" + ], [ "src/cli/analyze.ts", "src/reporters/self-analysis-debt-reporter.ts" @@ -1182,6 +1230,10 @@ "src/cli/readiness.ts", "src/types/artifacts.ts" ], + [ + "src/cli/readiness.ts", + "src/utils/run-id.ts" + ], [ "src/cli/scan.ts", "src/adapters/tree-sitter-initializer.ts" diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 34c823d..1188e0b 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -485,6 +485,10 @@ code-to-gate readiness --policy --from --out < partial設定は次の1行形式・複数行形式を同じように読み取る。`allow_partial`はboolean、`partial_warning_threshold`は0..1の数値で指定する。文字列の`"true"`や`"0.4"`、nullなどの不正な型はpolicyエラー(exit 5)になる。 +`partial_warning_threshold`はv1では予約設定であり、値を変えても警告・status・終了コードは変わらない。入力完全性は`completeness`と`allow_partial`で判断し、finding件数から欠落割合を計算しない。[Readiness入力仕様](specs/readiness-input-contract.md)に境界と受入条件を定義する。 + +Unreleasedの`exit.warn_only: true`は、正常に生成したreadiness判定の終了コードを0に変更する。artifactのstatusと理由は実際の評価を保持する。引数・policy・schema・I/Oのエラーは通常どおり失敗する。 + ```yaml partial: { allow_partial: true, partial_warning_threshold: 0.4 } ``` @@ -1921,7 +1925,7 @@ suppressions: |--------|-------------| | `fail_on_critical` | Exit with error on critical findings | | `fail_on_high` | Exit with error on high findings | -| `warn_only` | Never fail, only warn | +| `warn_only` | Return 0 for an evaluated verdict, preserving its status; input and I/O errors still fail | ### Policy DSL diff --git a/docs/error-model.md b/docs/error-model.md index 0936ff5..8847f7a 100644 --- a/docs/error-model.md +++ b/docs/error-model.md @@ -60,7 +60,7 @@ code-to-gate は CI で使われるため、失敗を曖昧にしない。 - base / head の差分が解決できる。 - changed files と blast radius が artifact に入る。 -- base ref が存在しない場合は exit code `2`。 +- base/head ref が存在しない場合は exit code `3`。必須ref引数の欠落は `2`。 - diff は取れるが一部ファイルが parser 失敗した場合は `partial` とし、policy に従う。 ### 3.4 `readiness` @@ -180,4 +180,4 @@ human-readable log は stderr に出す。machine-readable output と混ぜな | 17 | `RUN_BUSY` | Equivalent request is already running | | 18 | `EXECUTION_CANCELLED` | Run was cancelled before completion | -Agent runs persist an append-oriented manifest under `.qh/runs//`. A repeated request with the same fingerprint returns `status: "reused"`; a changed request with the same `request_id` fails closed. `next_actions` are declarative requests and are never auto-executed. \ No newline at end of file +Agent runs persist an append-oriented manifest under `.qh/runs//`. A repeated request with the same fingerprint returns `status: "reused"`; a changed request with the same `request_id` fails closed. `next_actions` are declarative requests and are never auto-executed. diff --git a/docs/policy-guide.md b/docs/policy-guide.md index f6c2df2..8fc2095 100644 --- a/docs/policy-guide.md +++ b/docs/policy-guide.md @@ -125,6 +125,12 @@ and accepts `manual-bb.json` or `manual-bb-seed.json`. ## Readiness Status +### Partial入力と警告運用 + +`partial.allow_partial`は、省略/falseなら不完全入力をブロックし、trueなら`passed_with_risk`として理由を残す。`partial_warning_threshold`はv1の予約設定で、有限の0..1として検証するが判定を変更しない。欠落割合の母数が入力にないため、指摘件数から割合を推定しない。完全性との12通りの受入条件は[Readiness入力仕様](specs/readiness-input-contract.md)を参照。 + +`exit.warn_only: true`は正常に生成されたreadiness判定の終了コードを0にする。artifactの実際のstatus・理由は保持し、不正入力やI/Oエラーは成功に変更しない。 + readinessの状態はblocking、partial、DSL等の評価結果から導出する。`readiness.criticalFindingStatus`という設定で切り替える機能は実装していない。 | Value | Meaning | diff --git a/docs/run-identity.md b/docs/run-identity.md index 5158070..67122b4 100644 --- a/docs/run-identity.md +++ b/docs/run-identity.md @@ -5,6 +5,7 @@ sourceのhash、finding fingerprint、cacheされた解析内容は、この実行識別とは別に維持する。 入力artifactを引き継ぐ処理は元の`run_id`を保持する。 +readinessは入力を別policyで評価する新しい実行として一意のIDを生成し、同じ実行のself-analysis-debtと共有する。元のfindingsのIDは変更しない。 agent APIのrequest/fingerprintによるrun IDと冪等再利用は従来どおりで、同じrequestを独立実行へ変換しない。 `run_id`は不透明な文字列として扱う。repoやcommitは`repo`フィールドを参照し、IDの末尾から推測しない。 diff --git a/docs/specs/readiness-input-contract.md b/docs/specs/readiness-input-contract.md new file mode 100644 index 0000000..caf5c9d --- /dev/null +++ b/docs/specs/readiness-input-contract.md @@ -0,0 +1,68 @@ +--- +intent_id: INT-MANUAL-BB-FIXES +owner: code-to-gate-team +status: active +last_reviewed_at: 2026-09-11 +next_review_due: 2026-10-11 +--- + +# Readiness入力・警告・実行識別の仕様 + +対象は `ctg/v1` / `findings@v1` / `release-readiness@v1`。manual-bbのPART-004と失敗ケースで確認した契約を定義する。修正はUnreleasedに含み、公開済みv1.6.0の動作保証へ遡及しない。 + +## 完全性とpartial設定 + +`findings.completeness`の`complete` / `partial`を入力完全性の根拠とする。指摘0件、baselineで新規0件、抑制後0件でもpartialは解消しない。`unsupported_claims`は原因説明であり、欠落割合の分子や母数にはしない。 + +`partial.allow_partial`はboolean、省略時false。以下は他にblocking/hold/低confidence条件がなく、`exit.warn_only`を指定しない場合の判定である。 + +| 入力 | allow_partial | status | 条件・説明 | exit | +|---|---|---|---|---:| +| complete | false / true | passed | INCOMPLETE_INPUTなし | 0 | +| partial | false / 省略 | blocked_input | INCOMPLETE_INPUT・partialの理由・再解析の推奨操作 | 1 | +| partial | true | passed_with_risk | INCOMPLETE_INPUT・partial許可の理由・再解析の推奨操作 | 0 | + +severity等の独立したblocking条件はpartialを許可しても有効。baselineは新規・悪化したfindingを絞るが、入力完全性は現在のartifact全体に適用する。 + +## partial_warning_thresholdの確定した扱い + +**v1では将来互換用の予約設定で、警告の有無・status・終了コードを変更しない。** 数値かつ有限、0以上1以下を受け付ける。省略時の内部既定値は0.2。文字列・null・負数・1を超える値はpolicyエラー(5)。 + +v1のfindings artifactには「解析すべき全入力数」と「欠落した入力数」の契約がないため、割合に基づく判定は提供しない。finding件数、unsupported claim件数、対象ファイルの単純比から欠落割合を推測しない。利用者は現在の許可判断にallow_partialを使う。 + +将来この予約値を実効化する場合は、対象入力の母数、欠落数、上限打切り時の扱い、境界の比較演算、出力先を別途定義し、既存v1利用者へ挙動変更を明示する。この文書はその将来機能を実装済みとしない。 + +PART-004の検収: complete/partial × allow_partial=false/true × threshold=0/0.2/1の12通りを実行する。同じ入力とallow_partialでは、閾値を変えてもstatus、INCOMPLETE_INPUT、終了コードが上表と一致する。値域・型の拒否はPOL-014のケースで検証する。 + +## warn_onlyと失敗の境界 + +`exit.warn_only: true`は、正常に入力を検証してreadiness artifactを生成できたときの品質判定による終了コード1を0へ変更する。artifactとstdoutのstatus、failedConditions、completeness、理由は実際の判定を保持する。警告運用はリリース承認と同義ではない。 + +必須引数の欠落、不正policy、入力artifactのschema違反、読み書き失敗は警告運用でも成功に変更しない。`warn_only`省略/falseのときは従来どおりpassed/passed_with_riskが0、それ以外の品質判定は1。 + +## confidence filterと抑制入力 + +`confidence.filter_low: false`は、min_confidence未満のfindingも通常のseverity/category判定へ渡す。trueまたは省略時は従来どおり閾値未満を判定対象から除外する。falseで通常判定に含めたfindingを、同時に低confidenceによる除外件数へ加算しない。 + +抑制YAMLは引用符、末尾コメント、flow形式を同じ値として解析する。構文エラーのあるファイルの先頭部分だけを採用しない。不正な日付や実在しない日付の抑制は適用しない。readinessは不正期限を推奨操作へ明示する。日付のみの期限はUTC 00:00:00を表し、その時刻を超えると期限切れになる。 + +## baselineの参照優先 + +readiness artifactをbaselineとして指定し、`artifactRefs.findings`がある場合は、その明示参照先を使用する。同階層の別findingsへ置き換えない。明示参照先を利用できない場合は設定エラーにし、暗黙の別baselineで合格にしない。参照を持たない旧readiness artifactの同階層findings、および直接findings/ディレクトリ指定は引き続き対応する。 + +## 独立readiness実行のID + +各readiness呼出しは新しいpolicy評価として一意のrun_idを生成する。同時刻の独立実行でも重複しない。同じ呼出しが生成するrelease-readinessとself-analysis-debtは同じrun_idを持つ。入力findingsのrun_idは変更しない。agent requestによる同じ実行の冪等再利用は独立した再評価と区別する。 + +## diff renameのv1表現 + +`diff-analysis.changed_files`は新しいpathと`status: renamed`でrenameを表現する。旧pathを持つpreviousPathフィールドや新旧対の出力はv1の要求に含めない。削除と追加・変更の区別、指定commit snapshot、blast radiusの契約は維持する。旧pathが必要な連携は別の契約追加として扱う。 + +## 根拠・関連文書 + +- [Policy Guide](../policy-guide.md) +- [CLI reference](../cli-reference.md) +- [実行ID](../run-identity.md) +- [findings schema](../../schemas/findings.schema.json) +- [diff schema](../../schemas/diff-analysis.schema.json) +- [Task Seed](../tasks/20260911-05-manual-bb-fixes.md) diff --git a/docs/tasks/20260911-05-manual-bb-fixes.md b/docs/tasks/20260911-05-manual-bb-fixes.md new file mode 100644 index 0000000..0c3e83c --- /dev/null +++ b/docs/tasks/20260911-05-manual-bb-fixes.md @@ -0,0 +1,46 @@ +--- +task_id: 20260911-05 +intent_id: INT-MANUAL-BB-FIXES +owner: code-to-gate-team +status: done +last_reviewed_at: 2026-09-11 +next_review_due: 2026-10-11 +--- + +# manual-bbの失敗修正と未確定仕様の確定 + +## 背景・ゴール + +main 2fe6b2eの公開CLI・ブラウザ検収は105ケース中95成功、9失敗、1保留。既知5件と新規5件(表示不整合を含む)を検出した。利用者の「未確定は仕様書を書き、失敗を直す」という指示に基づき、修正と同じケースによる再検収を完了する。 + +## スコープと分割 + +通常の小さな変更単位を守るため、以下の独立した修正単位へ分割し、rootが統合する。各単位は回帰テストから着手する。src/core、src/rules、governance、schemas、workflowは変更対象に含めない。 + +1. BUG-01: src/historical/ratchet-gate.ts と対応テストで明示baseline参照を優先。 +2. BUG-02/03: src/suppression のYAML・期限処理と対応テストを順に修正。 +3. BUG-04: src/config/policy-yaml-parser.ts / policy-loader.ts の明示入力検証と対応テスト。 +4. BUG-05/06: src/cli/readiness.ts と対応テストで独立ID・warn_only終了コードを修正。 +5. BUG-07/08: src/cli.ts / src/cli/analyze.ts のemit検証・SARIF生成と対応テスト。 +6. BUG-09/10: src/cli.ts のglobal help、src/viewerのversion表示と対応テスト。 +7. PART-004: v1の入力が持たない欠落割合をfinding件数から作らない。partial_warning_thresholdは型・値域だけを検証する予約設定、完全性とallow_partialによる判定は常時有効、と仕様書で確定する。閾値の変化で判定が変わらないことを公開CLIで検収する。 +8. READMEのimport→同一outでanalyze --from-imports→exportを同期。renameのv1公開表現も仕様へ明記。 + +## TDD / 検証 + +既存の失敗証跡を保存したまま、各修正の回帰テスト、build/lint/typecheck、全テスト、coverage、package smokeを実行する。manual-bbの105ケースを新しい証跡directoryへ再実行し、PART-004も確定した仕様をoracleにして実行する。変更行coverageを全体coverageと区別し、native standard Gateを再評価する。 + +## 完了条件 + +- 10件の不具合が同じ入力条件と正常対照で解消。 +- PART-004の仕様・oracle・実行結果が一致。 +- 既存公開artifactのschema互換性、agentの冪等性を維持。 +- Birdseye生成/check、適切な自動検証、BB検収結果を検収文書に記録。 + +## 検収記録 + +[検収記録](../acceptance/AC-20260911-05-manual-bb-fixes.md): 105/105成功、失敗0、保留0、native standard GateはGo。変更行coverageは185/205行(90.24%)。元の10不具合に加え、filter_low=falseの関連不一致も対照テストで修正した。 + +全体3,859件、Tree-sitter 63件、保守15件、coverage対象1,970件、追加coverage対象1,049件が成功。既存skipは通常/coverage 4件、追加coverage 1件。build/lint/typecheck、package smoke、文書参照・配布状態・roadmap・Birdseyeを検証した。PRのCIとmainへの反映は対応PRで追跡する。 + +旧証跡: ../code-to-gate-manual-bb-20260911/report.md。修正後証跡: ../code-to-gate-manual-bb-fix-20260911/report.md(いずれもrepo外の同一workspace)。 diff --git a/src/cli.ts b/src/cli.ts index 5a28e81..778dd1d 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -109,7 +109,7 @@ Options: Baseline findings/readiness artifact or artifact directory for ratchet gating --manual-evidence Manual BB evidence artifact used by Policy DSL - --emit Output formats (all, json, yaml, md, mermaid) + --emit Output formats (all, json, yaml, md, mermaid, sarif) --require-llm Require LLM analysis --llm-provider LLM provider (ollama, llamacpp, deterministic) --llm-mode LLM mode (local-only, allow-cloud) @@ -181,6 +181,43 @@ async function main(): Promise { return EXIT.OK; } + // Every public command accepts the global help form. `agent` is the + // machine-readable exception: its own protocol owns stdout and must + // continue to receive `--help` unchanged. + const helpCommands = new Set([ + "schema", "scan", "analyze", "diff", "import", "readiness", + "precision-review", "export", "viewer", "llm-health", "historical", + "spec-drift", "rule", "pack", "doctor", "test-plan", "ownership", + "query", "explain-gate", "drift-budget", "review-queue", + "baseline-ledger", "qeos", "release-pack", "pr-review", + "pr-review-publish", "plugin-marketplace", "evidence", "plugin-sandbox", + "assurance", + ]); + const valueOptions = new Set([ + "--out", "--base", "--head", "--policy", "--from", "--baseline", + "--manual-evidence", "--emit", "--format", "--llm-provider", "--llm-mode", + "--llm-model", "--llm-port", "--llm-base-url", "--title", "--public-url", + "--hosted-target", "--redaction-profile", "--intake", "--repo-root", + "--max-input-mb", "--producer-version", "--review", "--history", + "--current", "--previous", "--category", "--severity", "--description", + "--owner", "--approver", "--approval-reason", "--refresh-reason", + "--estimated-effort", "--prevention-note", "--failed-budget", + "--warning-budget", "--recurrence-budget", "--branch", "--ci-url", + "--comment-file", "--artifact-url", "--repo", "--pull", "--commit-sha", + "--target-version", "--plugins", "--input", "--sandbox", "--timeout", + "--memory", "--cpu", "--execution-policy", "--docker-image", "--output", + "--min-confidence", "--cache", "--parallel", "--suppress", "--blast-depth", + "--schema-version", "--scope", "--provider", "--run-id", + ]); + const commandHelpRequested = args.some((arg, index) => { + if (arg !== "--help" && arg !== "-h") return false; + return index === 0 || !valueOptions.has(args[index - 1]); + }); + if (helpCommands.has(command) && commandHelpRequested) { + printHelp(); + return EXIT.OK; + } + if (command === "agent") { return await agentCommand(args, { VERSION, EXIT, getOption }); } diff --git a/src/cli/__tests__/analyze.test.ts b/src/cli/__tests__/analyze.test.ts index 10a10a3..2ac7e0c 100644 --- a/src/cli/__tests__/analyze.test.ts +++ b/src/cli/__tests__/analyze.test.ts @@ -88,9 +88,32 @@ describe("analyze CLI", () => { expect(existsSync(path.join(allTestDir, "findings.json"))).toBe(true); expect(existsSync(path.join(allTestDir, "risk-register.yaml"))).toBe(true); expect(existsSync(path.join(allTestDir, "analysis-report.md"))).toBe(true); + expect(existsSync(path.join(allTestDir, "results.sarif"))).toBe(true); expect(existsSync(path.join(allTestDir, "audit.json"))).toBe(true); }); + it("--emit sarif generates results.sarif and records it in audit", async () => { + const sarifTestDir = path.join(tempOutDir, "emit-sarif"); + mkdirSync(sarifTestDir, { recursive: true }); + + const result = await analyzeCommand( + [fixturesDir, "--emit", "sarif", "--out", sarifTestDir], + { VERSION, EXIT, getOption } + ); + + expect(result).toBe(EXIT.OK); + const sarifPath = path.join(sarifTestDir, "results.sarif"); + expect(existsSync(sarifPath)).toBe(true); + const sarif = JSON.parse(readFileSync(sarifPath, "utf8")); + expect(sarif.version).toBe("2.1.0"); + expect(Array.isArray(sarif.runs)).toBe(true); + + const audit = JSON.parse(readFileSync(path.join(sarifTestDir, "audit.json"), "utf8")); + expect(audit.artifacts).toEqual(expect.arrayContaining([ + expect.objectContaining({ path: expect.stringContaining("results.sarif") }), + ])); + }); + it("exit code OK on successful analysis", async () => { const args = [fixturesDir, "--out", tempOutDir]; const result = await analyzeCommand(args, { VERSION, EXIT, getOption }); @@ -155,6 +178,7 @@ describe("analyze CLI", () => { "findings.json", "risk-register.yaml", "analysis-report.md", + "results.sarif", "test-seeds.json", "invariants.json", "repo-graph.json", @@ -659,17 +683,17 @@ describe("analyze CLI", () => { expect(existsSync(path.join(mermaidTestDir, "audit.json"))).toBe(true); }); - it("unknown emit format is filtered out", async () => { - const unknownTestDir = path.join(tempOutDir, "emit-unknown"); - mkdirSync(unknownTestDir, { recursive: true }); + it("rejects unknown emit formats with a usage error", async () => { + for (const value of ["invalid-format", "not-a-format"]) { + const unknownTestDir = path.join(tempOutDir, `emit-${value}`); + mkdirSync(unknownTestDir, { recursive: true }); - // unknown format should be filtered, still generates audit.json - const args = [fixturesDir, "--emit", "unknown,invalid", "--out", unknownTestDir]; - const result = await analyzeCommand(args, { VERSION, EXIT, getOption }); - // Should return OK - unknown formats are filtered out - expect(result).toBe(EXIT.OK); - // audit.json should always exist - expect(existsSync(path.join(unknownTestDir, "audit.json"))).toBe(true); + const args = [fixturesDir, "--emit", value, "--out", unknownTestDir]; + const result = await analyzeCommand(args, { VERSION, EXIT, getOption }); + + expect(result).toBe(EXIT.USAGE_ERROR); + expect(existsSync(path.join(unknownTestDir, "audit.json"))).toBe(false); + } }); it("completeness field in findings", async () => { diff --git a/src/cli/__tests__/cli-help.test.ts b/src/cli/__tests__/cli-help.test.ts new file mode 100644 index 0000000..121d711 --- /dev/null +++ b/src/cli/__tests__/cli-help.test.ts @@ -0,0 +1,68 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +interface CliRunResult { + code: number | string | undefined; + stdout: string; + stderr: string; +} + +async function runSourceCli(args: string[]): Promise { + const originalArgv = process.argv; + const originalExitCode = process.exitCode; + const stdout: string[] = []; + const stderr: string[] = []; + const log = vi.spyOn(console, "log").mockImplementation((...values) => { + stdout.push(values.join(" ")); + }); + const error = vi.spyOn(console, "error").mockImplementation((...values) => { + stderr.push(values.join(" ")); + }); + + try { + process.argv = ["node", "code-to-gate", ...args]; + process.exitCode = undefined; + vi.resetModules(); + await import("../../cli.js?cli-help-regression"); + await new Promise((resolve) => setImmediate(resolve)); + return { code: process.exitCode, stdout: stdout.join("\n"), stderr: stderr.join("\n") }; + } finally { + process.argv = originalArgv; + process.exitCode = originalExitCode; + log.mockRestore(); + error.mockRestore(); + } +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("public CLI global help", () => { + it.each(["scan", "export", "doctor"])( + "returns success for %s --help before required-argument validation", + async (command) => { + const result = await runSourceCli([command, "--help"]); + + expect(result.code).toBe(0); + expect(result.stdout).toContain("code-to-gate 1.6.0"); + expect(result.stdout).toContain(`code-to-gate ${command}`); + expect(result.stderr).toBe(""); + } + ); + + it("does not treat --help used as an option value as a help request", async () => { + const result = await runSourceCli(["scan", "--out", "--help"]); + + expect(result.code).toBe(2); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("out"); + }); + + it("keeps unknown command handling unchanged", async () => { + const result = await runSourceCli(["unknown-command", "--help"]); + + expect(result.code).toBe(2); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("unknown command: unknown-command"); + }); +}); diff --git a/src/cli/__tests__/readiness-partial-policy.test.ts b/src/cli/__tests__/readiness-partial-policy.test.ts index cd7a9e2..dd461c6 100644 --- a/src/cli/__tests__/readiness-partial-policy.test.ts +++ b/src/cli/__tests__/readiness-partial-policy.test.ts @@ -153,6 +153,25 @@ describe("readiness partial policy YAML", () => { expect(readiness?.recommendedActions?.[0]).toContain("scan diagnostics"); }); + it.each([0, 0.2, 1])("treats partial warning threshold %s as a reserved v1 value", async (threshold) => { + for (const completeness of ["complete", "partial"] as const) { + for (const allowPartial of [false, true]) { + const { findingsDir, outDir, policyPath } = createCase( + `reserved-${threshold}-${completeness}-${allowPartial}`, + `partial: { allow_partial: ${allowPartial}, partial_warning_threshold: ${threshold} }`, + ); + const inputPath = path.join(findingsDir, "findings.json"); + const input = JSON.parse(readFileSync(inputPath, "utf8")); + input.completeness = completeness; + writeFileSync(inputPath, JSON.stringify(input)); + const { exitCode, readiness } = await runReadiness(findingsDir, policyPath, outDir); + expect(readiness?.status).toBe(completeness === "complete" ? "passed" : allowPartial ? "passed_with_risk" : "blocked_input"); + expect(exitCode).toBe(completeness === "partial" && !allowPartial ? EXIT.READINESS_NOT_CLEAR : EXIT.OK); + expect(readiness?.failedConditions?.some(c => c.id === "INCOMPLETE_INPUT")).toBe(completeness === "partial"); + } + } + }); + it("keeps the omitted partial section strict", async () => { const { findingsDir, outDir, policyPath } = createCase("strict-omitted"); const { exitCode, readiness } = await runReadiness(findingsDir, policyPath, outDir); diff --git a/src/cli/__tests__/readiness.test.ts b/src/cli/__tests__/readiness.test.ts index e163ffc..e666f14 100644 --- a/src/cli/__tests__/readiness.test.ts +++ b/src/cli/__tests__/readiness.test.ts @@ -5,7 +5,7 @@ * Refactored: 15 tests (merged similar cases) */ -import { describe, it, expect, beforeAll, afterAll, beforeEach } from "vitest"; +import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from "vitest"; import { readinessCommand } from "../readiness.js"; import { validateArtifactObject } from "../schema-validate.js"; import { existsSync, readFileSync, rmSync, mkdirSync, writeFileSync } from "node:fs"; @@ -1018,15 +1018,49 @@ suppression: const out1 = path.join(tempOutDir, "run1"); const out2 = path.join(tempOutDir, "run2"); - await readinessCommand([fixturesDir, "--policy", policyFile, "--from", findingsDir, "--out", out1], { VERSION, EXIT, getOption }); - await new Promise(r => setTimeout(r, 100)); - await readinessCommand([fixturesDir, "--policy", policyFile, "--from", findingsDir, "--out", out2], { VERSION, EXIT, getOption }); + vi.useFakeTimers({ toFake: ["Date"] }); + vi.setSystemTime(new Date("2026-09-11T00:00:00.000Z")); + try { + await readinessCommand([fixturesDir, "--policy", policyFile, "--from", findingsDir, "--out", out1], { VERSION, EXIT, getOption }); + await readinessCommand([fixturesDir, "--policy", policyFile, "--from", findingsDir, "--out", out2], { VERSION, EXIT, getOption }); + } finally { + vi.useRealTimers(); + } const r1 = JSON.parse(readFileSync(path.join(out1, "release-readiness.json"), "utf8")); const r2 = JSON.parse(readFileSync(path.join(out2, "release-readiness.json"), "utf8")); expect(r1.run_id).toMatch(/^readiness-/); expect(r2.run_id).toMatch(/^readiness-/); + expect(r1.run_id).not.toBe(r2.run_id); + for (const [out, result] of [[out1, r1], [out2, r2]]) { + const debt = JSON.parse(readFileSync(path.join(out, "self-analysis-debt.json"), "utf8")); + expect(debt.run_id).toBe(result.run_id); + } + expect(JSON.parse(readFileSync(path.join(findingsDir, "findings.json"), "utf8")).run_id).toBe("test-run"); + }); + }); + + describe("warn-only exit policy", () => { + it.each([false, true])("keeps a blocked verdict with warn_only=%s", async (warnOnly) => { + const input = writeFindingsToDir(path.join(tempOutDir, "warn-input"), [ + createFinding({ ruleId: "DEBT_MARKER", category: "maintainability", severity: "high" }), + ]); + const warningPolicy = path.join(tempOutDir, "warn.yaml"); + writeFileSync(warningPolicy, `version: ctg/v1\nblocking:\n severity: { high: true }\nexit: { warn_only: ${warnOnly} }\n`); + const { exitCode, readiness } = await runReadiness([fixturesDir, "--policy", warningPolicy, "--from", input, "--out", tempOutDir]); + expect(exitCode).toBe(warnOnly ? EXIT.OK : EXIT.READINESS_NOT_CLEAR); + expect(readiness.status).toBe("blocked_input"); + expect(readiness.failedConditions).toEqual(expect.arrayContaining([expect.objectContaining({ id: "BLOCKING_SEVERITY_HIGH" })])); + }); + + it("does not hide invalid input under warn_only", async () => { + const input = writeFindingsToDir(path.join(tempOutDir, "invalid-warn"), [], { completeness: "invalid" }); + const warningPolicy = path.join(tempOutDir, "warn.yaml"); + writeFileSync(warningPolicy, "version: ctg/v1\nexit: { warn_only: true }\n"); + const { exitCode } = await runReadiness([fixturesDir, "--policy", warningPolicy, "--from", input, "--out", tempOutDir]); + expect(exitCode).toBe(EXIT.SCHEMA_FAILED); + expect(existsSync(path.join(tempOutDir, "release-readiness.json"))).toBe(false); }); }); diff --git a/src/cli/analyze.ts b/src/cli/analyze.ts index 74395c1..7b88769 100644 --- a/src/cli/analyze.ts +++ b/src/cli/analyze.ts @@ -65,6 +65,7 @@ import { generateRawFindingsArtifact, writeRawFindingsJson, } from "../reporters/raw-findings-reporter.js"; +import { writeSarifReport } from "../reporters/sarif-reporter.js"; import { classifySuppressedFindings, countSuppressedByClass, @@ -92,6 +93,8 @@ interface AnalyzeOptions { // Constants const VALID_LLM_PROVIDERS: LlmProviderType[] = ["ollama", "llamacpp", "deterministic"]; const VALID_LLM_MODES = ["local-only", "allow-cloud"]; +type AnalyzeEmitFormat = Exclude | "sarif"; +const VALID_EMIT_FORMATS: readonly AnalyzeEmitFormat[] = ["json", "yaml", "md", "mermaid", "sarif"]; function classifyGeneratedArtifact(filePath: string): AuditOutputArtifact["kind"] { const name = nodePathService.basename(filePath); @@ -166,12 +169,24 @@ export function buildGeneratedArtifactRefs(paths: string[], cwd: string): AuditO }); } -function parseEmitOption(value: string | undefined): EmitFormat[] { - if (!value || value === "all") { - return ["json", "yaml", "md", "mermaid"]; +function parseEmitOption(value: string | undefined): { + formats: AnalyzeEmitFormat[]; + invalidFormats: string[]; +} { + if (value === undefined || value === "all") { + return { formats: [...VALID_EMIT_FORMATS], invalidFormats: [] }; } - const formats = value.split(",").map((f) => f.trim() as EmitFormat); - return formats.filter((f) => ["json", "yaml", "md", "mermaid", "all"].includes(f)); + + const values = value.split(",").map((format) => format.trim()); + const invalidFormats = values.filter( + (format) => format !== "all" && !VALID_EMIT_FORMATS.includes(format as AnalyzeEmitFormat) + ); + const formats = values.includes("all") + ? [...VALID_EMIT_FORMATS] + : values.filter((format): format is AnalyzeEmitFormat => + VALID_EMIT_FORMATS.includes(format as AnalyzeEmitFormat) + ); + return { formats, invalidFormats }; } /** @@ -262,6 +277,17 @@ export async function analyzeCommand(args: string[], options: AnalyzeOptions): P return options.EXIT.USAGE_ERROR; } + const parsedEmit = parseEmitOption(emitValue); + if (parsedEmit.invalidFormats.length > 0) { + emitCliError(`Invalid emit format: ${parsedEmit.invalidFormats.join(", ")}`, { + code: "INVALID_EMIT_FORMAT", + command: "analyze", + exitCode: options.EXIT.USAGE_ERROR, + }); + console.error(`Valid formats: all, ${VALID_EMIT_FORMATS.join(", ")}`); + return options.EXIT.USAGE_ERROR; + } + // Validate repo argument if (!repoArg) { emitCliError("usage: code-to-gate analyze [--emit all] --out [--policy ] [--llm-provider ] [--llm-base-url ] [--from-imports] [--tree-sitter] [--database-analysis]", { @@ -307,7 +333,7 @@ export async function analyzeCommand(args: string[], options: AnalyzeOptions): P return options.EXIT.USAGE_ERROR; } - const emitFormats = parseEmitOption(emitValue); + const emitFormats = parsedEmit.formats; const absoluteOutDir = nodePathService.resolve(cwd, outDir); // Analyze uses text-based rules by default so large TypeScript repos stay responsive. @@ -558,6 +584,16 @@ Provide concise, actionable findings.`, const invariantsPath = writeInvariantsJson(absoluteOutDir, invariants); generated.push(invariantsPath); + if (emitFormats.includes("sarif")) { + const sarifPath = writeSarifReport(absoluteOutDir, reportedFindings, { + includeRiskRegister: true, + includeTestSeeds: true, + riskRegister, + testSeeds, + }); + generated.push(sarifPath); + } + // Generate self-analysis-debt.json only when policy is provided // When no policy, readiness command will generate authoritative debt artifact if (policy && suppressions.length > 0) { diff --git a/src/cli/readiness.ts b/src/cli/readiness.ts index d82fdda..67a7190 100644 --- a/src/cli/readiness.ts +++ b/src/cli/readiness.ts @@ -6,6 +6,8 @@ import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs"; import path from "node:path"; + +import { createUniqueRunId } from "../utils/run-id.js"; import { ensureDir } from "../core/file-utils.js"; import { EXIT, getOption, VERSION } from "./exit-codes.js"; import { loadPolicyFile, loadSuppressionFile, checkSuppressionExpiry, detectBroadSuppressions, type SuppressionEntry, type SuppressionExpiryWarning } from "../config/policy-loader.js"; @@ -442,7 +444,11 @@ export async function readinessCommand(args: string[], options: ReadinessOptions // Add expiry warnings to recommended actions for (const warning of expiryWarnings) { - if (warning.status === "expired") { + if (warning.status === "invalid") { + recommendedActions.push( + `WARNING: Suppression for ${warning.ruleId} at ${warning.path} has invalid expiry ${warning.expiry} and was not applied. Correct the date or remove the suppression.` + ); + } else if (warning.status === "expired") { recommendedActions.push( `WARNING: Suppression for ${warning.ruleId} at ${warning.path} expired ${warning.daysUntilExpiry} days ago. Review and update or remove.` ); @@ -490,7 +496,7 @@ export async function readinessCommand(args: string[], options: ReadinessOptions // Build readiness artifact const now = new Date().toISOString(); - const runId = `readiness-${now.replace(/[-:.TZ]/g, "").slice(0, 14)}`; + const runId = createUniqueRunId("readiness", { timestamp: now }); const readiness: ReleaseReadinessArtifact = { version: CTG_VERSION, @@ -579,8 +585,9 @@ export async function readinessCommand(args: string[], options: ReadinessOptions }) ); - // Return exit code based on status - if (readinessStatus === "passed" || readinessStatus === "passed_with_risk") { + // warn_only changes the verdict exit, retaining the actual artifact status. + // Input and I/O errors are handled separately and remain failures. + if (policy.exit?.warnOnly || readinessStatus === "passed" || readinessStatus === "passed_with_risk") { return options.EXIT.OK; } else { return options.EXIT.READINESS_NOT_CLEAR; diff --git a/src/config/__tests__/policy-evaluator.test.ts b/src/config/__tests__/policy-evaluator.test.ts index 3507d04..77a38cc 100644 --- a/src/config/__tests__/policy-evaluator.test.ts +++ b/src/config/__tests__/policy-evaluator.test.ts @@ -169,6 +169,32 @@ describe("policy-evaluator", () => { expect(result.status).toBe("needs_review"); }); + it.each([ + [true, "needs_review", 0, 1], + [undefined, "needs_review", 0, 1], + [false, "blocked_input", 1, 0], + ] as const)("honors filter_low=%s for below-threshold findings", (filterLow, status, blockedCount, lowConfidenceCount) => { + const policy = createDefaultPolicy(); + policy.confidence.minConfidence = 0.7; + policy.confidence.filterLow = filterLow; + policy.blocking.category.maintainability = false; + const result = evaluatePolicy([ + createMockFinding("below-threshold", "RULE_001", "high", "maintainability", 0.5), + ], policy); + + expect(result.status).toBe(status); + expect(result.blockedFindings).toHaveLength(blockedCount); + expect(result.lowConfidenceFindings).toHaveLength(lowConfidenceCount); + expect(result.passedFindings).toHaveLength(0); + if (filterLow === false) { + expect(result.failedConditions).toContainEqual(expect.objectContaining({ + type: "severity_block", + severity: "high", + findingId: "below-threshold", + })); + } + }); + it("should apply suppressions", () => { const policy = createDefaultPolicy(); policy.blocking.severity.critical = true; diff --git a/src/config/__tests__/policy-loader.test.ts b/src/config/__tests__/policy-loader.test.ts index 03ccc3c..2881ea8 100644 --- a/src/config/__tests__/policy-loader.test.ts +++ b/src/config/__tests__/policy-loader.test.ts @@ -2,7 +2,7 @@ * Tests for policy-loader.ts */ -import { describe, it, expect, beforeAll, afterAll } from "vitest"; +import { describe, it, expect, beforeAll, afterAll, vi } from "vitest"; import { createDefaultPolicy, loadPolicyFile, @@ -10,6 +10,7 @@ import { isValidPolicyVersion, loadSuppressionFile, isSuppressed, + checkSuppressionExpiry, detectBroadSuppressions, isBroadSuppression, POLICY_VERSION, @@ -584,6 +585,74 @@ suppressions: expect(result.suppressed).toBe(true); expect(result.expiry).toBe("2030-12-31"); }); + + it("should treat quoted fields with trailing comments like uncommented YAML", () => { + const plainPath = path.join(tempDir, "plain-suppression.yaml"); + const commentedPath = path.join(tempDir, "commented-suppression.yaml"); + writeFileSync(plainPath, `version: ctg/v1 +suppressions: + - rule_id: DEBT_MARKER + path: src/index.ts + reason: Accepted debt + expiry: 2099-12-31 +`); + writeFileSync(commentedPath, `version: "ctg/v1" # schema +suppressions: + - rule_id: "DEBT_MARKER" # rule + path: "src/index.ts" # source path + reason: "Accepted debt" # rationale + expiry: "2099-12-31" # review date +`); + + const plain = loadSuppressionFile(plainPath, tempDir); + const commented = loadSuppressionFile(commentedPath, tempDir); + + expect(commented.version).toBe(plain.version); + expect(commented.suppressions).toEqual(plain.suppressions); + expect(isSuppressed("DEBT_MARKER", "src/index.ts", commented.suppressions).suppressed).toBe(true); + }); + + it.each(["not-a-date", "2026-02-30"])("does not apply an invalid expiry (%s) and reports an invalid-date diagnostic", (expiry) => { + const suppressions: SuppressionEntry[] = [{ + ruleId: "DEBT_MARKER", + path: "src/index.ts", + reason: "Invalid test input", + expiry, + }]; + + expect(isSuppressed("DEBT_MARKER", "src/index.ts", suppressions).suppressed).toBe(false); + expect(checkSuppressionExpiry(suppressions)).toEqual([ + expect.objectContaining({ + path: "src/index.ts", + ruleId: "DEBT_MARKER", + expiry, + status: "invalid", + }), + ]); + }); + + it("uses UTC midnight for the YYYY-MM-DD expiry boundary", () => { + const suppressions: SuppressionEntry[] = [{ + ruleId: "DEBT_MARKER", + path: "src/index.ts", + reason: "UTC boundary", + expiry: "2026-06-30", + }]; + + vi.useFakeTimers(); + try { + vi.setSystemTime(new Date("2026-06-29T23:59:59.999Z")); + expect(isSuppressed("DEBT_MARKER", "src/index.ts", suppressions).suppressed).toBe(true); + + vi.setSystemTime(new Date("2026-06-30T00:00:00.000Z")); + expect(isSuppressed("DEBT_MARKER", "src/index.ts", suppressions).suppressed).toBe(true); + + vi.setSystemTime(new Date("2026-06-30T00:00:00.001Z")); + expect(isSuppressed("DEBT_MARKER", "src/index.ts", suppressions).suppressed).toBe(false); + } finally { + vi.useRealTimers(); + } + }); }); describe("strict.yaml fixture validation", () => { diff --git a/src/config/__tests__/policy-yaml-parser.test.ts b/src/config/__tests__/policy-yaml-parser.test.ts index ab1d659..5854122 100644 --- a/src/config/__tests__/policy-yaml-parser.test.ts +++ b/src/config/__tests__/policy-yaml-parser.test.ts @@ -258,6 +258,35 @@ describe("policy YAML parser", () => { expect(() => parseYamlPolicy("version: ctg/v1\npolicy_id: 42")).toThrow(/policy_id must be a string/); }); + it.each([ + ["empty version", 'version: ""\npolicy_id: policy', /version must not be empty/], + ["blank policy id", 'version: ctg/v1\npolicy_id: " "', /policy_id must not be empty/], + ["negative expiry warning", "suppression: { expiry_warning_days: -1 }", /suppression\.expiry_warning_days must be a non-negative integer/], + ["fractional suppression limit", "suppression: { max_suppressions_per_rule: 1.5 }", /suppression\.max_suppressions_per_rule must be a non-negative integer/], + ["negative unsupported claims", "llm: { unsupported_claims_max: -2 }", /llm\.unsupported_claims_max must be a non-negative integer/], + ["NaN suppression limit", "suppression: { max_suppressions_per_rule: .nan }", /suppression\.max_suppressions_per_rule must be a number/], + ["infinite unsupported claims", "llm: { unsupported_claims_max: .inf }", /llm\.unsupported_claims_max must be a number/], + ])("rejects explicitly invalid schema-bound value: %s", (_label, content, error) => { + expect(() => parseYamlPolicy(content)).toThrow(error); + }); + + it("preserves valid zero boundaries while rejecting invalid fraction boundaries", () => { + const parsed = parseYamlPolicy([ + "version: ctg/v1", + "policy_id: boundary-policy", + "confidence: { min_confidence: 0, low_confidence_threshold: 1 }", + "suppression: { expiry_warning_days: 0, max_suppressions_per_rule: 0 }", + "llm: { min_confidence: 0, unsupported_claims_max: 0 }", + "partial: { partial_warning_threshold: 1 }", + ].join("\n")); + expect(parsed.confidence).toMatchObject({ minConfidence: 0, lowConfidenceThreshold: 1 }); + expect(parsed.suppression).toEqual({ expiryWarningDays: 0, maxSuppressionsPerRule: 0 }); + expect(parsed.llm).toMatchObject({ minConfidence: 0, unsupportedClaimsMax: 0 }); + expect(parsed.partial?.partialWarningThreshold).toBe(1); + expect(() => parseYamlPolicy("confidence: { min_confidence: -0.1 }")).toThrow(/confidence\.min_confidence must be between 0 and 1/); + expect(() => parseYamlPolicy("partial: { partial_warning_threshold: 1.1 }")).toThrow(/partial\.partial_warning_threshold must be between 0 and 1/); + }); + it("parses suppression entries, inline fields, classes, and defaults", () => { const suppression = parseSuppressionFile([ "version: ctg.policy/v1", @@ -284,4 +313,22 @@ describe("policy YAML parser", () => { expect(parseSuppressionFile("- rule_id: ONLY_ID").suppressions).toEqual([]); expect(parseSuppressionFile(["-", " not-a-field"].join("\n")).suppressions).toEqual([]); }); + + it("uses YAML scalar rules for flow entries, quoted keys, and escaped values", () => { + const suppression = parseSuppressionFile( + '"version": "ctg/v1" # schema\n"suppressions": [{ "rule_id": \'RULE_ONE\', "path": \'src/#.ts\', "reason": "Keep \\"quoted\\" # debt", "expiry": "2027-01-01" }] # entry' + ); + + expect(suppression).toEqual({ + version: "ctg/v1", + suppressions: [{ + ruleId: "RULE_ONE", + path: "src/#.ts", + reason: 'Keep "quoted" # debt', + expiry: "2027-01-01", + author: undefined, + class: "temporary-debt", + }], + }); + }); }); diff --git a/src/config/policy-evaluator.ts b/src/config/policy-evaluator.ts index 914b234..fe34878 100644 --- a/src/config/policy-evaluator.ts +++ b/src/config/policy-evaluator.ts @@ -376,7 +376,7 @@ export function evaluatePolicy( } // Check confidence threshold - if (finding.confidence < policy.confidence.minConfidence) { + if (policy.confidence.filterLow !== false && finding.confidence < policy.confidence.minConfidence) { lowConfidenceFindings.push(finding); failedConditions.push({ type: "low_confidence", diff --git a/src/config/policy-loader.ts b/src/config/policy-loader.ts index 76154cc..416f833 100644 --- a/src/config/policy-loader.ts +++ b/src/config/policy-loader.ts @@ -21,6 +21,29 @@ import { } from "./policy-types.js"; import { parseYamlPolicy, mergeWithDefaults, parseSuppressionFile } from "./policy-yaml-parser.js"; +const SUPPRESSION_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/; + +function parseSuppressionExpiry(value: string): Date | undefined { + if (!SUPPRESSION_DATE_PATTERN.test(value)) { + return undefined; + } + + const [year, month, day] = value.split("-").map(Number); + const parsed = new Date(0); + parsed.setUTCHours(0, 0, 0, 0); + parsed.setUTCFullYear(year, month - 1, day); + + if ( + parsed.getUTCFullYear() !== year || + parsed.getUTCMonth() !== month - 1 || + parsed.getUTCDate() !== day + ) { + return undefined; + } + + return parsed; +} + // Re-export types and constants export { POLICY_VERSION, @@ -263,7 +286,10 @@ export function isSuppressed( } if (suppression.expiry) { - const expiryDate = new Date(suppression.expiry); + const expiryDate = parseSuppressionExpiry(suppression.expiry); + if (!expiryDate) { + continue; + } const now = new Date(); if (now > expiryDate) { continue; @@ -288,7 +314,7 @@ export interface SuppressionExpiryWarning { path: string; ruleId: string; expiry: string; - status: "expired" | "expiring_soon"; + status: "expired" | "expiring_soon" | "invalid"; daysUntilExpiry?: number; } @@ -308,10 +334,20 @@ export function checkSuppressionExpiry( continue; } - const expiryDate = new Date(suppression.expiry); + const expiryDate = parseSuppressionExpiry(suppression.expiry); + if (!expiryDate) { + warnings.push({ + path: suppression.path, + ruleId: suppression.ruleId, + expiry: suppression.expiry, + status: "invalid", + }); + continue; + } + const daysUntilExpiry = Math.ceil((expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); - if (daysUntilExpiry < 0) { + if (now > expiryDate) { warnings.push({ path: suppression.path, ruleId: suppression.ruleId, diff --git a/src/config/policy-types.ts b/src/config/policy-types.ts index c4d0c7c..677ec97 100644 --- a/src/config/policy-types.ts +++ b/src/config/policy-types.ts @@ -131,6 +131,7 @@ export interface LlmPolicyConfig { */ export interface PartialConfig { allowPartial?: boolean; + /** Reserved in v1: validated as 0..1; does not alter completeness or warnings. */ partialWarningThreshold?: number; } diff --git a/src/config/policy-yaml-parser.ts b/src/config/policy-yaml-parser.ts index d22608d..e0ad8d0 100644 --- a/src/config/policy-yaml-parser.ts +++ b/src/config/policy-yaml-parser.ts @@ -14,7 +14,6 @@ import { DEFAULT_SUPPRESSION_CLASS, type CtgPolicy, type SuppressionFile, - type SuppressionEntry, type SuppressionClass, type PolicyDslConfig, type PolicyDslRule, @@ -25,26 +24,40 @@ import { } from "./policy-types.js"; import type { RuleOptionsConfig } from "../types/rule-options.js"; -function splitYamlKeyValue(line: string): [string, string] | undefined { - const separatorIndex = line.indexOf(":"); - if (separatorIndex < 0) { +function asRecord(value: unknown): Record | undefined { + return typeof value === "object" && value !== null && !Array.isArray(value) + ? value as Record + : undefined; +} + +function legacyRootSuppressionDocument(content: string): string | undefined { + const lines = content.split(/\r?\n/); + const listIndex = lines.findIndex((line) => /^-\s*/.test(line)); + if (listIndex < 0 || !lines.slice(0, listIndex).some((line) => /^\s*version\s*:/.test(line))) { return undefined; } return [ - line.slice(0, separatorIndex).trim(), - line.slice(separatorIndex + 1).trim(), - ]; + ...lines.slice(0, listIndex), + "suppressions:", + ...lines.slice(listIndex).map((line) => line.trim() ? ` ${line}` : line), + ].join("\n"); } -function unquoteYamlScalar(value: string | undefined): string { - return (value ?? "").replace(/^["']|["']$/g, ""); -} - -function asRecord(value: unknown): Record | undefined { - return typeof value === "object" && value !== null && !Array.isArray(value) - ? value as Record - : undefined; +function loadSuppressionYaml(content: string): unknown { + try { + return yaml.load(content, { schema: yaml.JSON_SCHEMA }); + } catch (error) { + const legacyContent = legacyRootSuppressionDocument(content); + if (legacyContent === undefined) { + throw error; + } + try { + return yaml.load(legacyContent, { schema: yaml.JSON_SCHEMA }); + } catch { + throw error; + } + } } function scalarString(value: unknown): string | undefined { @@ -58,6 +71,26 @@ function numericValue(value: unknown): number | undefined { return typeof value === "number" ? value : Number.NaN; } +function nonNegativeInteger(value: unknown, label: string): number { + if (typeof value !== "number" || !Number.isFinite(value)) { + throw new Error(`${label} must be a number`); + } + if (!Number.isInteger(value) || value < 0) { + throw new Error(`${label} must be a non-negative integer`); + } + return value; +} + +function fraction(value: unknown, label: string): number { + if (typeof value !== "number" || !Number.isFinite(value)) { + throw new Error(`${label} must be a number`); + } + if (value < 0 || value > 1) { + throw new Error(`${label} must be between 0 and 1`); + } + return value; +} + function parseRuleOptions(content: string): RuleOptionsConfig | undefined { let parsed: unknown; try { @@ -186,10 +219,10 @@ function parsePartialSection(root: Record | undefined): CtgPoli partial.allowPartial = raw.allow_partial; } if (Object.prototype.hasOwnProperty.call(raw, "partial_warning_threshold")) { - if (typeof raw.partial_warning_threshold !== "number") { - throw new Error("partial.partial_warning_threshold must be a number"); + if (typeof raw.partial_warning_threshold !== "number" || !Number.isFinite(raw.partial_warning_threshold)) { + throw new Error("partial_warning_threshold must be a number"); } - partial.partialWarningThreshold = raw.partial_warning_threshold; + partial.partialWarningThreshold = fraction(raw.partial_warning_threshold, "partial.partial_warning_threshold"); } return partial; } @@ -216,6 +249,7 @@ export function parseYamlPolicy(content: string): Partial { const stringValue = (object: Record, key: string, label: string): string | undefined => { if (!has(object, key)) return undefined; if (typeof object[key] !== "string") throw new Error(`${label} must be a string`); + if (!(object[key] as string).trim()) throw new Error(`${label} must not be empty`); return object[key] as string; }; const booleanValue = (object: Record, key: string, label: string): boolean | undefined => { @@ -223,10 +257,13 @@ export function parseYamlPolicy(content: string): Partial { if (typeof object[key] !== "boolean") throw new Error(`${label} must be a boolean`); return object[key] as boolean; }; - const numberValue = (object: Record, key: string, label: string): number | undefined => { + const fractionValue = (object: Record, key: string, label: string): number | undefined => { if (!has(object, key)) return undefined; - if (typeof object[key] !== "number") throw new Error(`${label} must be a number`); - return object[key] as number; + return fraction(object[key], label); + }; + const nonNegativeIntegerValue = (object: Record, key: string, label: string): number | undefined => { + if (!has(object, key)) return undefined; + return nonNegativeInteger(object[key], label); }; result.version = stringValue(documentRoot, "version", "version"); @@ -266,7 +303,7 @@ export function parseYamlPolicy(content: string): Partial { for (const [yamlKey, property] of [ ["critical_max", "criticalMax"], ["high_max", "highMax"], ["medium_max", "mediumMax"], ["low_max", "lowMax"], ] as const) { - const value = numberValue(countThreshold, yamlKey, `blocking count threshold ${yamlKey}`); + const value = nonNegativeIntegerValue(countThreshold, yamlKey, `blocking count threshold ${yamlKey}`); if (value !== undefined) parsedBlocking.countThreshold[property] = value; } } @@ -276,8 +313,8 @@ export function parseYamlPolicy(content: string): Partial { const confidence = section(documentRoot, "confidence"); if (confidence) { result.confidence = { ...DEFAULT_CONFIDENCE }; - const min = numberValue(confidence, "min_confidence", "confidence.min_confidence"); - const low = numberValue(confidence, "low_confidence_threshold", "confidence.low_confidence_threshold"); + const min = fractionValue(confidence, "min_confidence", "confidence.min_confidence"); + const low = fractionValue(confidence, "low_confidence_threshold", "confidence.low_confidence_threshold"); const filter = booleanValue(confidence, "filter_low", "confidence.filter_low"); if (min !== undefined) result.confidence.minConfidence = min; if (low !== undefined) result.confidence.lowConfidenceThreshold = low; @@ -288,8 +325,8 @@ export function parseYamlPolicy(content: string): Partial { if (suppression) { result.suppression = {}; const file = stringValue(suppression, "file", "suppression.file"); - const expiry = numberValue(suppression, "expiry_warning_days", "suppression.expiry_warning_days"); - const max = numberValue(suppression, "max_suppressions_per_rule", "suppression.max_suppressions_per_rule"); + const expiry = nonNegativeIntegerValue(suppression, "expiry_warning_days", "suppression.expiry_warning_days"); + const max = nonNegativeIntegerValue(suppression, "max_suppressions_per_rule", "suppression.max_suppressions_per_rule"); if (file !== undefined) result.suppression.file = file; if (expiry !== undefined) result.suppression.expiryWarningDays = expiry; if (max !== undefined) result.suppression.maxSuppressionsPerRule = max; @@ -300,9 +337,9 @@ export function parseYamlPolicy(content: string): Partial { result.llm = {}; const enabled = booleanValue(llm, "enabled", "llm.enabled"); const mode = stringValue(llm, "mode", "llm.mode"); - const min = numberValue(llm, "min_confidence", "llm.min_confidence"); + const min = fractionValue(llm, "min_confidence", "llm.min_confidence"); const requireLlm = booleanValue(llm, "require_llm", "llm.require_llm"); - const unsupported = numberValue(llm, "unsupported_claims_max", "llm.unsupported_claims_max"); + const unsupported = nonNegativeIntegerValue(llm, "unsupported_claims_max", "llm.unsupported_claims_max"); if (enabled !== undefined) result.llm.enabled = enabled; if (mode !== undefined) { if (!["remote", "local-only", "none"].includes(mode)) throw new Error(`llm.mode is invalid: ${mode}`); @@ -390,93 +427,88 @@ export function parseSuppressionFile(content: string): SuppressionFile { suppressions: [], }; - const lines = content.split("\n"); - let currentSuppression: Partial | null = null; + let parsed: unknown; + try { + parsed = loadSuppressionYaml(content); + } catch (error) { + throw new Error( + `Invalid suppression YAML: ${error instanceof Error ? error.message : String(error)}`, + { cause: error } + ); + } - for (const line of lines) { - const trimmed = line.trim(); + // A bare root list was accepted by the old line parser as an omitted + // suppressions section. Keep that compatibility while valid files use an + // object root with an array-valued suppressions field. + if (Array.isArray(parsed)) { + return result; + } + if (parsed === null || (parsed !== undefined && !asRecord(parsed))) { + throw new Error("suppression root must be an object"); + } - if (!trimmed || trimmed.startsWith("#")) { - continue; + const root = asRecord(parsed) ?? {}; + const version = root.version; + if (version !== undefined && typeof version !== "string") { + throw new Error("suppression.version must be a string"); + } + if (typeof version === "string" && version.trim()) { + result.version = version; + } + + const rawSuppressions = root.suppressions; + if (rawSuppressions === undefined || rawSuppressions === null) { + return result; + } + if (!Array.isArray(rawSuppressions)) { + throw new Error("suppressions must be an array"); + } + + const validClasses: SuppressionClass[] = [ + "self-reference", + "fixture-intentional", + "generated-artifact", + "accepted-design", + "temporary-debt", + ]; + const readOptionalString = (entry: Record, key: string, index: number): string | undefined => { + const value = entry[key]; + if (value === undefined || value === null) { + return undefined; + } + if (typeof value !== "string") { + throw new Error(`suppressions[${index}].${key} must be a string`); } + return value; + }; - if (trimmed.startsWith("-")) { - if (currentSuppression && currentSuppression.ruleId && currentSuppression.path) { - result.suppressions.push({ - ruleId: currentSuppression.ruleId, - path: currentSuppression.path, - reason: currentSuppression.reason || "", - expiry: currentSuppression.expiry, - author: currentSuppression.author, - class: currentSuppression.class || DEFAULT_SUPPRESSION_CLASS, - }); - } - currentSuppression = {}; - - // Handle case where first field is on same line as dash - // e.g., "- rule_id: CLIENT_TRUSTED_PRICE" - const afterDash = trimmed.substring(1).trim(); - const inlineField = splitYamlKeyValue(afterDash); - if (inlineField) { - const [key, value] = inlineField; - if (key === "rule_id") { - currentSuppression.ruleId = unquoteYamlScalar(value); - } else if (key === "path") { - currentSuppression.path = unquoteYamlScalar(value); - } - } + for (const [index, rawEntry] of rawSuppressions.entries()) { + // Keep the legacy behavior that incomplete/null list items are ignored. + const entry = asRecord(rawEntry); + if (!entry) { continue; } - if (trimmed.includes(":") && currentSuppression) { - const field = splitYamlKeyValue(trimmed); - if (!field) { - continue; - } - const [key, value] = field; - - if (key === "rule_id") { - currentSuppression.ruleId = unquoteYamlScalar(value); - } else if (key === "path") { - currentSuppression.path = unquoteYamlScalar(value); - } else if (key === "reason") { - currentSuppression.reason = unquoteYamlScalar(value); - } else if (key === "expiry") { - currentSuppression.expiry = unquoteYamlScalar(value); - } else if (key === "author") { - currentSuppression.author = unquoteYamlScalar(value); - } else if (key === "class") { - // Parse class field, validate against allowed values - const classValue = unquoteYamlScalar(value) as SuppressionClass; - const validClasses: SuppressionClass[] = [ - "self-reference", - "fixture-intentional", - "generated-artifact", - "accepted-design", - "temporary-debt", - ]; - if (validClasses.includes(classValue)) { - currentSuppression.class = classValue; - } else { - // Invalid class defaults to temporary-debt - currentSuppression.class = DEFAULT_SUPPRESSION_CLASS; - } - } + const ruleId = readOptionalString(entry, "rule_id", index); + const pathValue = readOptionalString(entry, "path", index); + if (!ruleId || !pathValue) { + continue; } - if (trimmed.startsWith("version:")) { - result.version = trimmed.split(":")[1]?.trim() || POLICY_VERSION; - } - } + const reason = readOptionalString(entry, "reason", index) ?? ""; + const expiry = readOptionalString(entry, "expiry", index); + const author = readOptionalString(entry, "author", index); + const classValue = readOptionalString(entry, "class", index) as SuppressionClass | undefined; - if (currentSuppression && currentSuppression.ruleId && currentSuppression.path) { result.suppressions.push({ - ruleId: currentSuppression.ruleId, - path: currentSuppression.path, - reason: currentSuppression.reason || "", - expiry: currentSuppression.expiry, - author: currentSuppression.author, - class: currentSuppression.class || DEFAULT_SUPPRESSION_CLASS, + ruleId, + path: pathValue, + reason, + expiry, + author, + class: classValue && validClasses.includes(classValue) + ? classValue + : DEFAULT_SUPPRESSION_CLASS, }); } diff --git a/src/historical/__tests__/ratchet-gate.test.ts b/src/historical/__tests__/ratchet-gate.test.ts new file mode 100644 index 0000000..b38ebda --- /dev/null +++ b/src/historical/__tests__/ratchet-gate.test.ts @@ -0,0 +1,82 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { tmpdir } from "node:os"; + +import { createMockFindingsArtifact } from "../../test-utils/index.js"; +import { loadBaselineFindingsArtifact } from "../ratchet-gate.js"; + +describe("ratchet baseline artifact loading", () => { + let tempDir: string; + + beforeEach(() => { + tempDir = mkdtempSync(path.join(tmpdir(), "ctg-ratchet-gate-test-")); + }); + + afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }); + }); + + function writeFindings(filePath: string, runId: string): void { + mkdirSync(path.dirname(filePath), { recursive: true }); + writeFileSync( + filePath, + JSON.stringify(createMockFindingsArtifact({ run_id: runId, findings: [] }), null, 2), + "utf8" + ); + } + + function writeReadiness(filePath: string, findingsRef?: string): void { + mkdirSync(path.dirname(filePath), { recursive: true }); + writeFileSync( + filePath, + JSON.stringify({ + artifact: "release-readiness", + artifactRefs: findingsRef === undefined ? {} : { findings: findingsRef }, + }), + "utf8" + ); + } + + it("honors an explicit readiness findings reference before a sibling findings file", () => { + const reportDir = path.join(tempDir, "report"); + const readinessPath = path.join(reportDir, "release-readiness.json"); + const siblingPath = path.join(reportDir, "findings.json"); + const intendedPath = path.join(tempDir, "intended", "findings.json"); + + writeFindings(siblingPath, "unrelated-sibling"); + writeFindings(intendedPath, "intended"); + writeReadiness(readinessPath, "../intended/findings.json"); + + const loaded = loadBaselineFindingsArtifact(readinessPath, tempDir); + + expect(loaded.source).toBe(path.resolve(intendedPath)); + expect(loaded.artifact.run_id).toBe("intended"); + }); + + it("does not substitute a sibling when an explicit readiness findings reference is missing", () => { + const reportDir = path.join(tempDir, "report"); + const readinessPath = path.join(reportDir, "release-readiness.json"); + + writeFindings(path.join(reportDir, "findings.json"), "unrelated-sibling"); + writeReadiness(readinessPath, "../missing/findings.json"); + + expect(() => loadBaselineFindingsArtifact(readinessPath, tempDir)).toThrow( + /explicit artifactRefs\.findings/ + ); + }); + + it("keeps sibling fallback when readiness has no explicit findings reference", () => { + const reportDir = path.join(tempDir, "report"); + const readinessPath = path.join(reportDir, "release-readiness.json"); + const siblingPath = path.join(reportDir, "findings.json"); + + writeFindings(siblingPath, "sibling-without-explicit-ref"); + writeReadiness(readinessPath); + + const loaded = loadBaselineFindingsArtifact(readinessPath, tempDir); + + expect(loaded.source).toBe(path.resolve(siblingPath)); + expect(loaded.artifact.run_id).toBe("sibling-without-explicit-ref"); + }); +}); diff --git a/src/historical/ratchet-gate.ts b/src/historical/ratchet-gate.ts index 06ee874..43603b1 100644 --- a/src/historical/ratchet-gate.ts +++ b/src/historical/ratchet-gate.ts @@ -79,16 +79,23 @@ function candidateFindingsFromReadiness( cwd: string ): string[] { const dir = path.dirname(readinessPath); - const candidates = [path.join(dir, "findings.json")]; const ref = readiness.artifactRefs?.findings; - if (ref) { - candidates.push(path.isAbsolute(ref) ? ref : path.resolve(cwd, ref)); - candidates.push(path.resolve(dir, ref)); - candidates.push(path.join(dir, path.basename(ref))); + // An explicit findings reference is authoritative. Keep the historical + // cwd-relative and readiness-relative interpretations for compatibility, + // but never fall back to a sibling file when the reference is present. + if (ref !== undefined) { + if (typeof ref !== "string" || !ref.trim()) { + return []; + } + + return [ + path.isAbsolute(ref) ? ref : path.resolve(cwd, ref), + path.resolve(dir, ref), + ].filter((candidate, index, candidates) => candidates.indexOf(candidate) === index); } - return [...new Set(candidates)]; + return [path.join(dir, "findings.json")]; } function loadReadinessLinkedFindings(filePath: string, cwd: string): LoadedBaselineFindings | undefined { @@ -112,6 +119,12 @@ function loadReadinessLinkedFindings(filePath: string, cwd: string): LoadedBasel } } + if (parsed.artifactRefs?.findings !== undefined) { + throw new Error( + `explicit artifactRefs.findings not found: ${String(parsed.artifactRefs.findings)}` + ); + } + return undefined; } @@ -122,17 +135,27 @@ export function loadBaselineFindingsArtifact(inputPath: string, cwd: string): Lo } if (statSync(absolutePath).isDirectory()) { - const candidates = [ - path.join(absolutePath, "findings.json"), - path.join(absolutePath, "baseline-findings.json"), + // Readiness artifacts can point at the authoritative baseline findings. + // Resolve those references before considering directory-level siblings so + // an unrelated findings.json cannot silently replace an explicit ref. + const readinessCandidates = [ path.join(absolutePath, "release-readiness.json"), path.join(absolutePath, "baseline-release-readiness.json"), ]; - for (const candidate of candidates) { - const loaded = candidate.endsWith("readiness.json") - ? loadReadinessLinkedFindings(candidate, cwd) - : loadFindingsFile(candidate); + for (const candidate of readinessCandidates) { + const loaded = loadReadinessLinkedFindings(candidate, cwd); + if (loaded) { + return loaded; + } + } + + const directCandidates = [ + path.join(absolutePath, "findings.json"), + path.join(absolutePath, "baseline-findings.json"), + ]; + for (const candidate of directCandidates) { + const loaded = loadFindingsFile(candidate); if (loaded) { return loaded; } diff --git a/src/suppression/__tests__/suppression-loader.test.ts b/src/suppression/__tests__/suppression-loader.test.ts index 149a08b..e4ebdb0 100644 --- a/src/suppression/__tests__/suppression-loader.test.ts +++ b/src/suppression/__tests__/suppression-loader.test.ts @@ -90,6 +90,27 @@ suppressions: expect(result.suppressions[0].path).toBe("src/**/*.ts"); }); + it("strips trailing comments from suppression scalar values", () => { + const yaml = ` +version: ctg/v1 # schema +suppressions: + - rule_id: DEBT_MARKER # rule + path: "src/**/*.ts" # source path + reason: "Accepted debt" # rationale + expiry: "2099-12-31" # review date +`; + + const result = parseSuppressionYaml(yaml); + + expect(result.suppressions).toEqual([{ + rule_id: "DEBT_MARKER", + path: "src/**/*.ts", + reason: "Accepted debt", + expiry: "2099-12-31", + author: undefined, + }]); + }); + it("handles suppressions without optional fields", () => { const yaml = ` suppressions: @@ -287,7 +308,7 @@ suppressions: expect(result.suppressions).toHaveLength(1); }); - it("handles malformed YAML gracefully", () => { + it("rejects malformed YAML instead of partially applying earlier entries", () => { const yaml = ` suppressions: - rule_id: GOOD_RULE @@ -296,9 +317,24 @@ suppressions: - invalid entry without dash something: value `; - const result = parseSuppressionYaml(yaml); - // Should still parse the good entry - expect(result.suppressions.length).toBeGreaterThanOrEqual(1); + + expect(() => parseSuppressionYaml(yaml)).toThrow(/Invalid suppression YAML/); + }); + + it("rejects a valid suppression followed by a malformed expiry", () => { + const yaml = ` +suppressions: + - rule_id: GOOD_RULE + path: good/*.ts + reason: good + expiry: 2099-12-31 + - rule_id: BROKEN_RULE + path: broken/*.ts + reason: broken + expiry: "2099-12-31 +`; + + expect(() => parseSuppressionYaml(yaml)).toThrow(/Invalid suppression YAML/); }); it("handles very long paths", () => { @@ -324,4 +360,4 @@ suppressions: expect(result.suppressions[0].path).toBe("src/[test]/**/*.ts"); }); }); -}); \ No newline at end of file +}); diff --git a/src/suppression/__tests__/suppression-matcher.test.ts b/src/suppression/__tests__/suppression-matcher.test.ts index 962da47..38f07fb 100644 --- a/src/suppression/__tests__/suppression-matcher.test.ts +++ b/src/suppression/__tests__/suppression-matcher.test.ts @@ -89,6 +89,17 @@ describe("suppression-matcher", () => { expect(isExpired(dateStr)).toBe(false); }); + it("treats an invalid expiry as expired so it cannot keep a finding suppressed", () => { + const suppression = createSuppression("RULE_INVALID", "src/*.ts", { + expiry: "not-a-date", + }); + const finding = createFinding("f-invalid-expiry", "RULE_INVALID", "src/api.ts"); + + expect(isExpired(suppression.expiry, new Date("2026-06-30T00:00:00.000Z"))).toBe(true); + expect(matchSuppression(finding, [suppression]).status).toBe("expired"); + expect(isSuppressed(finding, [suppression])).toBe(false); + }); + it("accepts custom current date parameter", () => { const expiryDate = "2026-06-30"; const currentDate = new Date("2026-07-01"); @@ -624,4 +635,4 @@ describe("suppression-matcher", () => { expect(DEFAULT_EXPIRY_WARNING_DAYS).toBe(30); }); }); -}); \ No newline at end of file +}); diff --git a/src/suppression/__tests__/suppression-validator.test.ts b/src/suppression/__tests__/suppression-validator.test.ts index af60d52..b16b19a 100644 --- a/src/suppression/__tests__/suppression-validator.test.ts +++ b/src/suppression/__tests__/suppression-validator.test.ts @@ -358,6 +358,22 @@ describe("suppression-validator", () => { expect(result.valid).toBe(false); }); + it("rejects a date-only value that JavaScript would normalize", () => { + const suppression = createValidSuppression({ + expiry: "2026-02-30", + }); + + const result = validateSuppression(suppression, 0); + expect(result.valid).toBe(false); + expect(result.errors).toContainEqual( + expect.objectContaining({ + type: "field", + field: "expiry", + message: "Invalid date value", + }) + ); + }); + it("warns for expired date", () => { const suppression = createValidSuppression({ expiry: getPastDate(), @@ -540,4 +556,4 @@ function getPastDate(): string { const pastDate = new Date(); pastDate.setDate(pastDate.getDate() - 1); return pastDate.toISOString().split("T")[0]; -} \ No newline at end of file +} diff --git a/src/suppression/suppression-loader.ts b/src/suppression/suppression-loader.ts index cd957a5..d93424e 100644 --- a/src/suppression/suppression-loader.ts +++ b/src/suppression/suppression-loader.ts @@ -5,7 +5,7 @@ import { existsSync, readFileSync } from "node:fs"; import path from "node:path"; -import { parseSimpleYaml } from "../core/config-utils.js"; +import yaml from "js-yaml"; import { CTG_VERSION } from "../types/artifacts.js"; /** @@ -34,114 +34,85 @@ export interface SuppressionFile { suppressions: Suppression[]; } +function asRecord(value: unknown): Record | undefined { + return typeof value === "object" && value !== null && !Array.isArray(value) + ? value as Record + : undefined; +} + /** * Parse suppression YAML content * @param content - YAML content string * @returns Parsed suppression file object */ export function parseSuppressionYaml(content: string): SuppressionFile { - const baseResult = parseSimpleYaml(content); - - // Parse suppressions list from YAML - const suppressions: Suppression[] = []; - const lines = content.split("\n"); + let parsed: unknown; + try { + parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA }); + } catch (error) { + throw new Error( + `Invalid suppression YAML: ${error instanceof Error ? error.message : String(error)}`, + { cause: error } + ); + } - let currentSuppression: Partial | null = null; - let inSuppressionsBlock = false; + if (Array.isArray(parsed)) { + return { version: CTG_VERSION, suppressions: [] }; + } + if (parsed === null || (parsed !== undefined && !asRecord(parsed))) { + throw new Error("suppression root must be an object"); + } - for (const line of lines) { - const trimmed = line.trim(); + const root = asRecord(parsed) ?? {}; + if (root.version !== undefined && typeof root.version !== "string") { + throw new Error("suppression.version must be a string"); + } + const rawSuppressions = root.suppressions; + if (rawSuppressions === undefined || rawSuppressions === null) { + return { + version: typeof root.version === "string" && root.version.trim() ? root.version : CTG_VERSION, + suppressions: [], + }; + } + if (!Array.isArray(rawSuppressions)) { + throw new Error("suppressions must be an array"); + } - // Skip empty lines and comments - if (!trimmed || trimmed.startsWith("#")) { - continue; + const readOptionalString = (entry: Record, key: string, index: number): string | undefined => { + const value = entry[key]; + if (value === undefined || value === null) { + return undefined; } - - // Detect suppressions block start - if (trimmed === "suppressions:") { - inSuppressionsBlock = true; - continue; + if (typeof value !== "string") { + throw new Error(`suppressions[${index}].${key} must be a string`); } + return value; + }; - // Exit suppressions block on new top-level key (line without leading space or dash) - if (inSuppressionsBlock && !line.startsWith(" ") && !line.startsWith("-") && trimmed.includes(":")) { - inSuppressionsBlock = false; - // Save current suppression before exiting - if (currentSuppression && currentSuppression.rule_id && currentSuppression.path) { - suppressions.push({ - rule_id: currentSuppression.rule_id, - path: currentSuppression.path, - reason: currentSuppression.reason ?? "", - expiry: currentSuppression.expiry, - author: currentSuppression.author, - }); - } - currentSuppression = null; + const suppressions: Suppression[] = []; + for (const [index, rawEntry] of rawSuppressions.entries()) { + const entry = asRecord(rawEntry); + if (!entry) { continue; } - if (inSuppressionsBlock) { - // Start new suppression entry (line starting with -) - if (trimmed.startsWith("-")) { - // Save previous suppression if complete - if (currentSuppression && currentSuppression.rule_id && currentSuppression.path) { - suppressions.push({ - rule_id: currentSuppression.rule_id, - path: currentSuppression.path, - reason: currentSuppression.reason ?? "", - expiry: currentSuppression.expiry, - author: currentSuppression.author, - }); - } - currentSuppression = {}; - - // Handle case where first field is on same line as dash - // e.g., "- rule_id: CLIENT_TRUSTED_PRICE" - const afterDash = trimmed.substring(1).trim(); - if (afterDash.startsWith("rule_id:")) { - currentSuppression.rule_id = afterDash.split(":")[1]?.trim() ?? ""; - } - continue; - } - - // Parse suppression fields (indented under the dash line) - if (currentSuppression !== null) { - if (trimmed.startsWith("rule_id:")) { - currentSuppression.rule_id = trimmed.split(":")[1]?.trim() ?? ""; - } else if (trimmed.startsWith("path:")) { - // Handle quoted paths - const pathValue = trimmed.substring(5).trim(); - // Remove quotes if present - currentSuppression.path = pathValue.replace(/^["']|["']$/g, ""); - } else if (trimmed.startsWith("reason:")) { - // Handle quoted reasons - const reasonValue = trimmed.substring(7).trim(); - currentSuppression.reason = reasonValue.replace(/^["']|["']$/g, ""); - } else if (trimmed.startsWith("expiry:")) { - const expiryValue = trimmed.substring(7).trim(); - // Remove quotes if present - currentSuppression.expiry = expiryValue.replace(/^["']|["']$/g, ""); - } else if (trimmed.startsWith("author:")) { - const authorValue = trimmed.substring(7).trim(); - currentSuppression.author = authorValue.replace(/^["']|["']$/g, ""); - } - } + const ruleId = readOptionalString(entry, "rule_id", index); + const pathValue = readOptionalString(entry, "path", index); + if (!ruleId || !pathValue) { + continue; } - } - // Save last suppression if complete - if (currentSuppression && currentSuppression.rule_id && currentSuppression.path) { suppressions.push({ - rule_id: currentSuppression.rule_id, - path: currentSuppression.path, - reason: currentSuppression.reason ?? "", - expiry: currentSuppression.expiry, - author: currentSuppression.author, + rule_id: ruleId, + path: pathValue, + reason: readOptionalString(entry, "reason", index) ?? "", + expiry: readOptionalString(entry, "expiry", index), + author: readOptionalString(entry, "author", index), }); } return { - version: baseResult.version ?? CTG_VERSION, + version: typeof root.version === "string" && root.version.trim() ? root.version : CTG_VERSION, suppressions, }; } @@ -186,4 +157,4 @@ export function getSuppressionFilePath( ): string { const filePath = suppressionPath ?? DEFAULT_SUPPRESSION_FILE; return path.resolve(repoRoot, filePath); -} \ No newline at end of file +} diff --git a/src/suppression/suppression-matcher.ts b/src/suppression/suppression-matcher.ts index fb580a7..93efad9 100644 --- a/src/suppression/suppression-matcher.ts +++ b/src/suppression/suppression-matcher.ts @@ -33,6 +33,30 @@ export interface SuppressionMatchResult { */ export const DEFAULT_EXPIRY_WARNING_DAYS = 30; +function parseExpiryDate(value: string): Date | undefined { + const match = /^(\d{4})-(\d{2})-(\d{2})(?:T.*)?$/.exec(value); + if (!match) { + return undefined; + } + + const year = Number(match[1]); + const month = Number(match[2]); + const day = Number(match[3]); + const datePart = new Date(0); + datePart.setUTCHours(0, 0, 0, 0); + datePart.setUTCFullYear(year, month - 1, day); + if ( + datePart.getUTCFullYear() !== year || + datePart.getUTCMonth() !== month - 1 || + datePart.getUTCDate() !== day + ) { + return undefined; + } + + const parsed = new Date(value); + return Number.isNaN(parsed.getTime()) ? undefined : parsed; +} + /** * Check if a date string has expired * @param expiryDate - ISO date string (YYYY-MM-DD) @@ -45,8 +69,8 @@ export function isExpired( ): boolean { if (!expiryDate) return false; - const expiry = new Date(expiryDate); - return currentDate > expiry; + const expiry = parseExpiryDate(expiryDate); + return expiry === undefined || currentDate > expiry; } /** @@ -63,7 +87,8 @@ export function isApproachingExpiry( ): { expiring: boolean; daysRemaining?: number } { if (!expiryDate) return { expiring: false }; - const expiry = new Date(expiryDate); + const expiry = parseExpiryDate(expiryDate); + if (!expiry) return { expiring: false }; const warningThreshold = new Date(currentDate); warningThreshold.setDate(warningThreshold.getDate() + warningDays); @@ -262,4 +287,4 @@ export function buildSuppressionAuditRecords( } return records; -} \ No newline at end of file +} diff --git a/src/suppression/suppression-validator.ts b/src/suppression/suppression-validator.ts index f43ad5e..811a0aa 100644 --- a/src/suppression/suppression-validator.ts +++ b/src/suppression/suppression-validator.ts @@ -211,6 +211,31 @@ function validateExpiryDate(expiryDate: string): { }; } + const dateParts = /^(\d{4})-(\d{2})-(\d{2})/.exec(expiryDate); + if (!dateParts) { + return { + valid: false, + message: "Invalid date value", + }; + } + + const year = Number(dateParts[1]); + const month = Number(dateParts[2]); + const day = Number(dateParts[3]); + const dateOnly = new Date(0); + dateOnly.setUTCHours(0, 0, 0, 0); + dateOnly.setUTCFullYear(year, month - 1, day); + if ( + dateOnly.getUTCFullYear() !== year || + dateOnly.getUTCMonth() !== month - 1 || + dateOnly.getUTCDate() !== day + ) { + return { + valid: false, + message: "Invalid date value", + }; + } + // Parse and validate date const parsed = new Date(expiryDate); if (isNaN(parsed.getTime())) { @@ -257,4 +282,4 @@ export function checkMaxSuppressionsPerRule( } return exceeded; -} \ No newline at end of file +} diff --git a/src/viewer/__tests__/report-viewer.test.ts b/src/viewer/__tests__/report-viewer.test.ts index 18687f5..17a33e6 100644 --- a/src/viewer/__tests__/report-viewer.test.ts +++ b/src/viewer/__tests__/report-viewer.test.ts @@ -122,6 +122,58 @@ describe("report-viewer", () => { expect(html).toContain("/test/repo"); }); + it("uses the findings tool version in the escaped footer", () => { + const findings = createMockFindings({ + tool: { name: "code-to-gate", version: "1.6.0<&", plugin_versions: [] }, + }); + const html = generateReportHtml({ findings }); + + expect(html).toContain("Generated by code-to-gate v1.6.0<&"); + expect(html).not.toContain("Generated by code-to-gate v0.2.0"); + }); + + it("uses the readiness tool version when findings are absent", () => { + const readiness = createMockReadiness({ + tool: { name: "code-to-gate", version: "2.4.0<&", plugin_versions: [] }, + }); + const html = generateReportHtml({ readiness }, { showReadiness: true }); + + expect(html).toContain("Generated by code-to-gate v2.4.0<&"); + expect(html).not.toContain("Generated by code-to-gate v0.2.0"); + }); + + it("uses the graph tool version when findings and readiness are absent", () => { + const graph: NormalizedRepoGraph = { + version: "ctg/v1", + generated_at: "2026-09-11T00:00:00Z", + run_id: "graph-run", + repo: { root: "/repo" }, + tool: { name: "code-to-gate", version: "3.1.0<&", plugin_versions: [] }, + artifact: "normalized-repo-graph", + schema: "normalized-repo-graph@v1", + files: [], + modules: [], + symbols: [], + relations: [], + tests: [], + configs: [], + entrypoints: [], + diagnostics: [], + stats: { partial: false }, + }; + const html = generateReportHtml({ graph }, { showGraph: true }); + + expect(html).toContain("Generated by code-to-gate v3.1.0<&"); + expect(html).not.toContain("Generated by code-to-gate v0.2.0"); + }); + + it("marks the footer version as unknown when no artifact provides one", () => { + const html = generateReportHtml({}); + + expect(html).toContain("Generated by code-to-gate vunknown"); + expect(html).not.toContain("Generated by code-to-gate v0.2.0"); + }); + it("renders redaction summary when a profile is provided", () => { const profile = createRedactionProfile("regulated"); const summary = createRedactionSummary(profile); diff --git a/src/viewer/report-sections.ts b/src/viewer/report-sections.ts index 09a3033..54817f9 100644 --- a/src/viewer/report-sections.ts +++ b/src/viewer/report-sections.ts @@ -19,7 +19,7 @@ import type { HistoricalSummaryReport } from "../historical/types.js"; import type { QEGCodeToGateEvidence } from "../qeg/qeg-types.js"; import { GraphData, generateMermaidFlowchart } from "./graph-viewer.js"; -const VERSION = "0.2.0"; +const UNKNOWN_VERSION = "unknown"; /** * Escape HTML special characters @@ -47,6 +47,21 @@ export interface LoadedArtifacts { evidenceDag?: EvidenceDagArtifact; } +/** + * Resolve the producer version from whichever artifact backs this report. + * Findings are preferred when present, but graph/readiness-only reports must + * retain the version carried by their own artifact as well. + */ +export function resolveArtifactToolVersion(artifacts: LoadedArtifacts): string | undefined { + return artifacts.findings?.tool?.version + ?? artifacts.riskRegister?.tool?.version + ?? artifacts.testSeeds?.tool?.version + ?? artifacts.readiness?.tool?.version + ?? artifacts.graph?.tool?.version + ?? artifacts.historicalComparison?.tool?.version + ?? artifacts.evidenceDag?.tool?.version; +} + /** * Generate header section HTML */ @@ -60,7 +75,7 @@ export function generateHeader( const generatedAt = findings?.generated_at || new Date().toISOString(); const runId = findings?.run_id || "unknown"; const repoRoot = findings?.repo?.root || "unknown"; - const toolVersion = findings?.tool?.version || VERSION; + const toolVersion = resolveArtifactToolVersion(artifacts) ?? UNKNOWN_VERSION; return `
@@ -684,10 +699,10 @@ export function generateGraphSection( /** * Generate footer HTML */ -export function generateFooter(): string { +export function generateFooter(toolVersion = UNKNOWN_VERSION): string { return ` `; diff --git a/src/viewer/report-viewer.ts b/src/viewer/report-viewer.ts index f88d86f..19feb4a 100644 --- a/src/viewer/report-viewer.ts +++ b/src/viewer/report-viewer.ts @@ -27,11 +27,10 @@ import { generateHistoricalSection, generateQegSection, generateFooter, + resolveArtifactToolVersion, } from "./report-sections.js"; import { getReportJavaScript } from "./report-scripts.js"; -const VERSION = "0.2.0"; - // Re-export for external use export { LoadedArtifacts, escapeHtml }; @@ -123,7 +122,7 @@ export function generateReportHtml( const historicalSection = config.showHistorical ? generateHistoricalSection(artifacts.historicalComparison) : ""; - const footer = generateFooter(); + const footer = generateFooter(resolveArtifactToolVersion(artifacts)); const script = getReportJavaScript({ darkModeDefault: config.darkModeDefault }); const redactionSection = generateRedactionSection(config); @@ -167,7 +166,7 @@ function createEmptyFindings(): FindingsArtifact { generated_at: new Date().toISOString(), run_id: "none", repo: { root: "unknown" }, - tool: { name: "code-to-gate", version: VERSION, plugin_versions: [] }, + tool: { name: "code-to-gate", version: "unknown", plugin_versions: [] }, artifact: "findings", schema: "findings@v1", version: "ctg/v1alpha1",