From 522d99d5bd4227fc5ddd1acb4635d79dd4140c38 Mon Sep 17 00:00:00 2001 From: jack0jp Date: Thu, 6 Aug 2026 23:20:23 +0900 Subject: [PATCH 01/11] =?UTF-8?q?docs:=20=E3=83=AC=E3=83=93=E3=83=A5?= =?UTF-8?q?=E3=83=BC=E3=83=95=E3=83=AD=E3=83=BC=E3=81=AE=E8=A6=8B=E7=9B=B4?= =?UTF-8?q?=E3=81=97(Draft=E5=85=88=E8=A1=8C=20+=20CodeRabbit=E5=B0=8E?= =?UTF-8?q?=E5=85=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #18〜#32の実績分析(Claude/Copilotの指摘重複率、Copilotのクレジット 消費)を踏まえた運用変更。 - PRはまずDraftで作成し、Claude/Codex/CodeRabbit(無料)と反復してから Ready化してCopilot(有料)の最終レビューを受ける運用をCLAUDE.mdに明記 (Copilotのrulesetは既にreview_draft_pull_requests: falseのため ruleset自体の変更は不要だった) - .coderabbit.yamlを追加。デフォルトでdraftをスキップする設定を drafts: trueで上書きし、CLAUDE.mdの絶対ルール・RLS・test/dbの 観点をpath_instructionsで明示 - docs/roadmap.mdの「保留: 外部アカウント待ち」にCodeRabbit導入を追記 - docs/permissions.mdに、INSERT/UPDATE/DELETEのRETURNINGがSELECTポリシー で空になるだけでは「弾かれた」証明にならない、という#26で見つかった 罠を追記 --- .coderabbit.yaml | 32 ++++++++++++++++++++++++++++++++ CLAUDE.md | 14 +++++++++++--- docs/permissions.md | 21 +++++++++++++++++++++ docs/roadmap.md | 1 + 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..9f06f86 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,32 @@ +language: "ja-JP" + +reviews: + profile: assertive + auto_review: + enabled: true + # デフォルトはdraft PRをスキップするが、このリポジトリはDraftで + # Claude/Codexと反復してからReady化する運用(CLAUDE.md「ブランチとPR」)。 + # CodeRabbitは無料枠のためCopilotと違いdraft中も含めて都度レビューさせる。 + drafts: true + path_instructions: + - path: "**/*.{ts,tsx}" + instructions: | + CLAUDE.md の絶対ルールに違反していないか重点的に確認すること。 + - `as` によるキャスト、`any`、`@ts-ignore` / `@ts-expect-error` / `eslint-disable` による + エラーの黙殺がないか + - common/ に置くべき判断ロジック(フィルタ・並び順・検証・集計・権限判定・日付計算)が + app/ や mcp/ に複製・直書きされていないか + - 型を手書きせず、生成型(supabase/types.ts)かZodスキーマの z.infer から導出しているか + - path: "supabase/migrations/**" + instructions: | + docs/data-model.md・docs/permissions.md の権限マトリクスと突き合わせて確認すること。 + RLSポリシー内の自己参照サブクエリ(同一テーブルを問い合わせるEXISTS等)は + 呼び出し元のRLS越しに評価され、本来見えるべき行が見えず誤判定することがある + (security definer関数でラップする必要がないか確認する)。 + - path: "test/db/**" + instructions: | + docs/testing.md・docs/permissions.md「RLS検証の必須要件」に沿っているか確認すること。 + - service_roleキーを使っていないか + - 否定側のテストが、UPDATE/DELETEのRETURNINGやSELECTが空であることだけで + 「弾かれた」と誤認していないか(USING句が壊れていても同じ結果になりうる)。 + 対象行を見られる側の視点で値が実際に変化していないことまで確認しているか diff --git a/CLAUDE.md b/CLAUDE.md index 072b0f0..c3430a6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,9 +49,17 @@ **mainへの直接pushは禁止。**必ずブランチを作成し、PRを経由してmainにマージする。 mainはRulesetで保護されており、リポジトリ管理者(あなた)のみ緊急時にバイパスできる。 -- PRを作成すると、Claude(`claude-review.yml`)とCodex(`codex-review.yml`)による - 自動レビューが走る。シークレット未設定の間は自動でスキップされる - (`docs/roadmap.md`「保留: 外部アカウント待ち」) +**PRはまずDraftで作成する。** +Claude(`claude-review.yml`)とCodex(`codex-review.yml`)はdraftでもpushのたびに走るが、 +GitHub Copilotの自動レビュー(`copilot_code_review` Ruleset)は`review_draft_pull_requests: false` +に設定済みのためdraft中は走らない。Draftで指摘がなくなるまで反復し、`gh pr ready`で +Ready for reviewに変えたタイミングでCopilot(導入後はCodeRabbitも)の最終レビューを1回受ける。 +Copilotは1レビューあたりプレミアムリクエストを消費するため、Claude/Codexとの反復で +消費しないようにするための運用(PR #18〜#32の実績分析に基づく判断)。 + +- Ready化後にCopilot/CodeRabbitの指摘で追加修正が発生した場合は、都度pushしてよい + (Ready後はpushのたびに再レビューが走る) +- シークレット未設定の間、Codexは自動でスキップされる(`docs/roadmap.md`「保留: 外部アカウント待ち」) - 人間の承認レビューは必須にしていない(現状は開発者本人のみのため。GitHubは PR作成者自身の承認をカウントしない)。マージの実行自体が「人間の確認」に当たる (`docs/prd.md` 8.5) diff --git a/docs/permissions.md b/docs/permissions.md index 47f419c..9c45cfc 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -83,6 +83,27 @@ expect(await asUserA.from("expenses").select()).toHaveLength(3); expect(await asUserB.from("expenses").select()).toHaveLength(0); ``` +**UPDATE/DELETEの`RETURNING`が空であることだけで判定しない。** +`UPDATE ... RETURNING` / `DELETE ... RETURNING` は、対象行がUSING句で弾かれた場合だけでなく、 +USING句が壊れていて実際には書き換え・削除できてしまっている場合でも、その行をSELECTポリシー上 +見せられなければ同じく空配列を返す。RETURNINGが空であることは「USING句が効いている」ことを +何も証明しない。 + +``` +// これだけでは何も検証していない(USING句が壊れていても同じ結果になりうる) +const { data } = await asUserB.from("expenses").update({ amount: 1 }).eq("id", id).select(); +expect(data).toHaveLength(0); + +// これが本体。本人(対象行を見られる側)の視点で値が実際に変化していないことを確認する +const { data: unchanged } = await asUserA.from("expenses").select("amount").eq("id", id).single(); +expect(unchanged?.amount).toBe(元の値); +``` + +**INSERTの`RETURNING`にも同じ注意が必要。** 招待のように自分以外のユーザーの行を作成する +操作では、作成した本人(自分)がその行をSELECTポリシー上見られないことがある。この場合 +`INSERT ... RETURNING` はINSERT自体が要件を満たしていてもRLS違反エラーを返す。 +`.select()` を付けずにINSERTするか、作成された行の中身は対象ユーザー自身の視点で確認すること。 + ### 3. マトリクスを表のままテストに写す 上の表の×が1つでもテストされていなければ、それは検証されていない権限とみなす。 diff --git a/docs/roadmap.md b/docs/roadmap.md index 8979a6b..3cd6cca 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,6 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | +| CodeRabbitの導入 | **保留。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加を決定。[coderabbit.ai](https://coderabbit.ai) でGitHub Appをインストールし、このリポジトリを選択するだけで有効化される(プライベートリポジトリでも無料枠: 200ファイル/時・4レビュー/時。追加のAPIキーやシークレット設定は不要)。GitHub Appのインストールは**あなた自身の操作が必要** | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From 4af910b910c843fda2574c4fe8bb2f21a29f0e98 Mon Sep 17 00:00:00 2001 From: jack0jp Date: Thu, 6 Aug 2026 23:33:44 +0900 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20CodeRabbit=E3=81=AE=E5=88=9D?= =?UTF-8?q?=E5=9B=9E=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98?= =?UTF-8?q?=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - auto_pause_after_reviewed_commits: 0 を追加(既定5コミットで自動レビューが 止まる設定は反復push運用と相性が悪い) - CLAUDE.mdの記述を.coderabbit.yaml(drafts: true)と一致させる。 「Copilot(導入後はCodeRabbitも)の最終レビュー」という誤った表現を修正し、 CodeRabbitもDraft中から反復レビューする旨を明記 - CodeRabbit Freeプランの実際のレート制限(GitHub連携PRレビューは1回/時/開発者) をCLAUDE.md・docs/roadmap.md・.coderabbit.yamlに反映。前回調査した 「200ファイル/時・4レビュー/時」は誤りだった(CodeRabbit自身のレビュー コメントがPostgreSQL公式ドキュメントとCodeRabbit公式docsをその場で クロールして訂正) - docs/permissions.mdのRETURNING説明をPostgreSQL公式ドキュメントに基づき 修正。UPDATEはSELECTポリシー不一致だと実際はエラーになり(空配列ではない)、 DELETEはSELECTポリシーを満たさない行がそもそも削除候補から除外される、 というのが正確な挙動 - markdownlint MD040(コードフェンスの言語識別子)を修正 - .coderabbit.yamlのpath_instructionsを強化(security definerの安全条件、 操作別のRLS否定側テスト観点) --- .coderabbit.yaml | 26 +++++++++++++++++++------- CLAUDE.md | 21 +++++++++++++-------- docs/permissions.md | 21 +++++++++++++-------- docs/roadmap.md | 2 +- 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 9f06f86..394aef2 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -6,8 +6,15 @@ reviews: enabled: true # デフォルトはdraft PRをスキップするが、このリポジトリはDraftで # Claude/Codexと反復してからReady化する運用(CLAUDE.md「ブランチとPR」)。 - # CodeRabbitは無料枠のためCopilotと違いdraft中も含めて都度レビューさせる。 + # CodeRabbitはCopilotと違いdraft中も含めて都度レビュー対象にする + # (実際に消費するのはFreeプランのレート制限: GitHub連携のPRレビューは + # 1回/時/開発者。1時間に複数pushしても2回目以降はスキップされうる。 + # 詳細: https://docs.coderabbit.ai/management/plans) drafts: true + # 既定値5だと5コミット分レビューした時点で自動レビューが止まり、以降は + # `@coderabbitai review` の手動実行が必要になる。pushのたびに反復する + # 運用と相性が悪いため無効化する(実際の頻度はFreeプランのレート制限が握る)。 + auto_pause_after_reviewed_commits: 0 path_instructions: - path: "**/*.{ts,tsx}" instructions: | @@ -20,13 +27,18 @@ reviews: - path: "supabase/migrations/**" instructions: | docs/data-model.md・docs/permissions.md の権限マトリクスと突き合わせて確認すること。 - RLSポリシー内の自己参照サブクエリ(同一テーブルを問い合わせるEXISTS等)は - 呼び出し元のRLS越しに評価され、本来見えるべき行が見えず誤判定することがある - (security definer関数でラップする必要がないか確認する)。 + - RLSポリシー内の自己参照サブクエリ(同一テーブルを問い合わせるEXISTS等)は + 呼び出し元のRLS越しに評価され、本来見えるべき行が見えず誤判定することがある + (security definer関数でラップする必要がないか確認する) + - security definer関数を使う場合、`set search_path = ''`または安全な固定値を + 必須にし、内部の参照はスキーマ修飾名(`public.xxx`)にしているか。 + `PUBLIC`ロールへの不要なEXECUTE権限が残っていないか(必要なロールにのみGRANTする) - path: "test/db/**" instructions: | docs/testing.md・docs/permissions.md「RLS検証の必須要件」に沿っているか確認すること。 - service_roleキーを使っていないか - - 否定側のテストが、UPDATE/DELETEのRETURNINGやSELECTが空であることだけで - 「弾かれた」と誤認していないか(USING句が壊れていても同じ結果になりうる)。 - 対象行を見られる側の視点で値が実際に変化していないことまで確認しているか + - 否定側のテストが、対象行を見られない側から実行した結果(RETURNINGやSELECTが空) + だけで判定していないか。`WHERE`不一致で0件なのか、RLSで正しく弾かれて0件なのかは + その視点からは区別できない。UPDATEは対象行を見られる側の視点で値が変化していない + ことを、DELETEは行が存在し続けていることを、INSERTは新しい行が作られていない + ことを、それぞれ確認しているか diff --git a/CLAUDE.md b/CLAUDE.md index c3430a6..bc08d20 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,15 +50,20 @@ mainはRulesetで保護されており、リポジトリ管理者(あなた)のみ緊急時にバイパスできる。 **PRはまずDraftで作成する。** -Claude(`claude-review.yml`)とCodex(`codex-review.yml`)はdraftでもpushのたびに走るが、 -GitHub Copilotの自動レビュー(`copilot_code_review` Ruleset)は`review_draft_pull_requests: false` -に設定済みのためdraft中は走らない。Draftで指摘がなくなるまで反復し、`gh pr ready`で -Ready for reviewに変えたタイミングでCopilot(導入後はCodeRabbitも)の最終レビューを1回受ける。 -Copilotは1レビューあたりプレミアムリクエストを消費するため、Claude/Codexとの反復で -消費しないようにするための運用(PR #18〜#32の実績分析に基づく判断)。 - +Claude(`claude-review.yml`)・Codex(`codex-review.yml`)・CodeRabbit(`.coderabbit.yaml`、 +`drafts: true`)はdraftでもpushのたびに走るが、GitHub Copilotの自動レビュー +(`copilot_code_review` Ruleset)は`review_draft_pull_requests: false`に設定済みのため +draft中は走らない。Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for reviewに +変えたタイミングでCopilotの最終レビューを1回受ける。Copilotは1レビューあたり +プレミアムリクエストを消費するため、Claude/Codex/CodeRabbitとの反復で消費しないように +するための運用(PR #18〜#32の実績分析に基づく判断)。 + +- CodeRabbitのFreeプランはGitHub連携のPRレビューが1回/時/開発者に制限されている。 + Draftで短時間に何度もpushしても2回目以降はレート制限でスキップされうる + (`docs/roadmap.md`「保留: 外部アカウント待ち」参照)。反復の主力はClaude/Codexで、 + CodeRabbitは取れたときに追加の視点が入る、という位置づけで期待値を持つこと - Ready化後にCopilot/CodeRabbitの指摘で追加修正が発生した場合は、都度pushしてよい - (Ready後はpushのたびに再レビューが走る) + (Ready後はpushのたびに再レビューが走る。ただしCodeRabbitは上記レート制限の対象) - シークレット未設定の間、Codexは自動でスキップされる(`docs/roadmap.md`「保留: 外部アカウント待ち」) - 人間の承認レビューは必須にしていない(現状は開発者本人のみのため。GitHubは PR作成者自身の承認をカウントしない)。マージの実行自体が「人間の確認」に当たる diff --git a/docs/permissions.md b/docs/permissions.md index 9c45cfc..e72a762 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -75,7 +75,7 @@ service_roleはRLSをバイパスする。これで通ったテストは、**RLS 正常系だけのテストは、権限が全開放されていても通る。否定側が本体。 -``` +```typescript // これだけでは何も検証していない expect(await asUserA.from("expenses").select()).toHaveLength(3); @@ -83,14 +83,19 @@ expect(await asUserA.from("expenses").select()).toHaveLength(3); expect(await asUserB.from("expenses").select()).toHaveLength(0); ``` -**UPDATE/DELETEの`RETURNING`が空であることだけで判定しない。** -`UPDATE ... RETURNING` / `DELETE ... RETURNING` は、対象行がUSING句で弾かれた場合だけでなく、 -USING句が壊れていて実際には書き換え・削除できてしまっている場合でも、その行をSELECTポリシー上 -見せられなければ同じく空配列を返す。RETURNINGが空であることは「USING句が効いている」ことを -何も証明しない。 +**UPDATE/DELETEが「成功したかに見える」結果だけで判定しない。** +PostgreSQLのRLSでは、UPDATE/DELETEは対象コマンド自身のUSING句に加えて、テーブルのSELECTポリシーに +よる可視性も要求する。`UPDATE ... RETURNING`は、更新後の行がSELECTポリシーを満たさないと +エラー(`new row violates row-level security policy`)で失敗する。`DELETE`はSELECTポリシーを +満たさない行がそもそも削除候補から除外されるため、対象を見つけられず0件になる。 -``` -// これだけでは何も検証していない(USING句が壊れていても同じ結果になりうる) +つまり「RETURNINGが空で、エラーも出ない」という結果だけでは、(a) `WHERE`条件に一致する行が +最初から無かったのか、(b) USING句/SELECT可視性によって正しく弾かれたのか、を区別できない。 +UPDATE/DELETEを試みた後は、対象行を見られる側(本人など)の視点で、値が実際に +変化していないこと・行が存在し続けていることまで確認する。 + +```typescript +// これだけでは何も検証していない(WHERE不一致で0件なのか、正しく弾かれて0件なのか区別できない) const { data } = await asUserB.from("expenses").update({ amount: 1 }).eq("id", id).select(); expect(data).toHaveLength(0); diff --git a/docs/roadmap.md b/docs/roadmap.md index 3cd6cca..f438b78 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **保留。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加を決定。[coderabbit.ai](https://coderabbit.ai) でGitHub Appをインストールし、このリポジトリを選択するだけで有効化される(プライベートリポジトリでも無料枠: 200ファイル/時・4レビュー/時。追加のAPIキーやシークレット設定は不要)。GitHub Appのインストールは**あなた自身の操作が必要** | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From fe445e85caa161d72c87320dc014b05aba100161 Mon Sep 17 00:00:00 2001 From: jack0jp Date: Thu, 6 Aug 2026 23:48:29 +0900 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20CodeRabbit=202=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CLAUDE.md: レビュー実行条件をツールごとに正確化(Codexはシークレット設定時、CodeRabbitはFreeプランのレート制限対象) - docs/permissions.md: select()のコード例をdata/errorの分解に修正、UPDATE/DELETEのSELECTポリシー要求条件を限定 --- CLAUDE.md | 10 ++++++---- docs/permissions.md | 12 ++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index bc08d20..b54f4eb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,10 +50,12 @@ mainはRulesetで保護されており、リポジトリ管理者(あなた)のみ緊急時にバイパスできる。 **PRはまずDraftで作成する。** -Claude(`claude-review.yml`)・Codex(`codex-review.yml`)・CodeRabbit(`.coderabbit.yaml`、 -`drafts: true`)はdraftでもpushのたびに走るが、GitHub Copilotの自動レビュー -(`copilot_code_review` Ruleset)は`review_draft_pull_requests: false`に設定済みのため -draft中は走らない。Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for reviewに +Claude(`claude-review.yml`)はdraftのpushごとに走る。Codexは`OPENAI_API_KEY`設定時 +(`codex-review.yml`)、CodeRabbitは`drafts: true`(`.coderabbit.yaml`)でdraft中も +レビュー対象になるが、CodeRabbitはFreeプランのレート制限を受ける(下記参照)。 +GitHub Copilotの自動レビュー(`copilot_code_review` Ruleset)は +`review_draft_pull_requests: false`に設定済みのためdraft中は走らない。 +Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for reviewに 変えたタイミングでCopilotの最終レビューを1回受ける。Copilotは1レビューあたり プレミアムリクエストを消費するため、Claude/Codex/CodeRabbitとの反復で消費しないように するための運用(PR #18〜#32の実績分析に基づく判断)。 diff --git a/docs/permissions.md b/docs/permissions.md index e72a762..df6ec20 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -77,15 +77,19 @@ service_roleはRLSをバイパスする。これで通ったテストは、**RLS ```typescript // これだけでは何も検証していない -expect(await asUserA.from("expenses").select()).toHaveLength(3); +const { data: dataA } = await asUserA.from("expenses").select(); +expect(dataA).toHaveLength(3); // これが本体 -expect(await asUserB.from("expenses").select()).toHaveLength(0); +const { data: dataB } = await asUserB.from("expenses").select(); +expect(dataB).toHaveLength(0); ``` **UPDATE/DELETEが「成功したかに見える」結果だけで判定しない。** -PostgreSQLのRLSでは、UPDATE/DELETEは対象コマンド自身のUSING句に加えて、テーブルのSELECTポリシーに -よる可視性も要求する。`UPDATE ... RETURNING`は、更新後の行がSELECTポリシーを満たさないと +PostgreSQLのRLSでは、`WHERE`や`RETURNING`が対象テーブルの列を参照するUPDATE/DELETE +(このリポジトリのテストは`.eq("id", id)`などのWHEREを必ず伴うため該当する)は、対象コマンド +自身のUSING句に加えて、テーブルのSELECTポリシーによる可視性も要求する。 +`UPDATE ... RETURNING`は、更新後の行がSELECTポリシーを満たさないと エラー(`new row violates row-level security policy`)で失敗する。`DELETE`はSELECTポリシーを 満たさない行がそもそも削除候補から除外されるため、対象を見つけられず0件になる。 From 36212eda17185c2d493e04cedec8c9880f9ed79c Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 09:10:27 +0900 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20CodeRabbit=204=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0(Claude=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E3=81=AE=E3=83=88=E3=83=BC=E3=82=AF=E3=83=B3=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E3=82=92=E6=98=8E=E8=A8=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE_CODE_OAUTH_TOKEN未設定時はClaudeレビューがスキップされる旨が 記述から抜けており、実際のワークフロー(claude-review.yml)の挙動と 矛盾していた。Codex/CodeRabbitと同様に条件を明記する。 Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index b54f4eb..f1fa894 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,9 +50,10 @@ mainはRulesetで保護されており、リポジトリ管理者(あなた)のみ緊急時にバイパスできる。 **PRはまずDraftで作成する。** -Claude(`claude-review.yml`)はdraftのpushごとに走る。Codexは`OPENAI_API_KEY`設定時 -(`codex-review.yml`)、CodeRabbitは`drafts: true`(`.coderabbit.yaml`)でdraft中も -レビュー対象になるが、CodeRabbitはFreeプランのレート制限を受ける(下記参照)。 +Claude(`claude-review.yml`)は`CLAUDE_CODE_OAUTH_TOKEN`設定時にdraftのpushごとに走り、 +未設定時はスキップする。Codexは`OPENAI_API_KEY`設定時(`codex-review.yml`)、CodeRabbitは +`drafts: true`(`.coderabbit.yaml`)でdraft中もレビュー対象になるが、CodeRabbitはFreeプランの +レート制限を受ける(下記参照)。 GitHub Copilotの自動レビュー(`copilot_code_review` Ruleset)は `review_draft_pull_requests: false`に設定済みのためdraft中は走らない。 Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for reviewに From 4ef0ec866eaf3f014cc5e5cbb7c7022384d0e39a Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 09:17:02 +0900 Subject: [PATCH 05/11] =?UTF-8?q?fix:=20Claude=203=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0(=E6=9C=AA=E6=A4=9C=E8=A8=BC=E4=BA=8B?= =?UTF-8?q?=E9=A0=85=E3=81=AE=E6=98=8E=E8=A8=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit roadmap.mdがCopilotのdraft/ready挙動を「確認済み」と断定していたが、 このPR自体のTest planは未検証のままだった。CodeRabbitのDraft動作の 確認と、Copilotの挙動(CLAUDE.mdの既存記載を踏襲・未検証)を書き分けた。 .coderabbit.yamlのauto_pause_after_reviewed_commits: 0も、5コミットを 超えた継続の実地確認がまだであることをコメントに追記した。 Co-Authored-By: Claude Sonnet 5 --- .coderabbit.yaml | 2 ++ docs/roadmap.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 394aef2..778a59d 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -14,6 +14,8 @@ reviews: # 既定値5だと5コミット分レビューした時点で自動レビューが止まり、以降は # `@coderabbitai review` の手動実行が必要になる。pushのたびに反復する # 運用と相性が悪いため無効化する(実際の頻度はFreeプランのレート制限が握る)。 + # 0が「無制限」として機能するかはCodeRabbit公式ドキュメント通りの想定であり、 + # 5コミットを超えて継続することの実地確認はまだ済んでいない。 auto_pause_after_reviewed_commits: 0 path_instructions: - path: "**/*.{ts,tsx}" diff --git a/docs/roadmap.md b/docs/roadmap.md index f438b78..22c03cb 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動自体は、CLAUDE.mdの既存記載を踏襲したものでPR #35時点では未検証)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From c68ebb4ee9b1e55d9d8f9f32546d8bda3bcea91e Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 09:28:17 +0900 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20CodeRabbit=205=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0(Plan=E3=81=AE=E9=A3=9F=E3=81=84=E9=81=95?= =?UTF-8?q?=E3=81=84=E3=83=BBINSERT=E5=90=A6=E5=AE=9A=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E8=A6=B3=E7=82=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## CodeRabbit 5回目レビューの指摘分類 (commit 4ef0ec8) - CodeRabbitのレビュー実行結果が毎回`Plan: Pro Plus`と表示されており、 CLAUDE.md/roadmap.mdが前提としていた「Freeプラン・1回/時のレート制限」 と矛盾していた。GitHub App導入直後のトライアル期間中の可能性が高いため、 本物の修正として注記を追加した(トライアル終了後にFreeプランの制限が 実際に効き始めたら更新する)。 - .coderabbit.yamlのtest/db/**向けpath_instructionsで、INSERTの否定側 テストが「対象行を見られる側の視点で」新規行が作られていないことを 確認する、という条件が抜けていた(UPDATE/DELETEは明記済み)。妥当な nitpickとして、docs/permissions.mdの既存記述と揃える形で修正した。 Co-Authored-By: Claude Sonnet 5 --- .coderabbit.yaml | 4 ++-- CLAUDE.md | 2 ++ docs/roadmap.md | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 778a59d..4427b79 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -42,5 +42,5 @@ reviews: - 否定側のテストが、対象行を見られない側から実行した結果(RETURNINGやSELECTが空) だけで判定していないか。`WHERE`不一致で0件なのか、RLSで正しく弾かれて0件なのかは その視点からは区別できない。UPDATEは対象行を見られる側の視点で値が変化していない - ことを、DELETEは行が存在し続けていることを、INSERTは新しい行が作られていない - ことを、それぞれ確認しているか + ことを、DELETEは行が存在し続けていることを、INSERTは対象行を見られる側の視点で + 新しい行が作られていないことを、それぞれ確認しているか(service_roleは使わない) diff --git a/CLAUDE.md b/CLAUDE.md index f1fa894..f4d6552 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,6 +65,8 @@ Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for review Draftで短時間に何度もpushしても2回目以降はレート制限でスキップされうる (`docs/roadmap.md`「保留: 外部アカウント待ち」参照)。反復の主力はClaude/Codexで、 CodeRabbitは取れたときに追加の視点が入る、という位置づけで期待値を持つこと + (ただしGitHub App導入直後は`Plan: Pro Plus`のトライアル期間中でこのレート制限が + 適用されていない可能性がある。詳細は`docs/roadmap.md`「CodeRabbitの導入」参照) - Ready化後にCopilot/CodeRabbitの指摘で追加修正が発生した場合は、都度pushしてよい (Ready後はpushのたびに再レビューが走る。ただしCodeRabbitは上記レート制限の対象) - シークレット未設定の間、Codexは自動でスキップされる(`docs/roadmap.md`「保留: 外部アカウント待ち」) diff --git a/docs/roadmap.md b/docs/roadmap.md index 22c03cb..d3e39c8 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動自体は、CLAUDE.mdの既存記載を踏襲したものでPR #35時点では未検証)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動自体は、CLAUDE.mdの既存記載を踏襲したものでPR #35時点では未検証)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35時点のレビュー実行結果は毎回`Plan: Pro Plus`と表示されており、GitHub App導入直後のトライアル期間中の可能性がある。トライアル終了後はFreeプランのレート制限に戻る想定で運用し、実際に1回/時の制限が効き始めたタイミングでこの注記を更新すること | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From 2ec236b169a348489db4030afbc82e2079f39c11 Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 09:38:44 +0900 Subject: [PATCH 07/11] =?UTF-8?q?fix:=20Claude=204=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0(RETURNING/USING=E5=8F=A5=E3=81=AE=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E7=9F=9B=E7=9B=BE=E3=82=92=E4=BF=AE=E6=AD=A3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Claude 4回目レビューの指摘分類 (commit c68ebb4) - docs/permissions.md:88-99が自己矛盾していた。「UPDATE...RETURNINGは SELECTポリシー不一致でエラーになる」と書きながら、直後で同じ状況を 「エラーも出ない」と説明し、コード例もtry/catchなしでdata=[]を期待して いた。実際のexpenses_update_ownポリシー(using (user_id = auth.uid())) で検証すると、他人の行を更新しようとするケースはUSING句で静かに除外 される(エラーなし・0件)。「更新後の行がSELECTポリシーを満たさない とエラー」は別の仕組みで、UPDATE/SELECTポリシーの条件が食い違う場合 にのみ起こる、より狭いケース。本物の修正として2つの仕組みを分けて 説明し直した - docs/roadmap.mdの「Copilotのdraft/ready挙動はCLAUDE.mdの既存記載を 踏襲」という記述が誤り(base branch時点のCLAUDE.mdにCopilotへの言及は なく、このPRで新規に持ち込んだ主張だった)。妥当な指摘として、 Rulesetの設定自体は既知の事実である一方、挙動の実地確認はまだして いない、という位置づけに書き直した Co-Authored-By: Claude Sonnet 5 --- docs/permissions.md | 19 ++++++++++++------- docs/roadmap.md | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/permissions.md b/docs/permissions.md index df6ec20..52b15eb 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -86,15 +86,20 @@ expect(dataB).toHaveLength(0); ``` **UPDATE/DELETEが「成功したかに見える」結果だけで判定しない。** -PostgreSQLのRLSでは、`WHERE`や`RETURNING`が対象テーブルの列を参照するUPDATE/DELETE -(このリポジトリのテストは`.eq("id", id)`などのWHEREを必ず伴うため該当する)は、対象コマンド -自身のUSING句に加えて、テーブルのSELECTポリシーによる可視性も要求する。 -`UPDATE ... RETURNING`は、更新後の行がSELECTポリシーを満たさないと -エラー(`new row violates row-level security policy`)で失敗する。`DELETE`はSELECTポリシーを -満たさない行がそもそも削除候補から除外されるため、対象を見つけられず0件になる。 +PostgreSQLのRLSでは、UPDATE/DELETEの対象行はまずコマンド自身のUSING句で絞り込まれる。 +USING句を満たさない行は**エラーなく静かに除外される**(候補行が単に0件になるだけ)。 +「他人の行を更新/削除しようとする」典型的な否定側テスト(例: `expenses_update_own`の +`using (user_id = auth.uid())`)はこのケースに該当し、`data`は空配列、`error`は`null`になる。 + +`UPDATE ... RETURNING`にはこれとは別の落とし穴もある。USING句を通過して実際に +更新された新しい行の内容がテーブルのSELECTポリシーを満たさない場合、更新自体が +エラー(`new row violates row-level security policy`)になる。これはUSING句で +静かに弾かれるケースとは別の仕組みで、UPDATEとSELECTのポリシー条件が食い違っている +場合にだけ起こる。単に「他人の行を更新しようとする」だけの否定側テストでは通常 +発生しない。 つまり「RETURNINGが空で、エラーも出ない」という結果だけでは、(a) `WHERE`条件に一致する行が -最初から無かったのか、(b) USING句/SELECT可視性によって正しく弾かれたのか、を区別できない。 +最初から無かったのか、(b) USING句によって正しく弾かれたのか、を区別できない。 UPDATE/DELETEを試みた後は、対象行を見られる側(本人など)の視点で、値が実際に 変化していないこと・行が存在し続けていることまで確認する。 diff --git a/docs/roadmap.md b/docs/roadmap.md index d3e39c8..10bb1e8 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動自体は、CLAUDE.mdの既存記載を踏襲したものでPR #35時点では未検証)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35時点のレビュー実行結果は毎回`Plan: Pro Plus`と表示されており、GitHub App導入直後のトライアル期間中の可能性がある。トライアル終了後はFreeプランのレート制限に戻る想定で運用し、実際に1回/時の制限が効き始めたタイミングでこの注記を更新すること | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動は、`copilot_code_review` Rulesetの`review_draft_pull_requests: false`設定という既知の事実に基づくが、PR #35で新たにCLAUDE.mdに明文化したものでPR #35時点ではdraft/ready両方の実地確認はまだしていない)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35時点のレビュー実行結果は毎回`Plan: Pro Plus`と表示されており、GitHub App導入直後のトライアル期間中の可能性がある。トライアル終了後はFreeプランのレート制限に戻る想定で運用し、実際に1回/時の制限が効き始めたタイミングでこの注記を更新すること | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From 509c11f2510ad527f73b2c09db14606c5dee4874 Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 09:57:43 +0900 Subject: [PATCH 08/11] =?UTF-8?q?fix:=20Copilot=E5=88=9D=E5=9B=9E=E3=83=AC?= =?UTF-8?q?=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92=E5=8F=8D?= =?UTF-8?q?=E6=98=A0=20+=20auto=5Fpause=E3=81=AE=E5=AE=9F=E5=9C=B0?= =?UTF-8?q?=E6=A4=9C=E8=A8=BC=E7=B5=90=E6=9E=9C=E3=82=92=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Copilotレビューの指摘分類 (commit 2ec236b) - docs/permissions.md:112 | 妥当なnitpick | コード例の`元の値`が未定義識別子で コピペ不可だった。事前に本人視点で値を控える`before`変数を追加し、それと 比較する形に修正した - docs/permissions.md:84/94/108 | 妥当なnitpick | `.select()`の戻り値`data`は nullになり得るのに`toHaveLength`を直接呼んでいた。`data ?? []`で安全にした - docs/permissions.md:98 | 妥当なnitpick | UPDATE...RETURNINGのエラーを 「USING句とは別の仕組み」「WITH CHECKとの関係」まで断定していたのは 実装の内部機構に踏み込みすぎだった。PostgreSQL公式ドキュメントの一次情報の 引用に留める形にシンプル化した - .coderabbit.yaml:18 | 見送り(実地検証で解決) | 「0が無制限として機能するか 未確認」という記述に対し、Copilotは公式ドキュメント通り断定すべきと指摘。 実際にPR #35で7コミット目push後に`@coderabbitai review`を手動実行したところ 「Review rate limited」という応答で、「pauseされている」旨の案内では なかった。つまりauto_pause自体は意図通り無効化されており、レビューが 止まった原因はレート制限だと実地で確認できた。この結果をコメントと docs/roadmap.mdの注記に反映した Co-Authored-By: Claude Sonnet 5 --- .coderabbit.yaml | 10 +++++++--- CLAUDE.md | 3 +-- docs/permissions.md | 21 ++++++++++++--------- docs/roadmap.md | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 4427b79..66b3ee7 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -13,9 +13,13 @@ reviews: drafts: true # 既定値5だと5コミット分レビューした時点で自動レビューが止まり、以降は # `@coderabbitai review` の手動実行が必要になる。pushのたびに反復する - # 運用と相性が悪いため無効化する(実際の頻度はFreeプランのレート制限が握る)。 - # 0が「無制限」として機能するかはCodeRabbit公式ドキュメント通りの想定であり、 - # 5コミットを超えて継続することの実地確認はまだ済んでいない。 + # 運用と相性が悪いため無効化する。PR #35で7コミット分pushした後に + # `@coderabbitai review` を手動実行したところ、応答は「Review rate limited」 + # であり、「レビューがpauseされているので手動実行が必要」という案内には + # ならなかった(pause中ならその旨のメッセージが返る仕様)。つまりauto_pauseの + # 5コミット上限には引っかかっていない = 0が意図通り無効化として機能している + # と判断できる。実際にpushのたびのレビューが止まった原因はレート制限であり、 + # auto_pauseとは別物(詳細はdocs/roadmap.md「CodeRabbitの導入」参照)。 auto_pause_after_reviewed_commits: 0 path_instructions: - path: "**/*.{ts,tsx}" diff --git a/CLAUDE.md b/CLAUDE.md index f4d6552..61556a1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,8 +65,7 @@ Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for review Draftで短時間に何度もpushしても2回目以降はレート制限でスキップされうる (`docs/roadmap.md`「保留: 外部アカウント待ち」参照)。反復の主力はClaude/Codexで、 CodeRabbitは取れたときに追加の視点が入る、という位置づけで期待値を持つこと - (ただしGitHub App導入直後は`Plan: Pro Plus`のトライアル期間中でこのレート制限が - 適用されていない可能性がある。詳細は`docs/roadmap.md`「CodeRabbitの導入」参照) + (PR #35で実際にレート制限を確認済み。詳細は`docs/roadmap.md`「CodeRabbitの導入」参照) - Ready化後にCopilot/CodeRabbitの指摘で追加修正が発生した場合は、都度pushしてよい (Ready後はpushのたびに再レビューが走る。ただしCodeRabbitは上記レート制限の対象) - シークレット未設定の間、Codexは自動でスキップされる(`docs/roadmap.md`「保留: 外部アカウント待ち」) diff --git a/docs/permissions.md b/docs/permissions.md index 52b15eb..eab6a2d 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -78,11 +78,11 @@ service_roleはRLSをバイパスする。これで通ったテストは、**RLS ```typescript // これだけでは何も検証していない const { data: dataA } = await asUserA.from("expenses").select(); -expect(dataA).toHaveLength(3); +expect(dataA ?? []).toHaveLength(3); // これが本体 const { data: dataB } = await asUserB.from("expenses").select(); -expect(dataB).toHaveLength(0); +expect(dataB ?? []).toHaveLength(0); ``` **UPDATE/DELETEが「成功したかに見える」結果だけで判定しない。** @@ -92,11 +92,11 @@ USING句を満たさない行は**エラーなく静かに除外される**(候 `using (user_id = auth.uid())`)はこのケースに該当し、`data`は空配列、`error`は`null`になる。 `UPDATE ... RETURNING`にはこれとは別の落とし穴もある。USING句を通過して実際に -更新された新しい行の内容がテーブルのSELECTポリシーを満たさない場合、更新自体が -エラー(`new row violates row-level security policy`)になる。これはUSING句で -静かに弾かれるケースとは別の仕組みで、UPDATEとSELECTのポリシー条件が食い違っている -場合にだけ起こる。単に「他人の行を更新しようとする」だけの否定側テストでは通常 -発生しない。 +更新された新しい行の内容がテーブルのSELECTポリシーを満たさない場合、PostgreSQL公式 +ドキュメント([CREATE POLICY](https://www.postgresql.org/docs/current/sql-createpolicy.html)) +の通り更新自体がエラーになる("inserted or updated rows to be returned are never +silently ignored")。単に「他人の行を更新しようとする」だけの否定側テストは、通常 +USING句の時点で候補から除外されるため、このエラーには到達しない。 つまり「RETURNINGが空で、エラーも出ない」という結果だけでは、(a) `WHERE`条件に一致する行が 最初から無かったのか、(b) USING句によって正しく弾かれたのか、を区別できない。 @@ -104,13 +104,16 @@ UPDATE/DELETEを試みた後は、対象行を見られる側(本人など)の 変化していないこと・行が存在し続けていることまで確認する。 ```typescript +// 更新前に本人視点で元の値を控えておく +const { data: before } = await asUserA.from("expenses").select("amount").eq("id", id).single(); + // これだけでは何も検証していない(WHERE不一致で0件なのか、正しく弾かれて0件なのか区別できない) const { data } = await asUserB.from("expenses").update({ amount: 1 }).eq("id", id).select(); -expect(data).toHaveLength(0); +expect(data ?? []).toHaveLength(0); // これが本体。本人(対象行を見られる側)の視点で値が実際に変化していないことを確認する const { data: unchanged } = await asUserA.from("expenses").select("amount").eq("id", id).single(); -expect(unchanged?.amount).toBe(元の値); +expect(unchanged?.amount).toBe(before?.amount); ``` **INSERTの`RETURNING`にも同じ注意が必要。** 招待のように自分以外のユーザーの行を作成する diff --git a/docs/roadmap.md b/docs/roadmap.md index 10bb1e8..827da01 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動は、`copilot_code_review` Rulesetの`review_draft_pull_requests: false`設定という既知の事実に基づくが、PR #35で新たにCLAUDE.mdに明文化したものでPR #35時点ではdraft/ready両方の実地確認はまだしていない)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35時点のレビュー実行結果は毎回`Plan: Pro Plus`と表示されており、GitHub App導入直後のトライアル期間中の可能性がある。トライアル終了後はFreeプランのレート制限に戻る想定で運用し、実際に1回/時の制限が効き始めたタイミングでこの注記を更新すること | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動は、`copilot_code_review` Rulesetの`review_draft_pull_requests: false`設定という既知の事実に基づくが、PR #35で新たにCLAUDE.mdに明文化したものでPR #35時点ではdraft/ready両方の実地確認はまだしていない)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35のレビュー実行結果は毎回`Plan: Pro Plus`と表示されていたが、7コミット目のpush以降はレビューが自動発火せず、`@coderabbitai review`を手動実行すると「Review rate limited」と返ってきた(2026-08-07T00:55 UTC時点)。「レビューがpauseされている」旨の案内ではなかったため、`auto_pause_after_reviewed_commits: 0`は意図通り機能しており、止まった原因はレート制限だと判断できる。GitHub App導入直後のPro Plusトライアル期間が既に終了した可能性が高い。以降はFreeプランのレート制限(1回/時/開発者)を前提に運用する | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From 40bf55d31fc73608c1ed686379f25b794bd2dd44 Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 10:05:38 +0900 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20Claude=205=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0(Copilot=E6=8C=99=E5=8B=95=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E5=9C=B0=E7=A2=BA=E8=AA=8D=E7=B5=90=E6=9E=9C=E3=82=92=E8=A8=98?= =?UTF-8?q?=E8=BC=89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Claude 5回目レビューの指摘分類 (commit 509c11f) - docs/roadmap.mdの「Copilotのdraft/ready挙動は未検証」という記述が、 このPR自身のレビュー履歴(Ready化後にcopilot-pull-request-reviewerが 3回動いた記録)と食い違っていた。本物の修正として、Draft中は一度も Copilotのレビューが付かず、Ready化後に動いたことを実地確認済みとして 明記した - CLAUDE.mdに、CodeRabbitのレート制限は詳しく書かれているのに Copilotのquota上限による失敗モードがどこにも記載されていなかった。 本物の修正として、quota上限で失敗した場合の再リクエスト手順を追記した Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 5 +++++ docs/roadmap.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 61556a1..fbc9c31 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,6 +66,11 @@ Draftで指摘がなくなるまで反復し、`gh pr ready`でReady for review (`docs/roadmap.md`「保留: 外部アカウント待ち」参照)。反復の主力はClaude/Codexで、 CodeRabbitは取れたときに追加の視点が入る、という位置づけで期待値を持つこと (PR #35で実際にレート制限を確認済み。詳細は`docs/roadmap.md`「CodeRabbitの導入」参照) +- Copilotの最終レビューは「プレミアムリクエストのquota上限に達したため実行できなかった」 + という形で失敗することがある(PR #35で発生)。この場合レビューコメントは投稿されるが + 中身のないもので、コードは実際にはレビューされていない。quotaを追加してから + `gh api repos/{owner}/{repo}/pulls/{number}/requested_reviewers -X POST + -f 'reviewers[]=copilot-pull-request-reviewer[bot]'` で再リクエストする - Ready化後にCopilot/CodeRabbitの指摘で追加修正が発生した場合は、都度pushしてよい (Ready後はpushのたびに再レビューが走る。ただしCodeRabbitは上記レート制限の対象) - シークレット未設定の間、Codexは自動でスキップされる(`docs/roadmap.md`「保留: 外部アカウント待ち」) diff --git a/docs/roadmap.md b/docs/roadmap.md index 827da01..6b301ae 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に1回だけ走るという挙動は、`copilot_code_review` Rulesetの`review_draft_pull_requests: false`設定という既知の事実に基づくが、PR #35で新たにCLAUDE.mdに明文化したものでPR #35時点ではdraft/ready両方の実地確認はまだしていない)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35のレビュー実行結果は毎回`Plan: Pro Plus`と表示されていたが、7コミット目のpush以降はレビューが自動発火せず、`@coderabbitai review`を手動実行すると「Review rate limited」と返ってきた(2026-08-07T00:55 UTC時点)。「レビューがpauseされている」旨の案内ではなかったため、`auto_pause_after_reviewed_commits: 0`は意図通り機能しており、止まった原因はレート制限だと判断できる。GitHub App導入直後のPro Plusトライアル期間が既に終了した可能性が高い。以降はFreeプランのレート制限(1回/時/開発者)を前提に運用する | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に走るという挙動は、PR #35で実地確認済み。Draft中の7回のpushではCopilotのレビューは一度も付かず、`gh pr ready`実行後に`copilot-pull-request-reviewer`が動いた。ただし1回目はプレミアムリクエストのquota上限で失敗し、quota追加後に再リクエストして2回成功した。「1回だけ」という想定に反し、quota切れ時は失敗レビューがノーカウントで残る点は注意)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35のレビュー実行結果は毎回`Plan: Pro Plus`と表示されていたが、7コミット目のpush以降はレビューが自動発火せず、`@coderabbitai review`を手動実行すると「Review rate limited」と返ってきた(2026-08-07T00:55 UTC時点)。「レビューがpauseされている」旨の案内ではなかったため、`auto_pause_after_reviewed_commits: 0`は意図通り機能しており、止まった原因はレート制限だと判断できる。GitHub App導入直後のPro Plusトライアル期間が既に終了した可能性が高い。以降はFreeプランのレート制限(1回/時/開発者)を前提に運用する | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。 From 9447f05b34fab8f51310247c664fe54e7ae687bc Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 10:11:32 +0900 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20Copilot=202=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92?= =?UTF-8?q?=E5=8F=8D=E6=98=A0(data=E3=81=AEnull=E3=83=95=E3=82=A9=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E3=83=90=E3=83=83=E3=82=AF=E3=81=8C=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=82=92=E9=9A=A0=E3=81=99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Copilot 2回目レビューの指摘分類 (commit 40bf55d) - docs/permissions.md:81/85/108,112 | 本物の修正 | 前回追加した`data ?? []` というnull安全化が、実はerrorが発生してdata:nullになったケースを 「0件」として静かに握りつぶしてしまう、というCopilotの指摘は的確だった。 「否定側テストが何も検証していない」ことへの警戒を説くドキュメント自身が 同じ落とし穴を持っていたことになる。`?? []`を外し、`error`がnullである ことを明示的に検証する形に修正した Co-Authored-By: Claude Sonnet 5 --- docs/permissions.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/permissions.md b/docs/permissions.md index eab6a2d..220d033 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -77,12 +77,14 @@ service_roleはRLSをバイパスする。これで通ったテストは、**RLS ```typescript // これだけでは何も検証していない -const { data: dataA } = await asUserA.from("expenses").select(); -expect(dataA ?? []).toHaveLength(3); +const { data: dataA, error: errorA } = await asUserA.from("expenses").select(); +expect(errorA).toBeNull(); +expect(dataA).toHaveLength(3); // これが本体 -const { data: dataB } = await asUserB.from("expenses").select(); -expect(dataB ?? []).toHaveLength(0); +const { data: dataB, error: errorB } = await asUserB.from("expenses").select(); +expect(errorB).toBeNull(); +expect(dataB).toHaveLength(0); ``` **UPDATE/DELETEが「成功したかに見える」結果だけで判定しない。** @@ -108,8 +110,9 @@ UPDATE/DELETEを試みた後は、対象行を見られる側(本人など)の const { data: before } = await asUserA.from("expenses").select("amount").eq("id", id).single(); // これだけでは何も検証していない(WHERE不一致で0件なのか、正しく弾かれて0件なのか区別できない) -const { data } = await asUserB.from("expenses").update({ amount: 1 }).eq("id", id).select(); -expect(data ?? []).toHaveLength(0); +const { data, error } = await asUserB.from("expenses").update({ amount: 1 }).eq("id", id).select(); +expect(error).toBeNull(); +expect(data).toHaveLength(0); // これが本体。本人(対象行を見られる側)の視点で値が実際に変化していないことを確認する const { data: unchanged } = await asUserA.from("expenses").select("amount").eq("id", id).single(); From a9c1811a308cb2fabb606cabd2aaec50af55446d Mon Sep 17 00:00:00 2001 From: jack0jp Date: Fri, 7 Aug 2026 10:18:20 +0900 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20Copilot=203=E5=9B=9E=E7=9B=AE?= =?UTF-8?q?=E3=83=BBClaude=206=E5=9B=9E=E7=9B=AE=E3=83=AC=E3=83=93?= =?UTF-8?q?=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98=E3=82=92=E5=8F=8D=E6=98=A0?= =?UTF-8?q?(error=E6=A4=9C=E8=A8=BC=E3=81=AE=E4=B8=80=E8=B2=AB=E6=80=A7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## レビュー指摘分類 (commit 9447f05) - docs/permissions.md:110/119 | 本物の修正(Copilot) | 前回`error`検証を 追加したUPDATE否定側テスト例で、同じブロック内の`before`/`unchanged` 取得(`.single()`)にだけerror検証が抜けていた。一貫性のため全クエリに error検証を追加した - docs/roadmap.md:89 | 妥当なnitpick(Claude) | 「プレミアムリクエスト13回 相当」という数値に出典がなかった。公式の固定値ではなく実測値である旨を 明記した Co-Authored-By: Claude Sonnet 5 --- docs/permissions.md | 6 ++++-- docs/roadmap.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/permissions.md b/docs/permissions.md index 220d033..a735656 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -107,7 +107,8 @@ UPDATE/DELETEを試みた後は、対象行を見られる側(本人など)の ```typescript // 更新前に本人視点で元の値を控えておく -const { data: before } = await asUserA.from("expenses").select("amount").eq("id", id).single(); +const { data: before, error: beforeError } = await asUserA.from("expenses").select("amount").eq("id", id).single(); +expect(beforeError).toBeNull(); // これだけでは何も検証していない(WHERE不一致で0件なのか、正しく弾かれて0件なのか区別できない) const { data, error } = await asUserB.from("expenses").update({ amount: 1 }).eq("id", id).select(); @@ -115,7 +116,8 @@ expect(error).toBeNull(); expect(data).toHaveLength(0); // これが本体。本人(対象行を見られる側)の視点で値が実際に変化していないことを確認する -const { data: unchanged } = await asUserA.from("expenses").select("amount").eq("id", id).single(); +const { data: unchanged, error: unchangedError } = await asUserA.from("expenses").select("amount").eq("id", id).single(); +expect(unchangedError).toBeNull(); expect(unchanged?.amount).toBe(before?.amount); ``` diff --git a/docs/roadmap.md b/docs/roadmap.md index 6b301ae..3502b20 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -86,7 +86,7 @@ | Claudeレビューの本稼働化 | **完了。** `CLAUDE_CODE_OAUTH_TOKEN` シークレット追加 + GitHub App([github.com/apps/claude](https://github.com/apps/claude))インストール済み。PRへの総評+インラインコメント投稿を実PRで確認済み | | Copilot自動レビューの有効化 | **完了。** Copilot Proに加入し、Rulesetに `copilot_code_review` ルールを追加。実PRでのコメント投稿を確認済み | | Codexレビューの本稼働化 | **保留(意図的)。** OpenAI APIキーを取得しない方針のため、`codex-review.yml` はシークレット未設定のまま自動スキップし続ける。将来キーを取得したら `OPENAI_API_KEY` をリポジトリシークレットに追加するだけで動き出す | -| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(1レビューあたりプレミアムリクエスト13回相当)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に走るという挙動は、PR #35で実地確認済み。Draft中の7回のpushではCopilotのレビューは一度も付かず、`gh pr ready`実行後に`copilot-pull-request-reviewer`が動いた。ただし1回目はプレミアムリクエストのquota上限で失敗し、quota追加後に再リクエストして2回成功した。「1回だけ」という想定に反し、quota切れ時は失敗レビューがノーカウントで残る点は注意)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35のレビュー実行結果は毎回`Plan: Pro Plus`と表示されていたが、7コミット目のpush以降はレビューが自動発火せず、`@coderabbitai review`を手動実行すると「Review rate limited」と返ってきた(2026-08-07T00:55 UTC時点)。「レビューがpauseされている」旨の案内ではなかったため、`auto_pause_after_reviewed_commits: 0`は意図通り機能しており、止まった原因はレート制限だと判断できる。GitHub App導入直後のPro Plusトライアル期間が既に終了した可能性が高い。以降はFreeプランのレート制限(1回/時/開発者)を前提に運用する | +| CodeRabbitの導入 | **完了。** PR #18〜#32の実績分析でClaude/Copilotの指摘重複率と、Copilotのクレジット消費(実測で1レビューあたりプレミアムリクエスト13回相当。公式の固定値ではなく実績値)を踏まえ、無料の3人目のレビュアーとして追加。GitHub Appをインストール済み。`.coderabbit.yaml`で`drafts: true`を設定し、Draft PRでも反復レビューされることをPR #35で確認済み(Copilotがdraft中は走らずReady化後に走るという挙動は、PR #35で実地確認済み。Draft中の7回のpushではCopilotのレビューは一度も付かず、`gh pr ready`実行後に`copilot-pull-request-reviewer`が動いた。ただし1回目はプレミアムリクエストのquota上限で失敗し、quota追加後に再リクエストして2回成功した。「1回だけ」という想定に反し、quota切れ時は失敗レビューがノーカウントで残る点は注意)。Freeプランのレート制限はGitHub連携のPRレビューが**1回/時/開発者**(IDE/CLIは3回/時)で、当初調べていた「200ファイル/時・4レビュー/時」は誤り(CodeRabbit自身のレビューコメントで訂正された。参照: [docs.coderabbit.ai/management/plans](https://docs.coderabbit.ai/management/plans))。短時間の連続pushでは2回目以降のレビューがスキップされうる前提で運用する。**注記:** PR #35のレビュー実行結果は毎回`Plan: Pro Plus`と表示されていたが、7コミット目のpush以降はレビューが自動発火せず、`@coderabbitai review`を手動実行すると「Review rate limited」と返ってきた(2026-08-07T00:55 UTC時点)。「レビューがpauseされている」旨の案内ではなかったため、`auto_pause_after_reviewed_commits: 0`は意図通り機能しており、止まった原因はレート制限だと判断できる。GitHub App導入直後のPro Plusトライアル期間が既に終了した可能性が高い。以降はFreeプランのレート制限(1回/時/開発者)を前提に運用する | > シークレットは `gh secret set ` などリポジトリの設定画面から**あなた自身が追加すること**。 > Claudeにトークン・APIキーの値を渡さない。