「動いていないコード」の棚卸し — 未使用スクリプトの退役判断と形骸化した番犬の修正

  • #リファクタリング
  • #技術的負債
  • #テスト自動化
  • #運用改善
「動いていないコード」の棚卸し — 未使用スクリプトの退役判断と形骸化した番犬の修正

今回やったこと

手順書やルール文書に「必須」と書かれていたスクリプトが、実際には自動パイプラインのどこからも呼ばれておらず、本番記事にも長期間出力されていなかったことが判明した。対象は物販アフィリエイトの推薦ブロックを生成する scripts/amazon_recommender.py である。

このコードを復活させるべきか、削除すべきか、あるいは退役として残すべきかを実測値に基づいて切り分けた。さらに、この棚卸しの過程で「テストでNGを出力しているのに終了コード0で通過していた番犬」と「正規表現の前提がズレて本番記事のリンクを1件も検査していなかったバリデータ」の2つが見つかったため、合わせて改修した。

コードがリポジトリ内に存在すること、自動化から実行されていること、そしてテストや検査が実際に失敗を検知して止めることは、すべて別々に検証しなければならない。その切り分けと判断の記録をまとめる。

現役と思い込んでいたスクリプトの実測

発端は、運用ルールやAIエージェント向けの手順書(.claude/rules/.claude/TOOLS.md)の点検だった。そこには amazon_recommender.py について「記事キーワードから関連商品を検索し、アフィリエイトHTMLブロックを必ず生成すること」と明記されていた。

しかし、実際のパイプライン稼働ログを追うと、このスクリプトが呼び出された形跡が見当たらない。そこで以下の3段階で実態を調査した。

  1. 呼び出し元の検索: リポジトリ全体を走査したところ、ヒットしたのは手順書、テストスクリプト、そしてスクリプト本体のみで、自動投稿レーンからの呼び出しは0件だった。
  2. 本番記事の走査: WordPress API 経由で本番の直近600本の記事本文を走査した。その結果、amazon_recommender.py が出力する書影HTMLブロックは 0件 だった。
  3. 現行処理の確認: 記事本文中の物販枠は、既に別の独立したモジュール(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: 初稿。リポジトリ内のコミット記録および棚卸しログをもとに作成。

訂正履歴

(なし)