Files
Arcrun/registry/examples/km-wiki-ingest/description.md
T
Leo d93dc4e350 feat(km-wiki-ingest): parse_card 改用通用 code 零件;刪 domain 零件 km_wiki_card_parse
Arcrun#10 裁定:一次性解析走通用逃生口,不再鑄 domain 零件。

- workflow.yaml:parse_card 由 component:km_wiki_card_parse -> component:code,
  config.code 內聯 card-to-envelope 的 planCard 邏輯(去 import/export、raw NUL
  分隔符改 u0000 escape、改用 code 沙箱注入的 sha256);下游 refs 改 parse_card.data.*;
  加 limits(timeout_ms/max_output_bytes)。已端到端驗證(YAML 解析->JS eval)與原
  planCard 輸出逐欄全等(含 content_hash)。
- 刪 registry/examples/km-wiki-ingest/component-contract.yaml(km_wiki_card_parse 契約)。
- lib/card-to-envelope.mjs:header 改述為「code 節點內聯 JS 的權威來源 + 參考實作」,
  邏輯不變(續為 inline JS 之單一真相源)。
- lib/dry-run.mjs / description.md:框架改述為 code-節點形態;部署清單更新為「部署通用
  code 零件」。dry-run-evidence.json(3 entries/15 triplets/16 nodes)不變——解析輸出等價。

不部署、不寫 live。留分支可部署狀態。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 04:50:08 +00:00

