Repository navigation
Description
依頼(原文)
この課題は、利用者が 2026-10-31 に出した NDF の方針(5 点)の 3 点目を受けて、起票者(AI)が子の 7 件をまとめて起こした親の課題である。利用者の発言の原文は課題にも記録にも残っていない。下の 2 つを写す。
全ての工程で統一ルールに基づくレポートを JSON で出し、過程・判断・結果が分かるようにする
(書き手: 起票者〔利用者の方針を AI が要約して記録したもの。利用者の発言の原文ではない〕、日付: 2026-10-31)
起票時の本文(題「全工程の結果を統一した JSON レポートにし、失敗・未収束・未記録を ok で返さない」):
何が困るか
NDF のスクリプトは、失敗・未収束・欠けた材料・未記録を
status: okで返し、呼ぶ側もstatusだけを見て先へ進む。自律で回す工程では、止まるより「間違った成功」の害が大きい。気づいた時点で後続の工程が積み上がっている。
子 何が ok で返るか #2143 cross-review が収束しない( finalがmax_rounds・oscillation)のに駆動が ok#2079 置き換わらない差し込みが残ったステップが動き、検査の結果が「無し」になる。 queue.fill_queue_prは見つからないと"0"・""で埋める#2129 release_lib/materials.last_resultが番号の最大の試行をstatusを見ずに読み、落ちた試行の値を承認資料に載せる#2157 .ndf/が除外されていてもproject-mvv.py approveが ok#2183 差し戻しの記録が無いと gate-rejections.py countが「0 件」を ok で返す(未記録と区別しない)#671 progress-record.shが gh の失敗で理由を出さず終了コード 0#1849 upkeep.py applyを 2 回打つと report の区分の内訳と承認待ちが 0 件になる修正レイヤー
結果の共通形式(
plugins/ndf/scripts/lib/step_result.py、lib/README.mdの「手順のスクリプトの結果」)と、それを読む側の規則。 今の状態はok/gate/stoppedの 3 つで、「終わったが欠け・未達がある」を表せない。シェルのスクリプト(#671)はこの形式を通らない。直し方の方針
- 全ての工程が、統一したルールの JSON レポートを出す。過程(何を実行したか)・判断(何を根拠にどう決めたか)・結果(何ができ、何が欠けたか)を後から追えるようにする
okは成功・収束のときだけに限る。欠け・未達・未記録は別の状態か、ok以外として返す- 読む側は、
statusがokの試行だけを値として採る。置き場が無いことと材料が無いことを区別する- シェルのスクリプトも同じ形式で結果を返す
完了条件
- 子の 7 件で、失敗・未収束・未記録が
okで返らない- 全工程のレポートの形式が 1 か所に定まり、
lib/README.mdが正本になる- 子の個別の作業(gws-check.py がトークンの無い状態(auth_method: none)を認証済みと判定して exit 0 を返す #2067 のような判定の中身の誤りは対象外)は、子の issue で閉じる
(書き手: 起票者、日付: 2026-10-31。利用者の指示の原文として扱わない)
起票者の推定
利用者の方針(上の 1 文)に無く、起票者が推して足した条件。承認ゲート 1 で利用者が確かめるまで、利用者の決定として扱わない。
| # | 条件 | 推した出所 | この要求での扱い |
|---|---|---|---|
| S1 | 直す場所は結果の共通形式(lib/step_result.py・lib/README.md)と、それを読む側の規則である |
子の 7 件の原因の突き合わせ(本文の「修正レイヤー」) | 受け入れ条件 1〜6 |
| S2 | 今の 3 つの状態では「終わったが欠け・未達がある」を表せないので、別の状態が要る | 本文の「修正レイヤー」 | 未決 1(新しい状態を足すか、stopped か gate で返すかは設計で決める)。受け入れ条件は「ok で返らない」で書く |
| S3 | ok は成功・収束のときだけに限る |
本文の「直し方の方針」2 点目 | 受け入れ条件 2・3 |
| S4 | 読む側は status が ok の試行だけを値として採る |
#2129 の原因(materials.last_result) |
受け入れ条件 4 |
| S5 | 置き場が無いことと材料が無いことを区別する | #2079 の notes --check-state・#2183 の「0 件」 |
受け入れ条件 5 |
| S6 | シェルのスクリプトも同じ形式で結果を返す | #671 | 受け入れ条件 6。対象のシェルのスクリプトの範囲は前提 3 |
| S7 | 過程・判断・結果を「何を実行したか」「何を根拠にどう決めたか」「何ができ、何が欠けたか」と読む | 利用者の方針の 1 文を起票者が言い換えたもの | 受け入れ条件 1 |
| S8 | 子の 7 件の個別の直しは子の課題で閉じ、判定の中身の誤り(#2067 の類)は対象外 | 本文の「完了条件」 | 対象範囲(含まない)・受け入れ条件 7 |
目的
- 自律で回す工程(プラン・supervisor・conductor)が、失敗・未収束・欠けた材料・未記録を成功と読んで先へ進まないようにする。承認ゲート 2 の承認資料へ、落ちた試行の値や「無し」が黙って載らないようにする
- 工程ごとの結果 JSON から、後で人と AI が「何を実行し、何を根拠にどう決め、何ができて何が欠けたか」を追えるようにする(振り返りと承認の判断の材料にする)
前提
- 前提 1: 「全ての工程」は、Skill の本文かプランのステップから呼ばれ、結果を読み手(LLM・
supervise.py・承認資料の組み立て)が読む手順のスクリプトを指す。hook・statusline・利用者が手で打つだけの補助は含まない - 前提 2: 実験版(
plugins/ndf/scripts/experimental/)は対象に含まない。既定の振る舞いから参照されず、安定版へ移す時点で形式に合わせる(AGENTS.md の「安定版と実験版」) - 前提 3: 対象のシェルのスクリプトは、前提 1 に当たるもの(例:
progress-record.sh・projects-sync.sh・pr-body-decisions.sh)に限る。どれが当たるかの一覧は設計で決め、設計文書に載せる - 前提 4: 結果 JSON を読むのは同じ版の
plugins/ndfの中のコードと Skill の本文だけである。Factory(factory/)は結果 JSON を直接読まない(factory/contractsのresultは進行のイベントの別の語彙で、この課題では変えない) - 前提 5: 子の 7 件(cross-review が収束しない(final が max_rounds・oscillation)のに駆動が ok を返し、スプリントの検査の review が止まらない #2143・置き換わらない差し込み({queue_pr:…}・{queue_state:…})が残ったプランのステップがそのまま動き、承認資料の検査の結果が黙って「無し」になる #2079・承認資料の検査の結果が、やり直した refactor の落ちた試行の値を読んで採用 14 件を 0 件と書き、cross-review の見送り 2 件を 7 行に重ねる #2129・.ndf/ を追跡するかが Skill の間で食い違い、ルートの .gitignore が .ndf/ を外していても project-mvv.py approve は気づかずに成功する #2157・承認ゲートの差し戻しを conductor が記録し忘れても気づけず、振り返りの差し戻しの件数が 0 になる #2183・progress-record.sh が gh の失敗時に理由を出さず終了コード 0 で終わり、工程の記録が黙って抜ける #671・棚卸しで apply を 2 回打つと report の区分の内訳と承認待ちが 0 件になる #1849)の個別の直しは、この課題の共通の形式と読む側の規則が入った後に、子の課題で行う。この課題が閉じる条件は、子の 7 件が閉じていることを含む(受け入れ条件 7)
対象範囲
含む:
- 結果 JSON の形式の正本(
plugins/ndf/scripts/lib/README.mdの「手順のスクリプトの結果」)と、それを確かめるlib/step_result.pyのvalidate_result/emit okを返してよい条件と、欠け・未達・未記録を返す形(状態の値・終了コード)- 過程・判断・結果を結果 JSON に書く項目
- 読む側の共通の規則: 複数の試行から値を採る規則、置き場が無いことと材料が無いことの区別
- シェルのスクリプトが同じ形式の結果 JSON を出すための共通の手段
- 形式の変更に合わせた、
lib/README.md以外の文書(Skill の本文・references)からの参照の付け替え(形式を写さずに正本を指す)
含まない:
- 子の 7 件の個別の直し(子の課題で行う。前提 5)
- 判定の中身の誤り(gws-check.py がトークンの無い状態(auth_method: none)を認証済みと判定して exit 0 を返す #2067 のように、
statusの値ではなく判定の論理が誤っているもの) - 既存の全スクリプトへの過程・判断の項目の書き足し(この課題では形式と共通の手段を定め、
okを誤って返す箇所を直すことを優先する。書き足しの範囲は未決 2) - 実験版のスクリプト(前提 2)
- Factory の進行のイベントの語彙(前提 4)
ドメインイベント
| # | イベント | 引き金 | 失敗したとき | 順序の前提 |
|---|---|---|---|---|
| E1 | 手順のスクリプトが処理を終えた | Skill の本文・プランのステップがスクリプトを起動した | 例外・打ち切りで結果 JSON を出さずに終わる → 読む側は「結果が無い」を ok と読まない(受け入れ条件 4) |
— |
| E2 | スクリプトが結果を、成功・収束 / 欠けの残る結果 / 失敗 / 人か LLM の判断待ち のどれかに分けた | E1 | 分けた結果と書いた状態が食い違う(欠けがあるのに ok)→ emit が出さずに終了コード 2 で終える(受け入れ条件 3) |
E1 |
| E3 | スクリプトが結果 JSON を 1 行出し、状態に合った終了コードで終えた | E2 | 形の誤り → 終了コード 2(今と同じ) | E2 |
| E4 | 読む側が結果の置き場を開いた | 次のステップ・承認資料の組み立て・振り返りの集計 | 置き場が無い → 材料が無いとは読まず、ok 以外で返す(受け入れ条件 5) |
E3 |
| E5 | 読む側が採る試行を選んだ | E4 で同じステップの試行が複数あった | ok の試行が 1 つも無い → 落ちた試行の値を採らず、採れる試行が無いことを返す(受け入れ条件 4) |
E4 |
| E6 | 読む側が次の工程へ進んだか、止まった | E5 | — | E5 |
用語
| 用語 | 意味 |
|---|---|
| 結果 JSON | 手順のスクリプトが返す 1 行の JSON。status で読む(既存の語) |
| 試行 | 同じステップを流し直したときの 1 回ごとの実行と、その結果 JSON。状態ディレクトリの NN-<ステップ>.out の 1 つが 1 試行に当たる |
| 欠けの残る結果 | 手順は終わったが、出すはずの材料・記録の一部が無いか、目標(収束など)に届かなかった結果 |
| 結果の置き場 | 読む側が結果 JSON や材料を探す場所(状態ディレクトリ・記録のファイル)。置き場が無いことと、置き場はあるが材料が 0 件であることを分けて扱う |
受け入れ条件
-
-
lib/README.mdの「手順のスクリプトの結果」が、結果 JSON の全ての項目と状態の値・終了コードの表を持ち、過程(何を実行したか)・判断(何を根拠にどう決めたか)・結果(何ができ、何が欠けたか)をどの項目に書くかを定める。Skill の本文と references は形式の表を写さず、この節を指す(grepで、statusの値の表を持つ文書がlib/README.mdの 1 か所だけであることを確かめる)
-
-
-
lib/README.mdが、okを返してよいのは「手順が成功し、目標(収束など)に届き、欠けが無い」ときだけと定め、欠けの残る結果・未記録を返す状態と終了コードを定める
-
-
- 欠けの残る結果を表す項目(名前は設計で決める)を 1 件以上持つ結果 JSON を
status: okでemitすると → 標準出力へ何も出さず、標準エラーへ理由を出して終了コード 2 で終わる(validate_resultが誤りとして返す)
- 欠けの残る結果を表す項目(名前は設計で決める)を 1 件以上持つ結果 JSON を
-
- 同じステップの試行が複数ある状態ディレクトリから値を読む共通の関数が
libに 1 つあり、statusがokの試行のうち最も新しいものだけを採る。okの試行が 1 つも無いとき → 落ちた試行の値を返さず、採れる試行が無いことを呼び出し側が区別できる形で返す。番号の最大の試行がstoppedで、それより前の試行がokのとき → 前のokの試行の値を返す(単体テストで固定する)
- 同じステップの試行が複数ある状態ディレクトリから値を読む共通の関数が
-
- 読む側の共通の規則として、渡された置き場(ファイル・ディレクトリ)が存在しない・読めないとき → 材料が 0 件・「無し」とは返さず、
ok以外の状態で返す。置き場が存在し材料が 0 件のとき → 0 件であることを、置き場が無いときと別の値で返す(単体テストで両方を固定する)
- 読む側の共通の規則として、渡された置き場(ファイル・ディレクトリ)が存在しない・読めないとき → 材料が 0 件・「無し」とは返さず、
-
- 前提 3 のシェルのスクリプトは、共通の手段を通して結果 JSON を 1 行出し、その出力は
validate_resultを通る。中で呼んだghが失敗したとき →statusはokでなく、summaryかitemsに失敗の理由(ghの標準エラーの要旨)が入り、終了コードは 0 以外になる(偽のghをPATHの先頭に置くテストで確かめる)
- 前提 3 のシェルのスクリプトは、共通の手段を通して結果 JSON を 1 行出し、その出力は
-
- 子の 7 件(cross-review が収束しない(final が max_rounds・oscillation)のに駆動が ok を返し、スプリントの検査の review が止まらない #2143・置き換わらない差し込み({queue_pr:…}・{queue_state:…})が残ったプランのステップがそのまま動き、承認資料の検査の結果が黙って「無し」になる #2079・承認資料の検査の結果が、やり直した refactor の落ちた試行の値を読んで採用 14 件を 0 件と書き、cross-review の見送り 2 件を 7 行に重ねる #2129・.ndf/ を追跡するかが Skill の間で食い違い、ルートの .gitignore が .ndf/ を外していても project-mvv.py approve は気づかずに成功する #2157・承認ゲートの差し戻しを conductor が記録し忘れても気づけず、振り返りの差し戻しの件数が 0 になる #2183・progress-record.sh が gh の失敗時に理由を出さず終了コード 0 で終わり、工程の記録が黙って抜ける #671・棚卸しで apply を 2 回打つと report の区分の内訳と承認待ちが 0 件になる #1849)が、それぞれの受け入れ条件を満たして閉じている。各子の課題の再現の手順を流したとき、失敗・未収束・欠けた材料・未記録が
status: okで返らない(子の課題で確かめ、この課題では閉じていることを見る)
- 子の 7 件(cross-review が収束しない(final が max_rounds・oscillation)のに駆動が ok を返し、スプリントの検査の review が止まらない #2143・置き換わらない差し込み({queue_pr:…}・{queue_state:…})が残ったプランのステップがそのまま動き、承認資料の検査の結果が黙って「無し」になる #2079・承認資料の検査の結果が、やり直した refactor の落ちた試行の値を読んで採用 14 件を 0 件と書き、cross-review の見送り 2 件を 7 行に重ねる #2129・.ndf/ を追跡するかが Skill の間で食い違い、ルートの .gitignore が .ndf/ を外していても project-mvv.py approve は気づかずに成功する #2157・承認ゲートの差し戻しを conductor が記録し忘れても気づけず、振り返りの差し戻しの件数が 0 になる #2183・progress-record.sh が gh の失敗時に理由を出さず終了コード 0 で終わり、工程の記録が黙って抜ける #671・棚卸しで apply を 2 回打つと report の区分の内訳と承認待ちが 0 件になる #1849)が、それぞれの受け入れ条件を満たして閉じている。各子の課題の再現の手順を流したとき、失敗・未収束・欠けた材料・未記録が
-
- 退行しない: 成功し欠けの無い場合、既存の手順のスクリプトは今と同じ
status: ok・終了コード 0 を返す。既存のgate/stoppedの終了コード(1・2・3・4・10〜19・20〜29・69・75)の意味は変わらない(既存のテスト全体が通る)
- 退行しない: 成功し欠けの無い場合、既存の手順のスクリプトは今と同じ
-
- 退行しない: 新しい状態の値か終了コードを足した場合、結果 JSON の
statusを読む既存の読み手(supervise_libのステップの成否の判定など)は、それを成功として読まない(okだけを成功とする判定のまま、新しい値で止まることを単体テストで確かめる)
- 退行しない: 新しい状態の値か終了コードを足した場合、結果 JSON の
非機能の条件
| 大項目 | 条件 |
|---|---|
| 運用・保守性 | 形式の正本は lib/README.md の 1 か所、形の検査は step_result.py の 1 か所に置く。試行の選び方・置き場の区別を Skill ごとに書き分けない(MVV の Value 6) |
| 移行性 | 結果 JSON の契約が変わる。読み手は同じ版の plugins/ndf の中だけなので(前提 4)、同じ PR か同じ版で読み手も直す。利用者の手での移行は要らない |
影響
| 対象 | 影響 |
|---|---|
| 公開インタフェース | 変わる。結果 JSON の契約(状態の値・終了コード・項目)は安定版の「結果 JSON の契約」に当たる。読み手は同じ版の中だけで、版をまたぐ互換の経路は持たない(互換なし。ただし外部の利用者が結果 JSON を読む手段は文書化していない) |
| データ | 状態ディレクトリ・記録のファイルの形は変えない。読み方だけを変える |
| 既存の振る舞い | 今 ok で返っている欠けの残る結果が ok 以外になり、プランの on_fail が働いて止まるようになる(意図した変化) |
検証手段
| 項目 | 手段 |
|---|---|
| テスト | uv run --frozen --project . --all-extras pytest plugins/ndf/scripts/tests -q -n 4(形の検査・試行の選び方・置き場の区別・シェルのスクリプトの単体テスト) |
| 静的解析 | CI の既存のチェック(python3 scripts/check-skill-frontmatter.py・python3 plugins/ndf/scripts/instructions-check.py --root . ほか) |
| 手動確認 | リリース後テストで、検査のプランを流し直した状態ディレクトリから承認資料を作り、## 検査の結果 が ok の試行の値だけを載せることを見る |
前提とする取り決め
| 項目 | 参照先 / 決めたこと |
|---|---|
| プロジェクト構造 | 共通の形と読む規則は plugins/ndf/scripts/lib/ に置き、正本の説明は lib/README.md。Skill ごとの scripts/ に同じ役割の関数を置かない(lib/README.md の「置いてよいもの・いけないもの」) |
| コーディング規約 | 標準ライブラリだけで書く(step_result.py の冒頭)。.md の文言を照合するテストは書かない(AGENTS.md の DON'T) |
| テスト戦略 | 形の検査・試行の選び方・置き場の区別は単体テスト、シェルのスクリプトは偽の gh を使う結合テスト(tdd-cycle の testing-levels) |
境界
| 区分 | 内容 |
|---|---|
| 常に行う | 既存のテスト全体の実行、lib/README.md と step_result.py の同時の更新、形式を写している文書の付け替え |
| 確認してから行う | 状態の値・終了コードの追加(結果 JSON の契約の変更)。承認ゲート 1 の設計と承認ゲート 2 で人が見る |
| 行わない | 子の 7 件の個別の直し(子の課題で行う)、判定の中身の誤りの修正、実験版の書き換え |
未決
| 項目 | 誰が決めるか | 期限 |
|---|---|---|
1. 欠けの残る結果を、新しい状態の値で表すか、stopped(と新しい終了コード)で表すか |
設計(承認ゲート 1 で利用者が確かめる) | 設計 PR |
| 2. 過程・判断の項目を、どのスクリプトまでこの課題で書き足すか(必須にするか、任意の項目にして子と後の変更で埋めるか) | 設計(承認ゲート 1 で利用者が確かめる) | 設計 PR |
3. 前提 3 のシェルのスクリプトの一覧と、progress-record.sh が ok 以外を返したときに呼び出し側の工程を止めるか(progress-tracking は今「理由を 1 行出して終了コード 0」と定める) |
設計 | 設計 PR |
進行
モード: — / 進め方: auto
- 要求と受け入れ条件 — 2026-10-31 01:59
- 作業場所の用意 — 2026-10-31 03:59
- 設計 — 2026-10-31 02:02
- 素材の収集と出典の確定
- ドキュメント再構成
- ドキュメントレビュー
- 計画 — 2026-10-31 03:58
- 実装 — 2026-10-31 03:59
- 構造改善 — 2026-10-31 07:37
- 実装レビュー — 2026-10-31 09:11
- 完了判定 — 2026-10-31 04:52
- Pull Request — 2026-10-31 05:07
- 確定仕様化 — 2026-10-31 10:59
- 後片付け — 2026-10-31 10:57
- 配布 — 2026-10-31 10:33
- 体裁レビュー
- リリース後テスト — 2026-10-31 10:56
- 振り返り — 2026-10-31 11:00
- 棚卸し — 2026-10-31 11:21
振り返り: #2282 (comment)
リリース後テスト(v10.27.2)で残ったこと
条件 1〜6・8・9 は合格、条件 7 は不合格(子の #2143 が条件 2 を満たさず閉じていない。記録: #2281 (comment) )。子の #2079・#2129・#2157・#2183・#671・#1849 は閉じた。#2143 が閉じたときにこの課題を閉じる。
- 承認資料の組み立て(
plugins/ndf/scripts/release_lib/materials.py)は試行を自前の_outs・last_resultで選び、更新時刻の順に並べる。lib/README.mdの読む側の規則が定める共通の関数(lib/step_read.pick_ok_attempt、試行の番号の順)を通っていない。今回の実物はどちらでも同じ値だった
閉じた理由
受け入れ条件 1〜6・8・9 は v10.27.2 のリリース後テストで合格した。残っていた条件 7(子の 7 件が閉じている)は、最後の子の #2143 が 2026-11-01 に閉じて満たされた。本文の末尾に書いた、承認資料の組み立てが共通の試行の読み方を通らない件は #2289 が持つ。
Activity
docs(design): #2227 結果の読み方の手引きと次の手の表 5 つを構成要素へ足す
docs(design): #2227 配布のときの記録の無い必須の工程を items の stage-missing へ載せると決める
Merge: develop を取り込み、用語集の衝突を解く(#2229 の設計の語と #2227 の設計の語を両方残す)
Merge pull request #2242 from devbasex/design/issue-2227
Merge pull request #2254 from devbasex/feat/issue-2227-m26-1
fix: レビューの指摘 2 件を直す(PR #2268 round 2)