diff --git a/docs/glossary.md b/docs/glossary.md
index 4bebc4e2..ac35ac0b 100644
--- a/docs/glossary.md
+++ b/docs/glossary.md
@@ -181,6 +181,9 @@ base の設定が派生イメージと lfm へ届く道筋(containers/*/Docker
| 取り込み | — | lfm の Dockerfile が COPY --from=devbase-base:latest で base のイメージからファイルやディレクトリを同じパスへ持ち込むこと | — | — | `docs/specifications/lfm-base-settings.md` |
| 到達の検査 | — | base の Dockerfile から base の設定を集め、それぞれが lfm へ届くかを Docker を起動せずに判定するテスト(tests/containers/test_lfm_base_settings.py) | — | — | `docs/specifications/lfm-base-settings.md` |
| 除外表 | — | 到達の検査が、lfm へ届かなくてよいとする base の項目と、その理由の一覧 | — | — | `docs/specifications/lfm-base-settings.md` |
+| DinD | — | コンテナの中で dockerd を起こし、そのコンテナの中だけの docker を使う形。#400 で廃止し、ENABLE_DIND は知らせを 1 行出すだけになった。ホストの docker.sock を mount して使う形と区別する | — | — | — |
+| 展開後の大きさ | — | 建てたイメージから作ったコンテナで du -sbx / を測ったバイト数。docker images の圧縮後の大きさとは違う | — | — | — |
+| 文書の除外 | — | dpkg の path-exclude の設定で、apt が入れるパッケージから文書などの置き場を展開しないこと。base は Ubuntu の excludes に加え、changelog・info・/usr/include/node を外す(copyright は残す)。base を FROM で継ぐ派生イメージにも効く | — | — | — |
## コンテナの起動(`container-start`)
diff --git a/docs/glossary/glossary.json b/docs/glossary/glossary.json
index 8a762e93..dd9595d0 100644
--- a/docs/glossary/glossary.json
+++ b/docs/glossary/glossary.json
@@ -858,6 +858,27 @@
"context": "browser",
"meaning": "playwright install の --with-deps が apt で入れるパッケージ。共有ライブラリ(libnss3 など)とフォント(fonts-liberation・fonts-ipafont-gothic・fonts-wqy-zenhei など)を含む",
"source": "docs/specifications/base-image-rendering.md"
+ },
+ {
+ "term": "DinD",
+ "context": "image-lineage",
+ "meaning": "コンテナの中で dockerd を起こし、そのコンテナの中だけの docker を使う形。#400 で廃止し、ENABLE_DIND は知らせを 1 行出すだけになった。ホストの docker.sock を mount して使う形と区別する",
+ "source": "",
+ "pending_source": "issues/issue-400-requirements.md"
+ },
+ {
+ "term": "展開後の大きさ",
+ "context": "image-lineage",
+ "meaning": "建てたイメージから作ったコンテナで du -sbx / を測ったバイト数。docker images の圧縮後の大きさとは違う",
+ "source": "",
+ "pending_source": "issues/issue-400-requirements.md"
+ },
+ {
+ "term": "文書の除外",
+ "context": "image-lineage",
+ "meaning": "dpkg の path-exclude の設定で、apt が入れるパッケージから文書などの置き場を展開しないこと。base は Ubuntu の excludes に加え、changelog・info・/usr/include/node を外す(copyright は残す)。base を FROM で継ぐ派生イメージにも効く",
+ "source": "",
+ "pending_source": "issues/issue-400-requirements.md"
}
]
}
diff --git a/issues/issue-400-design.md b/issues/issue-400-design.md
new file mode 100644
index 00000000..a0260ce9
--- /dev/null
+++ b/issues/issue-400-design.md
@@ -0,0 +1,406 @@
+# base イメージ: 誰も使わない dockerd・aws-cdk-lib・root の uv・node のヘッダと片付けの漏れで展開後の大きさが約 0.5GB 余分にある → 外して arm64 で 450MB 以上小さくし、使う者のいない DinD を廃止する(#400)
+
+## 目的
+
+- **何が壊れているか**: base に、使う者が見当たらない中身と片付けの漏れが合わせて約 525MB ある。dockerd・containerd・グローバルの `aws-cdk-lib`・root の uv・node のヘッダと、apt の一覧である
+- **誰が困るか**: base とその派生を建てる・取得する・置くすべての利用者。建てる時間とディスクを、誰も使わない中身の分だけ払っている
+- **直すと何が成り立つか**: base の展開後の大きさが arm64 で 450MB 以上減る。docker CLI・buildx・compose・`cdk`・uv は今と同じに使える。`ENABLE_DIND` は廃止を 1 行で知らせて起動を続ける
+
+## 適用範囲
+
+- **働く範囲**: このリポジトリの `containers/base` と、それを `FROM` で継ぐ派生 7 つ。利用者が base を建て直した時点で届く。lfm は #403 で #400 より先に無くなるため含まない(決定 3)
+- **プロジェクトごとに違うもの**: 無し(イメージの中身だけを変え、プロジェクトの設定・引数を読まない)
+- **当たるモード**: `standard`
+
+## あるべき姿の根拠
+
+| 根拠 | 種類 | 何を示すか |
+| --- | --- | --- |
+| `docker run --rm --entrypoint bash devbase-base:latest` で測った値(2026-10-03・arm64): `/usr/include/node` 67MB・`/usr/share/doc` 8.0MB・`/usr/share/info` 940KB・`/var/lib/apt/lists` 42MB・グローバルの `aws-cdk-lib` 181MB | 実測 | 外す中身の大きさ。docker-ce 106MB・containerd 81MB・root の uv 40MB は課題の本文の実測 |
+| 同じコンテナの `/etc/dpkg/dpkg.cfg.d/excludes` が既に `man`・翻訳の `.mo`・`doc`(copyright と changelog を除く)を外している。`/usr/share/man` の下のファイルは 0。`/usr/share/doc` には copyright と `changelog*` のほかに 40 個のファイルと symlink が残る(`apt/NEWS.Debian.gz`・`gnupg/TODO`・`gnupg/examples/*`・`base-files/FAQ`・`libavahi-common3/README`・`python3/README.Debian`・`fonts-dejavu-core/*` などのファイルと、`libgcc-s1`・`libpython3.14` などの symlink)(2026-10-03・arm64 で `find /usr/share/doc ! -type d ! -name copyright ! -name 'changelog*'` を数えた) | 実測 | 文書の除外で足すのは changelog・info・`/usr/include/node` の 3 つ。dpkg の規則だけでは既に残る物が消えないため、最初の `RUN` と利用者の層で `/usr/share/doc` の下の copyright でないファイルと、ディレクトリを指さない symlink を消す(ディレクトリを指す symlink は copyright への経路なので残す。決定 4) |
+| `grep -rIl ENABLE_DIND` を `repos/*/`・`projects/*/` の compose.yml・env・.env にかけて 0 件。当たった compose の注記 1 件はホストの dockerd を指す | 実測 | `ENABLE_DIND` を設定する者がいない |
+| #403 の本文: lfm を使うプロジェクトは無く、利用者が 2026-10-03 に lfm の廃止を決めた。Dockerfile を読む試験の部品(`Instruction` / `parse`)をテストの共通の置き場へ移す | 利用者の指示 | DinD を前提に作られた唯一の派生が無くなる。#400 の試験は移した先の部品を使える |
+| #400 への利用者のコメント(2026-10-03): lfm は #403 で先に廃止する。lfm への影響は考えなくてよい | 利用者の指示 | #400 は lfm のファイル・試験・仕様が無い状態から始める |
+| 設計の起動の指示「DinD を廃止するかは …… grep して使う者の有無で決める」 | 利用者の指示の原文 | DinD の扱いを使う者の有無で決める |
+
+要求と受け入れ条件は #400 の本文にある(コピーは `issues/issue-400-requirements.md`)。この文書は「どう作るか」だけを扱う。
+設計の中で要求の前提 1 を「DinD を lfm に残す」から「DinD を廃止する」へ改め、本文の「変更の記録」に残した(決定 1)。
+
+## ドメインモデル
+
+### コンテキスト
+
+| コンテキスト | 何の語が 1 つの意味に決まるか |
+| --- | --- |
+| イメージの継承(`image-lineage`) | base の中身・文書の除外・展開後の大きさ・DinD。base が入れる物と、派生へ届く道筋 |
+| コンテナの起動(`container-start`) | entrypoint が起動のたびに行う用意。`ENABLE_DIND` の読み方 |
+
+イメージの継承が供給者、コンテナの起動が顧客の関係(顧客 / 供給者)。entrypoint は base が入れた物だけを前提に動く。
+base が dockerd を入れなくなるため、entrypoint は dockerd を起こす手順を持たない。
+
+### 集約
+
+| 集約 | 持ち主(書き換えてよいもの) | 根 | エンティティ | 値オブジェクト |
+| --- | --- | --- | --- | --- |
+| base の中身 | `containers/base/Dockerfile` | base イメージ | apt のパッケージ・npm のグローバルのモジュール・root と ubuntu の道具 | 文書の除外の設定・片付けの対象のパス・`PATH` |
+| 起動の用意 | `containers/base/entrypoint.sh` | 起動の手順 | DinD の知らせ | `ENABLE_DIND` の値 |
+
+### 不変条件
+
+| # | 集約 | 条件 | 破れたときの扱い |
+| --- | --- | --- | --- |
+| I1 | base の中身 | apt で `docker-ce`・`containerd.io` を入れず、`docker-ce-cli`・`docker-buildx-plugin`・`docker-compose-plugin` を入れる | 実装の誤り。試験がパッケージの名前を挙げて落ちる |
+| I2 | base の中身 | npm のグローバルに `aws-cdk-lib` を入れず、`aws-cdk` を入れる | 同上 |
+| I3 | base の中身 | uv のインストーラを呼ぶのは `USER ubuntu` の後の `RUN` だけで、`ENV PATH` に `/root/.local/bin` が無い | 同上 |
+| I4 | base の中身 | apt の一覧を取得する `RUN`(`apt-get update` か `--with-deps` を含み、`/var/lib/apt` を cache mount しないもの)は、同じ `RUN` で `/var/lib/apt/lists` を消す | 同上。どの `RUN` かを挙げて落ちる |
+| I5 | base の中身 | 文書の除外の設定が、最初の `RUN` より前に Ubuntu の `excludes` より後に読まれる名前で置かれ、copyright を残して changelog・info・man・`/usr/include/node` を外す。最初の `RUN` と利用者の層の `RUN` は、`/usr/share/doc` の下の copyright でないファイルと、ディレクトリを指さない symlink を消す(利用者の層は `sudo` で消す)。ディレクトリを指す symlink は残し、`/usr/share/doc/<パッケージ>/copyright` の経路を保つ | 同上 |
+| I6 | base の中身 | `containers/base/dind` が無く、Dockerfile は `/usr/local/bin/dind` を置かない | 同上 |
+| I7 | 起動の用意 | `ENABLE_DIND` が `true` か `1` のとき、DinD の廃止を 1 行出して起動を続ける。dockerd を起こさず、`/var/run/docker.sock` を消さず、`docker info` を待たない | 実装の誤り。entrypoint の試験で落とす |
+| I8 | 起動の用意 | `ENABLE_DIND` が無い・`true` と `1` 以外のとき、何も出さず、起動の手順と順序は変わらない | 同上 |
+
+### ドメインイベント
+
+| # | イベント | 発生元 | 受け手 |
+| --- | --- | --- | --- |
+| E1 | 変更前の base を建て、展開後の大きさを測った | 実装の担当(main の Dockerfile) | E5 の比べる元 |
+| E2 | 変更後の base を arm64 で建てた | 実装の担当(この変更の Dockerfile) | E3・E4・E6・E8 |
+| E3 | 変更後の base を amd64 で建てた | 実装の担当 | E4 |
+| E4 | 建てた base の中身を確かめた | 実装の担当 | PR の記録 |
+| E5 | 展開後の大きさを測り、減った量を PR に記録した | 実装の担当 | PR の記録・承認する人 |
+| E6 | 変更後の base から派生イメージを建てた | 実装の担当 | PR の記録 |
+| E7 | (#403 で対象が無くなったため削除) | — | — |
+| E8 | base で `ENABLE_DIND=true` のコンテナを起こし、廃止の知らせが出て起動が続いた | entrypoint | PR の記録 |
+| E9 | 利用者が base を建て直した | 利用者(main へのマージの後) | リリース後テスト |
+
+### 用語
+
+| 用語 | 意味 | 用語集への反映 |
+| --- | --- | --- |
+| DinD | コンテナの中で dockerd を起こし、そのコンテナの中だけの docker を使う形。#400 で廃止し、`ENABLE_DIND` は知らせを 1 行出すだけになった。ホストの docker.sock を mount して使う形と区別する | 意味の変更(`image-lineage`) |
+| 文書の除外 | dpkg の `path-exclude` の設定で、apt が入れるパッケージから文書などの置き場を展開しないこと。base は Ubuntu の `excludes` に加え、changelog・info・`/usr/include/node` を外す(copyright は残す)。base を `FROM` で継ぐ派生イメージにも効く | 意味の変更(`image-lineage`) |
+| 展開後の大きさ | 建てたイメージから作ったコンテナで `du -sbx /` を測ったバイト数。`docker images` の圧縮後の大きさとは違う | 新規(`image-lineage`) |
+
+意味の文はこの表が正本で、`docs/glossary/glossary.json` の `meaning` はこの表の文と同じ文にする(コードの印の backtick だけを除く)。
+
+## 機能一覧
+
+| # | 機能 | 誰が使うか |
+| --- | --- | --- |
+| F1 | base を建てると、dockerd・containerd・グローバルの `aws-cdk-lib`・root の uv が入らない | base と派生を建てる利用者 |
+| F2 | base と派生で、apt が入れるパッケージの changelog・info・man・node のヘッダが展開されない | 同上 |
+| F3 | base の最後の利用者の層に apt の一覧が残らない | 同上 |
+| F4 | docker CLI・buildx・compose・`cdk`・ubuntu の uv が今と同じに使える | コンテナの中で作業する利用者 |
+| F5 | `ENABLE_DIND` を設定したままの利用者に、DinD の廃止を 1 行で知らせ、起動は止めない | `ENABLE_DIND` を設定していた利用者 |
+
+## 構成要素
+
+型(クラス)は持たない。Dockerfile の命令と、entrypoint のシェル関数だけで構成する。
+
+| 要素 | 責務 | 変更 |
+| --- | --- | --- |
+| 文書の除外の設定(`containers/base/dpkg-excludes`、新規) | `/etc/dpkg/dpkg.cfg.d/excludes-devbase` として置かれ、Ubuntu の `excludes` の後に読まれて changelog・info・man・`/usr/include/node` を外し、copyright を残す(決定 4) | 作る |
+| base の Dockerfile の apt の層(最初の `RUN`) | 文書の除外の設定を `COPY` で先に置き、`docker-ce`・`containerd.io` を一覧から外す。同じ `RUN` の最後で `/usr/share/doc` の下の copyright でないファイルとディレクトリを指さない symlink(changelog を含む)と `/usr/share/info` の中身を消す。ディレクトリを指す symlink は残す(決定 4) | 変える |
+| base の Dockerfile の root の道具の層(2 つ目の大きな `RUN`) | root の uv のインストーラの呼び出しと、npm の `aws-cdk-lib` を外す | 変える |
+| base の Dockerfile の `ENV PATH` | `/root/.local/bin` を外す(決定 6) | 変える |
+| base の Dockerfile の利用者の層 | 片付けに `/var/lib/apt/lists/*` を足す(決定 7)。同じ片付けで `/usr/share/doc` の下の copyright でないファイルとディレクトリを指さない symlink を `sudo find` で消す。`USER ubuntu` の下で動き、apt が root 所有で作る物は `sudo` なしでは消せず `set -e` でビルドが止まるため(決定 4) | 変える |
+| base の Dockerfile の最後の `COPY` | `dind` の `COPY` を外し、`entrypoint.sh` だけを置く | 変える |
+| `containers/base/dind` | — | 消す |
+| entrypoint の DinD の知らせ(`devbase_notice_dind_removed`、新規) | `ENABLE_DIND` が `true` か `1` なら廃止を 1 行出して 0 で返る。それ以外は何も出さずに 0 で返る。`DEVBASE_ENTRYPOINT_LIB_ONLY` で source した試験から呼べる(決定 2) | 作る |
+| entrypoint の本体の手順 5 | dockerd を起こす分岐を消し、DinD の知らせを呼ぶ 1 行にする。手順 4 と AI の設定の間という位置は変えない | 変える |
+| base の形の試験(`tests/containers/test_base_dockerfile_slim.py`、新規) | I1〜I6 を Docker を起こさずに固定する。Dockerfile の読み方は #403 が共通の置き場へ移した `Instruction` / `parse` を import する(決定 5) | 作る |
+| DinD の知らせの試験(`tests/containers/test_entrypoint_dind_removed.py`、新規) | I7・I8 を固定する | 作る |
+| base のシェルスクリプトの数え上げ(`tests/containers/test_base_shellcheck_ci.py`・`.github/workflows/ci.yml`・`docs/developer/contributing.md`) | ShellCheck の対象の並びから `dind` を外す | 変える |
+| 確定仕様(`docs/specifications/base-image-shellcheck.md`・`ci-checks.md`) | 2 回目の apt の一覧・`dind` の ShellCheck・`SC2009` の抑止の記述を今の形へ直す | 変える |
+| 用語集(`docs/glossary/glossary.json`) | DinD・文書の除外の意味を直し、展開後の大きさを `image-lineage` に新しく載せ(意味は用語の表の文のまま)、`glossary.py render` で `docs/glossary.md` を作り直す | 変える |
+| `CHANGELOG.md` の `[Unreleased]` | 外した中身と、DinD の廃止(破壊的変更・ホストの docker.sock を使う)を書く | 変える |
+
+```mermaid
+graph TD
+ subgraph base["containers/base"]
+ X[文書の除外の設定] --> A[apt の層]
+ A --> R[root の道具の層]
+ R --> P[ENV PATH]
+ P --> U[利用者の層]
+ U --> E[entrypoint の COPY]
+ N[DinD の知らせ] -.属する.-> E
+ end
+ subgraph 派生["FROM で継ぐ派生 7 つ"]
+ D[自分の apt-get install]
+ end
+ subgraph 試験["tests/containers"]
+ T1[base の形の試験]
+ T2[DinD の知らせの試験]
+ end
+ X -->|dpkg の設定を継ぐ| D
+ T1 -.読む.-> base
+ T2 -.source.-> N
+```
+
+## 構造
+
+```text
+containers/
+├── base/
+│ ├── Dockerfile 変える
+│ ├── dpkg-excludes 新規
+│ ├── dind 消す
+│ └── entrypoint.sh 変える
+tests/containers/
+├── test_base_dockerfile_slim.py 新規
+├── test_entrypoint_dind_removed.py 新規
+└── test_base_shellcheck_ci.py 変える
+```
+
+## 処理の流れ
+
+### base を建てる順(変更後)
+
+```mermaid
+graph TD
+ F[FROM ubuntu:26.04] --> C1["COPY dpkg-excludes
/etc/dpkg/dpkg.cfg.d/excludes-devbase"]
+ C1 --> R1["RUN apt の層
docker-ce-cli・buildx・compose を入れる
doc の copyright でない物と info を消す"]
+ R1 --> R2[RUN 利用者とグループ]
+ R2 --> R3["RUN root の道具
aws・gcloud・npm(aws-cdk-lib なし)
root の uv なし"]
+ R3 --> P["ENV PATH
/opt/google-cloud-sdk/bin を足す"]
+ P --> R4[RUN bao・確認]
+ R4 --> R5["USER ubuntu の RUN
uv・claude・agy・kiro・playwright
片付けで apt の一覧と doc の copyright でない物も消す"]
+ R5 --> R6[設定の COPY と fc-cache]
+ R6 --> C2[COPY entrypoint.sh]
+```
+
+建てる流れと起動の流れに乗らない要素(試験・ShellCheck の対象の並び・確定仕様・用語集・`CHANGELOG.md`)は図に含めない。
+
+`playwright install --with-deps` の `apt-get` も文書の除外の設定に従うため、その層でも文書は展開されない。
+
+### コンテナの起動(`ENABLE_DIND` の扱い)
+
+```mermaid
+graph TD
+ S[手順 4 AWS の設定] --> Q{ENABLE_DIND は true か 1 か}
+ Q -->|はい| M["廃止の知らせを 1 行出す
(docker.sock・dockerd・docker info に触れない)"]
+ Q -->|いいえ| Z[何も出さない]
+ M --> AI[AI の設定の symlink]
+ Z --> AI
+ AI --> RP[リポジトリの用意] --> RD[完了の印] --> X[exec]
+```
+
+知らせの文は 1 行で、`ENABLE_DIND` が廃止されたことと、ホストの docker.sock を使うこと(`docker` はそのまま使える)を含める。
+文言は実装で決める。
+
+## 非機能の実現方式
+
+| 大項目 | 要求の条件 | 実現方式 | 確かめ方 |
+| --- | --- | --- | --- |
+| 性能・拡張性 | arm64 で展開後の大きさが 450MB 以上減る | 下の内訳の 7 つを外す。見込みは合わせて約 525MB で、450MB に約 75MB の余裕がある | 前提 8 の形で前後の base から作ったコンテナで `du -sbx /` を測り、差と内訳を PR に記録する |
+| 移行性 | 利用者は base を建て直すだけで移る。戻すときは前の Dockerfile で建て直す | 変えるのはイメージの中身と entrypoint だけで、ボリューム・設定・機密の形を変えない。`ENABLE_DIND` を残した利用者は起動が止まらず、知らせで気づく | 建て直した base で既存の entrypoint の試験が通ること・E8 の起動の出力を PR に記録する |
+| システム環境 | arm64 と amd64 の両方で建ち、受け入れ条件 1〜5 を満たす | アーキの `case` を足さない。外すのはアーキに依らない行だけで、文書の除外もアーキに依らない | arm64 で建てて 1〜6・8・9 を、amd64 で建てて 1〜5 を確かめ、amd64 の端末と方法を PR に書く |
+
+見込みの内訳(arm64):
+
+| 中身 | 大きさ | 出所 |
+| --- | --- | --- |
+| `docker-ce`(dockerd) | 106MB | 課題の本文 |
+| `containerd.io` | 81MB | 課題の本文 |
+| グローバルの `aws-cdk-lib` | 181MB | 実測(2026-10-03) |
+| root の uv | 40MB | 課題の本文 |
+| `/var/lib/apt/lists` | 42MB | 実測 |
+| `/usr/include/node` | 67MB | 実測 |
+| `/usr/share/doc` の changelog と `/usr/share/info` | 約 9MB | 実測(8.0MB と 940KB) |
+| 合計 | 約 525MB | — |
+
+`docker-ce` が依存で引き込んでいたパッケージ(`iptables` など)も、他に要る物が無ければ入らなくなる。この分は見込みに含めない。
+
+## 同じスプリントの課題との順と境目
+
+### 実装の順
+
+- **#403 → #400 → #401 → #402 の順に 1 本ずつマージする。** 後の課題は、前の課題がマージされた main を取り込んでから建てて測る。
+ 大きさの比べる元は、その時点の main で建てた base である
+- **#400 の 450MB は arm64 で測る。** #401 は amd64 だけを変えるため、#400 の測りに #401 は入らない
+- **#400 は #403 の後の main から始める。** lfm・`test_lfm_base_settings.py`・`lfm-base-settings.md` は既に無く、#400 は lfm に触れない。前提 8 の「前」の base も #403 の後の main で建てる
+
+```mermaid
+graph LR
+ D["#403
lfm の廃止"] --> A["#400 段階 1
使う者のいない中身"]
+ A --> B["#401 段階 2
amd64 の Chrome"]
+ B --> C["#402 段階 3
ブラウザ・フォント・terraform"]
+```
+
+### Dockerfile の行の持ち主
+
+#401・#402 は base の Dockerfile の同じ層を触る。#403 は #400 より先に入り、lfm を前提にした行を片付ける。行ごとに持ち主を 1 つに決め、他の課題の行には触れない(決定 8)。
+行番号は main の `9f3e5c5` の `containers/base/Dockerfile` で数えた。#403 の後の main では行がずれるため、実装の担当は中身で読み替える。
+
+| 場所(行) | 中身 | 持ち主 |
+| --- | --- | --- |
+| 最初の `RUN` の前(新しい `COPY`) | 文書の除外の設定 | #400 |
+| 22 | `fonts-noto-cjk-extra` | #402 |
+| 23〜25 の後(最初の apt の一覧) | `fonts-liberation` などの明示 | #402 |
+| 37〜43 | Docker の apt の取得元 | 変えない(CLI・buildx・compose に要る) |
+| 44〜48 | HashiCorp の apt の取得元 | #402 |
+| 56〜67 | amd64 の Chrome の取得元と `BROWSER_PKG` | #401 |
+| 71 | `docker-ce`・`containerd.io` | #400(`docker-ce-cli` は残す) |
+| 73 | `terraform` | #402 |
+| 73 | `$BROWSER_PKG` | #401 |
+| 75〜76 の後 | `/usr/share/doc` の下の copyright でないファイルとディレクトリを指さない symlink・`/usr/share/info` の中身の削除 | #400 |
+| 84〜89・111〜113・247〜251・259 | lfm を前提にした注記と `NPM_GID` | #403(先に入る。#400 は触らない) |
+| 155〜156 | root の uv | #400 |
+| 159 | `aws-cdk-lib` | #400 |
+| 177 | `/root/.local/bin` | #400 |
+| 234〜235 | Playwright の Chromium と `--with-deps` | #402 |
+| 236〜245 | 片付け(`/var/lib/apt/lists/*` と `/usr/share/doc` の下の copyright でない物の削除を足す。どちらも `sudo` で消す) | #400。注記の `--with-deps` の語は #402 |
+| 304〜308 | `fc-cache` の注記 | #402 |
+| 310〜312 | `dind` の `COPY` | #400 |
+
+### Dockerfile の外で重なるもの
+
+| 場所 | 重なり | 扱い |
+| --- | --- | --- |
+| `docs/specifications/base-image-shellcheck.md` の 2 回目の apt の一覧の行 | #400(`docker-ce` → `docker-ce-cli`)・#401(Chrome)・#402(`terraform`) | 後から入る側が main を取り込み、前の課題の直しを残して自分の語を直す |
+| `tests/containers/test_base_dockerfile_playwright.py` | #401・#402 | #400 は触らない。#400 の試験は新しいファイルに置く |
+| Dockerfile の読み方の部品(`Instruction` / `parse`) | #403(`test_lfm_base_settings.py` から共通の置き場へ移す)・#400(import する) | #400 の試験は #403 が移した先を import する。部品は直さない |
+| `CHANGELOG.md`・`docs/glossary/glossary.json` | 4 つすべて | 両側の記入を残して解く。`docs/glossary.md` は `glossary.py render` で作り直す |
+
+## 決定の記録
+
+### 決定 1: 使う者の有無で決めるため、DinD を廃止し、`dind` と dockerd を起こす分岐を消す
+
+`ENABLE_DIND` を設定する者は、リポジトリ・手元のプラグイン・手元のプロジェクトに 0 件である。DinD を前提に作られた
+lfm は使う者が無く、#403 で #400 より先に廃止する。lfm は自分で dockerd を入れ、NVIDIA の runtime を DinD 向けに書いていた。
+DinD を残しても動かす先が無く、`dind` と分岐は誰も通らない経路として base とすべての派生に配られ続ける。要求の前提 1 は
+lfm が残る前提で書かれていたため、課題の本文を改め「変更の記録」に残した。
+
+dockerd を入れた新しい派生へ DinD を移す形は採らない。移す先を使う者がいない。lfm に残す形は、lfm ごと消えるため採らない。
+
+根拠: Value 1 / P1(MVV 版 1)
+
+### 決定 2: 設定を残した利用者が原因に気づけるよう、`ENABLE_DIND` は 1 行で知らせて起動を続ける
+
+分岐を消すだけだと、`ENABLE_DIND` を残した利用者は DinD が起きない理由を知る手段が無い。起動を止めると、使っていない
+設定の残りのためにコンテナが使えなくなる。知らせは関数に切り出し、既存の entrypoint の試験と同じく
+`DEVBASE_ENTRYPOINT_LIB_ONLY` で source して呼べるようにする。
+
+`ENABLE_DIND` を黙って無視する形と、起動を止める形は採らない。前者は原因が見えず、後者は作業を止める。
+
+根拠: Mission(MVV 版 1)
+
+### 決定 3: #403 の後に入れるため、lfm には触らない
+
+利用者は m7c を #403 → #400 → #401 → #402 の順に入れると決め、#400 に「lfm への影響は考えなくてよい」とコメントした。
+#400 の起点の main には lfm の 3 つが無い。`containers/lfm`・`tests/containers/test_lfm_base_settings.py`・
+`docs/specifications/lfm-base-settings.md` である。base から `dind` を消しても、取り込む側が無いため壊れる物は無い。
+
+#400 が先に入る場合に備えて、lfm から `dind` の取り込みの 2 行を消す形は採らない。順が決まっているため、
+誰も通らない分岐を設計と PR に抱えるだけになる。
+
+根拠: Value 1(MVV 版 1)
+
+### 決定 4: 派生にも効かせて層の大きさから外すため、文書の除外を Ubuntu の `excludes` の後に読まれる別のファイルで置く
+
+`ubuntu:26.04` は `/etc/dpkg/dpkg.cfg.d/excludes` で man・`.mo`・doc を既に外している。copyright と changelog だけは
+`path-include` で残している。dpkg は後に読んだ規則を優先する。そのため `excludes` より後に並ぶ名前(`excludes-devbase`)の
+ファイルで doc を外し直し、copyright だけを入れ直せば changelog が外れる。
+
+同じファイルで `/usr/share/info/*`・`/usr/share/man/*`・`/usr/include/node/*` を外す。ファイルは
+`containers/base/dpkg-excludes` に置き、最初の `RUN` の前に `COPY` する。
+
+dpkg の規則だけでは受け入れ条件 5 の「copyright のほかのファイルが無い」を満たせない。今の base には changelog のほかに
+`NEWS.Debian.gz`・`README`・`examples/*` などのファイルと、別のパッケージの置き場を指す symlink(`libgcc-s1` など)が
+40 個残る(根拠の表の実測)。そのため最初の `RUN` の最後と利用者の層の片付けの両方で、
+`find /usr/share/doc -mindepth 1 ! -type d ! -xtype d ! -name copyright -delete` を実行し、`/usr/share/doc` の下の
+copyright でないファイルと、ディレクトリを指さない symlink(指す先の無い物を含む)を消す。`! -type d` は symlink を
+含み、`! -xtype d` は指す先がディレクトリの symlink を外す。`libgcc-s1` などのディレクトリを指す symlink は、
+条件 5 が残すと定める `/usr/share/doc/<パッケージ>/copyright` への経路なので消さない(指す先のディレクトリの copyright は
+同じ削除で残る)。利用者の層は `USER ubuntu` の下の `set -eux` の `RUN` で動き、`/usr/share/doc` は apt が root 所有で
+作るため、`sudo find /usr/share/doc ...` で消す(同じ層の `rm` が `sudo rm -rf` なのと同じ理由。`sudo` が無いと
+Permission denied で `find` が 0 でなく終わり、ビルドが止まる)。最初の `RUN` は root で動くので `sudo` を付けない。
+最初の `RUN` では `/usr/share/info` の中身も消す。利用者の層で消すのは、`playwright install --with-deps` の `apt-get` が入れる物を
+同じ規則で片付けるためである。`FROM` の層にある分は層の大きさが減らないが、条件 5 を満たす。
+
+翻訳(`/usr/share/locale`)は外さない。`.mo` は Ubuntu が既に外しており、残る `locale.alias` は glibc が読む。
+
+| 採らない形 | 理由 |
+| --- | --- |
+| Ubuntu の `excludes` を書き換える | Ubuntu の持ち物を混ぜる |
+| `RUN` の中で `printf` で書く | 試験がファイルとして読めない |
+| 入れた後に `rm` する | 前の層に大きさが残る |
+
+根拠: Value 1(MVV 版 1)
+
+### 決定 5: 試験が外した物を名前で挙げるよう、base の形の試験を新しいファイルに置く
+
+外した物ごとに 1 つの試験にし、Dockerfile へ戻すと名前を挙げて落ちる(受け入れ条件 11)。既存の
+`test_base_dockerfile_playwright.py` などは #401・#402 が直すため、同じファイルに書くと並行する変更がぶつかる。
+Dockerfile の読み方(命令への分け方)は新しく書かない。#403 が `test_lfm_base_settings.py` からテストの共通の置き場へ
+移した部品(`Instruction` / `parse`)を import する。
+
+根拠: Value 1(MVV 版 1)
+
+### 決定 6: 空の置き場を指さないよう、`PATH` から `/root/.local/bin` を外す
+
+root の uv を外すと `/root/.local/bin` に入る物が無くなる。`PATH` に残すと、何も入らない置き場を base とすべての派生に
+配り続ける。この要素を名前で除外していた lfm の試験は #403 で消えているため、外しても他の試験は変わらない。
+
+`PATH` を残す形は、理由の無い要素を配り続けるため採らない。
+
+根拠: Value 1(MVV 版 1)
+
+### 決定 7: #402 が Playwright を外しても壊れないよう、apt の一覧の片付けを規則で縛る
+
+試験は I4 の規則を見る。「`/var/lib/apt` を cache mount せずに apt の一覧を取得する `RUN` は、同じ `RUN` で一覧を消す」
+である。「利用者の層の片付けに `/var/lib/apt/lists` がある」は見ない。#402 が `--with-deps` を外すと、利用者の層は一覧を取得しなく
+なり、規則は当たる `RUN` が無いまま通る。片付けの 1 語が残っても害は無く、#402 が消してもよい。
+
+`--with-deps` の有無に関わらず利用者の層に片付けの語を求める形は、#402 の後に意味の無い要求になるため採らない。
+
+根拠: Value 1(MVV 版 1)
+
+### 決定 8: 並行する削減がぶつからないよう、#403 → #400 → #401 → #402 の順に 1 本ずつ入れ、Dockerfile の行の持ち主を分ける
+
+#403 は lfm と、lfm を前提にした base の行を先に片付け、後の 3 つの比べる元から lfm を外す。#400 以下の 3 つは段階の
+番号の順で、外す量の小さい順でもある。#400 は arm64 の測りが #401 に依らず、#401 は amd64 だけを触り、
+#402 は Playwright と apt の一覧の両方を変える。後の課題ほど前の結果を前提にできる。`main` は strict で、続けて
+マージすると後の 1 本が BEHIND になるため、1 本ずつ main を取り込み、建てて測り直してからマージする。行の持ち主は
+「同じスプリントの課題との境目」の表に従う。
+
+削減の 3 つを 1 本の PR にまとめる形は、測りが混ざり、どの削減が何を減らしたかを PR に記録できないため採らない。
+
+根拠: Value 1 / P1(MVV 版 1)
+
+## テスト設計
+
+| 受け入れ条件・不変条件 | どの振る舞いで縛るか | どう壊したら落ちるべきか |
+| --- | --- | --- |
+| I1(受け入れ条件 1・2) | base の apt の一覧に `docker-ce`・`containerd.io` が無く、`docker-ce-cli`・`docker-buildx-plugin`・`docker-compose-plugin` がある | `docker-ce` か `containerd.io` を一覧へ戻す・`docker-buildx-plugin` を消すと、そのパッケージの名前を挙げて落ちる |
+| I2(受け入れ条件 2・3) | npm のグローバルの一覧に `aws-cdk-lib` が無く、`aws-cdk` がある | `aws-cdk-lib` を戻す・`aws-cdk` を消すと落ちる |
+| I3(受け入れ条件 2・3) | uv のインストーラを呼ぶ `RUN` が `USER ubuntu` の後にだけあり、`ENV PATH` に `/root/.local/bin` が無い | root の `RUN` に uv のインストーラを戻す・利用者の `RUN` から消す・`PATH` に戻すと落ちる |
+| I4(受け入れ条件 4) | cache mount の無い apt の一覧の取得を持つ `RUN` は、同じ `RUN` で `/var/lib/apt/lists` を消す | 利用者の層の片付けから一覧を外すと、その `RUN` を挙げて落ちる。`--with-deps` を消した Dockerfile では当たる `RUN` が無く通る |
+| I5(受け入れ条件 5) | 文書の除外の設定が `excludes` より後に並ぶ名前で、最初の `RUN` より前に置かれ、doc の除外の後に copyright の取り込みがあり、changelog・info・man・`/usr/include/node` を外す | 名前を `devbase-excludes`(`excludes` より前)にする・`COPY` を最初の `RUN` の後へ動かす・copyright の取り込みを消す・`/usr/include/node` の行を消すと落ちる |
+| I5(受け入れ条件 5・残る文書の削除) | 最初の `RUN` と利用者の層の `RUN` は、どちらも `/usr/share/doc` の下の copyright でないファイルとディレクトリを指さない symlink を消す(`find /usr/share/doc` に `! -type d` と `! -xtype d` と `! -name copyright` と `-delete` がある)。利用者の層の `RUN` ではその `find` が `sudo find` である | どちらかの `RUN` から削除を消す・`! -name copyright` を外す・`! -type d` を `-type f` に変える(symlink が残る)・`! -xtype d` を外す(ディレクトリを指す symlink が消え copyright への経路が失われる)・利用者の層の `sudo` を外すと、その `RUN` を挙げて落ちる |
+| I6(受け入れ条件 11) | `containers/base/dind` が無く、Dockerfile に `/usr/local/bin/dind` が無い | `dind` を戻す・`COPY` を戻すと落ちる |
+| I7(受け入れ条件 9) | `ENABLE_DIND` が `true`・`1` のとき、DinD の知らせが 1 行だけ出て 0 で返り、`sudo`・`dockerd`・`docker`・`rm` を呼ばない | 知らせの後に `docker info` を待つ・docker.sock を消す・dockerd を起こす・0 以外で返るように壊すと落ちる |
+| I8(受け入れ条件 10) | `ENABLE_DIND` が無い・`false`・空のとき、何も出さずに 0 で返る。既存の entrypoint の試験が変わらず通る | 未設定でも知らせを出すように壊すと落ちる |
+| 受け入れ条件 1〜5(建てた base) | arm64 と amd64 で建てた base で、ubuntu の利用者のログインシェル(`docker run --rm --entrypoint bash devbase-base:latest -lc '<コマンド>'`)で確かめる。`/home/ubuntu/.local/bin` は `ENV PATH` に無く `~/.profile` が足すため、`-lc` でない `bash -c` では変更の前後どちらでも `uv` が見つからない。`ENV PATH` に足して通すと受け入れ条件 14 を破る。`command -v dockerd`・`command -v containerd` が失敗し、`docker --version` などの 5 つが 0 で終わり、`npm ls -g aws-cdk-lib` が空で、`/var/lib/apt/lists`・`/usr/share/man`・`/usr/include/node`・`/usr/share/doc` が条件どおりである(`find /usr/share/doc ! -type d ! -xtype d ! -name copyright` が 0 件で、`dpkg-query -W -f '${Package}\n'` の各パッケージのうち元の base で `/usr/share/doc/<パッケージ>/copyright` を読めた物が、変更後も読める。`libgcc-s1` などの symlink の先を含む) | 手動確認(マージ前)。出力を PR に記録する |
+| 受け入れ条件 6 | 前提 8 の形で前後の展開後の大きさの差が 450,000,000 バイト以上 | 手動確認。届かなければ内訳を PR に書いて人へ戻す |
+| 受け入れ条件 8 | 変更後の base から派生 7 つが建つ | 手動確認。建たなければ外した物を前提にした手順を直す |
+| 受け入れ条件 9(建てた base) | `ENABLE_DIND=true` で起こしたコンテナの起動の出力に知らせが 1 行あり、完了の印ができる | 手動確認。出力を PR に記録する |
+| 受け入れ条件 12 | `env -u DEVBASE_ROOT uv run --locked pytest tests/ -q` が通る | ShellCheck の対象に `dind` が残ると、既存の試験が落ちる |
+| 受け入れ条件 13 | `CHANGELOG.md` の `[Unreleased]` に、外した 5 つと DinD の廃止(破壊的変更・ホストの docker.sock を使う)がある | 実装のレビューで見る |
+| 受け入れ条件 14 | base の Dockerfile の差分が、次の 6 つの変更(除外の `COPY`・apt の層・root の道具の層・`PATH`・片付け・`dind` の `COPY`)だけである | 実装のレビューで `git diff main -- containers/base/Dockerfile` を見る |
+
+## 設計の結果
+
+| 課題 | 扱い | 取り込み先 | 触るファイル |
+| --- | --- | --- | --- |
+| #400 | 実装する | — | `containers/base/Dockerfile`、`containers/base/dpkg-excludes`、`containers/base/dind`、`containers/base/entrypoint.sh`、`tests/containers/`、`.github/workflows/ci.yml`、`docs/developer/contributing.md`、`docs/specifications/`、`docs/glossary/glossary.json`、`docs/glossary.md`、`CHANGELOG.md` |
+
+## 未確認のまま残ること
+
+| 項目 | 内容 |
+| --- | --- |
+| 大きさの見込み | docker-ce・containerd・root の uv の値は課題の本文の実測で、この設計では測り直していない。450MB に届くかは E5 で決まる。届かなければ人へ戻す |
+| amd64 の確かめ方 | WSL2 の端末で建てるか `docker buildx build --platform linux/amd64` で建てるかは実装の担当が決め、PR に書く(要求の前提 7) |
+| node のヘッダの無い環境 | ネイティブアドオンを入れるプロジェクトで node-gyp がヘッダを取得できるか(要求の前提 6)は、リリース後テストで利用者のプロジェクトで分かる |
+| 派生の apt の文書 | latex・php・php85 が自分で入れるパッケージの文書も外れる。実行時に `/usr/share/doc` の中身を読む道具が派生にあるかは、派生を建てて使うまで分からない |
+| #402 の要求との食い違い | #402 の前提 5 は amd64 の Chrome を base に残すとしているが、#401 がそれを外す。#402 の設計で前提を直す必要がある(#402 へ書き残した) |
+| 共通の部品の置き場 | #400 の試験が import する `Instruction` / `parse` の置き場の名前は #403 の実装で決まる。#400 の実装の担当は #403 の後の main で確かめる |
diff --git a/issues/issue-400-requirements.md b/issues/issue-400-requirements.md
new file mode 100644
index 00000000..6112a807
--- /dev/null
+++ b/issues/issue-400-requirements.md
@@ -0,0 +1,169 @@
+# #400: base から使う者が見当たらない中身を外す(dockerd・aws-cdk-lib・root の uv・apt の片付けの漏れ)
+
+正は課題の本文(#400)で、この文書はその写しである。`spec-copy.py write` で作り直す。手で直さない。
+
+## 依頼(原文)
+
+> base イメージから、使う者が見当たらない中身と片付けの漏れを外す。base の削減の段階 1(段階 2・3 は別の課題)。利用者は 2026-10-03 にこの削減を承認した(MVV の P1)。
+>
+> | 中身 | 場所 | 大きさ | 外す根拠 |
+> | --- | --- | --- | --- |
+> | `docker-ce` と `containerd.io`(dockerd と containerd) | `containers/base/Dockerfile:71` | 106+81MB | DinD でだけ使う。`ENABLE_DIND` を設定している箇所はリポジトリとプラグインに見当たらない(`grep -rn ENABLE_DIND`)。プロジェクトはどれもホストの docker.sock を mount する。CLI・buildx・compose は残す |
+> | グローバルの `aws-cdk-lib` | `Dockerfile:159` | 181MB | Node はグローバルのモジュールを `require` で探さず、CDK のアプリは自分の package.json に持つ。CLI の `aws-cdk` は残す |
+> | root の uv | `Dockerfile:156` | 40MB | ubuntu の uv(`Dockerfile:211`)と重複し、root で uv を使う処理が見当たらない |
+> | `/var/lib/apt/lists` | `Dockerfile:235-245` | 42MB | `playwright install --with-deps` の `apt-get update` が残し、片付けが消していない |
+> | `/usr/share/doc`・`man`・`/usr/include/node` など | apt の層 | 約 75MB | 実行時に読まない。dpkg の path-exclude で入れない |
+>
+> 決めること:
+> - DinD の扱い: `containers/base/dind` と entrypoint の `ENABLE_DIND` の分岐を消すか、dockerd を入れたうえで使う派生へ移すか
+> - path-exclude で外す置き場の範囲(copyright は残す)
+>
+> 受け入れ条件(起票時):
+> 1. 建てた base(arm64・amd64)に上の中身が無い。docker CLI・`docker buildx`・`docker compose`・`aws-cdk`・ubuntu の uv は動く
+> 2. 展開後の大きさが arm64 で 450MB 以上減る(`du -sbx /` の前後で測り、PR に記録する)
+> 3. lfm が建ち、`tests/containers/` が通る(lfm は自分で docker-ce を入れるため影響しない見込み)
+> 4. DinD を廃止するなら、利用者向けの文書と CHANGELOG に書く
+>
+> 由来: スプリント m7b の振り返りの後、利用者が「base が機能盛りすぎで肥大化している」として削減のプランを求めた(2026-10-03)。
+
+## 目的
+
+- base を建てる時間・取得する量・ディスクの消費を、誰も使っていない中身の分だけ減らす(MVV の Value 1「base を重くしすぎず、重い道具は派生イメージに置く」)
+- 利用者がコンテナの中で使う道具(docker CLI・buildx・compose・`cdk`・uv)は、削減の前と同じに使える
+
+## 調べて分かったこと(2026-10-03)
+
+| 事実 | 出所 |
+| --- | --- |
+| entrypoint の DinD の分岐は `ENABLE_DIND` が `true` / `1` のときだけ動き、最初に `/var/run/docker.sock` を消してから `dind dockerd` を起こし、`docker info` を最大 30 秒待つ | `containers/base/entrypoint.sh:862-` |
+| `ENABLE_DIND` を設定している compose・env は、このリポジトリと手元のプラグイン(`repos/` の下)に見当たらない。利用者向けの文書(`docs/`・`README`・`CHANGELOG.md`)にも DinD の案内は無い | `grep -rn "ENABLE_DIND\|DinD" docs README* CHANGELOG.md lib` と `grep -rln "ENABLE_DIND\|dockerd" repos/ projects/`(当たりはプラグインの 1 つ(proj-a)の compose の注記だけで、ホストの dockerd を指す) |
+| base を `FROM` で継ぐ派生イメージは bi-tools・general・go・latex・php・php85・trygroup。dpkg の設定(`/etc/dpkg/dpkg.cfg.d/`)は継がれ、latex・php・php85 は自分で `apt-get install` する | `containers/*/Dockerfile` |
+| 派生イメージに root で uv を使う手順は無い(bi-tools の `uv tool install` は `USER ubuntu` の下) | `containers/bi-tools/Dockerfile:29-47` |
+| CI はイメージを建てない。イメージの確かめは手元で行う | `.github/workflows/ci.yml` |
+| DinD を前提に作られた唯一の派生 lfm(自分で dockerd を入れ、base から `dind` を `COPY --from` で取り込む)は、使うプロジェクトが無く、同じスプリント m7c の #403 で #400 より先に廃止する | #403 の本文・#400 への利用者のコメント(2026-10-03) |
+| `ENABLE_DIND` を設定している compose・env は、手元のプラグイン(`repos/*/`)と `projects/*/` に 0 件である(設計で再び確かめた) | `grep -rIl ENABLE_DIND repos/*/ projects/*/ --include=compose.yml --include=env --include=.env` |
+
+## 前提
+
+- 前提 1(DinD の扱い): DinD を廃止する。base から dockerd と containerd を外し、`containers/base/dind` と entrypoint の `ENABLE_DIND` の分岐(dockerd を起こす手順)を消す。根拠: `ENABLE_DIND` を設定する者がリポジトリ・手元のプラグイン・手元のプロジェクトに無く、DinD を前提に作られた lfm は使う者が無く、#400 より先に #403 で廃止する。起票時の選択肢「消す」「使う派生へ移す」のうち、移す先を使う者がいないため前者を採る(設計で前提を改めた。「変更の記録」)
+- 前提 2: base とその派生で `ENABLE_DIND=true` を設定している利用者はいない(上の調べ)。設定していた利用者は、base を建て直した後に DinD が起きなくなる。entrypoint はこの設定を見つけたら廃止を 1 行で知らせて起動を続け、CHANGELOG でホストの docker.sock を使うよう案内する
+- 前提 3: root で uv を使う利用者・処理は無い。base の root の uv を外した後、`sudo uv` は「コマンドが無い」で失敗してよい
+- 前提 4: グローバルの `aws-cdk-lib` を `require` する利用者は無い。CDK のアプリは自分の `package.json` に `aws-cdk-lib` を持ち、`cdk synth` はそれを使う
+- 前提 5: dpkg の除外設定は base を `FROM` で継ぐ派生イメージにも効き、派生が後から apt で入れるパッケージの文書も入らなくてよい(copyright は残る)
+- 前提 6: `/usr/include/node` を外すと、npm のネイティブアドオンのビルドでは node-gyp がヘッダを取得する(ネットワークが要る)。これを許す
+- 前提 7: amd64 の確かめは、amd64 の Docker が動く端末(WSL2 の端末など)か、`docker buildx build --platform linux/amd64` で行う。どちらで行ったかを PR に書く
+- 前提 8: 大きさは、建てた base から作ったコンテナで `du -sbx /` を測った値で比べる。前は main の Dockerfile で建てた base、後はこの変更の Dockerfile で建てた base とし、同じ端末・同じ日に建てる(apt と npm の取得する版の差を小さくする)
+- 前提 9: #403(lfm の廃止)が #400 より先にスプリントの統合先へ入る。#400 の起点には `containers/lfm`・`tests/containers/test_lfm_base_settings.py`・`docs/specifications/lfm-base-settings.md` が無く、Dockerfile を読む試験の部品(`Instruction` / `parse`)は #403 が移した共通の置き場にある。#400 は lfm への影響を考えない(利用者のコメント、2026-10-03)
+
+## 対象範囲
+
+含む:
+- base の Dockerfile から `docker-ce`・`containerd.io`・グローバルの `aws-cdk-lib`・root の uv を外す
+- base の最後の利用者の層で残る `/var/lib/apt/lists` を消す
+- dpkg の除外設定で、`/usr/share/doc`(copyright を除く)・`/usr/share/man` などの文書と `/usr/include/node` を入れない
+- `containers/base/dind` と entrypoint の DinD の分岐を消し、`ENABLE_DIND` を設定したときは廃止の知らせを 1 行出す
+- 外した中身に触れる試験(`tests/containers/`)と仕様(`docs/specifications/`)の追従
+- `CHANGELOG.md` の `[Unreleased]` への記入
+
+含まない:
+- 段階 2・3 の削減(重い道具を派生イメージへ移す・版の固定の見直し)。別の課題
+- lfm の廃止(#403。#400 より先に入るため、#400 は lfm に触れない)
+- base の他の道具の追加・版の変更
+- イメージを建てる CI の追加
+- 利用者の環境で `devbase up` を実行して確かめること(P3。リリース後テストで利用者が行う)
+
+## ドメインイベント
+
+| # | イベント | 引き金 | 失敗したとき | 順序の前提 |
+| --- | --- | --- | --- | --- |
+| E1 | 変更前の base を建て、展開後の大きさを測った | 実装の着手 | 建たなければ main の不具合として別に起票し、測りを止める | — |
+| E2 | 変更後の base を arm64 で建てた | Dockerfile の変更 | 建たなければ変更を直す | E1 |
+| E3 | 変更後の base を amd64 で建てた | E2 の成功 | 建たなければ変更を直す(アーキの差は `case` の分岐で起きやすい) | E2 |
+| E4 | 建てた base の中身を確かめた(外した物が無く、残す道具が動く) | E2・E3 の成功 | 残す道具が動かなければ変更を直す | E2・E3 |
+| E5 | 展開後の大きさを測り、減った量を PR に記録した | E4 の成功 | 450MB に届かなければ、届かない理由と内訳を PR に書いて人へ戻す | E1・E4 |
+| E6 | 変更後の base から、`FROM` で継ぐ派生イメージを建てた | E2 の成功 | 建たなければ、外した物を前提にした取り込みや手順を直す | E2 |
+| E7 | (#403 で対象が無くなったため削除) | — | — | — |
+| E8 | base で `ENABLE_DIND=true` のコンテナを起こし、entrypoint が DinD の廃止を知らせて起動を続けた | E2 の成功 | 起動が止まる・dockerd を起こそうとする・ホストの docker.sock が消えるなら entrypoint を直す | E2 |
+| E9 | 利用者が base を建て直した | main へのマージ(配布) | 建たなければ利用者は前のイメージで動き続ける。リリース後テストで見つける | E2〜E8・マージ |
+
+## 用語
+
+| 用語 | 意味 |
+| --- | --- |
+| DinD | コンテナの中で dockerd を起こし、そのコンテナの中だけの docker を使う形。`ENABLE_DIND` で有効にする。ホストの docker.sock を mount して使う形と区別する。この課題で廃止する |
+| 展開後の大きさ | 建てたイメージから作ったコンテナで `du -sbx /` を測ったバイト数。`docker images` の圧縮後の大きさとは違う |
+| 文書の除外 | dpkg の `path-exclude` の設定で、apt が入れるパッケージから文書などの置き場を展開しないこと |
+
+## 受け入れ条件
+
+- [ ] 1. 変更後の base(arm64・amd64)で、`dockerd`・`containerd` がコマンドとして見つからない(`command -v` が失敗する)
+- [ ] 2. 変更後の base(arm64・amd64)で、ubuntu の利用者として `docker --version`・`docker buildx version`・`docker compose version`・`cdk --version`・`uv --version` がどれも終了コード 0 で版を出す
+- [ ] 3. 変更後の base で、`npm ls -g aws-cdk-lib` に `aws-cdk-lib` が無く、`/root/.local/bin/uv` が無い
+- [ ] 4. 変更後の base で、`/var/lib/apt/lists` の下に `lock` と `partial` のほかのファイルが無い
+- [ ] 5. 変更後の base で、`/usr/share/man` の下と `/usr/include/node` にファイルが無く、`/usr/share/doc` の下には `copyright` のほかのファイルが無い。`/usr/share/doc/<パッケージ>/copyright` は apt で入れたパッケージについて残る
+- [ ] 6. arm64 で、変更前の base と変更後の base の展開後の大きさの差が 450MB(450,000,000 バイト)以上ある。前後の値と差を PR に記録する
+- 7. (#403 で lfm が #400 より先に無くなるため削除。番号は参照を保つため詰めない)
+- [ ] 8. 変更後の base から、`FROM devbase-base:latest` で継ぐ派生イメージ(bi-tools・general・go・latex・php・php85・trygroup)が建つ
+- [ ] 9. `ENABLE_DIND` に `true` か `1` を設定して base のコンテナを起こすと、entrypoint は DinD を廃止したことを 1 行出して起動を続ける。`/var/run/docker.sock` を消さず、dockerd を起こさず、`docker info` を待たない
+- [ ] 10. `ENABLE_DIND` を設定しない base のコンテナの起動は、変更の前と同じ順で同じ用意を行う(entrypoint の既存の試験が通る)
+- [ ] 11. base の Dockerfile が 1〜5 を満たす形であり、`containers/base/dind` が無いことを、Docker を起こさない試験(`tests/containers/` の Dockerfile を読む試験)が固定する。外した物を Dockerfile へ戻すと、その試験が名前を挙げて落ちる
+- [ ] 12. `env -u DEVBASE_ROOT uv run --locked pytest tests/ -q` が通る
+- [ ] 13. `CHANGELOG.md` の `[Unreleased]` に、base から dockerd・containerd・グローバルの `aws-cdk-lib`・root の uv・文書を外したことと、DinD(`ENABLE_DIND`)を廃止したこと(破壊的変更。ホストの docker.sock を使う)を書く
+- [ ] 14. base の Dockerfile の差分は「対象範囲」の含むに挙げた物を外す変更だけで、ほかの道具の追加・削除・版の変更を含まない
+
+## 非機能の条件
+
+| 大項目 | 条件 |
+| --- | --- |
+| 性能・拡張性 | arm64 で展開後の大きさが 450MB 以上減る(受け入れ条件 6) |
+| 移行性 | 利用者は base を建て直すだけで移る。ボリューム・設定・機密は触らない。戻すときは前の Dockerfile で建て直す |
+| システム環境 | arm64 と amd64 の両方で建ち、受け入れ条件 1〜5 を満たす |
+
+## 影響
+
+| 対象 | 影響 |
+| --- | --- |
+| 公開インタフェース | devbase の CLI は変わらない。base のイメージから `dockerd`・`containerd`・グローバルの `aws-cdk-lib`・root の uv・文書が消える。base とその派生での `ENABLE_DIND=true` は DinD を起こさなくなり、廃止の知らせを 1 行出す |
+| データ | 変わらない |
+| 既存の振る舞い | entrypoint の DinD の分岐が無くなる。派生イメージで apt が入れるパッケージの文書が入らなくなる |
+
+## 検証手段
+
+| 項目 | 手段 |
+| --- | --- |
+| 起動 | `devbase build` で base と派生を建てる(建て方は設計で決める) |
+| テスト | `env -u DEVBASE_ROOT uv run --locked pytest tests/ -q` |
+| 静的解析・型検査 | `uvx ruff check --select=E9,F63,F7,F82 lib`・`python3 .github/scripts/proper_term_check.py`・base のシェルスクリプトの ShellCheck(開発参加ガイドの「CI が実行するもの」) |
+| 手動確認(マージ前) | arm64 で建てた base と派生で受け入れ条件 1〜6・8・9 を確かめ、出力と大きさを PR に記録する。amd64 で建てた base で受け入れ条件 1〜5 を確かめ、どの端末・どの方法で建てたかを PR に記録する |
+| 手動確認 | 利用者が自分の環境で base を建て直し、普段のプロジェクトで docker・`cdk`・uv が使えることを確かめる(リリース後テスト。P3 のため利用者が行う) |
+
+## 前提とする取り決め
+
+| 項目 | 参照先 / 決めたこと |
+| --- | --- |
+| プロジェクト構造 | `AGENTS.md` の「このリポジトリ」。イメージの定義は `containers/`、試験は `tests/containers/`、確定仕様は `docs/specifications/` |
+| コーディング規約 | `AGENTS.md` の「書き方」と開発参加ガイド。シェルは ShellCheck を通す |
+| テスト戦略 | Dockerfile の中身は Docker を起こさない試験で固定し(既存の `test_base_dockerfile_*.py` と同じ形)、entrypoint の分岐は既存の entrypoint の試験の形で確かめる。イメージを建てて確かめる条件は手動確認(マージ前)で PR に記録する |
+
+## 境界
+
+| 区分 | 内容 |
+| --- | --- |
+| 常に行う | 全体のテスト・lint・固有の語の検査を push の前に打つ。base を建てる前に `docker system df` で空きを見て、作業用のタグは記録の後に消す(`AGENTS.md` の落とし穴) |
+| 確認してから行う | 対象範囲の外の道具を base から外す・足す・版を変える(P1) |
+| 行わない | 利用者の環境で `devbase up` を実行する(P3)。タグ・Release を作る(P2)。lfm に触れる(#403 で #400 より先に廃止される)。プラグインのリポジトリの compose を直す |
+
+## 未決
+
+| 項目 | 誰が決めるか | 期限 |
+| --- | --- | --- |
+| dpkg の除外設定で外す置き場の一覧(`/usr/share/doc`・`man`・`info`・`locale`・`/usr/include/node` のどこまでか)と、除外設定を置く位置(最初の `apt-get install` より前) | 設計(`design`) | 設計 PR |
+| 外した後の `PATH` の `/root/.local/bin` を残すか消すか | 設計(`design`) | 設計 PR |
+| amd64 を建てる端末と方法(前提 7) | 実装の担当 | 手動確認(マージ前) |
+
+## 変更の記録
+
+| 日 | 工程 | 変えたこと | 理由 |
+| --- | --- | --- | --- |
+| 2026-10-03 | 設計 | 前提 1 を「DinD を lfm に残す」から「DinD を廃止する」へ改め、前提 2・対象範囲・E6〜E8・受け入れ条件 7・9・11・13・影響・境界・未決を合わせて直した | 要求を書いた後に #403 で lfm の廃止が決まり、DinD を使える唯一の派生が無くなる。`ENABLE_DIND` を設定する者も 0 件である |
+| 2026-10-03 | 設計 | #403 が #400 より先に入る前提へ改めた。前提 9 を足し、lfm の事実の 2 行・前提 2・5 の lfm・対象範囲の lfm の取り込み・E6・E7・受け入れ条件 7・影響・検証手段・境界・未決の lfm を消すか直した。E7 と受け入れ条件 7 は番号を詰めずに削除と書いた | 利用者が #403 → #400 → #401 → #402 の順に入れると決め、#400 で lfm への影響を考えなくてよいとコメントした |