Skip to content

release: v3.7.0 base イメージの描画と、名前・見出し・文書の食い違いの解消 - #212

Merged
takemi-ohama merged 15 commits into
mainfrom
release/v3.7.0
Sep 22, 2026
Merged

takemi-ohama merged 15 commits into
mainfrom
release/v3.7.0

Conversation

@takemi-ohama

@takemi-ohama takemi-ohama commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

このリリースの狙い

devbase の base コンテナでは、日本語が中国語のフォントで描かれていました。 sans-serif が
WenQuanYi Zen Hei へ解決されるため、Chromium / Playwright のスクリーンショット、PDF の生成、
画像の生成のすべてが中国語の字形と字幅で写ります。見た目だけの問題ではなく、生成物をそのまま
成果物として出せません。あわせて base には PDF や Office 文書を扱う道具が無く、確認のたびに
利用者がコンテナへ何かを入れる状態でした。

もう 1 つは、文書と確定仕様が約束していることと、実装が食い違ったまま残っていたことです。

  • devbase scale だけが docker compose を共通経路を通さずに呼ぶため、確定仕様が
    「COMPOSE_PROFILES は devbase 経由の操作に効かない」と書いている約束が scale で破れていた
  • 機密の参照の見出しがグループの読み替えの前の名前だけを出し、隣に並ぶパスと食い違って見えていた
  • 名前の形に合わないプロジェクトは、作られてから初めて「名前を指定した操作ができない」と分かった
  • pytest が実行したシェルの DEVBASE_ROOT を継承するため、テストが実環境の設定を読むことがあった
  • [name] と --context を取るサブコマンドの列挙が、文書の各所で実装より古かった

この版は、この 2 つ ── base イメージの描画と道具立て、約束と実装の食い違い ── を
まとめて解きます。

利用者に操作をお願いする変更(2 点)

1. base イメージは devbase build base --no-cache で建て直してください

フォントの解決とパッケージの追加はイメージの中の変更です。devbase up だけでは手元は
変わりません。

devbase build base --no-cache

containers/general など base から派生したイメージを使っているプロジェクトは、その派生
イメージも建て直し
、コンテナを作り直してください(devbase down → devbase up)。
devbase rebuild では建て直りません ── devbase build --expires=7 のシノニムのため、
期限内はビルドそのものを飛ばします。建て直すまで、手元の描画と道具立ては前の版のままです。

建て直した後は次のようになります。

  • sans-serif / sans / serif / monospace と、イメージに無い和文書体名(Meiryo /
    Yu Gothic / MS PGothic / Noto Sans JP など)が Noto CJK の JP フェイスへ解決される
  • Calibri / Cambria が metric 互換の Carlito / Caladea へ解決される(従来はどちらも中国語フォント)
  • pdftoppm / pdfinfo / pdffonts / pdftocairo と、python3 の PIL / defusedxml / lxml が使える
  • 欧文(Arial / Times New Roman / Courier New)は Liberation の metric 互換のまま変わらない
  • lang=zh-cn / lang=ko を明示した指定は、その言語の、同じ様式のフェイスのまま
  • 言語を明示しない中国語は日本語の字形で描かれます(意図した変更です)
  • 個人の設定(~/.config/fontconfig/fonts.conf)で上書きできます

イメージは +10.0 MB です。LibreOffice と pip は入れていません。Python パッケージが
要るときは既にある uv / uvx を使ってください。

2. COMPOSE_PROFILES を端末や .env に置いている方へ

devbase scale が、プロファイルのサービスを起動しなくなります。

これは是正です。確定仕様は以前から「COMPOSE_PROFILES を端末や .env に置いても devbase
経由の操作には効かない」と定めており、scale だけがその経路を外れて環境変数を素通しにして
いました。up / down / ps など他のサブコマンドは以前からこの約束どおりに動いています。

プロファイルのサービスを起動するときは、明示のコマンドを使ってください。

devbase project profile up <名前>

プロファイルを持たないプロジェクトでは、起動の対象の集合は変わりません。

そのほかの変更

  • 名前の形に合わないプロジェクトを、作られた時点で知らせます。 devbase plugin install /
    update / sync と devbase env import が、projects/ に載る名前(衝突時に合成する
    <名前>.<owner> を含む)を見て、名前を指定した操作ができない形なら警告を 1 行出します。
    弾きません。 作られる symlink・ディレクトリと終了コードは変わりません
  • 機密の参照の見出しが、グループの読み替えの前と後を出します。 group_aliases のある
    置き場で、devbase env list の見出しと件数、devbase env backend test の参照ごとの行、
    devbase env backend migrate の計画と完了の一覧が グローバル(グループ default) から
    グローバル(グループ default → nyle) になります。読み替えの無いグループ・version: 1・
    ファイル backend の表示と、置き場のパス・サーバへの要求・キャッシュは変わりません
  • スナップショットの名前が、末尾に改行を持つ値(abc\n)を受け付けなくなりました。
    位置引数のプロジェクト名と同じ規則へ寄せた結果です。それ以外に受け付ける名前とエラーの
    文言は変わりません
  • devbase scale の内部構造を、devbase up と同じ形(前提の検査 → 段階の実行 → 後処理)へ
    揃えました。
    本番の振る舞いは変えていません
  • 文書: [name] と --context を取るサブコマンドの列挙を argparse の実際の集合へ揃え
    (rebuild / open の漏れ)、プラグインが profiles: を使うときに requires.devbase を
    ">=3.5.0" へ上げる手順を足しました。あわせて、この版で実装が終わった設計の文書を確定仕様
    (docs/specifications/)へ取り込み、base イメージの描画の確定仕様を新設しました
  • テスト: pytest がセッション全体で DEVBASE_ROOT をテストごとの一時ディレクトリへ隔離
    します。実環境の projects/ と secrets/backend.yml を読む穴を塞ぎました

取り消しの手段と、その限界

対象 戻し方 限界
main の内容 このマージを revert して main へ入れる 利用者が引き直すまで手元は新しい版のまま
base イメージ 戻した containers/base で devbase build base --no-cache 建て直した人の手元は自動では戻りません。 イメージは各自の Docker にあり、main を戻しても置き換わりません。派生イメージとコンテナの作り直しも各自で要ります
devbase scale の振る舞い revert で戻る 移行先の devbase project profile up は以前からあるコマンドのため、手順を移した人はそのまま使えます

Test plan(結合の観点)

個別の振る舞いの確認は繰り返しません。ここで見るのは、束をまたいで同じ系を指すかだけです。

  • release/v3.7.0 の先端で env -u DEVBASE_ROOT uv run pytest -q が 3022 passed / exit=0
    (DEVBASE_ROOT の隔離が入った後も全体が緑であること)
  • uv lock --check が exit=0、python -m devbase.cli --version が devbase 3.7.0
  • base イメージを --no-cache で建て直し、変更前後を同じ日に建てて比較。fc-match の
    解決先 28 通り、pdftoppm と python3 の PIL / defusedxml / lxml、soffice / pip が
    入っていないこと、層の合計で +10.0 MB。派生イメージ(containers/general)でも同じ解決先
  • グループの読み替えのある端末で、devbase up / scale / env backend test / env list が
    同じ系を指すこと — マージ後のリリース後テストで確かめます
  • amd64(WSL2)での base イメージの建て直し — リリース後テストで確かめます

CI はこの Pull Request(base が main)で初めて全ジョブが動きます。release/v3.7.0 を base に
した個別の Pull Request では on.pull_request.branches が main だけのため 1 件も動きません
でした(#216)。

関連 Issue

Fixes #161
Fixes #160
Fixes #188
Fixes #192
Fixes #195
Fixes #203
Fixes #208
Fixes #209

開発用の進捗(レビュー対象外)
束 課題 設計 実装
文書の列挙 #208 #195 — #213
テストの環境の隔離 #209 — #217
scale の Compose の共通経路 #192 #225 #231 #232
プロジェクト名の知らせ #203 #230 #233 #235
機密の見出しのグループ #188 #223 #237
base イメージの描画 #161 #160 #221 #238
確定仕様化 — — #240
配布の準備 — — #241

この版で起票した範囲外の課題: #214 #215 #216 #218 #219 #220 #224 #226 #227 #228 #229 #234 #239

🤖 Generated with Claude Code

https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

配布の記録

段階: 検証(検証のチャネルが無いため、main へのマージが本番への配布にあたる。承認待ちのため未実施)
版: 3.6.0 → 3.7.0(MINOR: 後方互換のある追加と、確定仕様に合わせた scale の是正)
まとまり: PR #213 / #217 / #221 / #223 / #225 / #230 / #231 / #232 / #233 / #235 / #237 / #238 / #240 / #241

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
takemi-ohama and others added 6 commits September 22, 2026 21:19
* docs(PLAN63): base イメージの日本語の描画と、文書を扱う軽量の道具の要求仕様と設計 (#161, #160)

base コンテナで sans-serif が中国語フェイス(WenQuanYi Zen Hei)へ解決される問題と、
Office 文書・PDF を扱う軽量の道具が無い問題を、1 本の設計にまとめた。

どちらも containers/base/Dockerfile の同じ apt / COPY の区画を触るため 1 本にした。
実装は別のブランチで行う。この Pull Request は設計文書だけを載せる。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 受け入れ条件 6 の表を 8 通りへ揃え、wqy-zenhei の扱いを実態へ直す

レビュー指摘 2 件への対応。

- 受け入れ条件 6 の表に総称ファミリ 4 つ × 言語 2 つの 8 行が揃っていなかった。
  `sans:lang=zh-cn` / `sans:lang=ko` / `monospace:lang=ko` を足し、欧文を名指しした
  行にも `Arial:lang=ko` を足して 12 行にした(major)
- 設計文書の「解決先の表」にも同じ 4 行を足し、`serif:lang=ko` の変更前が
  `(未測定)` のままだったのを実測値 `WenQuanYi Zen Hei` へ直した
- テスト設計の受け入れ条件 6 の行を「8 つ」から「12 行(総称ファミリ 4 つ ×
  言語 2 つの 8 行と、欧文を名指しした 3 行、中国語の書体を名指しした 1 行)」へ改めた
- 「変えないもの」の `fonts-wqy-zenhei` の行が Dockerfile の実態と合っていなかった。
  導入の行は無く `npx playwright install --with-deps chromium` が依存として入れる、
  と書き直した。決定 6 の検査の観点も `apt-get remove` / `apt-get purge` / `dpkg -r`
  が無いことの確認へ具体化した(minor)

いずれも手元の devbase-base:latest(arm64)での実測にもとづく。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 切り戻し手順に派生イメージとコンテナの建て直しを足し、`<match>` の数を 9 に直す

cross-review round 2 (codex) の 2 件へ対応した。

- 切り戻し手順を 4 段(revert / base の再ビルド / 派生イメージの建て直し /
  稼働中コンテナの作り直し)へ書き直した。base のタグを戻しても、派生イメージは
  `FROM devbase-base:latest` を自分のビルドの時点で焼き込むため建て直すまで古い層を持つ。
  「影響」の表の「利用者の操作」の行にも同じことを書いた
- `fonts-local.conf` の `<match>` は、未導入の書体の受け皿 1 つと総称ファミリ 4 つ ×
  言語 2 つの 8 つで合計 9 つである。テスト設計の検査条件と本文の説明の両方を 9 つへ直した

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 解決先の表の漏れ・参照先・キャッシュの説明を直す

round 3 のレビュー指摘 3 件へ対応する。

- 解決先の表へ `Times New Roman:lang=zh-cn` の行を足す(実測済みの値。
  `Arial:lang=ko` は既にあった)
- 決定 2 の中の参照先を「決定 4」から「決定 8」へ直す。`sans-serif` の
  prefer を日本語へ向けるのは決定 8 である
- 決定 4 のキャッシュの説明を Docker の仕様へ合わせる。`RUN` のキャッシュが
  効いている間はその中身が実行されないため、取得先の内容が変わっても
  キャッシュは無効にならない

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 受け入れ条件 13 の合否のラインを測り方の違いに耐える形へ直す

受け入れ条件 13 は合否のラインを「約 24 MB」とし、検証を `docker images`
の差と定めていた。しかし 24 MB は稼働中のコンテナでの `du` の差(apt の
リストとキャッシュを含む)で、`docker images` が出す層単位の値とは測り方が
違う。そのままでは正しい実装でも不合格になりうる。

合否のラインを「7.09GB に対して +0.5% 未満(40 MB 以下)」へ改め、
24 MB をラインに使わない理由を条件の中に書いた。設計文書の
「未確認のまま残ること」にも、このラインが測り方の違いを吸収するための
ものである旨を追記した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): コンテナの作り直しの案内を devbase down → up へ統一する

devbase rebuild は devbase build --expires=7 のシノニム
(lib/devbase/commands/container.py の cmd_rebuild) で、イメージのビルドしか
行わず稼働中のコンテナを作り直さない。期限内ならビルドそのものを飛ばすため、
切り戻しにも適用にも使えない。

「影響」の表の「利用者の操作」と「切り戻し手順」の 4 番目の両方で、稼働中の
コンテナの作り直しを devbase down → devbase up に統一し、devbase rebuild が
ここでは使えない理由を書き添えた。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 受け入れ条件へ IPAPGothic と fc-match sans を足し、テスト設計に fc-match -s を書く (#221)

round 6 のレビュー指摘 3 件への対応。

- 受け入れ条件 6 の表へ `IPAPGothic`(名指し)の行を足した。イメージに実在する
  日本語の書体がそのまま残ることを固定する。受け入れ条件 4 は「イメージに無い
  書体名が JP へ落ちる」条件なので、`WenQuanYi Zen Hei`(名指し)と同じ性質の
  この行は 6 の表へ置いた
- 受け入れ条件 1 へ `fc-match sans`(`lang` なし)を足した。`fonts-local.conf` は
  `sans` の `<alias>` を持つのに、`lang` を付けない照合が固定されていなかった
- テスト設計の受け入れ条件 1〜4 の行へ、`fc-match -s sans-serif:lang=ja` の 1 件目も
  確かめることを明記した。あわせて受け入れ条件 6 の行数を 12 から 13 へ直した

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 受け入れ条件 5 から Calibri / Cambria を外し 11 へ移す

受け入れ条件 5 の見出しは「欧文が壊れない」だが、`Calibri` と `Cambria` は
変更前に `WenQuanYi Zen Hei`(中国語のフェイス)へ落ちており、`Arial` などの
「変更の前後で変わらない」ものとは性質が違う。同じ枠に並べると基準を誤読させる。

- 受け入れ条件 5 は変わらない 3 つ(`Arial` / `Times New Roman` / `Courier New`)に絞る
- 受け入れ条件 11 を「欧文の metric 互換が直る」とし、現状がどちらも
  `WenQuanYi Zen Hei` であることと、直す手段(`fonts-crosextra-carlito` /
  `fonts-crosextra-caladea`)を書く
- 設計文書のテスト設計の表の `5・11` の行を、上の切り分けに合わせる

受け入れ条件の番号は 1〜16 のまま変えていない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN63): 決定 2 の表がどの状態を測っているかを列の見出しと前置きで示す

「解決先の表」の ko の「変更前」と、決定 2 の表の ko の「規則なし」は
食い違って見えるが、測っている状態が違う。前者は /etc/fonts/local.conf
が無い今の base イメージそのまま(WenQuanYi Zen Hei)、後者は local.conf
は置いたうえで zh-cn / ko の <match> だけを書かなかった状態
(Noto Sans CJK JP / Noto Serif CJK JP)である。どちらも 2026-09-22 に
arm64 で実測した値なので、値は変えない。

読み分けられるように、決定 2 の表の列の見出しを「zh-cn / ko の規則なし」
へ改め、表の直前に 3 つの列がどれも local.conf を置いた状態であることと、
local.conf を置く前の値は「解決先の表」の「変更前」にあることを書いた。
決定 2 の末尾の段落の言い回しも同じ語に揃えた。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(PLAN64): 機密の参照の見出しにグループの読み替えの前後を出す設計 (#188)

要求と受け入れ条件 (issues/PLAN64_secret-label-group.md) と設計
(issues/PLAN64_secret-label-group-design.md) の 2 文書を足す。lib/ は変えない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN64): レビューの指摘 3 件を反映 (#188)

- 受け入れ条件 7 の例示を、実際に SecretRef.label() の既定を使う文言
  (OpenBaoBackend._check_group / runtime の DEVBASE_ACCOUNT_GROUP 警告) へ差し替えた。
  --group の不一致の文言 (_project_group_mismatch) は display_group を直接呼んでおり、
  今も読み替えの前後を出す。対象範囲の「含まない」と決定 2 に明記した
- 設計のテスト設計 7 の参照先を OpenBaoSettings.path_of から
  OpenBaoBackend._check_group へ直した
- 影響の「公開インタフェース」に env backend migrate を足した

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN64): round 2 の指摘 2 件を反映 (#188)

- 前提 2 を直した。config.openbao が None かどうかで backend の種類を判定しては
  ならない (backend: age でも openbao: 節が残れば None にならない)。表示の分岐は
  SecretStore.storage_group に任せる旨へ揃え、決定 3 の根拠にも足した
- 受け入れ条件 5・6 の検証を、既存テストの通過から新規の出力テストへ変えた。
  既存の assert は '=== グローバル' の前方一致で、見出しにグループが付いても通る
  ため「変わらないこと」を確かめられない

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN64): round 3 の指摘 2 件を反映 (#188)

- 設計文書の末尾に残っていた不要なタグ </content> を消した
- 受け入れ条件 3 とテスト設計を、env backend migrate の 2 つの一覧の両方を
  確かめる形へ直した。計画の一覧 (_MigrationPlan._heading) と --to age の
  完了表示は別の関数が出すため、--dry-run の計画一覧だけでは決定 4 を
  確かめられない

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN64): 決定 6 の仕様の書き換え指示を決定 2 の例外へ揃えた (#188)

「エラー文言とログを除く」と書くと、display_group を直接呼ぶ
_project_group_mismatch の -p の拒否の文言 (default → nyle を出す既存の仕様と
テスト) と矛盾する。除くものを「引数なしの SecretRef.label() で参照を表示する
エラー文言・ログ」に限る形へ直し、機能一覧 F2 と曖昧語の具体化にも同じ分かれ目を
書いた。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN64): テスト設計 7 の検証対象を要求文書へ揃えた (#188)

受け入れ条件 7 は 2 つの文言 (OpenBaoBackend._check_group の例外と、
runtime.py の DEVBASE_ACCOUNT_GROUP の警告) を挙げているが、設計のテスト設計は
例外だけを書いていた。警告文でも → が出ないことを見る旨を足した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
) (#225)

* docs(PLAN65): devbase scale の Compose 呼び出しを共通経路へ寄せる要求仕様と設計 (#192)

cmd_scale が docker compose を共通経路 (utils/docker.py の docker_compose) を
通さずに呼ぶため、compose_env() が適用されない。確定仕様
docs/specifications/compose-profiles.md は「COMPOSE_PROFILES を端末や .env に
置いても devbase 経由の操作には効かない」と約束する一方で、同じ文書の中で
cmd_scale をその対象から外している。

この食い違いを、約束の側を正として解く設計を置く。実測で cmd_login にも同じ穴が
あることが分かったため、そちらも同じ Pull Request で塞ぐ決定にした。

実装は 2 本の Pull Request に分ける (振る舞いと仕様 / 構造)。順序は
仕様 → 共通経路へ寄せる → 現状固定テストを足す → 関数を分ける。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN65): 決定 10 を決定の記録の一覧へ載せる (#192)

Pull Request 本文の「決めたこと」の節は設計文書の `## 決定の記録` の `###` 見出しから
作られるため、章へ切り出した決定 10 が一覧から漏れていた。章を指す見出しを置く。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN65): config 読み取りの統合を 1 本目の Pull Request へ移す (#192)

確定仕様の経路の表は _resolve_dev_service / _read_compose_services の 2 行を
docker_compose の用途へ畳む。畳んだ表を 1 本目で入れて統合を 2 本目に置くと、
1 本目のマージの時点で「共通経路を通る」と書いた仕様と、直接 subprocess.run を
呼ぶ実装が食い違った版が残る。受け入れ条件 A-1(grep が 6 → 3)・A-5(棚卸しの
一致)・D-1 も 1 本目では満たせない。

分け目を「Compose の呼び出しを共通経路へ寄せる」と「cmd_scale の段階を分ける」に
改め、受け入れ条件とどちらの Pull Request が対応するかの表を足した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(PLAN66): 名前の形に合わないプロジェクトを作られた時点で知らせる要求仕様と設計 (#203)

- プラグインの同期と env import で名前の形を検査し、弾かずに警告に留める
- スナップショットの名前の形を utils/names の述語へ寄せる
- 実装は含まない(設計だけの Pull Request)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): round 1 のレビュー指摘を反映する (#203)

- 検査の位置を候補の集約から symlink を張る直前へ移す(同じ名前で 2 行出る・載らない名前にも出る)
- 知らせの文を完了形にせず、dry-run や書き込み失敗と矛盾しない形にする
- 決定 7 の共通化の範囲(ヒント文だけ)を明記する
- 既存のテストファイルへの追加であることを検証欄に書く

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): round 2 のレビュー指摘を反映する (#203)

- env import の知らせを保存先ごとの文にする(age・サーバ backend は projects/ に作らない)
- 受け入れ条件へ age の保存先の条件を足す(番号を 1 つ繰り下げ)
- 受け入れ条件 11 の拒否リストへ末尾の改行を足し、設計の 8 件と揃える

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): round 3 のレビュー指摘を反映する (#203)

- age の保存先の受け入れ条件を backend を明示する流儀へ(平文へ落ちると条件を確かめられない)
- 同期の知らせの案内を出所ごとに分ける(別名と実ディレクトリでは改名先が違う)
- F2 と用語の定義を保存先の違いに合わせる
- real_projects を sorted で走査する旨を明記する
- 前提の番号の順序を昇順へ直す

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): F1 の文から、同期が作らない実ディレクトリを分けて書く (#203)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): round 5 のレビュー指摘を反映する (#203)

- 別名の案内を、名前の側と owner の側で分ける(_foo.valid-owner は改名で直る)
- 分かれ目を is_single_segment_name(<名前>) と明記し、_warn_unusable_name へ base を渡す
- 受け入れ条件 3 を 2 つの分岐で確かめる形にする(3 と 3-2)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): 知らせを出す時点の記述を、計画を立てた直後へ揃える (#203)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…の手順を足す (#208, #195) (#213)

* chore: 文書の列挙を揃える作業の Draft Pull Request を開く

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: [name] / --context を取るサブコマンドの列挙を揃え、profiles に requires.devbase の手順を足す

#208: argparse の集合を正本として、文書 8 か所の列挙に rebuild / open を足す。
  - [name]: 02-project.md / cli-reference/README.md(mermaid・ショートカットの表)/
    container-operations.md / specifications/compose-profiles.md
  - --context: 02-project.md / remote-docker-context.md の 2 か所(env token も)/
    environment-variables.md
  - profile も [name] を取るが解決の経路が違うことを 1 行添える
  - cli-argument-resolution.md と DEVBASE_DOCKER_CONTEXT の行は正しいので触らない

#195: profiles: を使う Plugin が plugin.yml の requires.devbase を ">=3.5.0" へ
  上げる手順を plugin-dev/compose-profiles.md へ足し、上げる契機を 1 つに限定していた
  plugin-yml-reference.md 側を広げて相互リンクする。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: #209 の作業ツリーを開く

pytest のセッション全体で DEVBASE_ROOT を隔離する作業の口を開ける。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test: pytest のセッション全体で DEVBASE_ROOT を隔離する (#209)

pytest は実行したシェルの環境を継承するため、tmp の root を作るだけで setenv しない
fixture を使うテストが、自前の `monkeypatch.setenv('DEVBASE_ROOT', ...)` を忘れると
実環境の devbase の `projects/` と `secrets/backend.yml` を読む。

fixture 1 つに setenv を足しても同じ穴は他にも残るため、`tests/conftest.py` に autouse
fixture `_isolate_devbase_root` を置き、テストごとの空の tmp の root へ固定する
(#209 の案 B)。autouse は同じ scope の明示の fixture より先に立つので、既存の 32 か所の
setenv は書き換えずに後勝ちで働き、未設定の分岐を試す道 (delenv) も残る。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#231)

* chore: #192 の実装 1 本目(Compose の呼び出しを共通経路へ寄せる)を始める

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN65): 実装 1 本目の計画を置く (#192)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN65): devbase scale と login を Compose の共通経路の対象に含める (#192)

確定仕様の「COMPOSE_PROFILES は devbase 経由の操作には効かない」を例外なしの約束にする
(設計の決定 1)。経路の表から cmd_scale の除外を削り、経路を 5 つに畳む。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(PLAN65): devbase scale の起動と config の読み取りを Compose の共通経路へ寄せる (#192)

- cmd_scale の [4/5] を docker_compose(['up', '-d', '--no-recreate', *services], check=False) にし、
  起動の対象を default_services(<生成物>) で明示する(設計の決定 1・3・4)
- config --format json を読む関数を _compose_config_services の 1 つにし、docker_compose を通す。
  _read_compose_services を削除し、_resolve_dev_service は名前と契約を保って載せ替える(決定 9)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(PLAN65): devbase login の exec にも compose_env() を渡す (#192)

経路の表が devbase の Compose の起動を網羅するよう、cmd_login の 1 行を塞ぐ(設計の決定 2)。
棚卸しのコメントを変更後の 4 経路(_compose_run / _compose_lines / cmd_login /
_query_container_name)へ書き直し、_compose_lines と cmd_login のテストを並べる。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(PLAN65): devbase scale の正常系の手順と範囲を固定する (#192)

cmd_scale の段階を分ける前の安全網。順序(グループの検査 → write_scale → ボリューム →
network → 生成 → default_services → 起動 → ready 待ち → bao → ./deploy)、bao と ./deploy の
範囲(current + 1 から new まで)、停止を呼ばないこと、受け付けない scale の扱いを固定する。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Test: characterize scale deploy failure and default login

Add current-behavior tests for continuing deployment after an instance failure and logging into instance 1 when arguments are omitted. Production code is unchanged.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default

* Test: characterization test for cmd_scale branch — lib/devbase/commands/container.py#cmd_scale

cmd_scale に明示的な project_name が渡された場合の分岐を固定する現状固定テストを追加。

Item-Id: R1-003
Round: 1
Impl-Runtime: agy
Impl-Model: default

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: #192 の実装 2 本目(cmd_scale の段階を分ける)を始める

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN65): 実装 2 本目の計画を置く (#192)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(PLAN65): cmd_scale の前提の検査を _check_scale_request へ出す (#192)

new_scale の 1 未満・現在以下の判定とログを関数へ移す(設計の決定 8)。
文言と出し分けは変えない。契約のテストを足し、既存の現状固定テストは書き換えない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(PLAN65): cmd_scale の [1/5]〜[5/5] を _run_scale_pipeline へ出す (#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>

* docs(PLAN65): 実装 2 本目の計画の受け入れ条件に結果を記す (#192)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* style(PLAN65): cmd_scale の空行と折り返しを元へ戻し、D-3 の行数の判断を記す (#192)

40 行に届かせるために削った空行・1 行へ詰めた文・短くしたコメントを、抽出前の書式へ戻した。
振る舞いは変えない。D-3 の意図(段階の命名と cmd_up との形の一致)は満たし、行数は
要求の数え方で 51 行になる。数字のために読みやすさを犠牲にしない判断を要求の文書と計画に記した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Test: characterize cmd_scale error paths

Preserve configuration and subprocess side effects on target resolution and readiness failures.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default

* Test: characterize cmd_scale default scale handling

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(PLAN66): 名前の形の知らせ(実装 1 本目)の作業を始める

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): 実装 1 本目(知らせ)の計画を置く

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(PLAN66): プラグインの同期が名前の形に合わない名前を projects/ に載せる直前に知らせる

symlink は今と同じく張り、戻り値も変えない(決定 1)。検査は winner の symlink の直前・
別名の symlink の直前・実ディレクトリの採取の直後の 3 か所に置き、discover_projects と
_collect_project_candidates には置かない(決定 2)。別名の案内は元の名前と <owner> の
どちらが原因かで分ける。名前の形の説明文は utils/names.NAME_FORM_HINT に置く(決定 7)。

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(PLAN66): env import が名前の形に合わないプロジェクト名を取り込むとき保存先に応じて知らせる

import は今と同じく通し、書庫の名前の規則(_PROJECT_ENV_RE)も変えない(決定 4)。
知らせは _build_plans の直後、--dry-run の判定より前に出す。平文の projects/<name>/.env
では作ることと改名の案内を、age・サーバ backend では保存先を名指しして projects/ に
何も作らないことを書く。env/secret_store.py は触らない。

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): 確定仕様の「運用」と CHANGELOG に名前の形の知らせを書く

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Test: characterize project name extraction, server import, and sync aliases

Add characterization coverage for R1-001, R1-002, and R1-003 without changing production code.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default

* fix(PLAN66): projects/ 直下の . 始まりの実ディレクトリに名前の形の警告を出さない

sync_projects の実ディレクトリの知らせが .vscode などにも出ていた。
決定 8 のとおり . 始まりはプロジェクトとして扱わず、知らせも出さない。
回帰テスト test_dot_real_directories_are_not_warned を追加。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(PLAN66): スナップショットの名前の寄せ(実装 2 本目)の作業を始める

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): 実装 2 本目の計画を置いた

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(PLAN66): スナップショットの名前の検証を utils/names の述語へ寄せる

_VALID_NAME_RE を消し、_validate_name が is_single_segment_name を呼ぶ(決定 5)。
例外の型・文言・_safe_snap_dir の封じ込めは変えない。狭まるのは末尾の改行を持つ名前だけ。
tests/snapshot/test_manager_name.py で受理 4 件・拒否 8 件を固定する(決定 6)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(PLAN66): 確定仕様の「運用」の 2 つ目と CHANGELOG の Changed を書いた

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Test: characterize invalid snapshot name rejection in create

Fix current public-entry behavior before directory creation or Docker execution.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default

* Test: characterize invalid snapshot name rejection in delete

Fix current public-entry behavior before directory deletion or rmtree execution.

Item-Id: R1-002
Round: 1
Impl-Runtime: agy
Impl-Model: default

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(PLAN64): 実装の作業場所を用意する (#188)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(PLAN64): 機密の参照の見出しにグループの読み替えの前後を出す (#188)

SecretRef.label() にキーワード引数 group_display を足し、見出し用の表示を作る口を
SecretStore.display_label(ref) の 1 つに置いた。読み替えの要否は storage_group が
決める (backend の種類・設定の有無・layout・グループの有無をまとめて見る唯一の判定)。

label() の既定の返り値は変えていない。読み替えの解決は BackendConfigError を送出
しうるため、43 か所のエラー文言・警告・ログを巻き込まない。

見出しの呼び出し 5 か所 (env list の節の見出しと件数の行・env backend test の参照
ごとの行・env backend migrate の計画の一覧と --to age の完了後の一覧) を display_label
へ寄せた。読み替えの対応が無いグループ・version: 1・ファイル backend の出力と、
env backend status の表示は変わらない。

確定仕様の相反する 2 つの記述を、文言の種類で分ける形に書き分けた。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test: characterize backend probe and flat layout labels

Add characterization tests for current-group probe headings, skipped project aliases, and grouped references on a flat layout.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default

* test: characterize project references in the migration plan and display_label

Add characterization tests for the project heading in the migration plan
listing and for project / personal-project references passed to
SecretStore.display_label.

Item-Id: R1-002
Item-Id: R1-005
Round: 1
Impl-Runtime: agy
Impl-Model: default

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

* test: characterize the migration plan listing towards openbao

Fix the headings of the reverse direction (age -> openbao) of
`env backend migrate --dry-run`, where the aliased group name and the
destination path have to name the same group on one line.

Item-Id: R1-003
Round: 1
Impl-Runtime: claude
Impl-Model: claude-opus-5

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

* Refactor: consolidate_duplication — lib/devbase/env/secret_store.py#SecretStore.mode

SecretStore.mode が backend_for と同じ backend の選択・存在判定・衝突検出を
重複して持っていたため、backend_for の結果の exists で判定する形にまとめた。

あわせて extract_method — lib/devbase/commands/env_backend.py#_MigrationPlan.apply:
書き込み後の読み戻し検証ループを _verify_read_back へ抽出した (R2-002)。

Item-Id: R2-001
Round: 2
Impl-Runtime: claude
Impl-Model: default
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Revert "Refactor: consolidate_duplication — lib/devbase/env/secret_store.py#SecretStore.mode"

This reverts commit cd75e0e.

構造改善の提案 R2-001 / R2-002 は、この Pull Request の差分の外
(`SecretStore.mode` と `_MigrationPlan.apply` の読み戻し検証) を指していた。
R2-001 は `mode` の分岐を `backend_for` へ寄せており、見出しの表示だけを変える
この変更の範囲を越えて振る舞いに触れうる。範囲外として取り消す。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
takemi-ohama and others added 2 commits September 23, 2026 05:23
* chore(PLAN63): base イメージの描画と文書の道具の実装の作業場所を用意する (#161, #160)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

* feat(PLAN63): base イメージの日本語の描画を直し、文書を扱う軽量の道具を足す (#161, #160)

`/etc/fonts/local.conf` を 1 つ置き、総称ファミリ (sans-serif / sans / serif /
monospace) と、イメージに無い書体名を Noto CJK の JP フェイスへ向ける。中国語・
韓国語の規則は総称ファミリを名指ししたときだけ効かせる (`<test name="family">`)。
この test を省くと `Arial:lang=zh-cn` から Liberation Sans を奪い、様式も崩れる。

conf.d/99-*.conf へ置くと `<alias><prefer>` が効かない。local.conf は
conf.d/51-local.conf 経由で読まれ、sans-serif を中国語フェイスへ向けている
64 / 65 より「先」になるためで、理由と実測は fonts-local.conf の先頭に残した。

あわせて 6 パッケージを 1 つ目の RUN の 1 回目の apt-get install へ足す。
poppler-utils / python3-pil / python3-defusedxml / python3-lxml と、欧文の
metric 互換の fonts-crosextra-carlito / fonts-crosextra-caladea である。
LibreOffice と pip は入れず、fonts-wqy-zenhei も消さない。

回帰テストは 2 段。Dockerfile と fonts-local.conf の形は Docker なしで、
fc-match の解決先は建てたイメージの中で固定する。後者はイメージが無い・古い
ときは skip する。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

* fix(PLAN63): probe の実行中の異常を skip でなく失敗として知らせる (#161)

docker run を包む except (SubprocessError, OSError) が TimeoutExpired まで
pytest.skip にしていたため、Docker もイメージもある状態で probe が 300 秒で
タイムアウトすると 39 件すべてが skip になり pytest が成功終了していた。

skip してよいのは Docker が使えない・イメージが無い (_docker_unavailable) と
イメージが古い (STALE_IMAGE_EXIT) の 3 つだけなので、docker run の try/except を
外して例外のまま失敗させる。意図はコメントで残す。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

* test(PLAN63): 新しい RUN の検査を RUN ブロック単位へ直す (#161)

`RUN ` で始まる行だけを集めていたため、各要素は `RUN set -eux; \` のような
1 行目だけになり、パッケージ名が入る継続行を見ていなかった。
`poppler-utils` / `fonts-crosextra` が無いという 2 つの assert は常に真で、
「6 パッケージのために RUN を足していない」という意図を固定できていなかった。

`_run_blocks()` を足して Dockerfile を RUN ブロック (行継続を含む 1 命令分) へ
分け、`_first_run_block()` はその 1 つ目を返す形に寄せた。検査は 1 つ目以外の
各ブロックの全文に対して行う。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…192, #203) (#240)

* docs(PLAN63): base イメージの文字の描画と文書の道具を確定仕様へ移す

新規の確定仕様 docs/specifications/base-image-rendering.md を置く。設定の置き場所を
/etc/fonts/local.conf から動かせない理由 (スロット 51 と <prefer> の prepend)、zh-cn / ko の
<match> が <test name="family"> を必ず持つ理由、未導入の書体の受け皿、fc-cache -f の位置の
制約、解決先の 26 行、入れないもの (LibreOffice / pip / ENV LANG / fonts-wqy-zenhei の削除)、
同梱する 6 パッケージ、派生イメージと稼働中コンテナへの伝播、テストの 2 段構成と skip の
4 段を書く。containers/lfm が対象外であること、確かめたのは fc-match の水準までで amd64 は
未確認であることは運用に残す。

docs/user/container-operations.md には devbase rebuild ではイメージが建て直らないこと
(build --expires=7 のシノニムで期限内はビルドを飛ばす) を足し、新規仕様へ相互リンクする。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

* docs(PLAN64, PLAN65, PLAN66): 残る決定と検証の観点を確定仕様へ移す

cli-argument-resolution.md (PLAN66): 構成要素の表へ plugin/syncer.py・env/io_import.py・
env/_import_merge.py・snapshot/manager.py の行を足し、utils/names.py へ NAME_FORM_HINT を
書き足す。仕様に「名前の形に合わない名前の知らせ」を置き、1 件 1 回の保証と検査の位置、
discover_projects に置かない理由、出所で 4 通りに分かれる案内、--dry-run でも出すこと、
保存先で文が分かれる理由を書く。運用の側は結果の要約にとどめて小節へリンクし、知らせが
同期のたびに毎回出ることを足す。テスト観点へ同期・import・age の保存先・スナップショットの
名前のテストを足す。

secret-backend.md (PLAN64): テスト観点へ test_secret_store_label.py と
test_env_group_label.py が固定している 5 点を足す。

compose-profiles.md (PLAN65): devbase scale の段落へ _previous_scale_compose を入れない
理由を 1 文足す。

CHANGELOG.md: Unreleased の Changed へ、devbase scale が端末や .env の COMPOSE_PROFILES を
見なくなる旨を足す。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@takemi-ohama takemi-ohama mentioned this pull request Sep 22, 2026
4 tasks
- CHANGELOG の [Unreleased] を [3.7.0] - 2026-09-23 として確定し、比較リンクを足す
- pyproject.toml / lib/devbase/__init__.py / lib/devbase/cli.py / uv.lock /
  architecture.md の版数を 3.7.0 にする


Claude-Session: https://claude.ai/code/session_011Vu8hNTZKeDeXVLg8hYuK8

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@takemi-ohama

Copy link
Copy Markdown
Contributor Author

本文の「配布の記録」は承認待ちの時点で書いたもので、段階: 検証(…承認待ちのため未実施)
のまま残っている。配布は 2026-09-23 に利用者の承認を得て実施済みのため、
実施後の値で記録を更新する。以下が最新の「配布の記録」である。

配布の記録

段階: 本番(検証のチャネルが無いため main へのマージが本番への配布にあたる。利用者の承認を 2026-09-23 に得て、同日 07:52 JST にマージ実施。マージコミット fd5fa48)
版: 3.6.0 → 3.7.0(MINOR: 後方互換のある追加と、確定仕様に合わせた scale の是正)
まとまり: PR #213 / #217 / #221 / #223 / #225 / #230 / #231 / #232 / #233 / #235 / #237 / #238 / #240 / #241

@takemi-ohama

takemi-ohama commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

リリース後テスト

対象の版: 3.7.0(2026-09-23 07:52 JST に main へマージ、fd5fa48)
導入経路: 主ディレクトリ /Users/takemi_ohama/devbase で git pull --ff-only(83d6625 → fd5fa48)。
利用者が devbase を更新するのと同じ経路で、作業ツリーは使っていない。
実行環境: macOS 25.6.0 / Apple Silicon(arm64)、実環境の OpenBao(version: 2 / layout: group / group_aliases: {default: nyle})。
書き込みの操作(env set / migrate / backend の切り替え / up / scale / login / プラグインの同期)は行っていない。

#161 / #160 の変更は、git pull だけでは利用者に届かない。 containers/base/Dockerfile の
変更のため、各利用者が devbase build base --no-cache を打った時点で初めて反映される
(CHANGELOG の [3.7.0] にも明記。派生イメージを使うプロジェクトは、その派生イメージも
建て直す必要がある)。この確認で使った devbase-base:latest は実装時に建てた同内容の
イメージで、/etc/fonts/local.conf の sha256 が配布物と一致することを確かめている。
「配布が終わった」ことと「利用者の手元で有効になった」ことは、この 2 課題では別である。

課題 受け入れ条件 実行したこと 実行時刻 結果
#161 1-4. sans / sans-serif / serif / monospace と lang=ja が Noto Sans(Serif/Mono) CJK JP を返し、Noto Sans JP / Meiryo / Yu Gothic / MS PGothic / 未導入の Zen Kaku Gothic New もすべて JP へ落ちる docker run --rm --entrypoint bash devbase-base:latest -lc 'fc-match <25 パターン>'(使い捨てのコンテナ) 2026-09-23 07:58 合格 / 該当 9 パターンすべて Noto Sans CJK JP 系
#161 5. 欧文が壊れない(Arial→Liberation Sans、Times New Roman→Liberation Serif、Courier New→Liberation Mono) 同上 2026-09-23 07:58 合格
#161 6. 他言語が壊れない(serif:lang=zh-cn→Noto Serif CJK SC、sans-serif:lang=ko→CJK KR、Arial:lang=zh-cn→Liberation Sans、WenQuanYi Zen Hei / IPAPGothic の名指しは残る) 同上 2026-09-23 07:58 合格 / issue 本文が「検証済み」としていた設定が壊す形だった 2 件(serif:lang=zh-cn / Arial:lang=zh-cn)を含めて確認
#161 7-8. 設定は /etc/fonts/local.conf にのみ置き conf.d/ には 1 つも置かない ls /etc/fonts/conf.d/ | grep -iE '99-|local' → 51-local.conf(OS 既定)のみ。sha256sum /etc/fonts/local.conf が containers/base/fonts-local.conf と一致(e8902e66…) 2026-09-23 07:57 合格
#161 描画そのもの(fc-match の水準より先。引き継ぎの未確認 5 件目) 使い捨てのコンテナで PIL(#160 が足した python3-pil)により「直骨海類様今対」を 3 通り描画し画素比較 — sans-serif と Noto Sans CJK JP が完全一致、Noto Sans CJK SC とは差あり(bbox 12,30-448,92)。生成した比較画像を目視し、JP の字形であることを確認 2026-09-23 08:01 合格
#161 14. uv run --locked pytest tests/ -q が exit 0 同コマンド(tests/containers/ の 193 件を含む。skip 0 件) 2026-09-23 08:00 合格 / 3022 passed in 133.61s exit=0
#161 15. devbase build base --no-cache が arm64 で成功する — — 保留(イメージの再ビルドは行わない判断。手元の devbase-base:latest は実装時(2026-09-23 04:16)のビルドで、/etc/fonts/local.conf の sha256 が配布物と一致するため中身は配布した版と同一。main からの新規ビルドの成否は #242 で amd64 と併せて確かめる)
#161 16. 派生イメージ(containers/general など)を建て直すと同じ解決先になる 使い捨ての 1 層のイメージ(FROM devbase-base:latest + RUN true)を建て、fc-match 6 パターンを実行。確認後にイメージを削除 2026-09-23 08:47 合格 / base と同一(sans-serif→Noto Sans CJK JP、Calibri→Carlito、serif:lang=zh-cn→Noto Serif CJK SC)。/etc/fonts/local.conf は base の層から継承する
#160 9. pdftoppm / pdfinfo / pdffonts / pdftocairo が PATH にある 使い捨てのコンテナで command -v 2026-09-23 07:57 合格 / 4 件すべて /usr/bin/
#160 10. python3 -c "import PIL, defusedxml, lxml" が exit 0 同上 2026-09-23 07:57 合格 / PIL 12.1.1 / lxml 6.0.2
#160 11. fc-match Calibri→Carlito、fc-match Cambria→Caladea 同上 2026-09-23 07:58 合格
#160 12. soffice / libreoffice / pip / pip3 が PATH に無く、uv はある 同上 2026-09-23 07:57 合格 / soffice なし
#160 13. イメージ増分が base(7.09GB)に対し +0.5% 未満 使い捨てのコンテナで dpkg-query -W -f='${Installed-Size}' により指定した 6 パッケージの導入後サイズを測定(依存は含まない) 2026-09-23 08:55 保留(合否はビルド前後の docker images の差分で決めるため。参考値として 6 パッケージの合計は 11.8 MB(lxml 5.6 / carlito 2.6 / pil 2.1 / poppler-utils 1.2 / caladea 0.3 / defusedxml 0.1 MB)で、issue の見積り「展開 約24 MB(依存込み 24 パッケージ)」と矛盾しない。#242 で確かめる)
#188 1. env backend test の見出しが グローバル(グループ default → nyle) devbase env backend test(読み取りのみ。実環境の OpenBao) 2026-09-23 07:56 合格 / 読めた参照 74 件、全行が (グループ default → nyle)、隣のパスは devbase/team/nyle/global のまま
#188 2. env list の === グローバル(グループ default → nyle) === と末尾の件数行 devbase env list(読み取りのみ) 2026-09-23 07:56 合格 / 見出し・件数行ともに読み替え後を出す
#188 8. env backend status の グループ: default → nyle が従来どおり devbase env backend status(読み取りのみ) 2026-09-23 07:55 合格
#188 3-7, 12. migrate の 2 経路 / 読み替えの無いグループ / version: 1 / ファイル backend / エラー文言は読み替え前 / pytest uv run --locked pytest tests/ -q(tests/env/・tests/commands/test_env_group_label.py を含む)と main の CI(run 35794620399、fd5fa48) 2026-09-23 08:00 合格 / 実環境での migrate は書き込みのため実行していない(単体テストと CI で代替)
#188 9-11. 確定仕様と利用者向け文書に読み替えのある例が載る docs/specifications/secret-backend.md:285,308-310,355-356 / docs/user/env-backend.md:373 / docs/user/cli-reference/03-env.md:78,412 を読む 2026-09-23 08:06 合格
#192 A-1. lib/ で compose_env() を渡さずに docker compose を起動する箇所が 0 件 grep -rn "docker.*compose" lib/ --include=*.py で起動点を洗い出し 2026-09-23 08:00 合格 / 起動点は 3 か所(utils/docker.py:56 / commands/container.py:266 / editor/opener.py:396)で、いずれも env=compose_env() を渡す
#192 D-1. docker compose config --format json の起動箇所が 1 か所 grep -rn "'config', '--format', 'json'" lib/ 2026-09-23 08:00 合格 / 1 件(commands/container.py:2003、docker_compose 経由)
#192 C-1. 正常系の順序を固定するテストがある(grep -rn "no-recreate" tests/ が 1 件以上) 同 grep 2026-09-23 08:00 合格 / 3 件
#192 D-3. cmd_scale 本体が 40 行以下 ast で本体の範囲を測定 2026-09-23 08:06 合格 / 本体 49 行・空行を除くと 39 行(cmd_up は 67 / 52)。受け入れ条件の数字に合わせるために空行を削る操作は実装レビューで差し戻し済みで、現在の形は意図を採った結果である
#192 B-1〜B-5 / C-2〜C-4 / E-1〜E-3. COMPOSE_PROFILES=__devbase_none__ / コマンド列 / 段階の順序 / up の不変 uv run --locked pytest tests/ -q と main の CI 2026-09-23 08:00 合格 / 3022 passed exit=0。実環境のプロジェクトでの scale は影響が大きいため実行していない(単体テストで代替)
#195 12-15. compose-profiles.md の devbase 行が 3.5.0 以上、requires.devbase を ">=3.5.0" へ上げる手順があり、plugin-yml-reference.md の「上げる契機」に profiles: が挙がり、相互リンクする docs/plugin-dev/compose-profiles.md:10,46-61 / docs/plugin-dev/plugin-yml-reference.md:172-178 を読む 2026-09-23 08:03 合格
#203 1-11, 15-17. sync_projects / env import / --dry-run / 名前衝突 / スナップショット名の 8 件の拒否と 4 件の許可 uv run --locked pytest tests/ -q(tests/plugin/test_repos_core.py / tests/env/test_io_import.py / tests/cli/test_env_bundle_backend.py / tests/snapshot/test_manager_name.py)と main の CI 2026-09-23 08:00 合格
#203 12. _VALID_NAME_RE が lib/ に残っていない grep -rn "_VALID_NAME_RE" lib/ 2026-09-23 08:00 合格 / 0 件
#203 13-14. cli-argument-resolution.md の「運用」3 点と CHANGELOG 両ファイルを読む 2026-09-23 08:03 合格
#208 10. argparse の集合と文書の列挙が完全一致 lib/devbase/cli.py の _create_parser() を再帰走査して [name] / --context を取るサブコマンドを列挙し、文書 8 か所と突き合わせ 2026-09-23 08:02 合格 / [name]: up down ps logs scale rebuild open(+ profile up/down/list)、--context: 同じ集合 + login / build / env exec / env token。差分なし
#208 1-9, 11. 文書 8 か所の列挙に rebuild / open(と env token)が入り、触らないと決めた 2 か所が不変 docs/user/cli-reference/02-project.md:9,23,67 / README.md:8,25,64 / container-operations.md:8 / compose-profiles.md:216 / remote-docker-context.md:43-46 / environment-variables.md:316,371 を読む 2026-09-23 08:02 合格
#209 1. tests/conftest.py の autouse fixture が DEVBASE_ROOT をテストごとの tmp へ setenv する tests/conftest.py:323-342 を読む 2026-09-23 08:01 合格 / _isolate_devbase_root が tmp_path_factory.mktemp('devbase-root') を setenv
#209 2. DEVBASE_ROOT の有無で pytest の結果が変わらない 3 通りで uv run --locked pytest tests/ -q を実行(継承したまま / env -u DEVBASE_ROOT / DEVBASE_ROOT=<空の偽 root>) 2026-09-23 08:00-08:05 合格 / 3 回とも 3022 passed / exit=0(133.61s / 129.39s / 130.98s)
#209 5. uvx ruff check --select=E9,F63,F7,F82 tests/conftest.py lib が exit 0 同コマンド 2026-09-23 08:06 合格 / All checks passed!
#161 #160 #188 #192 #195 #203 #208 #209 個別 PR では CI が 1 件も動いていなかった(#216)。main へのマージで CI が動いたことを確かめる gh api repos/devbasex/devbase/commits/fd5fa48/check-runs 2026-09-23 07:54 合格 / 7 件すべて success(Ruff lint / ShellCheck / Python syntax 3.10-3.12 / Pytest 3.10・3.13)。run 35794620399、2026-09-22T22:52:16Z 開始
#161 #160 #188 #192 #195 #203 #208 #209 配布した版が利用者の経路で入ること git pull --ff-only 後に bin/devbase --version、devbase project up/scale/login/rebuild/open --help 2026-09-23 07:53-07:55 合格 / devbase 3.7.0、読み取りだけの経路は 5 つとも exit=0

合否: 合格(表の 34 行中 32 行を実施、2 行は保留)

保留の 2 行は、いずれも base イメージの再ビルドを要するもの(#161 の 15、#160 の 13)である。
条件 16(派生イメージ)は、使い捨ての 1 層のイメージで踏めたため合格へ改めた(local.conf は
base の層にあり、FROM devbase-base:latest はそれを継承する)。
この端末(arm64)で再ビルドしても、引き継がれた未確認の 1 件目「amd64 は未検証」は解けないため、
再ビルドを伴う確認は amd64 の実機での確認とまとめて #242 で扱う。
手元の devbase-base:latest は実装時のビルドだが、/etc/fonts/local.conf の sha256 が配布物と
一致し、6 パッケージの導入も確認できているため、配布した版の中身を確かめたことにはなっている。

起票したもの:

@takemi-ohama

takemi-ohama commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

振り返り(2026-09-23)

対象: マイルストーン v3.7.0 の 8 課題 — #161 / #160 / #188 / #192 / #195 / #203 / #208 / #209
(配布: PR #212、main = fd5fa48、3.6.0 → 3.7.0)

base イメージの日本語の描画を直して文書を扱う軽量の道具を足し(#161 / #160)、機密の見出しに
グループの読み替えを出し(#188)、devbase scale と devbase login を Compose の共通経路へ
寄せ(#192)、プロジェクト名の検証の規則を 1 つに寄せ(#203)、文書 8 か所の列挙と
requires.devbase の手順を揃え(#195 / #208)、pytest が実環境の DEVBASE_ROOT を継承する
穴を塞いだ(#209)。6 束・12 本の個別 Pull Request に、確定仕様化 #240 と版上げ #241 を足して
通した。3 層(conductor / supervisor / worker)で、承認は配布の 1 回だけに絞って運用した。

何が起きたか

課題本文の「実測」が 4 束すべてで誤っていた

設計の束 4 つすべてで、issue 本文に実測として書かれた値が誤っていた。 誤りの種類は
4 件とも違う。

課題 本文の記述 実際 気づいた工程
#161 「直し方(検証済み)」として fontconfig の設定を全文掲載 その設定は serif:lang=zh-cn と Arial:lang=zh-cn を壊す 設計
#188 「差し替えるのは 2 か所で足りる」 5 か所 設計
#192 compose_env() が適用されないのは cmd_scale cmd_login にも適用されていなかった 設計
#203 「syncer が唯一の入口」 env import も projects/ にディレクトリを作る 設計

共通するのは、起票の時点の調査が「症状を再現するところまで」で止まり、修正の範囲までは
確かめていない
という形である。4 件とも設計の持ち場が入力として読んだ時点で崩れたため、
配布までは届かなかった。#161 は「検証済み」と明記された設定をそのまま採っていれば、
日本語を直して中国語を壊す形で配布されていた。

輪番の収束が 1 ラウンドでは足りなかった

ラウンド 1 の収束をそのまま信じていたら見逃していた指摘が複数あった。 3 者輪番では、
ラウンド 1 で外れた担当がその束を一度も見ていない状態で「新しい指摘が出なかった」に
なりうる。最後の束では、ラウンド 2 で codex が次の 2 件を見つけた。

  • Docker が要るテスト 39 件が、probe の時間切れで全部 skip されても pytest が成功で終わる
  • Dockerfile の形を固定する assert 2 つが常に真

どちらも「テストがある」という証跡そのものを無効にする穴で、ラウンド 1 の 2 者は指摘して
いない。今回のリリース後テストでは、この端末で uv run --locked pytest tests/ -q が
skip 0 件・3022 passed(tests/containers/ の 193 件を含む)で終わることを確かめており、
塞がったことを実環境で確認できている。

個別の Pull Request には CI が 1 件も当たっていなかった

.github/workflows/ci.yml の on.pull_request.branches が main だけで、12 本の個別
Pull Request は base が release/v3.7.0 だったため、CI が 1 件も起動しなかった(#216)。
gh pr checks の no checks reported は「通った」を意味しないが、束の中身に CI が当たったのは
release PR が初めてだった。12 本の証跡はすべて手元の実行である。

main へのマージで CI は動き、7 件すべて success(run 35794620399、fd5fa48)だったため
結果的に退行は無かった。当たらなかったこと自体は運用の穴として残る。

ただし、束の中身がまったく検査されていなかったわけではない。 release PR #212 は束の
最初(2026-09-21T20:40Z)に開いており、release/v3.7.0 へ何かがマージされるたびに
#212 の pull_request として CI が走っていた(15 回、すべて success)。
つまりマージ後の結果は連続して検査されていたが、個別の Pull Request の head は
マージ前に一度も検査されなかった。
落ちたのは「その変更を取り込んでよいか」を
取り込む前に見る機会であって、束全体の健全性ではない。#216 の影響はこの範囲である。

構造改善が Pull Request の外を指し続けた

cross-refactoring の --scope がファイル単位で、Pull Request の差分に絞らない。
最後の束では提案 5 件すべてが、その Pull Request が触っていないファイルを指した。
却下と driver の停止を繰り返し、agy が適用で結果を残さないまま同じ群を開き直す無限ループも
起きた。最終的に、利用者の操作で構造改善を打ち切る判断を受けた。

既存の課題(devbasex/ai-plugins#622)が同じ形を指している。

受け入れ条件の数字が、意図に反する満たし方を誘発した

#192 の D-3(cmd_scale 本体が 40 行以下)で、数字に合わせるために空行を削り 2 文を 1 行に
詰めた
担当がいた。検査で元に戻し、数字より意図を採った。

配布した main での実測は cmd_scale が本体 49 行・空行を除くと 39 行(cmd_up は
67 / 52)で、素直に段階を抽出すれば数字は自然に満たされていた。 詰める操作は要らなかった。

並行度を測れず、32 GiB の端末で 1 本に抑えた

parallel-measure.py capacity が macOS で /proc/meminfo を読めず終了コード 3(測れない)を
返した。規約どおり「起動してよい本数 1」として 6 束を順に通した。
実行計画の「測った値」は 14 行あり、14 行すべてが 測れない(exit 3 / macOS) で、
空き・cgroup の残り・スワップ・oom_kill の 4 つの列も全行「測れない」である。
同時に動いていた本数は 0 か 1 にとどまった。32 GiB の端末で
1 本に抑えたことの是非は論点として残る。束のあいだには依存があり(確定仕様化は全束の後)、
仮に 2 本動かせても短縮できたのは中盤の 2 束に限られる。既存の課題
(devbasex/ai-plugins#780)が原因を指している。

中断と 3 層の運用

  • 利用上限(429)で 2 回中断し、記録(ending: rate_limit / resets_passed)から再開した。
    記録から再開できており、進行そのものは失われていない
  • 利用者の操作で 1 回停止し、構造改善を打ち切る判断を受けた
  • supervisor が待ちの途中で応答を終えた例が 1 件(規則 4 違反)。conductor が SendMessage で
    続けさせた(1 回)

配布の記録が承認待ちの値のまま残っていた

PR #212 の本文の「配布の記録」が 段階: 検証(…承認待ちのため未実施) のままだった。
配布は承認を得て実施済みで、progress-tracking の「まとまりを閉じる」はこの行だけを読むため、
そのままでは 8 課題すべてが 開いたまま(本番への配布の前) になる。 仕上げの持ち場が
更新した記録をコメントで投稿して回避した。

「別途起票する」と書いた宿題が 6 件、番号を持たないまま残っていた

振り返りの段 1(起票の取りこぼしを拾う)で、範囲外と判断しながら番号が付いていない項目が
6 件見つかった。
15 本の Pull Request の本文・レビューコメントと、PLAN63〜PLAN66 の 14 本の
計画文書の「含まない」「目的と非目的」「未確認のまま残ること」を、由来で引いた課題の一覧と
突き合わせた結果である。

項目 どこに書かれていたか 起票
containers/lfm が #161 と同じ状態かは未調査(base 由来でないため直しが届かない) PLAN63 の 3 か所に「抱えていれば別途起票する」 #243
一覧の桁揃えが全角文字で崩れる PLAN64 の設計に「この変更とは別の課題である」 #244
secret_store の書き込みの経路に名前の形の知らせが届かない PLAN66 の設計に「G4 の束が同じファイルを触るため触らない」 #245
devbase scale の実環境での確認が最後まで未了 PLAN65・PR #231 / #232・PR #212 の Test plan の未チェック行 #246
名前の形の知らせがパイプ越しに見えるかの実機確認 PLAN66 の設計に「リリース後テストで見る」 #246 に含めた
shellcheck bin/devbase の既存 8 件 PR #213 の「未検証の項目 / 既存の失敗」 #247

3 件は同じ形で落ちていた。 計画・設計に「別途起票する」「別の課題である」と書きながら
番号を付けず、確定仕様化の工程で理由だけが残って宿題そのものが消えた。
containers/lfm は docs/specifications/base-image-rendering.md:250-251 に「対象外である」
とだけ残っており、調べた上で対象外にしたように読める。 実際は未調査である。

拾えたのは計画ファイルが issues/old/ に残っていたからで、確定仕様だけを読んでいたら
拾えなかった。

同じ束から出た Target.label のデッドコードは #222 として起票されているのに、隣の行の
桁揃えには番号が無い、という揺れもあった。判断(範囲外である)は行われており、
起票という操作だけが落ちている。

context window の大きさ

skill-stats.py --agents --session <このまとまりのセッション> の測定値である。
仕上げの持ち場は測定の時点で進行中のため、その行は途中の値を含む。

層 持ち場 モデル 件数 固定費の中央値 実作業の中央値 実作業 < 固定費 最大充填の最大 印
conductor - claude-opus-5 1 32023 418120 0 450143 割る候補
supervisor 設計 claude-opus-5 4 33879 318388 0 453327 割る候補
supervisor 実装 claude-opus-5 8 33272 116104 0 205986 割る候補
supervisor 検査 claude-opus-5 9 33319 121335 0 227804 割る候補
supervisor 取り込み claude-opus-5 1 34073 279865 0 313938 割る候補
supervisor 仕上げ claude-opus-5 1 33528 119949 0 153477
worker 調査 claude-opus-5 7 15553 62444 0 195618
worker 修正 claude-opus-5 22 32248 18770 20 150403
worker 検証 claude-opus-5 6 30859 8938 6 42526
worker 検証 claude-sonnet-5 1 35609 7460 1 43069

束ねの表から外した記録: 1 件(応答が 3 に満たない)

層 件数 固定費の合計 実作業の合計 総消費
conductor 1 32023 418120 450143
supervisor 23 768425 3838698 4607123
worker 37 1122725 1104367 2227092
合計 61 1923173 5361185 7284358
持ち場 supervisor supervisor の実作業 worker の件数 supervisor と worker の固定費の合計 印
設計 1 327873 9 310567
設計 2 290157 6 209216
設計 3 308903 1 49228
設計 4 419705 6 209195
検査 1 115484 1 63600
検査 2 94814 1 63891
検査 6 89467 2 94499 worker を使いすぎ
検査 7 131637 1 63959
検査 8 194485 2 95003
検査 9 185786 3 127968
取り込み 1 279865 3 141615
仕上げ 1 119949 2 94999

印ごとの判断

行 判断 理由
conductor(割る候補) そのまま まとまり全体を 1 本で通す設計で、6 束・12 本の対応関係を持ち続けるのが役目である。割ると引き継ぎの費用が実作業を上回る。ただし実作業 418120 / 最大充填 450143 は余裕が小さく、束が 8 以上のまとまりでは束ごとにセッションを分ける余地がある
supervisor 設計(割る候補) 割る 4 件中 2 件が実作業 290000 超、最大 453327 で、supervisor の中で突出している。設計の持ち場は「要求と受け入れ条件 → 設計 → ドキュメント再構成 → ドキュメントレビュー」の 4 工程を 1 本で通している。文書の工程(再構成・レビュー)を別の持ち場へ割るのが自然な切れ目である
supervisor 実装 / 検査(割る候補) そのまま 8 件・9 件と数が多く、実作業の中央値は 116104 / 121335 で最大充填も 227804 に収まる。既に束ごとに 1 本で、これ以上割ると束と持ち場の対応が読めなくなる。印は中央値ではなく最大の行に引かれている
supervisor 取り込み(割る候補) そのまま 1 件で、12 本の Pull Request のマージと後片付けをまとめて行う持ち場である。実作業 279865 は内容に見合う
検査 6(worker を使いすぎ) worker を減らす supervisor の実作業 89467 に対し、supervisor と worker 2 件の固定費の合計が 94499 で、固定費が実作業を上回っている。この規模の検査は supervisor が直接読むほうが安い
worker 修正(22 件中 20 件で実作業 < 固定費) 固定費を下げる 修正 worker の固定費の中央値 32248 に対し、実作業の中央値は 18770 である。worker 層の固定費の合計 1122725 は総消費 7284358 の 15.4% を占め、worker 層では固定費(1122725)が実作業(1104367)をわずかに上回った。持ち場で要る手順だけを渡す改善が効く(devbasex/ai-plugins#828)
worker 調査(印なし) そのまま 固定費の中央値 15553 が他の持ち場の半分で、実作業の中央値 62444 がそれを大きく上回る。読み取りだけの調査は worker へ出すのが最も効いている

次に変えること

変えること 落とし先 状態
課題本文の「実測」を計画に入る前に 1 つずつ踏み直し、食い違いを issue へ戻す requirements-design / implementation-plan の手順 devbasex/ai-plugins#838 として起票
配布を実施した直後に「配布の記録」を実施後の値へ更新する段を足す release の手順 devbasex/ai-plugins#837 として起票
数値の受け入れ条件に「その数字が何の代理か」と「認めない満たし方」を添える requirements-design の手順 devbasex/ai-plugins#839 として起票
「未確認のまま残ること」に番号を付けてから確定仕様へ移す(確定仕様化の時点で起票を強制する) plan-to-spec の手順 devbasex/ai-plugins#840 として起票
release ブランチを base にした Pull Request にも CI を当てる プロジェクトの取り決め(.github/workflows/ci.yml の on.pull_request.branches) #216 として起票済み
母集合の 3 者のうち 1 者も見ていない担当がいる間は収束にしない cross-review の手順 devbasex/ai-plugins#631 として起票済み
--scope を Pull Request の差分に絞る cross-refactoring の手順 devbasex/ai-plugins#622 として起票済み
並行度が測れないホストで「起動してよい本数 1」に落ちる原因を直す parallel-measure.py capacity devbasex/ai-plugins#780 として起票済み
worker へ Skill 本文を丸ごと渡さず、持ち場で要る手順だけを渡す サブエージェントの起動 devbasex/ai-plugins#828 として起票済み
リリース後テストで保留にした受け入れ条件を、後から合格へ改める手順を作る release-verification / progress-tracking の手順 devbasex/ai-plugins#775 として起票済み
base イメージの v3.7.0 の変更を amd64 の実機で確かめる 次の変更で試すこと #242 として起票
設計の持ち場を、文書の工程(ドキュメント再構成・ドキュメントレビュー)で割る 3 層の運用(conductor の持ち場の切り方) 次のまとまりで試す。測定で唯一「割る候補」が実質的に当たった行である(4 件中 2 件が実作業 290000 超、最大充填 453327)
検査の持ち場で worker を 1 件までにする 同上 次のまとまりで試す。検査 6 は supervisor と worker の固定費の合計(94499)が supervisor の実作業(89467)を上回った
supervisor が待ちの途中で応答を終えない(規則 4) 変えない 規則は既に書かれており、conductor の SendMessage で復帰できた。23 件中 1 件で、手順を足すより運用で足りる
並行度 1 で 6 束を順に通したこと 変えない 束のあいだに依存があり(確定仕様化は全束の後、版上げはその後)、2 本動かせても短縮できたのは中盤の 2 束に限られる。測れないときに 1 へ落ちる規約そのものは妥当で、直す対象は測定の側(ai-plugins#780)である

途中で起票した課題

工程の中で起票したもの(16 件)

番号 何を見つけたか 見つけた場面
#214 [name] / --context の列挙の正本を一元化し、argparse と文書の一致をテストで固定する PR #213 の実装中(#208 の恒久策)
#215 「devbase の機能 ↔ 必要な最低版数」の一覧表と、新機能の PR で 1 行足す運用 PR #213 の実装中(#195 の恒久策)
#216 リリースブランチ宛の Pull Request で CI が 1 件も動かない PR #213 の完了判定中(gh pr checks が no checks reported)
#218 DEVBASE_ROOT 以外の 8 つの環境変数がテストで隔離されていない PR #217 の実装中
#219 Office 文書を画像へ描画する経路を base の外へ(containers/docs の新設) PR #221 の設計中
#220 base が Playwright のブラウザを取得直後に捨て、arm64 に動く Chromium が入らない PR #221 の設計中(#161 の原因を辿る過程)
#222 env_migrate.Target.label に消費側が無い(デッドコード) PR #223 の設計中(SecretRef.label() 52 か所の棚卸し)
#224 devbase scale で増やしたインスタンスに _report_missing_repos / _apply_window_titles が行われない PR #225 の設計中
#226 plugin info が . 始まりのプロジェクトを除外せず、discover_projects と食い違う PR #230 の設計中
#227 env の書庫の名前の検証が末尾の改行を通す PR #230 の設計中
#228 衝突した別名の形が文書と実装で違う PR #230 の設計中
#229 名前の形の文言を utils/names.py の定数へ寄せる PR #230 の設計中(G5 の束が同じファイルを触るため先送り)
#234 tmux のセッションを名指しで attach・調査・終了できるようにする 束の実行中(Pull Request に紐付かない)
#239 containers/base のシェルの異常系と分岐が固定されていない PR #238 の構造改善中(差分の外を指した提案を却下して起票)
#242 base イメージの v3.7.0 の変更を amd64 で確かめる リリース後テスト(手元が arm64)
#248 スナップショットの世代がアカウントグループを跨ぐたびに増え、3 世代の保持枠を奪い合う 束の実行中(グループの違うプロジェクトを行き来したとき。Pull Request に紐付かない)

振り返りで拾って起票したもの(9 件)

番号 何を見つけたか 拾った場所
#243 containers/lfm が #161 と同じフォントの解決先かを確かめる PLAN63 の「別途起票する」
#244 env backend test / env list の桁揃えが全角文字で崩れる PLAN64 の「別の課題である」
#245 secret_store の書き込みの経路に名前の形の知らせが届かない PLAN66 の「この設計では触らない」
#246 v3.7.0 の devbase scale を実環境で確かめる(知らせの宛先も併せて) PR #231 / #232 / #212 の未チェック行
#247 shellcheck bin/devbase の既存 8 件と CI の severity PR #213 の「既存の失敗」
ai-plugins#837 承認前に書いた「配布の記録」が実施後に更新されない PR #212 の本文
ai-plugins#838 課題本文の「実測」を計画の前に踏み直す段が無い 4 束の手戻りの突き合わせ
ai-plugins#839 数値だけの受け入れ条件が、意図に反する満たし方を誘発する #192 の D-3 の差し戻し
ai-plugins#840 plan-to-spec で「未確認のまま残ること」が消え、宿題が失われる 上の 3 件に共通する形

起票しないと明記されたものは対象外である。 PR #231 の「範囲外と判断したもの(起票しない。
いずれも変更前と同じ挙動で不具合ではない)」、PR #217 の既存 32 か所の monkeypatch.setenv の
整理、PR #235 / #237 の cross-refactoring で差分の外・しきい値未満として却下された提案群、
PLAN63 の前提 2 / 7 / 8(fonts-wqy-zenhei の削除・ENV LANG・pip)がこれにあたる。
理由はいずれも計画か確定仕様に残っている。

起票済みの 25 件はいずれもマイルストーンが未設定で、v3.7.0 由来であることは本文の
## 由来 節にしか残っていない。
手入れの工程で拾う。

@takemi-ohama

Copy link
Copy Markdown
Contributor Author

実行計画: v3.7.0(マイルストーン 4 / 8 件)

状態: 閉じた
開始: 2026-09-22T00:00Z
oom_kill の起点: 測れない(macOS。/proc/meminfo が無い)

行

行 束 種類 課題 モード 触るファイルと節 確度 設計の依存 実装の依存 状態 Pull Request
G2-実装1 G2 実装 #208 #195 light docs/ 8 ファイル(列挙) 確定 なし なし マージ済み #213
G3-実装1 G3 実装 #209 light tests/conftest.py「autouse fixture」 確定 なし なし マージ済み #217
G1-設計 G1 設計 #161 #160 standard issues/PLAN63_* 確定 なし — マージ済み #221
G4-設計 G4 設計 #188 standard issues/PLAN64_* 確定 なし — マージ済み #223
G5-設計 G5 設計 #192 standard issues/PLAN65_* 確定 なし — マージ済み #225
G6-設計 G6 設計 #203 standard issues/PLAN66_* 確定 なし — マージ済み #230
G5-実装1 G5 実装 #192 standard docs/specifications/compose-profiles.md(経路の表・コマンド列の表・運用・テスト観点)、lib/devbase/commands/container.py「cmd_scale の [4/5]」「cmd_login」「_resolve_dev_service」「_read_compose_services」「_ensure_images」、tests/commands/test_container_scale_order.py(新設)、tests/utils/test_docker_profiles.py 確定 G5-設計:収束 なし マージ済み #231
G6-実装1 G6 実装 #203 standard lib/devbase/utils/names.py、lib/devbase/plugin/syncer.py、lib/devbase/env/_import_merge.py、lib/devbase/env/io_import.py、テスト 2 ファイル、docs/specifications/cli-argument-resolution.md「運用」の 1 つ目、CHANGELOG.md 確定 G6-設計:収束 なし マージ済み #233
G4-実装1 G4 実装 #188 standard lib/devbase/env/secret_store.py「SecretRef.label()」「SecretStore.display_label」、lib/devbase/commands/env_backend.py、lib/devbase/commands/env.py「_group_suffix」、docs/specifications/secret-backend.md、docs/user/env-backend.md、docs/user/cli-reference/03-env.md 確定 G4-設計:収束 なし マージ済み #237
G1-実装1 G1 実装 #161 #160 standard containers/base/Dockerfile「apt の一覧」「末尾の COPY」、containers/base/fonts-local.conf(新設)、tests/containers/ 確定 G1-設計:収束 なし マージ済み #238
G5-実装2 G5 実装 #192 standard lib/devbase/commands/container.py「cmd_scale」 確定 G5-設計:収束 G5-実装1:マージ マージ済み #232
G6-実装2 G6 実装 #203 standard lib/devbase/snapshot/manager.py、tests/snapshot/test_manager_name.py(新設)、docs/specifications/cli-argument-resolution.md「運用」の 2 つ目、CHANGELOG.md 確定 G6-設計:収束 G6-実装1:マージ マージ済み #235

release ブランチ: release/v3.7.0
base ブランチ: main(本番のチャネルも main)

重なり

行の組 ファイルと節 区分 扱い
G6-実装1 / G6-実装2 docs/specifications/cli-argument-resolution.md「運用」 書き換え G6-実装2 の実装の依存へ G6-実装1:マージ を足した(設計文書の決定)
G5-実装1 / G5-実装2 container.py「cmd_scale」 書き換え G5-実装2 の実装の依存へ G5-実装1:マージ を足した(設計文書の決定)
G6-実装1 / G6-実装2 / 他 CHANGELOG.md 足すだけ 並行してよい。後からマージする側が両方を残して解く
G2-実装1 / G5-実装 docs/specifications/compose-profiles.md 別の節 G2 は列挙(196 行目付近)、G5 は scale の除外の節。並行してよい。後からマージする側が競合を解く
G6-実装 / G5-実装 lib/devbase/commands/container.py 別の節 G6 の修正レイヤーは plugin/syncer.py。container.py へ及ぶなら見直しで区分を上げる

測った値

時刻 空き(MiB) cgroup の残り(MiB) スワップの空き(MiB) oom_kill 動いている本数 起動してよい本数 決めた条件 起動した行
2026-09-22T00:00Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G2-実装1
2026-09-22T01:00Z 測れない 測れない 測れない 測れない 1 1 測れない(exit 3 / macOS) 無し(G2 の検査を継続)
2026-09-22T02:00Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G3-実装1
2026-09-22T03:00Z 測れない 測れない 測れない 測れない 1 1 測れない(exit 3 / macOS) 無し(G3 の検査を継続)
2026-09-22T04:00Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G1-設計
2026-09-22T06:00Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G4-設計
2026-09-22T11:10Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G5-設計
2026-09-22T12:05Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G6-設計
2026-09-22T12:30Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G5-実装1
2026-09-22T14:00Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G5-実装2
2026-09-22T15:15Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G6-実装1
2026-09-23T01:10Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G6-実装2
2026-09-23T02:50Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G4-実装1
2026-09-23T04:00Z 測れない 測れない 測れない 測れない 0 1 測れない(exit 3 / macOS) G1-実装1(コンテナを建てる担当。他に動いている行は無い)

見直し

時刻 契機 変えたこと 理由
2026-09-23T06:30Z 取り込みの報告(関門)→ 利用者が配布を承認(2026-09-23) release PR #212 を main へマージ(fd5fa48)。8 課題すべてが自動で閉じた(milestone open=0 / closed=8)。仕上げの持ち場を起動する 本番の系へ届く操作の承認を受けた
2026-09-23T06:00Z G1-検査の報告(収束・Draft 解除)→ #238 を release へ取り込み 6 束すべてが マージ済み。取り込みの持ち場(まとまり単位)を起動する 実装 PR 8 本と設計 PR 4 本がすべて release に入った
2026-09-23T04:40Z G1-実装1 の報告 Pull Request に #238 を書き、検査を起動した。イメージは建て直し済み(サイズ +10.0 MB、合否のライン 40 MB 以下を満たす) 実装が終わり Draft PR が出たため
2026-09-23T04:00Z G4-検査の報告(収束・Draft 解除)→ #237 を release へ取り込み G4 の束を閉じた。G1-実装1 を起動した(最後の束) 3 者とも指摘 0 で収束。構造改善の提案 4 件は差分外のため却下・取り消し済み
2026-09-23T03:10Z G4-実装1 の報告 Pull Request に #237 を書き、検査を起動した 実装が終わり Draft PR が出たため
2026-09-23T02:50Z G6-検査2 の報告(収束・Draft 解除)→ #235 を release へ取り込み G6 の束を閉じた。G4-実装1 を起動した 空の名前の文言は変更前も同じ文で、削除の維持を実機で確認して収束
2026-09-23T01:25Z G6-実装2 の報告 Pull Request に #235 を書き、検査を起動した。空の名前の検査を削った点(文言が変わっていないか)の確認を検査へ渡した 設計の決定 5 が例外の文言を変えないと決めているため
2026-09-23T01:10Z G6-検査の報告(収束・Draft 解除)→ #233 を release へ取り込み G6-実装1 を マージ済み、G6-実装2 を起動した 依存(G6-実装1:マージ)が済んだ
2026-09-23T00:30Z G6-検査が利用者の操作で停止 → 利用者が「構造改善を打ち切って先へ」を選択 構造改善をテスト追加(570a2fe)で打ち切り、ブランチを開発用の作業ツリーへ戻した。検査の持ち場を cross-review から起動し直した(別の担当) 利用者の判断。打ち切りの理由は PR 本文に残させる
2026-09-22T15:40Z G6-実装1 の報告 Pull Request に #233 を書き、検査を起動した 実装が終わり Draft PR が出たため
2026-09-22T15:15Z G5-検査2 の報告(収束・Draft 解除)→ #232 を release へ取り込み G5 の束を閉じた(G5-実装2 を マージ済み)。G6-実装1 を起動した D-3 は意図を満たし数字は満たさない判断で収束。読みやすさを優先した理由は要求の文書と PR 本文にある
2026-09-22T14:15Z G5-実装2 の報告 Pull Request に #232 を書き、検査を起動した。D-3 の行数を詰めて合わせた点の判断を検査へ渡した 数字に合わせて読みやすさを削っていないかを確かめるため
2026-09-22T14:00Z G5-検査の報告(収束・Draft 解除)→ #231 を release へ取り込み G5-実装1 を マージ済み、G5-実装2 を起動した 依存(G5-実装1:マージ)が済んだ。設計の文脈が新しいうちに #192 を閉じる 2 本目を先に回す
2026-09-22T12:45Z G5-実装1 の報告 Pull Request に #231 を書き、検査の持ち場を起動した 実装が終わり Draft PR が出たため
2026-09-22T12:25Z 設計 PR 4 本の承認(利用者、2026-09-22T12:19Z 頃、4 本すべて)とマージ 設計の行を マージ済み に。#213 #217 も検査収束済みのため release へ取り込んだ。実装の行を 6 つ置いた(G5 と G6 は設計の決定で 2 本ずつ) 承認を受けた。先に取り込んだのは、後の実装が隔離と文書の修正を前提にできるようにするため
2026-09-22T15:35Z G6-設計が利用上限(429)で中断 同じ担当を SendMessage で再開した。行の状態は 動いている のまま 記録の ending が rate_limit、resets_passed が真。中断は cross-review の round 3 の直前
2026-09-22T12:05Z G5-設計の報告(収束・関門) G5 を 承認待ち にし、G6 の設計を起動した。設計 PR は #225。G5 の実装は 2 本に分かれる(1 本目「共通経路へ寄せる」→ :マージ → 2 本目「cmd_scale の段階を分ける」)ため、承認の後に行を 2 つへ置き直す 設計文書が実装の分け方を決めたため
2026-09-22T11:10Z G4-設計の報告(収束・関門) G4 を 承認待ち にし、G5 の設計を起動した。設計 PR は #223 承認は 4 束ぶんをまとめて 1 回にする
2026-09-22T10:35Z G4-設計が利用上限(429)で中断 同じ担当を SendMessage で再開した。行の状態は 動いている のまま 記録の ending が rate_limit、resets_passed が真。再開の指示に「外部へ書く前に既に書いたものを確かめる」を入れた
2026-09-22T06:00Z G1-設計の報告(収束・関門) G1 を 承認待ち にし、G4 の設計を起動した。設計 PR は #221 承認は 4 束ぶんをまとめて 1 回にするため、承認待ちのまま次の設計へ進む
2026-09-22T04:00Z G3-検査の報告(収束・Draft 解除) G3 を レビュー待ち にし、G1 の設計を起動した light の 2 束が検査を終えたため、standard の設計へ移る
2026-09-22T03:00Z G3-実装1 の報告 G3 の確度を 確定 に、Pull Request に #217 を書いた。検査の持ち場を起動した 実装が終わり Draft PR が出たため
2026-09-22T02:00Z G2-検査の報告(収束・Draft 解除) G2 を レビュー待ち にし、G3 を起動した 検査が終わり、取り込みはまとまり単位で後にまとめるため
2026-09-22T01:00Z G2-実装1 の報告(実装の持ち場が完了) G2 の確度を 確定 に、Pull Request に #213 を書いた。検査の持ち場を起動した 実装が終わり Draft PR が出たため
2026-09-22T00:00Z 着手 行を 6 つ置いた マイルストーンの説明に「並列の組」の表が無いため、課題の本文から束を決めた。#161 と #160 は containers/base/Dockerfile の同じ区画を触るため 1 本にした

閉じたときの測定

対象の Pull Request 期間(分) 重なり(分) 並行度 最大同時 oom_kill の増分
#213 #217 #221 #223 #225 #230 #231 #232 #233 #235 #237 #238 #240 #241(14 本) 1462 902 61.7% 6 測れない(macOS。起点も測れていない)

「最大同時 6」は担当の本数ではない。 起動してよい本数は最後まで 1 で、動いていた担当(supervisor)は常に 1 つだった。この値は Pull Request が同時に open だった数で、検査を終えてレビュー待ちのまま取り込みを待っていた本数を含む。実行計画の「本数に数えるのは 動いている だけである」の定義とは別物である。

並行度 61.7% も同じ理由で、担当の並行ではない。 1 本ずつ順に通しても、先の束の Pull Request が open のまま残るため重なりは生じる。

閉じたときの記録(進め方)

項目 値
期間 2026-09-21T20:44Z(最初の Pull Request)〜 2026-09-23T07:52 JST(main へのマージ)
束 6(G1〜G6)。課題 8 件
Pull Request 14 本(設計 4 / 実装 8 / 確定仕様化 1 / 版上げ 1)+ release PR #212
持ち場 19(設計 4 / 実装 8 / 検査 9(1 つは利用者の停止で途中終了)/ 取り込み 1 / 仕上げ 1)
関門 2 回(設計 PR 4 本をまとめて 1 回、配布で 1 回)。どちらも承認を得た
中断 利用上限 2 回(記録から再開)、利用者の停止 1 回(構造改善の打ち切りを決定)
報告なしで続けさせた 1 回(検査 #188 の担当が待ちで応答を終えた)
起票した範囲外の課題 devbase 19 件(#214 #215 #216 #218 #219 #220 #222 #224 #226 #227 #228 #229 #234 #239 #242〜#248)/ ai-plugins 5 件(#837〜#840・#842)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment