From a47a965c908ee008284f65d1d1005eb977626849 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Wed, 2 Sep 2026 15:56:27 +0900 Subject: [PATCH] =?UTF-8?q?docs(history):=20issue=20#139=20=E3=81=AE?= =?UTF-8?q?=E6=8C=AF=E3=82=8A=E8=BF=94=E3=82=8A=E3=82=92=E6=AE=8B=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docs/development-history/ を作り、最初の記録を置く。 進め方で分かったこと: - マージ前に追加した wrapper のテストは、run_python/cmd_build をスタブへ 差し替える方式のため dispatch より前の name 解決を素通りしていた。 リリース後テストで実際にコマンドを打って初めて #146 が見つかった - 仕様で「前提」として範囲外に置いた領域は、レビューの視野からも外れる - 実機ビルドは 3 分 18 秒で、マージ前に避けた理由に見合っていなかった 設計 PR を実装より先に通す運びは変えない。shell / Python どちらへ寄せるかを 実装前に固定できた効果のほうが大きい。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01V9tinzTAbF1LVEYvfUgzKx --- docs/development-history/01-2026-09-02.md | 107 ++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/development-history/01-2026-09-02.md diff --git a/docs/development-history/01-2026-09-02.md b/docs/development-history/01-2026-09-02.md new file mode 100644 index 00000000..24cda92f --- /dev/null +++ b/docs/development-history/01-2026-09-02.md @@ -0,0 +1,107 @@ +# 開発履歴と知見 (2026-09-02) + +**期間**: 2026-09-02 +**対象**: [issue #139](https://github.com/devbasex/devbase/issues/139) / [PR #143](https://github.com/devbasex/devbase/pull/143)(設計)/ [PR #144](https://github.com/devbasex/devbase/pull/144)(実装)/ [PR #145](https://github.com/devbasex/devbase/pull/145)(v3.1.0) + +`devbase build ` が必ず失敗する不具合を直した。`` の位置引数が剥がされないまま +`docker buildx build` へ渡り、PATH が 2 つになっていた。CLI リファレンスに正式な構文として +載っているにもかかわらず、ベースイメージだけを再ビルドする手段が無い状態が続いていた。 + +単体ビルドの実装は shell と Python の 2 か所にあり、タグの規約も食い違っていた +(shell が `devbase-base:latest`、Python が `base:latest`)。どちらへ寄せるかを設計で決め、 +Python へ集約したうえで、あわせて `v3.0.0` 以降に溜まっていた 11 件のマージを `v3.1.0` として +配布した。 + +## 何が起きたか + +### 受け入れ条件は 2 度変わった + +| いつ | 何が変わったか | きっかけ | +| --- | --- | --- | +| 設計 | AC8「単体ビルドの docker 呼び出しが 1 箇所」の対象から、shell の `build_base_image` を外した | compose ビルドの 1 段目であって単体ビルドではないため。Python へ寄せると `uv run` の往復が 3 回になり、振る舞いは変わらない | +| 実装レビュー | タグの接頭辞を「剥がしてから付け直す」から「剥がさない」へ反転した | `containers/xxx` と `containers/devbase-xxx` が同じタグを取り合い、ディレクトリ名とタグの 1:1 対応が崩れる | + +どちらも取り消し線で旧記述を残し、理由と日付を添えて計画ファイルへ書いた。消して差し替えると、 +「元の条件を満たしていない」のか「条件が変わった」のかがレビューで区別できなくなる。 + +### 手戻りは実装 PR に集中した + +| PR | 内容 | round 1 | round 2 | 指摘の合計 | +| --- | --- | --- | --- | --- | +| #143 | 要求仕様 + 設計 | 両者 APPROVE | — | 0 | +| #144 | 実装 | codex APPROVE / gemini REQUEST_CHANGES | codex COMMENT / gemini APPROVE | 3(major 1 / minor 2) | + +設計 PR が 1 round で通ったのは、依頼文が「確認が要る」としていた 2 点を設計の前に実測で +潰していたためと読める。 + +- `containers/` 配下 10 件すべてが `devbase-` 規約に従うことを、`compose.yml` の `image:`・ + 他 Dockerfile の `FROM`・`snapshot/manager.py` の `SNAPSHOT_IMAGE` から確認した +- 「Python 側の単体ビルドは到達不能」という issue の記述が誤りで、`devbase project build ` + からは到達できることを確認した。この事実が「実装をどちらへ寄せるか」の決め手になった + +一方、設計レビューでは「タグがディレクトリ名の単射になっているか」という観点が出ず、実装 PR で +初めて指摘された。仕様と設計のテキストだけを載せた差分では、写像の性質までは読み取りにくい。 +ただし捕まえ直したコストは実装 30 行の書き換えで済んでおり、設計 PR を分けた価値 +(shell / Python どちらへ寄せるかを実装前に固定できた)のほうが大きい。 + +### マージ前のテストは wrapper の前段を通らなかった + +追加した 25 件のテストは、`bin/devbase` を実プロセスで起動しつつ `run_python` / `cmd_build` / +`compose_with_secrets` をスタブへ差し替える方式で書いた。既存の +`tests/cli/test_project_name_resolution.py` に倣ったもので、dispatch の振り分けは正しく固定できる。 + +しかしこの方式は、**dispatch へ入る前の name 解決を素通りする**。`_build_single_image` に入れた +image 名の検証(`[A-Za-z0-9][A-Za-z0-9._-]*`)も、name 解決に引数を消費されると届かない。 + +リリース後テストで実際に `devbase build ../etc` を打って初めて分かった。 + +``` +$ devbase build ../etc +=== Building devbase images === +[1/2] devbase-base already exists (use --no-cache to rebuild) +[2/2] Building project image... +no configuration file provided: not found +``` + +`$DEVBASE_ROOT/projects/../etc` が `$DEVBASE_ROOT/etc` に解決され、そこへ cd していた +([#146](https://github.com/devbasex/devbase/issues/146))。この挙動自体は今回の変更より前から +あり、`build` に限らず name 解決を通る全コマンドに共通する。 + +**見つかった場所が、仕様で「前提」として範囲外に置いた領域の隣だった。** 前提 2 で +「`` と実在プロジェクト名の衝突は扱わない」と明記したため、レビューでもその周辺は +論点にならなかった。範囲外と宣言した領域は、レビューの視野からも外れる。 + +### 実機での確認は 3 分 18 秒で済んだ + +`devbase build base --no-cache` のフルビルドは 3 分 18 秒(15:50:16 → 15:53:34)。 +再ビルドしたイメージの中身(node v24.20.0 / gh 2.99.0 / `tmux-first` 10609 バイト)と、 +`FROM devbase-base:latest` が解決できることまで確認した。マージ前に避けた理由(時間がかかる)は +実測に見合っていなかった。 + +## 次に変えること + +| 変えること | 落とし先 | 状態 | +| --- | --- | --- | +| `bin/devbase` のテストに、name 解決を含む経路を 1 本通す。スタブ harness は dispatch 以降しか見ないため、前段の欠陥を固定できない | プロジェクトの取り決め(`tests/cli/`) | [#146](https://github.com/devbasex/devbase/issues/146) の修正に含める | +| 仕様で「前提」として範囲外に置いた項目を、リリース後テストで 1 度は実際に踏む。範囲外の宣言はレビューの視野からも外れるため、実機が最後の網になる | 次の変更で試すこと | [#146](https://github.com/devbasex/devbase/issues/146) へ由来として記録済み | +| 実行に時間がかかることを理由にマージ前の検証を落とすときは、所要時間を見積もりではなく実測で持つ。今回は 3 分 18 秒だった | 次の変更で試すこと | この記録に残す | + +設計 PR を実装より先に通す運びは変えない。2 段階に分けたことで「shell / Python のどちらへ +寄せるか」という後戻りの高い判断を実装前に固定でき、実装 PR のレビューは実装の細部に +集中できた。設計段階で写像の性質まで捕まえられなかったのは、2 段階レビューが結果的に +補っている。 + +## 途中で起票した課題 + +| 番号 | 何を見つけたか | 見つけた場面 | +| --- | --- | --- | +| [#141](https://github.com/devbasex/devbase/issues/141) | CI が `tests/` の pytest を実行していない。`compileall` / `ruff`(構文相当のみ)/ `shellcheck` の 3 つだけで、テストが壊れても main へ入る | 設計中(回帰テストの追加先を確認していて気づいた) | +| [#142](https://github.com/devbasex/devbase/issues/142) | `devbase build ` の `` が実在プロジェクト名と一致すると、name 解決に吸われて黙って別のものをビルドする。`projects/bi-tools` と `containers/bi-tools` が両方実在する | 設計中(全イメージで動くかを確認していて気づいた) | +| [#146](https://github.com/devbasex/devbase/issues/146) | name 解決が `projects/` の外へ出られる。`maybe_cd_project` が `-*` と空文字しか弾かない | リリース後テスト | + +いずれも由来を `issue #139` の形で本文へ書き、#139 側にもコメントで番号を残した。 +`gh issue list --state all --search "issue #139"` で 3 件とも引ける。 + +`quality-gates` の完了報告に挙げた「範囲外と判断したもの」は #141 / #142 の 2 件で、どちらも +起票済み。レビューの指摘 3 件はすべて修正しており、範囲外として resolve したものは無い。 +取りこぼしは無かった。