# thin-shell-alignment — Design

> **狀態**：草案，待確認。對應 `requirements.md`。
> **建立**：2026-06-27（issue #11）

---

## 1. 設計總綱

四塊，全守 rule 07（能力落 API、薄殼只暴露、讀同一源）：

1. **R1 P0**：CLI run 改打真 trigger 端點（一行修，但要端到端驗）。
2. **R2 P1**：CLI list 改走 `GET /webhooks/named`（KV 源），停止直連 CF KV。
3. **R3 P2**：單邊能力逐項判「補對稱 / 刻意單邊」。
4. **R4 防複發**（治本核心）：能力對照清單 + 本機 smoke test，讓假綠當場現形。

---

## 2. R1：CLI run 死端點（P0）

`cli/run.ts:102` 現打 `${executorUrl}/webhooks/${name}` → 改 `${executorUrl}/webhooks/named/${name}/trigger`。

- 對齊真端點 `webhooks-named.ts:279`（`POST /webhooks/named/:name/trigger`，X-Arcrun-API-Key header）。
- 注意：trigger 端點吃 header api_key + body trigger context（run.ts 現已帶 headers + inputContext，只差路徑）。
- **驗收**：leo21c 部署一個 workflow → `acr run <name>`（本機無該 YAML，走「玩法二」）→ 真的觸發執行（200），非 404。

---

## 3. R2：list 來源統一（P1）

### 3.1 收斂到 `GET /webhooks/named`
- CLI `list.ts` 停止 `CfKvClient` 直連 KV，改 `fetch(${executorUrl}/webhooks/named)`（X-Arcrun-API-Key header）。
- MCP `u6u_list_workflows` 從讀 KBDB record 改讀 `GET /webhooks/named`（經 CYPHER_EXECUTOR binding）。
- 兩者同一端點 → 同源、同欄位（#8 1.3b 已補 `GET /webhooks/named` 回 description/created_at/cron_expr）。

### 3.2 為何 list 讀 KV 而非 KBDB entry（職責分）
- **list = 精確列舉「我有哪些 workflow」** → 讀 KV（部署寫入處，權威）。
- **search = 語意找「做某事的 workflow」** → 讀 KBDB entry（#8 雙寫的 search-entry）。
- 兩者不同職責、不同源頭，本就該分。KBDB entry 是 search 投影，不是 list 真相（避免 list 受 embed 模組開關影響）。

### 3.3 順手修 CLI list 的 key 前綴 bug（核實補充①）
- CLI 直連 KV 讀 `workflow:` 前綴，但部署寫 `{apiKey}:wf:{name}` → 現狀 CLI list 列不到。改走 `GET /webhooks/named` 後此 bug 自然消失（端點內部用正確前綴 `${apiKey}:wf:`）。

---

## 4. R3：P2 單邊能力決策

| 能力 | 現況 | 判定 | 理由 |
|------|------|------|------|
| 驗證 YAML | CLI `acr validate` **純本機**（validate.ts:44，loadWorkflowYaml+parseTriplets+validateRelations，不打端點）；MCP `arcrun_validate_yaml` 打 server `/validate`（introspection.ts:34）| **隱藏漂移，需收斂**（總管 2026-06-27 核實）| 同「驗證 YAML」能力，CLI 走本機、MCP 走 server = 又一個不同源（同 list 病）。收斂：驗證邏輯落 API（/validate）為單一真相，CLI 改打它；或明確記「本機快驗 vs server 權威驗」兩層定位——但**別讓兩邊邏輯漂移**。實作時定，記進對照清單 |
| `acr creds push`（/credentials）| CLI only | **刻意單邊**（記明）| credential 上傳含 client 端加密 + 本機檔案路徑，是 CLI 慣例；AI 不該代傳 credential（mindset §6/§7）。記明非疏漏 |
| `u6u_search_workflows`（/workflows/search）| MCP only | **補 CLI 對稱**（次階段）| 對齊 #8 Phase 5（`acr workflow search`），同端點 |
| recipe 6 能力 / execute | 已對齊 ✅ | — | — |

> 判準：消費者是 AI → MCP 必有；含人類互動/本機檔/敏感操作 → 可刻意單邊但記明。**不強求 1:1**。

### 4.1 實作期發現：tag resource_id 語意債（Phase 2.2，需總管確認）
MCP list 改讀 `GET /webhooks/named`（KV 源，主鍵＝name）後，tag 過濾（`resource_tag` record 的 `resource_id`）出現語意不一致：
- 舊 `u6u_deploy_workflow` 寫 `workflow_metadata` 的 `workflow_id` ＝ `result.workflow_id ?? randomUUID()`（**可能是 UUID**）。
- `u6u_tag_resource` 的 `resource_id` 由用戶傳入（語意不明確，可能 name 也可能 id）。
- 原 list 用 `w.workflow_id` 比對 tag 集合；改讀 KV 源後只有 `name`（KV 無 UUID 概念）。

**過渡處理**：list tag 過濾改用 `name` 比對（KV 源唯一鍵）。舊用 UUID 的 tag 會在 re-tag 後對齊。
**待總管確認**：方向①收斂到 KV（主鍵＝name）後，tag `resource_id` 應統一為 **name**；是否要 backfill 舊 UUID tag？tag 系統不在 #11 明確範圍，但 list 收斂碰到它 → 標記待決，不擅自改 tag 寫入語意。

---

## 5. R4 ⭐：防複發機制（治本核心）

> 根因是假綠（宣稱對齊但端點不存在）。機制目標：**讓「打了不存在的端點」無法悄悄混過**。

### 5.1 推薦：雙層（對照清單 + 本機 smoke test），互補

**層 1：能力對照清單（靜態，文檔 + review 防線）**
- 一張表 `docs/4-guides/cli-mcp-capability-matrix.md`：`能力 | CLI 端點 | MCP 端點 | server route 存在? | 同源?`。
- 新增任何薄殼能力**必填一行**，PR review 對照。
- 治「忘了對齊」+「打不存在端點」的**意識層**。

**層 2：本機 smoke test（動態，端點存在性的客觀證據）** ⭐治本
- 一個**本機手動跑**的 script（`scripts/thin-shell-smoke.sh` 或 `acr selftest`）：對每個薄殼能力打一次真實端點，斷言「非 404」（不要求 200——有些需 auth/資料，但**404 = 端點不存在 = 死端點當場現形**）。
- **守 flag 紅線（C2/R4.2）**：本機/手動觸發，**非 CI、非 cron、非輪詢**。對齊「執行鏈路不依賴 CI」「部署走 local script」既有鐵律。
- 治「假綠」的**客觀層**：宣稱對齊前先跑它，死端點無所遁形。這正是當初 MCP `/workflows/deploy` 會被攔下的機制。

**層 3（輕量，PR 時）**：新薄殼工具 PR 描述附「打的端點在 server route 清單裡」的一行證據（grep route 即可）。低成本、補 review。

### 5.2 為何不單靠 CI smoke
- CI 高頻輪詢真實端點 = 違 flag 紅線（rule 05 §3、避免被 flag 鐵律 §3）。
- smoke 是「宣布完成前手動跑一次」的閘，不是每 push 自動跑。對齊 arcrun「執行鏈路不依賴 CI、稀有驗證才 CI」分層。

### 5.3 機制自驗（R4.3）
- 驗收：故意把某 CLI 工具的端點改成不存在的路徑 → 跑 smoke → **當場報該能力 404 死端點**。證明機制能攔。

---

## 6. 影響面（框架級，C1）

- **改 CLI**：`run.ts`（trigger 路徑）、`list.ts`（改走 cypher proxy 停直連 KV）、可能補 `acr workflow search`。
- **改 MCP**：`u6u_list_workflows`（改讀 GET /webhooks/named）、可能補 validate 對稱。
- **改 cypher**：可能無（複用既有 `GET /webhooks/named`）；確認它回的欄位夠 list 用（#8 1.3b 已補）。
- **新增**：能力對照清單文檔、smoke test script。
- **不改**：deploy 那條（#8/#10）；recipe/execute（已對齊）。

---

## 7. 拍板結果（leo 2026-06-27 issue #11，4 點全定）

1. **Q1 R4 = 雙層（對照清單 + 本機 smoke test）✅** 含 §5.3 機制自驗。守 flag 紅線（本機手動跑非 CI/cron）。
2. **Q2 CLI list = 複用 `GET /webhooks/named`✅**（不新建 proxy，CLI/MCP 同源）。
3. **Q3 P2 判定全照 SDD✅**：validate 補對稱（**但總管核實揭 validate 是隱藏漂移：CLI 純本機、MCP 打 server /validate，需收斂**，見 §4 表）／creds push 刻意單邊記明／search 補 CLI 次階段。
4. **Q4 smoke test = `scripts/thin-shell-smoke.sh` 本機跑 ✅**。

> **狀態：4 點拍定，已點頭實作。** 順序 P0→P1→P2→R4。完成標準＝leo21c 端到端（CLI/MCP 真打通 200 非 404、smoke 能攔故意死端點），非 tsc 綠。
