Skip to content

全工程の結果を統一した JSON レポートにし、失敗・未収束・未記録を ok で返さない #2227

Closed
7 of 7 issues completed

Description

@takemi-ohama

依頼(原文)

この課題は、利用者が 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 の試行だけを値として採る。置き場が無いことと材料が無いことを区別する
  • シェルのスクリプトも同じ形式で結果を返す

完了条件

(書き手: 起票者、日付: 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 が「何を実行し、何を根拠にどう決め、何ができて何が欠けたか」を追えるようにする(振り返りと承認の判断の材料にする)

前提

対象範囲

含む:

  • 結果 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 が誤りとして返す)
    • 同じステップの試行が複数ある状態ディレクトリから値を読む共通の関数が lib に 1 つあり、status が ok の試行のうち最も新しいものだけを採る。ok の試行が 1 つも無いとき → 落ちた試行の値を返さず、採れる試行が無いことを呼び出し側が区別できる形で返す。番号の最大の試行が stopped で、それより前の試行が ok のとき → 前の ok の試行の値を返す(単体テストで固定する)
    • 読む側の共通の規則として、渡された置き場(ファイル・ディレクトリ)が存在しない・読めないとき → 材料が 0 件・「無し」とは返さず、ok 以外の状態で返す。置き場が存在し材料が 0 件のとき → 0 件であることを、置き場が無いときと別の値で返す(単体テストで両方を固定する)
    • 前提 3 のシェルのスクリプトは、共通の手段を通して結果 JSON を 1 行出し、その出力は validate_result を通る。中で呼んだ gh が失敗したとき → status は ok でなく、summary か items に失敗の理由(gh の標準エラーの要旨)が入り、終了コードは 0 以外になる(偽の gh を PATH の先頭に置くテストで確かめる)
    • 退行しない: 成功し欠けの無い場合、既存の手順のスクリプトは今と同じ status: ok・終了コード 0 を返す。既存の gate / stopped の終了コード(1・2・3・4・10〜19・20〜29・69・75)の意味は変わらない(既存のテスト全体が通る)
    • 退行しない: 新しい状態の値か終了コードを足した場合、結果 JSON の status を読む既存の読み手(supervise_lib のステップの成否の判定など)は、それを成功として読まない(ok だけを成功とする判定のまま、新しい値で止まることを単体テストで確かめる)

非機能の条件

大項目 条件
運用・保守性 形式の正本は 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

  1. added 6 commits that reference this issue on Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ndf-skillNDF の Skill 本体priority: high実害・安全機構の欠落など、優先して対応する

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions