Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AI時代のPRレビューにどう向き合うか?

Avatar for KairiM KairiM
October 11, 2026

 AI時代のPRレビューにどう向き合うか?

Avatar for KairiM

KairiM

October 11, 2026

More Decks by KairiM

Other Decks in Technology

Transcript

  1. JDDUG Ryukyu (沖縄 ) 運営 丸山 海理 所属 (株)サンエー 情報システム部

    役職 課長 出身地 京都府 出身校 琉球大学 法文学部 経済 趣味 スポーツ観戦(サッカー/野球) 好きなAWS サービス KIRO cli SNS @KairiM0kinawa 2
  2. 概要 商号 株式会社サンエー 創業 1950年1月5日 会社設立 1970年5月28日 資本金 3,723百万円 営業収益(連結)

    2,455億48百万円(2026年2月期) 事業内容 食料品と衣料品ならびに家電 日用雑貨等の住居関連用品の小売業 本社所在地 〒901-2733 沖縄県宜野湾市大山7-2-10 3
  3. 店舗情報 店舗数 合計 78店舗(単体) 沖縄本島 総合店舗 20店舗 衣料・住関 1店舗 食品店舗

    43店舗 外食店舗 7店舗 医薬品 2店舗 宮古島 総合店舗 2店舗 食品店舗 外食店舗 1店舗 1店舗 石垣島 総合店舗 ※2026年2月末現在 1店舗 4
  4. 5

  5. 基幹システムを内製開発 技術スタック 2026 Main Architecture Layers Design & Frontend DevEx

    & Observability AI-Driven-DX API & Backend Quality &Tools Database & Auth Data Analytics Ops & Collab Infrastructure 6
  6. PRが一気に増えた。読む速度は上がらない。 開発者 + AI PR PR 開発者 AIが生成した大量のコード・ドキュメ ントを読んで確かめる 背景の言語化・全体像の提示が後回し

    になる PR PR PR レビュアー レビュアー 増え続けるPR・差分・説明文を読んで 判断する 1件ずつ「なぜ」を自力で再構築させ られる 両側で認知負荷が上がり、レビューが滞る 9
  7. レビュアーが困る2つのこと 01 02 背景・決定・捨てた代替案は diff のどこにも書いていない どのレイヤーに・どんな意図で 手を入れたかが見えない 「なぜこの変更をしたのか」が PRから読み取れない

    差分は読めても、 全体像が掴みにくい レビュアーは差分の前で、意図と全体像を"自力で再構築"させられる。 AIが量産したPRほど、この負担が大きい。 11
  8. コード差分に関してはある程度でAIでカバー AI 過激派(?) は AIレビューだけで自動mergeさせているケースもあると 聞くが・・・・ それは とてつもなく「成熟した組織」です。 そもそものソフトウェア設計がマイクロサービスになっていて何かあっても 障害範囲が狭かったり

    Code規約やPR規約がしっかりしており 人間がレビューしているときから、スムーズなレビューが出来ていた組織です ジュニアなうちの組織では絶対無理!!!! バグ・型・規約違反はコードに現れるのでAIで一定レビュー可能に 13
  9. 実装構想 01 02 ・Push のタイミングで生成AIを起動 ・Code の差分から開発者に質問 ・事前にAIと対話し聞き出した意図を含める ・触ったレイヤーをわかりやすく表現 ・FEであれば、見た目の変化のイメージがつくよう

    に 意図を引き出す 想定質問: 「なぜこのPRを出そうとしているのか?」 「他の実装方針もありそうだがなぜ選んでないの か?」 PRの説明を視覚化(HTML化) 11
  10. 参考にした考え方=ADR(Architecture Decision Record ) 目的 やり方 効果 過去の決定の「なぜ」を、将来 のメンバーに残す 理由を知らないまま決定を「盲

    目的に受け入れる」ことも、 「盲目的に覆す」ことも防ぐ 1件1ファイル、1〜2ページの Markdownで、コードと同じリ ポジトリに置く 構成は「タイトル/コンテキス ト/決定/ステータス/結果」 の5項目 番号は連番で再利用しない。決 定を覆すときは消さずに 「superseded」とマークする メンバーが入れ替わっても、決 定の背景と影響が引き継がれる 前提が変わったときに、決定を 見直すべきタイミングがわかる 将来の再設計を見据えた長期的 な意図を共有できる 引用 https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions 18
  11. 20

  12. サンプル環境の構成 1 2 3 4 5 6 7 8 9

    10 11 12 13 14 15 16 17 18 19 20 21 visual-review-poc/ ├── packages/ │ ├── backend/ # Clean Architecture の層が見える最小 API (Hono) │ │ └── src/ │ │ ├── domain/ # Entity / Repository interface / Result │ │ ├── application/ # UseCase │ │ ├── infrastructure/ # Repository 実装 + DI 配線 (container.ts) │ │ └── interface/ # Hono route │ └── frontend/ # React 19 + Vite + Tailwind v4 の最小メニュー画面 │ └── src/{components,api,types.ts,App.tsx} ├── scripts/adr-mr.sh # 【構想1】pre-push ランチャ(差分収集 → AI起動, fail-open) ├── .claude/skills/ │ ├── adr-mr-review/ # ADR対話 → MR説明文 反映の手順 │ └── visual-mr-review/ # ビジュアルレビューHTML生成の手順 ├── .gitlab-ci/visual-review.yml # 【構想2】HTMLをアーティファクト公開するCIジョブ ├── .gitlab/scripts/post-visual-review-comment.sh # MRコメント投稿(更新/新規) ├── lefthook.yml # pre-commit(品質) / pre-push(ADR対話) └── docs/ ├── ADR/ # 設計ADR(0001-0004) + 生成済みMR説明文の実例 ├── examples/ # 生成済みビジュアルレビューHTMLの実例(参考) └── review/ # ← ここに生成物が出力される 実開発環境のミニチュア 構想実現に必要なもの 24
  13. 実装のためのメイン部品(自社環境) AI エージェント hook機構 CI パイプライン Claude Code Lefthook Gitlab

    pre-commit のタイミングでClaude をhook し、開発者との会話をもとにHTMLを作成 Gitlab 上のアーティファクトにHTMLを埋め込み、レビュー時に確認できるようにする 25
  14. 詳しく見てみる 1 起動層 lefthook.yml pre-push / interactive: true — tty

    を確保してフック内で対話を 可能にする ランチャ層 scripts/adr-mr.sh 環境ガード(fail-open)・merge-base 差分収集・claude を1 回起動 3 生成層 .claude/skills/* adr-mr-review → visual-mr-review。ファイルに書くだけ (commit / push しない) 4 成果物 docs/ADR/*.md, docs/review/*.html 説明文(なぜ)と 単一HTML(何がどう) 5 運搬層 git notes --ref=mr-review refs/notes/* に載せて push --no-verify .gitlab-ci/visual-review.yml notes を fetch → MR本文 PUT → artifacts → 冪等コメント。AI は動かさない 2 6 反映層 26
  15. ①起動層: lefthook.yml 1 2 3 4 5 6 7 8

    9 10 11 12 13 14 15 16 pre-commit: parallel: true skip: [merge, rebase] commands: biome-check: run: pnpm exec biome check --write {staged_files} stage_fixed: true type-check: run: pnpm exec turbo run type-check --affected pre-push: skip: [merge, rebase] commands: adr-mr: interactive: true run: bash scripts/adr-mr.sh pre-commit = 品質チェック biome --write + stage_fixed:修正結果を自動で 再 add。開発者に再 add を要求しない turbo --affected:影響パッケージだけ型チェッ ク。TURBO_UI=0 でフック内の UI を無効化 skip: [merge, rebase]:コンフリクト解消中に暴 れない pre-push = 対話専用 品質チェックを commit 側に寄せ、push 側を空 けておく interactive: true しないと Claude 呼べない adr-mr.sh を起動するだけ 27
  16. ②ランチャ層: scripts/adr-mr.sh コンテキスト生成 1 2 3 4 5 6 7

    8 9 10 11 12 13 14 15 # --- コンテキストファイル生成 -------------------------------------------------- CTX="$(mktemp -t adr-mr-context.XXXXXX.md)" { echo "# ADR対話コンテキスト (自動生成)" echo "- ブランチ: \`$BRANCH\`" echo "- ベース: \`$BASE_REF\` (merge-base: \`${MERGE_BASE:0:12}\`)" echo "- 説明文の出力先: \`$DESC_FILE\`" echo "- ビジュアルHTMLの出力先: \`$HTML_FILE\`" git log --no-merges --pretty=format:'- %s' "$MERGE_BASE..HEAD" 2>/dev/null git diff --stat "$MERGE_BASE..HEAD" 2>/dev/null git diff "$MERGE_BASE..HEAD" 2>/dev/null | head -2000 } > "$CTX" note "AI ($ADR_TOOL) でADR対話を開始します。ブランチ: $BRANCH" note "コンテキスト: $CTX" 28
  17. ②ランチャ層: scripts/adr-mr.sh プロンプト作成とClaudeの起動 1 2 3 4 5 6 7

    8 9 10 11 12 13 14 15 16 # --- AI起動 -------------------------------------------------------------------- # 生成物は「ファイルに書くだけ」。glab反映・コミット・push は一切させない # (このスクリプトが note に載せて push し、反映は CI が担う)。 PROMPT= "MR用のADR対話を開始してください。adr-mr-review スキルの手順に厳密に従ってください。\ まず最初に「今回はこの処理をスキップしますか?」を確認すること。\ 変更コンテキストは次のファイルを読んでください: ${CTX}。\ 対象ブランチ=${BRANCH} / ベース=${BASE_REF}。\ 【重要】生成物はファイルに書くだけにすること: 確定したMR説明文を ${DESC_FILE} に、\ visual-mr-review スキルで生成したビジュアルレビューHTMLを ${HTML_FILE} に保存する。\ glab によるMR反映・git commit・git push は一切行わない(このランチャが git note に載せて push し、\ MRへの反映と HTML 公開は push 完了後に CI が行うため)。スキップ時は何も書かず正常終了すること。" set +e claude AI_EXIT=$? set -e "$PROMPT" 29
  18. ②ランチャ層: scripts/adr-mr.sh fail-open 失敗してもpushは継続 判定 条件 挙動 明示無効化 / CI

    ADR_SKIP=1 または CI=true exit 0 tty [ ! -t 1 ] || [ ! -t 0 ] exit 0 ブランチ特定 branch が空 or HEAD(detached) exit 0 ベースブランチへの push branch が main / master exit 0 ベース参照の存在 origin/main も main も無い exit 0 AIツールの存在 command -v claude が失敗 exit 0 30
  19. ③生成層: claude/skills/* adr-mr-review で AIから聞かれる内容の粒度を調整 visual-mr-revie でHTMLの内容を調整 1 2 3

    4 5 6 7 .claude/ ├── settings.local.json └── skills/ ├── adr-mr-review/ │ └── SKILL.md └── visual-mr-review/ └── SKILL.md … ローカル設定(git 追跡外) … 構想1: ADR対話 → MR説明文 … 構想2: ビジュアルレビューHTML仕様 31
  20. ⑤運搬層: git notes --ref=mr-review 運搬層構築前の課題 問題A:1push遅延 t0 git push 実行

    t1 push する ref を確定 … HEAD = C3 t2 pre-push フック起動 t3 AI が HTML を生成 t4 git commit → C4 t5 フック終了 t6 C3 まで を push(C4 は含まれない) 問題B:初回push二段階/ref の衝突 初回 push ではリモートにブランチが無く、glab mr create が source_branch: 存在しません(HTTP 400) で失敗する 当時の回避策は、説明文を保存 → push 完了後に claude --continue で再開 → 「反映して」と伝える、手 動の二段階フロー pre-push は push 対象の ref と SHA が確定した後に走る → HTML は次の push で初めてリモートへ。レビュアーがMRを開 いた時点でHTMLが無い 33
  21. ⑤運搬層: git notes --ref=mr-review 段階1 段階2 段階3 段階4 何を送るか決める pre-push

    フック オブジェクト転送 リモートが ref 更新 refs/heads/feat/xxx を 0000000 → C1 に更新したい 段階1の決定を stdin で受け取る ★ AI 対話はここ 段階1の決定どおりに 転送する ここで初めて リモートに ブランチができる フックが呼ばれた時点で、段階1の「何を送るか」はもう確定している ブランチは ref の一種にすぎない refs/heads/feat/xxx ブランチ refs/tags/v1.0 タグ refs/notes/mr-review ノート 34
  22. フックの中で作ったものは「間に合わない」 ローカル 段階1 段階2 段階3 段階4 C1 を送ると決定 pre-push フック

    転送 リモート ref 更新 (C2 はまだ 存在しない) AI対話 → HTML生成 → git commit で C2 決定どおり C1 だけ C2 は置き去り ローカル:C1 → C2 MR作成 リモート feat/xxx 無し 回避策: 先行 push glab mr create ✗ HTTP 400 ここで初めて ブランチができる feat/xxx 無し C1 のみ HTML が無い 受信中… push --no-verify で先にブランチ作成 次 HTML は の push 外側の push ✗ ref already exists まで届かない(1push遅延)/ 説明文は push 後に手作業で反映 35
  23. 別の住所(refs/notes/*)に載せて、反映は CI へ refs/heads/ feat/xxx 段階1 段階2 段階3 段階4 push

    完了後 C1 を送ると決定 pre-push フック 転送 ref 更新 MR パイプライン 0000000 → C1 と決定 触らない 決定はそのまま C1 を転送 リモート = C1 ✓ refs/notes/ mr-review C1 にメモを貼り notes を push MR メモも届いている ✓ メモを fetch して読む ブランチが存在 説明文を本文へ ✓ HTML を公開 ✓ 衝突しない 遅延ゼロ 手作業ゼロ 住所が別なので外側の push と無関係 コミットを増やさず今回の push で完結 MR 反映はブランチ作成後の CI が担当 36
  24. ⑥反映層: .gitlab-ci/visual-review.yml apply-review-note.sh を呼び出す 1 2 3 4 5 6

    7 8 9 10 11 12 13 14 15 16 visual-review:publish: image: node:24 stage: validate needs: [] cache: [] rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" script: - bash .gitlab/scripts/apply-review-note.sh artifacts: expose_as: "Visual Review" name: "visual-review-$CI_COMMIT_REF_SLUG" paths: - visual-review-artifact/ expire_in: 30 days when: always 37
  25. ⑥反映層: .gitlab-ci/visual-review.yml CI での Note の取得およびHTMLをアーティファクトとして公開 1 2 3 4

    5 6 7 8 9 10 11 12 13 14 15 16 # Note を習得する git fetch -q origin "+${NOTES_REF}:${NOTES_REF}" 2>/dev/null || { echo "notes ref を取得できず; skip"; exit 0; } # どのNoteを参照するか git notes --ref="${NOTES_REF#refs/notes/}" show "$SHA" > "$NOTEFILE" 2>/dev/null || true # --- 2) HTML をアーティファクト公開 + DLリンクをコメント ----------------------- rm -rf "$ARTIFACT_DIR"; mkdir -p "$ARTIFACT_DIR" SAFE_BRANCH="$(printf '%s' "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME:-${CI_COMMIT_REF_NAME:-branch}}" | tr '/' '-')" FNAME="mr-${SAFE_BRANCH}-visual-review.html" if printf '%s' "$HTML_B64" | base64 -d > "${ARTIFACT_DIR}/${FNAME}" 2>/dev/null; then LINK="${CI_JOB_URL}/artifacts/file/${ARTIFACT_DIR}/${FNAME}" echo "HTML を ${ARTIFACT_DIR}/${FNAME} に展開しました。" post_or_update_note "$MARKER_VR" "$(printf '## 🖼️ ビジュアルMRレビュー。_\n%s' "$FNAME" "$LINK" "$MARKER_VR")" else fi 38