何を見つけたか
/ndf:cross-review のレビュー担当(kiro)が CLI の月間の利用上限に達して応答しなかったとき、状態は NO_RESULT(理由 missing)になり、上限であることがどこにも出ない。 進行側は同じ担当を起動し直し、2 回目も同じ理由で落ちて、ループは final=error で終わった。
PR #601 (issue #545 )の cross-review、round 2(2026-09-13 10:56Z 開始)の実物である。
kiro の標準エラー(kiro-review-pr601-err.log):
Monthly request limit reached
同じラウンドの状態ファイル(cross-review-pr601-state.json の rounds[-1]、抜粋):
{"round" :2 ,"reviewers" :[" codex" ," kiro" ],
"kiro" :{"intent" :" NO_RESULT" ,"no_result_reason" :" missing" ,"posted_as" :null },
"critique_relaunched" :[" kiro" ],"verdict" :" no_result" ,"relaunched" :[" kiro" ]}
全体の final は error。
上限を読む仕組みは 2 つあるが、どちらもこの形を拾わない。
仕組み
何を読むか
拾わない理由
投稿の待ち行列(plugins/ndf/scripts/lib/post_queue.py の is_rate_limited)
GitHub への投稿の失敗
対象が GitHub の上限で、CLI の利用上限ではない
監視の早期の致命検知(plugins/ndf/scripts/lib/monitor.py の EARLY_ERROR_FATAL)
担当の CLI の err.log
上限の語が quota exceeded / rate limit exceeded に限られ、kiro の Monthly request limit reached に一致しない
一致したとしても、理由は missing のままになる。 state.py の NO_RESULT の理由は
missing / not_posted / no_verdict の 3 つで、監視の致命検知の結果を読まない。結果ファイルが無ければ
_read_review_result_file(state.py:2444)が missing を記録し、_die_no_result(:2436)が書き出す。
監視の結果はファイルに残る。 #662 は v10.13.0(2026-09-16)で解決した。 監視の結果は担当ごとの <stem>-monitor.json と
追記だけの monitor-outcomes.jsonl に残り、理由の語彙は
plugins/ndf/scripts/lib/monitor_outcome.py が持つ(ok / timeout / stalled /
early_error / missing / pidfile_bad の 6 語。usage_limit と cli_timeout は未実装)。
読む側がこれを読んでいない。 monitor.py の main(:944)が結果ファイルへ書く一方、state.py は
monitor_outcome を読み込んでおらず、NO_RESULT の理由は missing のままになる。
同じ形の検知漏れ
利用上限のほかにも、担当の CLI が err.log に理由を書いて終わるのに、早期の致命検知に一致せず、結果なし(missing)へ畳まれる形がある。
担当の CLI が書く文言
何が起きたか
課題
Monthly request limit reached
kiro の月間の利用上限
この課題
[agy] print timeout after 10m0s with turn in progress; returning partial output
agy 自身の実行時間の上限
#598 / #537 (v10.13.0 で解決。--print-timeout は上限の表から導く)
ERROR: unexpected status 404 Not Found: The model ... does not exist ...
codex の設定が引けないモデルを指す
#461
"api_error_status":429 を含む行
claude の利用上限。cross-refactoring で同じ項目の再試行が 3729 回記録された
#647
_scan_early_fatal に各文言を 1 行だけ書いた err.log を渡した結果(plugins/ndf/scripts/lib で実行):
'Monthly request limit reached' -> None
'Error: quota exceeded' -> Error: quota exceeded
'[agy] print timeout after 10m0s with turn in progress; retur' -> None
'ERROR: unexpected status 404 Not Found: The model `gpt-5.5` ' -> None
'{"type":"system","subtype":"api_retry","attempt":3,"error_st' -> None
None は一致なし(早期の致命ではない)を表す。対照として置いた Error: quota exceeded だけが致命として返る。
どこで見つけたか
plugins/ndf/skills/cross-review/scripts/state.py (NO_RESULT の判定と起動し直し)
plugins/ndf/scripts/lib/monitor.py の EARLY_ERROR_FATAL(:114-126)
マイルストーン v10.11.0 の並列実行中、PR 設計 Pull Request の本文の決めたことの節を設計文書と突き合わせる(#545) #601 の cross-review round 2。利用者がプランを変更し、kiro の応答を確かめてから再開した
なぜこの変更の範囲外なのか
マイルストーンの対象は各 issue の受け入れ条件に閉じており、cross-review の担当の失敗の分類はどれにも含まれない。発見時は #545 の担当が再開を優先し、起票しないまま進んだ(振り返りで取りこぼしとして拾った)。
直さないと何が起きるか
直し方
土台は入っている。 監視の結果は担当ごとの <stem>-monitor.json と追記だけの
monitor-outcomes.jsonl に残る。残るのは次の 3 つである。
残る作業
現状
理由の語彙を 2 つ足す
monitor_outcome.py の REASONS は 6 語で、usage_limit と cli_timeout は未実装(今は early_error と missing へ落ちる)
検知の文言を足す
EARLY_ERROR_FATAL(monitor.py:114-126)は kiro の Monthly request limit reached に一致しない
読む側を接続する
state.py は monitor_outcome を読み込まず、_die_no_result(:2436)と _read_review_result_file(:2444)が missing / not_posted / no_verdict しか記録しない
由来
PR #617 (ndf v10.11.0 の配布)の振り返り。発生は PR #601 (issue #545 )の cross-review。
関連
次の課題は、同じ出口(結果なし → 同じラウンドで起動し直す → final=error)を持つ。
原因と直す箇所はそれぞれ別で、1 件を直しても他は残る。
根本原因の親:
検知の部分が重なる課題:
初期化の時点で近い課題:
進行
モード: standard / 作業ツリー: .worktrees/feat/issue-729-outcome-vocabulary / 計画: issues/issue-729-619-584-implementation-plan.md
開いたままの理由
PR #791 で直し、ndf 10.16.0(2026-09-22、main / タグ ndf--v10.16.0、PR #810 )で配布した。リリース後テスト(#810 (comment) )の手動確認(#619 の再現)が不合格 だった。kiro の文言と claude の JSON の 429 は理由「利用上限」で起動し直さないが、codex の実物の文言(You've hit your usage limit…、exceeded retry limit, last status: 429)と claude のテキスト出力の文言は missing になり、同じラウンドで起動し直す。#811 を直して確かめ直してから閉じる。
振り返り: #810 (comment)
閉じる理由(2026-09-22)
10.16.0 のリリース後テストで手動確認が不合格だった (kiro と claude の JSON は usage_limit になるが、codex の実物の文言と claude のテキスト出力は missing で relaunch_same_agent=True のままだった)。原因は #811 として切り出し、#820 で直した 。
振り返り: #832 (comment)
何を見つけたか
/ndf:cross-reviewのレビュー担当(kiro)が CLI の月間の利用上限に達して応答しなかったとき、状態はNO_RESULT(理由missing)になり、上限であることがどこにも出ない。 進行側は同じ担当を起動し直し、2 回目も同じ理由で落ちて、ループはfinal=errorで終わった。PR #601(issue #545)の cross-review、round 2(2026-09-13 10:56Z 開始)の実物である。
kiro の標準エラー(
kiro-review-pr601-err.log):同じラウンドの状態ファイル(
cross-review-pr601-state.jsonのrounds[-1]、抜粋):{"round":2,"reviewers":["codex","kiro"], "kiro":{"intent":"NO_RESULT","no_result_reason":"missing","posted_as":null}, "critique_relaunched":["kiro"],"verdict":"no_result","relaunched":["kiro"]}全体の
finalはerror。上限を読む仕組みは 2 つあるが、どちらもこの形を拾わない。
plugins/ndf/scripts/lib/post_queue.pyのis_rate_limited)plugins/ndf/scripts/lib/monitor.pyのEARLY_ERROR_FATAL)err.logquota exceeded/rate limit exceededに限られ、kiro のMonthly request limit reachedに一致しない一致したとしても、理由は
missingのままになる。state.pyのNO_RESULTの理由はmissing/not_posted/no_verdictの 3 つで、監視の致命検知の結果を読まない。結果ファイルが無ければ_read_review_result_file(state.py:2444)がmissingを記録し、_die_no_result(:2436)が書き出す。監視の結果はファイルに残る。 #662 は v10.13.0(2026-09-16)で解決した。 監視の結果は担当ごとの
<stem>-monitor.jsonと追記だけの
monitor-outcomes.jsonlに残り、理由の語彙はplugins/ndf/scripts/lib/monitor_outcome.pyが持つ(ok/timeout/stalled/early_error/missing/pidfile_badの 6 語。usage_limitとcli_timeoutは未実装)。読む側がこれを読んでいない。
monitor.pyのmain(:944)が結果ファイルへ書く一方、state.pyはmonitor_outcomeを読み込んでおらず、NO_RESULTの理由はmissingのままになる。同じ形の検知漏れ
利用上限のほかにも、担当の CLI が
err.logに理由を書いて終わるのに、早期の致命検知に一致せず、結果なし(missing)へ畳まれる形がある。Monthly request limit reached[agy] print timeout after 10m0s with turn in progress; returning partial output--print-timeoutは上限の表から導く)ERROR: unexpected status 404 Not Found: The model ... does not exist ..."api_error_status":429を含む行_scan_early_fatalに各文言を 1 行だけ書いたerr.logを渡した結果(plugins/ndf/scripts/libで実行):Noneは一致なし(早期の致命ではない)を表す。対照として置いたError: quota exceededだけが致命として返る。どこで見つけたか
plugins/ndf/skills/cross-review/scripts/state.py(NO_RESULTの判定と起動し直し)plugins/ndf/scripts/lib/monitor.pyのEARLY_ERROR_FATAL(:114-126)なぜこの変更の範囲外なのか
マイルストーンの対象は各 issue の受け入れ条件に閉じており、cross-review の担当の失敗の分類はどれにも含まれない。発見時は #545 の担当が再開を優先し、起票しないまま進んだ(振り返りで取りこぼしとして拾った)。
直さないと何が起きるか
missingだけで、プランの変更で解けるのか、CLI の不調なのか、結果ファイルの書き出しの遅れ(cross-review: 結果ファイルの書き出しを待たずに NO_RESULT と判定して中断する #584)なのかを区別できない。PR 設計 Pull Request の本文の決めたことの節を設計文書と突き合わせる(#545) #601 では進行側がエラーログを開いて初めて分かった直し方
土台は入っている。 監視の結果は担当ごとの
<stem>-monitor.jsonと追記だけのmonitor-outcomes.jsonlに残る。残るのは次の 3 つである。monitor_outcome.pyのREASONSは 6 語で、usage_limitとcli_timeoutは未実装(今はearly_errorとmissingへ落ちる)EARLY_ERROR_FATAL(monitor.py:114-126)は kiro のMonthly request limit reachedに一致しないstate.pyはmonitor_outcomeを読み込まず、_die_no_result(:2436)と_read_review_result_file(:2444)がmissing/not_posted/no_verdictしか記録しないusage_limitのときは起動し直さずに止めて報告する判断もここに置ける(cross-refactoring の cross-refactoring: 実装担当が停止し続ける項目で適用ラウンドが無限に再試行される #647 と共通)由来
PR #617(ndf v10.11.0 の配布)の振り返り。発生は PR #601(issue #545)の cross-review。
関連
次の課題は、同じ出口(結果なし → 同じラウンドで起動し直す →
final=error)を持つ。原因と直す箇所はそれぞれ別で、1 件を直しても他は残る。
--print-timeoutが 600 秒固定で、大きな差分では CLI が先に打ち切る(CLI の上限)根本原因の親:
usage_limit/cli_timeout)と、state.pyがmonitor_outcomeを読む接続はこちらが持つ検知の部分が重なる課題:
monitor.pyで重なる初期化の時点で近い課題:
進行
モード: standard / 作業ツリー:
.worktrees/feat/issue-729-outcome-vocabulary/ 計画:issues/issue-729-619-584-implementation-plan.md開いたままの理由
PR #791 で直し、ndf 10.16.0(2026-09-22、
main/ タグndf--v10.16.0、PR #810)で配布した。リリース後テスト(#810 (comment) )の手動確認(#619 の再現)が不合格だった。kiro の文言と claude の JSON の 429 は理由「利用上限」で起動し直さないが、codex の実物の文言(You've hit your usage limit…、exceeded retry limit, last status: 429)と claude のテキスト出力の文言はmissingになり、同じラウンドで起動し直す。#811 を直して確かめ直してから閉じる。振り返り: #810 (comment)
閉じる理由(2026-09-22)
10.16.0 のリリース後テストで手動確認が不合格だった(kiro と claude の JSON は
usage_limitになるが、codex の実物の文言と claude のテキスト出力はmissingでrelaunch_same_agent=Trueのままだった)。原因は #811 として切り出し、#820 で直した。mainへ、タグndf--v10.16.1)relaunch_same_agent=False)。10.16.0 で合格していた 4 形も退行していない。記録: Release: ndf v10.16.1 #831 (comment)振り返り: #832 (comment)