Skip to content

carul の根本原因 B-2: 問いの当て先と再開の位置を、今の周回の外から参照で解決する #2664

Open
0 of 4 issues completed

Description

@takemi-ohama

具体例

配布待ちの周回を締め直すまとめの途中で区分つきの問いを出すと、loop hold-question は「進行中の周回が無い」で断り、答えを当てる場所が無くなる(#2638)。queue --resume --from はステップ名だけで照合するのでフルパスを断り(#2639 の 1 つ目)、強制終了した前の起動が残っていると無視して前の途中のステップから続ける(#2325)。

依頼(原文)

carulプロジェクトから大量のissueが届きました。
プロジェクトの進行に影響がある課題が多いので、そちらも1レーン使って対応します
ただし、いくつかの根本原因がトリガーのようですので、ひとつづつ直すのではなく根本原因を見つけて対処してください

阻害要因になっている上限の撤廃、保存先の永続化の問題、周回の問題が大きいようです

(書き手: 利用者、日付: 2026-11-06。親の課題 #2648 の本文から引用した)

次の文は課題を起票した AI の本文で、利用者の指示の原文ではない。

#2648(束 B)のうち、問いの当て先と再開の位置を、今の周回・今の起動の中の値でなく参照で解決する。

値 今の取り方 直す先
問いの当て先 進行中の周回だけ(lib/sprint_loop.py:546-556 cmd_hold_question。締め直しの cmd_finish の途中は進行中でない) 保留中も含むその周回を引く
再開の位置 名前の照合と前の起動の途中のステップ(supervise_lib/queue_resume.py:85) 耐久の記録の完了済みと指定の位置から決める
  1. 配布待ちの周回の締め直しの途中で出した問いを loop hold-question が受け付け、答えの後に止まったステップから続く
  2. --from にフルパスを渡しても再開でき、前の起動が残っていても指定が効く
  3. 取り込み済み・完了済みのプランを流し直さない(queue の再開が、取り込み済み・完了済みの実装のプランを流し直し、差分なしの PR 作成で止まる #2349)
  4. 問いの答えで再開するとき、答えの中身を読んでから流す(開発ループ: 問いの答えで再開するとき、答えの中身を読まずに止まったプランを流す #2466)
  5. 1〜4 をそれぞれ縛るテストがある
  6. 開発ループ: 保留の周回を締め直す途中で出た問いを loop hold-question が「進行中の周回が無い」で断り、答えを当てる場所が無くなる #2638・queue --resume の --from がフルパスを断り、再開したキューが配布の依頼の関門で 10 を返して loop lap が打たれない #2639・queue --resume の --from が、強制終了した前の起動が残っていると無視され、前の途中のステップから続く #2325・queue の再開が、取り込み済み・完了済みの実装のプランを流し直し、差分なしの PR 作成で止まる #2349・開発ループ: 問いの答えで再開するとき、答えの中身を読まずに止まったプランを流す #2466 の再現の手順を 1 回ずつ通し、消えたものは理由を添えて閉じ、残ったものは理由を本文に書く

#2639 の 2 つ目(配布の依頼の関門で queue --resume が 10 を返し、pipeline の && が loop lap を打たない)は結果の契約の問題で、#2337 に残す。

(書き手: 起票者、日付: 2026-11-06。本文の書き方と、#2648 の分割の節から、起票した AI の文と判断した)

この要求の整理の指示(書き手: AI の起動指示、日付: 2026-11-06):

人へ問わずに進め、決められない点は前提か未決として課題の本文へ書く。

解釈: 利用者が求めているのは、周回の問題を 1 件ずつでなく根本原因で直すことである。この課題が受け持つのは、「今の周回・今の起動」の中の値しか見ないため、保留の周回の締め直しとキューの続きで、問いが当たらず、再開の位置が食い違う経路である。

起票者の推定

題・本文のうち、利用者の原文に無く起票者が推して足した条件と、この要求を書いた AI が問わずに選んだ案。承認ゲート 1 で利用者が確かめるまで、利用者の決定として扱わない。

# 条件 推した出所 この要求での扱い
S1 問いの当て先は「保留中も含むその周回」である 本文の表、#2648 の「直せば消える理由」 受け入れ条件 1・2
S2 締め直しの途中で問いを保留したら周回を質問待ちへ戻し、前の配布の答えは残す #2638 の「直し方の案」 受け入れ条件 1・3
S3 再開の位置は、耐久の記録の完了済みと指定の位置から決める 本文の表 受け入れ条件 7〜9
S4 --from は名前とフルパスの両方で照合し、断る文に渡し方を書く #2639 の「期待」 受け入れ条件 6・7
S5 --from があれば前の途中の耐久ワークフローを子ごと止める #2325 の受け入れ条件、#2342 の決定 5 受け入れ条件 8
S6 --from で始めても実行条件を先に評価する。完了の後に中身が変わったプランは流さずに知らせる #2349 の「直したいこと」1・2、#2344 の受け入れ条件 6・7 受け入れ条件 10・12
S7 答えが差し戻し(rejected・revise)なら止まったプランを流さない。通常の答え(approved・answered)は中身を持ち主へ渡し、持ち主が読んで続けるかを決める #2466 の「決めること」。この要求を書いた AI が選んだ。--revise・--rejected は答えを送る人が選ぶ機械が読める値で、自由記述(#2638 の「まだ」)の意味は機械では読めないため、判断は持ち主の AI に置く(MVV の Value 5)。誤ると読み方の設計を直す手戻りが出るが、課金・外部公開・安全性に当たらないため問わずに選んだ 受け入れ条件 13〜15
S8 問いに続けないと答えたら周回を「人へ戻した」で締める #2466 の「決めること」2。配布の差し戻しの締め方(settle_release)に揃えた 受け入れ条件 13・15
S9 対象の課題は 1 件ずつ直さず、根本原因を直した後に再現の手順を 1 回ずつ通し、閉じるか残すかを本文に書く 本文の受け入れ条件 6、#2648 の「進め方」 受け入れ条件 18
S10 #2639 の 2 つ目は #2337 に残す 本文の「範囲の外」、#2648 の「直しても残るもの」 含まない
S11 #2342・#2344 の実装を待たず、この課題が今のキューの続きと開発ループのコードの上で直す 親の #2648 が子課題へ分けた判断と、#2342・#2344 が先行の柱のマージを待っている事実(下の「調べた事実」)。この要求を書いた AI が選んだ 前提 1

調べた事実

2026-11-06、ブランチ design/issue-2664(起点 v10.27.33-dev.1)で確かめた。

事実 根拠
--from はプランのファイル名でしか照合しない。ファイル名(4-check)と末尾の一致(impl-2044)は当たり、フルパス・相対パス・4-check.json は当たらない supervise_lib/queue_fill.py の named を実行(4-check と impl-2044 は True、フルパス・sprint/4-check.json・4-check.json は False)
キューの続きが途中の耐久ワークフローを止めるのは、プランの並びが変わったときだけである。続きは同じ並びを渡すため、--from があっても前の途中を続ける supervise_lib/queue.py の cmd_queue の flow.launch_queue(..., listing.get("plans") != all_plans) と durable.resolve の読み取り。実行では未確認(受け入れ条件 18 で通す)
前の起動が done を書けずに落ちたとき、続きは一覧に残した開始のステップだけを使い、途中のプランの最後のステップを見ない supervise_lib/queue_resume.py の if prev is None: found = kept
実行条件は開始のステップがあると打たない。この振る舞いは利用者向けの説明にも書いてある supervise_lib/engine.py:219、supervise_lib/plan.py:149(「--from で再開するときは打たない」)
耐久の実行の回の鍵はプランの中身を含むため、完了の後にプランが変わると完了の記録に当たらず流れる supervise_lib/flow.py:80-82 の prefix_of
hold-question は進行中の周回だけを見る。締め直しの途中の周回は保留のまま(結果が配布待ち・質問待ち)で、cmd_finish はこの間に届いた loop finish を受け付ける lib/sprint_loop.py:546-556・:524-534
答えの届いた質問待ちの周回は、答えの中身によらず pipeline を返す。答えは result(approved・revise・rejected・answered)・choice・note を持つ lib/sprint_loop_gate2.py の answered_lap、parallel.py:399、lib/parallel_run.py:358
質問待ちの続きは、止まったプランを run --from で流した後に、まとめのプランの全部をキューへ入れる。止まったプランがまとめの中にあると、同じプランが開始のステップなしでもう 1 度流れる lib/sprint_loop_gate2.py の finish_pipeline の読み取り。実行では未確認(受け入れ条件 3 で確かめる)
周回の秒は、配布待ちと質問待ちの両方の区間があると配布待ちの区間だけを足す lib/sprint_loop_record.py:266、tests/test_sprint_loop.py の test_characterize_active_seconds_held_lap(「両方あれば release を使う」)
#2342 の PR 2480 と #2344 の PR 2482 は設計文書のマージで、実装は develop に入っていない。lib/run_core.py・lib/lease.py・lib/refs.py は無い ls lib/run_core.py lib/lease.py lib/refs.py がいずれも「No such file or directory」、gh pr view 2482 --json files(issues/ の外は用語集の 2 件だけ)

目的

前提

対象範囲

含む:

含まない:

ドメインイベント

# イベント 引き金 失敗したとき 順序の前提
E1 周回を保留で締めた 配布の依頼・問い — —
E2 答えが届き、締め直しの pipeline を組んだ 周回の境の loop select・loop pending 差し戻しは流さない(E7) E1
E3 締め直しの途中で問いを送った まとめのプランの作業 送れない → 今の問いの扱いのまま E2
E4 問いの当て先の周回を引き、質問待ちへ戻した loop hold-question 当たる周回が無い → 断り、記録を変えない。引いた周回が複数ある → 止まったプランの属する周回を選ぶ E3
E5 元の pipeline の loop finish が遅れて届いた E3 の前に流れていた pipeline 質問待ちへ戻した後の done → 断り、周回は質問待ちのまま E4
E6 答えの中身を読み、記録した 周回の境 読めない → 答えが無いものとして待つ E4
E7 続けないと判断し、周回を締めた 差し戻しの答え、または持ち主の判断 — E6
E8 止まったプランをステップの続きから流し、残りとまとめを流して締め直した 続ける答え 途中で止まる → 周回は失敗で締まる E6
E9 キューの続きが開始の位置を決めた queue --resume 指定のプランが一覧に無い → 何も流さず stopped 一覧が done の隣にある
E10 --from があるため前の途中を子ごと止めた E9 止められない → 何も流さず stopped E9
E11 プランごとに実行条件を評価し、流すか飛ばすか知らせて止まるかを決めた E9・E10 判定できない → 止まった E10

洗い出しで移したもの: E4 の当たる周回の選び方は受け入れ条件 2 に、E5 は受け入れ条件 4 に、E11 の 3 つの分かれ方は受け入れ条件 10〜12 に置いた。E7 の持ち主の判断の手段は未決に置いた。

用語

用語 意味
周回 開発ループの 1 回分。選定から締めるまで
保留の周回 並列の計画のループのレーンで、答えを待たずに締めた周回(配布待ち・質問待ち)
質問待ち 作業の途中の問いをオーガナイザーへ送り、止まったプランとステップを残して締めた周回の結果
配布待ち 配布の依頼を送り、答えを待たずに締めた周回の結果
キューの続き supervise.py queue --resume <done>。前の起動のステージの並びを読み、完了していないプランを終えたステップから続ける
実行条件 プランを流す前に打つコマンド。skip_code を返せば worktree を作らずに完了とする
耐久の記録 1 回の起動が持つ DBOS の SQLite のファイル
done キューが終わったときに書く結果の JSON

受け入れ条件

問いの当て先

  • 1. 配布待ちの周回の締め直しの途中で loop hold-question を打つと、受け付けて ok を返し、周回の結果が質問待ちになり、question に依頼の id・止まったプラン・ステップが入り、release の答えと本番の版が残る
  • 2. 進行中の周回と締め直しの途中の周回が同時にあるとき、hold-question は --plan のプランが属する周回へ当たる。どの周回にも当たらないときは断り、周回の記録は変わらない(stopped。理由に周回が見つからないことと渡した --plan が出る)
  • 3. 1 の問いの答えの後、止まったプランが指定のステップから 1 回だけ流れ、残りのステージとまとめが流れて周回が締め直される。止まったプランがまとめの中にあっても、頭からもう 1 度流れない
  • 4. 質問待ちへ戻した周回に、戻す前に流れていた pipeline の loop finish が届くと断り、周回は質問待ちのままで、問いの答えを当てられる
  • 5. 締め直しの途中で問いが当たった周回の秒は、配布待ちの区間と質問待ちの区間の両方を足し、答えを待っていた時間を足さない

再開の位置

  • 6. queue --resume <done> --from <プラン>=<ステップ> の <プラン> に、一覧の stages に載ったフルパスと、同じファイルを指す相対パスを渡すと、ファイル名を渡したときと同じプランを同じステップから流す
  • 7. どのプランにも当たらないときは何も流さずに stopped を返し、断る文に「名前かフルパスで渡す」ことが出る
  • 8. 前の起動が強制終了で途中のまま残っていても、--from があれば、前の途中の耐久ワークフローを子ごと止め、指定のステップから新しい実行の回で流す。止められなければ何も流さず stopped を返す
  • 9. 8 のとき、--from の対象でないプランのうち、完了したものは流れず、途中だったものは頭からでなく終えたステップから続く
  • 10. キューの続きで開始のステップを持つプランの実行条件が飛ばす条件に当たると、そのプランは流れず、結果は 完了 で、理由に実行条件に当たらないことが出る
  • 11. 完了したプランを含む done を --from なしで --resume すると、完了したプランは流れず、記録した結果を返す
  • 12. 完了の後にプランのファイルが変わっていて --from が無いとき、そのプランは流れず、queue --resume は gate(終了コード 10 番台)で返り、変わったプランと、流し直す手段(--from)が結果に出る

答えの中身

  • 13. 質問待ちの周回に rejected か revise の答えが届くと、止まったプランは流れず(pipeline が空)、周回は「人へ戻した」で締まる
  • 14. 質問待ちの周回に approved か answered の答えが届くと、loop select と loop pending は status: finish と今の形の pipeline に加えて、metrics.answer に result・choice・note を返す
  • 15. 持ち主が答えの中身を読んで続けないと決めたとき、止まったプランを流さずに周回を「人へ戻した」で締める手段が 1 つある
  • 16. どの答えでも、答えの中身(result・choice・note・読んだ時刻)が周回の question に残り、loop status か loop.json から読める

テストと確かめ

起きてはいけないこと

  • 19. 進行中の周回への hold-question は、今と同じく周回を質問待ちで締め、答えの後に止まったプランを指定のステップから流す(退行しない)
    前提の確認: uv run --frozen --project . --all-extras pytest plugins/ndf/scripts/tests/test_sprint_loop.py -q -n 4 の test_hold_question_closes_the_lap_and_the_answer_resumes_the_stopped_plan → 通過(2026-11-06、v10.27.33-dev.1)
  • 20. --from の無い queue の打ち直しは、今と同じく落ちた前の起動を続け、済んだステップを流し直さない(退行しない)
    前提の確認: uv run --frozen --project . --all-extras pytest plugins/ndf/scripts/tests/test_supervise_queue.py -q -n 4 -k killed_queue_continues_from_the_running_step → 1 passed(2026-11-06)
  • 21. --from の名前の照合(ファイル名と末尾の一致)と、{queue_pr:<名>}・前提のプランの照合の結果が変わらない(退行しない)
    前提の確認: tests/test_supervise_queue_continue.py の test_resume_with_from_and_without_a_listing → 通過(2026-11-06)
  • 22. 承認ゲート 2 の承認の後の続き(run --from)は、実行条件で飛ばされない(前提 5。退行しない)
    前提の確認: supervise_lib/engine.py:219 の読み取り(開始のステップがあると打たない)。設計の前にテストで固定する
  • 23. 配布待ちの周回の released の答えの後の流れ(rejected・失敗の答えの締め方を含む)は変わらない(退行しない)
    前提の確認: tests/test_sprint_loop.py → 通過(2026-11-06)
  • 24. 全体テスト uv run --frozen --project . --all-extras pytest . -q -n 4 が、マージの前後で通る

非機能の条件

大項目 条件
運用・保守性 queue --resume は標準エラーへ、プランごとの開始の位置と理由(--from・前の結果・前の起動の開始・実行条件で飛ばす・完了の後に変わった)を 1 行ずつ出す。hold-question の結果に当たった周回の番号が出る
移行性 移す対象は無い。今の loop.json(question が 1 つの形)と done.plans.json をそのまま読める。切り戻しは PR の revert で前の形へ戻る。ただし、質問待ちへ戻した周回の記録が残っていると、前の版の loop finish がその周回を締める

影響

対象 影響
公開インタフェース 変わる(互換あり)。hold-question・queue --resume の引数は変わらない。--from が受ける値が増える。queue --resume --from は前の途中を止める。queue --resume は完了の後に変わったプランで gate を返す。loop select・loop pending の metrics.answer と、続けないときの手段が増える
データ スキーマの移行は無い。loop.json の周回の question に答えの鍵が増え、同じ周回に release と question が両方入る
既存の振る舞い 変わる。rejected・revise の答えで止まったプランが流れない。キューの続きで実行条件が評価される(plan.py の説明文を直す)。手順 2' の「pipeline をそのまま流す」に「答えを読んでから」が足される(references/loop.md・references/asking.md)

検証手段

項目 手段
テスト uv run --frozen --project . --all-extras pytest . -q -n 4。開発ループは tests/test_sprint_loop.py、キューの続きは tests/test_supervise_queue_continue.py に足す
静的解析・構造の検査 python3 scripts/check-script-structure.py、python3 scripts/check-ndf-contracts.py
配布物の検証 claude plugin validate .
手動確認(マージ前) #2325 の再現の手順(キューを強制終了し、--from で別のステップを指定する)を直した版で 1 回通し、結果を PR に書く。プロセスの強制終了を含むため、1 本の単体テストの外でも確かめる
手動確認 受け入れ条件 18: 5 件の再現の手順を本番へ出した版で通し、閉じるか残すかを各課題の本文に書く(リリース後テスト)

前提とする取り決め

項目 参照先 / 決めたこと
プロジェクト構造 既定で働くため plugins/ndf/scripts/ の今の場所に置き、experimental/ に置かない。factory/ を参照しない(AGENTS.md の「マーケットプレイスの構造」「安定版と実験版」)
コーディング規約 AGENTS.md の「最小限のコード実装」と、外部コマンド・自分で書いた入出力の形を書く前に実行して確かめる決まり
テスト戦略 開発ループは記録を使うテスト、キューの続きは実プロセスのテスト(test_supervise_queue*.py の形)で担保する。.md の文言を照合するテストは書かない(AGENTS.md の DON'T)

境界

区分 内容
常に行う #2342 の決定 5・#2344 の決定 8 の形に合わせる。全体テストと構造の検査を通す。plan.py・references/loop.md・references/asking.md の説明を振る舞いと揃える
確認してから行う(承認ゲート 1・2 で人が見る) queue --resume --from の振る舞いの変更と、gate を返す新しい経路。references/loop.md の手順 2' の契約の変更(公開インタフェース)
行わない 対象の課題を 1 件ずつ直す Pull Request。#2342・#2344 の範囲(持ち主の記録・プランの型・参照の部品)を先取りする変更。範囲外のリファクタリング

未決

項目 誰が決めるか 期限
受け入れ条件 15 の手段の形(新しい副命令か、既存の副命令の引数か)と、続けないときに fixes へ行を足して課題を次の周回で選ぶか この課題の設計 設計 Pull Request
受け入れ条件 12 の判定に使う前の中身の置き場。キューの差し込みがプランのファイルを書き戻すため、差し込みによる書き換えを「変わった」と読まない形(#2663 の PR 2669 と同じ箇所に当たる) この課題の設計 設計 Pull Request
同じ周回に問いが 2 回当たるときの記録の形(question の上書きと履歴のどちらか。受け入れ条件 16 は最後の問いと答えの両方が読めることを求める) この課題の設計 設計 Pull Request
受け入れ条件 12 の gate の終了コードの番号(step_result の表の範囲で選ぶ) この課題の設計 設計 Pull Request

関連

親: #2648。再開: #2342。参照: #2344。対象の課題: #2638・#2639・#2325・#2349・#2466

進行

モード: —

  • 要求と受け入れ条件 — 2026-11-06 15:59
  • 作業場所の用意
  • 設計 — 2026-11-06 16:05
  • 素材の収集と出典の確定
  • ドキュメント再構成 — 2026-11-06 16:23
  • ドキュメントレビュー
  • 計画
  • 実装
  • 構造改善
  • 実装レビュー
  • 完了判定
  • Pull Request
  • 確定仕様化
  • 後片付け
  • 配布
  • 体裁レビュー
  • リリース後テスト
  • 振り返り
  • 棚卸し

人の判断待ち(開発ループ lcarul2)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions