# Pending Changes（規格變更緩衝區）

> 規則來源：`SDD-LIFECYCLE.md` 第 3、4 條。
> 規格層變更（核心設計/方向改變）**只有這一條路**：CC 把 change proposal 寫進「待裁決」——
> 變更摘要與觸發原因＋影響分析（現行 SDD 哪些任務作廢/修改/不受影響/尚未完成）——然後**停止**，
> 等使用者明說「confirm」才依第 4 條開新 SDD；沒 confirm 就繼續依現行 SDD 工作。
> 多個 proposal 可並存，由人一次裁決。本檔不是 SDD，不掛 status。

## 待裁決

### P2｜fan-out 並行執行（一個節點的多條出邊目前是循序跑）— 2026-08-03

**觸發**：leo 08-03 原話——「這是在測試中的計畫，**希望體驗很好**，我發現用 gemma4 的反應非常慢。」
把 rag_chat 的生成端換成 Workers AI 之後（16.87 s → 2.2 s），一量才發現
**慢的大頭根本不是 LLM**。

**實測（1.4.4 實例，逐段疊加、每段取兩次的較快值）**
```
① prep（code）                    208 ms
② +kw_search                    1,383 ms   (+1,175)
③ +sem_search                   3,240 ms   (+1,857)
④ +fetch_triplets               5,198 ms   (+1,958)
⑤ +fetch_blocks a/b/c           7,793 ms   (+2,595)
⑥ +assemble（code）              8,421 ms   (+628)
   +ask_llm（Workers AI）        ≈10,400 ms (+2,000)
```
⇒ **6 個 KBDB 檢索節點合計約 7.6 s，佔全鏈 73%；LLM 只佔 20%。**
而這 6 個節點**彼此完全獨立**（kw／sem／triplets／blocks×3 誰都不吃誰的輸出），
只是因為 flow 被寫成一條鏈才一個接一個跑。

**根因在引擎，不在 workflow**（`cypher-executor/src/graph-executor.ts`）：
- 起點節點**已經是並行**的（`:85` `Promise.all(startNodes.map(...))`）
- fan-in **已經支援**（`:78-84` 入度 >1 的節點等所有上游到齊）
- 但**出邊是循序的**（`:427` `for (const edge of outEdges)`，迴圈內 `await executeNode`）
  ⇒ 一個節點分岔出 6 條 `ON_SUCCESS`，是一條跑完才跑下一條。
⇒ **改 workflow 解不了**：把 6 個節點都掛在 prep 底下，只是把「鏈」變成「6 條循序出邊」，一樣慢。

**提案（擇一，我建議 A）**

- **A. 出邊並行 ＋ 沿用既有 fan-in**：把 `:427` 那個迴圈改成
  「同型別、無條件分支的出邊」用 `Promise.all` 併發，其餘（`ON_TRUE`／`ON_FALSE`／`ON_BRANCH`／`ON_FAIL`）
  維持原樣。rag_chat 的 6 個檢索節點改掛在 prep 底下、匯流進 assemble（入度 6，fan-in 現成）
  ⇒ 預估 **7.6 s → 約 2 s**，全鏈約 **10.4 s → 4.5 s**。
  ⚠️ **這是引擎核心、風險最高**（照本 repo 自己的規矩：先寫測試再改）。
  需要先講清楚的語意：多條邊並行時 `result` 怎麼合併（現行是「後一條覆蓋前一條」的隱含語意）、
  任一條失敗時的行為、trace 的順序。**既有 workflow 行為必須零變化，且要跑一次證明。**

- **B. 只砍節點數（完全不動引擎）**：`kw_search`／`sem_search` 在 v2 計分裡只是小加分
  （kw 命中 +2、sem 前十 +0.4，主導權在 IDF 字面重疊）⇒ 拿掉這兩個節點可省約 3 s。
  代價是**檢索品質**（少了兩個佐證訊號），屬產品取捨，不是我能裁的。

- **C. 不做**：接受目前的 10 s。

**影響分析**
- 現行 active SDD `workflow-discovery`：A 屬引擎能力，與 3.9（`ON_TRUE`／`ON_FALSE` 走邊）同一塊，
  是**新增任務**，不作廢任何既有任務。
- B 只動 `arcrun-rag/workflows/rag-chat.local.yaml`，不碰本 repo。
- 三者都**不影響**已完成的 3.12（recipe 三層）與本次 Workers AI 換源。

**⏸ 停在這裡等 leo 裁**：回「A」我就先寫測試再改引擎；回「B」我只改 workflow；回「C」就記著不做。

### P1｜host fn 二進位通道（解開「零件無法處理非文字檔」的框架級限制）— 2026-07-27

**觸發**：leo 07-27 原話（arcrun-rag t73 收尾時）——
> 「**解析各種檔案的零件還是要開發的，要記下來**，雖然跟現在無關，
> 是因為**這次我用他本機來跑閃掉了**。」

**現況＝框架級硬牆（2026-07-27 實測，非推論）**：
Arcrun 的 host function 邊界是 **UTF-8 文字通道 ＋ 64 KB 上限**
（`outBuf` 64KB／`res.text()`／host fn 內 `TextDecoder`）。後果：
1. **零件拿不到二進位** ⇒ PDF/docx/圖片這類檔案，**做不出解析零件**。
2. 雲端 workflow 的 `fetch_raw` 走同一顆 `http_request` ⇒ 同樣拿不到。
3. 連純文字都受 64KB 限：15 頁 PDF 抽出約 40KB 尚可，**25 頁以上會爆**
   ＝「轉好了卻進不去」的靜默失敗。

