Repository navigation
Description
依頼(原文)
異常系処理とログ出力、異常時の回復処理が統一されていないから起こる不具合・課題が多い。1 件ずつ対処してもきりがない
内部データ構造と出力のフォーマットの不統一の影響も大きそう
NDF は Skill の Script 化から発展してきたため、内部データ構造や入出力契約がほぼ整理されていない
出力だけでなく入力もそろえるべき
(書き手: 利用者、日付: 2026-11-01。この課題の「調べ方」の節が引用した利用者の指摘。課題のほかの節(具体例・調査・あるべき姿・進め方・構成・受け入れ条件の初版)は、起票者(課題を書いた AI)が 2026-11-01 に調査と組み直しの記録として書いた文で、利用者の指示の原文として扱わない)
解釈: 利用者が求めているのは、異常系の扱い・記録・回復と、内部データ・入力・出力の形を NDF 全体で 1 つにそろえ、同じ型の不具合を 1 件ずつではなく型ごとに無くすことである。「1 つの実行の核へ集める」「柱 9 本に分ける」は、その手段として起票者が選んだもので、下の「起票者の推定」に並べて承認ゲート 1 で確かめる。
起票者の推定
題・本文のうち、上の利用者の原文に無く、起票者が推して足した条件。承認ゲート 1 で利用者が確かめるまで、利用者の決定として扱わない。
| # | 条件 | 推した出所 | この要求での扱い |
|---|---|---|---|
| S1 | 統一の手段は、すべてのステップを通す 1 つの「実行の核」である(部品を増やすのでなく、通らせる仕組みを作る) | 本文「あるべき姿」「根本の原因」 | 受け入れ条件 1 |
| S2 | ステップの出口は ok / gate / stopped の 3 つだけ。例外・中断・時間切れ・判定できないは stopped |
本文「あるべき姿」の結果の契約 | 受け入れ条件 2 |
| S3 | 記録は実行の識別子つきの JSON Lines 1 つの形 | 本文「あるべき姿」の記録 | 受け入れ条件 3 |
| S4 | 持ち主と並行の排他は同じ lease で取る | 本文「あるべき姿」の持ち主と後片付け | 受け入れ条件 4・4a |
| S5 | 上限と再試行の値は 1 つの宣言に置き、timeout=<数字> の直書きを残さない |
本文「あるべき姿」の再試行と上限・受け入れ条件 5 の初版 | 受け入れ条件 5(数え方を前提 3 で決め直した) |
| S6 | プランは値でなく参照を持ち、実行の直前に解決する | 本文「あるべき姿」の入力の解決 | 受け入れ条件 6 |
| S7 | 再開の手段は耐久の記録(durable)1 つにする |
本文「あるべき姿」の末尾 | 受け入れ条件 7 |
| S8 | A〜F の課題 103 件は 1 件ずつ直さず、柱を入れた後に再現の手順を通して閉じるか残すかに分ける | 本文「進め方」4 | 受け入れ条件 8・境界の「行わない」 |
| S9 | 効果は「後の 1 か月の新しい課題に占める A〜F の割合が 82% より下がる」で測る | 本文の受け入れ条件 9 の初版 | 受け入れ条件 9(起点と数え方を足した) |
| S10 | データの型は版を持ち、結果は status、時刻は UTC の ISO 8601 の at にそろえる |
本文「あるべき姿」のデータの契約 | 受け入れ条件 10 |
| S11 | 機械が読む出力は 1 行 JSON だけ。本文の値は <!-- ndf:... --> の機械用のブロックから読む |
本文「あるべき姿」の出力の形 | 受け入れ条件 11 |
| S12 | 引数の名前は --root / --out / --timeout などにそろえ、値の解決は「引数 → 環境変数 → 設定 → 既定値」の順 |
本文「あるべき姿」の入力の契約 | 受け入れ条件 12 |
| S13 | hook は核の対象から外す | 本文の受け入れ条件 1 の初版 | 対象範囲の「含まない」 |
| S14 | 柱 9 本(#2336〜#2344)・マイルストーン 28〜30・ループ lroot で進め、m26-3 が本番へ出た後に始める |
本文「構成と進め方(2026-11-01 の組み直し)」(書き手を確かめられない。利用者の指示を受けた組み直しの可能性がある) | 前提 1・2 |
| S15 | この課題の設計が終わるまで、A〜F の新しい課題は個別に直さずこの課題の子として起票する(即時修正の 4 条件と本番の停止は除く) | 本文「進め方」の末尾 | 前提 4 |
| S16 | 入口 91 本・受け渡しのファイル 114 種類・設定 15 種類・環境変数 56 種類などの数 | 本文「何を見つけたか」(2026-11-01 の grep) | 前提 3(棚卸し P0 が確定する) |
目的
- NDF の手順のスクリプトが、成功・失敗の判定・記録・後片付け・再試行と上限・入力の解決と、受け渡すデータの名前と形を、それぞれ自分で書かずに済む状態にする。新しいステップを足しても、A〜F(失敗の判定・記録・回復・待ちと上限・解決の時点・並行の衝突)の型の不具合が同じ仕組みで防がれる
- 達成したい状態: 入口とデータの契約が 1 か所の宣言にあり、宣言と実行の核を通らないコードを検査が落とす。既存の A〜F の課題は、型ごとの仕組みを入れた後にまとめて確かめて閉じる
具体例
スプリント m26-2(2026-10-31〜11-01)は、本番へ出すまでに conductor が手で 9 回止めて直した。どれも別々の課題として起票され、別々に直される。
| 起きたこと | 起票 | 原因の型 |
|---|---|---|
cross-review が final: error で終わったのに drive が exit 0 を返し、承認・マージへ進んだ |
#2143 | A 失敗の判定 |
| 打ち切った cross-refactoring の持ち主の記録に終了時刻が書かれず、24 時間「使用中」として次の実行を断った | #2321 | C 回復・再開 |
強制終了したキューを再開すると、--from が無視された |
#2325 | C 回復・再開 |
| 最終ゲートが締め切りを理由に、develop の取り込みまで巻き戻した | #2323 | D 待ち・上限 |
| 全体テストの CI 待ちが、PR で外した必須チェックをメインディレクトリの宣言から読み、待ち続けた | #2317 | E 解決の時点 |
| 版を作った時点に決めたため、並行するループが先に出して衝突した(3 回目) | #2164 | E 解決の時点 |
1 件ずつ直しても、同じ型の新しい事例が別の部品から出る。
何を見つけたか(2026-11-01 の調査)
課題の実物: 未完了 194 件の原因の型
未完了の課題 194 件を、本文から原因の型に分けた(分類の記録は下の「調べ方」)。
| 型 | 件数 | 何が起きるか |
|---|---|---|
| A 失敗の判定 | 39 | 失敗・未収束・判定できないを ok で返す。成功を失敗と読む。報告の自由文と結果の status が切り離されている |
| B 記録・ログ | 14 | 何が起きたか後から追えない。記録が漏れる・数え違う。止まった理由が途中で切れる |
| C 回復・再開 | 18 | 中断・強制終了の後に再開できない。持ち主・ロック・worktree・状態ファイルの残骸が次を止める |
| D 待ち・上限 | 13 | 上限の値と待ちの組み合わせで止まる・巻き戻す。同じ失敗の打ち直しが上限まで回る |
| E 解決の時点 | 14 | プランを作る時点の値(版・PR・宣言・予算・触るファイル)が実行の時点で古い |
| F 並行の衝突 | 5 | 並行するスプリント・ループ・プランが同じものを触る |
| G 機能・方針 / H 文書 / I その他 | 91 | 不具合でないもの・文書の直し・個別の事情 |
- A〜F(異常系・回復系)は 103 件。 新機能と文書(G・H)を除いた不具合 125 件の 82% に当たる。従の型まで含めると 127 件が関わる
- マイルストーンごとの A〜F: 24 後回しの軽微な課題 42/80、26 自律実行の信頼性 23/28、03 研究基盤 12/20、23 汎用性の回復 9/23
- 10 月以降、起票 289 件・完了 271 件。直す速さと同じ速さで新しい課題が出ている
コードの実物: 共通部品はあるが、通らずに済む
#1142 の L0 で共通部品を作った。足りないのは部品ではなく、部品を必ず通らせる仕組みである。
| 観点 | 共通部品 | 実物(plugins/ndf/scripts・skills/*/scripts、テストと実験版を除く) |
|---|---|---|
| 結果の形と終了コード | lib/step_result.py |
scripts の入口 37 本のうち 24 本が使う(hook を除き 10 本が外れる)。skills の Python 121 本のうち使うのは 11 本。全部の入口に形を強制するテストは無い |
| ログ | 無い | logging は 1 ファイル。print(..., file=sys.stderr) 52 ファイル、sys.stderr.write 5、独自の log()/info() 4 つ。実行を通して追う識別子が無い |
| 失敗の扱い | lib/proc.py(StepError) |
except Exception 48 か所、except の後が pass だけの箇所 49 か所。sys.exit の直書き 44 か所、raise SystemExit 11 か所 |
| 再試行 | lib/waits.py(tenacity) |
使う側 33 ファイル。ほかに再試行の関数が 8 個ある(design_stage._retrying・_gh_retrying・_git_retrying、paths._add_worktree_with_retry、post_queue.retry、cross-review の _retry_unmatched_scope、cross-refactoring の push_with_retry_marker など) |
| 上限 | 無い | timeout=<数字> の直書き 195 か所 |
| 持ち主と寿命 | lib/run_state.py・lib/run_owner.py(#2229) |
使う側 7 と 6。異常終了の後の後片付け(終了時刻を書く)は呼ぶ側の責任で、打ち切りの経路では書かれない(#2321) |
| 再開 | lib/durable.py(DBOS) |
使う側 25。再開の入口ごとに --from や状態ファイルの扱いが違う(#2325・#1592・#1635) |
| シェル | lib/step-result.sh |
29 本のうち set -euo pipefail は 4 本 |
コードの実物: 内部データと出力の形がそろっていない
同じ意味の値が、ファイルごとに別の名前と別の形で書かれ、読まれる。読む側が名前と形を推して読み違えると、A(失敗の判定)か E(解決の時点)の不具合として現れる。
| 観点 | 実物 |
|---|---|
| 同じ意味の別名 | 結果を表すキーが status(57 ファイル)・result(31)・verdict(22)・decision(15)・final(13)・exit(13)・outcome(8)・code・exit_code の 9 通り。PR は pr・prs・Pull Request・pull_request、課題は issue・issues・課題・number、理由は reason・text・summary・message・why |
| 日本語と英語のキーの混在 | 文字列で読むキーは 1,612 種類。うち日本語 82 種類(課題・フェーズ・実行の条件・取り込み先・触るファイル など。プランの JSON は日本語、状態と結果は英語) |
| 型の定義 | dict を文字列のキーで読む箇所が 4,500。型を持つのは dataclass 65 ファイル・NamedTuple 34・pydantic 7 で、スキーマの検査(jsonschema)は 0。状態ファイルの名前は 114 種類、版を持つのは 44 ファイル |
| 時刻 | isoformat 27 ファイル・strftime 17・time.time() 29。キーも at・started_at・ts・time・timestamp・created_at に分かれる |
| 出力の形 | 1 行 JSON(step_result)、Markdown の報告(## フェーズの報告・## 作業の報告)、シェルで eval する KEY=VALUE(30 ファイル)、YAML(5)。conductor は Markdown の報告を読んで次の手を決める |
| 文書を機械が読む | 課題・PR の本文の見出し(## 受け入れ条件・## 配布の記録・## 設計の結果 など)を読むファイルが 14、本文から正規表現で値を拾うファイルが 43、Markdown の表を割って読むファイルが 24。人が書く形の揺れがそのまま判定の誤りになる |
形が原因に関わる課題の例(分類の根拠の文から拾った 25 件の一部):
- 「対象の版:」の
vの付いた版を読めず課題を閉じない(sprint-close がリリース後テストの「対象の版:」に v の付いた版を読めず、課題を閉じない #2225) - 見出しの形を確かめずに通し、後で「受け入れ条件の節が無い」で落ちる(要求の工程が、## 受け入れ条件 の節を持たない本文を通す(承認後の new sprint で初めて落ちる) #2246)
- 表のセルが割れて合格と読まない(リリース後テストの表でコード表記の中の | がセルを割り、sprint-close が合格と読まずに理由も示さない → 書く側でエスケープし、読む側は割れた行を名指しする #1985)
- agy の JSON の鍵を確かめず本文が空になる(agy の --output-format json の成功時の形(response・usage の鍵)を実物で確かめないまま本番へ出ている → 認証の通る環境で確かめ、違えば読み方を直す #1981)
- 短い SHA を完全一致で比べる(merge-when-green の --expect-head が短い SHA を完全一致で比べ、同じ先端でも head_moved で止まる #2041)
- 想定どおりの exit 2 を最終結果と読む(mvv-gate: 設計のプランで、設計の前に打った requirements-check の exit 2 を材料に読み、関門 1 の助言が unknown になる #1502・承認ゲート 1 の MVV 判定が、要求の文書を書く前の requirements-check の exit 2 を材料の欠けと読む #2237)
- 条件失敗の判定が 3 か所で形が違う(factory/api: DynamoDB の条件の失敗の判定が 3 つの保存に別々にあり、判定の形が揃っていない #2275)
コードの実物: 入力の渡し方もそろっていない
同じものを受け取るのに、入口ごとに名前・渡し方・置き場所が違う。呼ぶ側(Skill の本文・プランの雛形・conductor)が入口ごとの違いを覚えて書くため、渡し忘れと渡し違いが起きる。
| 観点 | 実物 |
|---|---|
| 引数の読み方 | argparse 59 ファイル、sys.argv を手で読む 16 ファイル。オプションは 311 種類、位置引数は 78 |
| 同じものの別の名前 | リポジトリの根が --root(26 ファイル)・--repo(17)・--worktree(3)・--dir(2)・--cwd(1)。出力先が --out・--out-dir・--output・--json・--report。上限が --timeout・--budget・--budget-minutes・--limit・--max。版が --version・--to・--dev・--prod。PR は --pr のほかに位置引数で受ける入口がある |
| 環境変数 | 読む環境変数が 56 種類(NDF_*・CROSS_REVIEW_TMP_DIR・CROSS_REFACTORING_TMP_DIR など)。どの入口がどれを読むかの一覧が無い |
| 設定ファイル | .ndf/ の設定と記録が 15 種類(project.json・worktree.json・supervise.json・release.json・pace.json・ask.json・review.json・runtimes.json など)。同じ値を 2 か所が持つ(本番のブランチが worktree.json の production_branch と project.json の delivery、#2097)。どのファイルをメインディレクトリから読み、どれを worktree から読むかが入口ごとに違う(#2317・#1709) |
| 標準入力 | 標準入力から読むファイルが 28 |
| 値の優先順位 | 引数・環境変数・設定ファイル・既定値のどれが勝つかが入口ごとに違う |
入力が原因に関わる課題の例:
- 雛形が
--sync-commandを渡さない(検査のプランの構造改善が --sync-command を渡さず、生成元に触れる改善が push で止まる #2049) - 予算を渡さず既定の 30 分で打ち切る(検査のプランの構造改善が既定の予算で下限に届かず、33 行の差分でも refactor が落ちて abort へ進む #2047)
- オプションの付け忘れで判定が飛ぶ(sprint-close: --with-verification を付け忘れると、リリース後テストに不合格の行を持つ課題も閉じる #2293 の
--with-verification) - 着手前のテストがディレクトリを
{paths}に入れる(cross-refactoring: 全体テストを CI に任せる戦略の着手前のテストがディレクトリを {paths} へ入れ、ファイルだけを受けるテンプレートで落ちる #2096) - 起動の形が書かれておらず codex が標準入力待ちで止まる(document-rebuild: 読み手役を外部の CLI で立てるときに、止まらず文脈を持たない形で起動できるようにする #2114)
成り立ち: NDF は Skill の手順をスクリプトへ移すことで育った。スクリプトは Skill の 1 つの手順を自動にするために書かれ、そのたびに入力・出力・状態の形をその場で決めた。入口は scripts 直下に 52 本、Skill の scripts 直下に 39 本あり、Skill の本文から呼ばれるスクリプトの行は 60 種類ある。どの入口についても、受け取るもの・返すもの・書く状態を 1 か所に宣言した契約は無い(契約は Skill の本文・README・コードの docstring に散っている)。その後スクリプト同士が互いの出力と状態を読むようになり、決めていなかった契約が、読み違いの不具合として現れている。
根本の原因: 1 つのステップが「成功・失敗の判定」「記録」「後片付け」「再試行と上限」「入力の解決」をそれぞれ自分で書き、受け渡すデータの名前と形もそれぞれが決める。部品は呼べば使えるが、呼ばなくても書けて、検査も落とさない。そのため新しいステップのたびに同じ型の不具合が生まれる。
あるべき姿
すべての手順のステップは 1 つの実行の核の中で動く。 核が次の 8 つを引き受け、ステップは仕事の中身だけを書く。
| 核が持つもの | 今の型 | 決まり |
|---|---|---|
| 結果の契約 | A | ステップの出口は ok / gate / stopped の 3 つだけ。例外・中断・時間切れ・判定できないは核が stopped と理由に変える。ok は欠けが無いときだけ。worker の報告も同じ形で返し、自由文から完了を読まない |
| 記録 | B | 核が実行の識別子を振り、開始・終了・判断・失敗を 1 つの形の JSON Lines へ書く。標準エラーへの診断も同じ関数を通る。止まった理由は切らずに残す |
| 持ち主と後片付け | C・F | 核が実行の持ち主(lease)を取り、どの終わり方でも(正常・例外・シグナル・時間切れ)終了時刻と片付けを書く。並行の排他も同じ lease で取る |
| 再試行と上限 | D | 上限と再試行の方針を 1 つの表(宣言)に置き、核が当てる。同じ原因の失敗を繰り返さない(打ち直しの回数と、原因が同じかを核が見る) |
| 入力の契約 | E・A | 入口が受け取るもの(引数・環境変数・設定・標準入力)を契約の一覧に宣言し、同じものには同じ名前を使う(リポジトリの根は --root、出力先は --out、上限は --timeout など)。値は 1 つの読み込み部品が「引数 → 環境変数 → 設定 → 既定値」の決まった順で解決し、どこから来た値かを記録へ書く。設定は 1 つの値を 1 か所だけが持つ |
| データの契約 | A・E | 実行・プラン・状態・記録・結果の種類ごとに型(スキーマと版)を 1 つ持ち、同じ意味には 1 つの名前を使う(結果は status、時刻は UTC の ISO 8601 の at など)。核が読み書きの両方で型を確かめ、合わなければ stopped にする |
| 出力の形 | A・B | 機械が読む出力は 1 行 JSON の 1 形だけにする。Markdown は人へ見せる描画で、機械はそれを読まない(フェーズレポートも JSON を正にして Markdown を生成する)。課題・PR の本文から値を読む箇所は、本文に埋めた機械用のブロック(例 <!-- ndf:... --> の JSON)か、記録の JSON から読む |
| 入力の解決 | E | プランは値でなく参照(版・PR・宣言・予算)を持ち、核がステップの直前に解決して記録する。解決できなければ流さずに止まる |
再開は耐久の記録(durable)を唯一の手段にする。 --from と状態ファイルの手当ては核の上の 1 つの入口へ寄せる。
進め方
1 件ずつ直すのをやめ、型ごとにまとめて直す。
- 契約の棚卸しと定義(最初に行う): 入口 91 本と、入口の間で受け渡す状態・記録・結果のファイル(名前 114 種類)を一覧にし、それぞれの入力(引数・環境変数・設定・標準入力)・出力・書く状態・終了コードを 1 か所の宣言(契約の一覧)へ書き出す。
.ndf/の設定 15 種類と環境変数 56 種類も、どの入口が読むかを書く。今の振る舞いを写すだけで、変えない。ドメインの語(スプリント・プラン・ステップ・実行・課題・PR・リリース・記録)ごとに型を決め、同じ意味の別名を対応表にまとめる。以後の手順はこの一覧を正として進める - 止血(先に入れる): 新しく足すステップと入口が核を通らなければ、構造の検査(
scripts/check-script-structure.py)が落とす。今の外れは許可の一覧に載せ、一覧は減る方向にしか変えられない(ratchet) - 核とデータの型を作る: 既存の
step_result・proc・jsonio・locks・waits・durable・run_stateを束ねる。新しく書くのは束ね方・記録と上限の表・データの型の定義(名前の対応表を含む)だけにする。データの型は版を持ち、古い形の読み込みは型の側の移行関数 1 か所で受ける - 移す: 課題の集まる部品から順に核へ移す。分類で集まった部品は次のとおり
- supervise のプラン・judge・キュー(
supervise_lib) - cross-refactoring(
refactor.py・持ち主・着手前テスト・最終ゲート) - 課題を閉じる処理(
sprint-close.py・sprint_close_lib) - リリース(
release-steps.py・release_templates.py) - 外部 CLI の監視と結果の受け渡し(
lib/monitor_*・external-ai) - 使用量の帳簿(
lib/usage_*)
- supervise のプラン・judge・キュー(
- 既存の課題をまとめて閉じる: 移した部品に属する A〜F の課題は、移した後に再現の手順を 1 回ずつ通し、再現しないものを理由を添えて閉じる。1 件ずつの修正の Pull Request は作らない
この課題の設計が終わるまで、A〜F の型の新しい課題は個別に直さず、この課題の子として起票する。 例外は即時修正の 4 条件を満たすものと、本番を止めているもの。
構成と進め方(2026-11-01 の組み直し)
柱
この課題の子は柱 9 本で、未完了の課題 113 件を柱の子へ付け直した(既存の親 #2227・#2228・#2229・#2230・#715・#1142 は子ごと柱の下へ入れた)。振り分けは、課題の本文を 2 本の worker で読み、「この大方針の核・契約・型がそろえば解消する可能性があるか」で決めた。
| 柱 | 課題 | マイルストーン | 子の数 |
|---|---|---|---|
| P0 | #2336 契約の棚卸し | 28 | 17 |
| P1 | #2337 結果の契約 | 29 | 23 |
| P2 | #2338 記録とログ | 29 | 8 |
| P6 | #2339 データの契約 | 29 | 4 |
| P7 | #2340 出力の形 | 29 | 6 |
| P8 | #2341 入力の契約 | 29 | 14 |
| P3 | #2342 持ち主・後片付け・並行 | 30 | 19 |
| P4 | #2343 再試行と上限 | 30 | 12 |
| P5 | #2344 実行時点の解決 | 30 | 9 |
マイルストーン
| マイルストーン | 中身 |
|---|---|
| 28 根本解決 1: 設計と契約の棚卸し | この課題の設計と、柱 P0 |
| 29 根本解決 2: 結果・記録・データ・入出力の契約 | 実行の核と、柱 P1・P2・P6・P7・P8 |
| 30 根本解決 3: 回復・上限・実行時点の解決 | 柱 P3・P4・P5 |
進行中のスプリント(m26-1〜m26-3)の課題は、閉じる処理が終わるまでマイルストーン 26 に残し、親だけ柱へ付け直した。
2 大方針の並列
当面の開発は「25 Neural Development Factory」とこの根本解決の 2 本を並列で進める。どちらも開発ループで回す。
| Factory | 根本解決 | |
|---|---|---|
| ループ | 既存の l20261031(選定の対象を 25 へ戻す) |
新しい lroot(選定の対象は 28 → 29 → 30) |
| 主に触る場所 | factory/ |
plugins/ndf/ |
| 選ぶもの | 25 の課題 | 柱と、この課題(子の課題は選定から外し、柱の仕組みを入れた後にまとめて確かめて閉じる) |
始める時期: m26-3(#2164 版数を流す時点に決める、を含む)が本番へ出た後。2 本のループが同時に版を出しても衝突しないようにするためである。
2 大方針の外の課題は、31 費用の削減とテストの軽量化・32 Skill の機能と手順・33 文書と用語・34 研究基盤・汎用性・利用者を増やす、の 4 つへまとめた。当面は 2 大方針の後に扱う。
前提
- 前提 1: この課題(異常系・ログ・回復とデータ・入出力の形を 1 つの実行の核へ集め、異常系の課題 103 件を型ごとにまとめて解く #2335)の工程で作るのは、実行の核と契約の形を決める設計文書である。実装は柱 9 本(入口・受け渡しのファイル・設定・環境変数の契約を 1 か所に宣言し、宣言の外を検査で落とす #2336〜プランは値でなく参照を持ち、実行の直前に解決して照合する #2344)が、それぞれの設計とマイルストーン(28〜30)で行う。この課題は、柱がすべて閉じ、受け入れ条件 8・9 を確かめた時点で閉じる
- 前提 2: 柱の実装は m26-3 が本番へ出た後に、ループ
lrootで始める。始める前にplugins/ndf/の同じファイルを触る変更が入っても、柱の設計は契約の一覧(P0)を正として読み直す - 前提 3: 本文の数(入口 91 本・ファイル 114 種類・
timeout=<数字>195 か所など)は 2026-11-01 の調査の値で、受け入れ条件の判定には使わない。判定は「契約の一覧にある全部」「検査が落とすか」で行う。2026-11-01 に打ち直したgrep -rnE "timeout=[0-9]"(テストとexperimental/を除く)は 17 か所、timeout=全体は 78 か所で、本文の 195 と一致しない。受け入れ条件 5 は数でなく検査で判定する形にした - 前提 4: この課題の設計が承認されるまで、A〜F の型の新しい課題は個別に直さず、柱の子として起票する。例外は即時修正の 4 条件を満たすものと、本番を止めているもの
- 前提 5: 核が使う外部ライブラリは、既にある optional extras(
schemaの pydantic・waitsの tenacity・durableの dbos と filelock)の範囲に置く。新しい依存を足すときは設計で比べて承認ゲート 1 で示す - 前提 6: SIGKILL・電源断のように後片付けのコードが動けない終わり方は、終わった実行では書けない。この場合は、次の実行が持ち主の記録(pid と開始時刻)から持ち主の死を判定して片付ける(受け入れ条件 4a)
対象範囲
含む:
plugins/ndf/scriptsとplugins/ndf/skills/*/scriptsの入口・ステップ(Python とシェル。テストとexperimental/を除く)- 入口の間で受け渡す状態・記録・結果のファイル、プランの JSON、
.ndf/の設定、入口が読む環境変数 - 入口を呼ぶ側の書き方(Skill の本文・プランの雛形・conductor・supervisor・worker の報告の受け取り)
- 既存の A〜F の課題 103 件の閉じる・残すの仕分け
含まない:
- hook(
plugins/ndf/hooks/と hook から呼ぶ*-guard.sh)を核へ移すこと。hook は短い時間の上限の中で動き、核の記録と lease を持たせない factory/(Neural Development Factory)と、ほかのプラグイン(playwright-kit・mcp-*)- G 機能・方針 / H 文書 / I その他の課題(91 件)
- 子の課題を 1 件ずつ直す Pull Request(即時修正の 4 条件を満たすものと本番を止めているものは除く)
- 実験版(
plugins/ndf/scripts/experimental/)。実験版を本体へ移すときは、移す変更が核を通す
ドメインイベント
1 回の入口の実行で起きることを時間の順に並べる。設計のドメインモデルの節は同じ番号を引き継ぐ。
| # | イベント | 引き金 | 失敗したとき | 順序の前提 |
|---|---|---|---|---|
| E1 | 入口が起動された | Skill の本文・プラン・conductor・利用者のコマンド | 契約の一覧に無い引数・環境変数を受けた → stopped(理由に名前) |
— |
| E2 | 入力を解決し、値ごとの出所(引数・環境変数・設定・既定値)を決めた | E1 | 必須の値が無い・1 つの値を 2 か所の設定が持つ → stopped |
E1 |
| E3 | 実行の識別子を振り、記録へ開始を書いた | E2 | 記録の置き場へ書けない → 標準エラーへ理由を出して stopped |
E2(記録の置き場はリポジトリの根から決まる) |
| E4 | 持ち主(lease)を取った | E3 | 他の生きた実行が持つ → 待つか stopped を結果に出す。死んだ実行の残骸 → 片付けてから取る |
E3 |
| E5 | プランの参照(版・記録の PR・宣言・予算)を解決して記録した | E4 | 解決できない・承認ゲートで見た値と食い違う → stopped か gate |
E4(解決は lease の中で行い、並行する実行と同じ値を取り合わない) |
| E6 | 読んだデータの型と版を確かめた | E5 | 古い版 → 型の側の移行関数で読み替える。読み替えられない → stopped |
E5 |
| E7 | ステップの中身を実行した | E6 | 例外・SIGTERM・時間切れ → stopped と理由 |
E6 |
| E8 | 失敗したステップを再試行した | E7 の一時的な失敗 | 同じ原因の失敗が宣言の回数に達した → stopped |
E7 |
| E9 | 書くデータの型と版を確かめた | E7 | 合わない → 書かずに stopped |
E7 |
| E10 | 結果を ok / gate / stopped と決まった終了コードで返した |
E9 か、E1〜E8 のどこかの失敗 | — (欠けがあれば ok にしない) |
E1 |
| E11 | 記録へ終了を書き、持ち主の記録に終了時刻を書いて lease を返した | E10 | SIGKILL などで書けない → 次の実行の E4 が片付ける(前提 6) | E10 |
| E12 | 人へ見せる Markdown を結果の JSON から描いた | E10 | 描けない → 結果の JSON はそのまま返る(判定に使わない) | E10 |
| E13 | 中断した実行を耐久の記録から再開した | 利用者・conductor の再開の指示 | 耐久の記録が無い・壊れている → stopped。--from の指定がある → 指定のステップから始める |
E3 の識別子と耐久の記録がある |
洗い出しで移したもの: E3 の失敗(記録が書けない)は記録より前に起きるため、受け入れ条件 3a に標準エラーへの出し方を置いた。E11 の SIGKILL は前提 6 と受け入れ条件 4a に置いた。E2 と E4 の順(lease の置き場が入力の解決に依る)は設計で確かめる(未決)。
用語
| 用語 | 意味 |
|---|---|
| 実行の核 | 入口・ステップが必ず通る共通の実行の仕組み。入力の解決・記録・lease・型の確認・再試行と上限・結果の変換を引き受け、ステップは仕事の中身だけを書く |
| 契約の一覧 | 入口ごとの入力(引数・環境変数・設定・標準入力)・出力・書く状態・終了コードと、受け渡すファイルの形を 1 か所に書いた宣言 |
| 原因の型 | 課題を原因で分けた A〜I の区分。A 失敗の判定・B 記録とログ・C 回復と再開・D 待ちと上限・E 解決の時点・F 並行の衝突・G 機能と方針・H 文書・I その他 |
| 柱 | この課題の子で、原因の型ごとの仕組みを入れる課題(P0〜P8、#2336〜#2344) |
| 許可の一覧 | 核と契約を通らない今の外れを並べた一覧。構造チェックが読み、一覧を増やす変更を落とす |
| 機械用のブロック | 課題・PR の本文に埋めた、機械が値を読むための <!-- ndf:... --> の JSON |
| 実行の識別子 | 1 回の入口の実行に核が振る識別子。記録・持ち主の記録・耐久の記録をつなぐ |
受け入れ条件
番号は初版(2026-11-01、起票者)を引き継ぐ。初版から書き換えた条件は、条件の下に書き換えた点を残す。どの柱が満たすかを括弧に書く。
この課題の設計(マイルストーン 28)で満たすもの
- D1. 設計文書が「決めること(設計で)」の 5 項目それぞれに、選んだ案・比べた案・理由を持つ
- D2. 設計文書が、実行の核の入口の形(Python とシェルのそれぞれ)と、ステップが核へ渡すもの・核から受けるものを、型の名前とフィールドで書く
- D3. 設計文書が、契約の一覧のファイルの置き場と形(入口・ファイル・設定・環境変数の各行に何を書くか)を決め、柱 P0 がそのまま書き始められる
- D4. 設計文書が、受け入れ条件 0〜12 のそれぞれを満たす柱を 1 つ以上指し、柱の間の順序(どの柱がどの柱の仕組みを前提にするか)を書く
- D5. 設計文書が、引数名・出力の形・状態ファイルの形を変えるときの互換の扱い(旧い名前と旧い形をいつまで受けるか)を決める
大方針として満たすもの(柱がそろって満たす)
- 0. 入口と受け渡しのファイルすべての契約(入力・出力・書く状態・終了コード)が契約の一覧にあり、一覧に無い入口・ファイル・キーを検査が落とす(P0)
- 書き換えた点: 「入口 91 本」を「入口すべて」にした(数は前提 3)
- 1. hook を除くすべての入口とステップ(
plugins/ndf/scriptsとplugins/ndf/skills/*/scripts)が実行の核を通り、通らないものを構造チェックが落とす。許可の一覧は空になる(P0 が検査と許可の一覧を入れ、P1〜P8 が空にする) - 1a. 許可の一覧に行を足す変更を、構造チェックが落とす(P0)
- 書き換えた点: 本文「進め方」1 の ratchet を条件に足した
- 2. 正常・例外・SIGTERM・時間切れのどの終わり方でも、結果は
ok/gate/stoppedのどれかと、それぞれに決まった終了コードで返る(P1) - 2a. 欠けか例外があるのに
okを返す経路が無いことを、契約の一覧のすべての入口を回すテストが確かめる(P1)- 書き換えた点: 初版の 2 を、終わり方の条件と経路の条件の 2 つに分けた
- 2b. worker と外部 CLI の報告は構造化した結果で受け取り、自由文から完了を判定する箇所が残らない(P1・P7)
- 3. 1 回の実行の開始から終わりまでを、実行の識別子 1 つで、1 つの記録(JSON Lines)から追える。止まった理由が切れずに残る(P2)
- 3a. 記録の置き場へ書けないとき、核は標準エラーへ理由を出して
stoppedを返す(P2) - 4. 正常・例外・SIGTERM・時間切れのどの終わり方でも、持ち主の記録に終了時刻が書かれ、次の実行が残骸で止まらない。cross-refactoring の init が着手前テストの打ち切りで止まると、持ち主の記録が残り次の実行を 24 時間断る #2321 の再現の手順で確かめる(P3)
- 4a. SIGKILL で終わった実行の残骸は、次の実行が持ち主の死を判定して片付け、止まらない(P3)
- 書き換えた点: 前提 6 の終わり方を足した
- 5. 上限(時間・予算・待ち)と再試行の回数は 1 つの宣言から読まれ、テストを除くコードの
timeout=・上限と再試行の定数に数字のリテラルがあると検査が落とす(P4)- 書き換えた点: 初版の「
timeout=<数字>の直書きが残らない」は定数(例DEFAULT_TIMEOUT = 1800)を通すため、定数も対象にし、検査で判定する形にした
- 書き換えた点: 初版の「
- 5a. 同じ原因の失敗の打ち直しは宣言の回数で止まり、理由が結果に出る(P4)
- 6. プランは版・記録の PR・宣言の値を参照で持ち、核が実行の直前に解決する。解決できなければ流さずに止まる。スプリントのプランが作った時点の版数を配布と本番のプランへ書き込み、並行する別のスプリントがその版を先に出すとプランを作り直すまで止まる #2164・リリース記録の PR を、まとめのプランを組む時点でなく実行の時点で解決する #2230 の実装をこの形へ寄せる(P5)
- 7. 再開の手段は耐久の記録 1 つで、強制終了の後の再開で
--fromが効く。queue --resume の --from が、強制終了した前の起動が残っていると無視され、前の途中のステップから続く #2325 の再現の手順で確かめる(P3) - 8. A〜F の課題 103 件それぞれを、閉じた(再現の手順で解消を確かめた)・柱の子として残した(核の外の原因)のどちらかに分け、理由をこの課題の本文に記録する(各柱)
- 9. すべての柱が本番へ出た日から 30 日の間に起票された課題のうち、不具合(G・H を除く)に占める A〜F の割合が 82%(2026-11-01 の値)より下がる。分類は「調べ方」と同じ手順(本文の先頭 2500 字から主の型を 1 つ)で行い、分類の記録を残す(この課題)
- 書き換えた点: 「後の 1 か月」の起点と、割合の分母を足した
- 10. 実行・プラン・状態・記録・結果の種類ごとに型の定義(スキーマと版)が 1 つあり、核が読み書きの両方で確かめる。合わなければ
stoppedを返す(P6) - 10a. 同じ意味の値は 1 つの名前で、名前の対応表に無い別名が残らないことを検査が確かめる(P6)
- 書き換えた点: 初版の 10 を型の条件と名前の条件の 2 つに分けた
- 10b. 前の版の NDF が書いた状態ファイル・記録を、新しい版の核が型の側の移行関数で読める(P6)
- 11. 機械が次の手を決めるために読む出力は 1 行 JSON だけで、Markdown の報告・課題や PR の本文の自由な見出しと表から判定の値を読む箇所が残らない。人が書いた本文から読む値は機械用のブロックから読む(P7)
- 12. 同じものを受け取る引数は全部の入口で同じ名前で、
sys.argvを手で読む入口が無い(P8) - 12a. 引数・環境変数・設定・既定値の解決の順を 1 つの部品が決め、値ごとの出所が記録に残る(P8)
- 12b. 1 つの値を持つ設定ファイルは 1 つだけで、契約の一覧に無い引数・環境変数・設定のキーを検査が落とす(P0・P8)
- 書き換えた点: 初版の 12 を名前・解決の順・置き場の 3 つに分けた
起きてはいけないこと
- 13. 記録(JSON Lines)・入力の出所の記録に、秘密(トークン・鍵・認証情報)の値が書かれない。秘密に当たる環境変数は出所の名前だけを書く(P2・P8)
- 14. NDF が利用者の
.ndf/の設定を自動で書き換えない。設定の形を変えるときは、旧い形を移行関数で読み、書き換えは利用者へ案内する(P0・P6・P8) - 15. optional extras(pydantic・tenacity・dbos)が入っていない環境で、核は例外で落ちずに
stoppedと足りない extras の名前を返す(核) - 16. 既存の全体テストが、各柱のマージの前後で通る(各柱)
非機能の条件
| 大項目 | 条件 |
|---|---|
| 性能・拡張性 | 核を通すことによる 1 入口の起動の増分は、設計で python3 <入口> --help を変更の前後で 10 回ずつ測った中央値の差で示し、上限の値を設計文書に置く(未決) |
| 運用・保守性 | 記録: 1 回の実行を実行の識別子で開始から終了まで追える(受け入れ条件 3)。秘密の値を残さない(受け入れ条件 13)。保存: 記録の置き場と寿命は設計で決める(決めること 3) |
| 移行性 | 移す対象: 入口・状態ファイル・記録・プランの形。順序: 柱の順(P0 → P1・P2・P6・P7・P8 → P3・P4・P5)。並走: 移す途中は許可の一覧に載った入口が旧い形のまま動き、核を通る入口と同じ版に並ぶ。旧い版が書いた状態ファイルは移行関数で読む(受け入れ条件 10b)。切り戻し: 柱ごとの Pull Request を revert すれば前の形へ戻る |
| セキュリティ | 秘密: 受け入れ条件 13。認証・認可(C2)と秘密の扱い(C1)は変えない。秘密を扱う lib/auth.py・lib/git-credential.sh を核へ移す変更は、承認ゲートで人が見る |
| システム環境 | 依存: 前提 5。Claude Code と Codex の両方の配布で同じ核が動く。シェルの入口は bash で動く |
影響
| 対象 | 影響 |
|---|---|
| 公開インタフェース | 変わる。入口の引数名・結果の JSON・終了コード・Skill の本文が書くコマンドの形が変わる。互換の扱いは設計が決める(受け入れ条件 D5)。旧い名前を受ける期間を持たない入口は 互換なし を付ける |
| データ | 変わる。状態ファイル・記録・プランの JSON に型と版が付く。旧い形は移行関数で読む(受け入れ条件 10b)。利用者の .ndf/ は自動で書き換えない(受け入れ条件 14) |
| 既存の振る舞い | 変わる。今 ok を返している欠けのある結果が stopped になり、ループと承認ゲートで止まる回数が一時的に増えうる |
検証手段
| 項目 | 手段 |
|---|---|
| テスト | uv run --frozen --project . --all-extras pytest . -q -n 4(全体テスト)。核の終わり方(正常・例外・SIGTERM・SIGKILL・時間切れ)ごとのテストと、契約の一覧の全入口を回すテスト |
| 静的解析・構造の検査 | python3 scripts/check-script-structure.py(CI のジョブ script-structure)。契約の一覧・許可の一覧・上限のリテラル・名前の対応表の検査はここへ足す |
| 配布物の検証 | claude plugin validate . |
| 再現の手順 | #2321(打ち切った持ち主の終了時刻)・#2325(強制終了の後の --from)・#2164・#2230 の再現の手順を、該当する柱のマージの前に通す |
| 手動確認 | 受け入れ条件 9: すべての柱が本番へ出た日から 30 日後に、その間に起票された課題を「調べ方」と同じ手順で分類し、割合を本文に書く |
前提とする取り決め
| 項目 | 参照先 / 決めたこと |
|---|---|
| プロジェクト構造 | 核は既存の部品と同じ plugins/ndf/scripts/lib/ に置く。既定で働くため実験版(experimental/)に置かない。factory/ を参照しない(AGENTS.md の「マーケットプレイスの構造」) |
| コーディング規約 | AGENTS.md の「最小限のコード実装」・外部コマンドを書く前に実行して確かめる決まり。Skill の frontmatter は python3 scripts/check-skill-frontmatter.py |
| テスト戦略 | 核は単体テストで終わり方ごとの結果を担保し、入口は契約の一覧から作る契約のテストで担保する。子の課題は再現の手順で確かめる。.md の文言を照合するテストは書かない(AGENTS.md の DON'T) |
境界
| 区分 | 内容 |
|---|---|
| 常に行う | 契約の一覧を正として変更する。柱ごとに全体テストと構造チェックを通す。核を通した入口を許可の一覧から消す |
| 確認してから行う(承認ゲート 1・2 で人が見る) | 新しい依存の追加。互換なし になる入口の変更。.ndf/ の設定の形の変更(C7)。秘密を扱う部品を核へ移す変更(C1) |
| 行わない | 子の課題を 1 件ずつ直す Pull Request(前提 4 の例外を除く)。hook を核へ移す。利用者の .ndf/ を NDF が自動で書き換える。許可の一覧に行を足す |
対象の課題(主の原因の型ごと)
- A 失敗の判定(39 件): cross-refactoring: テストを足す項目(add-tests)が pytest の収集しないファイルへテストを足し、実行されないまま検証を通る #620 cross-refactoring: 提案担当の codex が結果ファイルを提出先に書けず NO_RESULT になる(提出先が読み取り用ディレクトリの外) #750 cross-review の監視が、err.log に写った既存コメントの「quota exceeded」を codex の利用上限と誤判定して中断する #1411 mvv-gate: 設計のプランで、設計の前に打った requirements-check の exit 2 を材料に読み、関門 1 の助言が unknown になる #1502 cross-refactoring: CI に任せる戦略の最終ゲートで、CI で落ちた範囲外のテストを修正の CLI が再現できない #1657 実装のプランが要求の手動確認(マージ前)を残したまま「完了」で返り、検査のプランの merge-gate まで conductor に見えない #1682 このリポジトリの runtime-plugin-validate.yml の 9 ジョブがテストの宣言に無く、cross-refactoring の項目が壊しても手元で拾えない #1694 「別の文脈の AI が手順を辿れる」受け入れ条件を担うステップがプランに無く、実装の worker が残したまま完了へ進む #1699 plan-to-spec: spec-finalize が --spec を 1 つしか受けず、既存の複数ファイルの確定仕様へ溶かすと残りのファイルがコミットに入らないまま ok で終わる #1715 release: plugin_dir と changed-plugins がプラグインの置き場を ndf・playwright-kit の名前で決め打ち、他のリポジトリで package-plugin の手順が止まる #1756 CI のチェックの結論を失敗と数える集合が lib/gh_checks.py と merged_lib/checks.py で別々にあり、取り消しと stale の扱いが食い違う #1774 cross-refactoring の assess が dbt の .sql を本番コードに数えず、飛ばしてよいと判定する #1777 relay: /goal の続きの応答では stop_hook_active が真になり、背景の作業が残る ndf-next の応答で Stop を止めて知らせる仕組みが働かない #1877 verify-install の Kiro は --plugins を見ず ndf の版を読むため、ndf 以外のプラグインで必ず version_mismatch になる #1889 agy の --output-format json の成功時の形(response・usage の鍵)を実物で確かめないまま本番へ出ている → 認証の通る環境で確かめ、違えば読み方を直す #1981 supervise が worker の途中の報告の「止まった」の語に反応し、作業の中身(止まったものとみなす実装)でも conductor へ attention を出す #1984 リリース後テストの表でコード表記の中の | がセルを割り、sprint-close が合格と読まずに理由も示さない → 書く側でエスケープし、読む側は割れた行を名指しする #1985 merge-when-green の --expect-head が短い SHA を完全一致で比べ、同じ先端でも head_moved で止まる #2041 サブモジュールのリポジトリでメインディレクトリを .git/modules の下と取り違え、project-decl.py check が宣言を「無い」と返す #2054 gws-check.py がトークンの無い状態(auth_method: none)を認証済みと判定して exit 0 を返す #2067 既定ブランチ宛の実装 PR の本文の閉じる語で、マージの時点に課題が閉じ、仕上げの工程と受け入れ条件のチェックが閉じた課題に残る #2082 実装のプランの design-tests が、設計で改名を決めたテストを止まりと判定せず、止まった理由を全文で残す #2118 sprint-close: 最終工程を通っていない課題を、リリース後テストの前に閉じないようにする #2119 リリース後テストの起動指示が根拠に指した配布の記録が条件の経路を通ったかを確かめず、#2104 の昇格の経路が実機で一度も通らないまま残る #2166 sprint-close がリリース後テストの「対象の版:」に v の付いた版を読めず、課題を閉じない #2225 全工程の結果を統一した JSON レポートにし、失敗・未収束・未記録を ok で返さない #2227 課題を閉じる時点を 1 つにし、最終の工程を通ってから閉じる #2228 棚卸しの切り出しの境界が人の判断待ちの行を容量に数える #2232 承認ゲート 1 の MVV 判定が、要求の文書を書く前の requirements-check の exit 2 を材料の欠けと読む #2237 handoff.py が終了コード 4・5 を共通の表と違う意味で返し、emit の検査も通らない #2241 要求の工程が、## 受け入れ条件 の節を持たない本文を通す(承認後の new sprint で初めて落ちる) #2246 取り込み(absorb)の後、取り込まれた課題の受け入れ条件の一部が取り込み先の実装から落ちたまま完了になる #2274 factory/api: DynamoDB の条件の失敗の判定が 3 つの保存に別々にあり、判定の形が揃っていない #2275 本番のプランの verify が導入の確認だけを流して「リリース後テスト」を通ったと記録し、受け入れ条件ごとの記録が無いためスプリントを閉じる工程で課題が閉じない #2288 結果を読む共通の関数(step_read.py の試行と置き場の読み方)を製品のコードが使わず、承認資料は試行の選び方を自前の last_result に持ち続ける #2289 sprint-close: --with-verification を付け忘れると、リリース後テストに不合格の行を持つ課題も閉じる #2293 中継の Stop の hook が、別のセッションの承認待ちを報告しただけの応答を「本文で承認を待って終わった」と差し戻す #2324 スプリントの閉じる条件 3: 別のリポジトリの課題が振り返りの記録を満たせず開いたまま残る #2327 NDF のスクリプトの結果の JSON・ログ出力・異常系の処理を 1 つの形へ揃える #2334
- B 記録・ログ(14 件): supervise.py のフェーズレポートが、設計の関門 1 でも「関門: 本番の系へ届く操作」と書く #1516 設計のプランで作成者 t <a@b>・題 tmp のコミットが設計ブランチに入り、worker の報告に出ない #1687 CHANGELOG の ndf 10.17.61 の節から移行の手順が消え、利用者が認証のし直しを知れない #1755 引継ぎ文書に「作成済み」と書いたファイルが実在しなくても、書く時点にも読む時点にも気付けない #1835 cross-refactoring の見送った提案(budget・not_done)が起票されず、マージの後に振り返りが改修計画を読むまで残らない #1839 後片付けを終えても課題の工程表の「後片付け」の行が未チェックのまま残る #1893 トークン削減の効果をサブエージェントだけで判定し、claude -p へ移しただけの施策を削減と数えている → 全体の値で測り直し、効いていない施策を戻すか直す #1957 usage-report.py の閉じた課題の数が UTC の日付で数えられ、使用量の集計(JST の日付)と期間がずれる → JST の両端で数える #1978 使用量の帳簿が同じ message.id の最後の usage を捨て、続けたサブエージェントを 2 回数え、日をまたぐ会話を丸ごと採るか落とす → 会話の記録の合計と一致させる #1979 cross-refactoring の drive が完了した回を返す案内に、持たない --reopen を書く #2057 監視が先に別の早期の警告を出していると、非致命にした permission_denials の件数を警告に残さない #2059 開発ループの周回の created[] を書く経路が無く、周回の中で起票した課題が記録に残らない #2132 NDF Factory: インフラ(private リポジトリ)の課題を辿れず、実環境の受け入れが保留のまま実施の契機が無い #2200 検査の記録の集計で閾値を見直せない: トリガーの評価が 0 回・落ちた工程が「不明」・流出不具合の記録が 0 行 #2300
- C 回復・再開(18 件): supervise.py のキューを頭から流し直すとき、状態ディレクトリを退避しても dbos の queue-*/review-* の記録から途中のステップへ戻る #1592 operation: 取り消しの手段に書いたコマンドが実在して効くかを、承認の前に確かめる手順が無い #1622 cross-review: drive.py --reopen が final=error で止まった耐久ワークフローを新しい実行の回へ移さない #1635 棚卸しで上限を超えて持ち越した候補が、次のスプリントの棚卸しへ渡らない #1640 supervise: pr のステップの push が一時的な拒否(missing necessary objects)で落ちても再試行せずプランを止める #1653 引き継ぎ文書に大きさの上限が無く、milestone-26.md が 52KB に育って conductor が区間の頭で毎回 3 万文字を読み込む #1785 作業ツリーから起動したキューが、後片付けで消えた cwd により --then の計画で落ちる #1886 配布の後片付けが承認資料 issues/approval-*.md を消さず、版ごとに未追跡のファイルがメインディレクトリへ溜まる #2009 NDF の手順が TMPDIR に置く一時の worktree と状態のファイルが消されず溜まる(1 回分で数百 MB) #2085 本番の配布で GitHub Release の作成だけが失敗すると、タグが既にあるため release のステップを打ち直しても再開できない #2198 実行をまたいで残る状態(待ち行列・一時の worktree)に寿命と持ち主を持たせ、並行する実行が互いを塞がないようにする #2229 一時の置き場の残る状態のうち #2229 の対象外の種類(ndf/ の下の Skill の置き場・ndf-stages・ndf-guards・ndf-checks・ndf-usage)に持ち主と寿命を決める #2243 リファクタリングの工程で着手前のテストが時間切れになると、作業場所が「使用中」のまま残り、テストのプロセスも残る #2285 全体テストとリファクタリングの時間の枠を直した PR に、リファクタリングを一度も通せていない #2313 cross-refactoring の init が着手前テストの打ち切りで止まると、持ち主の記録が残り次の実行を 24 時間断る #2321 cross-refactoring の最終ゲートが締め切りで巻き戻すとき、途中で取り込んだベースブランチの変更まで消す #2323 queue --resume の --from が、強制終了した前の起動が残っていると無視され、前の途中のステップから続く #2325 リリース後テストで「次のスプリントで確かめる」と保留にした条件を、次のスプリントで拾い直す工程が無く、課題が開いたまま残る #2330
- D 待ち・上限(13 件): relay: ndf-next と同じ応答に書いた質問を待たずに会話を切り替える #1286 cross-review: 修正担当(claude -p)がテストを背景で起動して通知を待ったまま終わり、結果ファイルを書かない #1734 test_external_ai_run の codex の成功ケースが CI でだけまれに落ちる #1735 conductor が出力ファイルを確かめる回数が移行後に 15 回から 1,185 回へ増え、conductor の費用の 12.7% を占める #1872 conductor が NDF のスクリプトをシェルでつないで待つと、hook が止めてプランと wait を案内する #1919 本番の配布のプランで judge が同じ CI の失敗に打ち直しを 7 回返し、上限まで同じ run を読み直す → 同じ失敗が続いたら止めて人へ戻す #1983 test_usage_capture: 負荷が高いときだけ test_runtime_specific_usage_shapes が落ちる #2093 PR の pytest が 1 回 10〜13 分かかり、push のたびに古い実行も止まらず走り直す #2154 cross-refactoring: 着手前のテストが上限の近くで通ると、範囲テストの雛形の試走の残り時間が数秒になり init が止まる #2158 cross-refactoring: 既定の予算を固定の分数でなく、テストの所要とコード量から決める #2202 cross-refactoring: 最終ゲートの CI の待ち(予算 30 分のうち 13.4 分)を想定最大時間の勘定から外し、別の上限で待つ #2203 待ちの部品 wait_until が上限の時刻に最後の照会を打たず、上限の最大 2 分前に CI 待ちを打ち切る #2224 構造改善の持ち越し: 周回 l20261031-2(#2206 #2186 #2216)の範囲に cross-refactoring を通す #2251
- E 解決の時点(14 件): 実行する版を解決する層を 1 つにし、開発中の版と配布済みの版の食い違いを根本原因の場所で直す #715 古い版の NDF が新しい版で足した .ndf/project.json の項目を「知らない項目」として拒み、プラグインを更新するまで手順 0 が止まる #1706 cross-refactoring: 戦略の宣言をメインディレクトリから読み、Pull Request が変えた宣言(足した静的解析の suite)が検証に入らない #1709 Skill を足す設計の触るファイルに Skill の数を持つ 7 箇所が入らず、実装のステップが範囲外の失敗で止まる #2028 new close: merge・手動の経路のスプリントで、リリース記録の PR をまとめの close へ渡す手段が無く、課題が --record-pr unknown で開いたまま残る #2044 検査のプランの構造改善が既定の予算で下限に届かず、33 行の差分でも refactor が落ちて abort へ進む #2047 検査のプランの構造改善が --sync-command を渡さず、生成元に触れる改善が push で止まる #2049 design-results の書き直しが、主題で束ねた実装のプランの触るファイルと課題を先頭の課題の分だけにする #2056 棚卸し: 自動の前倒しを退けると同じ rank で順位の表を書けず、先に打った反映で境界が動くと却下が効かない #2077 開発ループの承認ゲート 2 の後のまとめが配布の記録の PR を読まない → 本番の後に記録の PR を解いてまとめを組む(#2089) #2121 merge-when-green: 自動反映の本番チャネルへのマージで、承認ゲート 2 で見た先端と merge-approved がマージする先端を照合しない #2147 スプリントのプランが作った時点の版数を配布と本番のプランへ書き込み、並行する別のスプリントがその版を先に出すとプランを作り直すまで止まる #2164 リリース記録の PR を、まとめのプランを組む時点でなく実行の時点で解決する #2230 全体テストの CI 待ちが、PR で外したチェックをメインディレクトリの宣言から読んで待ち続ける #2317
- F 並行の衝突(5 件): supervise: 設計の置き場所のテストのディレクトリが重なりの判定に当たり、スプリントの実装のプランがすべて直列になる #1811 supervise queue の重なりの判定がファイル単位のため、設計が関数単位で分けた実装のプランも直列になる(スプリント a1 で 58 分が 2 時間 47 分) #2037 設計を持たない実装のプランが触るファイルを宣言せず、同時に流す別のプランと重なるとそのファイルを「変えない」と指示されて止まる #2165 設計 PR のマージのプランがベースブランチとの衝突(DIRTY)で取り込みへ戻らず止まり、並行の設計 PR の用語集の衝突を手で解く #2273 conductor どうしの排他が無い: Issue・プラン・ファイル・版数などの対象ごとにロックを置き、並列の conductor が同じ物を同時に書き換えないようにする #2316
既存の親とのつながり: #2227(結果の統一 JSON。A の親)・#2229(状態の寿命と持ち主。C の親)・#2230(記録の PR を実行の時点で解決。E)・#2334(スクリプトの結果・ログ・異常系の不統一)は、この課題の一部になる。m26-3 で実装中の #2230・#2164 は、受け入れ条件 6 の最初の事例として扱う。
決めること(設計で)
- 実行の核の形: 装飾子か、コンテキストマネージャか、
supervise.py runのような実行器か。シェルの入口の扱い - データの型の書き方:
dataclass・pydantic・JSON Schema のどれに寄せるか。プランの JSON の日本語のキーを残すか(人が読む・書く) - 記録の置き場所と寿命: 実行ごとか、リポジトリで 1 つか。
progress.jsonl・使用量の帳簿・ask.jsonlとの関係 - 移す順序と 1 スプリントの大きさ: 部品ごとか、型ごとか
- 既存のマイルストーン(24・26・03・23)に散る 103 件を、この課題のマイルストーンへ寄せるか
未決
「決めること(設計で)」の 5 項目に加えて、要求の整理で残ったもの。
| 項目 | 誰が決めるか | 期限 |
|---|---|---|
| 核を通す 1 入口の起動の増分の上限値(非機能の性能) | この課題の設計(実測して決める) | 設計 Pull Request |
| 入力の解決(E2)と lease(E4)の順。lease の置き場が入力の解決に依るときの扱い | この課題の設計 | 設計 Pull Request |
利用者が直接呼ぶ公開の入口の範囲(互換なし を付ける対象) |
柱 P0(契約の一覧に印を付ける) | マイルストーン 28 |
2026-11-01 の分類の記録の置き場。受け入れ条件 9 の基準値 82% を同じ手順で再現できる形で残す。本文は「分類の記録に残してある」とするが、リポジトリの issues/・docs/ には見当たらない(2026-11-01 に ls issues と grep -rl 2335 issues docs で確かめた) |
この課題の設計 | 設計 Pull Request |
本文の timeout=<数字> 195 か所と打ち直した値(17・78)の食い違いの出所 |
柱 P4(棚卸し P0 の数え方で確かめる) | マイルストーン 30 の設計 |
調べ方
- 課題:
gh issue list --state open --limit 500の 194 件を 4 つに分け、本文の先頭 2500 字から主の型 1 つと従の型 0〜2 個を付けた。境界の判断(例: 既定ブランチ宛の実装 PR の本文の閉じる語で、マージの時点に課題が閉じ、仕上げの工程と受け入れ条件のチェックが閉じた課題に残る #2082・sprint-close: 最終工程を通っていない課題を、リリース後テストの前に閉じないようにする #2119 の「早く閉じる」は A、リリースのプランの verify が、メインディレクトリが本番ブランチにいると develop を fast-forward できずに止まる #2140 は I+従に C)は分類の記録に残してある - コード:
plugins/ndf/scripts・plugins/ndf/skills/*/scriptsの Python 392 本とシェル 29 本(テストとexperimental/を除く)を grep で数えた - 2026-11-01 の利用者の指摘: 「異常系処理とログ出力、異常時の回復処理が統一されていないから起こる不具合・課題が多い。1 件ずつ対処してもきりがない」「内部データ構造と出力のフォーマットの不統一の影響も大きそう」「NDF は Skill の Script 化から発展してきたため、内部データ構造や入出力契約がほぼ整理されていない」「出力だけでなく入力もそろえるべき」
- データの形: キーは
.get("…")と["…"]で読む文字列を Python で数えた(テストを除く)
進行
モード: — / 進め方: auto
- 要求と受け入れ条件 — 2026-11-01 09:09
- 作業場所の用意 — 2026-11-01 10:24
- 設計 — 2026-11-01 09:14
- 素材の収集と出典の確定
- ドキュメント再構成
- ドキュメントレビュー
- 計画 — 2026-11-01 10:20
- 実装 — 2026-11-01 10:24
- 構造改善 — 2026-11-01 11:33
- 実装レビュー — 2026-11-01 12:12
- 完了判定 — 2026-11-01 15:15
- Pull Request — 2026-11-01 11:32
- 確定仕様化 — 2026-11-01 17:08
- 後片付け — 2026-11-01 17:07
- 配布 — 2026-11-01 15:27
- 体裁レビュー
- リリース後テスト — 2026-11-01 17:24
- 振り返り — 2026-11-01 17:44
- 棚卸し — 2026-11-01 17:49
人の判断待ち(開発ループ lroot)
- 判定: unknown(承認ゲート 1)
- 理由: 検査の一部が終わっていない。requirements-check が exit 2 で止まり、要求の写し(issues/issue-2335-requirements.md)を読めなかった。このファイルは変更の統計に含まれるため、要求と受け入れ条件と設計が対応しているかは確かめられていない。PR 本文もマージの前に再実行が要ると書いている。Value 2 は、承認の材料がそろってから承認を求めるとしている。Value 3 は、測らずに良いとは言わないとしている。この 2 つに照らし、材料が欠けたまま従うとは決められない/設計の中身は Mission・Vision に沿う。すべての入口を 1 つの実行の核と契約の一覧へ寄せる。核と契約の一覧を通らない入口は検査で落とす。これは Value 6(根本原因の場所で直す・同じ役割を分けない)と Value 4(判断の要らない手順はスクリプトに)に合う/プロジェクトごとに違う値は、入力の解決(引数 → 環境変数 → 設定 → 既定値)で受ける。核に ai-plugins の値を置かない。これは Value 5 に合う。柱ごとに Pull Request を 3 本までに抑え、150 ms の上限は実測から置く。これは Value 10・Value 3 に合う/今回の変更は文書と用語集だけである。必ず承認が要る操作には当たらない。秘密(C1)・認証(C2)・
.ndf/(C7)・配布の規則(P1)は触らない。マイルストーンの付け替えは GitHub の中なので C8 に当たらない。lib/auth.py を核へ移す件(C1)は、後の柱 P8 の Pull Request で扱うと設計に書かれている - 根拠の項目: Mission, Vision, Value 2, Value 3, Value 4, Value 5, Value 6, Value 10, C1, C7, C8, P1
- 設計 Pull Request: NDF のスクリプト: すべての入口が 1 つの実行の核と契約の一覧を通り、異常系の不具合を型ごとに防げるようにする(#2335) #2359
- 答え: approved
- 答え方:
python3 /persistent/ai/.claude/plugins/cache/ai-plugins/ndf/10.27.6/scripts/sprint-state.py loop answer lroot 2335 --approved|--rejected
振り返り: #2367 (comment)
Activity
[-]異常系・ログ・回復を 1 つの実行の核へ集め、異常系の課題 103 件を型ごとにまとめて解く[/-][+]異常系・ログ・回復とデータ・出力の形を 1 つの実行の核へ集め、異常系の課題 103 件を型ごとにまとめて解く[/+][-]異常系・ログ・回復とデータ・出力の形を 1 つの実行の核へ集め、異常系の課題 103 件を型ごとにまとめて解く[/-][+]異常系・ログ・回復とデータ・入出力の形を 1 つの実行の核へ集め、異常系の課題 103 件を型ごとにまとめて解く[/+]Docs: #2335 の設計で I1 の理由の置き場を summary と gaps に揃え、I9 に秘密の値の照合での伏せ字を足す
docs(design): I9 の秘密の照合を空でない文字列の値に限る (#2335)
Merge pull request #2359 from devbasex/design/issue-2335
Merge: develop を取り込み、用語集の衝突を解く
Merge pull request #2360 from devbasex/docs/2335-design-results-align
Merge: develop を取り込み、用語集の衝突を解く