# Design 補充：`acr init --self-hosted` 一鍵自動化（installer 模式）

> 2026-06-01 初稿 → 2026-06-02 定案改寫（richblack 拍板 installer 形態）。
> 本檔是 `sdk-and-website/design.md` 的單檔補充（規則 02 §4.3 允許）。
> **狀態：design 已與 richblack 對齊；實作前讀 §6 前置依賴。**
> 背景：戰法從 SaaS 轉 self-hosted 開源（docs/HANDOFF-self-host-harness.md §0）。

---

## 1. 定案形態（richblack 2026-06-02）

**arcrun CLI = installer / orchestrator**（類似 rustup / nvm：工具本身小，按需從遠端拉真正內容）。

### 用戶只做 4 件事，中間什麼都不用懂：
1. 申請 CF 帳號
2. 安裝 CF CLI（`wrangler`）
3. 安裝 arcrun CLI（`npm i -g arcrun`）
4. `acr init --self-hosted`（貼 CF Account ID + API Token）→ **完成，其餘看機器跑**

### CLI 自動做（用戶無感）：
- 驗 CF token 權限
- 建 7 個 KV namespace + 1 個 R2 bucket（冪等）
- **從 GitHub release 下載預編譯部署物**（含 24 個 `.wasm` + 各 Worker 的 wrangler.toml + cypher-executor/registry）
- 把建好的 KV namespace id 注入各 wrangler.toml + cypher-executor 的 `WORKER_SUBDOMAIN`
- **`wrangler deploy` 部署全部 Worker**（用戶已裝 wrangler）
- seed auth recipe + API recipe 進 RECIPES KV
- 寫回 `~/.arcrun/config.yaml`
- 印出「手動 `wrangler secret put CF_SECRETS_API_TOKEN`」提示（secret 不自動化，rule 05）

### 關鍵技術決策（richblack 2026-06-02）
| 決策 | 選擇 | 理由 |
|---|---|---|
| 零件部署物 | **預編譯 `.wasm`**（不在用戶端 build）| 用戶不懂 tinygo、也不該懂。下載即用。 |
| 部署工具 | **wrangler**（shell out）| 用戶已裝 CF CLI；self-host 本來就有上傳能力。CLI 不自己重寫 CF Script Upload API。 |
| 源碼來源 | **GitHub release tarball**（含預編譯 wasm）| 版本明確、不需用戶有 git、`acr update` 拉新 release 同一條路。 |
| 為何不是 git clone | repo **沒 commit `.wasm`**（rule 05 build 產物不 commit）→ clone 拿不到 wasm | 必須走含 wasm 的 release artifact。 |

---

## 2. 為什麼是 installer 而非「repo 內掃 wrangler.toml」（推翻初稿）

初稿假設「用戶在 repo 內跑、CLI 掃 wrangler.toml」。**推翻**，因為：
- npm 全域裝的 `acr` 手上**沒有** 24 個 Worker 源碼。
- repo 沒 commit `.wasm`（已查證 `git ls-files .component-builds | grep .wasm` = 0）→ 連 clone 都拿不到可部署的 wasm。
- 用戶不該需要懂 git / tinygo / repo 結構。

→ 正解：CLI 當 installer，從 **GitHub release（含預編譯 wasm）** 拉部署物到暫存目錄，在暫存目錄注入 KV id 後 `wrangler deploy`。

---

## 3. 流程設計（`initSelfHosted` 改寫）