**arcrun-rag 目前怎麼過關的（要講清楚，免得被誤會已解決）**：
把轉檔搬到 **daemon 本機**（`collector/convert.go` 調度層＋PDFium-via-wazero）——
**這是繞過（work around），不是修好**。leo 的原話「用他本機來跑閃掉了」講的就是這件事。

**為什麼仍要做（不擋當前工作，但別遺忘）**：
- **能力分裂**：現在只有「裝了 daemon 的人」有轉檔能力；**純雲端用戶永遠沒有**。
- **地端/雲端兩版格式支援會分岔**，長期維護兩套。
- 64KB 上限是**既有**限制，`.md` 今天就會撞到，PDF 只是讓它更快浮現。

**變更範圍（提案，待 leo confirm 才動）**：
① host fn 加二進位/base64 通道（或 ArrayBuffer 傳遞）
② 放大或分塊化 `outBuf`（串流/分頁讀取，避免單次 64KB 天花板）
③ 之上才談「各格式解析零件」

**影響分析**：
- **不受影響**：現行 active SDD `portal-auth` 的所有任務（不同層）。
- **不擋**：arcrun-rag t73 本機轉檔層照做（已 commit `74d18ff`）。
- **牽動**：`http_request` 零件、code 零件的 host fn 契約 ⇒ 屬**全人共用框架**改動，
  影響所有既有零件，**必須 leo 拍板**（跨專案結構決策）。

**現在不做的理由**：leo 明說「跟現在無關」＋客戶在等 daemon；本條僅**立案留底**，
避免「本機能跑了」被後人誤讀成「這個限制已解決」。

## 已裁決

### ✅ confirmed 2026-07-24｜CP2-F cypher 二～四刀拆分（leo 授權總管技術裁決）

> **裁決依據**：leo 2026-07-24 原話「不影響現在 CP 的話就排下一個，這個你是需要判斷的，不能是我，完全技術問題」。
> **總管裁決**：confirm。排程＝A4 全通＋t21/t24 合併重部之後（與在途不撞）。
> **四題**：①開工時點＝同上 ②刀④驗證＝**手寫**（瘦身工程不再引依賴；兩鏈手寫+測試）③新 worker 命名＝**arcrun-api** ④CP2-F 記載更正已由總管代辦。
> 開工時照 D35 ④ 先開新 SDD 搬任務再寫 code。

### P-2026-07-24：CP2-F 第二～四刀——執行引擎獨立成精簡 worker（cypher 瘦身收官）

> 提案人：總管交辦之 arcrun 偵察 subagent（唯讀分析，未動 code、未部署）。
> 觸發：頂層 CRITICAL-PATH.md CP2-F（w=9，P3）——「免費起步」承諾不成立；
> leo 定調：workflow 執行引擎獨立成精簡 worker（只做調度），console/portal/credentials/webhooks 拆出去。
> **依 D35：現行 active SDD＝portal-auth，與本題不同卷，故只寫 proposal 停下等 confirm，不動 code。**

#### 0. 先更正頂層 CP2-F 的過時記載（本次實測核實）

| 項目 | CP2-F 記載 | 2026-07-24 實測 | 出入原因 |
|---|---|---|---|
| 原始碼行數 | 15,446 行 | **11,050 行**（`find src -name '*.ts' \| xargs wc -l`） | 第一刀已砍 |
| bundle | 748KB | **528.1KB**（540,742 bytes，`wrangler deploy --dry-run --outdir` 實跑） | 同上 |
| 「ingest 必爆」 | 隱含現在式 | **已穩定**（第一刀驗收：連灌 10 張全過、同卡 6 連跑全過） | 5a16484 已修 |
| /health 5-7ms、9ms/節點 | 現在式 | **拆分前舊數，第一刀後未重測**——本提案每刀驗法含重測 | 未更新 |

第一刀＝commit `5a16484`（07-21）：console.ts(1623行)＋portal-ui.ts(1390行) 搬去 `console-ui/` CF Pages
（arcrun-console-ui.pages.dev），748→528KB（-29%）。07-22 `ad367e4` 補 console-ui build 修復＋
`deploy.targets.json` 具名部署目標（personal/enterprise 兩 profile，帳號＋apiBase＋專案名收一檔）。
→ **CP2-F 條目該由總管在頂層更新為「第一刀 ✅、二～四刀待裁」**，狀態從 ❌ 斷改 ◐ 半通。

#### 1. Bundle 實測解剖（528.1KB，sourcemap byte 級歸因，非推測）

方法：`npx wrangler deploy --dry-run --outdir=<scratch>` 產 index.js＋index.js.map →
自寫 VLQ 解碼器把每個 byte 歸因到原始檔（mapped 507.5KB＋bundler glue 20.5KB）。

