Files
Arcrun/system-dev/docs/3-specs/arcrun/artifact-sharing/design.md
T
Leo 1d7f69215a docs(spec): artifact-sharing 審查對齊 ×2 — K2 改 KBDB 唯一公庫後端(對齊 #16)+ 零件界線照 #23/D29
審查意見兩處(總管 2026-07-07):
1. K2 原「recipe 維持 KV 公庫、泛化端點 front 兩後端」與 #16(RECIPES KV→KBDB)衝突
   → 改為 KBDB 是唯一公庫後端;#16 落地前對 type=recipe 的 KV 轉接明定為過渡碼、
   #16 完成即拆(1.5/5.2 對應改);KV 公庫不得寫成穩態。遷移本體=#16 負責,不重工。
2. component 界線照 #23/D29 定案改:零件貢獻整層搬到獨立 repo Leo/arcrun-components
   (fork→PR→人審);市場只偵測缺件→引導去該 repo 開 PR,永不傳輸/安裝零件程式;
   arcrun_publish_component 路徑廢除。design/requirements/tasks 凡提零件發布處照此改。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 09:09:37 +00:00

19 KiB
Raw Blame History

Artifact Sharing — Design

狀態:草稿(待 review 建立:2026-07-07 | 最後更新:2026-07-07 負責人:Arcrun subagent(受 InkStoneCo 總管指派)


一句話說明

把 recipe 的 app-store 公庫模型,泛化成「一套公庫 record 模型 + 一組泛化端點 + 三個型別化 materialize adapter」,讓 recipe / workflow / template 都能發布、搜尋、pull、export,並在 pull 時解析依賴。


背景與問題

見 requirements.md。核心:recipe 已有 /public-recipes + submit + installRecipeRecord 的完整範本(cypher-executor/src/routes/recipes.ts),workflow / template 缺這一整套。要複製它的公私庫分界、UUID 身份、canonical_id/author、市場數據、pull=寫進自己私庫這幾個成熟決策,而非重新發明。


範圍

包含(In Scope

  • 統一的公庫 record 資料模型(三型共用身份/市場欄位)。
  • 三型 artifact 的可攜格式(export)+依賴清單。
  • 公庫端點:泛化的 /public-artifacts 一套打通三型(見「關鍵決策 K1」的取捨與結論)。
  • 導入語意(pull)與型別化 materialize adapter。
  • 依賴解析(recipe/template 共 pull、component 引導 PR、credential 引導填值)。
  • MCP tools / CLI 命令三層對齊。
  • 安全與審核設計(app-store 市場信任 vs 零件 PR 閘的分界)。

不包含(Out of Scope

  • 零件安裝(Leo/arcrun-components fork→PR→人審路徑,另案);credential 分享;跨環境市場聚合層;recipe 從 KV 遷 KBDB 的執行#16 負責;本 SDD 只以「KBDB 唯一公庫後端」為前提設計);SaaS/api-key。(詳 requirements Out of Scope。)

設計

架構概覽

                ┌──────────────── 公庫(KBDB,長效資料)────────────────┐
  發布 submit-p │  public_artifact entryentry_type=public_artifact  │  搜尋 / pull
  ────────────► │  { uuid, type, canonical_id, author, portable_body,   │ ◄────────────
                │    dependency_manifest, market_stat(per-uuid) }        │
                └───────────────────────────────────────────────────────┘
                          ▲                              │
        (export 產可攜檔)  │                              │ pull = 取全文
                          │                              ▼
   ┌──────────────────────┴───────┐        ┌─────────────────────────────────────┐
   │  自己 namespace(私庫)        │        │  materialize adapter(型別化落地)    │
   │  workflow → WEBHOOKS KV+KBDB │◄───────│  workflow → push (/webhooks/named)   │
   │  template → KBDB /templates  │        │  template → create_template          │
   │  recipe   → RECIPES(→KBDB#16) │        │  recipe   → installRecipeRecord      │
   └──────────────────────────────┘        │  + 依賴解析(遞迴 pull / 引導)        │
                                           └─────────────────────────────────────┘
  • 讀寫都走既有 worker:公庫 record 存 KBDBkbdb worker 的 /entries),泛化端點掛在 cypher-executor(已是 recipe 公庫 + workflow CRUD 的所在,且已有 KBDB fetch 慣例)。不新建 worker、不 service binding、不 wranglerarcrun-primer A 類)。

關鍵決策

決策 選擇 原因 放棄的選項
K1 端點:泛化一套 vs 每型別一套 泛化一套 /public-artifacts?type= 讀,型別化 adapter 寫 讀側(搜/列/取全文/market_stat/落空引導)三型邏輯完全同構,泛化成一套省 3×重複、給 AI 一致心智模型(low-code);寫側(materialize 落自己 namespace)三型的家不同,必須型別化 每型一套 /public-workflows+/public-templates(3× 複製 recipe 端點,維護面爆、AI 要記三套); 全泛化含寫(做不到,落地各異)
K2 公庫儲存後端 KBDB 是唯一公庫後端entry_type=public_artifact)。workflow/template 一開始就建在 KBDBrecipe 公庫隨 **#16RECIPES KV→KBDB 遷移)**收斂進同一後端。過渡期(#16 落地前)泛化端點可暫時把 type=recipe 轉呼既有 KV 路徑,但 KV 公庫=過渡態、非穩態#16 完成即拆轉接 對齊儲存鐵律(長效→KBDB)+白拿 KBDB 語意搜尋(Vectorize embedworkflow-discovery 已證);與 #16 同向不打架——遷移本體由 #16 負責,本 SDD 不對 KV 公庫做任何新投資 全部塞 KV(違鐵律、無語意搜尋); 把「KV 公庫 front 兩後端」寫成穩態(與 #16 衝突,雙後端維護面永久化); 本 SDD 自己動手遷 recipe(與 #16 重工)
K3 身份模型 沿用 recipe UUID 身份模型uuid=身份、canonical_id/author/type=屬性、submit-p=新增作者版本不覆蓋、per-uuid market_stat 已被 recipe 驗證(kbdb-base §7.5.5);三型共用同一套,pull「選市場最佳作者版本」邏輯可共享 為 workflow/template 另設身份模型(分裂、無法共用選版邏輯)
K4 依賴傳輸邊界 recipe/template 隨 workflow 一起 pullcomponent 只偵測引導、credential 只列清單 component 是程式=攻擊面,鎖 PR 路徑(#23);credential 是機密,永不可攜(鐵律) export 內嵌 component 程式(把 PR 閘繞掉,重演 #23); export 內嵌 credential 值(機密外洩)
K5 審核閘 資料 artifact 無 submit 前置人閘(市場信任),信任判斷點移到 import 時(市場數據+依賴清單+外呼檢查) leo 2026-06-29 已對 recipe 移除 exposure_consent 閘(arcrun 給 AI 用);資料 artifact 不在 host 上跑任意碼,風險≠零件 對 submit 加人類 consent 閘(與 recipe 已定案反向、增摩擦); 完全無信任訊號(import 端沒判斷依據)

統一公庫 record 模型(R1

公庫一筆 = KBDB entryentry_type='public_artifact'owner_id=author(歸屬即隔離),metadata_json 承載身份與市場鍵,content 放 canonical_id(供 keyword/semantic search)+ metadata_json.embed=true 開語意搜尋:

// public_artifact entry.metadata_json
{
  "uuid": "…",                 // 唯一身份(誕生即領,沿用 §7.5.5)
  "type": "workflow",          // recipe | workflow | template
  "canonical_id": "daily_digest",
  "author": "leo",             // 該 uuid 投稿者;'system'=種子
  "derived_from": "…uuid?",    // 可選:fork 溯源
  "display_name": "每日摘要",
  "description": "…",          // 供語意搜尋,強制非空(沿用 workflow-discovery R1
  "embed": true,               // 開 Vectorize
  "portable_body": {  },      // 見「可攜格式」
  "dependency_manifest": [  ] // 見「依賴解析」
  // market_stat 不存這裡——per-uuid 記在既有 recipe-stats 機制(KBDB),import 時 fetch
}

市場數據:沿用 recipe fetchMarketStatKBDB /recipe-stats/:idper-uuid)。泛化為 /artifact-stats/:uuid(或直接復用 recipe-stats 表,key=uuid 本就型別無關)。不在投稿時寫自報數(沿用 §7.3:自報數只當存證 *_submission entry,不併真實計數,避免污染市場)。

可攜格式(exportR2 / US-3

每型 portable_body = 該型的自足定義,去識別化 + 去機密

  • recipe:既有 RecipeDefinition 去掉 uuid/author/created_at(導入時重領),保留 endpoint/method/headers/body/auth_service/credentials_required(只有 key 名,無值)。
  • workflow{ name, flow, config, description }(cypher 三元組 + 節點設定)。config 內對零件的引用(component: rec_xxx / component: <builtin>)保留;credential 引用維持 {{credential.xxx}} 模板(無值)。
  • template{ name, slots[], description }

export 檔(YAML/JSON,二選一,預設 YAML 對齊 workflow.yaml 慣例)= portable_body + dependency_manifest + type/canonical_id 標頭。自足=任何相同 Arcrun 部署 import 後可跑(前提:component 已具備、credential 已填)。

泛化端點(R3K1 讀側泛化)

掛在 cypher-executortype 為必帶 query/param。行為對照 recipe /public-recipes* 完全同構:

  • GET /public-artifacts?type=&q=&limit=&offset= — 搜/列公庫。同 canonical_id 回多筆(多作者),各附 market_stat。落空(q 無命中)→ { found:false, type, query, hint } 創作引導(沿用 §7.5.6)。type 省略=跨型別搜(回傳項帶各自 type)。
  • GET /public-artifacts/:type/:canonical_id?author= — 取單一全文(pull 用)。多作者→選 market_stat.success_count 最高版本(沿用 recipe 選版邏輯)。落空→創作引導。
  • POST /public-artifacts/submit — 投稿(submit-p)。body 帶 { type, canonical_id, portable_body, dependency_manifest, author, stat? }領新 uuid = 新增作者版本(不覆蓋,§7.5.5);stat 只寫 *_submission 存證 entry,不併真實計數。

recipe 相容(過渡):終態=三型都走 KBDB public_artifact 路徑(K2:KBDB 唯一公庫後端)。#16RECIPES KV→KBDB)落地前的過渡期,泛化端點對 type=recipe 暫時轉呼既有 KV 公庫路徑(listAllRecipes/installRecipeRecord)——這段轉接碼是過渡碼#16 完成後 type=recipe 改走 KBDB、轉接即拆,不留雙後端。可先只上 workflow/templaterecipe 沿用既有 /public-recipes(見 tasks 分期)。

導入語意 + materialize adapterR4

pull(type, canonical_id) =

  1. GET /public-artifacts/:type/:canonical_id 取全文(含 market 最佳版本 + dependency_manifest)。
  2. 先解依賴(見下),再落地。
  3. materialize(型別化)
    • workflowPOST /webhooks/named(既有 pushowner_id=自己 api_key/namespace)。
    • templatePOST /templates(既有 create_template)。
    • recipeinstallRecipeRecord(既有)。
  4. 回報:落地的 uuid + 依賴處理結果(已 pull 的 recipe/template、缺的 component、待填 credential)。

依賴解析(R5 / K4)—— 關鍵設計點

一個 workflow 常引用四類東西。import 時分類處理,各走各的邊界

依賴類 來源(怎麼認) 導入處理 為何這樣
recipe workflow configcomponent: rec_xxx / http_request 引用的 canonical_id 遞迴 co-pull:對每個 recipe canonical_id 走 pull('recipe', …) 寫進自己私庫。有界遞迴(recipe 通常不再引用其他 artifact;設深度上限防環) recipe 是資料,同屬「資料庫就能完成」,一起帶走才可跑
template workflow 若寫 KBDB record(引用某 template name co-pulltemplate 不存在→pull('template', …)→create_template 同上;template 是 slots 宣告,可攜
component(零件/code workflow flow: cypher 用到的 builtin 零件(http_request/code/cron…) 只偵測缺口→引導開 PR,永不傳輸/安裝零件程式:對照本部署 acr parts。齊→放行;缺→回報「此 workflow 需零件 X,你的部署沒有。零件貢獻已整層搬到獨立 repo Leo/arcrun-componentsfork→PR→人審→併 main→隨部署/更新安裝),非 pull」。用 §7.5.6 式引導 零件是程式=攻擊面,唯一入口=Leo/arcrun-components 的 PR 人審閘(#23/D29 定案;arcrun_publish_component 路徑已廢除)。這是本 SDD 與零件案的界線落點
credential recipe 的 credentials_required[].key / workflow {{credential.xxx}} 只列清單引導:彙總所有需要的 key,回報「請 acr creds push 填:notion_token, …」。值永不隨 artifact 傳輸 機密鐵律:值存 CF Worker Secrets,可攜檔只帶 key 名
  • dependency_manifestexport/submit 時就算好並存進 record(掃 portable_body 抽引用),import 端不必反解 workflow 內部結構就能預覽「這東西會拉進哪些 recipe/template、需要哪些零件與 credential」——也是 import 的信任預覽面K5)。
  • 遞迴有界manifest 逐項 pull,維護 visited set 防環 + 深度上限(建議 5),超限回報中止並列未解項。

安全與審核(R7 / K5)—— 對照 Arcrun#23 教訓

  • #23 教訓 → #23/D29 定案publish_component 零人閘(提交即 active/public + MCP 全域)=攻擊面。結構解已定案:arcrun_publish_component 路徑廢除零件貢獻整層搬到獨立 repo Leo/arcrun-components,唯一入口=fork→PR→人審。市場/artifact 分享機制只做「缺件偵測→引導去該 repo 開 PR」,永不傳輸、永不安裝零件程式
  • 本 SDD 的分界:資料 artifactrecipe/workflow/template不是零件那種攻擊面——它們是宣告式資料,pull 進來只會執行預先審過的零件、只會打 recipe 指定的 endpoint、只會用 template 的 slots。故:
    1. submit 無前置人閘app-store 市場信任,沿用 leo 2026-06-29 對 recipe 移除 consent 的拍板)。壞版本靠市場數據淘汰,不靠事前審。
    2. 信任判斷點在 import 時,用三個既有訊號:① market_stat(真實使用成功率,per-uuid);② dependency_manifest(import 前預覽「會拉哪些依賴、打哪些 endpoint、要哪些 credential」);③ data-exfil-warning 外呼檢查(該 SDD 的 API 層:recipe endpoint 域名異常時警示)——pull 進來的 recipe 依賴同樣過這層。
    3. 零件閘不鬆動workflow 帶再多引用,也不能讓一個未經 PR 的新零件進入 host。缺零件=停在引導,這道牆就是防「拿 workflow 當殼夾帶惡意零件」。
    4. credential 零傳輸:機密不可攜,杜絕投稿夾帶他人 token / 誘導填入釣魚 credentialimport 端自己 acr creds push)。
  • 投稿存證submit 寫一筆 artifact_submission entry(誰、何時、投了什麼 uuid、自報 stat)當法律歸責軌跡(沿用 recipe §7.3),不當門檻。

API / 介面定義(R6 三層對齊)

recipe(既有樣板) 本 SDD 新增(workflow/template,泛化)
HTTP /public-recipes*/recipes/submit /public-artifacts*/public-artifacts/submittype= 打通三型)
MCP arcrun_recipe_search/pull/submit_p arcrun_artifact_search/pull/submit_p(帶 type 參數)+ arcrun_workflow_export / arcrun_template_export
CLI acr recipe search/pull/submit-p acr workflow search/pull/submit-p/exportacr template search/pull/submit-p/export(薄殼包泛化端點)

MCP/CLI 面向使用者可保留型別化命名(acr workflow pullacr artifact pull --type=workflow 更順口、更 low-code),底層打同一泛化端點。=「對外型別化措辭、對內泛化實作」,兼得可讀性與 DRY。

資料模型

  • 公庫 recordKBDB public_artifact entry(見上),KBDB 是唯一公庫後端(K2;recipe 過渡期例外見上)。不建新表entry_type + metadata_json 承載,KBDB 鐵律)。
  • market_stat:復用既有 KBDB recipe-statskey=uuid,型別無關)。
  • 存證:artifact_submission entry。
  • 私庫落地:沿用各型既有儲存(workflow=WEBHOOKS KV+KBDB 雙寫、template=KBDB /templates、recipe=RECIPES——現為 KV隨 #16 遷 KBDB),本 SDD 不改私庫儲存、materialize adapter 打各型既有寫入 API 故遷移對本 SDD 透明。

技術限制

  • 不能:新建 Worker、寫 Worker 程式碼、service binding、跑 wrangler、建 D1 新表、SQL 直寫(arcrun-primer 紅線;端點加在既有 cypher-executor / kbdb worker)。
  • 必須相容recipe 既有 /public-recipes* 路徑(不破現有 pull/submit);workflow 既有 /webhooks/named push 與 workflow-discovery 雙寫;template 既有 /templates
  • 必須遵守:儲存鐵律(長效→KBDB、機密→Secrets)、API-as-WallD6)、UUID 身份模型(§7.5.5)。
  • 效能:公庫搜尋走 KBDB 語意/keywordVectorize 已在 workflow entry 證可行),避免 recipe KV list({prefix}) 全掃在量大時疊加(kbdb-base §風險 已標)——這也是 workflow/template 公庫選 KBDB 而非 KV 的附帶好處。

