feat(ingest): 機械式 wiki 卡片→KBDB ingest(Arcrun#8 Phase A,dry-run 驗證)

新 ingest 模型(無 LLM,取代舊 raw→Haiku 路):
- 來源 = system-dev/wiki/cards/**/*.md(精耕卡)+ ## 實體/## 關聯 typed-edge + [[wikilink]]
- 卡片→base entry(metadata.embed=true);typed-edge/wikilink→graph triplet
- 純機械決定性,零 token

形式 = Arcrun workflow(cron drain + Gitea webhook delta)+ 新自訂零件 km_wiki_card_parse

不撞頂設計:一卡一 tick + 超大卡以 source_uri anchor 自動分段;
graph fan-out 精確 = 7+4N+M+D,dry-run 對 notes 三卡上限 33 subrequest(<50)。

Phase A:不部署、不寫 live。含純核心 + dry-run 證據(3 entries/15 triplets/16 nodes)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
This commit is contained in:
Arcrun CC
2026-07-06 03:52:50 +00:00
parent ed2e42e007
commit cc494a250e
7 changed files with 599 additions and 0 deletions
@@ -0,0 +1,65 @@
# 提案:新自訂 arcrun 零件 km_wiki_card_parse 的契約(Phase A 提案,尚未部署)。
# 定位:機械把「已精耕 wiki 卡片」解析成 base entry + graph triplet envelope(無 LLM、無 fs/網路)。
# 完全符合 arcrun 元件形狀(stdin_stdout_json、no_network_syscall、no_filesystem_syscall)。
# 參考實作:lib/card-to-envelope.mjs(決定性純函式;部署時移植成 Go/WASM 或以 workerd JS 元件承載)。
canonical_id: "km_wiki_card_parse"
display_name: "KM Wiki 卡片機械解析"
category: "transform"
version: "v1"
wasi_target: "preview1"
stability: "floating"
runtime_compat:
- "cf-workers"
- "workerd"
- "wazero"
constraints:
max_size_kb: 2048
max_cold_start_ms: 50
no_network_syscall: true # 純轉換,不打網路
no_filesystem_syscall: true # 卡片全文由上游 http_request 餵入,不讀檔
io_model: "stdin_stdout_json"
input_schema:
type: object
required: [content, rel_path]
properties:
content:
type: string
description: 卡片 Markdown 全文(上游 http_request 從 Gitea raw 抓)。
rel_path:
type: string
description: 卡片相對 repo 根的路徑(如 system-dev/wiki/cards/notes/Xxx.md)。
repo:
type: string
description: 來源 repo(如 Leo/notes),組 source.uri / page_name 用。預設 Leo/notes。
budget:
type: number
description: 單 envelope subrequest 目標上限(預設 40CF 硬頂 50)。超過則自動 anchor 分段。
commit:
type: string
description: git commit sha(可追溯,寫進 source.commit)。選填。
output_schema:
type: object
properties:
entry:
type: object
description: 卡片→base entry。含 page_name(冪等鍵)、entry_type、content、tags、metadata(embed=true, source, content_hash)。
envelopes:
type: array
description: >
卡片→graph triplet envelope 陣列(已分段、已符合 ingest-candidate.json 契約)。
每個 envelope 附 _estSubrequestsplanner 保證每段 ≤ budget。無邊的卡回空陣列。
meta:
type: object
description: canonical / title / content_hash 等追溯資訊。
gherkin_tests:
- scenario: "typed-edge 卡片"
given: '{"content":"## 實體\n- **A** — a\n- **B** — b\n## 關聯\n### 內文知識關係\n- A >> 關係 >> B","rel_path":"system-dev/wiki/cards/notes/t.md"}'
then_contains: '"subject":"A"'
- scenario: "embed 打標"
given: '{"content":"# t\n## 實體\n- **A** — a\n## 關聯\n### 內文知識關係\n- A >> r >> A","rel_path":"x/t.md"}'
then_contains: '"embed":true'
tags: [transform, wiki, ingest, mechanical, kbdb, primitive]
description: |
取代 kbdb-ingest-plugin 舊 raw→Haiku 路的機械版:讀「已精耕卡」的 ## 實體(節點)、
## 關聯 的 typed-edgeA >> 關係 >> B)與 [[wikilink]],直接映射 entry + triplet,零 LLM、零 token。
自動以 source_uri anchor 分段,保證每個 graph /triplets/ingest 呼叫壓在 CF subrequest 上限下。