| 模組 | KB | 佔比 | 主要檔案（行數） | 去向提議 |
|---|---|---|---|---|
| **dep: zod** | 130.6 | 24.7% | 只被 `lib/schemas.ts`＋`lib/prompt-recipe-schema.ts` import | 刀④逐出引擎 |
| **dep: hono** | 76.9 | 14.6% | 框架 | 兩邊都要，留 |
| **執行引擎核心** | 74.3 | 14.1% | graph-executor(702)、component-loader(370)、wasi-shim(674)、execute/executions/resume/cypher routes | **留（引擎本體）** |
| Credentials/Auth | 48.0 | 9.1% | auth.ts(467)、credentials.ts(322)、auth-dispatcher(301)、auth-recipe-seeds(748行/21.9KB) | CRUD＋seeds 搬；dispatcher 讀路徑留 |
| Portal（RAG 多人） | 42.3 | 8.0% | portal.ts(783)、portal-data.ts(457)、portal-auth、portal-seeds | 刀②搬 |
| Console API | 31.8 | 6.0% | console-dashboard(526)、console-auth(165)、兩 model(616) | 刀②搬 |
| dep: unenv/polyfill | 29.1 | 5.5% | nodejs_compat 代價 | 留（兩邊皆有） |
| Webhooks CRUD | 25.6 | 4.8% | webhooks-named(521)含觸發＋管理混一檔 | **拆檔**：trigger/query 留、CRUD 搬 |
| Recipes CRUD/seeds | 24.1 | 4.6% | recipes.ts(563)、api-recipe-seeds、init-seed | CRUD/seeds 搬；`resolveRecipe` 讀路徑留 |
| Docs/OpenAPI | 12.5 | 2.4% | openapi.ts(306) | 刀③搬 |
| KBDB proxy | 8.4 | 1.6% | kbdb-proxy.ts(272) | 刀②搬 |
| scheduled/cron | 3.7 | 0.7% | scheduled.ts、cron-* | 留（觸發面） |

**三個關鍵事實**：
- zod 一家＝24.7%，卻只服務「入口驗證」兩條鏈（execute→schemas、recipe-loader→prompt-recipe-schema）。
- 引擎真身（核心+hono+unenv）只要 ~180KB；其餘 ~350KB 全是管理/前端 API 面。
- 耦合點：`graph-executor.ts:6` import `resolveRecipe` from `routes/recipes.ts:406`——
  **讀路徑長在 CRUD 路由檔裡**，拆分前要先抽到 lib（刀②-0 前置小步）。

#### 2. 拆分方案（Option A：引擎留原地，管理面搬出——推薦）

**為什麼引擎留在 cypher-executor 原 worker 不搬家**：webhook 觸發 URL
（`/webhooks/:token/trigger`、`/webhooks/named/:ns/:name/trigger`、`/q/:ns/:name`）
被外部 caller（Telegram webhook、Routine、CLI、MCP）焊死；引擎留原地＝**外部零改動**。
反向（引擎搬新 worker）要全網改 URL，風險大得多，不採。

**佈局**：既有 25 顆（22 零件＋cypher＋kbdb＋mcp）→ **26 顆**：新增 1 顆 `arcrun-api`（管理/控制面 TS worker）。
（arcrun-api 是框架自身的 API 面、非業務零件，與零件須 WASM 的鐵律不衝突——cypher 本身同理。）

| 端點群 | 去向 |
|---|---|
| `/execute`、`/cypher/*`、`/validate`（刀④前）、`/resume`、`/executions/*`、`/workflows/:name/executions`、webhook **trigger/query**、`/health`、scheduled cron | **cypher-executor（引擎）留** |
| `/portal/*`、`/portal/data/*`、`/console/*`、`/kbdb/*`（proxy）、`/credentials/*`、`/auth/*` CRUD、`/recipes/*` CRUD、`/webhooks` CRUD＋named 管理（backfill/migrate/delete/list）、`/init-seed`、`/docs`＋OpenAPI | **arcrun-api（新）搬** |

**Service binding 過渡（13 顆 SVC_\* 懶載現況）**：零風險——13 個 binding 服務的是
`component-loader.ts:73-85` LOGIC_BINDING_MAP 的邏輯零件調度，**全屬引擎**；引擎不搬家＝
wrangler.toml `[[services]]` 原封不動。arcrun-api 完全不需要 SVC binding。
未配置時 fallback 公網 workers.dev 的既有機制（component-loader.ts:249-272）也不動。
self-hosted 的 deploy.ts 注入機制（D1 database_id 等）需對 arcrun-api 的 toml 複用同款注入——既有機制，非新開發。

**與 07-22 第一刀銜接**：console-ui Pages 的 `ARCRUN_API_BASE`（build 期參數）刀②時改指
arcrun-api；`deploy.targets.json` 兩 profile 各加一欄，部署命令不變。

**刀法（分三刀，每刀獨立可回退）**：
- **刀②（先抽 resolveRecipe 到 lib）**：Portal＋Console API＋kbdb-proxy 搬 arcrun-api。
  預估 -82.5KB → 引擎 ~446KB。console-ui apiBase 同步切。
- **刀③**：credentials/auth CRUD＋webhooks 管理面（先把 webhooks-named.ts 拆成 trigger/管理兩檔）＋
  recipes CRUD＋init-seed（含兩包 seeds 30KB）＋docs/openapi 搬過去。預估 -90KB → 引擎 ~355KB。
- **刀④（zod 逐出引擎）**：`/validate` 搬 arcrun-api（zod 隨行）；`/execute` 入口驗證改手寫窄驗證
  （graph shape 檢查 ~50 行）或換 valibot（~10KB）；prompt-recipe-schema 同款處理。
  預估 -130KB → **引擎 ~200-225KB（對 528KB 減 ~60%）**。

**目標與誠實邊界**：/health <2ms 主要靠 bundle 縮（冷啟 parse＋常駐面縮）可期；
但**單節點 10ms 內不保證光靠瘦身達標**——9ms/節點若主要來自 per-node KV put
（graph-executor.ts:352 每節點 `kvSetNodeOutput`）＋JSON 序列化，則需**刀④.5（備案）**：
node output 改「僅斷點/暫停時寫 KV、其餘記憶體傳遞」。是否需要動，以刀②後的 cpuTime 實測決定，不預先動。

#### 3. 每刀驗法（免費層 cpuTime 實測法）

