7bd7b4b26a
- 鋪檔(自 system-dev-template v1.15.0):SDD-LIFECYCLE.md+pending-changes.md +sdd-guard.sh(覆蓋舊版,加單一活性檢查)+sdd-check.md+sdd-active-check.sh - settings.json PreToolUse(Write|Edit|MultiEdit)掛上 sdd-guard.sh - 全部 SDD design.md 掛 frontmatter:portal-auth=active(現行 portal 線, #61 demo 四件套剛 merge);artifact-sharing=draft(零任務動工); 其餘 16 份=paused(皆有未完成任務,無明顯死件,不硬 close) - CLAUDE.md 加「SDD 生命週期鐵律」段(指向 SDD-LIFECYCLE.md+濃縮五條) +SDD 速查表改以 frontmatter status: active 為現行判準 - 驗證:sdd-active-check exit 0(恰 1 份 active);guard pipe-test code 檔 exit 0 帶現行 SDD 提示;反向測試(造 2 份 active)guard exit 2/check exit 1 全擋 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
118 lines
7.6 KiB
Markdown
118 lines
7.6 KiB
Markdown
---
|
||
status: paused
|
||
superseded_by: ""
|
||
---
|
||
|
||
# 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 綠。
|