# Repo Review

> 任意のリポジトリ（アプリ/ライブラリ/運用スクリプト/コンテンツ等）の種別を判定し、 種別に応じた評価軸（品質・テスト・依存、または検証ゲート等）で**実測ベース**評価して優先度付き改善案を出すスキル。 言語非依存（Python は AST 詳細・その他は近似と明記）。ベンダーコード混入・除外の空振り・偽の成功終了コードなど、 「黙って間違った数値を出す」失敗を構造的に封じる。 「リポジトリレビューして」「コード品質を評価して」「このプロジェクトを診断して」「包括レビュー」「repo-review」 「アーキテクチャ評価して」等で発火。/repo-review でも起動。

- Skill: `fukukei23/repo-review` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds add fukukei23/repo-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/fukukei23/repo-review/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: fukukei23 (https://skillmd.com/u/fukukei23)
- Updated: 2026-08-19
- Page: https://skillmd.com/skills/fukukei23/repo-review

---


# repo-review — リポジトリ包括レビュー

## 棲み分け（先に確認）

| 目的 | スキル |
|---|---|
| **実績数値**を正確に計測して SSOT/経歴書に記録 | `code-metrics` |
| **品質・設計を評価**して改善案を出す（本スキル） | **repo-review** |
| 差分（PR/コミット）のレビュー | `engineering:code-review` |
| 複数LLMに批評させて改訂案を作る | `multi-llm-review` |

本スキルは**コードを変更しない**（レビューのみ）。

---

## 大原則（これを破ったレビューは価値がない）

1. **推測で数値を書かない。** 実行して数える。実行できなかったものは「未検証」と明記する
2. **一般論を書かない。** すべての指摘に `file:line` または関数名を引用する
3. **根拠のない称賛を書かない。** 強みにも実測の裏付けを付ける
4. **終了コードを信じない。** 出力本文を読んで成功を判定する（後述 Phase 3）

---

## Phase -1: 既存レビューの検出（🔴 最初にやる・省略禁止）

**同じリポジトリが既にレビュー済みかを必ず先に調べる。** 調べずに始めると、前回より粗いレビューを
やり直して「新発見」として報告する事故が起きる。

```bash
# 1. バックログに完了済み/進行中のレビュータスクがないか
grep -n "包括レビュー\|repo-review\|レビュー" ~/projects/obsidian-ssot/00_SYSTEM/バックログ.md | grep -i "<repo名>"

# 2. 過去のレビュー記録（_INDEX.md は信じず実ファイルを直接見る）
ls ~/projects/obsidian-ssot/01_DECISIONS/<repo名>/ | grep -iE "レビュー|review|監査|audit"

# 3. 未マージのリモートブランチ上にレビューが無いか（ローカルだけ見ると取りこぼす）
git -C <REPO> fetch origin && git -C <REPO> branch -r | grep -iE "review|audit"

# 4. CI実行履歴のタイトルに既存レビューが無いか（← ここでしか気づけないケースがある）
gh run list --limit 10 -R <owner>/<repo>
```

**探索先は4つとも見ること。** SSOT（`01_DECISIONS/`）とバックログだけでは、
**未マージブランチ上・CI履歴上のレビューを取りこぼす**。

### 見つかった場合の分岐

| 状況 | 対応 |
|---|---|
| **完了済みレビューがある** | **差分レビューに切り替える**。前回の実測値を読み込み、今回は「前回から何が変わったか・前回の指摘は解消されたか・前回が見ていない観点」に絞る。**同じ数値を再掲しない** |
| 進行中（🟢）のレビューがある | 重複着手の soft 警告をユーザーに出す（`active-sessions.md` 参照） |
| 未マージのレビューブランチがある | そのブランチの内容を先に確認する。マージ判断がバックログに残っていないか調べる |
| 何も無い | 通常フロー（Phase 0 へ） |

> ⚠️ **実例1（2026-08-13・CI履歴でしか気づけなかった）**: `atelier-kyo-manager` のレビュー時、
> 既存レビューが**未マージのリモートブランチ上**にあり、SSOT と `docs/` を見ても発見できなかった。
> 偶然 `gh run list` の displayTitle（「包括的リポジトリレビュー（2026-08-12）」）で気づいたが、
> **気づかなければ14指摘を初出のように再掲していた**。
>
> ⚠️ **実例2（本スキル自身が踏んだ）**: 2026-08-17 に `atelier-kyo-manager` をレビューしたが、
> **08-13 に別セッションが同じプロンプトで実施済み**だった（バックログ L304 `[x]`）。
> しかも前回のほうが詳細で（CC平均5.64/中央値4・型注釈率73.4%・エンドポイント103中99が
> `@login_required`）、**P0の機能停止級バグ（Celery配線）まで発見・修正済み**だった。
> さらに悪いことに、バックログには既に
> **「repo-comprehensive-review.md プロンプト改良（既存レビュー検出手順の追加）」というタスクが
> 起票されていた**（L250）。**その存在に気づかず、まさにその問題を再演した。**

**教訓**: 過去経緯の探索は `_INDEX.md` を信じず**バックログと実ファイルを直接 grep** する
（`00_SYSTEM/チャーター.md`「読者前提」・`rules/_shared/LLMサボりバイアス防止.md`「タスク再着手時の必須検索」）。

---

## Pre-flight: 浅い用途でないかの確認（1問・Phase 0 の前）

スキル発火時に最初に1問だけ確認する:

> 「タイポ確認・特定ファイル1つの指摘など**浅い用途**ではありませんか？　（浅いなら本スキルでなく
> 通常のRead/Grepで対応します。包括評価ならこのまま進めます）」

浅い用途に大掛かりな6 Phaseを回すのは過剰（ユーザー・トークンの無駄）。**包括評価のみ Phase 0 へ進む。**

---

## Phase 0: リポジトリ種別の判定（Phase -1 の次・省略禁止）

**種別を誤ると評価軸ごと間違える。** 以下を測ってから分類する。

```bash
python3 <skill>/scripts/repo_metrics.py <REPO>
```

| 種別 | 判定条件（暫定閾値） | 評価軸 |
|---|---|---|
| **アプリケーション** | コードLOC > ドキュメントLOC・エントリポイントあり（main/実行スクリプト） | 全6観点（標準） |
| **ライブラリ/SDK** | 公開APIがある・利用側リポジトリが別・エントリポイントなし | API安定性・後方互換・型定義を重視 |
| **運用スクリプト集** | 依存宣言なし・`src/` なし・CI薄い | 「実行手段の文書化」「再現性」を重視。カバレッジは問わない |
| **コンテンツ** | ドキュメントLOC > コードLOC×3（目安 3:1超） | **コード品質より「コンテンツの検証ゲート」の有無**を評価 |
| **ハイブリッド（複合型）** | 複数種別の条件を同時に満たす（例: コンテンツ+運用スクリプト） | **両評価軸をマージ**して両方報告 |

### 判定ルール（暫定閾値・フェイルセーフ）

- 閾値は暫定。**判定に迷ったら必ずフルレビュー側（アプリケーション評価軸）へ倒す**（フェイルセーフ:
  浅く評価して見落とす害 > 深く評価して手間が増える害）
- スタックマーカーが複数ある（モノレポ）場合は、**サブディレクトリごとに種別判定と評価軸を分ける**
  （例: `web/` はアプリ・`packages/lib/` はライブラリ・`docs/` はコンテンツ）
- 判定根拠（どのLOC・マーカーで分類したか）は Phase 2.5 で検証するので残しておく

> ⚠️ **実例**: `zenn` は記事18,093行 vs コード1,283行（12.6:1）。`package.json` があるため素朴には
> "Node/JS-TS アプリ" と判定されるが、**JS/TS のコードは0行**（`zenn-cli` 用の設定ファイルだった）。
> **スタック判定は「設定ファイルの存在」でなく「実際のコードLOC」で裏取りすること。**

---

## Phase 1: 除外の確定（🔴 最重要・ユーザー確認必須）

**固定の除外リストは新しい生態系に必ず負ける。** 機械的に候補を列挙して**ユーザーに確認する**。

### 1-1. 既定の除外

正典はスクリプト側 `scripts/_shared.py` の `DEFAULT_EXCLUDE`（単一ソース・2026-08-18 critical対応）。

```
.git node_modules vendor .venv venv dist build target
__pycache__ .next coverage .mypy_cache .pytest_cache .ruff_cache htmlcov
.gradio mutants site-packages .terraform
```

除外指定は**ベース名（`node_modules`）とパス（`backend/plugins`）の両方**が効く（`_shared.py prune_dirnames`）。
対象リポジトリの生成物ディレクトリはパス指定で除外する。

### 1-2. 候補の機械的検出（既定リストで足りない分）

トップレベルの各ディレクトリについて LOC を出し、**次に該当するものを除外候補として提示**する:

- ディレクトリ名に `plugin` / `cache` / `marketplace` / `example` / `sample` / `fixture` / `third_party` / `external` を含む
- **同一ファイルが2箇所以上に存在する**（`cache/` と `marketplaces/` のような二重取り込み）
- リポジトリ総LOCの **30%以上を単独で占める**が、コミット履歴にほとんど出てこない

```
🔍 除外候補（確認してください）
   plugins/   271,207 LOC  ← 外部プラグイン取込・cache/ と重複
   skills/    183,232 LOC  ← マーケットプレイス由来
   .claude/   110,815 LOC
   これらを除外しますか？[y / 個別指定]
```

> ⚠️ **実例**: `claude-config` で除外しなかった場合 Python 88,330行と出たが、実体は **18,791行（4.7倍の誤差）**。
> さらに**最も複雑な関数の上位8件が全て他人（Anthropic公式プラグイン）のコード**で、
> `marketplaces/` と `cache/` に**同一関数が二重計上**されていた（CC=82 が2件）。

### 1-3. 除外が効いたことの検証（省略禁止）

除外を適用したら、**除外前後の数値を並べて確認する**。桁が変わったら除外が効いた証拠。効いていないのに気づかない事故を防ぐ。

> ⚠️ **実例**: `find . -path ./plugins -prune -o -name 'test_*.py' -print` の prune が効かず、
> テストファイル **2,429件（実際は44件・55倍）** と出たがエラーは一切出なかった。
> **`find -prune` は使わない。** Glob ツール / ripgrep の `--glob '!dir'` を使う。

---

## Phase 2: 計測

```bash
# 言語別LOC・ディレクトリ別LOC・Python複雑度・カバレッジ所在
PYTHONIOENCODING=utf-8 python3 <skill>/scripts/repo_metrics.py <REPO> [除外dir...]

# テスト/ソースの分離（テストが src ツリーに混在していても正しく出る）
PYTHONIOENCODING=utf-8 python3 <skill>/scripts/split_tests.py <REPO> [除外dir...]
```

### 2-1. 複雑度の扱い（🔴 言語で精度が違うことを必ず明記）

| 言語 | 手段 | 報告時のラベル |
|---|---|---|
| **Python** | 同梱スクリプトの AST 解析 | 循環的複雑度（正確） |
| JS/TS | `node_modules/acorn` があれば AST。無ければ**分岐キーワード密度**で代用 | **「近似値」と明記**・Python の CC と直接比較しない |
| Go / Rust / Java | `gocyclo` 等の既製ツールがあれば使用。無ければファイルLOCと分岐密度 | **「近似値」と明記** |

> ⚠️ **実例**: `reserve-optimizer`（JS 26,201行）で、Python の AST しか持たないスクリプトが
> **本体JSを一切測らず、デモ録画用の Python 1,310行だけを測って「最大CC=32」と報告**した。
> エラーは出なかった。**対象言語のLOCと、実際に解析した関数数が桁で合っているかを必ず突き合わせる。**

### 2-2. 複雑度は「率」と「最大値」の両方を見る

片方だけでは判断できない。

```
NexusCore : CC>20 が 16/1020 (1.6%)  最大CC=31
atelier   : CC>20 が 51/3537 (1.4%)  最大CC=63   ← 率は同等だが最大値が2倍
```

### 2-3. テスト件数の数え方（言語・フレームワークで違う）

| 環境 | 数え方 |
|---|---|
| pytest | `^\s*def test_` |
| jest / vitest | `it(` / `test(` |
| 自作ランナー | `assert` 呼び出し数などで代用し、**代用したことを明記** |

**テストの所在は1箇所とは限らない。** `tests/` だけ見て数えると過小評価する。

> ⚠️ **実例**: `claude-config` は `tests/` だけで168件だったが、実際は5箇所に分散して **448件（2.7倍）**。

### 2-4. カバレッジ

既存レポート（`coverage.xml` / `lcov.info` / `coverage.out`）をパースし、**生成日時を必ず報告する**。

- **バイナリの `.coverage` しか無い場合** → `coverage report` を試す。それも不可なら**「未計測」と明記**
- **レポートが無い場合** → 「カバレッジは測定手段自体が未整備」と書く。推測値は書かない

> ⚠️ **実例**: `atelier-kyo-manager` の `.coverage` は**2.5ヶ月前**のものだった。

### 2-5. LFS ファイルの検出

`.gitattributes` に LFS パターン（`filter=lfs`）があるか最初に確認する。ある場合:
**LFSポインタファイル（130バイト程度のテキスト）を実ファイルと混ぜて LOC に含めない**。
ポインタ実測は `git lfs ls-files` または対象拡張子ファイルのサイズ確認で行う。

> ⚠️ **実例**: `atelier-kyo-manager` は png 908件が LFS ポインタ化しており偽差分の温床になった。

---

## Phase 2.5: 計測健全性チェック（🔴 新設・省略禁止・Phase 3 の前）

計測結果が「黙って間違っている」可能性を Phase 3 以降に進む**前に**検査する。3項目全部確認:

1. **総LOC > 0** — 主要言語のLOCが0なら計測自体が失敗（除外過剰・パス違い）
2. **解析失敗件数の確認** — `repo_metrics.py` 出力の「⚠️ 解析失敗: N件」。N>0 は未検証事項への記載が必須
   （古いPythonで全ファイルSyntaxError→LOCは出るが関数0個報告、という最悪ケースが実在）
3. **種別判定の根拠と計測内容の一致** — Phase 0 の判定根拠とした言語のLOCと、実際に解析できた
   関数数・ファイル数が**桁で合っているか**を突き合わせる

**異常を検出したら残りの Phase を中断し、「計測不能の理由」を未検証事項として報告する。**
測定不能を誠実に返す停止条件（MiniMax critical指摘・2026-08-17 レビュー）。

---

## Phase 3: 実行系の検証（🔴 終了コードを信じない）

lint / 型チェック / テストを**実走**する。ただし:

### 失敗を成功と誤認する既知パターン

| 症状 | 見分け方 |
|---|---|
| **UNC パスで npm/node が動かない** | 出力に `UNC パスはサポートされません` / `CMD.EXE` / `C:\Windows` が出る。**それでも exit 0 になる** |
| ツール未インストール | `command not found` だが CI 上では通る等 |
| 権限拒否 | 実行自体がブロックされる |

**判定は終了コードでなく出力本文で行う。** 上記が出たら「未検証」として報告する。

> ⚠️ **実例**: `npm test` が `Cannot find module 'C:\Windows\tests\run-all.js'` で失敗したのに
> **exit 0** を返した。終了コードを信じていたら「テスト通過」と誤報告していた。

### CI の実態確認（宣言との突き合わせ）

CI 設定を**実際に読み**、走っているジョブと対象ディレクトリを列挙する。README の主張と突き合わせる。

> ⚠️ **実例**: `reserve-optimizer` の CI は29行・単一ジョブで `working-directory: worker` のみ。
> **本体の gas-project 14,894行と32テストファイルは push/PR で一度も実行されていなかった。**

---

## Phase 4: 分析6項目

1. **プロジェクト構造** — 構成の妥当性 / モジュール依存 / 命名 / **実行コードが何箇所に分散しているか**
2. **コード品質** — 複雑度分布 / 保守性 / 重複コード
3. **テスト** — 件数・比率・低カバレッジ領域 / **単体・統合・E2E の区別が実態として機能しているか**
4. **アーキテクチャ** — 層構造が守られているか（**逆流・循環**）/ スケーラビリティ / セキュリティ
5. **ドキュメント** — README の**記述と実体の一致** / docstring 品質
6. **依存関係** — 適切性 / **未使用依存** / バージョン整合性 / 脆弱性

### よくある実態（チェックリスト）

- [ ] **テストは書かれているが CI で走っていない**（5リポジトリ中3件で発生）
- [ ] テストマーカー/タグが定義だけされて実使用ゼロ
- [ ] 依存宣言に未使用パッケージ（**削除提案には動的import確認と削除後スモークを条件に付ける**）
- [ ] 言語バージョンが複数ファイルで食い違う
- [ ] README に存在しないディレクトリが書かれている

### 未使用依存の判定（誤判定しやすい）

静的検索だけを根拠にしない。

- **文字列リテラル内の import** をヒットさせない（サンドボックス用テンプレート等）
- **動的ロード**（`importlib` / `require(変数)` / `entry_points` / DI / リフレクション）の有無を先に調べる
- 削除提案には必ず「**削除後にフルテスト＋起動スモーク必須**」を条件として添える
- **依存削除の実行は本スキルでは行わない**（提案のみ・実行は対象リポジトリ側のタスクとして切り出す。
  本スキルはコードを変更しない大前提と整合）

---

## Phase 5: 出力

1. **エグゼクティブサマリー**（1〜2段落）＋ 専門知識のない人向けの平易な要約を併記
2. **強み Top5** — 各々に実測の根拠
3. **改善領域 Top10** — 優先度順・各項目に `file:line`（**種別テーラリング**: コンテンツ/運用スクリプト集と
   判定した場合は、改善領域の評価軸を Phase 0 の種別評価軸へ差し替える——例: コンテンツなら
   「検証ゲートの欠落」を、運用スクリプト集なら「再現手順の未文書化」を上位に置く）
4. **具体的推奨事項** — **実行可能なコマンド・変更箇所**を含む。着手順序と所要時間の目安も
5. **メトリクス表** — 規模 / カバレッジ / 複雑度 / アーキテクチャ / 依存
6. **未検証事項**（省略禁止）— 実行できなかった計測・古いデータ・確認しきれなかった前提

### 未検証事項のフォーマット（4要素必須）

各項目に **①Phase番号 ②計測項目 ③失敗理由 ④次に実行すべきコマンド** を必ず揃える。
（例: 「Phase 3 / テスト実行 / UNC パスで npm が起動せず exit 0 / `wsl bash -c 'cd <repo> && npm test'`」）

### Top10 のソート規則

優先度（P1→P3）順・**同一優先度内は影響行数（LOC・CC・対象関数数）の降順**で並べる。

### 優先度基準

- **P1** — 放置コストが継続発生（CI時間・脆弱性・誤った数値の対外公開）かつ**機械的作業で解消可能**
- **P2** — 構造的負債（今は動くが変更コストを上げ続ける）
- **P3** — 品質の実質（数値は良いが実効性に疑問）

---

## 環境上の注意（Windows Desktop + WSL の UNC 経由）

- `grep -r` / `find` は**2分でタイムアウトする**。**Grep ツール（ripgrep）/ Glob ツールを使う**
- cwd が UNC 配下だと**絶対 UNC パスへの再 `cd` が二重解決で失敗**する。既知の基点から相対で移動する
- Python 出力が文字化けする → `PYTHONIOENCODING=utf-8` を付ける
- `~/.claude/skills` 等が **I/O エラーで読めない**ことがある。`Path.exists()` の False は
  「無い」ではなく「**読めない**」かもしれない

### WSL ネイティブでは不要（2026-08-17 実測検証済み）

WSL 側（`/home/...` 配下）では上記 UNC 起因の摩擦は**発生しない**。実測（zenn リポジトリ・2026-08-17）:

| 摩擦点 | WSL ネイティブ実測 |
|---|---|
| `grep -r` / `find` タイムアウト | **0.025s / 0.147s** で完了（2分タイムアウトは UNC 起因） |
| `cd` の二重解決失敗 | 絶対パス再 `cd` 正常動作 |
| `PYTHONIOENCODING` なしの文字化け | **化けない**（WSL ロケールが UTF-8 のため・付けても害はないので Windows 併用なら付けたまま） |
| `npm test` の偽 exit 0 | **再現しない**（`MODULE_NOT_FOUND` で exit 1 を返す・node v20 実測） |

⚠️ 例外: **`/mnt/c/...` 配下のリポジトリを WSL から見る場合**は Windows FS 経由の I/O 遅延が
残るため、上記 UNC 時代の注意が依然有効。UNC 特有の問題は「UNC パス（`//wsl.localhost/...` または
`\\...`）経由」か「/mnt/c 経由」かで発生条件が変わることに注意。

---

## 複数リポジトリを続けて見るとき

**1リポジトリだけでは基準が持てない。** 比率や閾値は横断で初めて意味を持つ。

```
test:src 比の実測レンジ（同一ユーザーの5リポジトリ）
  NexusCore 3.10 / reserve-optimizer 0.74 / atelier 0.59 / claude-config 0.30 / zenn 0.15
→ 「0.59 は低い」とは言えない。種別と CI 実行有無をセットで見る
```

**このレンジは参考値であって閾値ではない。** 「0.15未満は赤」のような判定線として使わないこと。

横断で見たら、**個々では見えない共通パターン**（例:「テストは書くが CI に繋いでいない」）を必ず報告する。

---

## トリガーワード

「リポジトリレビューして」「コード品質を評価して」「このプロジェクトを診断して」「包括レビュー」
「アーキテクチャ評価して」「技術的負債を洗い出して」/ `/repo-review`