```
acr init --self-hosted
  │
  ├─ 1. 問 2 輸入：CF Account ID + CF API Token
  │     （wrangler 是否已裝？which wrangler；沒裝 → 提示先裝 CF CLI 再來）
  │     驗 token：CF API GET /accounts/{id}/tokens/verify + GET /accounts/{id}
  │     缺權限（Workers Scripts Edit / KV Edit / R2 Edit）→ exit 1 指出缺哪個 scope
  │
  ├─ 2. 建資源（冪等：先 list 已存在就重用）
  │     7 KV：WEBHOOKS / CREDENTIALS_KV / RECIPES / USERS_KV /
  │            SESSIONS_KV / ANALYTICS_KV / EXEC_CONTEXT（rule 01 資料儲存表）
  │     1 R2：WASM_BUCKET
  │
  ├─ 3. 下載部署物：GitHub release tarball → 解壓到暫存目錄 (~/.arcrun/.deploy-<ver>/)
  │     內含：cypher-executor/ + registry/ + .component-builds/*（每個含預編譯 component.wasm + wrangler.toml）
  │
  ├─ 4. 注入設定到暫存目錄的 wrangler.toml（不改用戶 repo，改暫存副本）
  │     - 各 Worker 的 KV binding id ← step 2 建立的
  │     - cypher-executor [vars] WORKER_SUBDOMAIN ← CF API GET /accounts/{id}/workers/subdomain
  │
  ├─ 5. 部署：對暫存目錄每個含 wrangler.toml 的 dir，shell out
  │     `wrangler deploy`（env CLOUDFLARE_API_TOKEN=<token>, CLOUDFLARE_ACCOUNT_ID=<id>）
  │     分兩層：tier1 = .component-builds/*（先）→ tier2 = cypher-executor / registry（後）
  │     每個 wrangler.toml 已含 workers_dev = true → workers.dev URL 自動啟用
  │
  ├─ 6. seed recipe 進 RECIPES KV（部署後打新 cypher URL，或直接 CF KV API 寫）
  │     - auth recipe：重用 AUTH_RECIPE_SEEDS（cypher-executor/src/lib/auth-recipe-seeds.ts）
  │     - API recipe：新增 seed-api-recipes.ts（見 §5）
  │
  ├─ 7. 寫回 config（mode: self-hosted + 所有 id + cypher_executor_url = 部署後 workers.dev URL）
  │
  └─ 8. 印手動 secret 提示：
        wrangler secret put CF_SECRETS_API_TOKEN --name arcrun-cypher-executor
        （credential 值交 CF Workers Secrets 託管；auth 零件不需 secret）
```

### `acr update`（同一條路，未來新零件）
- 拉新 GitHub release → 解壓 → 注入既有 config 的 KV id → wrangler deploy 變動的 Worker。
- 第一期至少做到「重跑等效 init 的部署步驟」；diff-only 部署可後續優化。

---

## 4. 動到的檔案

| 檔案 | 動作 |
|---|---|
| `cli/src/commands/init.ts` | 改寫 `initSelfHosted()`（line 105-131）為 installer 流程 |
| `cli/src/lib/cf-api.ts` | 擴充：KV namespace 建立/list、R2 bucket 建立、subdomain 查詢、token verify |
| 新增 `cli/src/lib/deploy.ts`（暫定）| 下載 release tarball + 解壓 + 注入 wrangler.toml + shell out wrangler deploy |
| 新增 `cli/src/commands/update.ts`（暫定）| `acr update`：拉新 release 重部署 |
| 新增 `cli/src/lib/api-recipe-seeds.ts` | API recipe **種子資料**（installer 用；放 CLI 端，**不放 cypher-executor/src**——rule 02 §2.2 hook 擋 cypher-executor TS hard-code endpoint，且 seed 資料本就屬 installer 職責）|
| 新增 `cypher-executor/scripts/seed-api-recipes.ts` | seed **腳本**（給 prod 補灌用，import CLI 的種子資料；`scripts/` 不受 §2.2 hook 管）|
| `cli/src/index.ts` | 註冊 `acr update` 指令 |

**不動**：cypher-executor 執行路徑、既有零件 wasm 源碼、config 讀取端（config.ts:52 已支援 self-hosted）。

---

## 5. API recipe seed（新增 seed-api-recipes.ts，richblack 2026-06-02 定）

codebase 只有 auth recipe seed。新增 `seed-api-recipes.ts`，把現役 API recipe hard-code 成種子。

### 現役 API recipe（從 prod KV 查得，2026-06-01）
- `kbdb_get`（+ create_block / patch_block / delete / ingest）→ auth_service: kbdb
- `gmail_send` → google_gmail_sa
- `google_sheets_append` / `google_sheets_read` → google_sheets_sa
- `telegram_send` → telegram
- `line_notify_send` → line_notify

### KBDB recipe 採 Supabase 模式（richblack 2026-06-02）
- **KBDB 是 richblack 提供的服務**（跟 arcrun 一樣），採「基礎免費、大量收費」。
- KBDB recipe **進 seed**（展示能力 = 引子，Supabase 模式）。使用者要用 → 去 **arcrun 取統一 API Key**（已有 /register 入口），把 key 設成 credential。
- ⚠️ **FOLLOW-UP（交 KBDB 端）**：現役 endpoint 是 `kbdb.finally.click{{_path}}`。richblack：這是 KBDB 端要改的問題——KBDB 該用統一對外網址提供大家用，不是 finally.click。**seed 先照現況進；KBDB 端改網址後同步更新 seed。** 此事不擋 init 實作。

---

## 6. 部署物產製：commit wasm 進 repo + codeload tarball（richblack 2026-06-02 定案）

> 此節**取代初稿的「GitHub release artifact」構想**。richblack 拍板更輕的做法：
> 直接把預編譯 wasm commit 進 repo，CLI 從 GitHub codeload tarball 拿。不需 release.yml 機制。

### 6.1 策略

- **repo 自帶可部署的 wasm**：刪 `.gitignore` 的 `*.wasm` 排除，commit 預編譯 wasm 進 repo。
  → repo 本身就是部署來源，CLI 直接拿、用戶用自己的 CF token deploy。
- **CLI 走 codeload tarball**：`https://codeload.github.com/richblack/arcrun/tar.gz/{ref}`
  （ref = main 或 tag）。用戶不需 git、版本可控（tag）。`acr update` 拉新 ref。
- **理由**（richblack）：「我在我的 CF 能用 = 我已擁有 wasm；用戶指向我的 GitHub 取得 wasm，
  用他自己的 CF credential deploy。開源，看不看源碼不重要，體驗好最重要。」

### 6.2 ⚠️ 推翻既有鐵律（rule 05）— 需同步改規則

`.claude/rules/05-deploy-convention.md` 明文「`.component-builds/{name}/component.wasm` **不 commit 進 repo**
（build 產物）」「Phase 1-3 暫時 commit 過，**之後會加 .gitignore 清理**」。
**本決策反向**：commit wasm 進 repo（self-host 需 repo 自帶可部署 wasm）。
→ **實作時必須同步改 rule 05 + .gitignore**，否則 pre-write hook / 規則與實作打架。
→ deploy.yml 的 CI rebuild 步驟仍保留（CI 部署 prod 時用最新 source rebuild，與 commit 的 wasm 不衝突；
  commit 的 wasm 是給「self-host 用戶 + acr init」用的部署來源）。

### 6.3 只 commit 部署所需的 wasm（省空間）

- 實況（2026-06-02 查）：`registry/components/*.wasm` 23 個（build 中間產物）+
  `.component-builds/*/component.wasm` 22 個（部署物），共 **~50MB**。
- **部署只需 `.component-builds/*/component.wasm`**（wrangler deploy 認這個）。
  → **只 commit `.component-builds/*/component.wasm`（22 個），不必 commit registry 那 23 個**（省一半）。
  `.gitignore` 改成：保留排除 `registry/components/**/*.wasm`（中間產物），只放行 `.component-builds/**/component.wasm`。
- ⚠️ **誠實 trade-off**（mindset §7）：commit wasm 進 repo → 每次 wasm rebuild 都在 git 歷史累積二進位，
  **repo 長期會膨脹**。可接受（self-host 體驗優先），但記錄此代價；未來若膨脹過劇，再考慮 release artifact / git-lfs。

### 6.3.1 「錯做成零件」的 3 個不 commit（richblack 2026-06-02）

實際 commit 的是 **19 個正當零件**，不是 22。排除的 3 個：`claude_api` / `km_writer` / `kbdb_upsert_block`。
- **原因（richblack 修正「待刪」說法）**：它們**不是 endpoint 薄殼，是把工作流硬塞進零件**（違反 DECISIONS §1）。
  例：`kbdb_upsert_block` 的 upsert 邏輯應在 KBDB API 那邊（API 提供 upsert endpoint），零件只該驅動它；
  現在卻把「GET 找→有則 PATCH 無則 POST」整段工作流塞進零件。本質是工作流/recipe，被錯做成零件。
