refactor(PLAN65): cmd_scale の段階を前提の検査と段階の実行へ分ける (#192) - #232
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
new_scale の 1 未満・現在以下の判定とログを関数へ移す(設計の決定 8)。 文言と出し分けは変えない。契約のテストを足し、既存の現状固定テストは書き換えない。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…192) cmd_up の _run_deploy_pipeline と対称の段にする(設計の決定 8)。起動が 0 以外なら Failed to start new containers を出して None を返し、ほかの失敗は伝播する。後処理 (bao の token・./deploy・完了のログ)は cmd_scale の本体に残す。段階の番号とログの 文言は変えない(決定 7)。cmd_scale の本体は 92 行から 40 行になる(D-3)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
40 行に届かせるために削った空行・1 行へ詰めた文・短くしたコメントを、抽出前の書式へ戻した。 振る舞いは変えない。D-3 の意図(段階の命名と cmd_up との形の一致)は満たし、行数は 要求の数え方で 51 行になる。数字のために読みやすさを犠牲にしない判断を要求の文書と計画に記した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Preserve configuration and subprocess side effects on target resolution and readiness failures. Item-Id: R1-001 Round: 1 Impl-Runtime: codex Impl-Model: default
改修計画 — devbasex/devbase #232
ラウンド 1(実装 codex / レビュー agy / kiro)R1-001 —
|
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| error | unit | — | codex / agy / kiro | 採用 | 1 |
なぜ: _resolve_docker_target が DevbaseError を送出したときに 'Scale failed' を出して 1 を返す try/except 経路が固定されていない。scale_harness は _resolve_docker_target を成功させるスタブに固定しており、この失敗分岐は既存テストで観測されていない。
手順: 1. scale_harness を使い、既存の設定と override の内容を保存し、./deploy を用意する。失敗箇所以外の外部依存は成功する疑似実装にする。
2. 接続先解決のケースでは実際の解決経路を通し、docker_context.resolve_target の依存境界で DevbaseError を発生させて cmd_scale(2) を実行する。現在の戻り値 1、設定と override の不変、Compose 起動要求なしを観測して固定する。
3. 別ケースでは wait_for_containers_ready の依存境界で DockerError を発生させて cmd_scale(2) を実行する。現在の戻り値 1、更新済み scale: 2 と生成済み override が残ること、Compose 起動要求があり停止・削除要求がないことを観測して固定する。
4. deploy は実際の実行経路を subprocess 境界まで通し、両ケースとも bash による deploy 実行要求がないことを固定する。内部ヘルパーの呼び出し回数やログの完全一致は検証しない。
R1-002 — lib/devbase/commands/container.py#cmd_scale
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| branch | unit | — | codex / agy | 検証中 | 1 |
なぜ: 既存の公開入口テストは project.yml に scale: 1 を指定しており、config.scale が None のとき DEFAULT_SCALE(現状 2)を現在台数として扱う分岐を固定していない。既定値は増設の可否と deploy の対象番号の両方に影響する。
手順: 1. scale_harness を使い、project.yml から scale 行だけを除いた入力を用意する。外部依存は疑似実装とし、private 関数を直接呼ばない。
2. 独立したケースで cmd_scale(2) と cmd_scale(3) を実行し、現在の戻り値、設定ファイル、外部起動要求を観測する。
3. 2 のケースでは戻り値 1、設定ファイルの不変、Compose 起動要求なしを固定する。
4. 3 のケースでは ./deploy を用意して実際の deploy 実行経路を subprocess 境界まで通し、戻り値 0、保存された scale が 3、bash 子プロセスの DEVBASE_INSTANCE_INDEX が 3 のみであることを固定する。内部関数の呼び出し順や回数、表示文言は比較しない。
見送った項目
(なし)
Fix current behavior when config.scale is omitted in project.yml. DEFAULT_SCALE is treated as current scale, rejecting scale 2 and deploying only instance 3 on scale 3. Item-Id: R1-002 Round: 1 Impl-Runtime: agy Impl-Model: default
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | agy | APPROVE
設計決定8に基づく抽出、受け入れ条件D-3の行数判断と文書の整合性、および追加テストの妥当性を確認しました。修正を要する問題はありません。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
構造変更として設計(決定 8)どおり _check_scale_request / _run_scale_pipeline を抽出し、try 境界・ログ文言・後処理の順序を維持できている。追記した 7 件のテストも green(uv run --locked pytest tests/commands/test_container_scale_order.py -q → 26 passed)で、実装の細部より段階の契約(D-4)と失敗系の現状固定を検証しており妥当。既存コメント R1-001 / R1-002 の範囲は本 PR のテストが対応済みで重複指摘なし。
修正提案(本番の振る舞いには影響しない、文書の正確性のみ):
- [minor / 正確性] PR 本文 D-3 表の行数が実測と不一致: PR 本文の D-3 表は
cmd_scaleの「def〜最後の行」列に 40 を記載しているが、実測は 54(astのend_lineno - lineno + 1。def 1665〜end 1718)。この 54 はissues/PLAN65_scale-compose-path-impl2.md:48(「92 → 54」)やissues/PLAN65_scale-compose-path.mdの「同じ数え方で 51 行」とも整合する。40 は本文の記述どおり「空行・コメントを除けば」の値であり、表の列見出し(def〜最後の行)とはずれている。修正: PR 本文 D-3 表の該当セルを 54 に直すか、列見出しを「空行・コメント除外」に改める。plan 側の文書(impl2.md / plan.md)は 54 / 51 で内部整合しているため変更不要。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | codex | APPROVE
新たな修正指摘はありません(関連テスト 156 件成功、D-3 の行数と未達の記録を確認)。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | kiro | APPROVE
構造変更として妥当。_check_scale_request(16 行)/ _run_scale_pipeline(48 行)の抽出は本番の振る舞いを変えず、DockerError が DevbaseError のサブクラスであるため cmd_scale の except DevbaseError が従来どおり捕捉する点も保たれている。D-3 の行数(def〜最後の行で 54、要求の数え方で 51)は ast で実装と一致し、40 行を満たさない判断とその根拠が impl2.md / PLAN65_scale-compose-path.md / PR 本文で一貫している。追記された 7 件のテストは 26 件すべて緑で、順序固定テストの範囲を超えた過剰な実装依存はなく、名前・docstring と assert が一致している。修正を要する指摘は無い。
Summary
設計文書
issues/PLAN65_scale-compose-path-design.mdの「実装の分け方」の 2 本目(cmd_scaleの段階を分ける)。設計の決定 8 のとおり、
_check_scale_request(前提の検査)と_run_scale_pipeline([1/5]〜[5/5])の 2 つを抽出した。後処理(bao の token・
./deploy・完了のログ)はcmd_scaleの本体に残し、cmd_up(_run_pre_up_checks→_run_deploy_pipeline→ 後処理)と対称にした。本番の振る舞いは変えない構造変更である。 計画は
issues/PLAN65_scale-compose-path-impl2.md。cmd_upとの形の一致)を満たし、40 行の数字は満たさない(下の D-3。要求の文書issues/PLAN65_scale-compose-path.md)lib/devbase/commands/container.pyのcmd_scaleだけ(新設の 2 関数をその直前に置いた)Closes #192
変更点
refactor(PLAN65):new_scaleの 1 未満(error 1 行)・現在以下(warning + info 2 行)の判定を_check_scale_request(new_scale, current_scale) -> boolへ出した。文言と出し分けは変えないrefactor(PLAN65):[1/5]〜[5/5](write_scale・ensure_volumes・ensure_network・_build_scaled_override・default_services・docker_compose(['up', '-d', '--no-recreate', *services])・wait_for_containers_ready)を_run_scale_pipeline(project_name, new_scale, current_scale, config, target, dev_service_name) -> Optional[Path]へ出した。起動が 0 以外なら
Failed to start new containersを出してNone、それ以外の失敗はDevbaseError/DockerErrorのまま伝播する(設計の契約の表どおり)tests/commands/test_container_scale_order.pyに新設の 2 関数の契約のテストを 7 件追記した。既存のテストは 1 行も書き換えていない(586a1aeの時点でgit diff eaa9e5d -- tests/commands/test_container_scale_order.pyの削除行 0)style(PLAN65): 40 行へ合わせるために詰めたcmd_scaleの空行・折り返し・コメントを抽出前の書式へ戻した(下の D-3)cmd_scaleの現状固定テストを 3 件足した(91ba4b4: 接続先の解決の失敗と ready 待ちの失敗、f2dc70a:project.ymlにscaleが無いときの既定台数)。scale_harnessに本物の_resolve_docker_targetを返す口とDockerErrorの import を足した(テスト本体の行は書き換えていない)。構造改善の提案は重要度 major 以上が 0 件で、本番コードへの変更は無い採らなかった案(設計の決定 8 が退けたもの): 段階ごとに 5 関数へ分ける /
_run_deploy_pipelineとの統合。1 本目の cross-refactoring で 3 者が挙げた extract_method は参考にとどめ、境界とシグネチャは設計に従った。
テスト駆動の証跡: 2 つの関数とも契約のテストを先に書き、変更前の実装で
AttributeError: module 'devbase.commands.container' has no attribute '_check_scale_request'(/_run_scale_pipeline)で落ちることを確かめてから抽出した。D-3:
cmd_scaleの行数 — 数字は満たさない(意図は満たす)D-3 の「40 行以下」は満たさない。数字のために読みやすさを犠牲にしない判断をした。
この条件の意図(設計の決定 8・#192)は「長い関数の段階に名前を付け、
cmd_upと形を揃える」ことで、行数はその目安である。一度は空行を削り 2 つの文を約 100 文字の 1 行へ詰めて 40 行に合わせたが、検査の持ち場で抽出前の書式へ戻した(
b4c839a)。40 行へ届かせるには、詰めるか、設計の決定 8 に無い 3 つ目の関数(後処理)を出すかのどちらかが要り、どちらも採らない。
要求の文書を書き足した:
issues/PLAN65_scale-compose-path.mdの D-3 の下に、この判断と数え方を追記した(条件の文言そのものは変えていない)。計画issues/PLAN65_scale-compose-path-impl2.mdの D-3 は未チェックにし、結果を記した。要求の「86 行」は、
defから最後の行まで(89 行)からシグネチャ 2 行とドキュメント文字列 1 行を除いた数(空行・コメントを含む)だった。ast)c3c0d3beaa9e5ddef〜最後の行(end_lineno - lineno + 1)新設:
_check_scale_request16 行、_run_scale_pipeline48 行。cmd_upはdef〜最後の行で 72 行。D-4: 段階の対応
grep -n "/5\]" lib/devbase/commands/container.py(コメントとドキュメント文字列を除くログの行はすべて_run_scale_pipeline(1615〜1662 行)の中):cmd_up側cmd_scale側(この Pull Request)_run_pre_up_checks_check_group_consistencyと_check_scale_request[1/5]〜[5/5]_run_deploy_pipeline([1/6]〜[5/6])_run_scale_pipeline./deploy→ bao → …)./deploy→ 完了のログ。順序は変えない)段階の番号の文字列(
[2.5/5]を含む)は変えていない(決定 7)。Test plan
release/v3.7.0を base にした Pull Request では CI が動かない(#216)。以下はすべて手元(作業ツリー、macOS)で実行した。実環境のプロジェクトでの
devbase up/scale/loginは実行していない。uv run --locked pytest tests/ -q(eaa9e5d+ 空コミット)→2889 passed、exit=0uv run --locked pytest tests/commands/test_container_scale_order.py -q→ 新しいテストだけがAttributeErrorで失敗(4 failed / 15 passed、3 failed / 19 passed)uv run --locked pytest tests/ -q -k scale→58 passed、exit=0(現状固定テストを含む)uv run --locked pytest tests/ -q -k scale→61 passed、exit=0uv run --locked pytest tests/ -q(586a1ae)→2896 passed、exit=0(足した 7 件の分だけ増えた。失敗 0)— C-3 / C-4 / E-1f2dc70a、2026-09-22 23:40):uv run --locked pytest tests/ -q→2900 passed、exit=0(2896+ 構造改善のテスト整備で足した 4 件〈parametrize 2 件を含む〉)uv run --locked --python 3.10 pytest tests/ -q→2900 passed、exit=0uv run --locked pytest tests/commands/test_container_scale_order.py tests/commands/test_container_up_order.py -q→44 passed、exit=0(E-1:test_container_up_order.pyは書き換えていない)python3 -m compileall -q lib bin→ exit=0 /uvx ruff check --select=E9,F63,F7,F82 lib→ exit=0--severity-threshold major): テスト整備 1 ラウンドで 2 項目を適用し各ラウンドの全件テストが exit=0。構造改善の提案は 5 件すべて minor で採用 0 件(収束)。最終ゲートの全件テスト exit=0。改修計画: refactor(PLAN65): cmd_scale の段階を前提の検査と段階の実行へ分ける (#192) #232 (comment)f2dc70aを見た)。round 1 の kiro のレビュー本文の minor(本文の D-3 の表の行数)はこの本文の更新で対応。未解決のスレッド 0devbase scale): 実行していない。本番の系に対してdevbase up/scaleを走らせない方針のため。振る舞いは現状固定テスト(コマンド列・子プロセスの環境・失敗経路)で固定しているastの行数 →cmd_scaleはdef〜最後の行で 54 行、要求の数え方で 51 行。40 行の数字は満たさない(理由は上の D-3)。段階のログ文字列はすべて_run_scale_pipelineにあるgrep -n "/5\]"の出力(上)🤖 Generated with Claude Code