こんにちは。
前回、うちのコーポレートサイトがある日を境にGoogle検索から丸ごと消えた話を書きました。流入がゼロになった原因を、技術要因を片っ端から潰しながら調べていった記録です(→ サーチコンソールの流入が突然ゼロに。技術要因を全部潰したら「サイトは無実」だった話)。
今回はその続きの、再発防止策です。結論から言うと、原因は技術ではなく 「サイト全体の品質が低いとGoogleに判断された」 が濃厚でした。対策として薄い記事を間引いたんですが、それだけだと 「また薄い記事が積み上がったら同じことになる」。そこで、記事をリリースする前に品質をチェックする“門番”を、CIでClaudeにやらせることにしました。その構築記です。
TL;DR
- 前回の続き。原因は品質っぽい → 薄い記事を間引いた → 今度は「蛇口」を締める(薄い記事を最初から入れない仕組み)
anthropics/claude-code-action@v1で 記事リリース判定CIを作成(ついでにコードレビューCIも)- 認証は
CLAUDE_CODE_OAUTH_TOKEN(claude setup-token→gh secret set) - ハマり①:
--allowedToolsの絞りすぎで「success なのにコメント無言」→track_progress: true - ハマり②:ワークフローがmainに無いと本体スキップ(セキュリティ仕様)→ マージして初めて動く
前回までのあらすじ(なぜ“門番”が要るのか)
流入ゼロの犯人探しは、結局こういう結末でした。
- コード・デプロイ・SSL・DNS・環境変数・Googleのコア更新…技術要因は全部シロ
- Search ConsoleのURL検査は「ページの取得=成功、なのにインデックス未登録」。つまり取得できるのに載せないとGoogleが判断している=品質・信頼性の問題
- 3年間ほぼ無変更のサイトが一斉に落ちた=変わったのはサイトではなくGoogleの評価
対策として、全記事を1本ずつ品質判定して、**一次体験も独自性もない薄い記事を間引き(プルーニング)**ました。でもここで気づくわけです。
間引くだけだと、また同じ薄い記事が増えたら、同じように沈む。
掃除するだけじゃなく、汚れを持ち込ませない仕組みが要る。それが今回の「記事リリース判定CI」です。
作った門番:記事のリリース判定CI
やることは、_posts/ の記事を追加・修正するPRが立ったら、Claudeが「これ公開していい?」を判定してコメントする、それだけです。
on:
pull_request:
types: [opened, synchronize]
paths:
- '_posts/**'
jobs:
judge:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
track_progress: true
prompt: |
追加・変更された _posts の記事を公開してよいか判定してください。
- frontmatterの必須項目(title, excerpt, date, author.name, tags, released)
- author.name が components/person.tsx の著者と一致するか
- 品質:一次体験・独自性・具体性があるか。薄い一般論の焼き直しでないか
- OGP画像 public/assets/ogp/<slug>.webp があるか
結論を「✅ リリース可 / ⚠️ 要修正」で明示してコメントしてください。
判定項目に 「一次体験・独自性があるか」 を入れているのがミソです。今回サイトを沈めた(と思われる)のがまさに「薄い一般論の焼き直し」だったので、そこを門前で弾きたい。
ついでにコードレビューCIももう1本作りました(app/** などソース変更で発火してPRを日本語レビュー)。構成はほぼ同じなので割愛しますが、こっちは純粋に開発の便利枠です。
認証はOAuthトークンで(ghコマンド)
APIキーではなく、Pro/MaxアカウントのOAuthトークンを使いました。コマンドで完結します。
# 1. トークン発行(ブラウザ認証が開く)
claude setup-token
# 2. リポジトリSecretに登録(入力は非表示。履歴に残らない)
gh secret set CLAUDE_CODE_OAUTH_TOKEN --repo <owner>/<repo>
# 3. 確認
gh secret list --repo <owner>/<repo>
--body "<token>" でも入れられますが、トークンがシェル履歴に残るので対話式が安全です。
さて、ここから本記事の存在意義(=2連続で転んだ話)です。
ハマり①:ジョブは成功、なのにコメントが出ない
最初、安全側に倒すつもりで claude_args に --allowedTools "Read,Grep,Glob,Bash" と使えるツールを絞っていました。
PRを立てると、ジョブは緑(success)。なのに PRには何のコメントも出ない。 無言です。
ログを掘ると、こう出ていました。
track_progress: false
--allowedTools "Read,Grep,Glob,Bash"
Claude Code Actionは、レビュー/判定結果をPRコメントとして投稿するのに専用ツールを使います。 ところが allowedTools を読み取り系だけに絞ったせいで、コメント投稿ツールごとブロックしてしまった。 Claudeは判定自体はやったけど「投稿する手段が無い」。だから成功なのに無言。
直し方はこれ。
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
track_progress: true # ← コメント投稿を有効化。これが必須
# allowedTools の過剰な制限は外す
教訓:結果をPRに出すのは
track_progressの仕事。オフのまま「コメントして」と頼んでも、手段が無ければ出ません。
ハマり②:そもそもClaude本体が走ってなかった
①を直して再実行。それでもテストPRで無言。「まだ!?」とログを最後まで読んだら、決定的な一文がありました。
Workflow validation failed. The workflow file must exist and have
identical content to the version on the repository's default branch.
...your workflow will begin working once you merge your PR.
Claude Code Actionは、ワークフローがデフォルトブランチ(main)に存在して内容も同一でないと、本体をスキップする仕様でした。
これはセキュリティ的に正しい挙動です。もし無かったら、悪意あるPRが「CI定義そのものを書き換えて機密を抜くコマンドを仕込む → そのPRのCIで実行」という攻撃が通ってしまう。だから「mainのCI定義と一致しないPR」では動かさない。賢い。
副作用として、「テスト用PRで動作確認する」が原理的にできません(ワークフローがまだmainに無いので当然スキップ)。私はこれに気づかず、テストPRを何度も立てては「なんで動かない…」とやっていました。ログに「マージすれば動くよ」と親切に書いてあったのに、最初スルーしてました。反省。
結論:この手のCIは、いったんmainにマージして初めて動く。
動作確認:この記事自身が、門番に止められた
門番が薄い記事を弾くかどうかは、別途わざと薄いダミー記事(released: false・一次体験ゼロ)でも試して「⚠️ 要修正」を確認済みです。でも一番笑ったのは、この記事そのものをCIにかけたときでした。
released: false のままこの記事のPRを立てたら、判定はこう返ってきました。

- frontmatter・著者・品質は✅(「前回記事の続編として一貫」「コードブロックの開閉OK」「リンクや
relatedPostSlugsも実在確認済み」とまで読み込んでいる) - でも OGP画像が未配置 → ⚠️ 要修正
- おまけに本文に残っていた
<!-- TODO: OGP画像を… -->コメントまで見つけて「消してね」と指摘
自分の記事が、自分で作った門番にOGP忘れを指摘される。 完全にブーメランですが、これこそ狙った動作です(笑)。しかも「品質は合格。あとはOGPだけ」と切り分けてくれるので、何を直せばいいかが一目で分かる。
で、OGP画像を足して本文のTODOを消し、push し直したら——今度は ✅ リリース可 に変わりました。

おまけ:公開OKなら「リリースしていい?」と提案してくる
判定が ✅ になると、門番は続けて released: false → true への変更を提案してきます。実際こう出ました。
前回の指摘事項(OGP画像未配置・TODOコメント残存)はすべて解消されています。
released: false→trueへの変更を提案します。
ただし 自動でコミットまではさせていません。AIに「公開する」判断まで握らせるのはやりすぎだと思っていて、「公開していいよ、押すのはお前だぞ」の一歩手前まで門番がやってくれる、くらいがちょうどいいバランスだと感じています。(※正直に言うと、この提案は今のところサマリーコメント内の提案ブロックとして出ていて、ワンクリック反映できる完全なインライン suggestion には詰めきれていません。ここは今後の宿題です)
まとめ
- 前回「検索から消えた原因は品質っぽい」で終わったので、その再発防止として動いた。
- 掃除(薄い記事のプルーニング)だけでなく、蛇口を締める=リリース前の品質ゲートをCIで用意した。
- 実装は
anthropics/claude-code-action@v1。認証はCLAUDE_CODE_OAUTH_TOKEN(claude setup-token→gh secret set)。 - ハマり①:
allowedTools絞りすぎでコメント無言 →track_progress: true。 - ハマり②:ワークフローがmainに無いと本体スキップ → マージ後に有効化。
- 動作確認では、この記事自身がOGP忘れで「⚠️ 要修正」→ 直したら「✅ リリース可」。おまけに✅のときは
released: trueへの変更まで提案してくれる(自動コミットはさせない)。
SEOで一度痛い目を見たあとだと、この「薄い記事を最初から入れない門番」がやたら頼もしく見えます。効果が出るのはこれからですが、掃除して、蛇口も締めたので、あとは良い記事を積み上げるだけ。再インデックスされるかは引き続き経過を見て、動きがあったら追記します。同じように検索から消えて困っている方の、次の一手の参考になれば幸いです!それではまた!
![[SEO] サーチコンソールの流入が突然ゼロに。技術要因を全部潰したら「サイトは無実」だった話](/assets/ogp/search-console-traffic-zero-canonical.webp)
![[Claude Code] コミットメッセージを考えるのがめんどくさいのでAIに書かせてみた](/assets/ogp/ai-commit-messages-claude-code.webp)