每刀收工四件、缺一不算完成（守 CP 使用規則 6/7）：
1. `wrangler deploy --dry-run` bundle size 對照表（貼實跑輸出，驗預估）。
2. vitest 全綠＋tsc 0（現基線：cypher 169/170，唯一失敗＝executor「不存在的零件」pre-existing）。
3. **免費層 cpuTime 實測**：部署後 `npx wrangler tail arcrun-cypher-executor --format=json` 抓
   `cpuTime`，三個探針各打 10 次取 P50：/health、單節點 workflow（http_request×1）、
   km_wiki_ingest（6 節點）。記進 CP2-F 條目當證據。
4. 端到端頭尾驗：console-ui 兩 profile 登入＋搜尋（打 arcrun-api）、portal 登入、
   `acr push`＋`acr run` 走引擎、**webhook trigger 原 URL 打通**（外部 caller 不改的承諾）。

**回退**：每刀＝一個 PR；arcrun-api 是加法（新 worker），引擎側只刪路由掛載——
回退＝revert PR＋重部引擎（arcrun-api 留著不礙事）。KV/D1 零 schema 變更，無資料遷移，無不可逆步驟。

#### 4. 影響分析（D35 第 3 條）

- **portal-auth（現行 active）**：P1-P4 已完成待部署排練。刀②把 `/portal/*` 路由搬 arcrun-api＝
  **只搬家不改行為**，其測試（portal 三套 56/56）隨檔案搬移後應原樣全綠；
  但其「部署清單」要加一行（portal 部署目標從 cypher 變 arcrun-api）。**不作廢任何任務**。
- **第一刀遺留（5a16484「未做（第二刀）」清單）**：console-dashboard/portal/portal-data＝本提案刀②，正式立案銷帳。
- **library-map（draft）**：M5 console 首頁區塊打 `/kbdb/map`——kbdb-proxy 刀②搬家後 console-ui apiBase 同步切，不改功能。
- **P-2026-07-21 registry proposal 的 B1**（「在 cypher-executor 開 GET /search」）：若兩案都 confirm，
  `/search` 統一面該開在 **arcrun-api** 而非引擎（搜尋是管理面不是執行面）——兩案不衝突，落點修一字。
- **不受影響**：22 顆零件、kbdb worker、mcp、CLI（`acr` 打的執行端點全留原 URL）、
  webhook 外部 caller、13 個 service binding、artifact-sharing（confirmed）各 Phase。
- **新增維護面（誠實記）**：多一顆 worker 要部署（官方＋self-hosted 各一次）；
  deploy 腳本/文件要加 arcrun-api；兩 worker 共用 KV/D1 binding（同一批 id，讀寫面分離）。

#### 5. 待 leo 拍板點

1. **開工排序**：CP 排 P3（P1=CP3-A、P1↑=A4 OAuth 在前）。本提案只求 confirm 方案，開工時點照 CP 排序走——除非 leo 要提前。
2. **刀④驗證庫選擇**：手寫窄驗證（零依賴、-130KB 全拿）vs valibot（保留 schema 風格、-120KB）——品味題。
3. **arcrun-api 命名**：`arcrun-api`？或併入既有規劃中的其他 worker？（跨 repo 佈局＝總管/leo 層決策）
4. **頂層 CP2-F 條目更正**（§0 表）由總管執行——本 repo 只能在此記載，不碰頂層文件。



> 提案人：總管交辦之 arcrun subagent。
> 觸發：leo 2026-07-21 —「一旦推進一個零件，就自動進 registry；recipe、workflow、app 都應該可以 registry，
> 不然搜不到。一邊是寫進去，另一邊是搜到，當然要有。」
> 判準：「Arcrun ＝ 讓 AI 輕易建立程式碼」「AI 要覺得 Arcrun 比 Python 還簡單，絕不可迷路」。
> **依 D35：本任務找不到對應的 active SDD（現行 active＝portal-auth，與本題無關），
> 故不動 code、不自建 SDD，寫本 proposal 後停止等 leo confirm。**

#### 一句話

registry 的寫入機制**存在且可用**，但它唯一的自動觸發點長在 GitHub Actions 上；
Actions 因防 flag 鐵律被整個刪除後（commit `037cf9b`），**寫入端失去觸發者、庫從此是空的**。
這不是「沒有機制」，是「機制的手被砍掉、沒補上替代觸發點」。

#### 根因（file:line 級）

| 事實 | 證據 |
|---|---|
| 寫入端點存在 | `registry/src/routes/components.ts:112` `POST /components/index-only`（metadata-only 索引，冪等） |
| 寫入實作存在 | `registry/src/actions/indexOnlyComponent.ts:44` 寫 `comp:{hash}:{ver}` + `idx:{canonical_id}` 兩個 KV key |
| 批次灌注腳本存在 | `registry/scripts/backfill-index.mjs`（掃 22 個 contract.yaml → POST index-only） |
| 單顆註冊腳本存在 | `registry/scripts/register-component.sh`（註解自稱「本地+CI 共用 SSOT」） |
| **唯一自動觸發點已不存在** | `git show 037cf9b^:.github/workflows/deploy.yml` 第 269-275 行有 `Register component in registry` step 呼叫上述 sh；`037cf9b` 刪除整個 `.github/workflows/`，**該 step 隨之消失，無替代品** |
| 從未跑過的實證 | 對 leo21c 跑 `REGISTRY_URL=... node scripts/backfill-index.mjs --dry-run` → 22 顆待灌；線上 `/components/search?q=http` 回 `count:0` |

→ **答案：是「有機制但從沒跑過」**（且失去觸發者），不是「沒有寫入機制」。
→ 附帶事實：`registry/wrangler.toml:26` 的 `[[routes]]` 寫死 `registry.arcrun.dev`，
  self-hosted（leo21c）只能靠 workers.dev URL，backfill 腳本預設 `REGISTRY_URL` 也是官方域 —— 需帶環境變數才會打到自己的庫。

