922a57fe34
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>
382 lines
23 KiB
Markdown
382 lines
23 KiB
Markdown
# arcrun — 進度與待辦
|
||
|
||
> 設計細節見 `arcrun/README.md`(產品說明)和 `arcrun/BETA_TEST.md`(封測指南)。
|
||
> 這份文件只記錄:目前狀態、還差什麼、封測能不能啟動。
|
||
|
||
---
|
||
|
||
## 一、封測目標場景
|
||
|
||
封測者是工程師朋友,有自己的網頁,需要後端自動化。目標是他能在 AI 協助下,一次或很少次完成以下完整流程:
|
||
|
||
1. `acr init` 取得 api_key
|
||
2. `acr parts scaffold` 查零件格式,AI 幫寫 workflow YAML
|
||
3. 若內建零件不足,`acr recipe push` 增加打外部 API 的 recipe
|
||
4. `acr creds push` 上傳 OAuth token(gmail / google_sheets 等)
|
||
5. `acr push` 部署 workflow,取得 Webhook URL
|
||
6. 網頁 POST /webhooks/named/{name}/trigger,結果存 Google Sheets
|
||
|
||
---
|
||
|
||
## 二、場景各步驟驗證狀態
|
||
|
||
### Step 1:acr init → api_key
|
||
- [x] `acr init` Standard 模式完成,api_key 存入 `~/.arcrun/config.yaml`
|
||
- [x] 已驗證:`mode: standard, api_key: ak_...` 正確
|
||
|
||
### Step 2:acr parts scaffold → AI 看到零件格式
|
||
- [x] `acr parts` 列出 21 個零件,完全內建,不依賴 registry.arcrun.dev
|
||
- [x] `acr parts scaffold google_sheets` 輸出 spreadsheet_id / range / operation / values 格式與 credentials.yaml 範本
|
||
- [x] 已驗證:輸出可直接貼入 YAML
|
||
|
||
### Step 3:acr recipe push → 打外部 API
|
||
- [x] `acr recipe push` 上傳成功,回傳 rec_hash
|
||
- [x] workflow 使用 `component: rec_xxxxxxxx`,acr push 後 trigger 能正確呼叫外部 API
|
||
- [x] 已驗證(2026-04-18):httpbin_post recipe → trigger → httpbin.org/post 回傳正確 ✅
|
||
|
||
### Step 4:acr creds push → 自動注入 token
|
||
- [x] `POST /credentials` API 完成,以 `{api_key}:cred:{name}` 存入 KV
|
||
- [x] Webhook trigger 時 injectCredentials 從 KV 取得 token 自動注入
|
||
- [x] `/register` 現在回傳 `encryption_key`,`acr init` 自動存入 config
|
||
- [x] `acr creds push` 從 config 讀 encryption_key,不再需要手動設定環境變數
|
||
- [x] 已驗證(2026-04-18):beta@arcrun.dev 帳號完整流程:init → creds push → trigger → credential 注入成功 ✅
|
||
|
||
### Step 5:acr push → Webhook URL
|
||
- [x] `acr push workflow.yaml` 部署成功,顯示 Webhook URL 和完整 curl 範例
|
||
- [x] config 中的 `component` / 參數在 push 時套入 graph 節點
|
||
- [x] 已驗證(2026-04-18):sheet-test workflow push 成功 ✅
|
||
|
||
### Step 6:網頁 POST → 執行 → 結果到 Google Sheets
|
||
- [x] `POST /webhooks/named/{name}/trigger -H 'X-Arcrun-API-Key: ...'` 觸發執行正常
|
||
- [x] google_sheets 零件有實作(append row 到 Sheets API)
|
||
- [x] 已驗證(2026-04-18):trigger sheet-test → 報「缺少 credential」(符合預期,credential 未上傳)✅
|
||
- [ ] **未驗證**:真實 google_oauth token + acr creds push → trigger → Google Sheets 實際寫入
|
||
- 需要真實 OAuth token 才能完整驗證
|
||
|
||
---
|
||
|
||
## 三、封測啟動阻擋項
|
||
|
||
P0 全部清除才啟動封測。
|
||
|
||
| # | 項目 | 狀態 | 說明 |
|
||
|---|------|------|------|
|
||
| 1 | acr parts scaffold 正確輸出 | ✅ 完成 | 21 個零件內建清單 |
|
||
| 2 | acr recipe push 端對端 | ✅ 完成 | httpbin_post 驗證通過 |
|
||
| 3 | acr creds push 代碼 | ✅ 完成 | 需 ARCRUN_ENCRYPTION_KEY |
|
||
| 4 | credential 注入端對端 | ✅ 完成 | 無 token 時錯誤訊息正確 |
|
||
| 5 | acr push + webhook trigger | ✅ 完成 | 端對端驗證通過 |
|
||
| 6 | acr creds push 實測 | ✅ 完成 | /register 回傳 encryption_key,acr init 自動存入 config(CLI 1.0.9)|
|
||
| 7 | Google Sheets 真實寫入 | ⚠️ 部分驗證 | credential 注入已驗證;實際 Sheets 寫入需真實 OAuth token |
|
||
| 8 | 第三方服務認證 recipe | ✅ 完成 | 20 個服務(Notion/Slack/GitHub/OpenAI 等),CLI 1.1.0 |
|
||
| **9** | **cypher-executor outbound HTTP fetch 全失效** | ✅ **已解決 2026-05-13**(CF 同 zone 自循環死鎖,改走 workers.dev)| 詳見下方專段 |
|
||
| **10** | **multi-node chain context propagation 漏失** | ✅ **已解決 2026-05-13**(ON_SUCCESS/ON_FAIL/IF/ON_CLICK 沒 spread baseCtx)| 詳見下方專段 |
|
||
|
||
**目前狀況**:P0 全部解決。
|
||
- #9 修復方式:component worker URL 從 `*.arcrun.dev`(同 cypher zone)改走 `arcrun-{name}.{WORKER_SUBDOMAIN}.workers.dev`(避開同 zone 自循環)
|
||
- #10 修復方式:4 個 edge type 補 `{...baseCtx, ...result}`,跟 PIPE/FOREACH 一致
|
||
|
||
兩個 P0 解完 mira 7 節點 workflow 端對端通(含真 Claude 16 秒呼叫)。
|
||
|
||
---
|
||
|
||
### ✅ P0 #9(2026-05-13 已解決):cypher-executor outbound fetch 全失效
|
||
|
||
**完整事件報告(含誤判路徑)**:[docs/incidents/2026-05-13-cypher-outbound-522.md](../../../docs/incidents/2026-05-13-cypher-outbound-522.md)
|
||
|
||
**修復方式**:cypher-executor fetch component worker 從 `*.arcrun.dev`(同 zone)改走 `arcrun-{name}.{WORKER_SUBDOMAIN}.workers.dev`。對外 `cypher.arcrun.dev` 不變,用戶 0 感知。
|
||
|
||
**改動檔案**(2026-05-13):
|
||
- `cypher-executor/src/lib/component-loader.ts`:`wasmWorkerUrl(canonicalId, subdomain)` 簽名加 subdomain 參數 + URL pattern 改 workers.dev
|
||
- `cypher-executor/src/actions/auth-dispatcher.ts`:同步新簽名
|
||
- `cypher-executor/src/types.ts`:`Bindings` 加 `WORKER_SUBDOMAIN: string`
|
||
- `cypher-executor/wrangler.toml`:`[vars]` 加 `WORKER_SUBDOMAIN = "uncle6-me"`
|
||
- 5 個 component worker 在 dashboard 啟用 workers.dev URL(kbdb-get / kbdb-ingest / kbdb-create-block / kbdb-patch-block / claude-api,**未來新 component 也都要開**)
|
||
|
||
**驗證**:cypher-executor → kbdb-get / claude-api 從 522 → 200。mira `acr run wiki_synthesis` 5 節點 workflow 跑通前 3 節點(kbdb_get chain)。
|
||
|
||
**Self-hosted fork 注意**:必須改 `wrangler.toml [vars] WORKER_SUBDOMAIN` 為自己的 CF 帳號 subdomain,並把所有 component worker 在 dashboard 啟用 workers.dev URL。
|
||
|
||
---
|
||
|
||
### ✅ P0 #10(2026-05-13 已解決):multi-node chain context propagation 漏失
|
||
|
||
**現象**:cypher binding workflow 從第 2 個節點開始,原始 input context(top-level `api_key` / `mira_token` 等)丟失,下游節點 `{{api_key}}` 模板原文未替換傳給零件 → 401 Unauthorized 或類似錯。
|
||
|
||
**測試重現**:
|
||
|
||
```yaml
|
||
flow:
|
||
- "input >> ON_SUCCESS >> n1"
|
||
- "n1 >> ON_SUCCESS >> n2"
|
||
config:
|
||
n1: { component: kbdb_get, api_key: "{{api_key}}", block_id: "{{b1}}" }
|
||
n2: { component: kbdb_get, api_key: "{{api_key}}", block_id: "{{b2}}" }
|
||
context: { api_key: "ak_xxx", b1: "...", b2: "..." }
|
||
```
|
||
|
||
n1 收到 ctx 含 `api_key / b1 / b2` ✓ → 跑通。
|
||
n2 收到的 ctx 只有 `n1.output spread`(blocks/count/success/block_id),**`api_key / b1 / b2` 不見**,`{{api_key}}` 原文傳到零件回 401。
|
||
|
||
**根因**:`graph-executor.ts` 在 PIPE / FOREACH 邊類型已修「baseCtx ∪ result」,但 **ON_SUCCESS / ON_FAIL / IF / ON_CLICK 四個 edge type 沒套同模式**,直接把 `result` 當下游 ctx 傳,丟掉原始 context。
|
||
|
||
**修法**(`cypher-executor/src/graph-executor.ts` line 407 / 415 / 423 / 472):
|
||
|
||
```typescript
|
||
// 改前
|
||
result = await this.executeNode(nextNode, graph, result, ...);
|
||
|
||
// 改後(同 PIPE/FOREACH 模式)
|
||
const baseCtx = (typeof context === 'object' && context !== null) ? context as Record<string, unknown> : {};
|
||
const baseResult = (typeof result === 'object' && result !== null) ? result as Record<string, unknown> : {};
|
||
const mergedCtx = { ...baseCtx, ...baseResult };
|
||
result = await this.executeNode(nextNode, graph, mergedCtx, ...);
|
||
```
|
||
|
||
**驗證**:mira `acr run wiki_synthesis` 7 節點 workflow 端對端跑通(16 秒,含真 Claude 呼叫)。每個節點都拿到正確 `api_key` 不再 401。
|
||
|
||
**歷史脈絡**:類似問題 2026-05-07 commit e8fca33 在 FOREACH edge 已修一次("FOREACH preserves outer context"),但當時沒同步處理另外 4 個 edge type。本次補完。
|
||
|
||
---
|
||
|
||
### ✅ P0 #10 補完三個衍生問題(2026-05-13 晚 ~ 2026-05-14)
|
||
|
||
P0 #10 修完後 mira 嘗試做 wiki 多段結構,又踩出三個 cypher binding 設計缺陷。**都是同一天解掉**。
|
||
|
||
#### A. interpolateData() 不遞迴 nested object
|
||
|
||
**現象**:`set` / `kbdb_create_block` 的 `values: { text: "{{classify.data.text}}" }`、`tags_json: ["facet:{{paragraph.facet}}"]` 等 nested config 內的 `{{x}}` 不被替換,原文傳給零件。
|
||
|
||
**根因**:`interpolateData()` 只 iterate top-level,對非 string 值(object / array)直接 pass-through 不下沉。
|
||
|
||
**修法**:拆 `interpolateString` + `interpolateValue`(遞迴 object / array),`interpolateData` 改 call `interpolateValue`。
|
||
|
||
**測試**:`set values: { text: "hello {{name}}", arr: ["item {{name}}"] }` 帶 `name=world` → 全展開。
|
||
|
||
#### B. ctx 沒存上游 output 的 node id namespace
|
||
|
||
**現象**:`{{classify.data.text}}` 找不到上游 classify 的 output;只能用 `{{data.text}}`(直接 spread 取),但會被下個節點覆蓋,多節點 chain 用不了。
|
||
|
||
**根因**:`propagateCtx` 只把上游 result spread 進 ctx,沒額外存 `[node.id]: result`。
|
||
|
||
**修法**:`propagateCtx` 改回傳 `{ ...baseCtx, ...baseResult, [upstreamNodeId]: upstreamResult }`。讓下游能用 `{{node_id.data.text}}` 從 namespace 取,永不被覆蓋。
|
||
|
||
**測試**:5 節點 chain 用 `{{load_schema.blocks.0.content}}` / `{{classify.data.text}}` 全展開。
|
||
|
||
#### C. FOREACH 找 iterable 只看 result,不看 ctx + 不看 nested
|
||
|
||
**現象**:mira wiki_synthesis 雙重 FOREACH(外層 `對每個 paragraph`、內層 `對每個 triplet`),外層 OK,內層跑 0 次。
|
||
|
||
**根因 (C1)**:`getIterableFromContext(result, key)` 只看當前節點 output。`result` 是 `create_paragraph` output(`{data, success}`),不含 paragraphs。但 `paragraphs` 早就在 ctx 從 classify spread 來。
|
||
|
||
**根因 (C2)**:當外層 FOREACH 把 `paragraph` item 注入 ctx,內層 FOREACH 要找 `paragraph.triplets`。`getIterableFromContext` 只看 top-level,看不到 `paragraph` 物件裡的 `triplets`。
|
||
|
||
**修法**:
|
||
- (C1) FOREACH `result` 找不到 iterable → fallback 找 `context`
|
||
- (C2) `getIterableFromContext` 加一輪「掃 ctx 內每個 object 找 nested key」
|
||
|
||
**測試**:mira wiki_synthesis 3 層樹(wiki-page → paragraphs → triplets)端對端跑通,KBDB 內驗證 `物理 AI` wiki 有 2 段 paragraph + 4 個 triplet,parent_id 正確接到對應 paragraph。
|
||
|
||
#### Edge type 一致化
|
||
|
||
抽 `propagateCtx(context, result, upstreamNodeId)` helper,5 個 edge type(PIPE / ON_SUCCESS / ON_FAIL / IF / ON_CLICK / FOREACH)全部用同一 function 組下游 ctx。**未來新 edge type 必須用這 helper**,避免再漏。
|
||
|
||
#### CLI validator 同步
|
||
|
||
`cli/src/lib/yaml-parser.ts` validateRelations 加 regex 支援 `對每個 X` / `FOREACH X` 迭代器命名(之前 validator 字串完全比對擋住,但 graph-builder 執行端早已支援)。
|
||
|
||
---
|
||
|
||
### 三-A、P1 待改進(不擋封測,但 mira 已踩到)
|
||
|
||
#### ✅ P1 #3:cypher-executor `scheduled()` handler(2026-05-14 完成)
|
||
|
||
**原痛點**:cron 零件只做 expression validation;cypher-executor 沒 `scheduled()` handler。寫了 cron 首節點的 workflow 不會真的跑。
|
||
|
||
**之前的 workaround**(已撤):mira 寫了個 `/mira/wiki-from-raw` route 從前端 fire-and-forget 觸發 wiki_synthesis。但這違反「一律 arcrun-native」原則,也讓 arcrun 永遠補不齊缺失。**已刪 route,回 arcrun-native 路線**。
|
||
|
||
**落地**:
|
||
1. `wrangler.toml`:`[triggers] crons = ["* * * * *"]`(每分鐘 tick)
|
||
2. `src/lib/cron-match.ts`:5 欄位 cron expression matcher(支援 `*` / `N` / `*/N` / `1-5` / `5,10` 組合)
|
||
3. `src/scheduled.ts`:scheduled handler 掃 KV `cron-idx:` prefix,比對 controller.scheduledTime,匹配就 `executeWebhookGraph` 背景跑
|
||
4. `routes/webhooks-named.ts`:acr push 偵測首節點是 cron 零件 → 抽 `cron_expr` 存進 record + 額外寫 `cron-idx:{api_key}:{name}` 輕量 index entry。DELETE 一併清理
|
||
5. `src/index.ts`:export default 改 `{ fetch, scheduled }`
|
||
6. cypher-executor 自己加 `workers_dev = true` 給未來 self-trigger 用(fork 用 path-based 子 trigger 也走 workers.dev 避同 zone)
|
||
|
||
**workflow YAML 慣例**:
|
||
```yaml
|
||
flow:
|
||
- "my_cron >> ON_SUCCESS >> downstream_node"
|
||
config:
|
||
my_cron:
|
||
component: cron
|
||
cron_expr: "*/5 * * * *" # 每 5 分鐘
|
||
```
|
||
acr push 就會自動建立 cron-idx 並開始定時觸發。
|
||
|
||
**測試**:`tests/arcrun-test/cron_heartbeat.yaml` — 每分鐘 fire 一次 + set 節點 log。
|
||
`wrangler tail arcrun-cypher-executor` 應看 `[scheduled] trigger cron_heartbeat ...`。
|
||
|
||
**對應 use case**:mira `mira_feed_watcher`(7B.3h,下一輪做)/ RSS 每日抓 / voice-stt 每小時掃 / 等所有 cron-driven source。
|
||
|
||
---
|
||
|
||
#### P1 #1:workflow 缺 IF/branch 能力(2026-05-14 mira 7B.3f 提出)
|
||
|
||
**現象**:mira 想做「找有則 PATCH 沒則 CREATE」(index-entry upsert),arcrun 目前只有 `ON_SUCCESS` + `對每個 X`(FOREACH)+ 已存在但壞掉的 `if_control`(見已知限制 #1),沒有 `>> ON_TRUE >>` / `>> ON_FALSE >>` 條件路由。
|
||
|
||
**短期 workaround**(已採用,2026-05-14):建 `kbdb_upsert_block` 零件,把分支邏輯封進零件內部(GET by page_name → 找到 PATCH 沒找到 POST)。caller 看到的是單純的 upsert 介面。
|
||
|
||
**長期解**:升 `if_control` false branch 路由 / 加 `>> ON_TRUE >>` edge type,讓 workflow 層可表達分支。對未來所有「找則改否則建」/「條件分流」場景都會撞到,不只 mira。
|
||
|
||
**位置**:cypher-executor/src/graph-executor.ts edge type 處理(5 個 edge type 抽出 `propagateCtx` 後新增 IF 應該不難)+ cli/src/lib/yaml-parser.ts validator。
|
||
|
||
---
|
||
|
||
#### P0 #11(2026-05-14 已解決):interpolateString stringify array 撐爆下游
|
||
|
||
**現象**:mira_feed_watcher 用 `items: "{{list_raws.blocks}}"` 把 kbdb_get 拿到的 blocks 陣列傳給 filter 零件。watcher 跑 264ms 完成、0 raw 處理。
|
||
|
||
**根因**:`interpolateString` 看到模板就用 `String.replace`,非 string 值(陣列)一律 `JSON.stringify`。filter 零件收到字串 `"[{...},{...}]"` 不是 array,items 被忽略 → 0 matches → FOREACH 跑 0 次。
|
||
|
||
**修法**:`interpolateString` 加 single-ref pass-through 規則:若整個值是純單一 `{{x}}` 引用,回 raw value(保留 array / object 型別)。多 ref / 混合文字仍 stringify 拼接字串。
|
||
|
||
**測試**:mira_feed_watcher 推到 prod 後下一個 cron tick 觀察 wiki-processed tag 是否在 raws 上出現。
|
||
|
||
---
|
||
|
||
### 三-B、新零件加入紀錄
|
||
|
||
| 日期 | 零件 | 動機 | 對應 SDD |
|
||
|---|---|---|---|
|
||
| 2026-05-14 | `kbdb_upsert_block` | mira 7B.3f index-entry per-entity upsert,繞過 workflow 缺 IF/branch 能力(P1 #1)。內部 GET by page_name → 找到 PATCH 沒找到 POST。page_name 當 idempotency key。 | polaris/mira/.agents/specs/mira-app/design.md §3.5.12.4.1 |
|
||
|
||
**新零件 checklist(避免 P1 #1 重蹈 kbdb_upsert_block 漏白名單覆轍)**:
|
||
|
||
每加一個 API/data 零件(不是 logic primitive),都要:
|
||
- [ ] `registry/components/{name}/main.go` + `component.contract.yaml` + `go.mod`
|
||
- [ ] `tinygo build -target=wasi` 通
|
||
- [ ] `.component-builds/{name}/` 完整 4 檔(`wrangler.toml` 含 `workers_dev = true` + `pnpm-lock.yaml` + `tsconfig.json` + `src/index.ts`)
|
||
- [ ] **`cypher-executor/src/lib/component-loader.ts` 的 `WASM_HTTP_RUNNER_IDS` 加 canonical_id**(漏這條 cypher-executor 永遠拋「找不到零件」,端對端會死靜悄悄)
|
||
- [ ] `acr validate workflow.yaml` 通
|
||
- [ ] 直接 curl `https://{kebab}.arcrun.dev` + `https://arcrun-{kebab}.{WORKER_SUBDOMAIN}.workers.dev` 都 200
|
||
|
||
---
|
||
|
||
### 三-C、P1 #2:workers_dev = true 全 component 自動化(2026-05-14 已收)
|
||
|
||
**原痛點**:每新部署一個 component worker,要去 CF Dashboard 手動 Enable workers.dev URL,否則 cypher-executor fetch 該 worker 會 404。
|
||
|
||
**解**:32 個 `.component-builds/*/wrangler.toml` 全部加 `workers_dev = true`。CI 每次 deploy 自動啟用對應 workers.dev URL,零手動。
|
||
|
||
**未來新 component**:模板 (`component-worker-template/`) 應該預設帶 `workers_dev = true`,新人 fork 不會踩。已列入「新零件 checklist」第 3 條。
|
||
|
||
**為何不走 `*.acr-comp.uncle6.me` 自訂 zone**:CF Universal SSL 只發一層子域,sub-sub `*.acr-comp.uncle6.me` 不蓋;要 ACM ($10/月) 才能簽。違反 arcrun「fork 後 self-host 用 free tier 跑得起來」核心目標。workers_dev=true 走 CF 默認的 workers.dev cert,free tier OK,更乾淨。
|
||
|
||
---
|
||
|
||
### 原 P0 #9 調查紀錄(保留作歷史參考)
|
||
|
||
**現象**:cypher-executor 的 `makeHttpRunner` (`cypher-executor/src/lib/component-loader.ts:142`) 對任何 outbound URL fetch 都回 CF **522 (origin timeout, ~1000ms)**。
|
||
|
||
**測試矩陣**(mira repo `polaris/mira/arcrun/wiki_synthesis.yaml` 端對端壓測時發現):
|
||
|
||
| 路徑 | 結果 | 證明 |
|
||
|---|---|---|
|
||
| 本機 curl → kbdb-get.arcrun.dev | 200 (22ms) | KBDB worker 本身健康 |
|
||
| cypher-executor → kbdb-get.arcrun.dev (HTTP) | **522** (1002ms) | outbound HTTP fetch 壞 |
|
||
| cypher-executor → claude-api.arcrun.dev (HTTP) | **522** | 同 zone 也壞 |
|
||
| cypher-executor → httpbin.org (外部) | **522** | 不只是 same-account loop |
|
||
| cypher-executor → string_ops (Service Binding) | 200 ✅ | SVC_* 路徑正常 |
|
||
| acr run hello (built-in via SB) | ✅ | hello.yaml 仍跑得通 |
|
||
|
||
**衍生小 bug**:`set` 零件 input schema 變了(要 `assignments` 陣列或 `values` 物件,不是 `value`)。tests/arcrun-test/hello.yaml 跑 string_ops 沒踩到。
|
||
|
||
**影響範圍(封測啟動阻擋)**:
|
||
|
||
- 任何用戶 workflow 含 outbound HTTP 都壞:
|
||
- 用戶 `acr recipe push` 後 trigger → 打外部 API 全 522(推翻 P0 #2 4/18 紀錄)
|
||
- 用戶要存資料進 arcrun 內建 KBDB → 522(mira 7B.3c 卡這裡)
|
||
- 任何 auth primitive 走獨立 Worker URL 路徑 → 522
|
||
- Google Sheets 寫入 → 522(推翻 P0 #7「待真實 OAuth 驗證」評估,根本還沒到 OAuth 步驟就壞)
|
||
- 只有「全內建邏輯零件 + 純 service binding」workflow 還能跑
|
||
|
||
**根因(2026-05-13 確認):5/8-5/9 9 次 manual `wrangler deploy` 把含 WIP bug 的 cypher-executor 推上 prod**
|
||
|
||
調查路徑(按時序):
|
||
|
||
1. 一開始懷疑 free tier CPU cap(10ms / invocation)→ 對照測試「5 節點 SB chain」跑了 2.2 秒卻通過,**推翻**
|
||
2. 換懷疑 CF zone 規則 / Bot Fight Mode → dashboard bindings 乾淨無攔截,**推翻**
|
||
3. 用戶補繳費恢復 Workers Paid → 重測仍全 522,**徹底排除付費假設**
|
||
4. 看 dashboard Version History:5/8 4 次 + 5/9 5 次 = **9 次 manual `wrangler deploy by uncle6.me`**
|
||
5. 對照 GitHub Actions:4/24 後完全沒 deploy(最後是 commit e222116 `fix(wasi-shim)`)
|
||
6. 對照 git:本機 main **領先 origin/main 3 commits 未 push**,含:
|
||
- `497f92a feat(arcrun): recipe system + resumable workflow + component registry canon`
|
||
- `e8fca33 feat(cypher): 3-node wiki workflow end-to-end (FOREACH + nested interp + unified parsing)`
|
||
- `519423c feat(arcrun): mira wiki page with tag filter + accumulated WIP`(自描含 `cypher-executor: auth-dispatcher / wasi-shim adjustments (WIP)`)
|
||
|
||
**結論**:那 9 次 manual deploy 把上面 3 個 unpushed commit 的 cypher-executor 改動推上 prod,其中至少一個改動破壞了 outbound fetch(最可能是 519423c WIP 內的 wasi-shim / auth-dispatcher 改動)。GitHub Actions 因為沒 push 沒跑,CI 沒 catch,4/18-4/24 那段 SDD「驗證通過」的紀錄是 truth,現在 prod 是壞的版本。
|
||
|
||
**為何 SB 路徑沒事 / HTTP 路徑全死**:SB 走 cypher-executor 內部 service binding API(`env.SVC_X.fetch()`),不經過 outbound HTTP code path。HTTP 路徑走 `makeHttpRunner` (component-loader.ts:142) 的 `fetch(url, ...)`,這條路被 WIP code 弄壞。具體壞在哪要 diff 那 3 個 commit 的 cypher-executor 改動才知道。
|
||
|
||
**驗證 wrangler tail 證據**:trigger 任何 outbound HTTP 的 graph,cypher-executor 自己 `wallTime: 497ms, cpuTime: 2ms, outcome: ok`、無 logs、無 exceptions。代表 cypher-executor 把「fetch 失敗的 522 response」當作 component 正常輸出包回 client,自己沒撞任何錯。
|
||
|
||
**解法(三選一)**:
|
||
|
||
- **A. Rollback prod 到 4/24 的 e222116** — CF dashboard → arcrun-cypher-executor → Deployments → 找 4/24 那筆 → Rollback。5 分鐘恢復 outbound fetch,丟失 wiki workflow / recipe / resumable 等 cypher 端 WIP 改動(但前端、registry components、KBDB blocks 都不丟,因為它們是別的 worker / 別的儲存)。**richblack 操作。**
|
||
- **B. Diff 3 個 unpushed commit 找出壞掉的改動修掉** — 不丟功能,但要動 src code 走 SDD 協議,30min - 數小時。
|
||
- **C. 架構切換**(mira 老闆 2026-05-13 提的):sub-workflow 自殺交棒模式,cypher-executor 不再做集中 graph executor。從根本繞開「cypher-executor 一個 invocation 跑長 graph」這條脆弱路徑。一勞永逸但是大改。
|
||
|
||
**衍生小 bug 仍要修**(跟付費無關):`set` 零件 input schema 變了(要 `assignments` 陣列或 `values` 物件,不是 `value`)。要嘛 update set 零件 contract 容錯,要嘛文件化新 schema。
|
||
|
||
**為什麼這直接擋封測**:
|
||
|
||
封測場景 Step 6「網頁 POST → 結果存 Google Sheets」走 google_sheets 零件 (HTTP outbound to googleapis.com)。如果 cypher-executor outbound 全壞,**封測者跑任何含外部 API 的 workflow 都會 522**,不是「Google Sheets 實際寫入未驗證」級別的小事。
|
||
|
||
**也直接擋 mira**:[polaris/mira/.agents/specs/mira-app/tasks.md] 7B.3c-f(wiki 合成 workflow)卡這裡。
|
||
|
||
---
|
||
|
||
## 四、封測前 P3(啟動當天)
|
||
|
||
- [ ] 用封測者 email 呼叫 `/register`,取得 api_key
|
||
- [ ] 將 ARCRUN_ENCRYPTION_KEY 以安全方式提供給封測者
|
||
- [ ] 確認聯絡管道
|
||
|
||
---
|
||
|
||
## 五、已知限制(封測期間不修)
|
||
|
||
1. `if_control` false branch 不路由(條件 false 時後續節點不執行)→ 升級計畫見 P1 #1,2026-05-14 mira 用 `kbdb_upsert_block` workaround
|
||
2. 多節點 context 不自動解包(上游輸出 flat merge,下游需從 `data.result` 取值)
|
||
3. 用戶自製邏輯零件(Phase 5)封測後才實作
|
||
|
||
---
|
||
|
||
## 六、實作進度
|
||
|
||
| Phase | 內容 | 狀態 |
|
||
|-------|------|------|
|
||
| 0 | Workers 部署、CI/CD、DNS | ✅ |
|
||
| 1 | CLI 基礎(init / validate / run / parts) | ✅ |
|
||
| 2 | /register、/cypher/execute、21 個零件 | ✅ |
|
||
| 3 | Service Binding 架構、{{variable}} 插值、ON_FAIL 修正 | ✅ |
|
||
| 4 | 動態 Recipe KV(CRUD)、acr recipe 指令 | ✅ |
|
||
| 5 | 用戶自製邏輯零件(WASM push) | ⏸ 封測後 |
|
||
| 6 | Credential 多租戶({api_key}:cred:{name})、acr creds push | ✅ |
|
||
| 7 | acr parts 內建清單、acr parts scaffold | ✅ |
|
||
| 8 | /webhooks/named、acr push 改版、config 套入 graph | ✅ |
|
||
|
||
### CLI 版本
|
||
|
||
| 版本 | 變更 |
|
||
|------|------|
|
||
| 1.1.0 | auth recipe 系統:20 個服務預建(Notion/Slack/GitHub/OpenAI/Google SA 等);acr auth-recipe 指令 |
|
||
| 1.0.9 | /register 回傳 encryption_key;acr init 自動儲存;creds push 不需手動設環境變數 |
|
||
| 1.0.8 | acr push → webhooks/named;config 套入 graph;acr parts 內建清單 |
|
||
| 1.0.7 | acr creds push → POST /credentials |
|
||
| 1.0.6 | acr recipe push / list / delete |
|
||
| 1.0.5 | hello.yaml 改 string_ops,--version 修正 |
|
||
| 1.0.4 | config/context 分離 |
|
||
| 1.0.3 | 初始發布 |
|