Skip to content

cross-refactoring: 名前が test_ で始まる本番のモジュール(lib/test_strategy.py)をテストとみなし、範囲テストのテンプレートの試走が終了コード 5 で止まる #2516

Closed

Description

@takemi-ohama

依頼(原文)

現象

開発ループ 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_ を名前に含めばテスト)も同じ基準で、危険度や本番コードの行数の数え方にも効いている。

再現の手順

  1. plugins/ndf/scripts/lib/ の本番のファイルを 1 行変える Pull Request を作る
  2. python3 plugins/ndf/scripts/refactor-scope.py --pr <番号> の出力を --scope に渡して drive.py <番号> --workflow-step を打つ
  3. init が上の ⛔ で止まる

受け入れ条件

  1. テスト関数を持たない test_*.py(本番のモジュール)が、範囲テストのテンプレートの試走の候補とテストの置き場所の判定に入らない。上の再現の手順で init が止まらない
  2. 直す箇所の案内が、テンプレートが正しいのに scope_command を指さない
  3. 全体テストが通る

補足

(書き手: 起票者(開発ループ 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・含まない

目的

前提

  • 前提 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)

振り返り: #2587 (comment)

振り返り: #2631 (comment)

Activity

  1. added
    quality品質向上の Issue(棚卸しの品質の枠。.ndf/backlog.json の quality)
    on Nov 5, 2026
  2. added 4 commits that reference this issue on Nov 5, 2026
  3. takemi-ohama commented on Nov 6, 2026

    @takemi-ohama
    ContributorAuthor

    スプリント(スプリント lroot3-18の後片付け)を通りました

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

    quality品質向上の Issue(棚卸しの品質の枠。.ndf/backlog.json の quality)

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions