Repository navigation
Description
依頼(原文)
現象
開発ループ lroot3 の周回 10(スプリント lroot3-10、#2369、Pull Request #2515 )の検査のプランで、cross-refactoring の
initが範囲テストのテンプレートの試走で止まった(refactor.py initが終了コード 4)。⛔ 範囲テストのテンプレートが {paths} に入るテストのファイルを受けません(suite: pytest) 入れたパス: plugins/ndf/scripts/lib/test_strategy.py plugins/ndf/scripts/lib/test_triage.py 試走: uv run --frozen --project . --all-extras pytest plugins/ndf/scripts/lib/test_strategy.py plugins/ndf/scripts/lib/test_triage.py -q -n 4 ... → 終了コード 5記録:
/tmp/ndf-worktrees/devbasex--ai-plugins/rf2515/work/.cross_refactoring/template-check.json、プランの報告/work/ai-plugins/.ndf/loop/lroot3/lap-10/sprint/4-check-state/report.md(手元の記録)原因
plugins/ndf/scripts/lib/test_strategy.pyとtest_triage.pyは本番のモジュールで、テスト関数を持たない。テストかどうかを名前だけで決めているため、テストのファイルとして扱われる。
refactor_lib/scope.pyのtest_files_underは名前の形(TEST_NAME_PATTERNS)だけで拾う。test_locationsは「配下にテストの名前のファイルがある」ことでplugins/ndf/scripts/libをテストの置き場所とみなす(決定 12 の本体と同じ場所に置く構成)template_check._probe_candidatesがその 2 本を試走の候補にし、pytest がテストを 1 件も集められず終了コード 5 で終わる。着手前のテストは通っているのでdefectと判定され、テンプレートの不備として止まる- テンプレート(
.ndf/project.jsonのtest.suites[0].scope_command)は正しい。直す箇所の案内が誤っている
plugins/ndf/scripts/libを触る Pull Request なら、#2369 に限らず同じように止まる(refactor-scope.pyが変更のディレクトリを--scopeに入れるため)。pathkinds.is_test_path(test_を名前に含めばテスト)も同じ基準で、危険度や本番コードの行数の数え方にも効いている。再現の手順
plugins/ndf/scripts/lib/の本番のファイルを 1 行変える Pull Request を作るpython3 plugins/ndf/scripts/refactor-scope.py --pr <番号>の出力を--scopeに渡してdrive.py <番号> --workflow-stepを打つinitが上の ⛔ で止まる受け入れ条件
- テスト関数を持たない
test_*.py(本番のモジュール)が、範囲テストのテンプレートの試走の候補とテストの置き場所の判定に入らない。上の再現の手順でinitが止まらない- 直す箇所の案内が、テンプレートが正しいのに
scope_commandを指さない- 全体テストが通る
補足
- 即時修正の 4 条件のうち「既存の方針の範囲に収まる」を満たすか判断がつかない(テストの見分け方を名前から中身へ広げると、他言語の構成と決定 12 の扱いが変わる)ため、その場で直さずに起票した
- この不具合が解けるまで、契約の棚卸しの残り: 呼び手の無い関数の片付けと子の課題 17 件の判定(#2336 の受け入れ条件 8・10) #2369 の Pull Request 2515 は検査のプランを通れない
(書き手: 起票者(開発ループ lroot3 の conductor)、日付: 2026-11-05。利用者の指示の原文は含まない)
#2516。人へ問わずに進め、決められない点は前提か未決として課題の本文へ書く。
(書き手: AI の起動指示、日付: 2026-11-05)
起票者の推定
課題の全文が起票者(AI)の記録で、利用者の指示の原文は無い。承認ゲート 1 で利用者が確かめるまで、次の条件を利用者の決定として扱わない。S4・S5 は要求を書いた AI が足した判断である。
| # | 条件 | 推した出所 | この要求での扱い |
|---|---|---|---|
| S1 | 名前が test_ で始まりテスト関数を持たない Python のファイルは、テストのファイルとして扱わない |
本文の「原因」「受け入れ条件 1」 | 受け入れ条件 1・2 |
| S2 | 案内がテンプレートを直す箇所として指すのは、テンプレートに不備があるときだけにする | 本文の「受け入れ条件 2」 | 受け入れ条件 3 |
| S3 | プロダクションコードの行数と危険度の判定(pathkinds.is_test_path)も同じ誤りを持つ |
本文の「原因」の最後の段落 | 受け入れ条件 5(S4 のとおり含める) |
| S4 | テストかどうかの見分け方は、試走の候補・置き場所の判定・行数と危険度の判定で 1 つにそろえる。片方だけ直すと、同じファイルを一方はテスト、もう一方はプロダクションコードと数える | プロジェクト MVV の Value 7(同じ役割の関数を分けない、根本原因の場所で直す) | 受け入れ条件 5・前提 2 |
| S5 | Python 以外の言語のテストの見分け方(名前の形とディレクトリの名前)は変えない | 本文の「補足」(他言語の構成と決定 12 の扱いが変わる懸念) | 受け入れ条件 6・前提 1・含まない |
目的
- 名前が
test_で始まるプロダクションコードのファイルを持つリポジトリでも、cross-refactoring の着手(init)がテンプレートの試走で誤って止まらないようにする - 止まったときの案内が、正しいテンプレートを直す箇所として示さないようにする
- 契約の棚卸しの残り: 呼び手の無い関数の片付けと子の課題 17 件の判定(#2336 の受け入れ条件 8・10) #2369 の Pull Request スプリント lroot3-10 #2515 が検査のプランを通れるようにする
前提
- 前提 1: 中身でテストかどうかを見分ける対象は Python のファイル(拡張子
.py)に限る。Python の場合、テストの関数とは pytest が既定で集める形(名前がtestで始まる関数、名前がTestで始まるクラスの中のtestで始まるメソッド)を指す。ほかの言語のファイルは今の名前の形の判定のまま扱う - 前提 2: 行数と危険度の判定(
is_test_path)は今はパスの文字列だけで決めている。見分け方をそろえるために作業ディレクトリの中身を読む形へ変えてよい。読めないファイル(削除済み・リポジトリの外)は今の名前の判定で扱う - 前提 3: ディレクトリの名前でテストの置き場所とみなす判定(
tests/spec/など)は変えない。tests/の配下にあるテスト関数を持たない補助のファイル(tests/test_helpers.pyなど)も、試走の候補からは外す(受け入れ条件 1 の対象に含む) - 前提 4: プロダクションコードのファイルの名前を変える(
test_strategy.pyを別名へ移す)ことはこの課題の直し方にしない。ほかのリポジトリにも同じ構成がありうるため、見分け方の側で直す(Value 6)
対象範囲
含む:
- cross-refactoring のテンプレートの試走の候補選び
--scopeのテストの置き場所の判定(本体と同じ場所にテストを置く構成の判定)- プロダクションコードの行数と危険度の判定でのテストのファイルの見分け方(S4)
- 上の 3 つを確かめるテスト
含まない:
- Python 以外の言語のテストの見分け方の変更(S5)
plugins/ndf/scripts/lib/test_strategy.py・test_triage.pyの名前の変更(前提 4)- 試走の判定の表(
template_verdict)の作り直し。終了コード 5 の扱いは「未決」に置く - cross-refactoring 以外の Skill のテストの見分け方
ドメインイベント
| # | イベント | 引き金 | 失敗したとき | 順序の前提 |
|---|---|---|---|---|
| E1 | init が --scope を受け取った |
drive.py <番号> --workflow-step |
--scope が無ければ既存の検査で止まる |
— |
| E2 | --scope のうちテストの置き場所が決まった |
E1 | 置き場所が 0 件なら既存の検査(scope_problem)で止まる |
E1 |
| E3 | 着手前のテストが走り、suite ごとの成否が記録された | E2 | 既存の振る舞い(既存失敗として記録) | E2 |
| E4 | 試走の候補のテストのファイルが選ばれた | E3 | 候補が 0 本なら undecided で止まる(既存) |
E2・E3 |
| E5 | テンプレートの試走が走った | E4 | 上限で打ち切り・起動の失敗は既存の判定 | E4 |
| E6 | 試走の判定(ok / defect / undecided)が決まり、ok 以外なら直す箇所の案内を出して止まった |
E5 | — | E3・E5 |
E2 と E4 がこの課題の対象である。E2 でテスト関数を持たないファイルを根拠に置き場所とみなすと、E4 でそのファイルが候補になり、E5 がテストを 1 件も集めずに落ちる。
用語
| 用語 | 意味 |
|---|---|
| 範囲テストのテンプレート | .ndf/project.json の test.suites[].scope_command。{paths} にテストのファイルのパスを入れて走らせる |
| テンプレートの試走 | init が着手前のテストの後に、範囲テストのテンプレートへテストのファイルを最大 2 本入れて 1 回走らせ、{paths} に入るパスを受けるかを見分けること |
| プロダクションコード | コードの拡張子を持ち、テストの置き場所でないファイル。この課題の後は、名前が test_ で始まりテストの関数を持たない .py もここに入る |
受け入れ条件
- 1. Python のファイルで、名前が
test_で始まり、テストの関数(前提 1)を 1 つも持たないものは、試走の候補に入らない(--scopeの配下・リポジトリ全体のどちらから選ぶ場合も) - 2.
--scopeの 1 件の配下に、テストの関数を持たないtest_*.pyしか無いとき、その 1 件はテストの置き場所とみなされない(ディレクトリの名前で当たる場合を除く。前提 3) - 3. 本文の「再現の手順」と同じ条件(
plugins/ndf/scripts/lib/のプロダクションコードのファイルだけを変え、refactor-scope.pyの出力を--scopeに渡す)で、initがテンプレートの試走で止まらず、scope_commandを直す箇所として示す案内も出ない - 4. テストの関数を持つ
test_*.py(tests/の配下・本体と同じ場所のどちらでも)は、今までどおり試走の候補とテストの置き場所の判定に入る - 5. プロダクションコードの行数と危険度の判定で、テストの関数を持たない
test_*.pyはプロダクションコードとして数えられる(受け入れ条件 1・2 と同じ見分け方になる) - 6. Python 以外の言語の名前の形(
*.spec.ts・*_test.goなど)とディレクトリの名前による判定の結果は変わらない(既存のテストが変更なしで通る) - 7. 全体テストが通る
非機能の条件
| 大項目 | 条件 |
|---|---|
| 性能・拡張性 | 中身を読むのは名前がテストの形の .py のファイルだけにする。このリポジトリで init の候補選びにかかる時間が、変更前の実測から 1 秒を超えて延びない |
影響
| 対象 | 影響 |
|---|---|
| 公開インタフェース | 変わらない(refactor.py と drive.py の引数・結果の JSON の形は同じ) |
| データ | 無し |
| 既存の振る舞い | テスト関数を持たない test_*.py が、試走の候補・テストの置き場所・行数と危険度の判定でテストとして扱われなくなる |
検証手段
| 項目 | 手段 |
|---|---|
| テスト | uv run --frozen --project . --all-extras pytest plugins/ndf/skills/cross-refactoring -q -n 4 と全体テスト uv run --frozen --project . --all-extras pytest . -q -n 4 |
| 静的解析・型検査 | CI の既存のジョブ(ruff) |
| 手動確認 | 配布の後、#2369 の Pull Request #2515 の検査のプランで init が試走で止まらないことを、template-check.json の判定が ok であることで確かめる(リリース後テスト) |
前提とする取り決め
| 項目 | 参照先 / 決めたこと |
|---|---|
| プロジェクト構造 | cross-refactoring のスクリプトは plugins/ndf/skills/cross-refactoring/scripts/refactor_lib/、テストは plugins/ndf/skills/cross-refactoring/tests/ に置く。テストの見分け方は 1 か所に置き、呼び出し元で写さない(Value 7) |
| コーディング規約 | AGENTS.md の「最小限のコード実装」。.md の文言を照合するテストを書かない |
| テスト戦略 | 判定の関数は単体テストで、init の通しの振る舞いは test_init.py の形の結合テストで確かめる。受け入れ条件 3 は一時の git リポジトリに lib/test_x.py(テスト関数なし)を置いて再現する |
境界
| 区分 | 内容 |
|---|---|
| 常に行う | 既存テストの実行、変更範囲内の命名の統一 |
| 確認してから行う | テストの見分け方を変えることで変わる既存のテストの期待値(承認ゲート 2 で人が見る) |
| 行わない | プロダクションコードのファイルの改名、Python 以外の言語の判定の変更、試走の判定の表の作り直し |
未決
| 項目 | 誰が決めるか | 期限 |
|---|---|---|
候補にテストが残っていても pytest が終了コード 5(テストが集まらない)で終わったとき、defect でなく undecided と判定するか。suite の実行器を読まない現行の方針(#1334 I1)との関係を含めて決める |
設計(design) |
設計 PR の承認まで |
中身の判定を、ファイルの構文解析で行うか、pytest の収集(--collect-only)で行うか |
設計(design) |
設計 PR の承認まで |
進行
モード: — / 進め方: auto
- 要求と受け入れ条件 — 2026-11-05 11:36
- 作業場所の用意 — 2026-11-05 20:01
- 設計 — 2026-11-05 11:45
- 素材の収集と出典の確定
- ドキュメント再構成 — 2026-11-05 11:48
- ドキュメントレビュー
- 計画 — 2026-11-05 20:01
- 実装 — 2026-11-05 20:01
- 構造改善 — 2026-11-05 21:15
- 実装レビュー — 2026-11-05 21:45
- 完了判定 — 2026-11-05 20:27
- Pull Request — 2026-11-05 19:16
- 確定仕様化 — 2026-11-05 19:14
- 後片付け — 2026-11-05 19:52
- 配布 — 2026-11-05 22:19
- 体裁レビュー
- リリース後テスト — 2026-11-05 19:47
- 振り返り — 2026-11-05 19:48
- 棚卸し — 2026-11-05 19:52
人の判断待ち(開発ループ lroot3)
- 判定: unknown(承認ゲート 1)
- 理由: 判定を読めない
- 根拠の項目: —
- 設計 Pull Request: cross-refactoring: テストの関数を持たない
test_*.pyをプロダクションコードとして扱い、initの試走が誤って止まらないようにする(#2516) #2558 - 答え: approved
- 答え方:
python3 /persistent/ai/.claude/plugins/cache/ai-plugins/ndf/10.27.21/scripts/sprint-state.py loop answer lroot3 2516 --approved|--rejected|--revise --note <指摘ファイル>
振り返り: #2587 (comment)
振り返り: #2631 (comment)
Activity
Docs: #2516 の設計で、テスト用ディレクトリの配下の扱いを不変条件と用語集に明記し、コミットの事実を前後の版で見分ける
docs(design): コミットの前後の版を 1 回だけ読んで判定する形にする (#2516)
Merge pull request #2558 from devbasex/design/issue-2516
Merge pull request #2610 from devbasex/feat/issue-2516-lroot3-18
takemi-ohama commentedon Nov 6, 2026
スプリント(スプリント lroot3-18の後片付け)を通りました