#### 重要更正：leo 要的東西**有一半已經存在，只是不在 registry 上**

`acr search <term>`（`cli/src/commands/search.ts`）已經是 leo 描述的「意圖驅動、跨類一次搜」——
它 fan-out 四個來源（component 靜態清單 / `/recipes` / `/auth-recipes` / `/webhooks/named`）。
**實測（2026-07-21，leo21c，真實輸出見交辦回報）**：
- `acr search http` → 命中零件 `http_request`（驗收劇本 1 ✅）
- `acr search notify` → 命中 recipe `line_notify_send` + auth-recipe `line_notify`（劇本 2 部分達成）
- `acr search github` → 命中 auth-recipe `github`（驗收劇本 3 ✅）
- `acr search telegram` → 命中 recipe `telegram_send` + auth-recipe `telegram`

→ **能力在 CLI 有、在 registry/MCP 沒有**。這正是薄殼原則（rule 07）被違反的典型：
  同一個「跨類搜尋」能力長在介面層（CLI）而非 API，於是另一個薄殼（MCP）享受不到。
  **修法的方向不是在 registry 重造一套搜尋，而是把 `acr search` 的 fan-out 能力下沉成 API 端點，CLI/MCP 同吃。**

#### 提案內容（四件，全部需 confirm 後才動）

**A. 寫入端：補回失去的觸發點（不復活 Actions）**
- A1. `acr push` / `acr deploy` 成功後自動呼叫 `POST /components/index-only`（本機發起、低頻、單 repo，守 D20 讀寫界線與防 flag 鐵律）。
- A2. `acr init` / `acr update` 部署完 22 顆零件後跑一次 backfill（讓新裝的人開箱即有索引）。
- A3. **recipe / workflow 不需要新的 registry 寫入路徑**——它們本來就活在 store（KV），
  `acr recipe push` / `acr push` 當下就已「寫進去」。缺的只是**搜尋端讀得到**（見 B）。
  → leo 說的「recipe、workflow、app 都應該可以 registry」，正解是**統一搜尋面**，不是把它們搬進 registry KV 再存一份（那會製造第二份真相源）。
- A4. `app`（bundle）已有 P-2026-07-19 artifact-sharing 卷涵蓋，本卷不重複立案，只在搜尋面預留類別。

**B. 搜尋端：能力下沉 + 語意**
- B1. 在 **cypher-executor** 開 `GET /search?q=`（不是 registry——因為 recipe/workflow 的真相源在 cypher 的 KV），
  server 端做 `acr search` 現有的四類 fan-out，回統一結果（含 `type` 欄位）。
- B2. `acr search` 與 MCP 新 tool `arcrun_search`（或改造 `arcrun_search_components`）雙雙改為呼叫 B1，介面層不再自行 fan-out（回歸薄殼）。
- B3. 語意搜尋：KBDB 那條路已驗證可用（Vectorize），把四類的 description 灌進去，讓「我要打一個 HTTP API」這種自然語言句命中 `http_request`。
  現行 `registry/src/actions/queryComponents.ts:104` 明載「這是 Phase 0 的純文字比對版本，Phase 2 接入 Vectorize」——本項即補完該 Phase 2。
- B4. 搜不到時的文案改為「導向 recipe / 既有 workflow」，**移除「可以用 arcrun_publish_component 提交新零件」的建議**（見 C）。

**C. 斷掉「推人去寫零件」的路**
- C1. `mcp/src/tools/arcrun_search_components.ts:50` 搜不到時明文建議 `arcrun_publish_component` —— 違反 leo 既定規矩（零件走 PR、專業等級）。改為導向 recipe/workflow。
- C2. `arcrun_get_component_guide`（回 TinyGo 寫 WASM 教學）與 `arcrun_publish_component` 對一般使用者是誤導 → 建議降級為「專業模式」才暴露（預設不掛載），或在描述首句明寫「99% 情況你不需要這個，先用 recipe」。
- C3. **查證結果：零件相關「已拆到另一個 repo」未獲證實**——`registry/components/` 22 顆零件仍在本 repo，
  wiki 與 git 均查無拆分紀錄。leo 的印象可能來自 `.github-public/` 對外鏡像（`GitHub mirror 發佈模型`）。**此點需 leo 確認**。

**D. 過時項**
- D1. MCP 仍要求已廢的 `api_key` 參數者共 **15 處**：`arcrun_introspection.ts`（4）、`arcrun_recipe.ts`（6）、`arcrun_workflow_crud.ts`（5）。
  2026-07-20 已改 namespace 明碼 → 這些應改為由 server 端 namespace 推導，不再要 AI 傳。
- D2. **1042 的真正解法已確認並已落地**（本項無需修 code，只需更正記載）：
  `global_fetch_strictly_public` compatibility flag，已實裝於 `cypher-executor/wrangler.toml:13`
  與 `.component-builds/http_request/wrangler.toml:8`。
  leo 說的「開了一個什麼，把所有呼叫都視為外部」＝**這個 flag**（讓 same-zone fetch 走公網前門）。
  wiki 已有正確記載：`system-dev/wiki/cards/decisions/same-zone-1042用flag解不用binding.md`、
  `mistakes.md:101`、`decisions-summary.md:84`。
  → 「graph_neighbors 改用 recipe 繞過」的過時說法**在本 repo wiki 查無此記載**（status.md:50-52 只寫 MCP tool PR），
    該過時記載可能在頂層 InkStoneCo wiki 或 MEMORY.md，需由總管在該層更正。

#### 影響分析（D35 第 3 條要求）

- **現行 active SDD（portal-auth）**：完全不受影響，本提案不碰其任務。
- **`component-registry-canon`（status: paused，2026-05-07 建）**：**本題其實早有此卷**，
  其 §1.2 診斷的根因與今日實測完全一致（「registry 活著但 index 空的，AI 找不到零件就會繞回 Python」），
  尚有 **29 個未完成任務**。→ **建議：不新開 SDD，改為把此卷 resume 成 active**（並把 A/B/C/D 的新項增補進其 tasks），
  這比另立新卷更符合 D35 第 4 條「先搬移未完成任務」的精神，也避免第二份重疊規格。
  ⚠️ 但這需要先把 portal-auth 收尾或轉 paused（單一活性鐵律），**此為 leo 的排序決策，不是 CC 能裁的**。
- **`workflow-discovery`（paused）／`library-map`（draft）**：與 B1 統一搜尋面高度重疊，resume 時應一併檢視是否合併。

#### 待 leo 拍板的四點

1. **排序**：要不要把 `portal-auth` 讓位、resume `component-registry-canon` 來做這件事？（單一活性鐵律強制二選一）
2. **C2**：`get_component_guide` / `publish_component` 要「預設不掛載」還是「留著但改描述」？（品味/方向）
3. **C3**：零件是否真的已拆到另一個 repo？（leo 記憶待證實）
4. **B3 語意搜尋**：四類描述灌進 Vectorize 會產生 embedding 呼叫成本，確認可行？（花錢）
### P-2026-07-19：artifact-sharing 增補「App（bundle）＋實例譜系＋訂閱更新＋多源分享」

> 狀態：**confirmed 2026-07-19**（leo「好的可走」）。四個拍板點總管採建議值（leo 可翻案）：①排序＝Phase 1.5 緊接 Phase 1、在 KV 退休（#16/#17）前後皆可並行 ②訂閱預設 policy＝notify ③側載標記第一波＝列表標記即可 ④P6 第一波＝官方源＋直連一個外源，org 私區留第二波。tasks 增補見 artifact-sharing/tasks.md「Phase 1.5」段。

> 提案人：雲端總管（leo 2026-07-19 對話三輪收斂後令「寫」）。
> 目標 SDD：`Leo/Arcrun` `system-dev/docs/3-specs/arcrun/artifact-sharing/`（#27＋#31）。
> 依 D35：本檔為規格層 proposal，**寫入 pending-changes.md 後停下等 leo confirm**，confirm 前不動 tasks、不寫 code。

## 一句話

workflow/recipe/template 的實體在平台（CF/KBDB），不在 YAML——YAML 是隨叫隨到的視圖（搖桿）。
因此版本控制、譜系、更新通知必須是**平台內建能力**，git 降級為：引擎程式碼的家＋人審 diff 面＋災備快照。
本提案把 #27 公庫從「單品發布/拉取」補全成「App 商店＋訂閱更新＋實例譜系」。

## 背景（為什麼現在）

- 實證痛點：arcrun-rag（企業）與 Mira（個人）跑同族管線的兩份變體（rag_ingest v2 vs km_wiki_ingest），
  「哪邊同步了沒」靠人腦；claude.ai 07-19 實測抓到的三個引擎缺口再證「修一次、兩實例都該自動受益」的通道不存在。
- T-pack-v2「repo 即真相源」是**過渡義肢**：因為平台缺版本層（KV 讀不回、無版本、無譜系），才用 git 代位。
  義肢照 D15 前例：平台長出器官後拆。
- 地端版（workerd）將成第三個實例形態——在複雜度上升前把「App×實例×版本」模型立好。

## 提案內容（五件）

### P1. bundle 第四型（App）
- `public_artifact` 新增 `type=bundle`。portable_body＝成員清單：
  `[{type: workflow|recipe|template, canonical_id, uuid(鎖版) 或 version_policy(track-latest)}]`
  ＋`install_params_schema`（安裝參數：多人開關、Gitea 端點、LLM provider…）＋`conformance`（見 P5）。
- 「裝一個 App」＝pull 一個 bundle，成員經既有 dependency_manifest 機制解析；
  個人版與企業版＝**同一個 bundle、不同 install params**。
- arcrun-rag 為第一個 bundle（現行 install.sh 即其手寫前身，落地時翻譯成 manifest）。

### P2. 訂閱與更新通知（可拒、可 pin）
- install/pull 時建立訂閱關係：新 entry `artifact_subscription`
  （subscriber namespace、canonical_id、目前安裝 uuid、policy: notify|auto|pin）。
  （`artifact_pull_event` 保持純事件帳本不改；訂閱是關係、事件是史料，分開存。）
- 新版 submit-p 後，訂閱者「得知」的通道**查詢式優先**：
  `GET /subscriptions/updates`（實例/AI/console 隨時問「我有沒有落後」）；
  推播（notify workflow）為選配、且**禁止因發布事件自動 fan-out 到多實例**（D4 紅線——通知生成可以批次/排程，不掛事件觸發鏈）。
- 更新永遠是訂閱端的**顯式動作**：可更、可拒、可 pin 死版本。

### P3. installed_from 譜系＋側載標記（隱形工作流可見化）
- 實例內每個 materialized artifact（workflow/recipe/template）落籍記
  `{installed_from_uuid, installed_at, content_hash}`（entry metadata，不建表）。