驗收標準

完成的定義(CC 完成任何 task 前必須確認):

  • POST /public-artifacts/submittype=workflow)投稿後,GET /public-artifacts?type=workflow&q= 搜得到、帶 market_stat。
  • GET /public-artifacts/workflow/:canonical_id 回市場最佳作者版本;落空回 {found:false,hint}
  • acr workflow pull <id> 把 workflow push 進自己 namespace,且遞迴 pull 其 recipe/template 依賴、列出缺的 component 與待填 credential。
  • acr workflow export <name> 產出自足 YAML,含 dependency_manifestgrep 不到任何機密值。
  • template 同上一套(submit-p/search/pull/export)跑通。
  • 投稿寫 artifact_submission 存證 entry;自報 stat 不進真實計數。
  • 一個引用「未具備零件」的 workflow,pull 時停在引導(不落地、不抓程式)。

相關文件

  • arcrun/kbdb-base/design.md §7.5recipe app-store / 公私庫雙向 / UUID 身份)— 本 SDD 的母範本。
  • component-gatekeeping/+獨立 repo Leo/arcrun-components(#23/D29:零件貢獻整層外移,fork→PR→人審)— 零件界線的另一側。
  • workflow-discovery/ — workflow 已雙寫 KBDB + 語意搜尋,本 SDD 的公庫搜尋基礎。
  • data-exfil-warning/ — import 時外呼信任檢查層。
  • 4-guides/arcrun-primer.mdInkStoneCo 頂層)— A/B 兩類工作、紅線。
  • Arcrun#23publish_component 零人閘教訓)、Arcrun#13workflow-store / 移除 consent 閘)。

待 leo / richblack 拍板的設計點

  1. K2recipe 公庫是否收斂到 KBDB 已定(審查 2026-07-07,對齊 #16KBDB 是唯一公庫後端,recipe 隨 #16 收斂;KV 只是 #16 落地前的過渡轉接,不是穩態。剩餘協調點只有「轉接拆除時機跟 #16 進度對齊」。
  2. export 預設格式YAML(對齊 workflow.yamlvs JSON。本 SDD 預設 YAML、兩者皆支援。
  3. MCP/CLI 命名:型別化措辭(acr workflow pullvs 泛化措辭(acr artifact pull --type=)。本 SDD 建議型別化對外、泛化對內。
  4. 依賴遞迴深度上限:建議 5,是否合適。
  5. K5 信任:資料 artifact submit 全程無人閘是否可接受於公開公庫場景(vs 現況多為 self-hosted 私庫 pull);若未來上真公開公庫,是否要加 import 端的「首次 pull 陌生作者 → AI 摘要依賴清單給人看一眼」的軟提示(非硬閘)。