From 4f7fe89349c0786a8d460ae1b77600130aa6aa0c Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 22 Sep 2026 16:13:04 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Docs:=20=E5=88=A9=E7=94=A8=E4=B8=8A?= =?UTF-8?q?=E9=99=90=E3=81=AE=E6=96=87=E8=A8=80=E3=81=A8=E8=B5=B7=E5=8B=95?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E7=A2=BA=E8=AA=8D=E3=82=B3?= =?UTF-8?q?=E3=83=9E=E3=83=B3=E3=83=89=E3=81=AE=E8=A6=81=E6=B1=82=E3=81=A8?= =?UTF-8?q?=E8=A8=AD=E8=A8=88=E3=82=92=E6=9B=B8=E3=81=8F=EF=BC=88#811=20#8?= =?UTF-8?q?13=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit codex と claude の実物の文言を記録と実行ファイルから集め、照合に足す 2 行と 誤検知の実測を設計に残す。認証の確認が起動できない例外を「通らない」として 返す設計と、10.16.1 のリリース後テストで確かめ直す条件(#478 #619 #729)を書く。 Co-Authored-By: Claude Opus 5 (1M context) --- issues/issue-811-813-design.md | 249 +++++++++++++++++++++++++++ issues/issue-811-813-requirements.md | 132 ++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 issues/issue-811-813-design.md create mode 100644 issues/issue-811-813-requirements.md diff --git a/issues/issue-811-813-design.md b/issues/issue-811-813-design.md new file mode 100644 index 000000000..713f3b996 --- /dev/null +++ b/issues/issue-811-813-design.md @@ -0,0 +1,249 @@ +# 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 形式の行と、引用符の内側の一致を除く | +| 標準エラーの記録 | 担当ごとの `-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 | 導入済みの実行ファイルに埋め込まれた文字列 | 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` を実行し、標準エラーの記録に次の行が出ることを確かめた。記録の +誤りの本文と同じ文字列である。利用上限の文言でこの形を見たわけではない(「未確認のまま残ること」)。 + +```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 の再試行の上限 `… last status: 429 Too Many Requests` | — | 一致 | +| 実物 | 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 · resets 3am (UTC)` | — | 一致 | +| 実物 | kiro の `Monthly request limit reached` / HTTP 429 の状態行 | 一致 | 一致 | +| 一致しない | codex の再試行の上限 `… last status: 503 Service Unavailable` | — | — | +| 一致しない | codex の 400 の行(上のコードブロック) | — | — | +| 誤検知 | 表(バッククォートあり / なし)、本文のバッククォート、本文の「」 | — | — | +| 誤検知 | 文の途中、リスト、引用、grep 形式、Python の文字列 | — | — | +| 誤検知 | 差分の追加行 `+ERROR: You've hit …`、差分の文脈行 | — | — | + +### 起動できないときの例外 + +| 条件 | 上がる例外 | `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 行に文章を +含むため、行頭の照合が効かず、担当のレビュー本文の引用に一致しうる。 + +### 決定 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["確認コマンドを
1 つ走らせる関数"] + MON["監視"] --> UL["利用上限の照合の表"] + UL --> OUT["結末の理由
利用上限"] +``` + +## 処理の流れ + +### 監視が標準エラーの記録を読む + +```mermaid +graph TD + A["標準エラーの記録の
末尾 200KB"] --> B{"利用上限の
照合の表に一致"} + B -->|"一致"| C{"除外の規則
表・引用・grep 形式"} + C -->|"除外しない"| D["担当を止める
理由は利用上限"] + C -->|"除外する"| B + B -->|"一致なし"| E["既存の致命の照合へ"] +``` + +足した 2 行は照合の表の末尾に入るため、既存の 4 行より後に照合される。どの行に一致しても +理由は同じであり、順序は結果を変えない。 + +### 認証の確認が 1 つの CLI を確かめる + +```mermaid +graph TD + A["確認コマンドを起動"] --> B{"例外"} + B -->|"見つからない"| C["通らない
コマンドが見つかりません"] + B -->|"時間切れ"| D["通らない
応答しませんでした"] + B -->|"その他の起動できない例外"| E["通らない
コマンドを実行できません"] + 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 で実行すると +権限が効かないため、そのときはテストを飛ばす。 + +## 未確認のまま残ること + +| 項目 | 内容 | +| --- | --- | +| codex の利用上限の文言の行頭の形 | 400 の誤りで測った形(`ERROR: ` + 本文)からの類推。照合は行頭の印の有無を問わないため、印が別の形(時刻を前に置くなど)だと一致しない。10.16.1 の後に上限に当たった記録で確かめる | +| codex の再試行の上限の状態の書き方 | 実行ファイルの文字列は `last status: ` までで、状態の後ろの書き方は記録に無い。照合は `429` の直後の語の区切りまでしか見ない | +| kiro と agy の利用上限の文言 | 手元の記録に 0 件。kiro は既存の #619 の実物、agy は照合なし | +| claude の旧い形 | 記録にも実行ファイルにも 0 件のため足さない(決定 4) | +| 行頭に固定しても残る誤検知 | 文言で始まる行をそのまま読み上げた場合(文書の本文の行頭に裸で置いた文言を `cat` したときなど)は一致する。この束の文書とテストでは、文言を表・バッククォート・文字列の中にだけ置く | diff --git a/issues/issue-811-813-requirements.md b/issues/issue-811-813-requirements.md new file mode 100644 index 000000000..e3eec807a --- /dev/null +++ b/issues/issue-811-813-requirements.md @@ -0,0 +1,132 @@ +# cross-review / cross-refactoring: codex と claude が利用上限で止まっても同じラウンドで起動し直され、PATH に読めないディレクトリがあると始まらない → 上限を理由として報告して起動し直さず、CLI が欠けても使える者だけで始まる(#811 #813) + +## 目的 + +- **壊れていること:** codex と claude の利用上限の文言を監視が読まず、上限で止まった担当を同じラウンドで起動し直す(#811)。PATH に読めないディレクトリがあると、CLI が 1 つ欠けただけで開始の手順が落ちる(#813) +- **誰が困るか:** 収束ループ(cross-review / cross-refactoring)を回す利用者。上限は解けないため打ち切りまで待たされ、理由も出ない。読めない PATH を持つ環境では、ループが始まらない +- **直すと成り立つこと:** 実物の文言で止まった担当は理由「利用上限」で報告され、起動し直されない。確認コマンドを実行できない CLI は外され、使える者だけで始まる + +設計は [issue-811-813-design.md](issue-811-813-design.md) にある。この文書は「何を満たすか」だけを扱う。 + +## 用語の対応表 + +本文は左の業務用語で書く。識別子は表とコードブロックにだけ置く。 + +| 業務用語 | 識別子 | +| --- | --- | +| 監視 | `plugins/ndf/scripts/lib/monitor.py` | +| 利用上限の照合の表 | `USAGE_LIMIT_FATAL` | +| 標準エラーの記録 | 担当ごとの `-err.log` | +| 結末 | 起動 1 回の終わり方(`read_launch_outcome` が返す `LaunchOutcome`) | +| 理由「利用上限」 | `reason = "usage_limit"` | +| 起動し直しの可否 | `relaunch_same_agent` | +| 早期の致命 | 監視の状態 `EARLY_ERROR`(終了コード 4) | +| 認証の確認 | `plugins/ndf/scripts/lib/auth.py` の `probe_auth` | +| 確認コマンドを 1 つ走らせる関数 | `auth._run_probe` | +| 開始の手順 | cross-review の `state.py init`、cross-refactoring の `refactor.py init` | +| 実物 | CLI が実際に出した文言。手元の記録か、導入済みの CLI の実行ファイルに埋め込まれた文字列 | + +## なぜ要るか + +ndf 10.16.0 のリリース後テスト(PR #810 のコメント、2026-09-22)で 3 つの受け入れ条件が不合格になった。 + +| 課題 | 条件 | 不合格の中身 | 起票 | +| --- | --- | --- | --- | +| #729 / #619 | 利用上限で止まった担当が理由「利用上限」で報告され、起動し直されない | kiro と claude の JSON 出力は満たした。codex の文言 2 形式と claude のテキスト出力の文言 2 形式は理由が「結果ファイル無し」になり、同じラウンドで起動し直す | #811 | +| #478 | AC45 前半: CLI が 1 者欠けても開始の手順が終了コード 0 で終わり、使える者だけで 2 席を埋める | PATH の 13 番目にある読めないディレクトリ(`/root/.local/bin`)のため、確認コマンドが見つからないときに権限の例外が上がり、終了コード 1 で落ちた | #813 | + +**#729 の要求の時点で文言を集めたのは kiro と claude の JSON 出力だけだった**(10.16.0 の振り返り)。そのため、この束では文言を実物から集め、集めた経路と件数を設計の「実測」に残す。 + +## 対象範囲 + +含む: + +- 監視が読む利用上限の文言に、codex と claude の実物の形を足す(#811) +- 確認コマンドを実行できないときに、例外を上げず「通らない」として返す(#813) +- 上の 2 つを cross-review と cross-refactoring の両方の経路で確かめる + +含まない: + +- **実物が見つからない文言は足さない。** claude の旧い形(`Claude AI usage limit reached|<時刻>`)は、手元の記録に 0 件だった。導入済みの claude 2.1.278 の実行ファイルにも 0 件だった(設計の「実測」)。agy の利用上限の文言も記録に 0 件で、足さない +- claude の標準出力(JSON)の照合は変えない。JSON の結果行が上限の状態コードを持つことは実行ファイルで確かめてあり、10.16.0 のリリース後テストでも合格している +- 利用上限の後に担当を替えるかどうかの判断(Skill 側の既存の振る舞い)は変えない +- 理由の語彙・監視の終了コード・標準出力のキーは変えない +- 必須の外部コマンド(`git` / `gh`)の呼び出しの例外処理は変えない。無ければ動けないため、落ちる振る舞いのままでよい +- **設計の成果物のうち、対象が無いため省くもの:** システム構成図(外部の系・配置が変わらない)、クラス図(型を足さず変えない)、非機能設計表(非機能の条件が無い) + +## 影響 + +| 対象 | 影響 | +| --- | --- | +| 公開インタフェース | 変わらない。監視の終了コード・標準出力のキー・結末の語彙はそのまま | +| データ | 変わらない。状態ファイル・監視の結果ファイルの形は同じ | +| 既存の振る舞い | 利用上限の照合の表に 2 行が増える。認証の確認が、起動できない CLI を例外ではなく「通らない」として返す | + +## 前提とする取り決め + +| 項目 | 参照先 / 決めたこと | +| --- | --- | +| プロジェクト構造 | `AGENTS.md`。監視と認証の確認は共通層(`plugins/ndf/scripts/lib/`)に置き、Skill 側へ写さない | +| コーディング規約 | `AGENTS.md` の「確かめる対象は外部コマンドに限らない」。照合の入力はこの束で集めた実物から作る | +| テスト戦略 | 照合の表は単体テスト(`plugins/ndf/skills/cross-review/tests/test_monitor_usage_limit.py`)、認証の確認は単体テスト(`plugins/ndf/scripts/tests/test_auth_probe.py`)、2 つの開始の手順は既存の参加者の解決のテストに PATH の条件を足す | + +## 境界 + +| 区分 | 内容 | +| --- | --- | +| 常に行う | 全テストの実行。照合の文言を足すときは、出所(記録か実行ファイル)を設計の「実測」に書く | +| 確認してから行う | 監視の終了コード・理由の語彙を変えること | +| 行わない | 実物の無い文言を照合へ足すこと。必須の外部コマンドの例外処理を変えること | + +## 検証手段 + +| 項目 | 手段 | +| --- | --- | +| テスト | `uv run --with pytest pytest scripts/tests plugins/ndf -q` | +| 文書の検査 | `python3 scripts/check-doc-line-limit.py`、`python3 scripts/check-markdown-links.py` | +| 手動確認 | AC10 / AC11 は、読めないディレクトリを先頭に置いた PATH で開始の手順を実際に実行する。AC12〜AC14 は 10.16.1 のリリース後テスト | + +## 受け入れ条件 + +### 利用上限の文言(#811) + +各条件の「利用上限として止まる」は、次の 3 つがそろうことを指す: 監視が担当を止めて早期の致命(終了コード 4)で終わる / 結末の理由が「利用上限」 / 起動し直しの可否が偽。 + +- [ ] AC1: 標準エラーの記録に codex の利用上限の文言の 1 行が出ると、利用上限として止まる。文言は `You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage …` である。行頭の `ERROR: ` の有無を問わない +- [ ] AC2: 標準エラーの記録に codex の再試行の上限の行が出て、最後の状態が 429 なら、利用上限として止まる。行は `exceeded retry limit, last status: 429 Too Many Requests` である。最後の状態が 429 以外(例 `503 Service Unavailable`)なら利用上限にならない +- [ ] AC3: 標準エラーの記録に claude の利用上限の文言が行頭から出ると、利用上限として止まる。確かめる形は設計の「実測」の claude の 5 形(週・セッション・個人の支出・月の支出・期間を書かない形) +- [ ] AC4: 10.16.0 で合格した形は、引き続き利用上限として止まる。形は 4 つで、kiro の `Monthly request limit reached`、claude の JSON の上限の状態コード、HTTP 429 の状態行、`Quota exceeded` である +- [ ] AC5: AC1〜AC3 の文言が、表・バッククォート・「」・リスト・引用・grep 形式・Python の文字列・差分の追加行と文脈行・文の途中に出たときは、利用上限として止まらない +- [ ] AC6: AC1〜AC5 のテストの入力は、設計の「実測」の表にある実物の文言をそのまま写したものである(推測で作った文言を入力にしない) + +### 確認コマンドを実行できないとき(#813) + +- [ ] AC7: PATH に読めないディレクトリがあり、確認コマンドがどこにも無いとき、認証の確認は例外を上げず「通らない」を返す。理由は `コマンドを実行できません(Permission denied)` の形である +- [ ] AC8: 確認コマンドが実行形式でない(`Exec format error`)など、権限以外の理由で起動できないときも、AC7 と同じく「通らない」を返し、理由に起動できなかった理由を入れる +- [ ] AC9: 確認コマンドが見つからないときの理由(`コマンドが見つかりません`)と、時間切れのときの理由は変わらない +- [ ] AC10: AC7 の PATH で CLI を 1 つ欠いたとき、cross-review の開始の手順が終了コード 0 で終わり、欠けた CLI を外して使える者だけで席を埋める +- [ ] AC11: AC7 の PATH で CLI を 1 つ欠いたとき、cross-refactoring の開始の手順が終了コード 0 で終わり、欠けた CLI を外して使える者だけで始まる + +### 10.16.1 のリリース後テストで確かめ直す条件 + +**次の 3 行は、10.16.1 を配布した後に利用者の環境で確かめる。** 3 行とも合格したら #478 #619 #729 を閉じる。 + +- [ ] AC12(#478 の AC45 前半): 利用者の PATH から `kiro-cli` だけを隠し、検証用の Pull Request で cross-review の開始の手順を実行する。終了コード 0 で終わり、使える者だけで 2 席を埋める。PATH は読めない `/root/.local/bin` を含んだままにする +- [ ] AC13(#619 / #729): 導入先の監視に、設計の「実測」の codex の 2 形と claude の 5 形を 1 つずつ与えて結末を読む。すべて理由「利用上限」・起動し直しの可否が偽になる +- [ ] AC14(#619 / #729 の退行): 同じ手順で、10.16.0 で合格した kiro と claude の JSON の形も理由「利用上限」・起動し直しの可否が偽のままである + +## 依頼(原文) + +### #811 の本文(抜粋) + +> ndf 10.16.0(タグ `ndf--v10.16.0`)の監視は、**codex と claude(テキスト出力)の利用上限の文言を利用上限として読まない。** 担当が上限で止まると理由が `usage_limit` ではなく `missing` になり、`read_launch_outcome` は `relaunch_same_agent=True` を返す。つまり同じラウンドで起動し直す。 + +### #811 の追記 + +> 直すときは、各 CLI の実物の記録(`~/.codex/sessions` の `error.message`、`claude -p` のテキスト出力、kiro の err.log)から利用上限の文言を集め、テストの入力をその写しから作る。 + +### #813 の本文(抜粋) + +> PATH に**読めないディレクトリ**があると、参加者の CLI が入っていないときに `cross-review` の `init` が終了コード 0 ではなく、トレースバックを出して終了コード 1 で落ちる。#478 が直した「CLI が 1 者欠けても使える者だけで始まる」が、この PATH では成り立たない。 +> +> 直し方の候補は `except OSError` で捕まえて「コマンドを実行できません(<理由>)」として外すこと。 From 33699a92fe86d63e479a9ff2e1ac2e5738a1f86a Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 22 Sep 2026 16:33:54 +0000 Subject: [PATCH 2/3] =?UTF-8?q?Docs:=20claude=20=E3=81=AE=E5=88=A9?= =?UTF-8?q?=E7=94=A8=E4=B8=8A=E9=99=90=E3=81=AE=E6=96=87=E8=A8=80=E3=81=8C?= =?UTF-8?q?=E6=A8=99=E6=BA=96=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=B8=E5=87=BA?= =?UTF-8?q?=E3=82=8B=E3=81=8B=E3=82=92=E6=9C=AA=E7=A2=BA=E8=AA=8D=E3=81=A8?= =?UTF-8?q?=E3=81=97=E3=81=A6=E6=98=8E=E8=A8=98=E3=81=99=E3=82=8B=EF=BC=88?= =?UTF-8?q?#811=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) --- issues/issue-811-813-design.md | 3 +++ issues/issue-811-813-requirements.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/issues/issue-811-813-design.md b/issues/issue-811-813-design.md index 713f3b996..39787fd73 100644 --- a/issues/issue-811-813-design.md +++ b/issues/issue-811-813-design.md @@ -142,6 +142,8 @@ claude は `You've hit your ` の後に期間や種類(週・セッション claude は JSON を出す形で起動しており、上限の結果行は状態コードを持つ。JSON は 1 行に文章を 含むため、行頭の照合が効かず、担当のレビュー本文の引用に一致しうる。 +claude の 5 形は、codex と共通の 1 行(決定 2)で読める。そのため標準エラーの記録に出れば利用上限になる。ただし、JSON 出力で起動した claude が上限のときに標準エラーへ書いた記録は無い。起動した claude の上限を読む経路は、標準出力の状態コードのままである。 + ### 決定 6: 確認コマンドを起動できないときは、例外の種類を問わず「通らない」として返す 認証の確認は「例外は上げない」を約束しており、起動できない理由(権限・実行形式など)が @@ -243,6 +245,7 @@ graph TD | 項目 | 内容 | | --- | --- | | codex の利用上限の文言の行頭の形 | 400 の誤りで測った形(`ERROR: ` + 本文)からの類推。照合は行頭の印の有無を問わないため、印が別の形(時刻を前に置くなど)だと一致しない。10.16.1 の後に上限に当たった記録で確かめる | +| claude の文言が標準エラーの記録へ出るか | 実測の claude の 5 形の出所は、会話の記録と実行ファイルである。JSON 出力で起動した claude が上限のときに標準エラーへ書いた記録は無い。起動した claude の上限は、標準出力の状態コード(10.16.0 で合格)で読む。10.16.1 の後に上限に当たった標準エラーの記録で確かめる | | codex の再試行の上限の状態の書き方 | 実行ファイルの文字列は `last status: ` までで、状態の後ろの書き方は記録に無い。照合は `429` の直後の語の区切りまでしか見ない | | kiro と agy の利用上限の文言 | 手元の記録に 0 件。kiro は既存の #619 の実物、agy は照合なし | | claude の旧い形 | 記録にも実行ファイルにも 0 件のため足さない(決定 4) | diff --git a/issues/issue-811-813-requirements.md b/issues/issue-811-813-requirements.md index e3eec807a..774c5ac0d 100644 --- a/issues/issue-811-813-requirements.md +++ b/issues/issue-811-813-requirements.md @@ -94,7 +94,7 @@ ndf 10.16.0 のリリース後テスト(PR #810 のコメント、2026-09-22 - [ ] AC1: 標準エラーの記録に codex の利用上限の文言の 1 行が出ると、利用上限として止まる。文言は `You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage …` である。行頭の `ERROR: ` の有無を問わない - [ ] AC2: 標準エラーの記録に codex の再試行の上限の行が出て、最後の状態が 429 なら、利用上限として止まる。行は `exceeded retry limit, last status: 429 Too Many Requests` である。最後の状態が 429 以外(例 `503 Service Unavailable`)なら利用上限にならない -- [ ] AC3: 標準エラーの記録に claude の利用上限の文言が行頭から出ると、利用上限として止まる。確かめる形は設計の「実測」の claude の 5 形(週・セッション・個人の支出・月の支出・期間を書かない形) +- [ ] AC3: 標準エラーの記録に claude の利用上限の文言が行頭から出ると、利用上限として止まる。確かめる形は設計の「実測」の claude の 5 形(週・セッション・個人の支出・月の支出・期間を書かない形)である。JSON 出力で起動した claude がこの文言を標準エラーへ書くかは確かめていない。起動した claude の上限は AC4 の JSON の状態コードで読む - [ ] AC4: 10.16.0 で合格した形は、引き続き利用上限として止まる。形は 4 つで、kiro の `Monthly request limit reached`、claude の JSON の上限の状態コード、HTTP 429 の状態行、`Quota exceeded` である - [ ] AC5: AC1〜AC3 の文言が、表・バッククォート・「」・リスト・引用・grep 形式・Python の文字列・差分の追加行と文脈行・文の途中に出たときは、利用上限として止まらない - [ ] AC6: AC1〜AC5 のテストの入力は、設計の「実測」の表にある実物の文言をそのまま写したものである(推測で作った文言を入力にしない) From cb1a7bfe367bfcdfc64d90f1c0aba3d186c8e629 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 22 Sep 2026 16:40:44 +0000 Subject: [PATCH 3/3] =?UTF-8?q?Docs:=20=E5=AE=9F=E7=89=A9=E3=81=AB?= =?UTF-8?q?=E7=84=A1=E3=81=84=E6=9C=AB=E5=B0=BE=E3=82=92=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=81=AE=E5=85=A5=E5=8A=9B=E3=81=8B=E3=82=89=E5=A4=96?= =?UTF-8?q?=E3=81=97=E3=80=81codex=20=E3=81=AE=E4=B8=8A=E9=99=90=E3=81=AE?= =?UTF-8?q?=E6=A8=99=E6=BA=96=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=AE=E8=A8=98?= =?UTF-8?q?=E9=8C=B2=E3=82=92=E5=AE=9F=E6=B8=AC=E3=81=B8=E5=85=A5=E3=82=8C?= =?UTF-8?q?=E3=82=8B=EF=BC=88#811=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) --- issues/issue-811-813-design.md | 12 +++++++----- issues/issue-811-813-requirements.md | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/issues/issue-811-813-design.md b/issues/issue-811-813-design.md index 39787fd73..66e361c35 100644 --- a/issues/issue-811-813-design.md +++ b/issues/issue-811-813-design.md @@ -46,6 +46,7 @@ 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 ` の後に期間や種類を差し込む作りである | @@ -56,7 +57,7 @@ claude 2.1.278(2026-09-22)。 **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."}} @@ -78,13 +79,13 @@ re.compile(r"^(?:ERROR:\s*)?exceeded retry limit, last status: 429\b", re.MULTIL | 区分 | 入力 | 今の利用上限 | 足した後 | | --- | --- | --- | --- | | 実物 | codex の利用上限(行頭の印あり / なし) | — | 一致 | -| 実物 | codex の再試行の上限 `… last status: 429 Too Many Requests` | — | 一致 | +| 実物(書き出し) | 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 · resets 3am (UTC)` | — | 一致 | +| 実物 | claude の `You've hit your limit`(実行ファイルの文字列) | — | 一致 | | 実物 | kiro の `Monthly request limit reached` / HTTP 429 の状態行 | 一致 | 一致 | | 一致しない | codex の再試行の上限 `… last status: 503 Service Unavailable` | — | — | | 一致しない | codex の 400 の行(上のコードブロック) | — | — | @@ -92,6 +93,8 @@ re.compile(r"^(?:ERROR:\s*)?exceeded retry limit, last status: 429\b", re.MULTIL | 誤検知 | 文の途中、リスト、引用、grep 形式、Python の文字列 | — | — | | 誤検知 | 差分の追加行 `+ERROR: You've hit …`、差分の文脈行 | — | — | +**実物に無い末尾は入力に足さない。** 再試行の上限の状態の後ろ(`Too Many Requests` など)と、claude の期間を書かない形の後ろ(`· resets 3am (UTC)`)は、#811 の表にある形で、記録にも実行ファイルにも無い。照合はどちらも末尾を読まないため、入力は実物の範囲で止める。 + ### 起動できないときの例外 | 条件 | 上がる例外 | `errno` | @@ -244,9 +247,8 @@ graph TD | 項目 | 内容 | | --- | --- | -| codex の利用上限の文言の行頭の形 | 400 の誤りで測った形(`ERROR: ` + 本文)からの類推。照合は行頭の印の有無を問わないため、印が別の形(時刻を前に置くなど)だと一致しない。10.16.1 の後に上限に当たった記録で確かめる | | claude の文言が標準エラーの記録へ出るか | 実測の claude の 5 形の出所は、会話の記録と実行ファイルである。JSON 出力で起動した claude が上限のときに標準エラーへ書いた記録は無い。起動した claude の上限は、標準出力の状態コード(10.16.0 で合格)で読む。10.16.1 の後に上限に当たった標準エラーの記録で確かめる | -| codex の再試行の上限の状態の書き方 | 実行ファイルの文字列は `last status: ` までで、状態の後ろの書き方は記録に無い。照合は `429` の直後の語の区切りまでしか見ない | +| codex の再試行の上限の状態の書き方 | 実行ファイルの文字列は `last status: ` までで、状態の後ろの書き方は記録に無い。テストの入力は `429` までにし、照合も `429` の直後の語の区切りまでしか見ない | | kiro と agy の利用上限の文言 | 手元の記録に 0 件。kiro は既存の #619 の実物、agy は照合なし | | claude の旧い形 | 記録にも実行ファイルにも 0 件のため足さない(決定 4) | | 行頭に固定しても残る誤検知 | 文言で始まる行をそのまま読み上げた場合(文書の本文の行頭に裸で置いた文言を `cat` したときなど)は一致する。この束の文書とテストでは、文言を表・バッククォート・文字列の中にだけ置く | diff --git a/issues/issue-811-813-requirements.md b/issues/issue-811-813-requirements.md index 774c5ac0d..3c036e0c6 100644 --- a/issues/issue-811-813-requirements.md +++ b/issues/issue-811-813-requirements.md @@ -93,7 +93,7 @@ ndf 10.16.0 のリリース後テスト(PR #810 のコメント、2026-09-22 各条件の「利用上限として止まる」は、次の 3 つがそろうことを指す: 監視が担当を止めて早期の致命(終了コード 4)で終わる / 結末の理由が「利用上限」 / 起動し直しの可否が偽。 - [ ] AC1: 標準エラーの記録に codex の利用上限の文言の 1 行が出ると、利用上限として止まる。文言は `You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage …` である。行頭の `ERROR: ` の有無を問わない -- [ ] AC2: 標準エラーの記録に codex の再試行の上限の行が出て、最後の状態が 429 なら、利用上限として止まる。行は `exceeded retry limit, last status: 429 Too Many Requests` である。最後の状態が 429 以外(例 `503 Service Unavailable`)なら利用上限にならない +- [ ] AC2: 標準エラーの記録に codex の再試行の上限の行が出て、最後の状態が 429 なら、利用上限として止まる。行は `exceeded retry limit, last status: 429` で始まる。最後の状態が 429 以外(例 `503 Service Unavailable`)なら利用上限にならない - [ ] AC3: 標準エラーの記録に claude の利用上限の文言が行頭から出ると、利用上限として止まる。確かめる形は設計の「実測」の claude の 5 形(週・セッション・個人の支出・月の支出・期間を書かない形)である。JSON 出力で起動した claude がこの文言を標準エラーへ書くかは確かめていない。起動した claude の上限は AC4 の JSON の状態コードで読む - [ ] AC4: 10.16.0 で合格した形は、引き続き利用上限として止まる。形は 4 つで、kiro の `Monthly request limit reached`、claude の JSON の上限の状態コード、HTTP 429 の状態行、`Quota exceeded` である - [ ] AC5: AC1〜AC3 の文言が、表・バッククォート・「」・リスト・引用・grep 形式・Python の文字列・差分の追加行と文脈行・文の途中に出たときは、利用上限として止まらない