- 平台即可回答四態：`up_to_date / behind / diverged（本地改過）/ sideloaded（無譜系，API 直建）`。
- list/console/MCP 的 workflow 列表帶狀態標記。**側載不禁止、只標記**（Android sideload 哲學）；
  「沒有 YAML 就不准」的 policy 不採納——對 AI 是降頻，可見性由本條提供。
- 既有 git 外掛式 drift 稽核（guard 對 hash）為過渡措施，本條落地後退役。

### P4. 更新與分岔語意
- update＝拉新版重新 materialize（installed_from 換新 uuid）。
- `diverged` 者不自動覆蓋：提示二選一——fork（submit-p 推回公庫成自己的作者版本，derived_from 記溯源）或捨棄本地改動收新版。
- 對應 leo 模型：「Mira 和 Arcrun RAG 都 clone 了 rag app，都可以推回去存成新版本，收到更新通知但自己決定要不要更」。

### P5. conformance self-check 隨 bundle（驗收矩陣自動化）
- bundle 附驗收清單：介面×能力的機械檢查（例：portal 登入 200、MCP tools/list 含 kbdb_*＋graph、
  keyword/semantic/graph 三模式各一題 golden question 命中）。
- install/update 完自動跑、產報告；解「企業 GUI 驗了但企業 MCP／個人 GUI／個人 MCP 不知道、檢查到沒完沒了」——
  可用性從人肉巡邏變安裝產物。地端（workerd）實例＝同一張體檢單多跑一列。

### P6. registry＝源（source）非地方：多源與點對點分享（leo 2026-07-19 追加）
- 公庫端點長在 cypher-executor＝**每個實例都內建 registry 能力**；官方公開市場只是「預設源」。
- 實例可加多個源：公開市場／org 內部源／**另一個實例直連**（A 做了 App，B 把 A 加為源直接拉，CF-to-CF，不經公開市場——Homebrew tap 模式）。
- artifact 加 `visibility: public | org | unlisted`；外源拉取走既有 token 認證（portal-auth／MCP OAuth 機制，A 發「可拉取」token 給 B）。
- P3 落籍擴充：`installed_from` 記「源＋uuid」；P2 訂閱跨源成立（B 訂閱「A 源上的 canonical_id」）。
- **信譽記分邊界**：私下/org 內分享的 pull 事件留在該源帳本，**不進公開信譽**；日後同 canonical 發布公開市場，溯源保留、私史不折算。
- 信任判斷仍在 import 端（#27 原則）：來源是誰，列表標記說清楚。

### P6 鐵律：拉取＝落地複本，runtime 零外部依賴（leo 2026-07-19 Drive 之問定形）
- pull/install＝把 artifact（含 dependency_manifest 解析出的全部依賴，跨源亦然）**materialize 進本實例 KBDB**——複本式分發（npm/App Store），非引用式分享（Google Drive）。
- 源斷線/停止分享＝只失去更新，**已裝的照跑**；狀態標 `source_lost`。互相參照在安裝時全落地，runtime 永不回頭找源；只有「查更新」動作碰源。
- 多源不亂的機制：裝完面對的是一張本地清單（每項帶源＋五態標記）；同 canonical_id 跨源衝突＝安裝時顯式選源，不靜默合併；bundle 鎖版 uuid＝lockfile 對應物。

### 排序定調：分享先行、投稿後行（leo 2026-07-19 收斂）
- **官方的本質＝第一個策展人**（leo 定調）：官方源不是特權角色，就是「把很多資源收集起來分享給大家的人」；公開市場＝分享機制＋官方獎勵制度（信譽層）疊上去，作為分享落地後的下一件事。
- **先做**：P6 最小版（官方源＋直連外源）＋P1＋P3 → 這就是產品自己的部署通道（leo 官方源→客戶實例拉 arcrun-rag bundle；第一組 A/B＝leo 與第一個客戶、以及 Mira）；再 P2 訂閱更新。
- **後開**：公開投稿＋信譽榜——空市場掛榜＝鬼城，等 self-hosted 用戶密度夠再開（社群玩法）。
- **零代價保證**：#31「事件是真相、統計是視圖」——pull/submission 事件 day-one append，信譽晚開也能從頭算，先分享不欠投稿任何債。

### 附：獎勵/信譽（確認既有設計，非新增）
- 「貢獻 recipe 得 reputation」＝#31 作者信譽經濟已設計（作者頁/聚合信譽/選版複合分/獎勵層預留、author 綁認證身份）；事件 day-one append 保證信譽可事後計算。
- 本提案只補一句：**bundle（App）作者同樣累積信譽**——組裝 App 與寫 recipe 同屬貢獻。

## 影響分析

- **不建表**：全部走 entry_type＋metadata_json（D6 鐵律）；`artifact_subscription`／落籍 metadata 皆 template/slot 層。
- **與 Phase 1 關係**：不改既有 1.1–1.6 任務；本提案為 Phase 1.5（bundle/lineage/subscription 建在單品公庫之上）。
  1.5 的 recipe KV 過渡（#16）不受影響。
- **與 D4 flag 鐵律**：通知採查詢式優先、禁事件 fan-out（見 P2），無 GitHub 流量、無 Actions。
- **與現行 installer**：過渡期 install.sh 續用；第一步可先讓 installer **代寫 installed_from 落籍**（義肢幫器官接生），
  公庫端點好了再切換 pull 路徑——遷移平滑、無一次性大爆改。
- **受益者**：Mira 跟上企業版＝「訂閱同一個 bundle 按更新」；未來 N 個客戶實例同此通道；地端版=第三個實例非第三套系統。
- **風險**：scope 擴張（#27 尚未動工就加型）——緩解：P1/P3 是最小核（bundle 形狀＋落籍欄位），
  P2 通知與 P5 self-check 可各自獨立分批落地；全部 compute-on-read 起步，物化快照沿用 #31 判準。

