Skip to content

Instantly share code, notes, and snippets.

@hdknr
Created April 3, 2026 00:06
Show Gist options
  • Select an option

  • Save hdknr/b3fbb36d80ee881172cff7395f482290 to your computer and use it in GitHub Desktop.

Select an option

Save hdknr/b3fbb36d80ee881172cff7395f482290 to your computer and use it in GitHub Desktop.
Claude Code 開発で機能が静かにデグレードする問題と対策

Claude Code 開発で機能が静かにデグレードする問題と対策

TL;DR

Claude Code でリファクタリングや新機能追加を行うと、既存機能の出力品質が意図せず劣化することがある。機能は正しく動いておりテストも通るが、ユーザーが期待する情報が出力から消えている。これは「新しいコードパス」に注力するあまり「既存パスの出力同等性」が見落とされるために起きる。

何が起きたか

経緯

日本株・BTC のトレーディングシステムで、日次の投資提案を GitHub Issues に自動投稿している。

  1. ポートフォリオ統合最適化機能を追加(3月)
    • 成功時: 1つの統合 Issue に「市場概要」「総評」を含む詳細な分析を出力
    • 失敗時(フォールバック): 銘柄別 Issue + サマリー Issue を作成
  2. テスト全パス、PR マージ
  3. ある日、ポートフォリオ最適化が失敗しフォールバックが発動
  4. サマリー Issue を見るとポートフォリオ一覧とリンクテーブルだけ — 「結局ホールドすべき?買うべき?」がわからない
  5. 統合パスには存在する「銘柄横断の総評」が、フォールバックパスでは最初から実装されていなかった

サマリー Issue の Before / After

Before(デグレード状態):

# 2026-04-03 総合投資評価
## 現在のポートフォリオ
(ポジション一覧テーブル)
## 銘柄別計画
(リンクテーブル)
## 子課題チェックリスト
(チェックボックス一覧)

After(修正後):

# 2026-04-03 総合投資評価
## 現在のポートフォリオ
(ポジション一覧テーブル)
## 銘柄別計画
(リンクテーブル)
## 銘柄別サマリー          ← 追加
(各銘柄の総評を一覧表示)
## 総評                    ← 追加
### アクション分布
| BUY | SELL | HOLD | 合計 |
### 全体判断
(HOLD多数→「積極エントリー不向き」等の方針)
平均信頼度: 55%(低信頼度: 6526)
## 子課題チェックリスト
(チェックボックス一覧)

なぜ Claude Code で起きやすいか

1. 新しいパスに注力し、既存パスは最低限になる

Claude Code はタスクを忠実に実行する。「ポートフォリオ最適化を追加して」と指示すると:

  • 統合パス(成功時): 丁寧に設計。市場概要・総評・リスクサマリーを含む詳細な出力
  • フォールバックパス(失敗時): 「最低限動く」安全網として実装。出力品質まで考慮されない

人間の開発者でも同じことは起きるが、Claude Code はユーザーとして出力を見た経験がないため、「この情報がないと困る」という暗黙の期待を推測しにくい。

2. 会話が切れるとコンテキストが消える

統合最適化を実装した会話と、フォールバックの問題に気づく会話は別セッション。前回の設計意図や「統合パスと同等の出力品質を保つ」という暗黙の要件は引き継がれない。

3. テストが「動作」を検証し「品質」を検証しない

既存のテストは以下を検証していた:

  • 銘柄別 Issue が作成される ✅
  • DB に紐付けが保存される ✅
  • サマリー Issue が作成される ✅

しかし「サマリー Issue に総評セクションが含まれるか」は検証していなかった。テストは全パスするため、デグレードに気づけない。

対策

1. 出力仕様をテストする(最も効果的)

def test_fallback_summary_issue_contains_required_sections(self, ...):
    """サマリーIssueに銘柄別サマリーと総評が含まれる (#360)."""
    # ...フォールバック実行...

    body = summary_issue_call.kwargs["body"]

    # 必須セクションの存在を検証
    assert "## 銘柄別サマリー" in body
    assert "## 総評" in body
    assert "### アクション分布" in body
    assert "### 全体判断" in body

    # 各銘柄のサマリーが含まれている
    assert "7203" in body
    assert SAMPLE_PLAN_7203["summary"] in body

「Issue が作成される」だけでなく「Issue に何が書かれているか」までテストする。これにより、将来のリファクタリングで総評が消えたら即座にテストが落ちる。

2. 複数パスがある機能は出力同等性を意識する

CLAUDE.md やコードコメントに明記する:

## 開発規約
- 新しいコードパスを追加する際は、既存パスの出力内容が劣化しないか確認する
- 特にフォールバック/エラーパスは「最低限動く」ではなく「同等の情報量」を目指す

3. 出力のゴールデンファイルを用意する

テンプレートに必須セクションを定義し、レンダリング結果を検証する。テンプレートエンジン(Jinja2 等)を使っている場合、必須変数の未展開もテストで検出できる。

まとめ

項目 内容
問題 リファクタリングで新パスを追加した際、既存パスの出力品質がデグレード
原因 テストが「動作」のみ検証、出力内容(品質)を検証していなかった
対策 出力の必須セクションをアサーションでテスト
教訓 Claude Code は機能を正しく動かすが、ユーザー体験の同等性は暗黙の要件。明示的にテストで守る

Claude Code は強力だが万能ではない。特に「正しく動くが情報が足りない」という静かなデグレードは、テストをすり抜けやすい。出力仕様のテストを習慣にすることで、AI 開発でも品質を維持できる。


  • 修正 PR: #360 — 総評セクション追加
  • テスト PR: #361 — リグレッションテスト追加
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment