chore: D22 落地——docs/SDD/wiki/CLAUDE.md 進 repo(Gitea private 預設全 push)

頂層 D22 決策(leo 2026-07-03 拍板):推什麼由開發環境歸屬決定,
Gitea private=除機敏值/build 產物/.github 外全 push。
解 T1.5 卡點:雲端工人 clone 拿得到 credential-store-migration.md,可就地改寫 SDD。
機敏掃描兩輪通過(新增 189 檔約 2.1MB,node_modules/dist/wasm 照舊排除)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-07-03 07:13:15 +08:00
parent c830150da1
commit 5d00e71275
190 changed files with 39486 additions and 14 deletions
@@ -0,0 +1,112 @@
# thin-shell-alignment — Design
> **狀態**:草案,待確認。對應 `requirements.md`。
> **建立**2026-06-27issue #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. R1CLI 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 contextrun.ts 現已帶 headers + inputContext,只差路徑)。
- **驗收**leo21c 部署一個 workflow → `acr run <name>`(本機無該 YAML,走「玩法二」)→ 真的觸發執行(200),非 404。
---
## 3. R2list 來源統一(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. R3P2 單邊能力決策
| 能力 | 現況 | 判定 | 理由 |
|------|------|------|------|
| 驗證 YAML | CLI `acr validate` **純本機**validate.ts:44loadWorkflowYaml+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 不該代傳 credentialmindset §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 tagtag 系統不在 #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 #114 點全定)
1. **Q1 R4 = 雙層(對照清單 + 本機 smoke test)✅** 含 §5.3 機制自驗。守 flag 紅線(本機手動跑非 CI/cron)。
2. **Q2 CLI list = 複用 `GET /webhooks/named`✅**(不新建 proxyCLI/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 綠。
@@ -0,0 +1,95 @@
# thin-shell-alignment — Requirements
> **來源**InkStoneCo 總管 GitHub issue #11[全面對齊] CLI/MCP 薄殼漂移系統性盤點 + 防複發機制,leo 發起)。
> **狀態**:草案,待總管/richblack 確認方向後實作。
> **建立**2026-06-27
> **白名單**`.claude/hooks/pre-write-guard.sh` KNOWN_SDDS 已加(2026-06-27 issue #11 授權)。
---
## 1. 問題:CLI/MCP 系統性漂移,根因=假綠
不是單點 bug,是**系統性漂移**。總管盤查 + 本 SDD 核實確認。
**根因(issue #11 git 史盤查)=假綠**MCP deploy 工具建於 2026-06-06 commit「薄殼原則落地 + 部署一致性」——在宣稱「一致性落地」的**同一次 commit** 裡,MCP deploy 卻打了一個不存在的端點 `/workflows/deploy`(必 404、從未端到端跑過)。違 mindset §7「完成=客觀證據非口頭宣布」。**這就是要防複發機制的理由**——光靠「宣稱對齊」會再犯。
---
## 2. 盤點結果(總管盤 + 本 SDD 核實,file:line
### 🔴 P0 死端點(打的 route 不存在 → 404)
| 能力 | 介面 | 打的端點 | 真端點 | file:line | 歸屬 |
|------|------|---------|--------|-----------|------|
| 部署 | MCP | `/workflows/deploy` | `/webhooks/named`(吃 graph | `mcp/u6u_deploy_workflow.ts:22` | **#8 ①-a + #10 ①-b**(本 SDD 不重複改)|
| 執行已部署 | CLI | `/webhooks/<name>` | `/webhooks/named/:name/trigger` | `cli/run.ts:102` | **本 SDD P0** |
✅ 核實 CLI run 死端點:`run.ts:102``${executorUrl}/webhooks/${workflowName}`(缺 `/named/``/trigger`);真端點 `webhooks-named.ts:279``/webhooks/named/:name/trigger`。確認 404。
### 🟡 P1 架構分歧(同能力不同來源)
| 能力 | CLI | MCP | 問題 |
|------|-----|-----|------|
| list workflow | 直連 CF KV 讀 `workflow:` 前綴(`cli/list.ts:35``CfKvClient`| 讀 KBDB `/records?template=workflow_metadata``mcp/u6u_list_workflows.ts:26`)| 讀不同源 → 列出的東西不一樣,違 rule 07 §4 |
> **本 SDD 核實補充(比總管盤點更深,2 個額外問題)**:
> 1. **key 前綴對不上**CLI list 讀 `workflow:{name}`,但部署(`webhooks-named.ts` kvKey)寫的是 **`{apiKey}:wf:{name}`** → CLI list **永遠列不到新部署的 workflow**(前綴根本不匹配,不只是「來源不同」)。
> 2. **CLI list 直連底層儲存**`CfKvClient` 直打 Cloudflare KV REST API(繞過 cypher)→ 違薄殼更深一層(薄殼不該直碰儲存),且 self-hosted 用戶得有 CF API token 才能 list。
### 🟢 P2 單邊能力(一邊有一邊無)
- CLI only`acr validate`/cypher/search)、`acr creds push`/credentials)。
- MCP only`u6u_search_workflows`/workflows/search#8 新增)。
- 已對齊✅:recipe 6 能力、execute 本機 YAML(兩邊都打 /cypher/execute)。
---
## 3. 需求(issue #11 任務 → 可驗收條目)
### R1P0 死端點修掉
- **R1.1** CLI run 改打 `/webhooks/named/:name/trigger`(真端點),不再 404。
- **R1.2** MCP deploy 死端點**不在本 SDD 修**(歸 #8 ①-a / #10 ①-b,避免三方重複改 deploy);本 SDD 僅記其存在 + 防複發機制要能攔它。
### R2P1 list 來源統一
- **R2.1** CLI 與 MCP list 都讀**同一個 API 端點** `GET /webhooks/named`KV 源,`webhooks-named.ts`),CLI 停止直連 CF KV。
- **R2.2** list 讀 KV 源(部署寫入處),**KBDB search-entry 只供 search 不供 list**(職責分:list=KV 精確列舉、search=entry 語意檢索)。對齊 #8 雙寫設計。
- **R2.3** CLI list 改走 cypher proxy(薄殼不直碰儲存),self-hosted 用戶不需 CF API token 即可 list。
### R3P2 單邊能力盤點決策
- **R3.1** 逐項決定:該補齊對稱的(薄殼出貨標 §5「CLI+MCP 覆蓋同組能力」)vs 刻意單邊的(記明原因,如 `creds push` 屬 CLI 慣例)。
- **R3.2** 不強求每個端點兩邊各開(齊的單位是「能力」非「端點」,decisions-summary 2026-06-15 釐清)。
### R4 ⭐:防複發機制(本 issue 治本核心,不可省)
- **R4.1** 設計一個讓「假綠」無法再悄悄發生的機制。候選(design 評估擇一/組合):
- **能力對照清單**:一張表「能力 × CLI 端點 × MCP 端點 × 同源?」,新增能力必填、review 對照。
- **end-to-end smoke test**:每個薄殼能力對真實端點跑一次(非 tsc 綠),死端點當場現形。
- **PR 證據要求**:新薄殼工具必附「打的端點在 server route 清單裡存在」的證據。
- **R4.2** 守 flag 紅線:smoke test 本機/手動跑,**非 CI 高頻輪詢**。
- **R4.3** 機制本身要可驗:能攔住一個**故意的死端點**(驗收標準,issue #11 明列)。
---
## 4. 約束(頂層鐵律)
- **C1 框架級**:改全 arcrun 用戶 → 先 SDD 確認方向。
- **C2 守 rule 07**:能力只實作一次;薄殼讀同一份來源、不直碰儲存。
- **C3 守 mindset §7**:完成=leo21c 端到端客觀證據(CLI/MCP 真打通 200 非 404),非 tsc 綠。
- **C4 三方協調**#11(全面盤點+防複發)/ #8deploy 強制+search/ #10(編排下沉)有交集,**deploy 那條不重複改**(本 SDD 只盤點 + 防複發涵蓋它)。
- **C5 署名**:跨 repo comment 開頭 `[arcrun CC]`
---
## 5. 非目標
- ❌ 改 deploy 死端點(歸 #8/#10)。
- ❌ 把防複發機制做成 CI 高頻 gateC2 flag 紅線、rule 05 §3)。
- ❌ 強求 CLI/MCP 端點 1:1(齊的單位是能力非端點)。
---
## 6. 開放問題(design 回答 / 待拍板)
- **Q1**:R4 防複發機制採哪個/哪幾個組合?(design 給推薦 + 為何)
- **Q2**CLI list 改走 cypher proxy,需不需要新 proxy 端點,還是複用 `GET /webhooks/named`?(後者已存在,傾向複用)
- **Q3**:P2 單邊能力,哪些補對稱、哪些刻意單邊?(design 逐項給判準)
- **Q4**smoke test 放哪(CLI 自帶 `acr selftest`?獨立 script?)、怎麼「本機手動跑非輪詢」?
@@ -0,0 +1,56 @@
# thin-shell-alignment — Tasks
> **狀態**:方向待確認,**尚未實作**(全 `[ ]`)。確認後才動 code。
> 對應 `design.md`。每完成一個立刻標 `[x]`,不批次。
> 建立:2026-06-27issue #11
---
## Phase 0:方向確認(前置)
- [x] 0.1 SDD 三件式寫好,核實總管盤點(P0 CLI run 死端點屬實 + 挖到第三漂移:CLI list key 前綴對不上 + 直連 KV
- [x] 0.2 回報 issue #11 comment(署名 [arcrun CC])— leo 2026-06-27 全拍定,4 點照 SDD
- [x] 0.3 確認 validate 對齊狀態 — **總管核實揭第四漂移:CLI `acr validate` 純本機(validate.ts:44 不打端點)、MCP `arcrun_validate_yaml` 打 server /validate → 需收斂**Phase 3.1 處理)
## Phase 1P0 死端點(R1
- [x] 1.1 CLI `run.ts:102` 改打 `/webhooks/named/:name/trigger`(真端點)— headers 已含 X-Arcrun-API-Key、body 已就緒,只改路徑一行。tsc 綠
- [ ] 1.2 驗證:leo21c 部署 workflow → `acr run <name>`(本機無 YAML 走玩法二)→ 觸發 200 非 404
- [ ] MCP deploy 死端點不在本 SDD,歸 #8 ①-a / #10 ①-b
## Phase 2P1 list 來源統一(R2
- [x] 2.1 CLI `list.ts``CfKvClient` 直連 KV,改 `GET /webhooks/named`X-Arcrun-API-Key)— 整段改寫,tsc 綠
- [x] 2.2 MCP `u6u_list_workflows` 改讀 `GET /webhooks/named`(取代讀 KBDB recordtag 過濾仍走 resource_tag)— registry 簽名加 partnerTokentsc 綠。⚠️ tag resource_id 語意債(UUID vs name)記 design §4,待總管確認 tag 收斂
- [x] 2.3 確認 `GET /webhooks/named` 回欄位夠 list 用(#8 1.3b 已補 description/created_at/cron_expr)— CLI/MCP 都讀 name/description/created_at
- [ ] 2.4 驗證:CLI list 與 MCP list 對同帳號回**同一組** workflow(同源、欄位齊);key 前綴 bug 消失(列得到新部署的)
- [ ] 2.5 驗證:self-hosted 用戶不需 CF API token 即可 list(走 cypher 不直連 KV
## Phase 3P2 單邊能力(R3
- [⏸] 3.1 validate:核實完成——**真漂移且依賴 #10**。CLI 本機驗 YAMLloadWorkflowYaml+parseTriplets+validateRelations);MCP 打 server /validate 但傳的是已解析的 `{nodes,edges}` graphgraphSchema.safeParse)。兩邊**輸入不同層**YAML vs graph),與 deploy 的 YAML→graph 編排債同根。乾淨收斂依賴 #10 編排下沉(YAML→graph 變 API 能力後 validate 才能統一吃 YAML)。**標記依賴 #10,記對照清單,不在本 SDD 強收**
- [ ] 3.2 creds push:記明「刻意單邊」於能力對照清單(含原因:含加密+本機檔,AI 不代傳 credential
- [ ] 3.3 searchCLI `acr workflow search` 對稱補(次階段,同 #8 Phase 5
## Phase 4 ⭐:防複發機制(R4,治本)
- [x] 4.1 能力對照清單 `docs/4-guides/cli-mcp-capability-matrix.md`(能力×CLI端點×MCP端點×route存在?×同源?)— 13 能力盤好,標 3 個已知債連 SDD
- [x] 4.2 本機 smoke test `scripts/thin-shell-smoke.sh`:對每能力打真端點斷言非 404(本機手動跑,非 CI/cron/輪詢)— 跑 prod 通,死端點 exit 1
- [x] 4.3 機制自驗:注入故意死端點 `/this-route-does-not-exist-xyz` → smoke 當場攔下列入死端點清單、exit 1(證明能攔)✅
- 📌 **副產品實證**smoke 對 prod 跑揭出 `search_workflow`/`backfill` 報 404 — 非 bug,是「#8 code 已寫但 prod cypher 未部署」的假綠被當場揭出(正是 #11 治本要點)
## Phase 5:收尾
- [ ] 5.1 tsc 全綠(cli / mcp / cypher 受影響者)
- [ ] 5.2 leo21c 端到端:對齊後的能力 CLI/MCP 都真打通(200 非 404)、防複發機制驗收可攔死端點
- [ ] 5.3 issue #11 comment 回報端到端證據;由實證決定結案
---
## 鐵律提醒
- 能力落 API、薄殼讀同一源、不直碰儲存(rule 07)。
- 完成=leo21c 端到端客觀證據非 tsc 綠(mindset §7,這正是 #11 要治的假綠)。
- smoke test 本機手動跑,非 CI 高頻(flag 紅線)。
- deploy 那條不重複改(#8/#10 處理)。
- 跨 repo comment 署名 [arcrun CC]。