# 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 entry（entry_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 存 KBDB（`kbdb` worker 的 `/entries`），泛化端點掛在 **cypher-executor**（已是 recipe 公庫 + workflow CRUD 的所在，且已有 KBDB fetch 慣例）。**不新建 worker、不 service binding、不 wrangler**（arcrun-primer A 類）。

### 設計原則（market 層）

- **資料完整性優先於界面（leo，2026-07-07）**：「可以沒有界面，但這些資訊會留下；如果哪天已有 1000 個資源、想做個網站告訴大家，卻發現資訊都不足、少東少西，那就糟了。」UI 是未來的皮，**record 完整性是現在的責任**——本 SDD 的公庫 record 與事件記錄，一律用「未來 showcase 網站需要什麼」反推首日 schema（見 R1 欄位清單），而非「現在端點用到什麼」。
- **事件型資料事後不可重建 → day-one 就 append 記錄**：衍生統計（author_reputation、熱門榜）可以晚算、隨時重算；但**原始事件**——誰何時 pull/download 了哪個 uuid、誰何時 submit 了什麼——**錯過當下就永遠沒有**。故 `artifact_pull_event` / `artifact_submission` 從第一天就寫（KBDB append-only 正好是這個用途），有沒有人看是另一回事。

### 關鍵決策

| 決策 | 選擇 | 原因 | 放棄的選項 |
|------|------|------|----------|
| **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 一開始就建在 KBDB；recipe 公庫隨 **#16（RECIPES KV→KBDB 遷移）**收斂進同一後端。過渡期（#16 落地前）泛化端點可暫時把 `type=recipe` 轉呼既有 KV 路徑，但 **KV 公庫＝過渡態、非穩態**，#16 完成即拆轉接 | 對齊儲存鐵律（長效→KBDB）＋白拿 KBDB 語意搜尋（Vectorize embed，workflow-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 一起 pull；component 只偵測引導、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 entry，`entry_type='public_artifact'`，`owner_id=author`（歸屬即隔離），`metadata_json` 承載身份與市場鍵，`content` 放 canonical_id（供 keyword/semantic search）＋ `metadata_json.embed=true` 開語意搜尋：

欄位完整性用「未來 showcase 網站」反推（見設計原則）：哪天有 1000 個資源想做網站，**首日投稿就捕捉的欄位不能少東少西**。每欄標【必填＝投稿時必給｜自記＝系統寫入｜可選】：

```jsonc
// public_artifact entry.metadata_json
{
  "uuid": "…",                 // 【自記】唯一身份（誕生即領，沿用 §7.5.5）
  "type": "workflow",          // 【必填】recipe | workflow | template
  "canonical_id": "daily_digest", // 【必填】
  "author": "leo",             // 【必填/自記】該 uuid 投稿者（自 namespace 帶出）；'system'=種子
  "created_at": "…",           // 【自記】投稿時間（版本沿革與「最新發布」榜的依據）
  "updated_at": "…",           // 【自記】metadata 修訂時間（portable_body 不覆蓋——改版＝submit-p 新 uuid）
  "derived_from": "…uuid?",    // 【可選】fork 溯源；同 canonical_id+author 的歷代版本則靠 created_at 排序追（不需額外欄）
  "display_name": "每日摘要",   // 【必填】
  "description": "…",          // 【必填】人讀的一句話；供語意搜尋，強制非空（沿用 workflow-discovery R1）
  "tags": ["social", "fb"],    // 【可選，建議】分類/標籤（showcase 分類頁的料）
  "compat": {                  // 【自記，可覆蓋】相容性：投稿當下的 arcrun / portable 格式版本
    "arcrun_version": "1.3.x",
    "schema_version": 1
  },
  "license": "MIT",            // 【可選】未定→不填（顯示「未聲明」）；是否改必填待拍板
  "embed": true,               // 【自記】開 Vectorize
  "portable_body": { … },      // 【必填】見「可攜格式」
  "dependency_manifest": [ … ],// 【自記】掃 portable_body 產出，見「依賴解析」
  "deps_summary": {            // 【自記】manifest 的輕量聚合（submit 時一併算好存入，搜尋列表直接帶）
    "recipes": ["facebook"],   // 各類依賴的名稱清單；空類回空陣列
    "templates": ["fb_posts"],
    "components": [],
    "credentials": ["facebook_token"]
  }
  // market_stat 不存這裡——per-uuid 記在既有 recipe-stats 機制（KBDB），import 時 fetch
}
```

> **deps_summary（leo 補點，2026-07-07）**：`dependency_manifest` 是 pull 用的完整清單；`deps_summary` 是它的**搜尋層摘要**（各類依賴的名稱陣列），submit/export 算 manifest 時順手聚合、存進 metadata_json → 列表回應直接帶、不必解 portable_body。**為什麼要在搜尋層**：對 low-code 用戶，「裝不裝」的判斷資訊必須在搜尋結果就看到，不是 pull 之後才發現缺東西——搜到「把 Facebook post 拉回來儲存」的 workflow，列表項直接顯示「需 1 template（fb_posts）＋1 recipe（facebook）＋1 credential 待填（facebook_token）」，一眼可判斷。

> **市場數據**：沿用 recipe `fetchMarketStat`（KBDB `/recipe-stats/:id`，per-uuid）。泛化為 `/artifact-stats/:uuid`（或直接復用 recipe-stats 表，key=uuid 本就型別無關）。**不在投稿時寫自報數**（沿用 §7.3：自報數只當存證 `*_submission` entry，不併真實計數，避免污染市場）。

### 作者信譽（author reputation）—— market 的核心（leo 定義，2026-07-07）

> leo 原話意涵：「Leo 發表了 100 個 recipe，他的 reputation 非常好，而你找到 Leo 就能看到他 share 的這 100 個 recipes」＋未來獎勵機制掛在信譽上。**Market 的核心＝作者信譽經濟（author-centric）**，per-uuid market_stat（單品數據）只是底層原料，作者層才是信任與激勵的單位。

- **author_reputation ＝衍生視圖，不另立真相源**：per-author 統計（發布 artifact 數、彙總 success/failure、最近活躍時間）**全部從 per-uuid market_stat ＋ 該 author 的 public_artifact entry 清單聚合而來**。取捨：
  - **第一階段＝查詢時聚合（compute-on-read）**：單一作者的 artifact 數量級小（10²），KBDB 查該 author 的 entries + 逐 uuid 撈 stat 聚合即可，**零新儲存、零一致性問題**（真相永遠在 per-uuid）。
  - **量大再物化**：作者/流量成長後改「定期物化」（cron 聚合寫成 `author_reputation` entry，**明確標記為快取、非真相源**，過期重算）。先簡後繁，避免一開始就養兩份數據。
- **曝光位**：① 搜尋結果每項的**作者名旁**附信譽摘要（如 `leo（42 發布・96% 成功）`）；② **作者頁頂部**（見端點段 authors 端點）。
- **選版邏輯升級**：多作者同 canonical_id 時，排序訊號從「單品 success_count」擴為「**單品數據＋作者信譽**」的複合分——單品數據不足（新發布）時作者信譽當先驗。**權重配比待 leo 拍板**（見待拍板清單）。
- **獎勵機制（future layer，本 SDD 不實作）**：**第一階段的獎勵＝信譽本身**（曝光、排序加權、信任標記）；未來付費分潤/積分**掛在 author identity 上**。因此 **author 身份必須穩定可驗**——現況 author 是字串 namespace（self-hosted 單租戶下夠用），**進 SaaS/多人公開市場前，author 必須綁認證身份**（否則信譽可被冒名、獎勵可被盜領），列為該階段的**前置條件**，非本 SDD 範圍。

### 可攜格式（export，R2 / 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 已填）。

### 泛化端點（R3，K1 讀側泛化）

掛在 cypher-executor，`type` 為必帶 query/param。行為對照 recipe `/public-recipes*` 完全同構：

