test(ledger): ディレクトリ宣言の注釈が既存ファイルを列挙していないことを検査する (検査 C) - #481
Conversation
ADR-074 決定 4 の 2026-09-06 追記「ディレクトリ宣言の注釈で既存ファイルを候補として 列挙しない」を lib-ledger の実台帳検査として機械強制する。 2026-09-05 の run 33983134567 は順位 356 で 2 ターン・0 変更で停止した。09-04 に 書き直した注釈が候補ファイルとして staleness.rs を挙げていたが、それは順位 136 の working-copy staleness で本タスクとは無関係だった。同じ形の注釈で 310 は通っているので、 原因は判断委譲の文言ではなく列挙したファイルの誤り。「正しく列挙せよ」は ADR-075 として 既にあり ADR-074 の筆者自身が破ったので、規約を「列挙するな」にして機械化する — 書く場所を無くせば外れる余地も無くなる。 - target_files に annotations (注釈の中身の抽出、strip_annotations の対) と is_directory_declaration を追加 (どちらも cfg(test)、本番ビルドの公開面は増やさない) - annotation_check (cfg(test)) を新設。auto lane の行のうちディレクトリ宣言を持つものに ついて、注釈のバッククォート引用で拡張子を持つものを宣言ディレクトリからの相対パス (および / を含めばリポジトリ相対) として解決し、実在すれば落とす - 実在しない名前 (順位 426 の「例 facade_reexports.rs」) は列挙ではない。ファイル宣言の 注釈は対象外 (mod tests の位置などを補う従来の書き方を壊さない)。識別子・ディレクトリ 言及は数えない - deployed_ledger が 800 行に達したため、検査 C は別 module に置き、あちらの read_ledger / task_rows / target_file_cells / is_auto_lane / TaskRow を pub(crate) にした - ADR-074 の帰結 § 欠点 と決定 6 の表に、本 ADR の規約が機械へ移った最初の例として記録 pre-push security review (SEC-NEW-lib-ledger-annotation_check-L51): 対象ファイル欄の 自由記述が失敗メッセージ経由で cargo test 出力に載り、後続 fix agent の信頼境界を破る 経路 (lib.rs::build_task が本番経路で reject_prompt_frame_escape を課している欄)。 takt fix step は違反する名前を found から除外する形で直したが、それは fail-open — 注釈に枠マーカーを書けば検査 C を素通りできる。task_rows が同じ脅威に採った fail-closed に揃え、行を失敗として報告しつつ中身は表示しない (row_failure)。あわせて non-blocking warning の traversal 形の名前 (.. / \ / 先頭 /) は exists に渡さない。 実測: master の台帳 (順位 356 の 09-04 版注釈) に対して本検査は 3 ファイルの列挙で落ち、 #480 (2 ファイル宣言) の版では通る。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (5)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughauto lane のディレクトリ宣言を対象に、注釈内の既存ファイル列挙を検出する Changes注釈検査の追加
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to This adds a test-only ledger rule that rejects directory annotations enumerating existing files, with parsing and traversal-safety coverage. No remaining merge-blocking risk is identified. Sequence Diagram(s)sequenceDiagram
participant CargoTest
participant read_ledger
participant task_rows
participant annotation_check
participant target_files
CargoTest->>read_ledger: 台帳を読み取る
read_ledger->>task_rows: 台帳行を解析する
task_rows->>annotation_check: auto lane 行を渡す
annotation_check->>target_files: 対象ファイル欄と注釈を解析する
annotation_check->>CargoTest: 検査結果を返す
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
指摘レビュー指摘は現時点で 0 件 (CodeRabbit は本リポジトリでは自動レビューが行われない設定のため、今後も付かない見込み)。CI 状態と diff 概要のみ記す。 Diff 概要
PR title 「検査 C」どおり、既存の検査 A/B ( 次のアクション
|
implement 後の停止のうち guard=failure (変更なし) は、完了済み / 詳細エントリの矛盾 / 宣言が決められない / 権限不能 の 4 種が同じ 1 行に落ちる。理由を知っている唯一の主体は agent 自身だが、workflow は SDK 出力を hidden for security で捨てていた。2026-09-05 の 順位 356 (2 ターン・0 変更) は、ターン数と秒数から推論するしかなかった。 - agent プロンプトに「変更せず終了するときは最終メッセージの先頭行を `[NIGHTLY_AGENT_STOP] ` で始め、何が決まらなかったかを 1 行で書く」を追加 - claude-code-action の execution_file (SDK メッセージの JSON 配列) を Report outcome へ AGENT_EXECUTION_FILE として渡す - cli-nightly-outcome に agent_reason を追加。最終 assistant メッセージの先頭の内容行が 接頭辞で始まるときだけ、その 1 行を lib-ledger の screen_for_public_output (ADR-072 決定 14 と同じ関数: 制御文字除去・バッククォート置換・200 文字切り詰め) に通して出す。 接頭辞が無ければ本文には触れず「理由行なし」とだけ出す — それ自体が指示不達の情報になる - 接頭辞は先頭行に限る。どこかに含めばよいとすると、途中で「ここからが理由」と言い張る 行を後から足せてしまうため - 色には影響しない。読めない / 無い / 形式違いのいずれも fail-open で、exit code は 従来どおり publish / handoff だけが決める。module doc の「外部 I/O を行わない」に この 1 ファイル読み取りを例外として明記 - 接頭辞の定義は exe 側 (STOP_PREFIX) を唯一の出所とし、agent プロンプトがそれを含むこと、 Report outcome が execution_file を渡していることを、実 workflow を読むテストで固定 CodeRabbit #482 (契約の厳密化) を受けた受理幅の明示: - 接頭辞の直後はトークン境界 (行末か空白) を要求。`[NIGHTLY_AGENT_STOP]理由` は Unstated - 理由が空 (空白・制御文字・不可視文字のみで screening 後に「(内容なし)」) なら Unstated。 「(内容なし)」を Stated として出すと理由が書かれていると誤読される - 先頭の空行と行頭の空白は許す。markdown 整形で起こる形で、そこで理由を捨てると本機能の 目的 (理由を拾う) に反する。空行より前には何も無いので後付け行が「先頭」を名乗る経路に はならない - 「(内容なし)」は lib-ledger screening.rs の固定文と結合するため、実関数の出力と照合する テストで drift を止める これは診断の短縮であって再発防止ではない。防止側は ADR-074 決定 4 の 2026-09-06 追記 (#480) とその機械強制 (#481) が担う。ADR-072 決定 10 に追記。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
implement 後の停止のうち guard=failure (変更なし) は、完了済み / 詳細エントリの矛盾 / 宣言が決められない / 権限不能 の 4 種が同じ 1 行に落ちる。理由を知っている唯一の主体は agent 自身だが、workflow は SDK 出力を hidden for security で捨てていた。2026-09-05 の 順位 356 (2 ターン・0 変更) は、ターン数と秒数から推論するしかなかった。 - agent プロンプトに「変更せず終了するときは最終メッセージの先頭行を `[NIGHTLY_AGENT_STOP] ` で始め、何が決まらなかったかを 1 行で書く」を追加 - claude-code-action の execution_file (SDK メッセージの JSON 配列) を Report outcome へ AGENT_EXECUTION_FILE として渡す - cli-nightly-outcome に agent_reason を追加。最終 assistant メッセージの先頭の内容行が 接頭辞で始まるときだけ、その 1 行を lib-ledger の screen_for_public_output (ADR-072 決定 14 と同じ関数: 制御文字除去・バッククォート置換・200 文字切り詰め) に通して出す。 接頭辞が無ければ本文には触れず「理由行なし」とだけ出す — それ自体が指示不達の情報になる - 接頭辞は先頭行に限る。どこかに含めばよいとすると、途中で「ここからが理由」と言い張る 行を後から足せてしまうため - 色には影響しない。読めない / 無い / 形式違いのいずれも fail-open で、exit code は 従来どおり publish / handoff だけが決める。module doc の「外部 I/O を行わない」に この 1 ファイル読み取りを例外として明記 - 接頭辞の定義は exe 側 (STOP_PREFIX) を唯一の出所とし、agent プロンプトがそれを含むこと、 Report outcome が execution_file を渡していることを、実 workflow を読むテストで固定 CodeRabbit #482 (契約の厳密化) を受けた受理幅の明示: - 接頭辞の直後はトークン境界 (行末か空白) を要求。`[NIGHTLY_AGENT_STOP]理由` は Unstated - 理由が空 (空白・制御文字・不可視文字のみで screening 後に「(内容なし)」) なら Unstated。 「(内容なし)」を Stated として出すと理由が書かれていると誤読される - 先頭の空行と行頭の空白は許す。markdown 整形で起こる形で、そこで理由を捨てると本機能の 目的 (理由を拾う) に反する。空行より前には何も無いので後付け行が「先頭」を名乗る経路に はならない - 「(内容なし)」は lib-ledger screening.rs の固定文と結合するため、実関数の出力と照合する テストで drift を止める これは診断の短縮であって再発防止ではない。防止側は ADR-074 決定 4 の 2026-09-06 追記 (#480) とその機械強制 (#481) が担う。ADR-072 決定 10 に追記。 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
post-merge feedback 採用分のうち、実際に一度指摘されたのにテストが無く実装が 直らなかった 2 件を回帰テストで固定する。 ## lib-ledger: 台帳セル由来の失敗メッセージ (#481 系統) - `reject_prompt_frame_escape` から位置を持たない `frame_escape_reason` を切り出し、 検査 C が渡していたリテラル `0` (= 実在しない「0 行目」がメッセージに混入) を無くす。 行の同定は順位で足りる。 - 併せて両関数を `screening.rs` へ移す (`lib.rs` が 800 行上限を超えたため。 不可視文字判定の隣が置き場所としても自然)。 - 追加した回帰テスト 4 本は、いずれも変異を入れて落ちることを実測した: 境界検査を列挙の後ろへ「返す」形にすると 2 本が落ち、ディレクトリ宣言が無いセルで 早期 return すると 1 本が落ち、行番号 0 を復活させると 1 本が落ちる。 ## cli-nightly-outcome: 停止理由行の段限定 (#482 系統) `[NIGHTLY_AGENT_STOP]` は「変更せず終了するとき」に限って書かせている接頭辞なので、 理由行が説明として成立するのは guard 段と段不明のときだけ。変更がある段 (verify / ledger_completion / ledger_removal) で理由が書かれていたら申告と実態が 食い違っているので、理由の中身ではなく食い違いそのものを 1 行にする。 - pre-push review が 1st run で指摘したが、テストが guard の 1 ケースしか無かった。 全段 × 全 reason の表で押さえる。 - この変更で **e2e fixture の誤りが露見した**: guard 停止の夜を模す 3 本が `VERIFY_OUTCOME` を渡しておらず、`<未実行>` = 非成功として停止段が verify に なっていた。fixture 側を直した。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
post-merge feedback (#476-#485) の採用分のうち、コードで塞げないものを既存の 台帳エントリへ反映する。新規の Tier 3 エントリは作らない。 ## 既存エントリへの追記 - 順位 460 (信頼境界の ADR 化): 「台帳セル由来の文字列を失敗メッセージへ埋める経路は 新設のたびに screening を通す」を 4 つ目の原則として追加。#481/#482/#483 の 3 レポートが 独立に同じ提案を出したのは、原則が未文書である合図として扱う。 - 順位 342 (陽性証拠): 射程を「検知機構のテスト検証」まで広げた。「出なかったこと」は 検知が働いた証拠にならない (検知が壊れていても同じ結果になる)。#311 の実装側と #479 の検証側は同じ 1 原則の 2 適用先なので、別エントリを立てず 1 本化する。 ## 順位 461 の前提が変わった dev-conventions.md への一括追記を出口としていたが、**その出口を採らない**方針が示された (dev-conventions.md は ADR 運用から棚上げした項目を積み上げた負の遺産であり縮小方向。 決定事項は ADR で管理し、それ以外は仕組み化する)。着手前に 12 項目を 「ADR 化 / 仕組み化 / 却下」へ振り分ける作業を先頭に置いた。 ## 順位 514 を新設 行き先を失った #479 Tier2 #1 (外部コマンド出力パーサのテスト入力は実出力から採る) を、 規約ではなく仕組みの検討として登録する。#479 と #313 の 2 件が同型なので、型の網羅性 / fixture 契約 / 計測の 3 案を比較してから決める。 ## PR #314 feedback の後始末 - A: ADR 参照 5 箇所をバッククォートから markdown link へ (台帳全体では link 262 件 vs backtick 5 件で慣例は明確) - B / C: 対象エントリ (順位 339 / 336) が既に台帳から消えており失効 - D: 「Tier ↔ 絵文字の凡例を書く」は**採らない**。実測すると絵文字は Tier 番号の関数に なっておらず (🔧 Tier 3 が 16 箇所)、凡例を書くとその食い違いを正当化してしまう。 絵文字の削除は別 PR で行う。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
post-merge feedback (#476-#485) の採用分のうち、コードで塞げないものを既存の 台帳エントリへ反映する。新規の Tier 3 エントリは作らない。 ## 既存エントリへの追記 - 順位 460 (信頼境界の ADR 化): 「台帳セル由来の文字列を失敗メッセージへ埋める経路は 新設のたびに screening を通す」を 4 つ目の原則として追加。#481/#482/#483 の 3 レポートが 独立に同じ提案を出したのは、原則が未文書である合図として扱う。 - 順位 342 (陽性証拠): 射程を「検知機構のテスト検証」まで広げた。「出なかったこと」は 検知が働いた証拠にならない (検知が壊れていても同じ結果になる)。#311 の実装側と #479 の検証側は同じ 1 原則の 2 適用先なので、別エントリを立てず 1 本化する。 ## 順位 461 の前提が変わった dev-conventions.md への一括追記を出口としていたが、**その出口を採らない**方針が示された (dev-conventions.md は ADR 運用から棚上げした項目を積み上げた負の遺産であり縮小方向。 決定事項は ADR で管理し、それ以外は仕組み化する)。着手前に 12 項目を 「ADR 化 / 仕組み化 / 却下」へ振り分ける作業を先頭に置いた。 ## 順位 514 を新設 行き先を失った #479 Tier2 #1 (外部コマンド出力パーサのテスト入力は実出力から採る) を、 規約ではなく仕組みの検討として登録する。#479 と #313 の 2 件が同型なので、型の網羅性 / fixture 契約 / 計測の 3 案を比較してから決める。 ## PR #314 feedback の後始末 - A: ADR 参照 5 箇所をバッククォートから markdown link へ (台帳全体では link 262 件 vs backtick 5 件で慣例は明確) - B / C: 対象エントリ (順位 339 / 336) が既に台帳から消えており失効 - D: 「Tier ↔ 絵文字の凡例を書く」は**採らない**。実測すると絵文字は Tier 番号の関数に なっておらず (🔧 Tier 3 が 16 箇所)、凡例を書くとその食い違いを正当化してしまう。 絵文字の削除は別 PR で行う。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
背景
ADR-074 決定 4 の 2026-09-06 追記「ディレクトリ宣言の注釈で既存ファイルを候補として列挙しない」(#480) を、
lib-ledgerの実台帳検査として機械強制する。2026-09-05 の run 33983134567 は順位 356 で 2 ターン・0 変更で停止した。09-04 に書き直した注釈が候補ファイルとして
staleness.rsを挙げていたが、それは順位 136 の working-copy staleness で本タスクとは無関係だった。同じ形の注釈で 310 は通っているので、原因は判断委譲の文言ではなく列挙したファイルの誤りである。「正しく列挙せよ」は ADR-075 として既にあり、ADR-074 の筆者自身が破った。そこで規約を「列挙するな」にし (#480)、ここで機械化する — 書く場所を無くせば外れる余地も無くなる。「無関係かどうか」の意味判断は要らず、存在確認だけで決まるので機械化できる。本 ADR の規約が機械へ移った最初の例である。
変更
target_files:annotations(注釈の中身の抽出、strip_annotationsの対) とis_directory_declarationを追加。どちらも#[cfg(test)]で本番ビルドの公開面は増やさないannotation_check(新設、#[cfg(test)]): auto lane の行のうちディレクトリ宣言を持つものについて、注釈のバッククォート引用で拡張子を持つものを宣言ディレクトリからの相対パス (および/を含めばリポジトリ相対) として解決し、実在すればcargo testで落とすfacade_reexports.rs」) は列挙ではないmod testsの位置などを補う従来の書き方を壊さない)deployed_ledgerが 800 行に達したため、検査 C は別 module に置き、read_ledger/task_rows/target_file_cells/is_auto_lane/TaskRowをpub(crate)にした実測
master の台帳 (順位 356 の 09-04 版注釈) に対して本検査は実物を捕まえた:
#480 (2 ファイル宣言) の版では通る。本 PR は #480 のマージ後に rebase 済み。
pre-push security review への対応 (fix step の実装は採らなかった)
SEC-NEW-lib-ledger-annotation_check-L51(High): 対象ファイル欄の自由記述が失敗メッセージ経由でcargo test出力に載り、後続 fix agent の信頼境界を破る経路。lib.rs::build_taskが本番経路で同じ欄にreject_prompt_frame_escapeを課している以上、検査側も揃えるべきという指摘で妥当。takt の fix step は「違反する名前を
foundから除外する」形で直したが、それは fail-open — 注釈に枠マーカーを書けば検査 C を素通りできる。task_rowsが同じ脅威に採った fail-closed (行をErrにする) と逆向きなので採らず、行を失敗として報告しつつ中身は表示しないrow_failureに書き直した。あわせて non-blocking warning の traversal 形の名前 (../\/ 先頭/) はexistsに渡さない guard を追加。回帰テスト: 枠マーカー / bidi 制御文字で行が落ち名前が出ないこと、traversal 名でexistsが呼ばれないこと。検証
cargo test -p lib-ledger191 passed (実台帳検査 A / B / C を含む)cargo clippy -p lib-ledger --all-targets -- -D warningsclean🤖 Generated with Claude Code
Summary by CodeRabbit
新機能
ドキュメント