「動いていないコード」の棚卸し — 未使用スクリプトの退役判断と形骸化した番犬の修正
今回やったこと
手順書やルール文書に「必須」と書かれていたスクリプトが、実際には自動パイプラインのどこからも呼ばれておらず、本番記事にも長期間出力されていなかったことが判明した。対象は物販アフィリエイトの推薦ブロックを生成する scripts/amazon_recommender.py である。
このコードを復活させるべきか、削除すべきか、あるいは退役として残すべきかを実測値に基づいて切り分けた。さらに、この棚卸しの過程で「テストでNGを出力しているのに終了コード0で通過していた番犬」と「正規表現の前提がズレて本番記事のリンクを1件も検査していなかったバリデータ」の2つが見つかったため、合わせて改修した。
コードがリポジトリ内に存在すること、自動化から実行されていること、そしてテストや検査が実際に失敗を検知して止めることは、すべて別々に検証しなければならない。その切り分けと判断の記録をまとめる。
現役と思い込んでいたスクリプトの実測
発端は、運用ルールやAIエージェント向けの手順書(.claude/rules/ や .claude/TOOLS.md)の点検だった。そこには amazon_recommender.py について「記事キーワードから関連商品を検索し、アフィリエイトHTMLブロックを必ず生成すること」と明記されていた。
しかし、実際のパイプライン稼働ログを追うと、このスクリプトが呼び出された形跡が見当たらない。そこで以下の3段階で実態を調査した。
- 呼び出し元の検索: リポジトリ全体を走査したところ、ヒットしたのは手順書、テストスクリプト、そしてスクリプト本体のみで、自動投稿レーンからの呼び出しは0件だった。
- 本番記事の走査: WordPress API 経由で本番の直近600本の記事本文を走査した。その結果、
amazon_recommender.pyが出力する書影HTMLブロックは 0件 だった。 - 現行処理の確認: 記事本文中の物販枠は、既に別の独立したモジュール(
scripts/matome/affiliate.py)が担当しており、記事生成スクリプト(compose.py)から自動的に1枚だけ差し込まれる仕組みになっていた。
# 呼び出し元の調査(ドキュメントとテスト以外に実行元がない)
git grep "amazon_recommender" -- :!docs :!.claude :!scripts/test_*
もし「ルールに書かれているから」と安易に amazon_recommender.py を自動レーンへ再配線していた場合、既存の affiliate.py と重複し、同一記事内に同じ商品・同じトラッキングIDの書影カードが2枚並ぶ事故になるところだった。また、末尾CTA枠の追加という案も検討されたが、過去の検証データ(in_body_product_card.md §0)において記事末尾CTAの成果がゼロであった実測と矛盾するため却下された。
削除ではなく「退役」を選んだ理由
使われていないスクリプトであれば即座に git rm で削除するのが原則だが、今回はスクリプト本体を削除せず、明示的な「退役(Deprecation)」宣言を付与して維持する判断をとった。
理由として以下の2点があった。
- 過去記事の回帰テスト: 過去の約125本の記事に対してトラッキングIDの付け替えを行ったスクリプト(
retag_amazon_tracking.py)の回帰テストが、このモジュールの出力関数を参照していた。 - HTML構造の仕様記録:
generate_html_block()が出力するマークアップ構造が、本文中に埋め込まれた過去記事のHTML構造の仕様定義として機能していた。
そのため、ファイルの先頭 docstring に以下の退役宣言を明記し、後続の開発者やエージェントが誤って再利用しないようガードを敷いた。
"""Amazon アフィリエイト レコメンダー(★レガシー・2026-08-30 退役 / Issue #3142)
**新しい記事でこれを呼ばないこと。**
実測: 自動レーンからの呼び出しゼロ/本番の直近600本で書影ブロック0件/
運用者も手では叩いていない。生きているのは過去の約125本だけ。
本文中のAmazon枠は scripts/matome/affiliate.py が担当している。
"""
あわせて、ルール文書(.claude/rules/)、ツール索引(TOOLS.md)、他エージェントへの引き継ぎ文書(docs/matome_x_pipeline_design_handover.md)の記載を「必須」から「レガシー(現役は affiliate.py)」へと一斉に更新した。
動いていなかった2つの番犬
今回の棚卸しに伴い、関連するテストと検査スクリプトを点検したところ、重大な「形骸化した検査」が2件見つかった。
1. 印字するだけで終了コード0を返していたテスト
1つ目は scripts/test_amazon_recommender.py である。トラッキングIDの分離(枠ごとの個別ID付与)を担保するための検査項目 [5] および [6] が追加されていたが、途中にあった別のエラー処理の sys.exit(1) より後に配置されていた。
# 修正前の構造(概念図)
if failed_early:
sys.exit(1)
# ここに追加された検査項目[5][6]
if check_tracking_id_failed():
print("[NG] トラッキングID分離エラー")
# ここに sys.exit(1) が無かった!
# スクリプト末尾まで到達して正常終了(exit 0)してしまう
テストは異常を検知してコンソールに [NG] を印字していたものの、プロセスとしては正常終了(exit 0)していたため、CIのパイプラインは一度も停止していなかった。判定を末尾に移動し、全項目の結果を評価した上で終了コードを返すよう修正した。
2. 本番リンクを1件も見ていなかったASINバリデータ
2つ目は まとめ媒体用の記事バリデータ によるASIN(Amazon商品識別番号)の抽出処理である。従来の正規表現は /dp/<ASIN>/ という「末尾にスラッシュが必須」の形式を仮定していた。
しかし、現役の自動化パイプラインが挿入していたリンクは /dp/<ASIN>?tag=... というパラメータ形式だったため、正規表現に1件もマッチしていなかった。結果として、リジェクト対象のブラックリストASIN(例: B00EXAMPLE)が含まれていても、エラーが一切発火しない状態になっていた。
| 検査対象 | 期待された形式 | 実際の本番形式 | 判定結果 |
|---|---|---|---|
| ASIN抽出 | /dp/([A-Z0-9]{10})/ | /dp/([A-Z0-9]{10})\?tag= | 抽出数 0件(検査素通り) |
| トラッキングID | 枠別の個別ID | 共通ID | テストが [NG] 印字も exit 0 |
この問題に対しては、長さ10桁の英数字パターンで双方の形式を確実に抽出できるよう正規表現を改修した。
さらに、今後の再発を防ぐため scripts/test_asin_gate.py を新設した。無効なURLやリジェクト済みASINを意図的に入力し、非0の終了コードで確実に停止することを「対照群」付きでテストする設計とした。
# 対照群付きASINゲートテストの実行
python3 scripts/test_asin_gate.py
やってみてわかったこと
運用が長期化すると、「ドキュメント上は現役」「リポジトリにコードが存在する」「テストがCIで通っている」という外見上の正常性が揃っていても、中身が完全に停止しているケースが生じる。
- ドキュメントの鮮度: コードが改修されても、手順書側の「必須」という文言が残ったまま放置されると、後から参入したエージェントや開発者が誤った復旧を試みてしまう。
- 実行有無の実測: コードの生死はコードを見るだけでは分からない。自動実行ジョブの呼び出し元と、本番出力(直近600本)を実測して初めて判断できる。
- テストの対照群: 「テストが通る(exit 0)」ことの確認だけでは不十分で、「異常値を与えたときに正しく非0で落ちるか」を対照群として検証しなければ、ただ印字して素通りする番犬を見落とすことになる。
使われなくなったコードを整理する際は、安易な再有効化や削除に走る前に、実測値・依存関係・検査の実効性を三位一体で確認することが不可欠である。
更新履歴
- 2026-09-03: 初稿。リポジトリ内のコミット記録および棚卸しログをもとに作成。
訂正履歴
(なし)