75 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# km-wiki-ingest — 機械式 wiki 卡片 → KBDB ingestArcrun#8 / 頂層 SDD T2T4
> Phase A 產物:機械 ingest 邏輯 + 乾跑證據 + workflow 設計。**不部署、不寫 live KBDB。**
## 解決什麼問題
把各 repo 的 `system-dev/wiki/cards/**/*.md`(人工精耕卡)**機械地**(無 LLM)灌進 leo21c KBDB
- **卡片 → base entry**`metadata.embed=true`,供語意搜尋)。
- **`## 實體` → graph node****`## 關聯` 的 typed-edge`A >> 關係 >> B`)與 `[[wikilink]]` → graph triplet**。
取代舊 `kbdb-ingest-plugin/scripts/ingest-cli.mjs``raw → Haiku → 三元組` 路:新路純解析卡片內既有結構,**決定性、零 token、零幻覺**。
## 形式選擇與理由(給總管)
**形式 = Arcrun workflowYAML 編排)+ 通用 `code` 零件(sandbox inline JSArcrun#10)承載卡片→envelope 解析 現成零件(`cron` / `http_request` / `foreach_control` / `kbdb_upsert_block`)。** 不再鑄 domain 零件 `km_wiki_card_parse`Arcrun#10 裁定:一次性解析走通用逃生口)。
理由:
1. **編排本來就是 arcrun 的主場**cron 限速 drain、Gitea webhook 只吃 delta、foreach 小批、冪等 upsert——這些跟現成零件 1:1 對得上,且 leo 要「Arcrun workflow 慢慢做」、arcrun 哲學禁一次性腳本。
2. **arcrun 唯一缺的是「卡片 → envelope」的解析**。那是一段**決定性純轉換**(無 LLM、無網路、無檔案)——正好是 `code` 零件 sandbox 的理想形狀(`stdin_stdout_json` + `no_network_syscall` + `no_filesystem_syscall`)。用通用 `code` 節點內聯這段 JS(而非鑄 domain 零件、也非在 YAML 裡塞 `string_ops` 正則):workflow 可讀、解析可單元測試、且 registry 不因一次性邏輯增生 domain 零件。
3. **小批是結構性的,不是靠祈禱**:一卡一 tick,每卡在 graph worker 的 fan-out ≈ `7+4N+M` subrequestnotes 卡 N≈4/M≈5 → est 28~33,穩壓 CF 50 頂下);`code` 節點內聯解析會**預先把超大卡以 `source_uri` anchor 分段**,任何單一 graph 呼叫都不破頂。
**Phase A 交付**:純解析+打包核心(`lib/card-to-envelope.mjs`,現在就能跑,= `code` 節點內聯 JS 的權威來源)+乾跑驗證器(`lib/dry-run.mjs`,印出「將寫入什麼」)+本 workflow.yamlparse_card = `code` 節點)。解析零件=通用 `code`Arcrun#10 分支,已就緒待部署);本 example 不再自帶 domain 零件契約。部署被閘控,故 live 接線是「設計而非執行」。
## 診斷小結:fan-out 精確來源 + 小批為何解得掉
`kbdb-graph-plugin` 現役寫入路徑(`triplet-ingest.ts` / `triplet-crud.ts` / `templates.ts` / `kbdb-client.ts`)逐行拆帳:
```
POST /triplets/ingestgraph worker 單次 invocation)對 base 的 subrequest
ensurePluginTemplates(3) # 頂層一次
+ listRecordsByTemplate(1) # 抓同 source 現存 active(冪等分組)
+ Σ_triplet [ createTriplet → ensurePluginTemplates(3) + createRecord(1) ] # ★ 每條邊重跑 ensure
+ persistNodes [ ensurePluginTemplates(3) + Σ_node createRecord(1) ]
+ Σ_deprecated updateRecord(1)
= 7 + 4*N_triplets + M_nodes + D_deprecated
```
- **精確炸點還原**07_01 單一 envelope 吞 `N=11, M=10, D=0``7+44+10 = 61 > 50` → 破頂半殘。**放大器=`createTriplet` 內每條邊都重呼 `ensurePluginTemplates`3 個 GET**,佔了 33/61。
- **小批為何解得掉**:把「整檔一 envelope」改成「一卡一 envelope、必要時再 anchor 分段」,把 `N` 壓到讓 `7+4N+M ≤ 40`。notes 三卡實測 est 上限 = 33,全綠。超大卡(自測 20 邊/22 節點=114)→ 自動分 4 段,每段 ≤ 38。
- **附帶建議(非本 Phase 必改)**:graph 端把 `createTriplet`/`persistNodes` 內重複的 `ensurePluginTemplates` 提到 ingest 入口只跑一次,可把每 envelope 省下 `3*(N+1)` 個 subrequest(單卡 est 33→約 18),批量還能更大。此為 graph-plugin 的可選優化,記此存查。
## 冪等設計
| 對象 | 冪等鍵 | 行為 |
|---|---|---|
| **entry** | `page_name`(穩定:`wikicard:<repo>/<canonical>`+ `metadata.content_hash` | 找到同 page_namehash 相同 → skip;不同 → PATCH content(觸發重嵌)。沒有 → POST 新建。 |
| **triplet envelope** | `source.uri` + `source.content_hash` | graph 現役 per-source 冪等:同 hash 整包 no-op`triplet-ingest.ts:65`)。 |
| **分段** | 各段 `source.uri = <基uri>#segNN` | 各段獨立 uri → 各自獨立冪等,**繞開 per-source content_hash 整包 skip**(否則同 uri 第 2 段起會被判定「已落地」而整包跳過)。節點只放進「首次引用它的段」,跨段不重送(避免 graph 重建 entity)。 |
## 觸發(兩階段,對齊 SDD R3)
- **Phase 0(一次性 backfill**`cron */2` 每 tick drain 一張卡(限速慢推),反覆跑到全庫清空。冪等 → 可續傳、重跑零寫入。
- **穩態(日常增量)****Gitea push webhook → arcrun workflow**,只吃 `commits[].{added,modified}` 中的 `system-dev/wiki/cards/**/*.md`。⚠️ Gitea → Cloudflare(arcrun)**非 GitHub Actions**,不觸 GitHub flag 紅線(D4/D20)。量小、不撞頂、不限速。
## 乾跑證據(Phase A,不寫 live
```
node lib/dry-run.mjs --repo-path <notes clone> --repo Leo/notes --self-test
```
`Leo/notes` 的 3 張卡實測:3 entriesembed=true+ 3 envelopes、15 triplets、16 nodes
**單次 graph 呼叫 subrequest 上限 = 33< 50),無任一 envelope 破頂**
self-test 合成超大卡(不分段 est=114 會炸)→ 自動分 4 段、每段 ≤ 38,全綠。
## 待 live 部署 + 寫入(總管過 leo 閘用)
1. **部署通用 `code` 零件**Arcrun#10 分支 `feat/issue-10-code-component`,已就緒):`cd registry/components/code && npm install && npx wrangler deploy`(→ `code.arcrun.dev`)+ `register-component.sh code`。本 workflow 的 parse_card 以 `component: code` 引用它,解析 JS 已內聯在 workflow.yaml(= `lib/card-to-envelope.mjs` 邏輯)。不再部署 domain 零件 `km_wiki_card_parse`
2. **部署 workflow**`km_wiki_ingest_drain`cron drain);`wrangler` 直推 leo21c**禁 `acr update`**——codeload 綁 GitHub 假綠,Arcrun#4)。
3. **注入環境變數**(不放 repo):`repo=Leo/notes ref=main gitea_token kbdb_url=https://arcrun-kbdb.leo21c.workers.dev kbdb_api_key graph_url graph_api_key=leo``CLOUDFLARE_ACCOUNT_ID=leo21c`(別讓官方 58309b 污染)。
4. **entry 寫入路徑確認**:若 `kbdb_upsert_block` 尚不透傳 `metadata_json`(需 `embed:true`/`content_hash`),entry 改用 `http_request` 直打 base `POST/PATCH /entries``body_json.metadata_json`
5. **預期寫入量(Leo/notes 現況 3 卡)**3 entries + 15 triplets + 16 node records(去重後更少);分 3 次 graph 呼叫(每次 ≤ 33 subrequest+ 3 次 entry upsert。全庫鋪開時照 cron 一卡一 tick 慢推。
6. **驗收**ingest 後 `GET /embed/backfill/status` 應見 pending 上升→drain 後歸零、embedded 增加;三模式(關鍵字/語意/圖)curl 驗。