- **為何「現在就不 commit」而非「先 commit 之後刪」**：commit 二進位進 git 歷史後，即使日後 `git rm`，
  歷史裡仍永久殘留（repo 體積已被佔），除非 rewrite history（很麻煩）。**錯誤的東西不灌進永久歷史。**
- **落地**：`.gitignore` 放行 22 個後**再排除這 3 個**（後出現規則勝出）；`deploy.ts discoverWorkerDirs`
  只部署「同時有 wrangler.toml + component.wasm」的目錄 → self-host 用戶 codeload 拿到的目錄缺這 3 個 wasm → 自然跳過。
- **後續**：這 3 個的降級（變回工作流/recipe）是 BACKLOG 既有待辦，本次不處理，但確保它們不進 self-host 部署來源。

### 6.4 CLI deploy 流程（deploy.ts downloadAndDeploy 補實作）

```
1. 下載 codeload tarball（ref 預設 main，acr update 可帶 tag）→ 解壓 ~/.arcrun/.deploy-<ref>/
2. 讀解壓出的 .component-builds/* + cypher-executor/ + registry/
3. 各 wrangler.toml 注入 ctx.kvNamespaceIds + cypher-executor WORKER_SUBDOMAIN
4. tier1=.component-builds/*（先）→ tier2=cypher-executor/registry（後）
   每個 dir：pnpm install（若有 lock）→ CLOUDFLARE_API_TOKEN=<用戶> wrangler deploy
5. 回 cypherExecutorUrl = https://arcrun-cypher-executor.<subdomain>.workers.dev
```

注意：tier2（cypher-executor/registry）是 TS，wrangler deploy 會在用戶端用內建 esbuild bundle
（不需額外工具，richblack 確認源碼可見不重要、體驗優先 → artifact 含 TS 源碼即可）。

### 6.5 實作順序

1. 改 `.gitignore`（放行 `.component-builds/**/component.wasm`）+ commit 22 個 wasm。
2. 同步改 rule 05（記錄此決策推翻原慣例）。
3. 補實 `deploy.ts downloadAndDeploy`（codeload 下載 + 注入 + wrangler deploy）。
4. **在 1-2 完成前，downloadAndDeploy 維持誠實 unimplemented，不假裝（mindset §7）。**

### 6.6 未來方向：零件按需安裝（richblack 2026-06-02，現在不做）

- 現在 `acr init --self-hosted` **全裝基礎零件**（22 個一次部署）。簡單、夠用。
- **未來若零件數量真的變很多**，再思考「按需安裝」（只裝 workflow 實際用到的零件 / 用戶選裝）。
- **現在不做的理由**（DECISIONS 附錄「會不會累積成債」）：零件目前少且未來絕大多數是 recipe
  （不需 deploy）→ 為「零件爆量」做按需安裝基建 = 為不存在的規模做自動化 = 過度工程。
  零件真的爆量再回頭做，屆時是「未來一次性處理的設計點」，現在不必焦慮。

---

## 7. 驗收標準（客觀證據，mindset §7）

1. richblack 用**全新 CF 帳號** + wrangler 已裝 + 一個 CF API Token 跑 `acr init --self-hosted`
   → 全程無手動建 KV / 無手動 clone / 無 tinygo / 無手動填 namespace id。
2. 跑完印 secret 提示，richblack 手動 `wrangler secret put CF_SECRETS_API_TOKEN`。
3. `acr push` 一個含 http_request + 自建 recipe 的 workflow → trigger → **HTTP 2xx + execution trace**。
4. 冪等：重跑 init 不重建已存在 KV / 不報錯。
5. `acr update` 拉新 codeload tarball（tag）→ 重部署成功。

---

## 7.5 壓測修正（2026-06-04）：fork 帳號裝不起來的四個阻斷項

> 來源：`docs/壓測報告.md`（壓測者：一個「完全不懂程式」的人 + AI 自架）。
> §3/§6 的 installer 流程在**非官方 CF 帳號**上實測**無法完成部署**。根因與修法如下，全部在本 SDD 範圍內（installer 補洞 + R2 dead storage 清除），不是新架構。