- `GET /public-artifacts?type=&q=&author=&limit=&offset=` — 搜/列公庫。同 canonical_id 回多筆（多作者），各附 `market_stat` **與 `deps_summary`**（配套需求摘要：這個 artifact 要配哪些 recipe/template/component/credential 才跑得起來——「搜一個、看到各要裝什麼」在列表層就成立，見 R1 的 deps_summary 說明），作者名旁附**作者信譽摘要**（見作者信譽段）。**`author=` 過濾**＝跨型別列該作者全部發布（「找到 Leo 就看到他 share 的 100 個 recipes」），可與 `type`/`q` 併用——就是 author 欄的查詢面，成本低。落空（q 無命中）→ `{ found:false, type, query, hint }` 創作引導（沿用 §7.5.6）。`type` 省略＝跨型別搜（回傳項帶各自 type）。
- `GET /public-artifacts/authors/:name` — **作者頁**：頂部 author_reputation 摘要（發布數、彙總成功率、最近活躍）＋該作者全部發布清單（每項附 market_stat/deps_summary）。reputation＝查詢時從 per-uuid stat 聚合（見作者信譽段的取捨）。
- `GET /public-artifacts/:type/:canonical_id?author=` — 取單一全文（pull 用）。多作者→**複合分選版**：單品 `market_stat` ＋作者信譽（單品數據不足時作者信譽當先驗；權重待拍板）。落空→創作引導。**成功回應時 append 一筆 `artifact_pull_event`**（誰的 namespace、何時、拉了哪個 uuid）——pull 事件事後不可重建，day-one 就記（見設計原則）。
- `POST /public-artifacts/submit` — 投稿（submit-p）。body 帶 `{ type, canonical_id, portable_body, dependency_manifest, author, tags?, compat?, license?, stat? }`。**領新 uuid = 新增作者版本**（不覆蓋，§7.5.5）；`stat` 只寫 `*_submission` 存證 entry，不併真實計數。

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

### 導入語意 + materialize adapter（R4）

`pull(type, canonical_id)` =
1. `GET /public-artifacts/:type/:canonical_id` 取全文（含 market 最佳版本 + dependency_manifest）。
2. **先解依賴**（見下），再落地。
3. **materialize（型別化）**：
   - `workflow` → `POST /webhooks/named`（既有 push；owner_id=自己 api_key/namespace）。
   - `template` → `POST /templates`（既有 create_template）。
   - `recipe` → `installRecipeRecord`（既有）。
4. 回報：落地的 uuid + 依賴處理結果（已 pull 的 recipe/template、缺的 component、待填 credential）。

### 依賴解析（R5 / K4）—— 關鍵設計點

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

