arcrun — AI workflow execution engine (clean history)

Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。

此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在
richblack/arcrun 與本地 backup 分支)。含:
- acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe)
- recipe push 把關(資料外流提醒 + 打通檢查)
- 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1)
- CLI / cypher-executor / registry / 完整 SDD

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-06-03 15:52:38 +08:00
commit 922a57fe34
485 changed files with 89356 additions and 0 deletions
@@ -0,0 +1,822 @@
# Design Document: u6u Platform Evolution
## Overview
u6u 平台演進的核心目標是將現有的「HTTP endpoint 零件 + 單一 Cloudflare 部署」架構,演進為「WASM 零件模型 + 三層物理部署 + 雙面翻轉畫布」的完整平台。
設計的最高原則是 **Dogfooding**:每一層都是下一層的第一個用戶。底層先建立最小可運行的能力,再用自己的方式往上蓋。這確保每個設計決策都被真實使用場景驗證,而非紙上談兵。
### Bootstrap 順序(不可跳過)
```
Phase 0:最小 WASM 執行核心
→ Component Dispatcher 能在 CF Workers 執行一個 .wasmstdin/stdout JSON
→ validate_json.wasm 作為第一個真實零件(TinyGo< 50KB,驗證整個 pipeline
→ Component Registry API/guide、/validate-contract、/components
Phase 1:遷移現有零件
→ 將 u6u-builtins 的 20 個 HTTP endpoint 逐一遷移為 .wasm
→ 遷移期間 Component Dispatcher 雙模式並存(HTTP fallback
→ 每個零件附帶 component.contract.yaml
Phase 2Cypher 語意擴展 + Multi-Tier Dispatcher
→ 支援 IS_A、ON_SUCCESS、ON_FAIL、CALLS_SUBFLOW、ON_CLICK
→ Component Dispatcher 路由層(Tier 1 CF / Tier 2 workerd / Tier 3 Wazero
Phase 3:前端畫布(用自己的 Web Components 開發)
→ 先建立 Web Components 零件庫(u6u-btn、u6u-card 等)
→ 畫布本身用這些 Web Components 組裝
→ 雙面翻轉介面
```
### 關鍵設計約束
- **KBDB 不變量**:永遠只有三張表(blocks / templates / slots),不新增表
- **API-First 鐵律**:所有跨服務通訊只透過 HTTP API,禁止相對路徑引用
- **零件 I/O 不變量**:唯一合法的 I/O 模型是 `stdin_stdout_json`
- **Tier 3 約束**:無 V8、無 Node.js、無網路,所有零件必須在 Wazero 上跑
---
## Architecture
### 系統全景圖
```mermaid
graph TB
subgraph "Tier 1 — Cloudflare Workers(雲端)"
CE[Cypher Executor<br/>GraphExecutor]
CD[Component Dispatcher<br/>路由層]
CR[Component Registry<br/>KBDB HTTP API]
KBDB[(KBDB<br/>blocks/templates/slots<br/>+ Vectorize)]
R2[(R2<br/>.wasm 二進位)]
CE --> CD
CD --> CR
CR --> KBDB
CR --> R2
end
subgraph "Tier 2 — workerd self-hosted(企業地端)"
T2D[Tier 2 Dispatcher<br/>同 wasi-shim,不同部署]
T2R[本地 Registry 快取]
T2D --> T2R
end
subgraph "Tier 3 — 邊緣載具"
T3E[Go 排程引擎]
Wazero[Wazero Runtime]
SQLite[(SQLite<br/>本地 KBDB)]
DTN[DTN 佇列]
T3E --> Wazero
T3E --> SQLite
T3E --> DTN
end
subgraph "前端"
Canvas[雙面翻轉畫布<br/>React 19 + Web Components]
WC[Web Components 零件庫<br/>u6u-btn / u6u-card / ...]
Canvas --> WC
end
CD -->|WASM 執行| Tier1WASM[.wasm 執行]
CD -->|Cypher binding| ExtSvc[外部服務<br/>MCP / n8n / 任意 URL]
CD -->|HTTP| T2D
T2D -->|Wazero IPC| Wazero
DTN -->|Burst 傳輸| T2D
Canvas -->|u6u:trigger event| CE
```
### Cypher Binding 的正確定義
**Cypher binding** 是 u6u 的核心執行機制,指「用 Cypher 三元組語法把零件串接成工作流,串接關係儲存在 KBDB,不寫死在程式碼裡」。
這個概念相對於 Cloudflare Workers 原生的 **Service Binding**(需要 deploy、串接關係寫死在 wrangler.toml)。
`cypher-executor` 就是執行 Cypher binding 的引擎。
**零件本身只有兩種 component_type**
| component_type | 說明 | 需要 deploy |
|---|---|---|
| `wasm` | 所有後端零件(內建或用戶自建),本地 WASM 執行 | 否 |
| `service_binding` | 多個零件預組合成單一高頻零件的效能最佳化(如 OAuth + GSheets 常用組合) | 是 |
> **重要:`cypher_binding` 不是 component_type。** 它是整個執行引擎的名字,描述「零件如何被串接」,而不是「零件如何被執行」。所有零件(不管是內建還是用戶自建、不管是打外部 API 還是純邏輯)都是 `.wasm`,透過 Cypher 三元組串接。
> **所有後端零件都是 `.wasm`。** 需要呼叫外部 HTTP API 的零件(如 google-sheets、http-request),透過 WASI shim 注入的 **host function** 發出網路請求,不在 .wasm 內部直接呼叫網路 syscall。
### Component Dispatcher 路由決策樹
```mermaid
flowchart TD
A[Cypher Executor 呼叫零件 id] --> B{查 Component Registry<br/>取得合約}
B --> C{component_type?}
C -->|wasm| E{當前 Tier?}
C -->|service_binding| SB{有 CF Service Binding?}
SB -->|是| SBExec[CF Service Binding 執行<br/>需 deploy,效能最佳]
SB -->|否| SBErr[回傳錯誤:binding 未宣告]
E -->|Tier 1 / Tier 2| I[workerd WASM<br/>WebAssembly.instantiate<br/>+ WASI shim(兩者相同)]
E -->|Tier 3| L[Wazero IPC<br/>stdin/stdout,完全離線]
I --> RC{runtime_compat<br/>包含 cf-workers?}
RC -->|否| J[回傳 RUNTIME_INCOMPATIBLE 錯誤]
RC -->|是| Exec[執行 .wasm]
```
### KBDB 資料模型(tpl-component
```mermaid
erDiagram
TEMPLATES {
string template_id "tpl-component"
string name
string description
}
BLOCKS {
string block_id "comp-{id}-{version}"
string template_id
string user_id
string page_name
}
SLOTS {
string slot_id
string block_id
string key
string value
}
TEMPLATES ||--o{ BLOCKS : "defines"
BLOCKS ||--o{ SLOTS : "has"
```
---
## Components and Interfaces
### 1. Component Registry`u6u-core/registry/`
Component Registry 是 KBDB 的薄包裝層,透過 HTTP API 管理零件合約。
#### 零件命名機制
零件有兩個名稱,職責完全不同:
| 欄位 | 由誰決定 | 用途 | 範例 |
|---|---|---|---|
| `display_name` | 建立者自由取 | 顯示用,不影響任何邏輯 | `宇宙無敵 GSheets 超級寫入器` |
| `canonical_id` | Registry AI 正規化後確認 | 搜尋、版本控制、Cypher 引用的唯一鍵 | `gsheets_create_table` |
**canonical_id 正規化流程:**
```
提交者輸入 display_name
Registry 用 Workers AI 建議 canonical_id
(格式:{service}_{verb}_{object},全小寫底線)
同時搜尋 Vectorize,若相似度 > 0.9 的 canonical_id 已存在
→ 提示「可能與 gsheets_create_table 重複,是否作為新版本提交?」
提交者確認或修改 canonical_id
上架,canonical_id 永久不變
```
#### 零件分類機制
採用「強制 category + 自由 tags」雙層分類:
- **`category`**:強制填,有限集合,定義前後端邊界
- `logic`:後端邏輯零件(.wasm,純計算/轉換)
- `api`:後端 API 零件(.wasm + cypher_binding,呼叫外部服務)
- `ui`:前端 UI 元件(Web Component,瀏覽器執行)
- `style`:前端樣式零件(CSS tokens
- `anim`:前端動畫零件
- **`tags`**:自由增加,跨零件共享語意
- 例:`gsheets_create_table``["google", "sheets", "spreadsheet", "storage", "write"]`
- 例:`excel_write_row``["microsoft", "excel", "spreadsheet", "storage", "write"]`
- 搜尋「外部存儲」時,兩個都能透過 Vectorize 語意搜尋找到
**HTTP 端點:**
```
GET /components/guide → 機器可讀開發指引(Markdown)
POST /components/validate-contract → 驗證 component.contract.yaml 格式
POST /components → 提交零件(.wasm + contract)觸發沙盒驗收
GET /components/:id → 取得零件合約(最優版本)
GET /components/:id/versions → 取得所有版本清單(含評分)
GET /components/search?q=... → 語意搜尋零件
```
**KBDB 整合:**
- 每個零件版本 = 一個 Block`block_id = comp-{id}-{version}`
- Template = `tpl-component`(預先建立,不新增表)
- `.wasm` 二進位存 R2KBDB slot 只存 `wasm_r2_key`
- `description` + `tags` 欄位寫入 Vectorize 索引,支援語意搜尋
**Slot 欄位對應(tpl-component):**
| Slot key | 說明 | 範例值 |
|---|---|---|
| `canonical_id` | 正規化功能名稱(永久不變,搜尋/版本控制用) | `gsheets_create_table` |
| `display_name` | 建立者自取的顯示名稱 | `宇宙無敵 GSheets 超級寫入器` |
| `category` | 零件分類(有限集合) | `logic` / `api` / `ui` / `style` / `anim` |
| `version` | 實作版本 | `v1` |
| `wasi_target` | WASM 目標 | `preview1` |
| `stability` | 穩定性標籤 | `floating` |
| `runtime_compat` | 相容 runtimeJSON 陣列) | `["cf-workers","wazero"]` |
| `component_type` | 零件類型 | `wasm` / `service_binding` |
| `max_size_kb` | 體積上限 | `2048` |
| `max_cold_start_ms` | 冷啟動上限 | `50` |
| `no_network_syscall` | 禁止網路 syscall | `true` |
| `input_schema` | JSON SchemaJSON 字串) | `{"type":"object",...}` |
| `output_schema` | JSON SchemaJSON 字串) | `{"type":"object",...}` |
| `gherkin_tests` | 測試案例(JSON 字串) | `[{"scenario":"..."}]` |
| `wasm_r2_key` | R2 物件鍵(wasm 模式) | `components/validate_json/v1.wasm` |
| `service_binding_key` | CF binding keyservice_binding 模式) | `CLINIC_GSHEETS` |
| `description` | 自然語言描述(寫入 Vectorize) | `在 Google Sheets 建立新工作表` |
| `tags` | 自由標籤(JSON 陣列,跨零件共享語意) | `["google","sheets","storage","write"]` |
| `success_rate` | 成功率(0-1 | `0.98` |
| `avg_duration_ms` | 平均執行時間 | `12` |
| `call_count` | 被調用次數 | `1024` |
| `status` | 狀態 | `active` / `deprecated` / `tombstone` |
| `deprecated_at` | 棄用時間戳記 | `1700000000000` |
### 2. Component Dispatcher`cypher-executor/src/lib/component-loader.ts` 擴展)
Component Dispatcher 是 `createComponentLoader` 的升級版,新增 WASM 執行路徑。
**介面定義:**
```typescript
// 零件類型(只有兩種)
type ComponentType =
| 'wasm' // 所有後端零件,透過 Cypher binding 串接,本地 WASM 執行
| 'service_binding'; // 效能最佳化:CF Service Binding,需 deploy,用於高頻預組合零件
// 新版 ComponentDescriptor
type ComponentDescriptor = {
component_type: ComponentType;
// WASM 模式
wasm_r2_key?: string;
runtime_compat?: string[];
max_cold_start_ms?: number;
// Service Binding 模式(CF Worker 間高效呼叫,需 deploy
binding?: string; // wrangler.toml 中宣告的 binding key
path?: string;
};
```
**Tier 1 WASM 執行(CF Workers 原生):**
Cloudflare Workers 原生支援 `WebAssembly.instantiate`,但 WASI preview1 需要手動實作 WASI imports。設計採用輕量 WASI shim 方案:
```typescript
// WASI preview1 shim(只實作 stdin/stdout/stderr,其餘 syscall 回傳 ENOSYS
function createWasiImports(stdin: Uint8Array): {
imports: WebAssembly.Imports;
getStdout: () => Uint8Array;
} {
const stdoutChunks: Uint8Array[] = [];
let stdinOffset = 0;
return {
imports: {
wasi_snapshot_preview1: {
fd_write: (fd: number, iovs: number, iovs_len: number, nwritten: number) => { /* ... */ },
fd_read: (fd: number, iovs: number, iovs_len: number, nread: number) => { /* ... */ },
proc_exit: (code: number) => { throw new Error(`wasm exit: ${code}`); },
// 其餘 syscall 回傳 ENOSYS76
fd_seek: () => 76,
fd_close: () => 0,
environ_get: () => 0,
environ_sizes_get: () => 0,
args_get: () => 0,
args_sizes_get: () => 0,
clock_time_get: () => 0,
random_get: (buf: number, buf_len: number) => { /* crypto.getRandomValues */ return 0; },
},
},
getStdout: () => { /* 合併 stdoutChunks */ },
};
}
```
> **設計決策**:不使用 `@cloudflare/workers-wasi`(已停止維護)。改用自製輕量 WASI shim,只實作 `fd_read`/`fd_write`/`proc_exit`/`random_get`,其餘 syscall 回傳 `ENOSYS`。這足以支援 TinyGo/Rust/AssemblyScript 的 stdin/stdout 零件,且不引入外部依賴。
**執行流程:**
```
1. 從 R2 取得 .wasm 二進位(ArrayBuffer
2. WebAssembly.compile(buffer) → WebAssembly.Module
3. 建立 WASI imports shim(注入 stdin = JSON.stringify(input)
4. WebAssembly.instantiate(module, imports)
5. 呼叫 _start() 或 main()
6. 從 stdout buffer 讀取輸出
7. JSON.parse(stdout) → output
```
**R2 快取策略:**
- 第一次呼叫:從 R2 fetch `.wasm``WebAssembly.compile` 後快取 `WebAssembly.Module`Worker 記憶體,跨請求共享)
- 後續呼叫:直接用快取的 Module,只重新 instantiate(避免重複編譯)
### 3. Cypher Triplet Parser 擴展(`cypher-executor/src/actions/triplet-parser.ts`
現有 parser 只支援 `PIPE / IF / FOREACH / CONTINUE`。需擴展支援新語意關係。
**新增 EdgeType**
```typescript
export type EdgeType =
| 'PIPE' | 'IF' | 'FOREACH' | 'CONTINUE' // 現有
| 'IS_A' | 'ON_SUCCESS' | 'ON_FAIL' // 新增:執行語意
| 'ON_CLICK' | 'CALLS_SUBFLOW' // 新增:觸發語意
| 'CONTAINS' | 'HAS_STYLE' | 'HAS_BEHAVIOR'; // 新增:結構語意
```
**URI 協議解析:**
```typescript
// 節點 componentId 解析
function resolveComponentId(uri: string): {
type: 'component' | 'workflow' | 'ui' | 'style';
canonicalId: string;
stability: 'floating' | 'stable' | 'pinned';
pinnedVersion?: string;
} {
// component://validate_json@stable → { type: 'component', canonicalId: 'validate_json', stability: 'stable' }
// component://validate_json@pinned:v1 → { type: 'component', canonicalId: 'validate_json', stability: 'pinned', pinnedVersion: 'v1' }
// workflow://wf_save_to_db → { type: 'workflow', canonicalId: 'wf_save_to_db', stability: 'floating' }
// ui://u6u-btn → { type: 'ui', canonicalId: 'u6u-btn', stability: 'floating' }
}
```
**ON_SUCCESS / ON_FAIL 執行語意:**
GraphExecutor 需要區分「節點執行成功」vs「節點執行失敗」,而非依賴 context 欄位:
```typescript
// 在 executeNode 中,捕捉 try/catch 後分別走 ON_SUCCESS / ON_FAIL 邊
case 'ON_SUCCESS':
// 只在上游節點成功時執行
if (!nodeError) {
result = await this.executeNode(nextNode, ...);
}
break;
case 'ON_FAIL':
// 只在上游節點失敗時執行(接收 error context
if (nodeError) {
result = await this.executeNode(nextNode, graph, { ...context, error: nodeError }, ...);
}
break;
```
**CALLS_SUBFLOW 執行語意:**
```typescript
case 'CALLS_SUBFLOW': {
// 從 KBDB 載入子 Workflow 定義
const subWorkflowId = nextNode.componentId!.replace('workflow://', '');
const subGraph = await loadWorkflowFromKBDB(subWorkflowId, env);
const subExecutor = new GraphExecutor(loader);
const subResult = await subExecutor.execute(subGraph, result as Record<string, unknown>, kvNamespace);
result = { ...(result as Record<string, unknown>), ...subResult.data as Record<string, unknown> };
break;
}
```
### 4. Web Components 零件庫(`u6u-core/web-components/`
Web Components 以原生 Custom Elements API 實作,不依賴任何框架。
**`<u6u-btn>` 介面:**
```typescript
// HTML attributes
interface U6uBtnAttributes {
label: string; // 顯示文字
color?: string; // 主題色(CSS custom property
tooltip?: string; // 滑鼠懸停提示(純靜態)
workflow?: string; // workflow://id
disabled?: boolean;
}
// 發出的自訂事件
interface U6uTriggerEvent extends CustomEvent {
detail: {
workflowId: string;
payload: Record<string, unknown>;
};
}
```
**`<u6u-card>` Smart Container 邏輯:**
```typescript
// u6u-card 攔截子元件的 u6u:trigger 事件
// 收集同容器內所有 u6u-text-input / u6u-text-field 的值
// 合併至 payload 後再向上冒泡
connectedCallback() {
this.addEventListener('u6u:trigger', (e: Event) => {
const trigger = e as CustomEvent;
e.stopPropagation();
const inputs = this.querySelectorAll('u6u-text-input, u6u-text-field');
const collected: Record<string, unknown> = {};
inputs.forEach(input => {
const name = input.getAttribute('name');
const value = (input as any).value;
if (name) collected[name] = value;
});
this.dispatchEvent(new CustomEvent('u6u:trigger', {
bubbles: true,
composed: true,
detail: {
...trigger.detail,
payload: { ...trigger.detail.payload, ...collected },
},
}));
});
}
```
### 5. 雙面翻轉畫布(`inkstone-admin/frontend/web/`
畫布本身用 React 19 + Web Components 組裝,體現 dogfooding 原則。
**翻轉狀態機:**
```mermaid
stateDiagram-v2
[*] --> UIView: 初始狀態
UIView --> LogicView: 點擊翻面按鈕
LogicView --> UIView: 點擊翻面按鈕
LogicView --> Editing: 修改三元組
Editing --> Saving: 確認儲存
Saving --> LogicView: KBDB 寫入成功
Saving --> LogicView: KBDB 寫入失敗(顯示錯誤)
```
---
## Data Models
### Component Contract YAML(完整規格)
```yaml
canonical_id: "validate_json" # 正規化功能名稱(永久不變,Registry AI 正規化後確認)
display_name: "JSON 格式驗證器" # 建立者自取,顯示用
category: "logic" # logic | api | ui | style | anim
version: "v1" # 實作版本
wasi_target: "preview1" # WASM 目標格式
stability: "floating" # floating | stable | pinned
runtime_compat:
- "cf-workers"
- "workerd"
- "wazero"
constraints:
max_size_kb: 2048
max_cold_start_ms: 50
no_network_syscall: true
no_filesystem_syscall: true
io_model: "stdin_stdout_json" # 唯一合法值
input_schema:
type: object
required: ["json_string"]
properties:
json_string:
type: string
description: "待驗證的 JSON 字串"
output_schema:
type: object
properties:
valid:
type: boolean
error:
type: string
description: "驗證失敗時的錯誤訊息"
gherkin_tests:
- scenario: "合法 JSON 通過驗證"
given: '{"json_string":"{\"key\":\"value\"}"}'
then_contains: '{"valid":true}'
- scenario: "非法 JSON 回傳錯誤"
given: '{"json_string":"not-json"}'
then_contains: '{"valid":false,"error":'
tags: ["validation", "json", "utility"]
description: "驗證輸入字串是否為合法 JSON 格式"
```
### 零件開發語言決策
**內建零件使用 TinyGo**(純邏輯零件)和 TinyGo + `json.RawMessage`(需要任意 HTTP body 的零件)。不引入 Rust 作為內建零件語言。
**用戶自建零件支援三種語言,按難度分層:**
| 語言 | 目標用戶 | JSON 能力 | 備註 |
|---|---|---|---|
| **AssemblyScript** | 一般用戶(TS 背景) | 社群套件 `assemblyscript-json`,支援動態 JSON | 語法最接近 TS,門檻最低;靜默錯誤風險,沙盒驗收必須通過 |
| **TinyGo** | 技術較強用戶(Go 背景) | 靜態 struct 完整支援;`json.RawMessage` 處理任意 body | 編譯期報錯,AI 生成安全性較高 |
| **Rust** | 進階用戶 | `serde_json::Value` 完整動態 JSON | 生態最成熟,體積最小;學習曲線陡 |
**`/components/guide` 端點提供三份語言範例**,用戶根據自身背景選擇。
**內建零件 JSON 策略(TinyGo):**
```go
// 固定 schema 零件(google-sheets、gmail 等)→ 靜態 struct
type Input struct {
SpreadsheetId string `json:"spreadsheet_id"`
Range string `json:"range"`
AccessToken string `json:"access_token"`
}
// 任意 body 零件(http-request)→ json.RawMessage 傳遞 raw bytes,不解析
type Input struct {
URL string `json:"url"`
Method string `json:"method"`
Body json.RawMessage `json:"body"` // 任意 JSON,不解析
}
```
### Workflow Cypher 三元組(完整語法)
```yaml
kind: Workflow
id: wf_submit_form
triplets:
# 節點類型宣告
- "btn_submit >> IS_A >> ui://u6u-btn"
- "step_validate >> IS_A >> component://validate_json"
- "step_save >> IS_A >> component://kbdb_write"
# 前端觸發後端
- "btn_submit >> ON_CLICK >> step_validate"
# 成功/失敗分支
- "step_validate >> ON_SUCCESS >> step_save"
- "step_validate >> ON_FAIL >> step_notify_error"
# 子流程呼叫
- "step_save >> ON_SUCCESS >> CALLS_SUBFLOW >> workflow://wf_notify_user"
# 容器結構
- "card_main >> CONTAINS >> btn_submit"
- "card_main >> CONTAINS >> input_name"
```
### Evaluation BlockKBDB tpl-evaluation
每次 Workflow 執行後,Evaluator Agent 寫入一個 Evaluation Block
| Slot key | 說明 |
|---|---|
| `run_id` | 執行唯一 ID |
| `workflow_id` | Workflow ID |
| `component_id` | 被評價的零件 ID |
| `verdict` | `success` / `failed` / `timeout` |
| `duration_ms` | 執行時間 |
| `error_message` | 失敗訊息(可選) |
| `evaluated_at` | 評價時間戳記 |
### Pitfall BlockKBDB tpl-pitfall
| Slot key | 說明 |
|---|---|
| `component_id` | 問題零件 ID |
| `failure_pattern` | 失敗模式描述 |
| `first_seen_at` | 首次發現時間戳記 |
| `occurrence_count` | 發生次數 |
---
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### Property Reflection(去重分析)
在寫出最終屬性前,先做冗餘分析:
- **1.1 + 1.2**:都是合約欄位完整性驗證,合併為 Property 1「合約格式完整性」
- **2.1 + 2.2**:驗收流程執行 + 失敗回報,合併為 Property 2「沙盒驗收流程正確性」
- **2.3 + 2.4**:提交後可讀取 + 冪等提交,合併為 Property 3「零件提交冪等性與持久性」
- **3.1 + 3.5**WASM 執行 + 雙模式路由,合併為 Property 4「Component Dispatcher 路由正確性」
- **3.4 + 6.4**:不相容 Tier 回傳錯誤 + 結構化錯誤,合併為 Property 5「Dispatcher 錯誤結構完整性」
- **4.1**URI 解析 round-trip,獨立為 Property 6
- **4.2 + 4.4**:版本選擇算法(floating 最高分 + pinned 固定版本),合併為 Property 7「版本選擇策略正確性」
- **4.5**:版本保留不變量,獨立為 Property 8
- **5.7**Confluence 屬性,獨立為 Property 9
- **8.3 + 8.4 + 8.5**Web Components 事件與渲染,合併為 Property 10「Web Components 事件與渲染冪等性」
- **10.6 + 12.5**:評價冪等性 + 查詢冪等性,合併為 Property 11「系統操作冪等性」
最終保留 11 個屬性,每個提供獨立驗證價值。
---
### Property 1: 合約格式完整性
*For any* component contract object,若缺少任何必填欄位(`id``version``wasi_target``stability``runtime_compat``constraints.max_size_kb``constraints.max_cold_start_ms``constraints.no_network_syscall``constraints.io_model``input_schema``output_schema``gherkin_tests`),合約驗證器 SHALL 拒絕該合約並回傳包含缺失欄位名稱的錯誤;反之,包含所有必填欄位的合約 SHALL 通過格式驗證。
**Validates: Requirements 1.1, 1.2, 1.4**
---
### Property 2: 沙盒驗收流程正確性
*For any* 提交的零件(.wasm + contract),若零件在驗收步驟 N 失敗,Component_Registry 的回應 SHALL 包含步驟 N 的名稱與具體失敗原因,且不執行步驟 N+1 之後的步驟。
**Validates: Requirements 2.1, 2.2**
---
### Property 3: 零件提交冪等性與持久性
*For any* 通過驗收的零件(id, version),提交後從 Component_Registry 讀取該零件的合約,所有欄位值 SHALL 與提交時的合約完全一致(序列化 round-trip);對相同 (id, version) 重複提交 N 次,KBDB 中 SHALL 只存在一個對應的 Block。
**Validates: Requirements 2.3, 2.4**
---
### Property 4: Component Dispatcher 路由正確性
*For any* 零件合約,若 `io_model = "stdin_stdout_json"`Component_Dispatcher SHALL 使用 WASM 執行路徑,將 input JSON 寫入 stdin,從 stdout 讀取 output JSON;若 `io_model = "http_endpoint"`SHALL 使用 HTTP 路徑。對任意合法 JSON inputWASM 執行路徑的輸出 SHALL 與 HTTP 執行路徑的輸出語意等效。
**Validates: Requirements 3.1, 3.5, 3.6**
---
### Property 5: Dispatcher 錯誤結構完整性
*For any* (component_id, tier) 組合,若該零件的 `runtime_compat` 不包含當前 tierComponent_Dispatcher 的錯誤回應 SHALL 同時包含:零件 id、當前 tier 名稱、已嘗試的呼叫路徑清單,三個欄位缺一不可。
**Validates: Requirements 3.4, 6.4**
---
### Property 6: 零件 URI 解析 Round-Trip
*For any* 合法的零件 URI 字串(格式為 `component://id``component://id@stable``component://id@pinned:vN`),解析後再重新序列化 SHALL 產生與原始 URI 語意等效的字串;解析出的 `id``stability``pinnedVersion` 欄位 SHALL 與原始 URI 中的對應部分完全一致。
**Validates: Requirements 4.1**
---
### Property 7: 版本選擇策略正確性
*For any* 零件 id 下的版本集合(每個版本有 success_rate、avg_duration_ms、call_count 評分),當 stability = `floating` 時,Component_Dispatcher SHALL 選取「成功率 × 速度評分 × 被調用次數」最高的版本;當 stability = `pinned:vN` 時,無論版本集合中其他版本的評分如何,SHALL 永遠選取版本 vN。
**Validates: Requirements 4.2, 4.4**
---
### Property 8: 歷史版本永久保留不變量
*For any* 已上架的零件版本(id, version),無論該版本後來被標記為 `deprecated``tombstone`,其 `.wasm` 二進位 SHALL 永遠可從 R2 讀取,且 `pinned` 引用 SHALL 永遠能透過 Component_Dispatcher 執行該版本。
**Validates: Requirements 4.5, 10.5**
---
### Property 9: Cypher 三元組解析 Confluence(順序無關性)
*For any* 合法的 Cypher 三元組集合,無論三元組在輸入陣列中的排列順序如何,`parseTriplets` 產生的執行圖(節點集合、邊集合、拓撲結構)SHALL 語意等效——即相同的節點 id 集合、相同的 (from, to, type) 邊集合。
**Validates: Requirements 5.7**
---
### Property 10: Web Components 事件與渲染冪等性
*For any* workflow URI 設定於 `<u6u-btn>``workflow` attribute,使用者點擊後發出的 `u6u:trigger` 事件 detail 中的 `workflowId` SHALL 與 URI 中的 id 完全一致;*For any* 一組具名 `<u6u-text-input>` 元件置於 `<u6u-card>` 內,觸發事件後收集到的 payload SHALL 包含所有輸入元件的 name-value 對;*For any* attribute 值,對同一 Web Component 設定相同 attribute 值 N 次,渲染結果 SHALL 與設定一次相同(冪等渲染)。
**Validates: Requirements 8.3, 8.4, 8.5**
---
### Property 11: 系統操作冪等性
*For any* Workflow 執行日誌(run_id),Evaluator_Agent 對相同 run_id 處理 N 次,KBDB 中 SHALL 只存在一個對應的 Evaluation Block,不產生重複記錄;*For any* Component_Registry 讀取操作的查詢參數,在 KBDB 資料不變的前提下,對相同參數呼叫 N 次 SHALL 回傳完全相同的結果。
**Validates: Requirements 10.6, 12.5**
---
## Error Handling
### Component Dispatcher 錯誤分類
| 錯誤類型 | 觸發條件 | 回應格式 |
|---|---|---|
| `COMPONENT_NOT_FOUND` | KBDB 中找不到零件 | `{ error: "COMPONENT_NOT_FOUND", component_id, tier }` |
| `RUNTIME_INCOMPATIBLE` | runtime_compat 不含當前 Tier | `{ error: "RUNTIME_INCOMPATIBLE", component_id, tier, attempted_paths: [] }` |
| `WASM_EXECUTION_TIMEOUT` | 超過 max_cold_start_ms | `{ error: "WASM_EXECUTION_TIMEOUT", component_id, timeout_ms }` |
| `WASM_INVALID_OUTPUT` | stdout 不是合法 JSON | `{ error: "WASM_INVALID_OUTPUT", component_id, raw_output }` |
| `WASM_SYSCALL_VIOLATION` | .wasm 嘗試網路/檔案 syscall | `{ error: "WASM_SYSCALL_VIOLATION", component_id, syscall_name }` |
| `CONTRACT_VALIDATION_FAILED` | 合約格式不合規 | `{ error: "CONTRACT_VALIDATION_FAILED", missing_fields: [] }` |
### 沙盒驗收失敗回應格式
```json
{
"success": false,
"failed_step": "syscall_scan",
"reason": "發現禁止的 syscallsock_connect",
"guide_anchor": "#syscall-constraints",
"component_id": "my_component",
"version": "v1"
}
```
### Tier 3 離線錯誤處理
Tier 3 在離線環境中,所有無法執行的操作都寫入 DTN 佇列,不拋出錯誤:
```go
// Go 排程引擎的錯誤處理策略
type DTNEntry struct {
Type string // "missing_component" | "sync_log" | "request_wasm"
Payload json.RawMessage
CreatedAt time.Time
RetryCount int
}
```
### Web Components 錯誤邊界
`<u6u-btn>``workflow` attribute 未設定時,點擊不發出事件,僅在 console 輸出警告:
```
[u6u-btn] workflow attribute is not set, click event ignored
```
---
## Testing Strategy
### 雙軌測試策略
本功能採用「單元測試 + 屬性測試」雙軌策略:
- **單元測試(Vitest)**:驗證具體範例、邊界條件、錯誤情境
- **屬性測試(fast-check**:驗證上述 11 個 Correctness Properties,每個屬性最少執行 100 次迭代
### 屬性測試配置
使用 `fast-check`(已在 tech stack 中),每個屬性測試標記格式:
```typescript
// Feature: arcrun-platform-evolution, Property N: {property_text}
it.prop([fc.record({ id: fc.string(), version: fc.string(), ... })])(
'Property 1: 合約格式完整性',
(contract) => {
// ...
},
{ numRuns: 100 }
);
```
### 各 Phase 測試重點
**Phase 0WASM 執行核心):**
- Property 4WASM 執行路徑 round-trip`validate_json.wasm` 作為 ground truth
- Property 1:合約格式驗證
- 單元測試:WASI shim 的 `fd_read`/`fd_write` 正確性
**Phase 1(零件遷移):**
- Property 3:提交冪等性(20 個零件各提交兩次,驗證無重複)
- Property 2:沙盒驗收流程(各步驟失敗案例)
- Property 8:歷史版本保留(deprecate 後仍可讀取)
**Phase 2Cypher 擴展):**
- Property 9Confluence(三元組順序無關性,fast-check shuffle
- Property 6URI 解析 round-trip
- Property 7:版本選擇策略(floating 最高分、pinned 固定版本)
- Property 5:錯誤結構完整性
**Phase 3(前端畫布):**
- Property 10Web Components 事件與渲染冪等性(`@testing-library/react` + fast-check
- Property 11:評價冪等性(Evaluator Agent 重複處理)
### 整合測試
以下場景使用整合測試(1-3 個具體範例,不用 PBT):
- Tier 1 CF Workers 環境中實際執行 `validate_json.wasm`(驗證 WASM 在 Workers 環境可運行)
- KBDB tpl-component Template 建立與 Slot 讀寫(驗證 KBDB 整合)
- R2 `.wasm` 上傳與讀取(驗證 R2 整合)
- Vectorize 語意搜尋(驗證「查詢 Google Sheets 資料」能找到 `gsheets_get_entries`
### 單元測試重點(非 PBT
- WASI shim`fd_read` 正確讀取 stdin、`fd_write` 正確寫入 stdout
- `evaluateCondition`:現有條件評估函數的邊界案例
- `resolveComponentId`:URI 解析的邊界案例(空字串、特殊字元)
- `<u6u-card>` Smart Container:巢狀容器的事件冒泡行為
@@ -0,0 +1,219 @@
# Requirements Document
## Introduction
u6u 平台演進規格描述從現況(HTTP endpoint 零件、單一 Cloudflare 部署、無前端畫布)
到目標架構(WASM 零件模型、三層物理部署、雙面翻轉畫布)的完整演進路徑。
本規格涵蓋三個核心演進軸:
1. **零件模型遷移**:將 20 個內建零件從 Cloudflare Worker HTTP endpoint 遷移至 WASI preview1 `.wasm` 格式,附帶 `component.contract.yaml`,以 stdin/stdout JSON 作為唯一 I/O 模型。
2. **多 Tier 執行抽象**:讓 Cypher Executor 透過統一的 Component Dispatcher 介面,跨 Tier 1Cloudflare Workers)、Tier 2workerd 地端叢集)、Tier 3Go + Wazero 邊緣載具)呼叫零件。
3. **前端雙面畫布**:建立以 Web Components 為基礎的視覺化畫布,正面為 UI 視圖,反面為 Cypher 邏輯視圖,智慧容器自動打包表單值。
---
## Glossary
- **Component(零件)**:系統最小執行單元,一個零件只做一件事,以 `.wasm`WASI preview1)或 Web Component 形式存在。
- **Component_Contract**:每個零件附帶的 `component.contract.yaml`,定義 id、version、wasi_target、stability、runtime_compat、constraints、input_schema、output_schema、gherkin_tests。
- **Component_Registry**KBDB 中儲存所有零件合約與 `.wasm` 位置的索引,以 `tpl-component` Template Block 實作。
- **Component_Dispatcher**Cypher Executor 內部的路由層,根據零件的 `runtime_compat` 與目標 Tier 決定呼叫路徑(Service Binding / workerd HTTP / Wazero IPC)。
- **Cypher_Executor**Workflow 執行引擎,解析三元組語法,透過 GraphExecutor 執行節點,現部署於 Cloudflare Workers。
- **Cypher_Triplet**`"A >> 關係 >> B"` 格式的三元組,描述節點間的語意關係。
- **KBDB**:三位一體記憶庫(blocks / templates / slots),搭配 Cloudflare Vectorize,是平台唯一的持久化狀態來源。
- **Tier_1**:雲端層,Cloudflare Workers + D1 + Vectorize + R2,全球無伺服器部署。
- **Tier_2**:企業地端層,workerd 叢集 + Kùzu 或 PostgreSQL + AGE,高機密內網環境。
- **Tier_3**:邊緣載具層,Go 排程引擎 + 內嵌 Wazero + SQLite,無 V8、無網路的極限環境(無人機、AGV)。
- **WASI_Preview1**WebAssembly System Interface preview1 規格,零件唯一合法的 WASM 目標格式。
- **Canvas(畫布)**:前端雙面翻轉介面,正面為 UI 視圖,反面為 Cypher 邏輯視圖。
- **Smart_Container**:畫布上的排版容器(如 `<u6u-card>`),自動打包同容器內所有輸入元件的值並附加至觸發事件的 payload。
- **Forge_AI**:工匠 AI,負責在 Tier 2 地端接收零件規格、生成 TinyGo 程式碼、編譯並測試 `.wasm`
- **Evaluator_Agent**:強制評價代理,每次 Workflow 執行後自動評估成功率、效能、警告訊息。
- **Pitfall_Block**KBDB 中記錄已知問題的 Block,AI 搜尋時強制讀取以繞道。
- **Stability_Tag**:零件版本穩定性標籤,值為 `floating`AI 自動選最優)、`stable`(人工確認才換)、`pinned`(版本凍結)。
- **DTN**Delay-Tolerant NetworkingTier 3 邊緣載具在間歇性網路下的短點射傳輸協議。
---
## Requirements
### Requirement 1:零件合約規格標準化
**User Story:** As a 平台架構師, I want 每個零件都有標準化的 `component.contract.yaml` 合約, so that AI 能透過統一介面讀取零件能力,並在任何 Tier 上驗證相容性。
#### Acceptance Criteria
1. THE Component_Contract SHALL 包含以下必填欄位:`canonical_id`(功能合約名稱,永久不變)、`display_name`(人類可讀名稱,可自由撰寫)、`description`(語意搜尋用途,需精確描述零件能做什麼、適用情境,至少 20 字)、`version`(實作版本)、`wasi_target`(值為 `"preview1"`)、`stability`(值為 `floating``stable``pinned` 之一)、`runtime_compat`(陣列,值為 `cf-workers``workerd``wazero` 的子集)、`constraints``input_schema``output_schema``gherkin_tests`
1a. THE `canonical_id` SHALL 遵循以下命名規範,以確保全庫一致性:
- 格式:`{scope}_{action}``{scope}_{object}``{scope}`(單詞),全部小寫底線,不超過 4 個單詞
- **整合類**category: api):以服務名稱為 scope,可加動作;範例:`gmail``gmail_send``google_sheets``google_sheets_append``telegram``telegram_send`
- **資料處理類**category: data):以資料型別或操作為 scope;範例:`string_ops``array_ops``date_ops``json_transform`
- **控制流類**category: logic):以控制結構名稱命名;範例:`if_control``foreach_control``try_catch``switch``wait`
- **AI 類**category: ai):以 `ai_` 為前綴;範例:`ai_transform_compile``ai_summarize``ai_classify`
- 禁止:中文、空格、大寫、連字號(`-`)、版本號混入 id`gmail_v2``version: v2` 表達)
1b. THE `display_name` SHALL 為人類可讀的自由格式名稱(可中文、可含空格);此欄位供 UI 顯示用,不作為系統識別符。範例:`canonical_id: google_sheets_append``display_name: "Google Sheets — 新增一列"`
1c. THE `description` SHALL 用於 Vectorize 語意搜尋索引;撰寫時應以「能做什麼、適合什麼情境」為核心,避免只寫零件名稱的同義詞。範例:`"傳送 Gmail 電子郵件,適合 Workflow 完成時通知使用者、訂閱確認信、錯誤警報等場景。需要 Gmail OAuth token。"` 而非 `"Gmail 發信零件"`
2. THE Component_Contract SHALL 在 `constraints` 中包含以下欄位:`max_size_kb`(上限 2048)、`max_cold_start_ms`(上限 50)、`no_network_syscall`(布林值)、`io_model`(值為 `"stdin_stdout_json"`)。
3. WHEN 一個零件的 `id` 已存在於 Component_RegistryTHE Component_Registry SHALL 允許以新 `version` 值新增該零件的新實作,而不覆蓋舊版本。
4. THE Component_Contract SHALL 在 `gherkin_tests` 中至少包含一個正常情境(happy path)與一個錯誤情境(error path)的測試案例。
5. IF 一個零件的 `input_schema``output_schema` 涉及序列化或反序列化操作,THEN THE Component_Contract SHALL 包含一個 round-trip 測試案例,驗證 `parse(format(x)) == x`
---
### Requirement 2:零件沙盒驗收流程
**User Story:** As a 零件提交者(AI 或開發者), I want 提交的零件自動通過沙盒驗收, so that 只有符合品質標準的零件才能進入零件宇宙。
#### Acceptance Criteria
1. WHEN 一個零件被提交至 Component_RegistryTHE Component_Registry SHALL 依序執行以下驗收步驟:(a)體積檢查(`.wasm` 小於 `max_size_kb`)、(b)冷啟動時間測量(小於 `max_cold_start_ms`)、(c)syscall 掃描(不含網路或檔案系統 syscall)、(d)Gherkin 測試執行(所有 scenario 100% 通過)、(e)多 runtime 相容測試(`runtime_compat` 列出的所有 runtime)。
2. IF 任一驗收步驟失敗,THEN THE Component_Registry SHALL 拒絕該零件上架,並回傳包含失敗步驟名稱與具體原因的錯誤訊息。
3. WHEN 所有驗收步驟通過,THE Component_Registry SHALL 將零件合約存入 KBDB 的 `tpl-component` Template Block,並記錄上架時間戳記。
4. THE Component_Registry SHALL 以冪等方式執行驗收流程,對相同 `id``version` 的重複提交回傳相同結果而不重複執行測試。
---
### Requirement 3:現有 HTTP 零件遷移至 WASM
**User Story:** As a 平台開發者, I want 將現有 20 個 HTTP endpoint 零件遷移為 WASI preview1 `.wasm` 格式, so that 零件能在 Tier 3 邊緣載具(無 V8、無網路)上執行,消除技術債。
#### Acceptance Criteria
1. THE Component_Dispatcher SHALL 支援以 WASM 模式呼叫零件:讀取 `.wasm` 二進位、透過 WASI preview1 runtime 執行、將 input JSON 寫入 stdin、從 stdout 讀取 output JSON。
2. WHEN 一個 WASM 零件需要呼叫外部 HTTP API(如 Google Sheets),THE Component_Dispatcher SHALL 透過 host function 注入方式提供網路能力,而非允許 `.wasm` 內部直接發出網路 syscall。
3. THE Component_Dispatcher SHALL 在 Tier 1Cloudflare Workers)環境中,以 `workerd` 內建的 WASM 執行能力執行 WASI preview1 零件。
4. WHEN 一個零件的 `runtime_compat` 不包含當前執行環境的 TierTHE Component_Dispatcher SHALL 回傳錯誤,說明該零件不相容於當前 Tier,而非嘗試執行。
5. THE Component_Dispatcher SHALL 在遷移期間同時支援舊有 HTTP endpoint 模式(Service Binding 或外部 URL)與新 WASM 模式,以 Component_Contract 的 `io_model` 欄位區分呼叫路徑。
6. FOR ALL 現有 20 個內建零件,遷移後的 WASM 版本 SHALL 通過與原 HTTP 版本相同的 Gherkin 測試案例(round-trip 等效性)。
---
### Requirement 4:零件版本控制與穩定性標籤
**User Story:** As a Workflow 設計者, I want 在 Cypher 三元組中指定零件的穩定性需求, so that 關鍵業務流程不會因 AI 自動升級零件而中斷。
#### Acceptance Criteria
1. THE Cypher_Executor SHALL 支援以下三種零件引用語法:`component://id`(預設 floating)、`component://id@stable``component://id@pinned:vN`
2. WHEN 一個 Workflow 引用 `component://id`floating),THE Component_Dispatcher SHALL 從 Component_Registry 選取該 `id` 下「成功率 × 速度 × 被調用次數」評分最高的版本執行。
3. WHEN 一個 Workflow 引用 `component://id@stable`THE Component_Dispatcher SHALL 使用當前標記為 stable 的版本,並在有更優版本時記錄提示至 KBDB,但不自動切換。
4. WHEN 一個 Workflow 引用 `component://id@pinned:vN`THE Component_Dispatcher SHALL 永遠使用版本 `vN`,即使該版本已被標記為 Deprecated。
5. THE Component_Registry SHALL 保留所有歷史版本的 `.wasm` 二進位,不因版本淘汰而刪除檔案。
---
### Requirement 5Cypher 語意關係擴展
**User Story:** As a Workflow 設計者, I want Cypher 三元組支援完整的語意關係集合, so that 能描述條件分支、子流程呼叫、前端觸發等複雜業務邏輯。
#### Acceptance Criteria
1. THE Cypher_Executor SHALL 解析並執行以下語意關係:`IS_A`(節點類型宣告)、`ON_SUCCESS`(成功後繼)、`ON_FAIL`(失敗後繼)、`ON_CLICK`(前端點擊觸發)、`CALLS_SUBFLOW`(呼叫子 Workflow)、`CONTAINS`(容器包含關係)、`HAS_STYLE`(樣式關聯)、`HAS_BEHAVIOR`(行為關聯)。
2. WHEN 解析 `IS_A` 關係,THE Cypher_Executor SHALL 從 Component_Registry 載入對應的零件合約,並以合約的 `input_schema` 驗證節點的輸入 context。
3. WHEN 解析 `ON_SUCCESS``ON_FAIL` 關係,THE Cypher_Executor SHALL 根據上游節點的執行結果(成功或拋出錯誤)決定走向,而非依賴 context 中的特定欄位。
4. WHEN 解析 `CALLS_SUBFLOW` 關係,THE Cypher_Executor SHALL 以當前 context 作為子 Workflow 的 initialContext 執行,並將子 Workflow 的輸出合併回主流程 context。
5. WHEN 解析 `ON_CLICK` 關係,THE Cypher_Executor SHALL 接受來自前端 Smart_Container 打包的 payload,並以該 payload 作為 Workflow 的 initialContext。
6. THE Cypher_Executor SHALL 支援 URI 協議前綴:`component://`(零件引用)、`workflow://`Workflow 引用)、`ui://`(前端零件引用)、`style://`(樣式零件引用)。
7. FOR ALL 合法的 Cypher 三元組序列,THE Cypher_Executor SHALL 保證解析結果的冪等性:對相同輸入三元組集合,無論排列順序,產生語意等效的執行圖(Confluence 屬性)。
---
### Requirement 6Component Dispatcher 多 Tier 路由
**User Story:** As a 平台架構師, I want Cypher Executor 透過統一的 Component Dispatcher 介面呼叫跨 Tier 零件, so that Workflow 設計者不需要知道零件部署在哪個 Tier。
#### Acceptance Criteria
1. THE Component_Dispatcher SHALL 根據以下優先序決定呼叫路徑:(1Tier 1Cloudflare Service Binding(若零件部署為 Worker)或 WASM 直接執行;(2Tier 2workerd 叢集 HTTP endpoint;(3Tier 3Wazero IPCstdin/stdout)。
2. WHEN Component_Dispatcher 在 Tier 1 環境中呼叫一個 `runtime_compat` 包含 `cf-workers` 的零件,THE Component_Dispatcher SHALL 優先使用 Cloudflare Service Binding,若 binding 不存在則退回 WASM 執行模式。
3. WHEN Component_Dispatcher 在 Tier 3 環境中呼叫零件,THE Component_Dispatcher SHALL 只使用 Wazero 執行本地 `.wasm` 檔案,不發出任何網路請求。
4. IF Component_Dispatcher 無法在當前 Tier 找到可用的呼叫路徑,THEN THE Component_Dispatcher SHALL 回傳結構化錯誤,包含:零件 id、當前 Tier、嘗試的呼叫路徑清單。
5. THE Component_Dispatcher SHALL 對每次零件呼叫記錄執行時間(ms)、成功或失敗狀態,並非同步寫入 KBDB 的 Evaluation Block,不阻擋主流程。
6. WHILE Component_Dispatcher 執行零件呼叫,THE Component_Dispatcher SHALL 強制套用 Component_Contract 中的 `max_cold_start_ms` 作為逾時上限,超時後回傳逾時錯誤。
---
### Requirement 7Tier 3 邊緣離線生存能力
**User Story:** As a 邊緣載具操作者(無人機、AGV), I want 載具在完全離線環境中仍能執行預載的 Workflow, so that 業務不因網路中斷而停擺。
#### Acceptance Criteria
1. THE Tier_3 執行引擎 SHALL 在無網路連線的環境中,使用本地 SQLite 作為 KBDB 替代儲存,執行預先下載的 Cypher Workflow 與 `.wasm` 零件。
2. WHEN Tier_3 執行引擎在執行中發現缺少所需零件,THE Tier_3 執行引擎 SHALL 記錄缺失零件的 `id``input_schema` 至本地 DTN 佇列,待下次連網時以 Burst 傳輸方式送至 Tier_2 請求代工。
3. WHEN Tier_3 執行引擎收到來自 Tier_2 的新 `.wasm` 零件,THE Tier_3 執行引擎 SHALL 在執行前對該零件進行 syscall 掃描,確認不含網路或檔案系統 syscall,通過後才載入執行。
4. THE Tier_3 執行引擎 SHALL 在 Cypher 圖譜執行中途動態替換失敗零件(如感測器零件因環境變化失效),以 Component_Registry 中相同 `input_schema` 的備用零件繼續執行,不中斷整體 Workflow。
5. WHEN Tier_3 執行引擎重新連線至 Tier_2THE Tier_3 執行引擎 SHALL 將本地執行日誌(包含 trace、評價結果、Pitfall 記錄)同步至 Tier_2 的 KBDB,確保全局狀態一致。
---
### Requirement 8:前端 Web Components 零件庫
**User Story:** As a 前端開發者, I want 一套以 Web Components 標準實作的 u6u UI 零件庫, so that 畫布上的 UI 元件能在任何現代瀏覽器中獨立運作,不依賴特定前端框架。
#### Acceptance Criteria
1. THE Canvas SHALL 提供以下核心 Web Components`<u6u-btn>`(按鈕)、`<u6u-text-input>`(文字輸入)、`<u6u-text-field>`(多行文字)、`<u6u-chart>`(圖表)、`<u6u-card>`(智慧容器)。
2. THE `<u6u-btn>` SHALL 支援以下 HTML attributes`label`(顯示文字)、`color`(主題色)、`tooltip`(滑鼠懸停提示,純靜態,不觸發 Webhook)、`workflow`(綁定的 Workflow URI,格式為 `workflow://id`)。
3. WHEN `<u6u-btn>``workflow` attribute 被設定且使用者點擊按鈕,THE `<u6u-btn>` SHALL 發出 `u6u:trigger` 自訂事件,事件 detail 包含 `{ workflowId, payload }`
4. THE `<u6u-card>` SHALL 在接收到子元件的 `u6u:trigger` 事件時,自動收集同容器內所有 `<u6u-text-input>``<u6u-text-field>` 的當前值,合併至事件的 `payload` 後再向上冒泡。
5. FOR ALL Web ComponentsTHE Canvas SHALL 保證元件的 HTML attribute 變更能即時反映至視覺渲染,且渲染結果與 attribute 值之間的對應關係具有冪等性(相同 attribute 值永遠產生相同渲染結果)。
---
### Requirement 9:雙面翻轉畫布介面
**User Story:** As a 業務使用者(非工程師), I want 畫布上每個 UI 元件都能翻面查看並編輯其 Cypher 邏輯連線, so that 不需要寫程式就能理解並修改業務邏輯。
#### Acceptance Criteria
1. THE Canvas SHALL 為每個 UI 零件提供「翻面」操作,切換至邏輯視圖後,顯示該零件關聯的 Cypher 三元組(以視覺化節點連線方式呈現)。
2. WHEN 使用者在邏輯視圖中修改 Cypher 連線(新增、刪除或修改三元組),THE Canvas SHALL 即時更新對應 Workflow 的 KBDB Block,並在正面 UI 視圖中反映連線狀態變更(如按鈕顏色或 badge 提示)。
3. THE Canvas SHALL 在邏輯視圖中提供 Workflow URI 選擇器,列出 KBDB 中所有可用的 Workflow,讓使用者透過下拉選單完成 `ON_CLICK >> workflow://id` 的綁定,不需手動輸入 URI。
4. WHEN 使用者在畫布上將兩個 UI 零件拖入同一個 `<u6u-card>` 容器,THE Canvas SHALL 自動在邏輯視圖中顯示 Smart_Container 的自動打包關係,說明哪些輸入值會被自動收集。
5. THE Canvas SHALL 在使用者嘗試替換一個已綁定 Workflow 的 UI 零件時,只顯示 Component_Registry 中具備相同觸發能力(即 `u6u:trigger` 事件)的候選零件,過濾掉不相容的零件。
---
### Requirement 10:自動演化評價迴圈
**User Story:** As a 平台維運者, I want 每次 Workflow 執行後自動觸發 AI 評價, so that 系統能持續識別問題零件並累積避坑知識。
#### Acceptance Criteria
1. WHEN 一個 Workflow 執行完畢(無論成功或失敗),THE Evaluator_Agent SHALL 在執行結束後非同步評估以下維度:執行狀態(成功 / 失敗 / 逾時)、各節點執行時間、零件錯誤率趨勢。
2. WHEN Evaluator_Agent 發現某零件的錯誤率在連續 5 次執行中超過 50%THE Evaluator_Agent SHALL 在 KBDB 中為該零件建立 Pitfall_Block,記錄:零件 id、失敗模式描述、首次發現時間戳記。
3. WHEN Component_Dispatcher 在 Component_Registry 搜尋零件時,THE Component_Dispatcher SHALL 讀取目標零件的所有關聯 Pitfall_Block,並在選擇版本時降低有 Pitfall 記錄的版本的評分權重。
4. WHEN 一個零件連續 30 天無任何 Workflow 引用,THE Component_Registry SHALL 將該零件標記為 `Deprecated`,並從預設搜尋結果中移除,但保留 `.wasm` 二進位與合約。
5. WHEN 一個 `Deprecated` 零件再經過 90 天仍無引用,THE Component_Registry SHALL 將該零件移入墓地(tombstone 狀態),從所有搜尋結果中移除,但 `pinned` 版本的 `.wasm` 永遠保留且可被 Component_Dispatcher 存取。
6. THE Evaluator_Agent SHALL 以冪等方式處理重複的執行日誌,對相同 `run_id` 的重複評價請求回傳相同結果而不重複建立 Pitfall_Block。
---
### Requirement 11:零件開發指引(Component Authoring Guide
**User Story:** As a 零件開發者(使用自己的 AI 工具,如 Claude、GPT、本地模型), I want 平台提供完整的零件開發指引, so that 我的 AI 能根據指引生成符合合約規格的 `.wasm` 零件,並一次通過沙盒驗收。
#### Acceptance Criteria
1. THE Component_Registry SHALL 在 `GET /components/guide` 端點提供機器可讀的開發指引文件(Markdown 格式),內容包含:零件合約 YAML 完整範例、I/O 模型說明(stdin/stdout JSON)、各語言(TinyGo、Rust、AssemblyScript)的最小可運行範例程式碼、本地測試指令(`wasmtime` 執行方式)、常見錯誤與解法。
2. THE Component_Registry SHALL 在開發指引中明確列出所有禁止行為:網路 syscall、檔案系統 syscall、打包 runtimeQuickJS、Node.js 等)、超過 2MB、混合前後端邏輯於同一零件。
3. THE Component_Registry SHALL 在開發指引中提供 `component.contract.yaml` 的 JSON Schema 定義,讓開發者的 AI 能在提交前自行驗證合約格式正確性。
4. WHEN 一個零件提交驗收失敗,THE Component_Registry SHALL 在錯誤回應中附上指向開發指引對應章節的錨點連結(如 `#syscall-constraints`),讓開發者的 AI 能直接定位修復方向。
5. THE Component_Registry SHALL 提供 `POST /components/validate-contract` 端點,接受 `component.contract.yaml` 內容,回傳格式驗證結果(欄位完整性、schema 合法性、gherkin_tests 最低數量),讓開發者在提交 `.wasm` 前先驗證合約。
6. FOR ALL 開發指引中的程式碼範例,THE Component_Registry SHALL 保證範例能通過 Requirement 2 定義的沙盒驗收流程(指引本身是可執行的 ground truth)。
---
### Requirement 12KBDB Component Registry 整合
**User Story:** As a 系統開發者, I want Component Registry 完全以 KBDB 的 Template/Block/Slot 機制實作, so that 零件狀態與平台其他知識共享同一個持久化層,不引入新的資料庫。
#### Acceptance Criteria
1. THE Component_Registry SHALL 以 KBDB 的 `tpl-component` Template 儲存零件合約,每個零件版本對應一個 Block,Block 的 slots 對應合約的各欄位(id、version、wasi_target、stability、runtime_compat、constraints 等)。
2. THE Component_Registry SHALL 以 KBDB 的 Vectorize 索引零件的 `description``tags` 欄位,支援語意搜尋(如「查詢 Google Sheets 資料」能找到 `gsheets_get_entries`)。
3. WHEN Component_Dispatcher 搜尋零件時,THE Component_Registry SHALL 回傳按「成功率 × 速度評分 × 被調用次數」排序的版本清單,最多回傳 10 個候選版本。
4. THE Component_Registry SHALL 透過 KBDB 的 HTTP API 存取所有資料,不直接操作 D1 SQL,符合平台的 API-First 通訊鐵律。
5. FOR ALL Component_Registry 的讀取操作,THE Component_Registry SHALL 保證在 KBDB 資料不變的情況下,對相同查詢參數回傳相同結果(查詢冪等性)。
@@ -0,0 +1,411 @@
# Implementation Plan: u6u Platform Evolution
## Overview
依照 Bootstrap 順序分四個 Phase 實作,每個 Phase 都是下一個 Phase 的基礎。
技術棧:TypeScript、Hono、Zod、Vitest、fast-check,部署於 Cloudflare Workers。
---
## Phase 0:最小 WASM 執行核心
- [x] 1. 建立 Component Registry 基礎架構(`u6u-core/registry/`
- [x] 1.1 建立 `tpl-component` Template Block(透過 KBDB HTTP API
- 呼叫 KBDB `/templates` 建立 `tpl-component` template(若不存在)
- 定義所有 slot keyscanonical_id、display_name、category、version、wasi_target、stability、runtime_compat、constraints、input_schema、output_schema、gherkin_tests、wasm_r2_key、cypher_binding_url、service_binding_key、description、tags、success_rate、avg_duration_ms、call_count、status、deprecated_at
- _Requirements: 12.1_
- [x] 1.2 實作 `POST /components/validate-contract` 端點
- 以 Zod schema 驗證 component.contract.yaml 所有必填欄位
- 回傳缺失欄位清單(`missing_fields: string[]`
- _Requirements: 1.1, 1.2, 11.5_
- [ ]* 1.3 寫 property test for 合約格式完整性
- **Property 1: 合約格式完整性**
- **Validates: Requirements 1.1, 1.2, 1.4**
- 用 fast-check 生成隨機缺少任意必填欄位的合約物件,驗證 validator 必定拒絕並回傳該欄位名稱
- 用 fast-check 生成包含所有必填欄位的合約物件,驗證 validator 必定通過
- [x] 1.4 實作 `GET /components/guide` 端點
- 回傳 Markdown 格式開發指引(TinyGo 白名單、禁止行為、contract YAML 範例、wasmtime 測試指令)
- _Requirements: 11.1, 11.2, 11.3_
- [x] 1.5 實作 `POST /components` 零件提交端點(沙盒驗收流程)
- 依序執行五個驗收步驟:(a) 體積檢查、(b) 冷啟動時間測量、(c) syscall 掃描、(d) Gherkin 測試執行、(e) runtime 相容測試
- 任一步驟失敗立即停止,回傳 `{ success: false, failed_step, reason, guide_anchor, component_id, version }`
- 通過後以 KBDB HTTP API 寫入 Block`block_id = comp-{id}-{version}`
- 同時上傳 `.wasm` 至 R2slot `wasm_r2_key` 記錄 R2 key
- _Requirements: 2.1, 2.2, 2.3_
- [ ]* 1.6 寫 property test for 沙盒驗收流程正確性
- **Property 2: 沙盒驗收流程正確性**
- **Validates: Requirements 2.1, 2.2**
- 用 fast-check 生成在步驟 N 失敗的零件,驗證回應包含步驟 N 名稱與原因,且不執行步驟 N+1
- [ ]* 1.7 寫 property test for 零件提交冪等性與持久性
- **Property 3: 零件提交冪等性與持久性**
- **Validates: Requirements 2.3, 2.4**
- 用 fast-check 生成通過驗收的零件,提交後讀取合約驗證所有欄位 round-trip 一致
- 對相同 (id, version) 重複提交 N 次,驗證 KBDB 只存在一個 Block
- [x] 2. 實作 WASI preview1 shim 與 WASM 執行核心(`cypher-executor/src/lib/`
- [x] 2.1 實作輕量 WASI preview1 shim`wasi-shim.ts`
- 實作 `fd_read`(從 stdin buffer 讀取)、`fd_write`(寫入 stdout/stderr buffer)、`proc_exit`(拋出 Error)、`random_get``crypto.getRandomValues`
- 其餘 syscall 一律回傳 ENOSYS76
- 不引入任何外部依賴(不使用 `@cloudflare/workers-wasi`
- _Requirements: 3.1, 3.3_
- [x]* 2.2 寫單元測試 for WASI shim
- 測試 `fd_read` 正確讀取 stdin buffer(含多次讀取、邊界條件)
- 測試 `fd_write` 正確寫入 stdout bufferfd=1)與 stderr bufferfd=2
- 測試 `proc_exit` 拋出 Error
- [x] 2.3 實作 Tier 1 WASM 執行器(`wasm-executor.ts`
- 從 R2 fetch `.wasm` ArrayBuffer
- `WebAssembly.compile` 後快取 `WebAssembly.Module`Worker 記憶體,跨請求共享)
- 建立 WASI shim,注入 stdin = `JSON.stringify(input)`
- `WebAssembly.instantiate(module, imports)` → 呼叫 `_start()``main()`
- 從 stdout buffer 讀取輸出,`JSON.parse` 後回傳
- 套用 `max_cold_start_ms` 逾時(`Promise.race`
- _Requirements: 3.1, 3.3, 6.6_
- [ ]* 2.4 寫 property test for Component Dispatcher 路由正確性
- **Property 4: Component Dispatcher 路由正確性**
- **Validates: Requirements 3.1, 3.5, 3.6**
- 用 fast-check 生成合法 JSON input,驗證 WASM 執行路徑輸出與預期語意等效
- [x] 3. 建立 `validate_json.wasm` 第一個真實零件(TinyGo
- [x] 3.1 撰寫 `validate_json` TinyGo 原始碼(`u6u-core/registry/components/validate_json/main.go`
- 只使用白名單 import`os``io``encoding/json`
- 讀取 stdin JSON,解析 `json_string` 欄位,嘗試 `json.Unmarshal`
- 成功輸出 `{"valid":true}`,失敗輸出 `{"valid":false,"error":"..."}`
- _Requirements: 3.1, 11.6_
- [x] 3.2 撰寫 `validate_json` component.contract.yaml
- 包含所有必填欄位、gherkin_testshappy path + error path
- `runtime_compat: ["cf-workers","workerd","wazero"]`
- _Requirements: 1.1, 1.2, 1.4_
- [ ]* 3.3 寫單元測試 for validate_jsonGherkin 場景驗證)
- 測試合法 JSON 輸入回傳 `{"valid":true}`
- 測試非法 JSON 輸入回傳 `{"valid":false,"error":...}`
- [x] 4. Checkpoint — Phase 0 驗收
- 確認 `validate_json.wasm` 能在 CF Workers 環境中透過 WASM 執行器執行
- 確認 Component Registry `/guide``/validate-contract``/components` 端點可用
- 確認所有 Phase 0 測試通過,向使用者確認是否繼續 Phase 1
---
## Phase 1:遷移現有零件(20 個 HTTP → WASM
- [x] 5. 升級 Component Dispatcher 支援雙模式(`cypher-executor/src/lib/component-loader.ts`
- [x] 5.1 重構 `ComponentDescriptor` 型別(移除舊 `http_endpoint`,新增 `component_type`
- 定義 `ComponentType = 'wasm' | 'cypher_binding' | 'service_binding'`
- 新版 `ComponentDescriptor` 欄位:`component_type``wasm_r2_key``runtime_compat``max_cold_start_ms``url`cypher_binding)、`method``binding`service_binding)、`path`
- _Requirements: 3.5_
- [x] 5.2 實作路由決策邏輯(`component-dispatcher.ts`
- 查 Component Registry 取得合約
-`component_type` 分流:`wasm` → WASM 執行器;`cypher_binding` → HTTP POST 到外部 URL`service_binding` → CF Service Binding
- 檢查 `runtime_compat` 是否包含當前 Tier,不包含則回傳 `RUNTIME_INCOMPATIBLE` 錯誤
- _Requirements: 3.4, 6.1, 6.2_
- [ ]* 5.3 寫 property test for Dispatcher 錯誤結構完整性
- **Property 5: Dispatcher 錯誤結構完整性**
- **Validates: Requirements 3.4, 6.4**
- 用 fast-check 生成 (component_id, tier) 組合,當 runtime_compat 不含當前 tier,驗證錯誤回應同時包含 component_id、tier、attempted_paths 三個欄位
- [x] 6. 遷移 20 個內建零件(`u6u-core/builtins/``u6u-core/registry/components/`
- [x] 6.1 為每個零件撰寫 TinyGo 原始碼與 component.contract.yaml(批次作業)
- 每個零件:只用白名單 import、stdin/stdout JSON I/O、附帶 gherkin_tests
- 需要外部 API 的零件(如 gsheets):改用 `cypher_binding` 模式,contract 中記錄 `cypher_binding_url`
- _Requirements: 3.6, 11.6_
- [x] 6.2 透過 `POST /components` 批次提交 20 個零件至 Component Registry
- 每個零件通過沙盒驗收後自動寫入 KBDB
- 驗證 20 個零件的 Gherkin 測試全部通過
- _Requirements: 2.1, 3.6_
- [ ]* 6.3 寫 property test for 歷史版本永久保留不變量
- **Property 8: 歷史版本永久保留不變量**
- **Validates: Requirements 4.5, 10.5**
- 用 fast-check 生成已上架零件,標記為 deprecated 後,驗證 `.wasm` 仍可從 R2 讀取,pinned 引用仍可執行
- [x] 7. 實作 Component Registry 查詢端點
- [x] 7.1 實作 `GET /components/:id``GET /components/:id/versions`
- 透過 KBDB HTTP API 查詢 `tpl-component` blocks
- `/versions` 回傳按「成功率 × 速度評分 × 被調用次數」排序的版本清單(最多 10 個)
- _Requirements: 12.3_
- [x] 7.2 實作 `GET /components/search?q=...` 語意搜尋
- 呼叫 KBDB Vectorize API,以 `description` + `tags` 欄位做語意搜尋
- _Requirements: 12.2_
- [ ]* 7.3 寫單元測試 for 查詢冪等性
- 驗證相同查詢參數在 KBDB 資料不變時回傳相同結果
- [x] 8. Checkpoint — Phase 1 驗收
- 確認 20 個零件全部通過沙盒驗收並存入 KBDB
- 確認 Component Dispatcher 雙模式路由正確(WASM + cypher_binding
- 確認所有 Phase 1 測試通過,向使用者確認是否繼續 Phase 2
---
## Phase 2Cypher 語意擴展 + Multi-Tier Dispatcher
- [x] 9. 擴展 Cypher Triplet Parser`cypher-executor/src/actions/triplet-parser.ts`
- [x] 9.1 新增 EdgeType 定義
- 在現有 `PIPE | IF | FOREACH | CONTINUE` 基礎上新增:`IS_A | ON_SUCCESS | ON_FAIL | ON_CLICK | CALLS_SUBFLOW | CONTAINS | HAS_STYLE | HAS_BEHAVIOR`
- _Requirements: 5.1_
- [x] 9.2 實作 URI 協議解析函數(`resolveComponentId`
- 解析 `component://id``component://id@stable``component://id@pinned:vN``workflow://id``ui://id``style://id`
- 回傳 `{ type, canonicalId, stability, pinnedVersion? }`
- _Requirements: 4.1, 5.6_
- [ ]* 9.3 寫 property test for 零件 URI 解析 Round-Trip
- **Property 6: 零件 URI 解析 Round-Trip**
- **Validates: Requirements 4.1**
- 用 fast-check 生成合法 URI 字串,解析後再序列化,驗證語意等效;驗證解析出的 id、stability、pinnedVersion 與原始 URI 完全一致
- [ ]* 9.4 寫 property test for Cypher 三元組解析 Confluence
- **Property 9: Cypher 三元組解析 Confluence(順序無關性)**
- **Validates: Requirements 5.7**
- 用 fast-check 生成合法三元組集合,用 `fc.shuffledSubarray` 打亂順序,驗證 `parseTriplets` 產生相同節點集合與邊集合
- [x] 10. 擴展 GraphExecutor 執行語意(`cypher-executor/src/graph-executor.ts`
- [x] 10.1 實作 `IS_A` 關係處理
- 從 Component Registry 載入零件合約,以 `input_schema` 驗證節點輸入 context
- _Requirements: 5.2_
- [x] 10.2 實作 `ON_SUCCESS` / `ON_FAIL` 分支執行
-`executeNode` 的 try/catch 中,成功走 `ON_SUCCESS` 邊,失敗走 `ON_FAIL` 邊(傳遞 error context
- _Requirements: 5.3_
- [x] 10.3 實作 `CALLS_SUBFLOW` 子流程呼叫
- 從 KBDB 載入子 Workflow 定義,建立子 GraphExecutor 執行,將輸出合併回主流程 context
- _Requirements: 5.4_
- [x] 10.4 實作 `ON_CLICK` 前端觸發處理
- 接受來自前端 Smart Container 打包的 payload,作為 Workflow initialContext
- _Requirements: 5.5_
- [x] 10.5 實作 `CONTAINS` / `HAS_STYLE` / `HAS_BEHAVIOR` 結構語意解析(不執行,僅記錄圖結構)
- _Requirements: 5.1_
- [x] 11. 實作版本選擇策略(Component Dispatcher 升級)
- [x] 11.1 實作 floating 版本選擇算法
- 從 KBDB 查詢該 id 下所有版本,計算「成功率 × 速度評分 × 被調用次數」,選取最高分版本
- _Requirements: 4.2_
- [x] 11.2 實作 stable / pinned 版本選擇
- `stable`:使用當前標記為 stable 的版本,有更優版本時記錄提示至 KBDB 但不切換
- `pinned:vN`:永遠使用版本 vN,即使已 deprecated
- _Requirements: 4.3, 4.4_
- [ ]* 11.3 寫 property test for 版本選擇策略正確性
- **Property 7: 版本選擇策略正確性**
- **Validates: Requirements 4.2, 4.4**
- 用 fast-check 生成版本集合(各有不同 success_rate、avg_duration_ms、call_count),驗證 floating 選最高分;驗證 pinned:vN 無論其他版本評分如何永遠選 vN
- [x] 12. 實作 Evaluator Agent 與評價迴圈(`cypher-executor/src/actions/`
- [x] 12.1 實作 `execution-evaluator.ts`(擴展現有 `execution-logger.ts`
- Workflow 執行完畢後非同步寫入 KBDB Evaluation Block`tpl-evaluation`
- 記錄:run_id、workflow_id、component_id、verdict、duration_ms、error_message、evaluated_at
- 冪等處理:相同 run_id 不重複建立 Block
- _Requirements: 10.1, 10.6_
- [x] 12.2 實作 Pitfall Block 建立邏輯
- 偵測某零件連續 5 次執行錯誤率 > 50%,建立 `tpl-pitfall` Block
- 版本選擇時降低有 Pitfall 記錄的版本評分權重
- _Requirements: 10.2, 10.3_
- [x] 12.3 實作零件自動 Deprecated / Tombstone 狀態轉換
- 連續 30 天無引用 → 標記 `deprecated`,從預設搜尋移除
- 再 90 天無引用 → 標記 `tombstone`,從所有搜尋移除(pinned `.wasm` 永久保留)
- _Requirements: 10.4, 10.5_
- [ ]* 12.4 寫 property test for 系統操作冪等性
- **Property 11: 系統操作冪等性**
- **Validates: Requirements 10.6, 12.5**
- 用 fast-check 生成 run_id,對相同 run_id 呼叫 Evaluator N 次,驗證 KBDB 只存在一個 Evaluation Block
- 驗證相同查詢參數在資料不變時回傳相同結果
- [x] 13. Checkpoint — Phase 2 驗收
- 確認新 EdgeType 全部可解析執行(IS_A、ON_SUCCESS、ON_FAIL、CALLS_SUBFLOW、ON_CLICK
- 確認版本選擇策略(floating / stable / pinned)行為正確
- 確認 Evaluator Agent 冪等寫入 KBDB
- 確認所有 Phase 2 測試通過,向使用者確認是否繼續 Phase 3
---
## Phase 3:前端畫布(Web Components + 雙面翻轉)
- [x] 14. 建立 Web Components 零件庫(`u6u-core/web-components/`
- [x] 14.1 實作 `<u6u-btn>` Custom Element
- 支援 attributes`label``color``tooltip``workflow``disabled`
- `workflow` 設定且點擊時發出 `u6u:trigger` CustomEvent`{ workflowId, payload }`
- `workflow` 未設定時點擊不發出事件,console 輸出警告
- _Requirements: 8.2, 8.3_
- [x] 14.2 實作 `<u6u-text-input>``<u6u-text-field>` Custom Elements
- 支援 `name``placeholder``value` attributes
- `value` property 可被 `<u6u-card>` 讀取
- _Requirements: 8.1_
- [x] 14.3 實作 `<u6u-card>` Smart Container
- 攔截子元件的 `u6u:trigger` 事件(`stopPropagation`
- 收集同容器內所有 `<u6u-text-input>` / `<u6u-text-field>` 的 name-value 對
- 合併至 payload 後重新發出 `u6u:trigger``bubbles: true, composed: true`
- _Requirements: 8.4_
- [x] 14.4 實作 `<u6u-chart>` Custom Element(基礎版)
- 支援 `data` attributeJSON 字串)、基本折線圖渲染
- _Requirements: 8.1_
- [ ]* 14.5 寫 property test for Web Components 事件與渲染冪等性
- **Property 10: Web Components 事件與渲染冪等性**
- **Validates: Requirements 8.3, 8.4, 8.5**
- 用 fast-check 生成 workflow URI,驗證點擊後 `u6u:trigger` detail.workflowId 與 URI id 完全一致
- 用 fast-check 生成具名 input 集合置於 u6u-card,驗證收集到的 payload 包含所有 name-value 對
- 用 fast-check 生成 attribute 值,對同一元件設定相同值 N 次,驗證渲染結果冪等
- [x] 15. 建立雙面翻轉畫布(`inkstone-admin/frontend/web/`
- [x] 15.1 實作翻轉狀態機(`Canvas.tsx`
- 狀態:`UIView``LogicView`(點擊翻面按鈕切換)
- `LogicView``Editing`(修改三元組)→ `Saving`(確認儲存)→ `LogicView`
- _Requirements: 9.1_
- [x] 15.2 實作邏輯視圖(Cypher 三元組視覺化)
- 顯示零件關聯的 Cypher 三元組(節點連線方式)
- 修改三元組後即時更新 KBDB Workflow Block(透過 KBDB HTTP API
- _Requirements: 9.2_
- [x] 15.3 實作 Workflow URI 選擇器
- 列出 KBDB 中所有可用 Workflow,下拉選單完成 `ON_CLICK >> workflow://id` 綁定
- _Requirements: 9.3_
- [x] 15.4 實作 Smart Container 拖放與自動打包關係顯示
- 拖入同一 `<u6u-card>` 時,邏輯視圖自動顯示 CONTAINS 關係與自動打包說明
- _Requirements: 9.4_
- [x] 15.5 實作零件替換過濾器
- 替換已綁定 Workflow 的 UI 零件時,只顯示具備 `u6u:trigger` 能力的候選零件
- _Requirements: 9.5_
- [x] 15.6 在畫布中整合 u6u Web ComponentsDogfooding
- 畫布 UI 本身使用 `<u6u-btn>``<u6u-card>``<u6u-text-input>` 組裝
- 驗證 Web Components 在 React 19 環境中正確運作
- _Requirements: 8.1, 9.1_
- [ ]* 15.7 寫整合測試 for 畫布翻轉流程
- 測試 UIView → LogicView → Editing → Saving → LogicView 完整狀態轉換
- 測試 KBDB 寫入成功與失敗兩種情境
- [x] 16. Final Checkpoint — 全平台驗收
- 確認四個 Phase 的所有測試通過(`pnpm test` in each service
- 確認 Dogfooding:畫布本身用 u6u Web Components 組裝,每一層都是下一層的第一個用戶
- 確認 KBDB 不變量:仍只有三張表(blocks / templates / slots
- 確認 API-First 鐵律:所有跨服務通訊只透過 HTTP API
- 向使用者確認所有任務完成
---
## Phase 4:邊緣基礎設施(Tier 3 支援)
> 這個 Phase 不在零件遷移範圍內,是獨立的基礎設施工作。
- [ ] 17. Credentials 邊緣支援評估與改寫(`u6u-core/credentials/`
- [ ] 17.1 評估 Tier 3 是否需要 Credentials
- 場景:無人機在有網路時呼叫外部 API(如取得感測器資料),需要 access_token
- 結論:Tier 3 需要在連網時從 Tier 2 取得 Credential,離線時使用本地快取的加密 token
- _Requirements: 7.1, 7.2_
- [ ] 17.2 實作 Credential 本地快取機制(Tier 3 用)
- Tier 3 Go 排程引擎在連網時從 Tier 2 Credentials Worker 取得加密 token
- 存入本地 SQLiteAES-GCM 加密,key 存於設備安全儲存)
- 離線時從本地快取讀取,過期時加入 DTN 佇列等待更新
- _Requirements: 7.1, 7.3_
- [ ] 18. Go Cypher ExecutorTier 3 邊緣執行引擎)(`u6u-core/executor/`
- [ ] 18.1 用 Go 實作 Cypher 三元組解析器
- 解析 `"A >> 關係 >> B"` 格式,建立執行圖(nodes + edges
- 支援 IS_A、ON_SUCCESS、ON_FAIL、CALLS_SUBFLOW、ON_CLICK 語意關係
- 對應 `cypher-executor/src/actions/triplet-parser.ts` 的 Go 版本
- _Requirements: 5.1, 5.7_
- [ ] 18.2 用 Go + Wazero 實作 WASM 零件執行器
- 載入本地 `.wasm` 檔案,透過 Wazero 原生 WASI preview1 執行
- 注入 `u6u` host module`http_request` host function,透過 DTN 或直接 HTTP
- stdin/stdout JSON I/O,與 Tier 1/2 的 `wasm-executor.ts` 語意等效
- _Requirements: 7.1, 7.4_
- [ ] 18.3 實作 DTN 佇列(離線請求緩衝)
- 零件需要網路但當前離線時,寫入本地 SQLite DTN 佇列
- 連網時 Burst 傳輸:批次送出佇列中的請求,接收回應後繼續執行
- _Requirements: 7.2, 7.5_
- [ ]* 18.4 整合測試:validate_json.wasm 在 Wazero 執行
- 確認同一個 `.wasm` 在 Tier 1wasi-shim.ts)和 Tier 3Wazero)執行結果一致
---
## Notes
- 標記 `*` 的子任務為選填,可跳過以加速 MVP 交付
- 每個任務都引用具體的 Requirements 條款以確保可追溯性
- Checkpoint 任務確保每個 Phase 完成後有明確的驗收點
- Property tests 使用 fast-check,每個屬性最少執行 100 次迭代
- 所有跨服務呼叫只透過 KBDB HTTP API,不直接操作 D1 SQL
- TinyGo 零件只使用白名單 import`os``io``encoding/json`
## Phase 5u6u-mcp 對齊新 Registry + u6u-gui 前端
> 壓測前必須完成,讓 AIu6u-mcp)和人類(u6u-gui)都能操作新的 WASM 零件架構。
- [x] 19. 更新 u6u-mcp 對齊新 Component Registry`u6u-mcp/src/tools/`
- [x] 19.1 更新 `u6u_publish_component`
- 舊:呼叫 `/components/publish`payload 為 `{ component_id, gherkin, api_config }`
- 新:呼叫 `POST /components`payload 為 `{ contract: ComponentContract, wasm_base64: string }`
- 新增 `contract``wasm_base64` 參數,更新工具描述說明 TinyGo 零件提交流程
- [x] 19.2 更新 `u6u_search_components`
- 舊:呼叫 `/components/match`(不存在的端點)
- 新:呼叫 `GET /components/search?q={query}`(新 Registry 語意搜尋端點)
- 更新工具描述:AI 可用自然語言搜尋零件(如「查詢 Google Sheets 資料」)
- [x] 19.3 更新 `u6u_get_component`
- 舊:讀舊格式 slots`component_id``name``published_at`
- 新:對齊 `tpl-component` slot 欄位(`canonical_id``display_name``category``version``stability``wasm_r2_key` 等)
- 呼叫新 Registry `GET /components/:id` 端點
- [x] 19.4 新增 `u6u_get_component_guide` 工具
- 呼叫 `GET /components/guide`,回傳開發指引給 AI
- AI 在開發新零件前可先讀取指引,確保生成符合規範的 TinyGo 程式碼
- [x] 20. 建立 u6u-gui 前端(`u6u-gui/`
- [x] 20.1 建立 Cloudflare Pages 專案結構
- React 19 + Vite + Tailwind CSS v4
- 整合 `@u6u/web-components`alias 指向 `u6u-core/web-components/src`
- wrangler.toml 設定 Pages 部署
- [x] 20.2 建立主畫布頁面(`/canvas`
- 整合 `Canvas.tsx`(從 inkstone-admin 移植)
- 連接 Cypher Executor API`POST /cypher/execute`
- 連接 Component Registry API(搜尋、查詢零件)
- AI 操作後(透過 u6u-mcp 修改 KBDB)畫布即時反映變更
- [x] 20.3 建立零件庫頁面(`/components`
- 列出所有已上架零件(呼叫 `GET /components/search`
- 顯示零件合約、評分、版本歷史
- 提供「提交新零件」入口(連結到開發指引)
- [x] 20.4 建立 Workflow 管理頁面(`/workflows`
- 列出所有 Workflow(從 KBDB 查詢 `tpl-workflow`
- 點擊進入畫布編輯
- 顯示執行歷史(Evaluation Block
- [x] 20.5 部署至 Cloudflare Pages
- `pnpm build && npx wrangler pages deploy dist`
- 設定環境變數(KBDB_URL、CYPHER_URL、REGISTRY_URL