-
Notifications
You must be signed in to change notification settings - Fork 0
cross-review / cross-refactoring: codex と claude が利用上限で止まっても同じラウンドで起動し直され、PATH に読めないディレクトリがあると始まらない → 上限を理由として報告して起動し直さず、CLI が欠けても使える者だけで始まる(#811 #813) #819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
takemi-ohama
merged 3 commits into
develop
from
design/issue-811-813-release-verification-fixes
Sep 22, 2026
+386
−0
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,254 @@ | ||
| # cross-review / cross-refactoring: codex と claude が利用上限で止まっても同じラウンドで起動し直され、PATH に読めないディレクトリがあると始まらない → 上限を理由として報告して起動し直さず、CLI が欠けても使える者だけで始まる(#811 #813) | ||
|
|
||
| ## 目的 | ||
|
|
||
| - **壊れていること:** 監視の利用上限の照合の表が codex と claude の実物の文言に 1 つも一致しない(#811)。認証の確認が権限の例外を捕まえず、開始の手順ごと落ちる(#813) | ||
| - **誰が困るか:** 収束ループを回す利用者。上限の担当を打ち切りまで待たされ、読めない PATH の環境ではループが始まらない | ||
| - **直すと成り立つこと:** 実物の文言に一致する 2 行を照合の表へ足し、確認コマンドを起動できないときは「通らない」として返す。どちらも関数 1 つの範囲で直す | ||
|
|
||
| 要求と受け入れ条件は [issue-811-813-requirements.md](issue-811-813-requirements.md) にある。この文書は「どう作るか」だけを扱う。 | ||
|
|
||
| ## 用語の対応表 | ||
|
|
||
| 本文は左の業務用語で書く。識別子は表とコードブロックにだけ置く。 | ||
|
|
||
| | 業務用語 | 識別子 | | ||
| | --- | --- | | ||
| | 監視 | `plugins/ndf/scripts/lib/monitor.py` | | ||
| | 利用上限の照合の表 | `USAGE_LIMIT_FATAL` | | ||
| | 行単位の照合 | `_scan_patterns`。表・引用・grep 形式の行と、引用符の内側の一致を除く | | ||
| | 標準エラーの記録 | 担当ごとの `<stem>-err.log` | | ||
| | 行頭の印 | codex が標準エラーの誤りの行に付ける `ERROR: ` | | ||
| | 認証の確認 | `plugins/ndf/scripts/lib/auth.py` の `probe_auth` | | ||
| | 確認コマンドを 1 つ走らせる関数 | `auth._run_probe` | | ||
| | 権限の例外 | `PermissionError`(`errno` 13)。`OSError` の下位 | | ||
| | 起動できない例外 | `OSError` とその下位のすべて | | ||
| | 実物 | CLI が実際に出した文言。手元の記録か、導入済みの CLI の実行ファイルに埋め込まれた文字列 | | ||
|
|
||
| ## なぜ要るか | ||
|
|
||
| **利用上限の照合の表は 4 行で、どれも codex と claude の実物に一致しない。** #729 の要求の | ||
| 時点で集めた文言は kiro と claude の JSON 出力だけだった。codex(既定の参加者)が上限に | ||
| 当たると、理由が「結果ファイル無し」になり、同じラウンドで起動し直してまた上限で落ちる。 | ||
|
|
||
| **認証の確認は、確認コマンドが見つからないことを「見つからない例外」だけで判定している。** | ||
| Python の子プロセスの起動は PATH を順に探し、見つからないまま読めないディレクトリを通ると、 | ||
| 見つからない例外ではなく権限の例外を上げる。認証の確認は「例外は上げない」を約束しているが、 | ||
| この例外が開始の手順まで抜ける。 | ||
|
|
||
| ## 実測 | ||
|
|
||
| 測った環境: `develop`(90c0f06f)、Python 3.14.4、bash 5.3.9、codex-cli 0.154.0、 | ||
| claude 2.1.278(2026-09-22)。 | ||
|
|
||
| ### 文言を集めた経路と件数 | ||
|
|
||
| | CLI | 集めた経路 | 件数 | 見つかった形 | | ||
| | --- | --- | --- | --- | | ||
| | codex | `~/.codex/sessions` の記録の誤りの本文(`error.message`)。誤りの種別が `usage_limit_exceeded` のもの | 62(1 形、2026-09-15) | `You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at <日時>.` | | ||
| | codex | この設計 Pull Request の cross-review のラウンド 2 で、codex が利用上限で止まった標準エラーの記録(2026-09-22 16:35 UTC、132 行) | 2 行(1 形) | `ERROR: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at 5:44 PM.` | | ||
| | codex | 導入済みの実行ファイルに埋め込まれた文字列 | 6 形 | 上の形のほか、`You've hit your usage limit.` で始まる 3 形、`You've hit your usage limit for <モデル>.`、`exceeded retry limit, last status: <状態>` | | ||
| | claude | `~/.claude/projects` の記録のうち、API の誤りの印(`isApiErrorMessage`)が真の本文 | 5,103(4 形、2026-09-01〜22) | 週 3,751 / セッション 758 / 個人の支出 593 / 月の支出 1(下の表) | | ||
| | claude | 導入済みの実行ファイル | 期間を書かない形 `You've hit your limit` ほか | `You've hit your ` の後に期間や種類を差し込む作りである | | ||
| | claude | 同上。旧い形 `Claude AI usage limit reached` | 0 | 記録にも 0 件 | | ||
| | kiro | `~/.kiro` の記録 | 0 | 既存の照合の `Monthly request limit reached` は #619 の実物から採った | | ||
| | agy | `~/.gemini` の記録と `antigravity-cli/cli.log` | 0 | 一致したのは監視の照合の定義を写した行と、別のリポジトリのコード差分だけ | | ||
| | 全 CLI | 手元に残る標準エラーと標準出力の記録 296 件 | 上限の実物 0 | 一致したのは設計文書・テストを担当が読み上げた行だけ | | ||
|
|
||
| **codex が誤りを標準エラーへ書く形は、行頭の印の後に誤りの本文を続けた 1 行である。** 存在しない | ||
| モデルを指定して `codex exec` を実行し、標準エラーの記録に次の行が出ることを確かめた。記録の | ||
| 誤りの本文と同じ文字列である。利用上限の文言でも同じ形になることを、上の表のラウンド 2 の記録で確かめた。この記録を今の照合の表で読むと一致せず、監視の結末は理由「結果ファイル無し」になった。足す 2 行を加えると、行頭の印の付いた行に一致する。 | ||
|
|
||
| ```text | ||
| ERROR: {"type":"error","status":400,"error":{"type":"invalid_request_error","message":"The 'ndf-no-such-model-xyz' model is not supported when using Codex with a ChatGPT account."}} | ||
| ``` | ||
|
|
||
| **claude の JSON 出力の上限は、足さなくても読める。** 導入済みの実行ファイルは、API の誤りで | ||
| 終わった結果行に `api_error_status` を載せる。10.16.0 のリリース後テストでも、この形は理由 | ||
| 「利用上限」になった。 | ||
|
|
||
| ### 足す 2 行の照合の結果 | ||
|
|
||
| 次の 2 行を照合の表の末尾に足し、行単位の照合で入力 1 行ずつを読んだ結果である。 | ||
|
|
||
| ```python | ||
| re.compile(r"^(?:ERROR:\s*)?You['’]ve hit your (?:[\w'’ ]+ )?(?:limit|budget)\b", re.MULTILINE) | ||
| re.compile(r"^(?:ERROR:\s*)?exceeded retry limit, last status: 429\b", re.MULTILINE) | ||
| ``` | ||
|
|
||
| | 区分 | 入力 | 今の利用上限 | 足した後 | | ||
| | --- | --- | --- | --- | | ||
| | 実物 | codex の利用上限(行頭の印あり / なし) | — | 一致 | | ||
| | 実物(書き出し) | codex の再試行の上限 `ERROR: exceeded retry limit, last status: 429`。書き出しは実行ファイルの文字列、`429` は差し込まれる状態 | — | 一致 | | ||
| | 実物 | codex の `Quota exceeded. Check your plan and billing details.` | 一致 | 一致 | | ||
| | 実物 | claude の `You've hit your weekly limit · resets Sep 22, 6am (UTC)` | — | 一致 | | ||
| | 実物 | claude の `You've hit your session limit · resets 6:30pm (UTC)` | — | 一致 | | ||
| | 実物 | claude の `You've hit your individual spend limit · run /usage-credits …` | — | 一致 | | ||
| | 実物 | claude の `You've hit your monthly spend limit. Run /usage-credits …` | — | 一致 | | ||
| | 実物 | claude の `You've hit your limit`(実行ファイルの文字列) | — | 一致 | | ||
| | 実物 | kiro の `Monthly request limit reached` / HTTP 429 の状態行 | 一致 | 一致 | | ||
| | 一致しない | codex の再試行の上限 `… last status: 503 Service Unavailable` | — | — | | ||
| | 一致しない | codex の 400 の行(上のコードブロック) | — | — | | ||
| | 誤検知 | 表(バッククォートあり / なし)、本文のバッククォート、本文の「」 | — | — | | ||
| | 誤検知 | 文の途中、リスト、引用、grep 形式、Python の文字列 | — | — | | ||
| | 誤検知 | 差分の追加行 `+ERROR: You've hit …`、差分の文脈行 | — | — | | ||
|
|
||
| **実物に無い末尾は入力に足さない。** 再試行の上限の状態の後ろ(`Too Many Requests` など)と、claude の期間を書かない形の後ろ(`· resets 3am (UTC)`)は、#811 の表にある形で、記録にも実行ファイルにも無い。照合はどちらも末尾を読まないため、入力は実物の範囲で止める。 | ||
|
|
||
| ### 起動できないときの例外 | ||
|
|
||
| | 条件 | 上がる例外 | `errno` | | ||
| | --- | --- | --- | | ||
| | PATH に読めないディレクトリがあり、コマンドがどこにも無い | 権限の例外 | 13 `Permission denied` | | ||
| | 読めないディレクトリの無い PATH で、コマンドがどこにも無い | 見つからない例外 | 2 | | ||
| | 読めないディレクトリの後ろにコマンドがある | 例外なし(終了コード 0) | — | | ||
| | 実行権の無いファイル | 権限の例外 | 13 | | ||
| | 実行形式でないファイル | 起動できない例外 | 8 `Exec format error` | | ||
|
|
||
| **cross-refactoring の開始の手順も落ちることを確かめた。** 参加者の解決の関数を、ホストの | ||
| claude が見つからず読めないディレクトリを含む PATH で呼ぶと、権限の例外で終了コード 1 になる。 | ||
| 読めないディレクトリを外すと、codex だけが使える者として返る。 | ||
|
|
||
| ## 決定の記録 | ||
|
|
||
| ### 決定 1: 誤検知を防ぐために、足す文言は行頭で始まる形だけを照合する | ||
|
|
||
| 監視は担当が生きている間に照合し、一致すれば担当を止めて起動し直さない。文書の引用に一致すると、 | ||
| 結果を書ける担当を止める。見逃すと 1 度起動し直すだけである。誤検知の費用のほうが大きい。 | ||
| **codex は作業中のコマンドの出力(差分やファイルの中身)も標準エラーへ書く**ため、文言を | ||
| 含む文書やテストを読み上げた行が記録に入る。行頭に固定すると、文の途中・差分の行・字下げ | ||
| した文字列は一致しない。行頭の印は codex の形に合わせて省略可能にする。 | ||
|
|
||
| 行頭に固定しない照合は採らない。除外の規則(表・引用・grep 形式)は文の途中に裸で出た文言を | ||
| 除けない。 | ||
|
|
||
| ### 決定 2: 利用上限の文言は、期間や種類を問わず 1 行の照合で読む | ||
|
|
||
| claude は `You've hit your ` の後に期間や種類(週・セッション・個人の支出など)を差し込んで | ||
| 文言を作る。codex も同じ書き出しで 5 形を持つ。書き出しと、末尾の `limit` / `budget` で読めば、 | ||
| 記録と実行ファイルで見つけた書き出しの形をすべて 1 行で覆える。形ごとに行を足すと、CLI が種類を増やすたびに照合が遅れる。 | ||
|
|
||
| ### 決定 3: codex の再試行の上限は、最後の状態が 429 のときだけ利用上限と読む | ||
|
|
||
| 同じ文言は状態コードを差し込んで作られ、503 などの一時的な誤りでも出る。一時的な誤りは | ||
| 起動し直せば解けうるため、利用上限にしない。 | ||
|
|
||
| ### 決定 4: 実物が見つからない文言は照合に足さない | ||
|
|
||
| 照合の表の行は、記録か導入済みの実行ファイルに出所を持つものだけにする。出所の無い行は、 | ||
| 合っているかをテストで確かめられない。書いた側の思い込みがテストの期待値にも入り、通って | ||
| しまう。claude の旧い形(`Claude AI usage limit reached`)は記録にも実行ファイルにも無いため | ||
| 足さない。記録に現れたら、同じ手順で出所を書いて足す。 | ||
|
|
||
| ### 決定 5: 照合を足す先は標準エラーの記録だけにし、claude の標準出力の照合は変えない | ||
|
|
||
| claude は JSON を出す形で起動しており、上限の結果行は状態コードを持つ。JSON は 1 行に文章を | ||
| 含むため、行頭の照合が効かず、担当のレビュー本文の引用に一致しうる。 | ||
|
|
||
| claude の 5 形は、codex と共通の 1 行(決定 2)で読める。そのため標準エラーの記録に出れば利用上限になる。ただし、JSON 出力で起動した claude が上限のときに標準エラーへ書いた記録は無い。起動した claude の上限を読む経路は、標準出力の状態コードのままである。 | ||
|
|
||
| ### 決定 6: 確認コマンドを起動できないときは、例外の種類を問わず「通らない」として返す | ||
|
|
||
| 認証の確認は「例外は上げない」を約束しており、起動できない理由(権限・実行形式など)が | ||
| 何であっても、その CLI は使えない。見つからない例外だけは従来の理由のまま残し、その他の | ||
| 起動できない例外は `コマンドを実行できません(<理由>)` にまとめる。理由には例外の説明 | ||
| (`strerror`)を入れる。 | ||
|
|
||
| 権限の例外だけを足す形は採らない。実行形式でないファイルで同じ落ち方をする。 | ||
|
|
||
| ### 決定 7: 読めない PATH で見つからないときも、理由は起動できないとして出す | ||
|
|
||
| Python の起動は、読めないディレクトリがあると「見つからない」と「実行権が無い」を同じ | ||
| 例外で返す。見分けるには PATH を自分で探し直す必要があり、関数 1 つの範囲を超える。理由の | ||
| 文言に `Permission denied` が出れば、利用者は PATH かファイルの権限を見ればよい。 | ||
|
|
||
| ## 構成要素 | ||
|
|
||
| | 要素 | 変えること | | ||
| | --- | --- | | ||
| | 利用上限の照合の表(監視) | 決定 1〜3 の 2 行を末尾に足す | | ||
| | 確認コマンドを 1 つ走らせる関数(認証の確認) | 起動できない例外を捕まえ、「通らない」と理由を返す | | ||
| | 監視のテスト | 実測の表の実物と誤検知の形を入力にする | | ||
| | 認証の確認のテスト | 起動できない 2 形(権限・実行形式)を入力にする | | ||
| | 2 つの開始の手順のテスト | 読めないディレクトリを含む PATH で、欠けた CLI が外れることを確かめる | | ||
|
|
||
| ```text | ||
| plugins/ndf/ | ||
| ├── scripts/lib/ | ||
| │ ├── monitor.py # 利用上限の照合の表に 2 行 | ||
| │ └── auth.py # 確認コマンドを 1 つ走らせる関数 | ||
| ├── scripts/tests/ | ||
| │ └── test_auth_probe.py | ||
| └── skills/ | ||
| ├── cross-review/tests/ | ||
| │ ├── test_monitor_usage_limit.py | ||
| │ └── test_state_review_pool.py | ||
| └── cross-refactoring/tests/ | ||
| └── test_init.py | ||
| ``` | ||
|
|
||
| ```mermaid | ||
| graph TD | ||
| CR["cross-review の開始の手順"] --> AU["認証の確認"] | ||
| RF["cross-refactoring の開始の手順"] --> AU | ||
| AU --> RP["確認コマンドを<br/>1 つ走らせる関数"] | ||
| MON["監視"] --> UL["利用上限の照合の表"] | ||
| UL --> OUT["結末の理由<br/>利用上限"] | ||
| ``` | ||
|
|
||
| ## 処理の流れ | ||
|
|
||
| ### 監視が標準エラーの記録を読む | ||
|
|
||
| ```mermaid | ||
| graph TD | ||
| A["標準エラーの記録の<br/>末尾 200KB"] --> B{"利用上限の<br/>照合の表に一致"} | ||
| B -->|"一致"| C{"除外の規則<br/>表・引用・grep 形式"} | ||
| C -->|"除外しない"| D["担当を止める<br/>理由は利用上限"] | ||
| C -->|"除外する"| B | ||
| B -->|"一致なし"| E["既存の致命の照合へ"] | ||
| ``` | ||
|
|
||
| 足した 2 行は照合の表の末尾に入るため、既存の 4 行より後に照合される。どの行に一致しても | ||
| 理由は同じであり、順序は結果を変えない。 | ||
|
|
||
| ### 認証の確認が 1 つの CLI を確かめる | ||
|
|
||
| ```mermaid | ||
| graph TD | ||
| A["確認コマンドを起動"] --> B{"例外"} | ||
| B -->|"見つからない"| C["通らない<br/>コマンドが見つかりません"] | ||
| B -->|"時間切れ"| D["通らない<br/>応答しませんでした"] | ||
| B -->|"その他の起動できない例外"| E["通らない<br/>コマンドを実行できません"] | ||
| B -->|"なし"| F["終了コードと文言で判定"] | ||
| ``` | ||
|
|
||
| 見つからない例外は起動できない例外の下位にあるため、先に捕まえる。時間切れの例外は起動 | ||
| できない例外の下位ではないため、順序に依らない。 | ||
|
|
||
| ## テスト設計 | ||
|
|
||
| | 受け入れ条件 | 何で確かめるか | | ||
| | --- | --- | | ||
| | AC1〜AC4 | 監視のテストに、実測の「実物」の行を 1 つずつ標準エラーの記録へ書き、結末を読む。理由が利用上限・起動し直しの可否が偽・終了コード 4 | | ||
| | AC2 の後半 | 同じテストで 503 の行を書き、利用上限にならないこと | | ||
| | AC5 | 同じテストで実測の「誤検知」の形を書き、担当が止まらないこと | | ||
| | AC6 | テストの入力の文字列が、実測の表の文言と一致すること(レビューで照らす) | | ||
| | AC7 / AC8 | 認証の確認のテストで、読めないディレクトリを含む PATH と、実行形式でないファイルを確認コマンドにする | | ||
| | AC9 | 同じテストの既存の 2 件(見つからない・時間切れ)が通ること | | ||
| | AC10 | cross-review の参加者の解決のテストに、読めないディレクトリを含む PATH の場合を足す | | ||
| | AC11 | cross-refactoring の開始の手順のテストに、同じ場合を足す | | ||
| | AC12〜AC14 | 10.16.1 のリリース後テスト(利用者の環境で手動) | | ||
|
|
||
| 読めないディレクトリはテストの中で作る(権限を外した一時ディレクトリ)。root で実行すると | ||
| 権限が効かないため、そのときはテストを飛ばす。 | ||
|
|
||
| ## 未確認のまま残ること | ||
|
|
||
| | 項目 | 内容 | | ||
| | --- | --- | | ||
| | claude の文言が標準エラーの記録へ出るか | 実測の claude の 5 形の出所は、会話の記録と実行ファイルである。JSON 出力で起動した claude が上限のときに標準エラーへ書いた記録は無い。起動した claude の上限は、標準出力の状態コード(10.16.0 で合格)で読む。10.16.1 の後に上限に当たった標準エラーの記録で確かめる | | ||
| | codex の再試行の上限の状態の書き方 | 実行ファイルの文字列は `last status: ` までで、状態の後ろの書き方は記録に無い。テストの入力は `429` までにし、照合も `429` の直後の語の区切りまでしか見ない | | ||
| | kiro と agy の利用上限の文言 | 手元の記録に 0 件。kiro は既存の #619 の実物、agy は照合なし | | ||
| | claude の旧い形 | 記録にも実行ファイルにも 0 件のため足さない(決定 4) | | ||
| | 行頭に固定しても残る誤検知 | 文言で始まる行をそのまま読み上げた場合(文書の本文の行頭に裸で置いた文言を `cat` したときなど)は一致する。この束の文書とテストでは、文言を表・バッククォート・文字列の中にだけ置く | | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.