Skip to content

fix(backend): fetch_repo_tree が rate-limit の 403 をリトライせず黙って partial 扱いにする(ADR-0016 D9) #485

Description

@yusuke0610

背景

ADR-0016 のキャップ実データチューニング(#478 / PR #483)の計測中に見つかった、fetch_repo_tree の 403 握り込みバグ。#478 の完了条件外だったため follow-up として切り出す。

fetch_repo_treebackend/app/services/intelligence/github/api_client.py:195)は非 200 レスポンスを無条件で ([], True)(partial マーク)として返す:

resp = await client.get(f"/repos/{owner}/{repo}/git/trees/{branch}", params={"recursive": "1"})
if resp.status_code != 200:
    return [], True   # ← 403 (rate limit) もここで握り潰される

問題

GitHub API は rate limit でも 403 を返すfetch_repos_rawapi_client.py:93-102X-RateLimit-Remaining ヘッダを見て RetryableError を raise し分けている)。ところが fetch_repo_tree は 403 を rate limit かどうか判別せず、リトライ経路(RetryableError)を通さずに「partial な走査結果」として即返してしまう。

結果として、レート制限に当たったリポはリトライされずに黙って部分スキャン扱いになり、そのリポの依存宣言・import・IaC 検出がまるごと取りこぼされる(partial フラグは立つが warning ログすら出ない)。連携全体は成功扱いのまま、スキル証跡だけが静かに欠ける。

完了条件

  • fetch_repo_tree の 403 を rate limit(X-RateLimit-Remaining: 0 / 429)とそれ以外で判別し、rate limit なら fetch_repos_raw と同様に RetryableErrorretry_after 付き)を raise する
  • rate limit 以外の非 200 は最低でも logger.warning を残す(現状の httpx.HTTPError catch は warning を出しているが、非 200 の早期 return は無言)
  • レート制限判別ロジックが fetch_repos_raw と重複するなら共通ヘルパへ抽出(_retry_after_from_github が既にあるので隣接させる / .claude/rules/common/duplication.md
  • exploit 視点の回帰テスト: 403 + rate limit ヘッダで RetryableError、403 + 残量あり(本当の権限エラー)で partial 返却、を分けて検証

想定サイズ

小(1 セッション)。決定論的ロジック層の変更のため TDD 対象(.claude/rules/common/tdd.md)。schema / API 契約は不変(migration / codegen 不要)。

参考

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendバックエンドbugバグ修正

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions