chore: D22 落地——docs/SDD/wiki/CLAUDE.md 進 repo(Gitea private 預設全 push)
頂層 D22 決策(leo 2026-07-03 拍板):推什麼由開發環境歸屬決定, Gitea private=除機敏值/build 產物/.github 外全 push。 解 T1.5 卡點:雲端工人 clone 拿得到 credential-store-migration.md,可就地改寫 SDD。 機敏掃描兩輪通過(新增 189 檔約 2.1MB,node_modules/dist/wasm 照舊排除)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
# Design: KBDB Base —— 原子化萬用表(self-hosted 資料底座 + 官方核心)
|
||||
|
||||
> 2026-06-07 richblack 拍板。來源:壓測報告(`test_arcrun/docs/壓測報告.md`)暴露 self-hosted 無資料層 →
|
||||
> richblack 決定把 KBDB 的「基礎儲存」開源進 arcrun,向量/三元組走插件模式(如 PostgreSQL 的 PGVector / Apache AGE)。
|
||||
> **架構同時影響官方版**:官方也改成「基礎核心 + 可選模組」,故開源與官方共用同一基礎,不維護兩套。
|
||||
|
||||
---
|
||||
|
||||
## 0. 為什麼(壓測暴露的缺口)
|
||||
|
||||
壓測(第一次完整壓測,6 輪回歸)跑通了「表單 → workflow → Google Sheets」,但暴露 **self-hosted 沒有資料層**:
|
||||
|
||||
| 缺口 | 現況 | KBDB Base 如何解 |
|
||||
|---|---|---|
|
||||
| **無「專案」維度** | KV key 只有 `{namespace}:{type}:{name}`,無 project;recipe 甚至全局共享 | entries 樹狀(entry_type=project/workflow,parent_id)→ 可列「某專案的所有工作流」 |
|
||||
| **D1 完全空置** | self-hosted init 只建 8 KV,無 D1;`grep d1_databases` 全 repo 零結果 | KBDB Base 用 D1 → 填上閒置的 D1 |
|
||||
| **recipe 成功無記錄** | push 時 probe 2xx 但不持久化 | 成功記錄存 entries/records → 可監控、可當投稿依據 |
|
||||
| **資料碎(像 n8n)** | 散落 KV,無結構 | templates 做虛擬表 → 結構化資料形態 |
|
||||
|
||||
> recipe 成功記錄 + 投稿(帶記錄免驗證)本次一起做(見 7)。recipe 信譽/市場/排序是後續,不在本次。
|
||||
|
||||
---
|
||||
|
||||
## 1. 核心設計:原子化萬用表(萬年不動)
|
||||
|
||||
> richblack 設計原則:「基礎表是 truth,萬年不動。新技術(embed/triplet/未來)一直增加,
|
||||
> 它們把衍生結果記在**各自的地方**,不回頭改基礎表。」這正是 PostgreSQL 核心 + PGVector/AGE 插件的模型。
|
||||
|
||||
### 三張表(沿用 KBDB v3 `0005_universal_table`,已驗證可用)
|
||||
|
||||
| 表 | 作用 |
|
||||
|---|---|
|
||||
| `entries` | 原子資料。`entry_type`:`block`/`value`/`template`/`slot`(+ 本 SDD 擴充 `project`/`workflow`)。樹狀 `parent_id`、多租戶 `owner_id` |
|
||||
| `templates` | 定義虛擬表的 slots(`slots_json`,如 `["display_name","gender"]`)→ 同一份 entries 用不同 template 呈現不同資料形態 |
|
||||
| `entry_values` | 把多個 entries 按 template 組成一筆結構化記錄(`record_id` + `slot_name` + `entry_id`) |
|
||||
|
||||
### 萬年不動原則(本 SDD 要修正 KBDB 現況的地方)
|
||||
|
||||
KBDB 現況**大致已符合**,但有違反處要修:
|
||||
- ✅ embed:`block-embed.ts` 把向量 upsert 到 **Vectorize**(獨立),不動 blocks 表。
|
||||
- ✅ triplet 主體:`triplet-crud.ts` 主要 `INSERT INTO entry_values`(獨立記錄)。
|
||||
- 🔴 **違反處**:`triplet-crud.ts:106/110` `UPDATE blocks SET entity_type = ?` —— 抽 triplet 後回頭改基礎表。
|
||||
→ **修法**:衍生屬性(entity_type 等)移出基礎表,記到衍生層(entry_values 或獨立 template)。基礎表只存 truth。
|
||||
|
||||
---
|
||||
|
||||
## 2. 插件模式:一套 code,三層 binding 開關(不維護兩套)
|
||||
|
||||
> richblack:「像 PGVector/AGE 是插件。基礎模組提供原子化萬用表(這也是賣點);要向量、要圖資料庫另外裝。
|
||||
> 我還是希望只維持一套。」
|
||||
|
||||
| 層 | 能力 | 依賴 | 開源 / 費用 |
|
||||
|---|---|---|---|
|
||||
| **基礎 KBDB Base** | entries/templates/entry_values CRUD + **D1 LIKE 關鍵字搜尋** | D1 only | ✅ 開源,免費,**不綁卡** |
|
||||
| **+ embed 模組** | 語義搜尋(search 升級) | CF **Vectorize** binding + AI | embed 是 **CF 內建**(程式薄)→ **不拆 repo,給「開/關」**:有 Vectorize binding 就啟用,沒有就降級 LIKE。Vectorize 需用戶自開(自付費) |
|
||||
| **+ triplet 模組** | 三元組抽取 / 知識圖譜 / 圖查詢 | AI + triplet-*.ts(8 個 action,較重) | triplet 是 **richblack 的 IP、程式量大** → **獨立 repo / 獨立 worker**,基礎不依賴它,要才裝 |
|
||||
|
||||
### Q1 拍板(richblack 2026-06-07):embed 不拆、triplet 拆
|
||||
|
||||
- **embed → 不拆 repo,binding 開/關**:因為 embed 靠 CF 內建 Vectorize,程式薄(呼叫 `env.VECTORIZE.upsert`),沒 binding 就降級。一套 code、開關即可。
|
||||
- **triplet → 獨立 repo/worker**:非 CF 內建、是 richblack IP、action 多(triplet-extract/normalize/embed/crud/stats/syntax/entities/update)。基礎 KBDB **不 import triplet**,要才裝。
|
||||
|
||||
### search 分層(壓測者問「search 還是要有,只是沒語義」→ 對)
|
||||
|
||||
KBDB `search.ts` 已有兩層骨架:
|
||||
- 基礎版:D1 `LIKE` 全文搜尋(KBDB 現有 fallback 邏輯,不需 Vectorize)。
|
||||
- + embed:語義搜尋(Vectorize + AI)。
|
||||
**API 不變,能力分層**:基礎用 LIKE,裝 embed 升級語義。
|
||||
|
||||
---
|
||||
|
||||
## 3. 解耦工作(把寫死的觸發改成可選)
|
||||
|
||||
KBDB 現況:`blocks.ts` 把 `ingestText`/`createTriplet`/`deleteBlockVector` **寫死 import 進寫入流程**(寫 block 順手 embed+抽 triplet)。
|
||||
|
||||
解耦目標:
|
||||
- 寫 block = 只寫 block(純基礎)。
|
||||
- embed = 可選 hook(Vectorize binding 在才掛)。
|
||||
- triplet = 可選(triplet 模組裝了才掛)。
|
||||
- 基礎 `blocks.ts` / `templates.ts` / `records.ts` **不 import** vectorize/triplet。
|
||||
|
||||
> ✅ 已查證 `templates.ts` / `records.ts` 本就乾淨(只 import record-crud);主要工作在 `blocks.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 落地形態:import 進 arcrun(如 MCP 的 pattern)
|
||||
|
||||
> richblack:「像先前把 MCP import 進本專案一樣,也把 KBDB import 進來。」對,同一 pattern。
|
||||
|
||||
- **基礎 KBDB Base 搬進 `arcrun/kbdb/`**(如 `arcrun/mcp/`)。形態:獨立 Worker + D1。納入 deploy 掃描(rule 05:新目錄 + wrangler.toml 自動部署)。
|
||||
- **init 建 D1**:`cli/src/lib/cf-api.ts` 加 D1 建立(如現有 KV 建立),`deploy.ts` 注入 D1 id。**self-hosted 從只建 KV → 建 KV + D1**。
|
||||
- **cypher 改用 KBDB Base 存專案/工作流**:webhook/credential/recipe 的「專案歸屬」走 KBDB entries(漸進,不一次搬完)。
|
||||
- **embed**:隨基礎進 arcrun,Vectorize binding 開關。
|
||||
- **triplet**:獨立 repo,self-host 用戶要才另裝(不進 arcrun 基礎)。
|
||||
|
||||
### 共用同一基礎(官方也改)
|
||||
|
||||
richblack 決定官方版也改成「基礎核心 + 可選模組」→ 官方與 self-hosted **共用同一份基礎 KBDB code**,差別只在 binding(官方全開、self-host 基礎免費可選開)。**不維護兩套。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 邊界(本 SDD 不做)
|
||||
|
||||
- **recipe 投稿入口 + 帶成功記錄免驗證**:✅ **本次要做**,見新增 §7(與 KBDB 成功記錄嵌在一起)。
|
||||
- **recipe 信任 = 市場機制(靠量/星數模型)**:拍板用市場優先、暫不做強防偽(見 §7.3)。本次(5.2)做投稿端點(submit 私庫 / submit-p 公共庫覆蓋同 canonical_id)+ stat 存證;**跨環境「靠量同步回市場」聚合層另排 task**;強防偽(官方重跑/多方回報)只在市場失靈才做。
|
||||
- **triplet 模組本身**:獨立 repo,不在本 SDD(本 SDD 只確保基礎不依賴它、可選掛上)。
|
||||
- **vectorize 的進階用法**(suggest/entities-graph-embed):隨 triplet/進階模組,不在基礎。
|
||||
- **官方版的搬遷細節**:本 SDD 聚焦「基礎 KBDB 進 arcrun self-hosted」,官方共用基礎是方向,搬遷另排。
|
||||
|
||||
## 7. recipe 公庫/私庫機制 + 帶 KBDB 成功記錄(市場信任)—— 本次要做
|
||||
|
||||
> §7.1-7.4 原只想「投稿」單向(本次最小已做:成功記錄 5.1 + submit-p 雛形 5.2)。
|
||||
> §7.5 是 richblack 2026-06-07 指示補的 **CHANGE**:把公庫/私庫的所有互動情境想全(pull/搜尋/投稿/市場同步),
|
||||
> 待 review。下方 7.1-7.4 是已成立的基礎,7.5 是擴充全貌。
|
||||
|
||||
> richblack 2026-06-07:本次只做「可投稿 + 帶成功記錄免驗證」,這兩件嵌在一起。
|
||||
> 背景:官方初期那批 recipe 是一次性建立、未驗證(只為「Arcrun 推出不能空空的」)。
|
||||
> 壓測者打通的修正版(如 google_sheets_append method/body)回不了官方 → 官方仍錯,下個用戶再撞。
|
||||
> 不該由 AI 手改種子 recipe(治標);正解是投稿機制 + 用真實成功記錄當免驗證依據(治本)。
|
||||
|
||||
### 7.1 兩件嵌在一起
|
||||
|
||||
1. 成功記錄(KBDB):判定單位是「**工作流執行**」(對標 n8n execution,非逐節點)。一條 workflow 跑完,
|
||||
整體成功(到 Output、無 error)→ 把這次**用到的每個 recipe 節點**各記成功 +1;整體失敗 → 已跑到的 recipe 節點各記失敗 +1。
|
||||
歸屬對象是 recipe(因為投稿的是 recipe),**canonical_id 取 auth recipe 的 `service` 欄位**(與投稿身份一致)。
|
||||
單節點工作流(cron→gdrive,一個節點一個 credential)是最簡情形。存 D1(entry/record),可累積、可查。
|
||||
> 註(術語別混):**cypher-executor = 工作流引擎**,用 cypher **語法**(節點+邊的圖遍歷語意)把零件串成工作流,
|
||||
> 本就在開源核心內,**不是** graph DB。「可選/不在核心」的是兩個插件:① **triplet**(知識三元組的圖**儲存**,
|
||||
> 對標 Apache AGE)② **vectorize**(CF 內建但可能多花錢)。recipe 成功記錄是純 D1 KBDB 核心能力,不依賴這兩個插件。
|
||||
2. 投稿(registry/官方):投稿 recipe 時帶上它在投稿者環境的成功記錄。官方端看記錄即信,免人工驗證——真實打通比投稿者自寫測試可信(呼應 gherkin-not-safety-sandbox-is)。
|
||||
|
||||
### 7.2 本次範圍(最小)
|
||||
|
||||
- recipe 成功/失敗計數落地 D1(KBDB 成功記錄)。
|
||||
- 一個投稿端點:收 recipe + 其成功記錄 → 進官方 recipe 池,**新增一個作者版本**(app-store 模型 §7.5.5,**非**覆蓋同 canonical_id;同 canonical 多作者並存)。
|
||||
- 投稿者目前就是 richblack,不需誘因;重點是有入口可投 + 帶記錄免驗證。
|
||||
|
||||
### 7.3 信任機制:市場優先(靠量,非人力/強防偽)—— richblack 2026-06-07 拍板
|
||||
|
||||
> 這個決策之前討論過、那時選「先不做」,導致今天又重講一次 → 故此次**寫進 SDD**,不再丟。
|
||||
|
||||
**核心:recipe 信任靠「量」決定,像 GitHub 星數,不靠人力檢核、也不先做強防偽。**
|
||||
|
||||
不可能全世界這麼多 recipe 都靠人力檢核。改用市場機制:
|
||||
- recipe 的成功/失敗由**全體使用者的真實執行**累積(投稿者 A 的 recipe 通過 2000 次;投稿者 B 的失敗 500 次 = 像被按爛)。
|
||||
- 上傳爛 recipe → 別人用會失敗 → 累積失敗數 → 投稿者信用下降 → 有動機更新自己發佈的 recipe,避免持續被按爛。
|
||||
- **數據來源 = §7.1 的成功記錄**(每次工作流執行把用到的 recipe 成功/失敗記到 KBDB)。市場機制 = 把這些**跨使用者**的記錄**同步回公共市場**匯總。
|
||||
|
||||
**為什麼先市場、暫不做強防偽(誠實,mindset §7)**:
|
||||
self-hosted 投稿者 = 自己環境 root,能寫任意數字進自己 KBDB → 自報 stat 可造假。
|
||||
但**先信市場**:實驗一段時間,若市場反應爛(造假猖獗)再考慮強防偽(官方重跑 / 多方獨立回報——證據由投稿者控制不了的一方產生)。
|
||||
故**本次不拿投稿者自報的數字當自動放行門檻**(那會造債:未來門檻是空的)。stat 先當存證 + 法律歸責軌跡。
|
||||
|
||||
**分期**:
|
||||
- **本次(5.2)**:投稿端點 `POST /recipes/submit`。submit(私庫)vs submit-p(公共庫,需 exposure_consent = 暴露同意,mindset §6)。
|
||||
公共庫**新增作者版本**(app-store 模型 §7.5.5,非覆蓋)。投稿者帶的 stat 寫進官方 KBDB 當存證(不當門檻)。
|
||||
- **後續(市場同步,§7.3 主體)**:跨環境「靠量同步回市場」——self-hosted 各用戶的真實成功/失敗匯總回公共市場,
|
||||
形成 recipe 的星數/信用。是 §7.1 數據的跨環境聚合層。本次先留接口(5.1 已在各環境記錄,市場聚合另排 task)。
|
||||
- **更後續(強防偽,只在市場失靈才做)**:官方 in-process 重跑投稿者工作流拿官方自己的 2xx / 第二投稿者獨立回報。
|
||||
(註:app-store 模型下「版本並存」是常態、不刪舊版 §7.5.5;舊版靠市場淘汰,不做下架引導。)
|
||||
|
||||
### 7.4 與零件投稿的差異
|
||||
|
||||
零件投稿走 GitHub PR(人 merge + CI runtime 驗 wasm,記憶 component-submission-via-pr)。
|
||||
recipe 是純文字資料(非 wasm),不需 CI 跑沙箱;它的驗證改用真實成功記錄。故 recipe 投稿機制與零件不同,不混用 component-registry-canon SDD。
|
||||
|
||||
### 7.5 公庫 / 私庫雙向機制(CHANGE,richblack 2026-06-07 指示「把兩庫所有情境想好」)—— 待 review
|
||||
|
||||
> 背景修正:原 §7.1-7.4 只想了「投稿」單向,太窄。richblack 指出:
|
||||
> **SaaS 版(standard mode)本來就只有公庫;self-hosted 版本來就只有私庫**。
|
||||
> 兩庫的互動是 overall 架構(不只為投稿):私庫是公庫的**按需子集**——self-hosted 也許只用 10 個,
|
||||
> 公庫也許有 10000 個,**不需每次全部拉下來,用到的再複製**。投稿(submit-p)只是其中一條反向流。
|
||||
|
||||
#### 7.5.1 兩個庫的物理本質(已確認現況)
|
||||
|
||||
| 庫 | 是誰 | 物理 | 規模 | 角色 |
|
||||
|----|------|------|------|------|
|
||||
| **公庫** | 官方 SaaS(`cypher.arcrun.dev`)的 `RECIPES` KV | 官方 CF 帳號 | 大(~10000,含社群投稿) | 唯一公共真相、可瀏覽/搜尋/pull |
|
||||
| **私庫** | 每個 self-hosted(用戶自己帳號)的 `RECIPES` KV | 用戶 CF 帳號 | 小(~10,按需子集) | 自己實際用到的 + 自己改的 |
|
||||
|
||||
- recipe key 都是 `recipe:{canonical_id}`(無 owner 前綴)。同一套部署的 KV = 那套的庫。**物理隔離**(不同帳號不同 KV)。
|
||||
- `mode`(cli config):`standard` = SaaS 用戶(只連公庫,無私庫);`self-hosted` = 自己一套(有私庫,可選連公庫 pull/submit);`local` = 純本地。
|
||||
|
||||
#### 7.5.2 三種使用者 × 互動矩陣
|
||||
|
||||
| 使用者 | 有哪些庫 | 取 recipe | 改 / 投稿 | 成功記錄 |
|
||||
|--------|----------|-----------|-----------|----------|
|
||||
| **SaaS 用戶**(standard) | 只公庫 | 直接用公庫(公庫即他的庫) | 改了直接寫公庫(=投稿,需 consent) | 記在官方 KBDB(即市場數據本身) |
|
||||
| **self-hosted 用戶** | 私庫(主)+ 公庫(唯讀來源) | **公→私 pull**:搜公庫→複製到私庫 | 私庫改 →(可選)**submit-p** 推回公庫 | 記在自己 KBDB;市場同步另排(§7.3 5.5) |
|
||||
| **local** | 無遠端庫 | 本地 recipe 檔 | 無 | 本地 |
|
||||
|
||||
#### 7.5.3 四條互動流(窮舉)
|
||||
|
||||
1. **公→私 pull(核心,之前漏)**:self-hosted `acr recipe pull <canonical_id>` → 從公庫只讀端點抓該 recipe → 寫進自己私庫 KV。
|
||||
按需,**不全量同步**(10000 不必拉)。pull 也可帶公庫的成功記錄(市場星數)供用戶判斷要不要用。
|
||||
2. **公庫瀏覽/搜尋**:`acr recipe search <q>` / `list` → 打公庫只讀端點(`GET /public-recipes?q=`)。
|
||||
self-hosted 沒搜尋能力就不知道公庫有什麼可 pull。SaaS 用戶同一端點即用。
|
||||
3. **私→公 submit-p(已做雛形)**:self-hosted 把私庫某 recipe 推回公庫(`POST /recipes/submit`,需 exposure_consent)。**新增作者版本**(app-store 模型 §7.5.5,非覆蓋;同 canonical 多作者並存)。
|
||||
4. **成功記錄 → 市場同步(§7.3 5.5,另排)**:self-hosted 各環境真實成功/失敗匯總回公庫的市場星數。pull(流1) 帶的星數就來自這裡。
|
||||
|
||||
#### 7.5.4 公庫只讀端點(公→私 + 瀏覽的基礎,待實作)
|
||||
|
||||
官方 cypher 開**公開只讀**端點(無需 api_key,因公庫本就公共):
|
||||
- `GET /public-recipes?q=&limit=&offset=` → 搜尋/列出公庫 recipe。**同 canonical_id 回多筆(多作者)**,各附作者 + 市場星數 success/failure,供 CC/AI 依數據選(§7.5.5)。
|
||||
- `GET /public-recipes/:canonical_id?author=` → 取單一 recipe 全文(pull 用)。不指定 author → 回市場最佳版本(成功率最高)。
|
||||
- **搜尋/取用落空 → 回 `{ found: false, canonical_id, hint }` 創作引導**(§7.5.6),不回空陣列乾等。讓 CC 知道下一步是「自己做一個成為作者」。
|
||||
> 與現有 `GET /recipes`(已存在,列當前部署 KV)的差別:`/public-recipes` 語意是「**這是公庫**,給外部 self-hosted pull/瀏覽」,且**含作者維度 + 市場數據**。
|
||||
> 在官方部署上讀同一 KV;命名分開是為了語意清楚 + 公庫的多作者/市場排序不污染內部 `/recipes`。
|
||||
|
||||
> **市場星數 per-uuid(§7.5.h 已實作)**:5.1 改收集 API recipe 的 **uuid**(非 auth service),KBDB 市場星數記 per-uuid。
|
||||
> 故 `GET /public-recipes/:canonical_id` 的「選市場最佳作者版本」**真正能區分 Leo 版/John 版**(各自 uuid 各自累積)。
|
||||
> 舊資料無 uuid → fallback canonical_id(migration 後自然帶 uuid)。
|
||||
|
||||
#### 7.5.5 recipe = 具名作者作品(app-store 模型)+ UUID 身份 —— richblack 2026-06-07 拍板
|
||||
|
||||
> 這條推翻了我原本「覆蓋同 canonical_id」的錯誤前提。正確模型如下。
|
||||
|
||||
**每個投稿的 recipe 是一個「具名作者作品」,像 app store 上的一個 app,只有作者(+admin)能改。**
|
||||
|
||||
- Leo 投稿 `gsheets_upsert` = 在 app store 放了一個 app。**只有 Leo + admin 能動它**。
|
||||
- John 覺得 Leo 的很爛 → John **另推一個** `gsheets_upsert`(John 的作品)。**只有 John + admin 能動**。
|
||||
- 公庫裡因此**同 canonical_id 並存多份**(Leo 版、John 版),各帶作者、各帶獨立市場數據。
|
||||
|
||||
**所以:**
|
||||
1. **submit-p ≠ 覆蓋**。投稿是**新增一個作者版本**,不是覆蓋同 canonical_id。(修正原 §7.2/§7.3 的「覆蓋」字眼。)
|
||||
2. **沒有「公庫改了 Leo 要不要跟」的問題**:Leo 的作品只有 Leo 改;別人不滿意是自己推新作品,不是改 Leo 的。版本關係問題消失。
|
||||
3. **向後相容、不刪舊 recipe**:Leo 的 5/10 不被刪,只是市場上沒人選 → 自然淘汰(長尾留著,無破壞性刪除)。
|
||||
4. **選擇由市場數據驅動(CC/AI 操盤手選)**:CC 搜 `gsheets_upsert` → 找到 2 個 → 看數據(Leo 5成功/10失敗、John 100成功/0失敗)→ **選 John 的**。Leo 的逐漸沒人用。
|
||||
|
||||
**身份模型(落地)= UUID(richblack 2026-06-07 拍板,比 canonical_id+author 複合鍵更乾淨)**:
|
||||
|
||||
**每個 recipe 一誕生就領一個 UUID = 唯一身份。`canonical_id` / `author` / `公私` 全是屬性,不是身份。**
|
||||
- 身份(UUID) 與 歸屬(author 屬性) 分離 → 沒有「同 canonical_id 撞 key」問題(key 是 UUID,本就唯一)。
|
||||
- **KV key 設計**:`recipe:{uuid}` 存 recipe 本體;`idx:canonical:{canonical_id}` → UUID 清單(同 canonical 多 UUID);
|
||||
私庫執行:`idx:installed:{canonical_id}` → 該 canonical 在本庫安裝的**唯一** UUID(pull/author 時定一個)→ 執行查找仍由 canonical_id 解析到唯一 recipe,**不破執行**。
|
||||
- **Leo 改 John 的**:Leo 拿 John 版(UUID-J)改 → 發出去領**新 UUID-L** = Leo 作品。UUID-J/UUID-L 是兩個東西,不冒名、天然不衝突。
|
||||
- **author 屬性 = 該 UUID 誕生時的投稿者**(誰投誰負責那版市場數據);可選帶 `derived_from: {uuid}` 溯源(致謝/fork upstream)。
|
||||
|
||||
**「Leo 跟 John 一模一樣」怎麼辦**(你問的):兩個不同 UUID 都通過、各跑各的市場數據。
|
||||
**重複 = 市場冗餘,靠數據淘汰不靠技術阻止**(先有數據的勝,複製品沒人選自然沉底,§7.3 靠量不靠人力)。
|
||||
|
||||
**檢舉功能**:本次**不做**。檢舉 = 人力檢核,與「市場優先、暫不強防偽」(§7.3)矛盾,提前做還用不到 = 造債。
|
||||
市場失靈才考慮(§7.3 更後續)。**CC 不檢舉**(mindset §7:CC 是操盤手不是審查者、不代人裁決;CC 對爛 recipe 的「投票」= 不選它 = 市場數據)。
|
||||
|
||||
> 影響現有 code:5.2 的 `POST /recipes/submit` 改「覆蓋」→「領新 UUID 新增」;recipe key 從 `recipe:{canonical_id}` 轉
|
||||
> `recipe:{uuid}` + canonical 索引;執行查找改經 `idx:installed:{canonical_id}` 拿唯一 UUID(保證不破 component-loader/auth-dispatcher/credential-injector)。列入 7.5.f task。
|
||||
|
||||
#### 7.5.6 搜尋落空 = 創作入口(richblack 2026-06-07 拍板)
|
||||
|
||||
> app-store 模型的閉環關鍵:公庫沒有的 recipe,由 CC 現做成為作者,再投回公庫補上。
|
||||
|
||||
**CC 搜「gsheets_delete_sheet」公庫沒有 → 端點不能只回空陣列乾等,要回「可創作」訊號 → CC 說「那我做一個」→ CC 成為作者。**
|
||||
|
||||
- 公庫只讀端點(§7.5.4)搜尋**落空時的回應 = 創作引導**,不是空結果:
|
||||
明確回 `{ found: false, canonical_id, hint: "公庫無此 recipe,可自行建立並 submit-p 投稿成為作者" }`,
|
||||
讓 CC(AI 操盤手)知道下一步是「自己做一個」而非卡住。
|
||||
- CC 現做 → 跑成功累積市場數據(§7.1)→ submit-p 推回公庫 → 成為公庫**第一個** `gsheets_delete_sheet`(CC 是作者)。
|
||||
- **閉環**:
|
||||
- 公庫有 → pull 用(市場數據選最佳作者版本,§7.5.5)。
|
||||
- 公庫沒有 → CC 現做成為作者 → 用 → 投稿 → 公庫從此有了。
|
||||
- 呼應 mindset:**CC 是大腦**(arcrun 是 AI 呼叫的工具),缺能力時 CC 自己補(做 recipe / 工作流),
|
||||
不停在「找不到」。工作流是 default、零件是例外(缺能力先想工作流/recipe,不是停手)。
|
||||
|
||||
---
|
||||
|
||||
## 8. KV list 上限威脅免費承諾 → 高頻 list 遷 D1(CHANGE,2026-06-08 richblack CF 收到 list 超標信)
|
||||
|
||||
> 事件:richblack 的 CF 帳號收到「Workers KV 免費等級每日 1000 次 list 上限已超」信,
|
||||
> list API 回 429 直到隔日重置。**這直接威脅 arcrun「免費可用」核心承諾**([[deploy-via-local-deploy-not-ci]] 免費優先精神)。
|
||||
> 方向拍板(richblack 2026-06-08):**高頻 list 改走 D1**(對齊 §6 Q2 的 KV vs D1 分工——要列舉/搜尋的進 D1)。
|
||||
|
||||
### 8.1 根因:哪些 KV list 是高頻(grep cypher-executor/src)
|
||||
|
||||
| 位置 | list 操作 | 頻率 | 嚴重度 |
|
||||
|------|----------|------|--------|
|
||||
| `scheduled.ts:34` | `WEBHOOKS.list({prefix:'cron-idx:'})` | **每分鐘一次 = 1440/日** | 🔴 **常駐單獨就爆**(>1000 上限) |
|
||||
| `recipes.ts` public-recipes(§7.5 新加) | `RECIPES.list({prefix:'recipe:'})` | 每次 recipe 搜尋 | 🟠 搜尋頻繁就疊加爆 |
|
||||
| `recipes.ts` GET /recipes / listAllRecipes | `RECIPES.list` | 每次列 recipe | 🟠 |
|
||||
| `webhooks-list.ts` / `webhooks-named.ts` | `WEBHOOKS.list` | 每次列 workflow | 🟠 |
|
||||
|
||||
> **D1 額度遠寬**:免費 5M 讀/日、100K 寫/日(§6 Q4),對比 KV list 僅 1000/日。要「列舉/搜尋/排序」的天生該 D1。
|
||||
|
||||
### 8.2 緊急止血(cron,今天在爆)
|
||||
|
||||
`scheduled.ts` 每分鐘 list `cron-idx:` → 改成**不靠 list**:
|
||||
- 方案:維護**單一固定 key**(如 `cron-idx:_all` 存所有 cron workflow 的 {apiKey,name,cron_expr} JSON 陣列),
|
||||
scheduled 只 `get` 一次(取代 list)。acr push 時 upsert 進這個 key。
|
||||
- 1440 次/日 list → **0 次 list**(改 1 次 get/分鐘 = 1440 get/日,KV get 免費額度 100K/日,遠夠)。
|
||||
|
||||
### 8.3 治本(recipe / workflow 查詢遷 D1,分期)
|
||||
|
||||
對齊 §6 Q2(recipe + workflow 進 D1):
|
||||
- **recipe**:recipe 本體從 RECIPES KV 遷進 KBDB D1(entry_type='recipe' 或專表)。
|
||||
public-recipes 搜尋、list 改 D1 query(LIKE/WHERE,含 §7.5 多作者/市場排序天生適合 SQL)。
|
||||
執行時 resolveRecipe 也改 D1(但執行是 get-by-key 級,KV get 不爆——可漸進)。
|
||||
- **workflow**:workflow record 從 WEBHOOKS KV 遷 D1(entry_type='workflow' 掛 project parent,§6 Q1)。
|
||||
list workflow 改 D1 query。
|
||||
- **保留 KV 的**:session / credential / exec context(§6 Q2:短期高頻純 get,不 list)。
|
||||
|
||||
### 8.4 分期建議(待 richblack 拍板細節)
|
||||
|
||||
1. **P0 止血**(§8.2):cron 改單 key get。最小改動、今天可止血。
|
||||
2. **P1**:public-recipes / recipe list 改 D1(我 §7.5 新加的 list 是疊加元兇)。
|
||||
3. **P2**:workflow list 改 D1。
|
||||
4. **P3**:recipe/workflow 本體完整遷 D1(resolveRecipe / KV→D1 讀寫)。
|
||||
|
||||
> **誠實 trade-off**:遷 D1 要寫 migration + 雙寫過渡(KV 舊資料相容),工程量不小。
|
||||
> 但不遷 = 免費承諾破功(用戶用一用就 429)。**這是核心承諾必修項,不是優化。**
|
||||
> 待 review §8 + 拍板分期顆粒度後動 code。**勿在 review 前動。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 開放問題(待 review)
|
||||
|
||||
1. **專案維度怎麼進 entries**:`entry_type='project'` + workflow 用 `parent_id` 掛專案?還是 templates 定義「專案」虛擬表?
|
||||
1. Leo:由你決定,我記得先前 KBDB 已經有實作,參考原有做法。
|
||||
2. [DECIDED, CC 2026-06-07] use entry_type=project + parent_id tree (NOT templates virtual table). Matches existing KBDB: entry_type is an extensible string, entry-crud.ts already supports WHERE parent_id; no schema change (honors table-never-changes). "list workflows under project" = WHERE parent_id=PROJECT_ID AND entry_type=workflow. templates/slot reserved for structured records like recipe success stats.
|
||||
2. KV vs D1 分工[拍板 2026-06-07]:KV 不全廢,按特性分。workflow YAML + recipe + 成功記錄進 D1(要層級/列舉/排序);session、verdict、credential 留 KV(短期高頻純取用)。類比 PostgreSQL + Redis。workflow 變 entry(entry_type=workflow 掛 project parent)。
|
||||
1. Leo:同意
|
||||
3. **triplet 獨立 repo 的接點**:基礎 KBDB 怎麼讓 triplet 模組「掛上」——HTTP hook?還是 triplet worker 自己讀同一個 D1?
|
||||
1. Leo:triplet 其實也就是 template 加上一些函式,最簡單就是你給他一段文字抽取出三元組,但如果要自動化,就會提供 API,背後是工作流,例如 block 存入時就叫起 triplet 功能,這個功能如果自動化就是在安裝時同意,但應該也可以有 mcp 讓 AI 易於操作,如同前述,交貨時有 MCP,因為是 AI Friendly 的系統。
|
||||
4. **init 建 D1 的冪等 + self-hosted 免綁卡確認**:D1 是否如 KV 一樣免費不綁卡(需查證 CF D1 免費額度條件)。
|
||||
1. Leo:一樣不綁卡,除非他用量很大,屆時不是我來提醒而是 CF 會提醒他
|
||||
@@ -0,0 +1,221 @@
|
||||
# Tasks: KBDB Base — atomic universal table
|
||||
|
||||
> 對應 design.md。design 待 richblack review 後才動 code。每完成一個 task 立刻標 [x],不批次。
|
||||
> 來源:壓測報告暴露 self-hosted 無資料層;richblack 2026-06-07 拍板 KBDB 基礎開源 + 插件模式。
|
||||
|
||||
---
|
||||
|
||||
## 狀態:SDD 草稿,待 review design + 拍板開放問題後才動 code
|
||||
|
||||
- [x] Q1 專案維度[拍板 2026-06-07]:richblack 授權 CC 決定,參考 KBDB 既有實作(已有 project/parent 做法)
|
||||
- [x] Q2 KV vs D1 分工[拍板 2026-06-07]:KV 不全廢,按特性分——workflow YAML+recipe+成功記錄進 D1;session/verdict/credential 留 KV
|
||||
- [x] Q3 triplet 接點[拍板 2026-06-07]:triplet = template + 函式。手動(給文字回三元組)或自動(block 存入時叫起,安裝時同意);提供 MCP(AI-friendly,交貨帶 MCP)
|
||||
- [x] Q4 D1 免費不綁卡[查證 2026-06-07 CF docs]:Workers Free 可用、不需信用卡(不像 R2)。額度 5M 讀/日、100K 寫/日、5GB。用量大時 CF 自會提醒用戶。
|
||||
|
||||
## Phase 0:基礎抽取與解耦
|
||||
|
||||
- [x] 0.1 三表 migration 抽出 arcrun/kbdb/migrations/0001_base.sql(entries/templates/entry_values + recipe_stat template seed),無 triplet/entity/vectorize 表
|
||||
- [x] 0.2 萬年不動:新基礎 schema 本就不含 entity_type(那是 triplet 衍生欄位)→ 基礎 entries 無此欄,衍生屬性天然在基礎表外。原 kbdb 的 UPDATE blocks SET entity_type 屬 triplet 模組(獨立 repo),不影響 arcrun 基礎
|
||||
- [x] 0.3 解耦:arcrun/kbdb 從零寫乾淨基礎(entry/template/record CRUD),不 import 任何 embed/triplet(grep 證);不去動原 kbdb repo(官方版仍用,動它有風險)
|
||||
- [x] 0.4 templates/records route 純淨:只依賴 record-crud(D1),無 vectorize/triplet
|
||||
- [x] 0.5 基礎 search = D1 LIKE(GET /entries/search?q=,mode:keyword);語義層留給 embed 模組(未在基礎)
|
||||
|
||||
## Phase 1:embed 模組(CF 內建,binding 開/關,不拆 repo)
|
||||
|
||||
> 狀態:基礎已與 embed 完全解耦(不 import)。embed 模組本身(Vectorize upsert + 語義 search)尚未實作——基礎不依賴它即可,embed 待要用時再加。以下 1.x 未做。
|
||||
|
||||
- [ ] 1.1 embed 改可選 hook:有 env.VECTORIZE 才掛
|
||||
- [ ] 1.2 search 語義層:有 Vectorize 啟用,否則降級 LIKE,API 不變
|
||||
- [ ] 1.3 wrangler.toml:Vectorize/AI binding 可選
|
||||
|
||||
## Phase 2:import 進 arcrun(如 MCP pattern)
|
||||
|
||||
- [x] 2.1 基礎 KBDB Base 搬進 arcrun/kbdb/(Worker + D1):kbdb/ 已建(三表 CRUD + recipe-stats + migration),納入 find wrangler.toml deploy 掃描
|
||||
- [x] 2.2 cf-api.ts 加 D1 建立(listD1Databases/ensureD1Database);deploy.ts 注入 d1DatabaseId 到 kbdb wrangler.toml
|
||||
- [x] 2.3 self-hosted init 建 KV + D1(Q4 已確認免綁卡):init ensureD1Database 建空 D1 → deploy 部署完對 D1 套 migrations/0001_base.sql(CF /d1/query API,idempotent)建三表 + recipe_stat seed + 注入 wrangler.toml database_id
|
||||
- [ ] 2.4 cypher 改用 KBDB 存專案/工作流歸屬(依 Q1/Q2,漸進)— 未做(後續)
|
||||
|
||||
## Phase 3:triplet 模組(獨立 repo,本 SDD 只定接點)
|
||||
|
||||
- [ ] 3.1 確認基礎不依賴 triplet(Phase 0.3 後驗證)
|
||||
- [ ] 3.2 定義 triplet 掛上基礎的接點(依 Q3)
|
||||
- [ ] 3.3 triplet 本身 → 獨立 repo,不在本 SDD
|
||||
|
||||
## Phase 4:官方共用基礎(方向,搬遷另排)
|
||||
|
||||
- [ ] 4.1 官方版改用同一份基礎 KBDB(binding 全開)→ 不維護兩套
|
||||
|
||||
## Phase 5:recipe 投稿 + 帶 KBDB 成功記錄(免官方驗證)—— 本次要做(design 7)
|
||||
|
||||
- [x] 5.1 recipe 成功記錄落地 D1:判定單位=工作流執行(n8n execution)。GraphExecutor 收集本次用到的 recipe key(usedRecipeKeys=API recipe uuid,§7.5.h 改 per-uuid;舊資料 fallback canonical_id);executeWebhookGraph 執行結束後一次性 POST KBDB /recipe-stats/record(整體成功→各+1成功、真錯非paused→各+1失敗,fire-and-forget via waitUntil)。cypher tsc exit 0
|
||||
- [x] 5.2 投稿端點(cypher recipes.ts):POST /recipes/submit(需 exposure_consent、stat 存證不當門檻)。**已修正**(7.5.f):原「覆蓋同 canonical_id」→ app-store/UUID 模型「領新 uuid 新增作者版本」,同 canonical 多作者並存。cypher tsc exit 0
|
||||
- [x] 5.3 CLI 接點(= 7.5.b/c/e):acr recipe push(私庫)/ pull(公→私)/ submit-p(公共庫帶暴露同意)。cli tsc exit 0
|
||||
- [x] 5.4 市場機制(靠量/星數模型,design §7.3):stat 存證已做(5.2 recipe_submission entry)+ per-uuid 市場數據(5.1+7.5.h)。先市場優先、暫不強防偽(5.6 後續)
|
||||
- [ ] 5.5 市場同步(跨環境聚合層,§7.3 主體):self-hosted 各用戶真實成功/失敗匯總回公共市場 → recipe 星數/信用。5.1 已在各環境記錄,聚合另排
|
||||
- [ ] 5.6 強防偽(只在市場失靈才做):官方 in-process 重跑投稿者工作流拿官方自己 2xx / 第二投稿者獨立回報;版本並存/舊版下架
|
||||
|
||||
## Phase 7.5:公庫/私庫雙向機制(CHANGE,design §7.5)—— richblack 2026-06-07 review 通過,可執行
|
||||
|
||||
> richblack 指示「把兩庫所有情境想好」+「這些細節想好是可以執行」→ §7.5 review 通過,開始動 code。
|
||||
> **7.5.5 拍板:recipe = 具名作者作品(app-store 模型)**——同 canonical_id 多作者並存、只有作者+admin 能改、
|
||||
> 投稿=新增作者版本(非覆蓋)、向後相容不刪舊、選擇由市場數據驅動、無「公庫改私庫要不要跟」問題。
|
||||
> **7.5.6 拍板:搜尋落空=創作入口**——公庫沒有→回 found:false 創作引導→CC 現做成為作者→投稿補上(閉環)。
|
||||
|
||||
- [x] 7.5.g 落空創作引導:GET /public-recipes(?q=) 與 GET /public-recipes/:canonical_id 落空回 { found:false, hint } 創作引導,不回空陣列。cypher tsc exit 0
|
||||
- [x] 7.5.a 公庫只讀端點(cypher recipes.ts):GET /public-recipes?q=&limit=&offset=(list/search 多作者+per-uuid 市場星數)、GET /public-recipes/:canonical_id?author=(pull 取全文,多作者選市場最佳)。cypher tsc exit 0
|
||||
- [x] 7.5.h **市場星數 per-uuid(§7.5.h)**:5.1 改收集 API recipe uuid(resolveRecipe,非 resolveAuthRecipe);usedRecipeServices→usedRecipeKeys;KBDB 星數記 per-uuid;public-recipes 選最佳 per-uuid 查 → 真正區分 Leo/John 版。cypher tsc exit 0
|
||||
|
||||
- [x] 7.5.f **recipe UUID 身份模型(app-store 核心,§7.5.5 拍板)**:recipes.ts RecipeDefinition 加 uuid/author/derived_from;installRecipeRecord helper(recipe:{uuid} + idx:canonical 清單 + idx:installed + idx:hash);POST /recipes=私庫沿用 installed uuid 就地更新;POST /recipes/submit=領新 uuid 新增作者版本(非覆蓋);resolveRecipe 向後相容(uuid→installed→fallback 舊 key,不破執行鏈);DELETE 清 uuid+索引;GET dedup;init-seed 用 UUID(author=system);POST /recipes/migrate-uuid 一次性轉舊 key(增量寫不刪舊、冪等)。cypher tsc exit 0。重複靠市場淘汰、不做檢舉、CC 不檢舉(§7.3+mindset §7)
|
||||
- [x] 7.5.b 公→私 pull(CLI 薄殼):acr recipe pull <canonical_id> [--author] → GET 公庫 /public-recipes/:id → POST 自己私庫 /recipes(帶 derived_from 溯源)。cli tsc exit 0
|
||||
- [x] 7.5.c 公庫搜尋(CLI 薄殼):acr recipe search <q> → GET 公庫 /public-recipes?q=,印多作者+市場數據,落空印創作引導。cli tsc exit 0
|
||||
- [x] 7.5.e submit-p(CLI 薄殼):acr recipe submit-p <canonical_id> [--author] → GET 私庫取全文 → 暴露同意 → POST 公庫 /recipes/submit(新增作者版本)。config 加 DEFAULT_PUBLIC_LIBRARY_URL(公庫=官方 cypher,ARCRUN_PUBLIC_LIBRARY_URL 可覆蓋)。cli tsc exit 0
|
||||
- [x] 7.5.i **MCP 薄殼補齊 recipe 工具(rule 07 §5)**:新增 mcp/src/tools/arcrun_recipe.ts 六工具 arcrun_recipe_search/pull/submit_p/push/list/delete(registerAllRecipeTools 註冊進 registry.ts),全用 cypherFetch 薄殼模式(無業務邏輯)。與 CLI 六能力對齊,MCP 不再落後。submit_p 帶 exposure_consent 把關。mcp tsc exit 0。註:MCP 連平台 cypher(§5.2 account-source 已知違反 pre-existing,沿用既有模式不一併修)
|
||||
|
||||
## Phase 8:KV list 上限威脅免費承諾 → 高頻 list 遷 D1(CHANGE,design §8)—— 待 richblack review 分期顆粒度,勿動 code
|
||||
|
||||
> 2026-06-08 richblack CF 帳號收到 KV list 超標信(每日 1000 上限,429)。威脅免費核心承諾。
|
||||
> 方向拍板:高頻 list 遷 D1(對齊 §6 Q2)。根因①cron 每分鐘 list(1440/日單獨就爆)②§7.5 新加的 recipe 搜尋 list。
|
||||
> 待 review §8 分期顆粒度後才動 code。
|
||||
|
||||
- [x] 8.P0 **緊急止血 cron**(§8.2):scheduled.ts 每分鐘 WEBHOOKS.list('cron-idx:') → 改單一固定 key(cron-idx:_all 存 {apiKey}:{name}→cron_expr map)只 get 一次。新增 lib/cron-index.ts(readCronIndex/updateCronIndexEntry,單 key read-modify-write);webhooks-named POST/DELETE 改維護單 key;新增一次性 POST /webhooks/named/migrate-cron-index 把舊 per-key 折進集中 key(冪等、不刪舊);acr update 部署後自動呼叫 migrate(接在 seed 後,冪等、失敗不致命)→ 既有 cron 不必手動重 push。1440 list/日 → 0 list。cypher+cli tsc exit 0。**已完成 2026-06-09**
|
||||
- [ ] 8.P1 recipe 查詢遷 D1(§8.3):public-recipes 搜尋 + GET /recipes list(§7.5 新加的元兇)改 D1 query(LIKE/WHERE,多作者/市場排序天生適合 SQL)
|
||||
- [ ] 8.P2 workflow list 遷 D1:webhooks-list/webhooks-named 的 list 改 D1 query(entry_type=workflow)
|
||||
- [ ] 8.P3 recipe/workflow 本體完整遷 D1:resolveRecipe / KV→D1 讀寫 + migration + 雙寫過渡(KV 舊資料相容)。session/credential/exec-context 留 KV(§6 Q2)
|
||||
|
||||
## Phase 9:KBDB 資料層薄殼補 MCP/CLI(HANDOFF §2,design §4「交貨帶 MCP」)—— 本次做
|
||||
|
||||
> 核實:CLI/MCP 現在完全沒 KBDB 資料層能力(既有 arcrun_skills_examples 打的是舊 /blocks /search
|
||||
> v3 schema,非本基本盤三表)。基本盤 API 已完整(templates/records/entries/search)。
|
||||
> 本 Phase = **薄殼暴露**,不重寫能力(rule 07)。
|
||||
> **KBDB 鐵律(leo 2026-06-14)**:不提供建表/SQL tool,AI 只有「建 template(name+slots) + 填 record(slot→content)」
|
||||
> 可用(類 Supabase 萬用表);薄殼只經 KBDB service binding 調基本盤 HTTP API,不直連 D1、不寫 SQL。
|
||||
|
||||
- [x] 9.1 **MCP 薄殼**(AI 用,插件也走這條):mcp/src/tools/kbdb_data.ts,6 工具
|
||||
`kbdb_create_template`(name+slots)、`kbdb_list_templates`、`kbdb_create_record`(template+values)、
|
||||
`kbdb_get_record`(record_id)、`kbdb_query`(by-template 列 records)、`kbdb_search`(entries LIKE q)。
|
||||
全走既有 kbdbFetch(KBDB binding)薄殼模式,無業務邏輯。registerAllKbdbDataTools 註冊進 registry.ts。
|
||||
**不含建表/SQL tool**(鐵律,grep 證 code 無 CREATE TABLE/.prepare/env.DB/SQL)。**mcp tsc exit 0**(2026-06-14)。
|
||||
- [x] 9.5 **cypher KBDB proxy(9.2 的前置,2026-06-14)**:CLI 是 client 只認證到 cypher,達不到獨立
|
||||
KBDB worker(MCP 走內部 service binding 可達,CLI 不行)。故在 cypher 開 `cypher-executor/src/routes/kbdb-proxy.ts`
|
||||
純轉發 `/kbdb/templates|records|search` → KBDB 基本盤(沿用 KBDB_BASE_URL HTTP fetch + KBDB_INTERNAL_TOKEN,
|
||||
**不新增 service binding** rule02 §3.1)。**租戶隔離(leo 拍板選項①)**:X-Arcrun-API-Key 自動當 owner_id 注入
|
||||
records/entries(強制覆寫 caller 自帶 owner_id 防跨租戶寫);**templates 全域共享**(虛擬表定義是 schema 非資料)。
|
||||
無 SQL/建表/業務邏輯(純 proxy)。掛進 index.ts。cypher tsc exit 0。
|
||||
- [x] 9.2 **CLI 薄殼**(人用,2026-06-14):`cli/src/commands/kbdb.ts` — acr kbdb template create/list、
|
||||
record create/get、query、search,透過 9.5 的 cypher proxy 打基本盤(與 MCP kbdb_* 同能力,差異只來自介面慣例
|
||||
rule07 §3.4)。註冊進 index.ts(`acr kbdb`)。無業務邏輯(薄殼)。cli tsc exit 0。
|
||||
**未驗收**:端到端需 cypher 部署 + KBDB_BASE_URL 可達後實測(acr kbdb template create → query 回得到)。
|
||||
- [x] 9.3 **基本盤 entries 加 page_name 讀過濾**(2026-06-14):listEntries 加 `page_name` 過濾 +
|
||||
GET /entries 接 `?page_name=`(既有欄位的便利查詢,不動表結構、不違反「表不變」鐵律)。
|
||||
用途:skills/examples 用 page_name 當 idempotency key 做 get-by-key。kbdb tsc exit 0。
|
||||
- [x] 9.4 **修復 LI M3 斷鏈**(2026-06-14,連動 llm-interface M3.2/M3.4):skills/examples 整條從
|
||||
舊 v3 `/blocks` `/search` 改打基本盤 `/entries`(entry_type 對應)。5 個已上線的 MCP 工具原本
|
||||
對死 route 回 404(假綠),現修正;sync-registry-to-kbdb.py 改打 /entries idempotent upsert。
|
||||
誠實降級:基本盤無語義 search → search_examples 改 LIKE 關鍵字(embed 模組 Phase 1 上線再換回語義)。
|
||||
mcp + kbdb tsc exit 0。
|
||||
|
||||
- [x] 9.6 **cypher proxy 補 `/kbdb/entries` CRUD(HANDOFF §2 缺口①,2026-06-15)**:9.5 proxy 只轉發
|
||||
templates/records/search,**漏了基本盤的 `/entries` CRUD**——這正是 mira `_kbdb_client.py` 主線遷移
|
||||
(ingest/create_block/get_by_id/get_by_page_name/patch_block)要打的端點。補 POST/GET(list)/GET(:id)/PATCH(:id)
|
||||
`/kbdb/entries` 純轉發到 KBDB 基本盤 `/entries`。**租戶隔離同 9.5 選項①**:寫入強制注入 owner_id、list 強制
|
||||
以本租戶 owner_id 過濾(防跨租戶讀)、PATCH 剝除 caller 自帶 owner_id(防認領/踢走);by-id GET 沿用既有
|
||||
records by-id 慣例(require-key)。**刻意不開 DELETE**(基本盤 delete-by-id 無 owner 檢查,經 proxy 暴露 =
|
||||
跨租戶刪除風險;mira 也不需要)。無 SQL/業務邏輯(純 proxy)。**cypher tsc exit 0** + **端到端 prod 驗收綠**(2026-06-15):
|
||||
無 key→401;A POST→owner_id 自動=A;GET by id 回得到;A list count=1、B list 同 type **count=0**(跨租戶隔離);
|
||||
PATCH 改 content 成功且 owner_id hijack→B 被剝除(仍=A、B 看不到);page_name lookup count=1(mira idempotency 路徑);
|
||||
POST 帶 caller owner_id=B→覆寫成 A。已部署 arcrun-cypher-executor(官方 58309bb9)。smoke 資料已清。
|
||||
- [x] 9.7 **修 `arcrun_report_feedback` 死 route(HANDOFF §3b 連帶,9.4 漏網,2026-06-15)**:9.4 把
|
||||
skills/examples 從舊 v3 `/blocks` 改打基本盤 `/entries`,但 `arcrun_report_feedback` 仍 POST 死掉的 `/blocks`
|
||||
(KBDB 基本盤只 mount entries/templates/records/recipe-stats,無 /blocks → 404 假紅)。改打 `/entries`
|
||||
(entry_type=agent-feedback、owner_id=用戶 namespace、source/api_key 併入 metadata_json、tags_json 不變)。
|
||||
回傳 id 從基本盤 `{entry:{id}}` 取(兼容舊 `{id}`)。薄殼模式不變(kbdbFetch)。**mcp tsc exit 0** +
|
||||
**端到端 prod 契約驗收綠**(2026-06-15):確認舊 `/blocks`→**404**(正是原 bug、report_feedback 假紅根因);
|
||||
用 9.7 實際送的 payload(entry_type=agent-feedback + metadata_json/tags_json)POST `/entries`→success、欄位保留;
|
||||
經 cypher proxy 讀回 count=1。已部署 arcrun-mcp(官方 58309bb9)。注:MCP service-binding hop 由既有 kbdb_* 工具
|
||||
(9.1,同 kbdbFetch 路徑,2026-06-14 已驗)佐證 binding 活;本次只修死 URL。smoke 資料已清。
|
||||
|
||||
## Phase 10:base 補 record PATCH(mira-dissolve T2 `[→arcrun]`,issue #6)—— 本次做
|
||||
|
||||
> 來源:頂層 SDD `docs/3-specs/mira-dissolve/`(T2.1/T2.2),總管經本 repo GitHub issue #6 交辦。
|
||||
> 用途:graph 插件的精耕「取代」語意(同來源檔重萃 → 舊版 deprecate)需要「改既有 record 的 slot 值」。
|
||||
> **三表 append-only 不破**:deprecate = 翻 record 的 slot 值(改底層 `entries.content`),不動表結構、不加欄、不刪 row。
|
||||
> **base 不知 triplet(解耦鐵律 0.3,grep-proven)**:故 base 端 **不建 `/templates/triplet` 專屬端點**。
|
||||
> issue 描述的「PUT /templates/triplet 加 status/superseded_by」拆兩半(與頂層 tasks T2.2/T3.2 一致):
|
||||
> base 只提供**通用** template 增改 slots 能力(既有 `PATCH /templates/:id` 已替換 slots_json,本就支援);
|
||||
> triplet 專屬的 `status`/`superseded_by` 兩 slot 由 **T3.2 在 kbdb-graph-plugin 的 `TRIPLET_SLOTS` 補**(另一 repo,非本次)。
|
||||
|
||||
- [x] 10.1 **`PATCH /records/:id`(T2.1,前置硬依賴)**:改既有 record 的 slot→content 值。底層更新對應
|
||||
`entries.content`(既有 slot 找 entry_value→entry 改 content);slot 不存在則補建 entry + entry_value(用 record 的
|
||||
template 推算 slot 是否合法)。**三表結構一個欄位都不加**。`updateRecord` 在 record-crud.ts、route 在 records.ts。
|
||||
- [x] 10.2 **template 增改 slots = 既有 `PATCH /templates/:id`(T2.2,base 端)**:核實 `updateTemplate` 已支援
|
||||
`slots` 替換(record-crud.ts:44 既有)→ base 端通用能力已就緒,**無需新 code、不建 triplet 端點**。triplet 兩 slot
|
||||
歸 T3.2(plugin repo)。本條=核實 + 文檔釐清,非改 code。
|
||||
- [ ] 10.3 **(選)`DELETE /records/:id`(T2.3)**:暫不做。依賴頂層 T8.3「死資料自動刪除原則」(design 待觀察未定);
|
||||
且 deprecated record 查詢 `where status=active` 本就濾掉 → 無此端點不阻擋 deprecate 落地。待頂層拍板再補。
|
||||
|
||||
## Phase 11:self-hosted KBDB 查詢能力補缺(issue #5,普世框架視角)—— 本次做
|
||||
|
||||
> 來源:issue #5(原 Mira dogfood 開,Mira 已蒸發 → 當「未來任何 self-hosted 用戶都會撞的框架缺口」處理)。
|
||||
> 四點分流依 leo 2026-06-26 修正指示 + 頂層 mira-dissolve 重審:
|
||||
> 規則判準見 07-thin-shell §3.5(issue #4 自力救濟階梯):source/DELETE 屬**自家 API 缺能力 → 補 API**。
|
||||
|
||||
- [x] 11.1 **source 過濾(#5 第1點,✅ 做,普世成立)**:`listEntries` 加 `source` filter,
|
||||
GET /entries 接 `?source=`。**零建表/零 migration**:用 SQLite `json_extract(metadata_json,'$.source')`
|
||||
查既有 metadata_json TEXT 欄(**不加欄、表不變鐵律**)。cypher proxy `GET /kbdb/entries` 白名單加
|
||||
`source`(隨租戶 owner_id 一起篩)。按來源篩 + 語義/關鍵字查詢都會用,ingest envelope 帶 source.uri。
|
||||
kbdb+cypher tsc exit 0。**端到端待 leo21c 部署驗**(需寫一筆帶 metadata.source 的 entry → ?source= 篩回)。
|
||||
- [ ] 11.2 ~~documents 聚合 GROUP BY page_name(#5 第2點)~~ **不做**(舊河道頁特例):新架構「跨 vault 的圖」
|
||||
走 graph MCP traverse/neighbors,不靠 KBDB 出 SQL 聚合端點。普世用戶也不需要。頂層 R6 已否決。
|
||||
- [ ] 11.3 **cypher proxy DELETE(#5 第3點)⏸ 暫擱置**:依賴頂層「死資料自動刪除原則」(mira-dissolve T8,
|
||||
待觀察未定)。等 T8 拍板再補。**註**:#6 已對 records proxy 同理擱置 DELETE(裸 delete-by-id 無 owner 檢查,
|
||||
經 proxy 暴露=跨租戶刪除風險,補時要先讀 entry 驗 owner_id==本租戶才放行)。
|
||||
- [→#7] 11.4 **embed-on-write(#5 第4點)併入 #7**:開 embed module + `kbdb_embed:true` 後寫入是否自動
|
||||
embed,由 #7 embed 模組定義(module 職責,前端不該手動戳 process-page)。不在 #5 單獨處理。
|
||||
- [x] 11.5 **能力對照文件(#5 第二部分)**:`docs/4-guides/kbdb-capabilities.md` —
|
||||
self-hosted arcrun-kbdb 現有查詢能力清單 + 端點對照。**不寫「documents/process-page 待移植」**
|
||||
(舊河道視角,新架構不移植)。
|
||||
|
||||
## Phase 12:optional embed 模組 + vectorize 開關 + 語義查詢(issue #7 / mira-dissolve T2.4)—— 本次做
|
||||
|
||||
> 來源:issue #7(總管,全包 4 件)+ 頂層 mira-dissolve T2.4 系列。普世框架能力(任何 self-host 用戶可選開語義查詢)。
|
||||
> 鐵律:embedding 屬 **base optional 模組**(非 graph/ingest);CF Vectorize+AI binding 開/關,不拆 repo;
|
||||
> **不裝保持輕**(free-tier 友善);不對每個 block 地毯式 embed(精耕:只 embed 標 embed:true 的 entry)。
|
||||
> 解鎖下游:ingest embed(第二階段)+ graph 詞+gloss 語義 normalize(T3.2c)等此。
|
||||
|
||||
- [x] 12.1 **base embed 模組(T2.4,從零做)**:`kbdb/src/embed.ts`——`embedEnabled()`(VECTORIZE+AI binding 都在才算開)、
|
||||
`embedOnWrite()`(寫入時對標 `metadata_json.embed:true` 的 entry 做 Workers AI `@cf/baai/bge-base-en-v1.5`
|
||||
768 維 → `VECTORIZE.upsert`,標 is_embedded=1,**不動表結構**)、`semanticSearch()`(query 向量 + metadata filter
|
||||
owner_id/source)。**base 對內容語意無知**:用通用 `embed:true` flag 而非寫死 entry_type 白名單(不破解耦)。
|
||||
wrangler.toml 加註解版 `[[vectorize]]+[ai]`(deploy 開時取消註解)。
|
||||
- [x] 12.2 **entries route 接 embed(含 #5 第4點 embed-on-write)**:POST/PATCH 用 `executionCtx.waitUntil`
|
||||
fire-and-forget embed(模組開 + entry embeddable 才做,失敗不致命);DELETE 連帶刪向量(避孤兒);
|
||||
**GET /entries/search 加 `mode=keyword|semantic`**:semantic 需模組開,未開→**誠實降級 keyword + `capability_hint`
|
||||
告知「叫 CC 幫開 vectorize」**(發現閉環,#7 第4點 + 不假綠)。kbdb tsc exit 0。
|
||||
- [x] 12.3 **vectorize 開關從零做(T2.4c)**:`.arcrun.yaml`/config 加 `kbdb_embed`(config.ts interface + env override
|
||||
ARCRUN_KBDB_EMBED 布林);`deploy.ts` 加 `DeployContext.kbdbEmbed`:開時 `ensureVectorizeIndex`(REST
|
||||
`POST /vectorize/v2/indexes` dims=768/cosine,冪等)+ `injectWranglerConfig` 取消 kbdb toml 的 vectorize/ai 註解
|
||||
(**置於 stripOfficialOnlyBindings 之後**,否則 [ai] 被 strip 清掉——已驗);`acr init` 互動加問「要不要開語義查詢」
|
||||
(預設關);存進 config 讓 acr update 維持一致。cli tsc exit 0。
|
||||
- [x] 12.4 **KBDB MCP 加語義查詢(T2.4b)**:`kbdb_search` 加 `mode`/`source` 參數透傳 + 把 base 的 `capability_hint`
|
||||
當 next-step 回給 AI(語義/關鍵字同一 KBDB MCP,D17 邊界)。薄殼模式不變(kbdbFetch)。mcp tsc exit 0。
|
||||
- [x] 12.5 **CC 幫開 vectorize(T2.4d,第一版)**:路徑=CC 寫 config `kbdb_embed:true` + `acr update`(已接 kbdbEmbed
|
||||
→ 建 index + 注入 binding redeploy)。base 查詢回應的 `capability_hint` 是發現入口。Pages 設定頁不做(leo 排未來)。
|
||||
- [ ] 12.V **端到端驗收 ⏳ 待 leo21c 部署驗**(需官方/leo21c 帳號開 Vectorize index):開 kbdb_embed → acr update →
|
||||
寫一筆帶 `metadata.embed:true` 的 entry → `?mode=semantic` 搜回;未開時 `?mode=semantic` 回 keyword+capability_hint。
|
||||
本次只到 **tsc exit 0(kbdb/cypher/cli/mcp 全綠)+ toml 注入 dry-run 驗證**,不假裝端到端綠(mindset §7)。
|
||||
|
||||
## 驗收
|
||||
|
||||
- [ ] V1 純 D1(無 Vectorize/AI)能 CRUD entries/templates/records + LIKE search
|
||||
- [ ] V2 開 Vectorize 語義啟用、關掉降級 LIKE,API 不變
|
||||
- [ ] V3 基礎 blocks/templates/records grep 無 vectorize/triplet import
|
||||
- [ ] V4 self-hosted init 建 D1 成功、不綁卡
|
||||
- [ ] V5 列出某專案下所有工作流可行
|
||||
- [ ] V6 各 worker tsc exit 0
|
||||
|
||||
## Notes
|
||||
|
||||
- 插件模型對標 PostgreSQL:基礎核心=psql core;embed=PGVector;triplet=Apache AGE。
|
||||
- embed 不拆 repo(CF 內建、binding 開關);triplet 拆獨立 repo(IP、action 多)。
|
||||
- 官方與 self-hosted 共用同一基礎,差別只在 binding → 只維護一套。
|
||||
- recipe 投稿入口是另一條線(registry),不在本 SDD。
|
||||
Reference in New Issue
Block a user