## 待 leo 拍板點

1. Phase 1.5 排序：在 Portal（#24/#25 已收官）之後、KV 退休（#16/#17）之前或之後？
2. 訂閱 policy 預設值：notify（通知不動手）？
3. 側載標記的呈現強度：只列表標記，或 console 加「無譜系 workflow」提醒區塊？
4. P6 多源第一波範圍：只做「官方源＋直連一個外源」？org 私區（visibility=org）是否留第二波？

---

## [proposal] 兩個真缺口要進 SDD（2026-07-30，總管提，等 leo confirm）

**來源**：頂層 CP `critical-paths/arcrun-usable.md`（leo confirm 開工）逐步查證後，
發現兩件事**SDD 完全沒有**，而它們是「AI 不必寫 code」的前提。

leo 的判準（2026-07-30）：
> 「如果在這裡編任務，不就是廢掉了原本的 SDD，那到底要照 SDD 做事還是照 CP？」
⇒ **照 SDD 做事、照 CP 排順序**。CP 不得自帶任務 ⇒ 這兩件必須進 SDD 才能做。

### 缺口 ①：引擎缺條件邊（`ON_TRUE`／`ON_FALSE`）→ 建議進 `arcrun-core-mvp`

- **實測**：`if_control` 的 output 是 `{result: boolean, branch: "true"|"false"}`，
  但 `cypher-executor/src` 全域 grep `ON_TRUE|ON_FALSE` = **0**（圖的邊只有 `ON_SUCCESS`）
- **後果**：AI 照規矩用 `if_control` 也只拿到布林值，**還是得寫 code 判斷該走哪裡**
  ⇒ 這是「為什麼 workflow 全變成 code」的根（8 個 code 節點含 if×61）
- **佐證**：`kbdb_upsert_block` 契約自述「解 arcrun workflow **缺 IF/branch 能力**的缺口
  （arcrun.md P1 #1）」；Gitea **Arcrun#5**「if_control 無法真擋分支，filter+FOREACH 才是真閘」
  於 **2026-07-04** 就發現，至今未修
- **SDD 查證**：`grep "ON_TRUE|ON_FALSE|條件邊|分支"` 於全部 SDD → 7 命中**全是別義**
  （「部署分支」「git 分支」），**條件邊本身完全沒設計過**
- **影響面**：改圖 schema ＋ `graph-executor` 走邊邏輯＝引擎核心，風險最高
  ⇒ 建議排在「查詢誠實」「節點替換」驗過之後

### 缺口 ②：recipe 缺 payload 與回應處理層 → 建議進 `recipe-system`

- **實測**：recipe schema 只有 `{canonical_id, endpoint, method, auth_service}`
  （線上 `GET /recipes/telegram_send` 實查）
- **後果**：`telegram_send` 的 description 明寫「body 帶 chat_id+text」但**schema 存不住 body**
  ⇒ 任何要帶 body 的 API 都只能繞過 recipe、把 URL/header/body 整包寫進 workflow
  ⇒ Gemini 就是這樣寫死的（`ask_llm` 三層全塌進節點）
- **要補三層**
  - `body_template`（payload）
  - `response_map`（回應正規化：取值路徑／思考型模型旗標／淨化規則）
    ——現在這段是 workflow 裡 2786 字元的 code（`finalize`）
  - `auth` 加第四型 `binding`（免金鑰；一次打開 `env.AI`／`VECTORIZE`／`BROWSER`／`QUEUE`）
- **SDD 查證**：`grep "body_template|response_map|payload"` → 17 命中**全是別的 payload**
- **不做的話**：LLM 換源永遠要改 workflow（而非換 recipe），違反「LLM 可換源」原則

### 誤標修正（誠實記錄）
總管原本在 CP 標了 **5 個新缺口**，逐條查 SDD 後**只有上述 2 個是真的**：
- `success_rate` 回寫 → **`arcrun-core-mvp/design.md:499` 早就設計**
  （`success_rate = success_runs / total_runs * 100`、排序規則、UI 顯示），只是沒實作
- 8 個壞範例、意圖節點替換 → 相關設計散在既有 SDD，已改為引用

### ⏸ 等 leo confirm
- confirm 後依 D35：兩份 SDD 目前皆 `paused`，要動需先處理單一活性
  （現行 active＝`workflow-discovery`）


## 提案：workflow export/import 一等公民化（2026-07-31，總管代 leo 口頭定調立案）

- **來源**：leo 07-31 原話（見 workflow-discovery tasks.md 3.9 引文）——分享 workflow
  給同事的正路＝export 檔→import，不是「用 search 湊」。
- **變更面**：① cypher `GET /webhooks/named/:name/definition`（已實作，staging 試點中，
  零新資料模型／同 list 認證）② `acr workflow export <name>`／`acr workflow import <file>`
  新 CLI 命令（已寫未接線）③ 安裝器 workflows.json＝export 檔同形狀（graph 預編，已上 prod）。
- **不動的牆**：KBDB 零接觸（export 讀 WEBHOOKS KV workflow record；import 打既有
  POST /webhooks/named）；「部署≠發現」（import 不驗零件存在，執行時現形）；
  description 必填閘照舊。
- **影響分析**：新公開端點 1 個（租戶 key 認證，吐的是該租戶自己部署的 workflow 定義；
  無跨租戶讀）；CLI 新命令 2 個（薄殼，能力全在既有 API）；無 schema migration、無新金鑰面。
- **狀態**：⏳ 待 leo confirm 後 3.9b 接線。