| 依賴類 | 來源（怎麼認） | 導入處理 | 為何這樣 |
|---|---|---|---|
| **recipe** | workflow `config` 裡 `component: rec_xxx` / http_request 引用的 canonical_id | **遞迴 co-pull**：對每個 recipe canonical_id 走 `pull('recipe', …)` 寫進自己私庫。有界遞迴（recipe 通常不再引用其他 artifact；設深度上限防環） | recipe 是資料，同屬「資料庫就能完成」，一起帶走才可跑 |
| **template** | workflow 若寫 KBDB record（引用某 template name） | **co-pull**：template 不存在→`pull('template', …)`→create_template | 同上；template 是 slots 宣告，可攜 |
| **component（零件/code）** | workflow `flow:` cypher 用到的 builtin 零件（`http_request`/`code`/`cron`…） | **只偵測缺口→引導開 PR，永不傳輸/安裝零件程式**：對照本部署 `acr parts`。齊→放行；缺→回報「此 workflow 需零件 X，你的部署沒有。零件貢獻已整層搬到獨立 repo **`Leo/arcrun-components`**（fork→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_manifest** 在 **export/submit 時就算好並存進 record**（掃 portable_body 抽引用），import 端不必反解 workflow 內部結構就能預覽「這東西會拉進哪些 recipe/template、需要哪些零件與 credential」——也是 import 的**信任預覽面**（K5）。
- **deps_summary 讓配套需求在「搜尋層」就可見**（leo 補點）：算 manifest 時順手聚合出各類依賴名稱清單存進 metadata_json，`GET /public-artifacts` 列表項直接帶。low-code 用戶判斷「裝不裝」的資訊要在搜尋結果就給，不是 pull 之後才發現缺東西——例：搜到「把 Facebook post 拉回來儲存」，列表項即顯示「需 1 template（fb_posts）＋1 recipe（facebook）＋1 credential 待填（facebook_token）」。
- **遞迴有界**：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 的分界**：資料 artifact（recipe/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 / 誘導填入釣魚 credential（import 端自己 `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/submit`（`type=` 打通三型） |
| 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/export`、`acr template search/pull/submit-p/export`（薄殼包泛化端點） |

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

### 資料模型

- 公庫 record：KBDB `public_artifact` entry（見上），**KBDB 是唯一公庫後端**（K2；recipe 過渡期例外見上）。**不建新表**（entry_type + metadata_json 承載，KBDB 鐵律）。
- market_stat：復用既有 KBDB recipe-stats（key=uuid，型別無關）。
- **事件記錄（day-one append，設計原則第 2 條）**：`artifact_pull_event` entry（誰的 namespace、何時、拉了哪個 uuid——取全文成功即寫）＋ `artifact_submission` entry（誰、何時、投了什麼 uuid、自報 stat）。皆 append-only、不更新不刪除；熱門榜/下載數/作者活躍度等統計全部從這兩類事件＋recipe-stats 事後聚合，**事件是真相，統計是視圖**。
- **author_reputation：衍生視圖、非真相源**（見作者信譽段）：第一階段查詢時聚合；量大後定期物化成標記為快取的 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-Wall（D6）、UUID 身份模型（§7.5.5）。
- **效能**：公庫搜尋走 KBDB 語意/keyword（Vectorize 已在 workflow entry 證可行），避免 recipe KV `list({prefix})` 全掃在量大時疊加（kbdb-base §風險 已標）——這也是 workflow/template 公庫選 KBDB 而非 KV 的附帶好處。

---

## 驗收標準

完成的定義（CC 完成任何 task 前必須確認）：
- [ ] `POST /public-artifacts/submit`（type=workflow）投稿後，`GET /public-artifacts?type=workflow&q=` 搜得到、帶 market_stat **與 deps_summary**（搜尋結果每項可見「要配哪些東西才跑得起來」，不必取全文）。
- [ ] `GET /public-artifacts/workflow/:canonical_id` 回市場最佳作者版本（複合分：單品＋作者信譽）；落空回 `{found:false,hint}`；成功取全文有 append `artifact_pull_event`。
- [ ] `GET /public-artifacts?author=leo` 列出該作者跨型別全部發布；`GET /public-artifacts/authors/leo` 回信譽摘要＋清單。
- [ ] `acr workflow pull <id>` 把 workflow push 進自己 namespace，且遞迴 pull 其 recipe/template 依賴、列出缺的 component 與待填 credential。
- [ ] `acr workflow export <name>` 產出自足 YAML，含 dependency_manifest，grep 不到任何機密值。
- [ ] template 同上一套（submit-p/search/pull/export）跑通。
- [ ] 投稿寫 `artifact_submission` 存證 entry；自報 stat 不進真實計數。
- [ ] 一個引用「未具備零件」的 workflow，pull 時停在引導（不落地、不抓程式）。
- [ ] **資料完整性（可測定義）**：不看任何 UI，僅用公庫 record + 事件記錄（`public_artifact`/`artifact_pull_event`/`artifact_submission`/recipe-stats），就能重建出一個完整的市場網站首頁——作者榜、熱門榜、最新發布、每項的配套需求。缺哪個欄位榜單做不出來＝schema 不合格。

---

## 相關文件

- `arcrun/kbdb-base/design.md` §7.5（recipe 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.md`（InkStoneCo 頂層）— A/B 兩類工作、紅線。
- Arcrun#23（publish_component 零人閘教訓）、Arcrun#13（workflow-store / 移除 consent 閘）。

---

## 待 leo / richblack 拍板的設計點

1. ~~**K2**：recipe 公庫是否收斂到 KBDB~~ **已定（審查 2026-07-07，對齊 #16）**：KBDB 是唯一公庫後端，recipe 隨 #16 收斂；KV 只是 #16 落地前的過渡轉接，不是穩態。剩餘協調點只有「轉接拆除時機跟 #16 進度對齊」。
2. **export 預設格式**：YAML（對齊 workflow.yaml）vs JSON。本 SDD 預設 YAML、兩者皆支援。
3. **MCP/CLI 命名**：型別化措辭（`acr workflow pull`）vs 泛化措辭（`acr artifact pull --type=`）。本 SDD 建議型別化對外、泛化對內。
4. **依賴遞迴深度上限**：建議 5，是否合適。
5. **K5 信任**：資料 artifact submit 全程無人閘是否可接受於**公開**公庫場景（vs 現況多為 self-hosted 私庫 pull）；若未來上真公開公庫，是否要加 import 端的「首次 pull 陌生作者 → AI 摘要依賴清單給人看一眼」的軟提示（非硬閘）。
6. **選版複合分權重**：多作者同名時「單品 market_stat vs 作者信譽」怎麼配權（含新發布單品數據不足時作者信譽當先驗的冷啟動處理）。
7. **license 欄位**：維持可選（未填顯示「未聲明」）或投稿必填。
8. **author 綁認證身份的時點**：現況字串 namespace 夠用（self-hosted 單租戶）；進 SaaS/多人公開市場前必須綁認證（信譽防冒名、獎勵防盜領）——在哪個里程碑動手。
