
自社で配布しているWordPressプラグイン「PageGuard」の1.0.0を、実装・レビュー・プルリクエスト作成までAIエージェントに任せて作りました。人がやったのは、仕様を決めることと、マージするかどうかの判断だけです。
この記事は、そのときに分かったことの記録です。ツールの使い方の記事ではありません。使ったのはVK Orchestratorですが、ツール固有の手順は扱いません。ツールは入れ替わっても、「何を、どれくらいの大きさで、どこに書いて渡すか」という部分はそこまで変わらないと思います。
作ったものについては、こちらの記事をご覧ください。
WordPressで特定のページだけにID・パスワードをかける方法
目次
1本のプラグインを、3つのissueに割った
PageGuardは「ページ単位でBASIC認証をかける」プラグインです。これを次の3本に割り、1本ずつ順番に流しました。
– A:認証コア — 認証そのものと、ページごとのユーザー名/パスワードを設定するUI、総当たり対策
– B:裏口経路の除外 — 検索結果・フィード・サイトマップ・REST APIなどに保護ページを出さない
– C:設定画面と1.0.0化 — 対象投稿タイプの選択、ロック中アクセス元の解除、保護中ページ一覧
同時に走らせなかったのは、単純に同じファイルを取り合うからです。並列にしたほうが速そうに見えますが、複数のエージェントが同じファイルに同時に手を入れると、その調整に人が呼ばれます。直列なら構造的に起きません。
結果
3本の実績です。差分・コミット数はプルリクエストに、所要時間は作業ログに残っている実測値です。
| – | A:認証コア | B:裏口経路 | C:設定画面・1.0.0 |
|---|---|---|---|
| 差分 | +14,777 / -20 | +858 / -31 | +1,284 / -24 |
| コミット | 11 | 5 | 2 |
| レビュー | 6巡 | 再レビューで欠陥1件 | 全通過 |
| 実装〜PR | 2時間46分(中断あり) | 中断あり | 1時間28分(中断なし) |
Aの差分が飛び抜けて見えますが、大半は同梱している更新チェック用ライブラリで、自作コードは約2,000行です。それでもBの858行、Cの1,284行より大きく、レビューは6巡かかりました。
なお「中断」は、実行の途中で作業が止まって再開が必要になった回数です。原因は環境側の事情でこの記事の主題から外れるため、内訳は省きます。ここで使うのは「Cだけが中断ゼロで完走した」という事実だけです。
結論:1つのissueに「仕組み」と「画面」を両方入れない
3本を並べると、はっきり出ています。
– A=仕組み(認証・総当たり対策)と画面(編集画面のUI)の両方 → 約2,000行・レビュー6巡・中断あり
– B=仕組みだけ → 858行
– C=画面だけ → 1,284行・レビュー全通過・1時間28分・中断ゼロ
Cは行数だけならBの1.5倍ですが、中断ゼロで完走しています。大きさそのものより、1本の中に性質の違うものが入っているかのほうが効いていました。Aを「認証の仕組み」と「編集画面のUI」に割っていれば、どちらもC程度に収まったはずです。
割り方の目安は、行数ではなくレビューの観点で考えるのが実用的でした。「認証が正しく効いているか」と「画面が使いやすいか」は別の観点で、見る担当も違います。1本に混ぜると、レビューが往復するたびに毎回その両方が動きます。1つのissueに、レビューの観点が1つだけ入るように割る。これが今回の答えです。
issue本文は十数行に絞り、詳細はリポジトリに置く
issueに全部書きたくなりますが、やめました。情報の置き場所を4層に分けています。
| 置き場所 | 書くもの |
|---|---|
| issue本文 | 何ができたら完了か。十数行 |
| docs/spec.md | 確定仕様(正本) |
| CLAUDE.md | 実装上の制約。「やってはいけないこと」 |
| CLAUDE.local.md | 検証環境のパスや資格情報。gitに入れない(配布物にも入らない) |
理由は2つあります。仕様はissueより長生きすること——A・B・Cの3本すべてが同じ仕様を読む必要があり、issueに書くと3回書くことになります。もう1つは、issueは「今回やること」を書く場所であって、恒久的な制約を書く場所ではないことです。
やってはいけないこと
– .htaccess を自動で書き換えない。
他プラグイン・サーバー設定と衝突して500 になったときの復旧コストが重い。診断結果とスニペットの表示に留める。
– 設定済みパスワードを画面に再表示しない。
password_hash で保存しpassword_verify で検証する。文字列比較が要る箇所は hash_equals を使う。
– 「メディアファイルへの直リンクは守れない」を隠さない。
README と管理画面の両方に明記する
検証
– curl による HTTP 実測を主とする
(401 と WWW-Authenticate の有無、-u での 200、REST / フィードの応答)。BASIC 認証の 401 はブラウザのネイティブダイアログなので、ブラウザ自動操作とは相性が悪い
最後の「検証方法を指定する」は、地味ですが効きました。BASIC認証の認証ダイアログはブラウザが出すもので、自動操作では扱いにくい。ステータスコードとヘッダーで機械的に合否が決まる curl に寄せておくと、エージェントが自分で確認でき、そのログがそのまま証跡になります。何で検証させるかまで書いておくと、「確認しました」の中身が揃います。
仕様は、issueを立てる前に固める
PageGuardは、着手前に仕様を10項目まで詰め切ってから起票しました。パスワードの保存方式、サーバーによる差の吸収、どこまでを漏れ対策の範囲にするか、ログイン中のユーザーの扱い、総当たり対策の単位——といった具合です。issue本文が十数行で済んだのは、詰め終わっていたからです。
仕様が固まっていない状態でissueを立てると、エージェントはそれらしい実装を返してきます。しかも、それは動きます。動くので、意図と違うことに気付くのが遅れます。
この「詰める」作業そのものにも、AIとの対話をそのまま使っています。特別なことはしておらず、決まっていない点を1つずつ質問させ、全部答え終わるまで実装に入らせないだけです。この工程を挟むかどうかで、後工程の往復回数がはっきり変わりました。
レビュー役を、観点ごとに分けて直列に置く
実装役の後ろに、観点の違うレビュー役を並べています。
1. コード品質・セキュリティ
2. UX(画面と導線)
3. リリースできる形になっているか(自社事情)
4. 実機での動作確認
VK Orchestratorには既存で役が設定されていますが、独自の役を追加することもできます。3番目は既存の役にはなく、自分で足したものです。見るのは「機能が正しいか」ではなく「出荷できるか」——版数を上げたか、配布ブランチの前提を崩していないか、Requires PHP の宣言と実際のコードが合っているか、READMEと管理画面の文言が食い違っていないか、過去に「やらない」と決めたことを復活させていないか。
作業を始める前に必ず読むもの
1. ~/.claude/etbs-plugin-rules.md — プラグイン共通のルールと過去に踏んだ既知の罠など。
2. 対象リポジトリの CLAUDE.md — そのプラグイン固有の制約
3. 対象リポジトリの CLAUDE.local.md(あれば)
4. リポジトリに docs/spec.md があれば、それも読む
指摘の書き方
– 再現条件を書く。「欠陥がある」と「発火している」は別。誰が・どの経路で・何が起きるかまで示す。
– 根拠を示す。 共通ルールのどの項目に由来する指摘かを明記する。
– 重大度を付ける。 Blocker は「この状態で配布すると利用者に実害が出る」ものだけ。
– 指摘が無ければ「無し」と明記する。数を揃えるために弱い指摘を足さない。
最後の1行は実務的に重要でした。放っておくと、レビュー役は毎回それらしい指摘を並べてきます。「無しと書いてよい」と明示しておかないと、弱い指摘に人の時間が取られます。
事情はエージェント定義に書かない。共通ルール1枚を全員に読ませる
上の定義に、具体的な決まりごとが1つも書かれていないことにお気づきかと思います。これは意図的です。事情はエージェント定義に焼き込まず、全員が読む1枚のファイルに集約しています。
理由は2つあります。
1. 事情はプラグインごとに違い、変わり続ける。定義に焼き込むと、次の案件で嘘になります。
2. その知識が1体に閉じてしまう。レビュー役だけが知っていて実装役が知らない、という状態になり、実装 → 指摘 → 修正の往復が増えます。
そこで共通ルールを1枚のファイルにまとめ、全員に「まずこれを読め」とだけ書きました。新しい罠を踏んだら、このファイルに1行足す。定義側は触りません。
踏んだ罠3つ
1. 共通ルールに書くと、担当外の作業まで拾う
共通ルールに「.gitattributes は必須」と1行足したところ、Aを担当していたエージェントが、別のissueに切り出してあった作業まで先回りして実装しました。
ルールが効いている証拠ではあります。ただし、issueの境界は越えます。境界を守らせたいなら、ルール側ではなくissue側に「今回はやらないこと」を書く必要があります。
2. 過去の判断の蓄積を、丸ごと参照させてはいけない
過去の案件で決めたことの記録が80件以上あったのですが、当初はこれを参照させようとしましたが、やめました。9割が別案件固有のもので、そのまま持ち込むと「過去に決めたことを巻き戻す指摘」が出るため。
いまは索引だけ渡し、関係する1〜2件だけを読ませる形にしています。読ませる範囲を絞るのは、性能のためではなく判断の汚染を防ぐためです。
3. 検証しているのが、実装前のコードだった
エージェントは作業用の複製(worktree)で実装します。一方こちらの検証環境は、シンボリックリンクで元のクローンを指していました。つまり、実装は進んでいるのに、確認しているのは実装前のコードという状態が作れてしまいます。
「動きません」という報告が来たら、まずどこを見ているかを疑ってください。今回はエージェント側がリンクを張り替えて回避しましたが、マージ後に戻す作業が残ります。
「実測で通ったから」でレビューを省かない
Bの再レビューで、こういう指摘が出ました。認証の通過判定を、フックの優先度に依存しない形にすること。他のプラグインが同じフックに同じ優先度で入ると、判定の順番が変わり得るという欠陥です。
このとき、curl での実測は全部通っていました。当然です。実測は「いまのこの環境で通るか」しか見ていません。他のプラグインが入っていない検証環境では、絶対に出てきません。
正直に書くと、「実測で全部通ったのだから再レビューは省いてよいのでは」と考えた場面でした。省かなくて正解でした。
同種のものが、ほかに2件レビューで潰れています。どちらも動かすだけでは出ません。
– アクセス元の丸め方の誤り。IPv6のアドレスを一定範囲でまとめる処理が、IPv4を表す形式(::ffff:1.2.3.4)まで同じ枠に潰していました。この状態だと、すべてのIPv4の訪問者が1つのロック枠を共有します。誰か1人が総当たりで弾かれると、全員が巻き添えです。原因はテストに「同じ範囲」「違う範囲」しか並べていなかったこと。
– 認証領域(realm)の付け方。BASIC認証のrealmをサイト共通にすると、ブラウザは一度覚えた資格情報を、同じrealmの別ページにも先回りして送ります。PageGuardはページごとに鍵が違うので、正規の閲覧者が2ページ目を開くだけで認証失敗が1回記録されることになります。失敗回数はページ単位で数える形に変えました。
人がやったこと
最後に、人の作業を整理しておきます。
– 仕様を詰める(着手前)
– issueを割る(大きさと順番を決める)
– マージするかどうかの判断
– 公開前の実測(未認証のアクセスで全経路を確認する)
実装・レビュー・プルリクエストの作成には手を入れていません。逆に言えば、人の仕事は前工程に寄ります。仕様が固まっていないまま流すと、後工程で全部返ってきます。
まとめ
– 1つのissueに、レビューの観点は1つだけ。仕組みと画面を混ぜない。
– issue本文は十数行。仕様と制約はリポジトリ側に置く。
– 仕様は着手前に固める。固まっていないと、それらしく動くものが返ってくる。
– レビュー役は観点で分けて直列に。最後に「出荷できる形か」を見る役を置く。
– 事情はエージェント定義ではなく、全員が読む1枚のファイルに集約する。
– 実測で通ったからといって、レビューを省かない。
このやり方で作ったPageGuardは、無料で配布しています。中身の紹介はこちらの記事にまとめました。
https://etbs.jp/blog/pageguard/
WordPressプラグインの開発・カスタマイズのご依頼は、弊社サポートページ からお問い合わせください。
自己紹介
インディーズでミュージシャンをやっていたのですがいつのまにか…
とある企業でショップのアルバイトスタッフから正社員、支店長を経てシステム部門に異動するという、開発担当としては変わった経緯を持っている方だと思います。
「Excel VBA」からスタートして、Yamaha RTX シリーズで VPN環境構築、Hyper-V環境構築、Windowsアプリ開発などを経験した後、「 WordPress 」に出会い、どっぷりハマっています。
現在勤めているETBS合同会社では、「 WordPress 」を活用したWEBサイト、業務用WEBアプリケーション開発を中心に、記事の執筆代行や掲載に必要な情報のリサーチ、映像のテロップ入れや切りはりなどの簡単な動画編集なども、まとめて行なっています。
宮崎県 都城市 出身。東京都 葛飾区 在住。現在、代表兼二児のパパ。子育てを通じて、こどもたちにもプログラミングの楽しさに触れてほしいと思うようになり、「 こどもICTかつしか教室 」を開講中。最近は童心に帰り、簡単なゲーム制作なんかも楽しんでいます(^_^)。






コメントを残す