### 根因
各 worker 的 `wrangler.toml`（repo 內）寫死了**只有 arcrun 官方帳號才有的綁定**：
- `[[routes]] zone_name = "arcrun.dev"`（每個零件 + cypher-executor）→ fork 沒有此 zone → `wrangler deploy` 找不到 zone 失敗（阻斷 #1）
- `[[r2_buckets]]` + `[ai]`（cypher-executor）→ fork 未必有 R2/AI（阻斷 #2）
- R2 是 dead storage，卻因 CF R2 首次啟用**強制綁信用卡** → 違背「開源免費自架」（阻斷 #3）
- R2 bucket 名 `WASM_BUCKET`（大寫+底線）違反 R2 命名規則 → 證明該碼從未成功跑過（阻斷 #4）

### 修法（只動 `cli/`，**不刪 repo 內 worker toml**）
**關鍵判準**：repo 內 toml 的 `[[routes]]` 是**官方 prod CI 部署**需要的（對外開放零件），直接刪會破壞官方部署。
正解是 `deploy.ts` 在**注入暫存副本**時 strip（§3 step 4 本就「不改用戶 repo，改暫存副本」），因為 deploy.ts 只在 self-hosted 路徑跑。

| 檔案 | 改動 |
|---|---|
| `cli/src/lib/deploy.ts` | 新增 `stripOfficialOnlyBindings()`：注入時移除 `[[routes]]`/`zone_name`/`[[r2_buckets]]`/`[ai]`。worker 靠 `workers_dev=true` 對外。移除 `REQUIRED_R2_BUCKET` |
| `cli/src/commands/init.ts` | 移除 `ensureR2Bucket` 呼叫 + `wasm_bucket` config + token 提示去掉「R2 Edit」+ 結果文案改「7 KV，無需綁卡」 |
| `cli/src/lib/cf-api.ts` | 移除 `ensureR2Bucket()` 方法 |
| `cli/src/lib/config.ts` | 移除 `wasm_bucket?` 欄位 |
| `cli/src/commands/validate.ts` | 錯誤文案「WASM_BUCKET 中找不到」→「registry 中找不到零件」（去命名誤導） |

→ self-hosted 改為**只需 Workers + KV**（皆免費額度、不綁卡），回歸開源免費承諾。

### 客觀證據（mindset §7）
- `stripOfficialOnlyBindings()` 對真實 `auth_static_key`/`cypher-executor` toml 實測：routes/R2/AI 全 strip，name/workers_dev/kv_namespaces/vars 全保留。
- `npx tsc --noEmit` CLI 全綠；`grep R2/WASM_BUCKET src/` 零殘留。

### 報告其他項（本次未動，記錄待辦）
- **#7 init 只能互動式**（readline，無 flag/env）→ AI/CI 不友善。建議支援 `--account-id`/`--api-token` 或讀 env。**待 richblack 決定**。
- **#8 無多帳號/專案 scope**（config 寫死全域 `~/.arcrun/config.yaml`）→ 接案者痛點。報告建議專案層 `.arcrun.yaml` 覆蓋全域（git config 模式）。**屬新功能（change），需 richblack 確認後另開 SDD**。
- **#5/#6 權限前置驗證 + 錯誤訊息**：移除 R2 後 R2 權限問題自然消失；KV 前置一次驗證可後續優化。

## 7.6 壓測修正（2026-06-06）：seed 下沉成 API 行為（推翻 §5「seed 資料放 CLI」）

> 來源：壓測報告 §4.1（seed 機制對所有 self-host 用戶都壞）+ §5.5（薄殼原則）。richblack 點名「薄殼原則寫入鐵律」。
> **此節推翻 §5「種子資料放 CLI 端」+ §8「只動 cli/」的範圍**——seed 改為 API 行為（rule 07）。

### 推翻什麼
§5 原寫「種子資料放 `cli/src/lib/api-recipe-seeds.ts`（installer 職責）」。壓測證明這是 §4.1 bug 的結構根因：
seed 邏輯寫在 CLi `init.ts`（迴圈 POST + `deployFullyOk` gate），registry 一個無關 worker 失敗就連坐讓 seed 永遠被跳過；且 init 從不 seed auth recipe。

