SKILL.md

.claude/skills/article-review/SKILL.md(119 行)

SKILL.md
---
name: article-review
description: >-
  ブログ記事の統合レビュー指揮役スキル。config.yaml の設定に従い、機械計測(scripts/review_metrics.py)→
  レビュアー並列起動 → 2層ゲート判定 → リライトループ → (任意)6軸ロールアップ → レビューサマリー出力 →
  公開前の鮮度照合(md5)までを通しで進める。「レビューして」「公開前チェック」「記事レビュー」「総合レビュー」
  「記事を1本仕上げて」等の依頼時、または記事を新規作成・大幅加筆・リライトしたときに、明示依頼が無くても
  公開前に必ず使う。記事本体は書き換えない(修正は blog-writer に差し戻す)。合格しても自動では公開しない。
---

# article-review(記事レビュー指揮役)

本スキルは**指揮役**。採点・指摘はレビューエージェント、修正は `blog-writer` に任せ、ここでは「並列起動・ゲート判定・リライトループ・ロールアップ・統合レポート・運営者へのエスカレーション」だけを行う。

**鉄則**: 記事本体は書き換えない(修正は `blog-writer` のレビュー反映へ)/本文を1文字でも変えたら公開前に再レビュー(md5 で機械的に担保)/同じ層のレビューは1メッセージで並列起動/合格点・ループ上限・レビュアー編成・優先順・フォルダはすべて `config.yaml` の値を使い、このスキルの中で数値を決めない。

以下、`{paths.X}`・`{gate.X}` は `config.yaml` の該当キーの値を指す。最終判断をする人は `operator_name` の呼び方で呼ぶ(本文では「運営者」)。

## STEP 0. 設定の読み込み(必ず最初に)

1. プロジェクトルートの `config.yaml` を Read する。無ければ「`config.example.yaml` を `config.yaml` にコピーして埋めてください」と伝えて止まる
2. **`gate.pass_score` または `gate.max_rewrite_loops` が空なら、採点を始めずに止まり、運営者に値を尋ねる**(推測で補わない。既定値は無い)。`site.key`・`site.name`・`site.domain` が空のときも同じ
3. `gate.target_score` が空なら合格点と同じ値として扱う
4. 記事パス(または slug)が未指定なら運営者に確認する。記事の原本は `{paths.articles}/{slug}.md`(または `.html`)。`{paths.public}` は触らない
5. `site.project_instructions` と `site.writing_guide` を読む(各レビュアーの起動指示にもこの2ファイルのパスを含める)

**フルパイプライン**(「記事を1本仕上げて」): `blog-idea-scout` でテーマ確定(`{paths.ideas}`)→ `blog-researcher` で一次情報の裏取り(`{paths.research}/{slug}.md`)→ `blog-writer` で執筆 → STEP 1 へ。

## レビュー体制

config のレビュアー名とエージェントの対応:

| config の名前 | エージェント | 担当 |
|---|---|---|
| `legal` | `legal-reviewer` | 景品表示法・ステマ規制・広告プログラムの規約・YMYL・著作権・AI透明性 |
| `consistency` | `consistency-reviewer` | 数値/件数の矛盾・二重構成・コードと事実の整合・鮮度・校正 |
| `confidentiality` | `confidentiality-reviewer` | 発信者や第三者が特定される情報・個人情報の写り込み |
| `seo` / `cro` | `growth-reviewer` | SEO と収益導線(1回の起動で2つのスコアを別々に出し、`seo_`・`cro_` の2ファイルに出力) |
| `panel` | `blog-readers-panel` | 読者体験(ピラー記事・収益記事はフル会議、通常記事は軽モード。運営者の指定があればそれに従う) |

- **TIER1(`gate.tier1`)**: 必須指摘が1件でもあれば点数に関係なく止める層
- **機密レビュー**: `gate.confidentiality_required` が true なら `confidentiality-reviewer` を TIER1 に加え、**毎巡フルで実行**する。高リスクの指摘が1件でもあれば、点数に関係なく公開を止める。false のときは運営者が指定した場合だけ起動する
- **TIER2(`gate.tier2`)**: 合格点で判定し、リライトループの対象になる層。`gate.skip_cro_for_non_monetized` が true で広告を置かない記事なら、CRO は採点しない(`growth-reviewer` の起動時に「SEO のみ」と指示する)

## STEP 1. 並列レビュー(1巡目)

起動前に指揮側で機械計測を実行し、**計測結果の全文と記事の md5** を各レビュアーの指示に含める(md5 は鮮度スタンプ):

```bash
python -X utf8 scripts/review_metrics.py {記事パス} --config config.yaml
```

- 指揮側で**巡タイムスタンプ `TS = YYYYMMDD-HHMMSS`** を採番し、全員の指示に含める(レビュアーは現在時刻を取れない)。同じ巡は全員同じ TS=TS が巡IDを兼ねる
- 出力先は `{paths.reviews}/{レビュアー名}_{slug}_{TS}.md`(レビュアー名は config の名前。全版保存・上書き禁止・再レビューは新しい TS で新ファイル)。複数記事をまとめて見るときは `{レビュアー名}_batch-{テーマ}_{TS}.md`
- 各レビュアーは、冒頭に100点満点のスコア、指摘ごとの「🤖 blog-writer で直せる/🧑 運営者の手作業が要る」タグ、到達見込み(🤖 をすべて直した場合の上限点)を返す
- **レビューMDの冒頭に機械可読の frontmatter を必ず付ける**(無いとレビューログから漏れる)。起動指示にこの規定を含める:

```yaml
---
reviewer: legal              # ファイル名のプレフィックスと同じ語
date: YYYY-MM-DD HH:MM:SS    # 指揮が採番した TS と同時刻
articles:                    # 対象 slug を全列挙・値=今回のスコア(未採点は null)
  sample-article: 97
---
```

記事以外(テンプレート・CSS・固定ページ)が対象なら frontmatter は省略してよい。

## STEP 2. ゲート判定

- TIER1 に必須指摘が1つでもあれば**スコアに関係なく即停止**し、警告を付けて運営者にエスカレーションする(機密レビューの高リスク指摘・法令違反の疑いも同じ扱い)
- TIER1 をクリアしたら、**合格=起動したゲート対象の全員が `gate.pass_score` 以上、かつ必須指摘0**。目標は全員 `gate.target_score` 以上

## STEP 3. 到達可能性チェック

到達見込みが全員 `gate.pass_score` 以上ならリライトへ進む。**🧑 起因(実機写真・実測・実体験など、運営者にしか用意できないもの)で合格点に届かないなら、ループせず即停止**し、運営者にやってほしいことを添えてエスカレーションする。

## STEP 4. リライトループ(上限 `gate.max_rewrite_loops` 回・差分方式)

1. 指摘を集約して `blog-writer` に差し戻す(TIER1 の必須指摘が最優先)。差し戻しには **①各レビューの「維持すべき強み」=変更禁止リスト ②反映対象レビューMDの最新版パス**(`{paths.reviews}` を全部読ませない)を必ず添える。指摘同士がぶつかったら **`gate.conflict_priority` の順(左が強い)**で裁定し、採用しなかった理由を記録する
2. 再実行するのは**前巡で不合格だったレビュアー+TIER1 全員**だけ。合格済みのスコアは維持する。`growth-reviewer` は片方だけ不合格なら「◯◯観点のみ再レビュー」と明記し、該当ファイルだけ更新させる
3. 2巡目以降の TIER1 は**軽量再監査**(指示に「軽量再監査・前回版={パス}・変更差分={要約}」を明記。フルは初回・全面改稿・広告や開示を変えたときだけ)。**例外: 機密レビューは毎巡フル**
4. `build_check_command` が設定されていれば実行し、エラーが無いことを確認する
5. 停止条件: (a) 全員が合格点以上+必須指摘0 → 合格 / (b) ループ上限に到達 → 停止し、スコア推移・残った指摘・収束しにくい理由・推奨アクションを報告 / (c) 🧑 起因で合格点に届かない → 即停止。各ループでスコア推移を記録する
6. ループ完了時に旧版を `{paths.reviews}/archive/` へ移す: `python -X utf8 scripts/archive_reviews.py --apply`

## STEP 5. 6軸ロールアップ(任意)

運営者が「総合点を出して」と求めたときに行う。各レビュアーのスコアと指摘を `docs/blog_article_rubric.md` の6軸(配点・内訳・減点トリガー・判定帯はルーブリックが正)に集約する。

| 軸 | 集約元 |
|---|---|
| 1 検索意図・結論ファースト | seo |
| 2 E-E-A-T | seo(panel を起動していれば Experience に加味) |
| 3 正確性・一貫性 | consistency |
| 4 構成・読みやすさ | panel(未起動なら consistency+seo で代替) |
| 5 法令・規約 | legal |
| 6 技術SEO・収益導線 | seo+cro |

各軸に根拠を1行付ける。リライト優先度は **(100−総合点)×月間表示回数**(表示回数は `blog-analytics` の実測。憶測で作らない)。

## STEP 6. レビューサマリー(1巡ごとに必ず出力)

`{paths.reviews}/review_summary_YYYYMMDD.html`(自己完結HTML・CSS/JS はインライン・表は `overflow-x: auto`。同じ日の再実行は上書き統合し、複数記事・複数ループも1枚にまとめてスコア推移を履歴として残す)。

- 含める要素: 対象記事・レビュー日・ループ N/上限/全体判定(🟢合格/🔴継続/⚠️停止)/記事×レビュアーのスコア表(合格点以上=緑・未満=赤・到達見込みと🤖/🧑を併記)/コメント要約/必須対応と🧑の一覧/(6軸を出したとき)6軸表+総合点+判定/複数記事なら合格数・平均点・優先度順
- 生成後、運営者にパスを伝える。スコアはレビューMD最新版と矛盾させない。`{paths.reviews}` は公開フォルダの外に置く
- 出力後に `python -X utf8 scripts/review_log.py` で `{paths.reviews}/review_log.md` を再生成する

## STEP 7. 公開前ゲート(合格しても自動では公開しない)

- **鮮度照合**: `review_metrics.py` をもう一度実行し、各最新レビューMDに記録された md5 と現在の記事の md5 を照合する。不一致=未レビューの変更があるので、再レビューが済むまで公開に進まない
- 広告プログラムへの申請前は、`legal-reviewer` の**精密監査モード**(`docs/legal_audit_rubric.md`)を追加で実行する
- 法令・広告表記・機密に関する最終的な公開判断は運営者が行う。合格でも「公開してよい」と自動で判断しない。ビルド・公開作業は**運営者の明示的な指示があってから**
- 軽微な修正でも、公開前に最低限 `legal-reviewer`(ゲートモード)と `build_check_command` を通す

## 既知の限界

6軸ロールアップは編集判断を含む近似/合格点に正解は無く、運用しながら調整する/点数は検索順位を保証しない(Search Console・GA4 の実データと併用する)/サイト全体の監査は、本フローを記事群に回して集計する。レビュー対象は実測データで選ぶ。

MIT ライセンスで配布しています。