### 改法（seed = API 能力，薄殼只呼叫一次）
| 檔案 | 改動 |
|---|---|
| 新增 `cypher-executor/src/routes/init-seed.ts` | `POST /init/seed`：一次灌 API recipe + auth recipe（冪等、直寫 KV、誠實計數）|
| 新增 `cypher-executor/src/lib/api-recipe-seeds.ts` | 種子資料**唯一真相移到 server**（rule 02 §2.2 hook 對 `*-seeds.ts` 整類加例外，richblack 2026-06-06 授權）|
| 刪 `cli/src/lib/api-recipe-seeds.ts` | CLI 重複檔刪除（避免漂移）|
| `cypher-executor/scripts/seed-api-recipes.ts` | import 改指 server 端；備援路徑 |
| `cli/src/commands/init.ts` | `seedApiRecipes` 迴圈 → `callSeedEndpoint` 一次呼叫；移除 deployFullyOk gate |
| `cli/src/commands/update.ts` | 重部署後也呼叫 `/init/seed`；改重解析全部 KV id |
| `cli/src/lib/deploy.ts` | `REQUIRED_KV_NAMESPACES` 加 `SUBMISSIONS_KV`（修 registry 20/21，§4.1.1）|

### 對 §8「為何不違反鐵律」的修正
§8 原寫「只動 cli/ + scripts/」。現在**也動 cypher-executor/src/**（新增 `/init/seed` route + 種子資料），
但**不違反 rule 02 §2.2**：seed 端點只做「讀內嵌種子資料 → 寫 KV」的 routing/資料搬運，不解密/不簽章/不展開 template；
種子的 endpoint 字串是資料宣告（`*-seeds.ts` 類豁免），真正 API 呼叫仍走零件路徑。符合薄殼原則（rule 07）。

## 7.7 壓測修正（2026-06-06）：self-hosted 身份 = 明碼 namespace（不發 api_key）

> 來源：壓測報告 §7.2（seed 通了，但 creds push/push/runtime 全卡「缺少 api_key」）。
> richblack 拍板：self-hosted 不需要「祕密 api_key」，因為它只需要 namespace（分區標籤），不需要認證（你的 cypher 在你自己的 CF，無「別人」會冒用）。

### 根因
credential/部署/執行三條路徑全建在多租戶 `{api_key}:cred:{name}` 模型，但 self-hosted（單租戶）init 從不發 api_key →
`creds push`/`push` 硬要 api_key 而退出；runtime webhook trigger 也要 `X-Arcrun-API-Key` header（公開表單帶不了）。

### 設計（richblack 2026-06-06）
**self-hosted 的「api_key」= 明碼 namespace，用戶在 `.env` 自填。工具不生成、不 hash、不外傳。**
- 一欄（由用戶持有）：
  - `NAMESPACE=leo`（明碼分區標籤，當 KV 前綴；**非密碼**）
- **誠實限制**（mindset §7）：namespace 明碼不提供認證。要防外部呼叫 → 對 webhook 加保護（mindset §6）；arcrun 不做授權判斷（mindset §3）。
- **零分叉**：SaaS 仍走 register 發的真 api_key；self-hosted 走 .env 的 NAMESPACE。**同一條 `api_key` 路徑、同一份 config 解析**，只是值來源不同。

### 改法
| 檔案 | 改動 |
|---|---|
| `cli/src/lib/config.ts` | `ENV_MAP` 加 `NAMESPACE`/`ARCRUN_NAMESPACE` → 對應 `api_key`；新增 `.env` 自動載入（就近往上找，shell > .env，無 dotenv 依賴）|
| `cli/src/commands/creds.ts`、`push.ts` | self-hosted 缺值時，引導設 `.env` 的 NAMESPACE |
| `cli/src/commands/init.ts` | self-hosted 結尾改提示「在 .env 設 NAMESPACE」+「把 CF_SECRETS_API_TOKEN wrangler secret put 進 worker；不想自己跑可明示同意我代設」|
| `cypher-executor/src/routes/webhooks-named.ts` | 新增 `POST /webhooks/named/:ns/:name/trigger`（namespace 走 path，公開表單免 header）；與 header 路徑共用 `triggerNamed`，不分叉 |
| `cli/src/commands/push.ts` | self-hosted 輸出 path-based 公開 webhook URL（免 header）|

### 為何 namespace 進 URL path 安全
namespace 是明碼標籤非密碼，放 path 不洩漏任何祕密。真正的祕密是 credential 值（由 CF Workers Secrets 託管，永不進 URL/path）。要防外部濫用 webhook 是「webhook 保護層」職責，非 namespace。

## 7.8 壓測修正（2026-06-08）：onboarding 四缺陷 → pip 式自我修復安裝（CHANGE，待 review）

> 來源：Haiku 冷啟動壓測（test_arcrun/2/test_record.md）+ richblack 觀察。
> **核心判準（[[haiku-capable-is-design-goal]]）**：Haiku 撞牆 = 介面缺陷，不是換強模型。
> 暴露的四個缺陷都是 onboarding/AI-UX，非功能 bug。**richblack 要的是系統級正解，不是暫時解法/外掛 doctor。**

### 缺陷清單（壓測實證）

| # | 缺陷 | 根因 | Haiku 實際行為（撞牆） |
|---|------|------|------|
| D1 | **安裝不偵測環境**（缺 node/wrangler/CF登入/D1 任一就卡） | init 假設前置齊備，缺了不自己補也不引導 | Haiku 遇 D1 不存在 → **跑去讀原始碼自己想辦法建**（非技術用戶災難） |
| D2 | **帳號 scope：AI 繞過 CLI 自己 curl 全域** | config 優先序**已實作**（專案>全域，config.ts:169-193），但 AI 不用 CLI 讀帳號、自己 curl 猜 → 打到全域 | Haiku curl 全域帳號 URL，非當前 project scope |
| D3 | **MCP 掛不進不提示重啟** | 安裝完 project scope MCP 顯示無法用，沒告訴用戶「MCP 要重啟 client 才載入」 | 用戶以為壞了 |
| D4 | （壓測舊版 1.3.0 無 D1 自動建；1.3.2 已修，但 D1↑ 的「偵測+冪等」更根本） | — | — |

### 正解：安裝流程內建偵測 + 自我修復 + 冪等（pip 式）—— richblack 2026-06-08 拍板

**`acr init`（安裝流程本身）= 像 pip：先偵測環境有什麼、版本對不對，才動手；缺什麼 Arcrun 自己負責裝。
重跑會檢查後說「什麼也沒動」（冪等）。不另做 doctor——偵測是正規安裝流程的一部分。**

1. **偵測先於動作**：init 先檢查各前置（node / wrangler / CF 登入 / D1 / KV / migration）+ 版本 →
   缺的才裝/建、有的跳過、版本不對才升。**不是假設齊備直接動手**。
2. **Arcrun 負責裝它需要的**：缺什麼是 Arcrun 的工作，不丟給 AI/用戶自己想辦法（D1 不存在 → init 自己建+套 migration，
   非讓 AI 讀原始碼）。需人類授權的（建 CF 資源、暴露）仍停下請示（mindset §7 非 TTY 不偽造同意）。
3. **冪等可重跑**：重跑檢查後「什麼也沒動」（像 pip install 已裝），不報錯不重建。
4. **AI 無腦入口 = 一個 GitHub 連結**：AI 讀 README/連結就照著走，**不繞、不讀原始碼、不自己 curl**。
   安裝指示集中在一處，AI 跟著做即可。

### 配套介面（讓 AI 不需也不該猜）

- **`acr whoami` / `acr config show`**（D2 修法）：印「當前生效帳號 + scope 來源（project/global/env）」。
  AI 無腦問 CLI 拿正確帳號，**不自己 curl**。同步加 **MCP `arcrun_whoami`**（薄殼一致，rule 07 §5）。
  → 治本 D2：不是 config 沒實作（已對），是 AI 該用工具讀、不該繞 CLI 猜帳號。
- **MCP 掛載後提示重啟**（D3 修法）：`acr init` / `acr mcp-setup` 寫完 `.mcp.json` 後，
  明確印「⚠️ MCP 已設定，**請重啟 IDE/client 才會載入** project scope MCP」。掛不進時引導重啟，不讓用戶以為壞了。

### 範圍 / 分期（richblack 2026-06-09 授權 P0-P2 執行）

- [x] **P0**：`acr init` 偵測 + 驗收（pip 式）。新增 `cli/src/lib/preflight.ts`：
  - `detectEnvironment()` 安裝前偵測 node/wrangler（缺=fatal 停下給補救指令，不假設齊備直接動手）；
  - `verifyInstall()` 裝完實查 CF（KV/D1 listKv/listD1）+ 打 cypher `/health` 確認真就緒，缺哪項報哪項 + 一鍵補裝（acr update 冪等）。
  - `initSelfHosted` 開頭接 detect（fatal 即 exit 1）、結尾接 verify（未就緒印補裝指引）。冪等沿用 ensureKv/ensureD1。cli tsc exit 0。**2026-06-09 完成**
- [x] **P1**：`acr whoami`（`cli/src/commands/whoami.ts`，人讀 + `--json`，印 mode/帳號/連哪台/來源層，薄殼讀 resolveConfigSources）+ MCP `arcrun_whoami`（`mcp/src/tools/arcrun_whoami.ts`，回報 orgNamespace + binding，與 CLI 對齊）。AI 問工具拿身份，不自己 curl 猜。cli+mcp tsc exit 0。**2026-06-09 完成**
- [x] **P2**：MCP 掛載重啟提示（D3）。`cli/src/commands/mcp-setup.ts` 寫完 `.mcp.json` 後印「⚠ 請重啟 IDE/client 才會載入 project scope MCP」+ 信任工作區提醒。經 init 也會流到（init 呼叫 cmdMcpSetup）。**2026-06-09 完成**
- [~] **P3**：README/GitHub 入口整理成「AI 讀了就照著裝」的單一指引（D 無腦入口）。**部分完成 2026-06-09**：
  - 新增 repo 根 `.env.example` 範本（CF Account/Token 基礎兩格 + NAMESPACE + 服務 token 區，
    每格上面白話說明「去哪申請、怎麼拿」，值留空。`.gitignore` 加 `!.env.example` 放行進 repo）。
  - `llms.txt` step 3 改成「**你（AI）先 `cp .env.example .env`**，帶用戶填值（用戶只填「=」右邊）」——
    把「建 .env 結構」從用戶身上挪到 AI，用戶只做貼值。step 4 補 init「安裝驗收」說明。
  - 仍待：`arcrun.dev/llms.txt` 沒 serve（landing/public 缺檔，404；GitHub repo 內 llms.txt 正常）。
    test/5 prompt 給 GitHub URL 故不阻擋；arcrun.dev serve 另排。

> **誠實**：偵測各前置 + 版本比對 + 冪等重跑工程量不小（跨 CLI 多步）。但「裝很久 + AI 一直繞」對非技術用戶
> 是致命體驗 → 這是 onboarding 必修不是優化。
>
> **2026-06-09 補（test_arcrun/4 壓測根因）**：D1/D2/D3 之上還有更致命的一層——壓測時 AI **整個沒跑 `acr init`**
> （settings.local.json 沒 allow init），導致 D1/harness/MCP/slash-command 全沒裝（全掛在 cmdInit 內）。
> P0 的「偵測+驗收」讓「跑了 init 但環境半殘」能被看見並自癒；但「**根本沒跑 init**」要靠 P3（README/入口
> 引導 AI「第一件事就是 acr init」）+ harness 的 mindset/CLAUDE.md 提醒。P3 後續補。

---

## 8. 為何不違反鐵律

- 只動 `cli/` + 新增 `cypher-executor/scripts/`（seed 腳本，非執行路徑業務邏輯）。
- 不在 `registry/components/` 寫 TS；不在 cypher-executor TS 實作 credential/auth/JWT。
- 不新增 Service Binding。
- secret 不進自動化（§3 step 8 手動）。
- 不重寫部署輪子（用 wrangler，不自寫 CF Script Upload）。
