Files
Arcrun/system-dev/docs/3-specs/workflow-discovery/tasks.md
T
Leo 47c6aaea03 feat(t152): workers_ai_chat 種子(auth: binding,免金鑰)+ 修 /init/seed 吃掉 3.12 欄位+ 修 D1 LIKE 長查詢 500
SDD: workflow-discovery 3.12/3.13(不是新規格;3.12 已 confirmed 並實作完成)

## 1) workers_ai_chat 種子(新)
Cloudflare Workers AI 走 env.AI binding ⇒ 用戶不必填任何 API 金鑰就能問答。
放種子表而非產品安裝器:「裝好後預設有哪些 recipe」是平台能力(rule 07 薄殼原則)。
換模型/換供應商=改這一筆 recipe,workflow 不動。

選型實測(1.4.4 實例,真實長度 RAG prompt,每個模型連跑 2 次):
  llama-4-scout-17b        2373/2173 ms   答案最完整、引用正確 ← 選它
  llama-3.3-70b-fp8-fast   3261/2147 ms   可用但波動較大
  mistral-small-3.1-24b    3560/3631 ms
  qwen2.5-coder-32b        3572/3353 ms
  gpt-oss-120b             1971/2295 ms   回應形狀不同,response 取不到文字
  gemma-3-12b-it            5018 帳號無權限
對照舊路徑 Gemini gemma-4-31b-it:同型提問 16.87 s,且吐整段英文思考草稿。

## 2) 修 /init/seed 靜默吃掉 3.12 欄位
3.12 給 RecipeDefinition 加了 body_template/response_map/auth/binding_name,
但 /init/seed 是**列舉欄位重建** recipe record ⇒ 不在名單上的欄位被丟掉。
最惡劣的地方是「哪裡都不會紅」:recipe 查得到、endpoint 對,只有跑起來像沒設定過。
與 08-02 syncManifest 吃掉 manifest.daemon 欄同型(教訓:東西還在不在也要進機械閘)。
加 tests/init-seed-recipe-fields.test.ts:拿掉修復會紅、補回會綠(已實測會擋)。

## 3) 修 D1 LIKE pattern 50 bytes 上限造成的 500
/entries/search?q=… 只要 q 超過 48 bytes 就回 HTTP 500,沒有錯誤訊息。
逐 byte 二分:48→200/49→500;中文 16 字→200/17 字→500。
判別實驗:q 固定 48 bytes、其他 filter 全塞滿讓 SQL 變很長 → 仍 200
⇒ 爆的是 LIKE 的 pattern('%'+q+'%' = 50),不是 statement 長度。
中文問句超過 16 字是常態,而 rag_chat 用整句問題當 q ⇒ 聊天對正常問句等於不能用。
(=InkStoneCo status.md 待辦第 1 條「KBDB keyword 長查詢會炸」的根因。)
修法:q ≤ 48 bytes 走原路(行為逐字不變),超過才拆詞/切 UTF-8 邊界片段。
kbdb 全套 83 測全綠(含新增 8 項)。

## 4) 順手
- 移除被 commit 進 repo 的 node_modules 壞 symlink(指向 leo Mac 的絕對路徑,
  害任何 fresh clone 裝不起來、切分支還會把裝好的蓋掉——本次撞了兩次)。
- pending-changes.md 加 P2 提案(fan-out 並行執行)+等裁決,未動引擎。

驗證:cypher-executor 新增測試 17/17 綠;tsc 與基線逐字相同;
全套測試失敗集合與基線**逐字相同**(基線 14 個失敗,本分支 t173 既有,非本次引入)。
2026-08-03 02:56:53 +00:00

234 lines
20 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.
# workflow-discovery — Tasks
> **狀態**:方向待確認,**尚未實作**(全部 `[ ]`)。確認後才動 code。
> 對應 `design.md`。**tasks.md 是唯一進度來源**,每完成一個立刻標 `[x]`,不批次。
> 建立:2026-06-27issue #8
---
## Phase 0:方向確認(前置,擋住所有實作)
- [x] 0.1 SDD 三件式回報到 issue #8 comment,列關鍵決策(方案 C 雙寫 / YAML description 為準 / 提示式回填)
- [x] 0.2 等總管/richblack 點頭;拍板 design §9 的 4 個待決點 — **leo 2026-06-27 全拍定,Q2 翻案(CC 據實生成 vs 介面層不生成)已吸收進 design §3.2**
- [x] 0.3 實作前核實 `/entries/search` 是否支援 `entry_type` filter — **總管查證:不支援(只有 q/owner_id/source/mode),schema 有欄位+索引,要改 4 處(route/searchEntries/semanticSearch/kbdb-proxy),做 base 通用 filter**
---
## Phase 1:強制 descriptionR1,Q2 定案:CC 據實生成、用戶可改)
- [x] 1.1 cypher `POST /webhooks/named``description` 改必填,trim 後空 → 400 + 可操作錯誤訊息(定位:要求操盤 CC 據實寫一句「能做什麼」,非逼用戶手填、非介面層機械塞)— webhooks-named.ts 加驗證,tsc 綠
- [⏸] 1.2/1.3 MCP deploy 改走 /webhooks/named(方向①,leo 拍定)— **卡在 ①-a/b/c 子決策**design §3.1b/c):實作期發現 /webhooks/named 吃 graph 非 YAMLYAML→graph 編排現在寫在 CLI push.ts 介面層;MCP 複製=違 rule 07。等總管定 ①-a(複製)/①-b(編排下沉新 /workflows/deploy 吃 YAMLCLI 也改用)/①-c(先 a 通、b 另開 issue)。**注**:無論哪個,MCP 最終打 /webhooks/named(已強制 description1.1 完成)→ description 強制目標三選項都達成。
- [x] 1.3b(方向①前置,三選項共需)`GET /webhooks/named` 補回 description/created_at/cron_expr 欄位,讓 MCP list 改讀本端點時欄位齊 — webhooks-named.tstsc 綠
- [ ] 1.4 驗證:兩條路徑各跑一次「無 description 部署」→ 都被擋(端到端,非只 tsc)— CLI 路徑已可驗,MCP 待 ①-a/b/c 收
## Phase 2:可搜 entry 雙寫(R2 資料層)
- [x] 2.1 cypher 部署 handlerrecord 寫完後雙寫一個 `entry_type=workflow` entrycontent=description、metadata_json.embed:true、owner_id=apiKey),`waitUntil` 非阻塞 — webhooks-named.ts 加 writeWorkflowSearchEntry helper(注意:KBDB 用 metadata_json 字串非 metadata 物件)。tsc 綠
- [x] 2.2 補 KBDB `/entries/search``entry_type` filterbase 通用,不寫死 workflow)— 改 4 處:searchEntries(entry-crud.ts) + semanticSearch(embed.tsentry_type 已 index) + route(entries.ts) + cypher kbdb-proxy `/kbdb/search` 透傳。kbdb+cypher tsc 綠
- [ ] 2.3 驗證:部署一個帶 description 的 workflow → KBDB 查得到對應 entryowner_id 正確)
## Phase 3search_workflow 工具(R2 介面層)
- [x] 3.1 cypher 新增 `GET /workflows/search?q=&mode=`:轉發 KBDB `/entries/search`(限 entry_type=workflow + 本租戶 owner_id,預設 mode=semantic 自動降級)— webhooks-named.ts。tsc 綠
- [x] 3.2 MCP 新增 `u6u_search_workflows(query)`:呼叫 3.1,格式化結果,透傳 `capability_hint`(AI 看到可主動問用戶開 Vectorize)— 新檔 + registry 註冊。tsc 綠
- [ ] 3.3 驗證 mode=keywordVectorize 未開):LIKE 命中 + 回 capability_hint「叫 CC 幫你開語義查詢」
- [ ] 3.4 驗證 mode=semanticVectorize 開,需 self-hosted leo21c):語意命中,限本租戶
- [ ] 3.5 租戶隔離驗證:A 租戶搜不到 B 租戶的 workflowcount=0
## Phase 4:既有工作流回填(R3)
- [x] 4.1 cypher `POST /workflows/backfill-search-entries`(限本租戶):有 description 的 record → 補寫 entry;無 description 的 → 列出回報,不自動編造 — webhooks-named.tstsc 綠
- [ ] 4.2 backfill 經 CLI/MCP 暴露為主動指令(非 cron,守 C2)
- [ ] 4.3 驗證:對既有 workflow 跑 backfill → 有 desc 的可搜、無 desc 的被正確列出待補
## Phase 5:薄殼對稱補(R2.5,次階段,可獨立驗收)
- [ ] 5.1 CLI `acr workflow search <query>`:對等 MCP 工具(同一 cypher 端點)
- [ ] 5.2 驗證:CLI/MCP 同 query 回同一組結果(底層同端點,差異只來自介面慣例)
## Phase 6:收尾
- [ ] 6.1 tsc 全綠(cypher / mcp / cli / kbdb 受影響者)
- [ ] 6.2 部署 + 端到端實證(leo21c 帳號跑強制填 + 搜尋 + 回填,收客觀證據非自報)
- [ ] 6.3 issue #8 comment 回報端到端綠燈證據;由實證決定結案時機(待端到端綠才 close)
- [ ] 6.4 同步更新 design.md(若實作中發現偏差)+ wiki status
## 3.x 追加(2026-07-31,頂層總管交棒;出處=leo 定義步驟 3 考題)
> leo:「你要找的 Google Slides API 我沒有,你可以自己做。有 2 種:
> 一種是要一個**零件**(如 Crypto)但沒有→用 **PR** 產生;
> 另一種是要一個 **recipe**(如 Google Slides)但沒有→**自己寫 recipe**。」
> 機械考題已在頂層 `arcrun-usable/verify.sh` 03 組(aes_encryptgoogle_slides_create 兩題,
> 現對實例跑全紅=正確標記)。**行為綠過才准佔用 arm 部署**(頂層 mistakes 07-31 條)。
- [x] 3.6 recipe 納入 `/cypher/search` 存在性查詢(現只查零件 registry ⇒ 說不出「某 recipe 沒有」)
— 2026-07-31 search-nodes.tsregistry 落空後查 RECIPES KVresolveRecipe),
recipe found 附 source:'recipe'+description+endpoint;本地實測 telegram_send found ✓
- [x] 3.7 缺件回應分型指路:`suggestion` 欄——計算原語型→「投稿零件 PR」;外部 API 型→「自己寫 recipe」
(欄位契約定案時同步頂層 verify.sh 03 組的 grep
**且每筆要帶「去哪裡看」**leo 07-31 三次定調):component 路→skill `add_new_wasm_component`
(已存在、安裝器現會 seed 進新實例);recipe 路→skill `write_recipe`**不存在,見 3.8**
— 2026-07-31 完成:status 契約定 `not_found`(同 verify.sh 01/03 grep);分型=服務詞/計算詞
簡單規則(不接 LLM,規則在 code 註解);附 similar_components/similar_recipes 相近候選
(自然語言「判斷有沒有新資料」媒合到 if_control)。順手修二病灶:①頭節點被 resolveNodeRole
判 Input 而免查(`aes_encrypt >> … >> code` 假 found)→ 只有字面 input/output 名才短路;
② registry 查詢層把 KV 裡的 input_schema 丟掉 → 補透傳。本地 wrangler dev 跑頂層
verify.sh 0103 組 9/9 全綠(部署後要對真實例重驗)
- [x] 3.8 寫 `write_recipe` skillregistry/skills/)——「怎麼寫 recipe」的 playbook 目前是空地,
3.7 的 recipe 指路沒有目的地;寫完納入安裝器 seed 清單(compile-skills.mjs 自動收)
— 2026-07-31 完成:內容從真 code 反推(RecipeDefinition schemaapi-recipe-seeds 的
telegram_send+gmail_send 真範例/auth-recipes 必填欄位/acr recipe push 打通檢查),
比照 write_intent_workflow 風格;INDEX.mdwrite_intent_workflow.md 同步指路 not_found
- 設計基調(leo 07-31 二次定調):**回覆的重點是「缺哪些」不是「有哪些」**——
有的照常編圖不必報告;缺的要兩庫(零件+recipe)都搜過後點名+給正確指示。
驗收兩層:機械(verify 01/03)綠 → haiku 真考(只讀回覆就能說出缺什麼、該做什麼)。
## 3.9 追加(2026-07-31 深夜,t158 後續;leo 定調 export/import 原語)
> leo:「你要做的就是一個叫 export,另一個是 import,打包好的幾個工作流準備好直接
> import 就好了。現在如果我要把我做的工作流分享給同事,我要怎麼 export?他要如何
> import?是缺了功能用 search 來湊嗎?在從前就是寫成幾個 yaml 丟過去讓新的送進
> KBDB 不是嗎?」+「絕對不能違背原來的堅持(不能違規)」。
- [x] 3.9a `GET /webhooks/named/:name/definition`export 引擎端):吐 workflow record
原樣(graphconfigdescription)——與既有 list 同認證(X-Arcrun-API-Key)、
同租戶 key 前綴,**零新資料模型**。062757f 已入 staging bundle 試點。
KBDB 牆自證:讀的是 WEBHOOKS KVworkflow 記錄),不碰 KBDB。
- [ ] 3.9b `acr workflow export/import` CLI 接線(命令已寫 cli/commands/workflow.ts
**未接進 index.ts**——D35 ③:新命令面屬規格層,已走 pending-changes 提案,
confirm 後才接)。importgraph 直 POST /webhooks/named(既有部署端點,
零編圖零 search);手寫 yaml 指去 acr push。
- [ ] 3.9c 安裝器同一條路驗證:workflows.json 打包期預編 graph+純上傳(rag-installer
5a6539d 已上 prod)——安裝器不走私有路徑的機械檢查(copy-contract 級)留此收。
- [x] 3.10 意圖節點→真實零件/recipe 替換(CP arcrun-usable **步驟 4**;頂層交棒 t159
— 2026-07-31 search-nodes.ts `trySubstitution`discover 混搜兩庫 exact 落空後,
在 t158「一次抓好的兩庫清單」**記憶體內**媒合(零新增 round-trip)。兩條保守規則
(不接 LLM,規則在 code 註解):A 服務詞→recipe(名字裡全部服務詞命中同一 recipe
且唯一才換;「google_slides_create」不會被 google_sheets 誤吃);B 強欄位斷詞→零件
canonical/display/aliases 強命中×10description/tags 弱命中,需至少一強命中且
分數唯一最高;「aes_encrypt」無強命中不換)。換到=status `resolved``substitution`
欄(from/componentId/recipe/reason),cypher 圖節點直接帶真實 componentId、不列
missing;換不到照舊 not_found3.7 指路+候選。**只動 discover**——compile(部署/
推送複製路徑)零替換零查詢(t158 邊界不動)。
驗(本地 wrangler devregistry 種 20 合約+/init/seed 10 recipe):
「判斷有沒有新資料 >> ON_SUCCESS >> 傳到 telegram」→ if_controlresolved)+
telegram_sendresolvedsubstitution.componentId=http_request)=feature 06 驗法過;
機械考 27/27 全綠(01 組 503 組 4 迴歸+06 組 8target 8compile 迴歸 2);
冷啟第一發 94ms、熱 8–13mst158 病史對照:舊 25.7s
- [x] 3.10 `/cypher/search``target` 指定搜尋對象(leo 07-31:「難道我不能指定要搜尋
工作流或節點或 recipe 嗎?」)— componentrecipeworkflow
tripletstarget=component|recipe=只查該庫;querytarget=名字搜尋,各走**既有**
機制不新造(component→registry /components/searchMCP arcrun_search_components
同一條路;recipe→私庫 RECIPES KV 同 discover 第二庫讀法,回應註明公庫走
arcrun_recipe_searchworkflow→新抽 lib/workflow-search.tsGET /workflows/search
與 target=workflow 共用同一 KBDB 轉發=MCP arcrun_search_workflows 同一條路)。
防呆:mode=compiletarget → 400target=workflow 吃 query 不吃 triplets400 指路);
非法 target → 400。已知缺口如實透傳:workflow 無 description 搜不到(capability_hint
照舊),補救仍走 /workflows/backfill-search-entries。
MCP 三分型工具盤點:search_componentssearch_workflowsrecipe_search 均註冊活著;
前兩者與 target 走同一條路;recipe_search 搜公庫 vs target=recipe 搜私庫=語料不同
是設計(installed vs marketplace),回應互相指路,非行為漂移
---
## 3.y 追加(2026-08-01leo confirm 兩缺口進 SDD;服務 CP `arcrun-usable` 步驟 5
> **D35 處置(鐵律④ 判斷結果:不開新 SDD、不換 active、不搬移 paused 任務)**
>
> leo 2026-08-01 confirm 頂層 `pending-changes.md` 07-30 兩段(缺口①引擎條件邊/
> 缺口② recipe payload 與回應處理層)。處置理由逐條:
>
> 1. **不開新 SDD**——鐵律②「CC 在任何情況下不得主動建新 SDD」。confirm 的是
> 「規格層 proposal」,鐵律④只規定「**開新 SDD 時**」的搬移程序,並未要求每個
> confirm 都必開新 SDD。本案能落進現行 active 就不該增生第三本。
> 2. **不把 active 交給 arcrun-core-mvprecipe-system**——兩本 paused 的未完成任務
> core-mvp 14 筆=credential 注入/auth-workermulti-tenant KVanalytics
> recipe-system 10 筆=prompt_recipe 的 MCP tool 與 mira wiki 端到端)
> **與本次兩缺口零交集**。升任一本為 active 就得先收掉 workflow-discovery16 筆
> 未完成、正在服務 CP 步驟 3/4),等於為了掛兩筆新任務把進行中的鏈打斷。
> 3. **落在 workflow-discovery=任務層變更(鐵律②第二類)**——CP `arcrun-usable`
> 步驟 3→4→5 是**同一條有序鏈**,步驟 3(誠實查詢)、步驟 4(節點替換)的任務
> 本來就掛在本 SDD 的 3.x;步驟 5 是同鏈的下一步,且**改的是同一顆 worker**
> cypher-executor)。掛同一本=與既有 3.6–3.10 同源,不是新方向。
> 4. **兩本 paused 維持 paused、未完成任務原地不動**——沒有被取代、沒有被繼承,
> 故不填 `superseded_by`、不移入 archive/。pending-changes 原提案標的
> (缺口①→arcrun-core-mvp、缺口②→recipe-system)僅為「議題歸屬」描述,
> 非活性歸屬;實作歸屬依鐵律①走現行 active。
>
> **作廢任務清單:無**(本次不作廢任何既有任務)。
> **搬移任務清單:無**(不換 active,故無跨 SDD 搬移;新增下列 3.11–3.13)。
- [x] 3.11 **缺口①:引擎通用具名分支邊**(=Arcrun#5 根治;CP 步驟 5 交付物之一)
✅ 08-01 本地綠(commit `323ccc8`):`ON_TRUE``ON_FALSE``ON_BRANCH` 三邊型+
`readBranch()` 四層相容讀法(data.branch → branch → data.result → result)。
**做成通用具名分支,非布林特例**leo 08-01「你改了 if,有改 switch 嗎?switch 更嚴重」)——
三顆流程控制零件的 output_schema 本來就都收斂到 `data.branch: string`
if_control→true/falseswitch→case 名/default_branchtry_catch→try/catch
⇒ 引擎只需一個機制,不留「做完 if 還要為 switch 再改一次」的債。
ON_TRUE/ON_FALSE=布林路語法糖,測試已證與 ON_BRANCH branch="true" 等價。
**分支用法查得到**leo 08-01 n8n 式逐顆查):新增 `lib/branch-hints.ts`
三顆零件的查詢回應自帶 `branch_hint`branch_field/branches/edge_types/usage/example),
四條回應路徑全 wirecatalog foundlegacy 逐顆/步驟4 substitutiontarget=component)。
測試 `tests/conditional-edges.test.ts` 16 項全綠;零變化:現存 workflow 用到新邊型=0 筆。
〔原始描述〕
現況:`if_control` 只回 `{result, branch}``cypher-executor/src` grep
`ON_TRUE|ON_FALSE`0,圖的邊只有 `ON_SUCCESS``IF`FOREACH ⇒ AI 照規矩用
`if_control` 也還是得寫 code 判斷該走哪條路 ⇒「全變成 code」的根。
要做:`EdgeType``ON_TRUE``ON_FALSE``graph-executor` 走邊邏輯依上游
`branch` 選路。**引擎核心、風險最高:先寫測試再改**;既有 4 支官方 workflow
行為必須零變化(跑一次證明)。
- [x] 3.12 **缺口②:recipe payload 與回應處理層**CP 步驟 5 交付物之二、之三)
✅ 08-01 本地綠(commit `5f5c0a8`):新增 `lib/recipe-payload.ts`
`renderBodyTemplate` 遞迴插值+保留型別+dot path;`applyResponseMap` 取值路徑/
thinking_model 剔除 thoughtanswer_marker 用 lastIndexOfstrip_prefixes 循環剝殼),
`RecipeDefinition` 加四個**全選填**欄位 body_templateresponse_mapauthbinding_name
`component-loader``makeBindingRecipeRunner``pickRecipeRunner`auth='binding'
走平台 binding=免金鑰、開機即可用;一次打開 env.AI/VECTORIZE/BROWSER/QUEUE 整排)。
**payload 用法查得到**`buildPayloadHint()` wire 進三條 recipe 回應路徑
(守 D36:只說「金鑰由系統注入、你不必也不該填」,不吐值)。
測試 `tests/recipe-payload-response.test.ts` 14 項全綠(含 Gemini/Claude/Workers AI
三家形狀各用不同 path 都取得出文字=換源=換 recipe 的實證)。
相容:未設新欄位的既有 recipe 行為完全不變(有測試守)。
〔原始描述〕
現況 schema 只有 `{canonical_id, endpoint, method, auth_service, headers, body}`
⇒ 帶 body 的 API 只能繞過 recipe 把整包寫進 workflow code;回應解析
`finalize` 2786 字元)綁死 Gemini 格式。
要補三層:`body_template`payload 模板+變數插值)/`response_map`(回應正規化:
取值路徑・思考型模型旗標・淨化規則)/`auth` 第四型 `binding`(免金鑰,
一次打開 `env.AI``VECTORIZE``BROWSER``QUEUE`)。
**相容硬要求**:既有 recipe(無新欄位)行為完全不變。
- [◐] 3.13 **驗收=CP 步驟 5 考試(features/07**
◐ 08-03t152**3.13「真正的改寫」那半落地**):`rag_chat``ask_llm`
「整包 Gemini 細節寫在 workflow 節點」改成 `component: workers_ai_chat`(一個 recipe 名 一個 prompt),
`finalize`**2786 字元縮到 12 行**(回應解讀搬進 recipe 的 `response_map`)。
本 repo 側配套:`api-recipe-seeds.ts` 新增 `workers_ai_chat` 種子(`auth: binding`
3.12 第四型認證的第一個真實案例)+修掉 `/init/seed` **列舉式重建吃掉 3.12 四個欄位**的洞
(種子帶了 body_template/response_map/auth 卻進不了 KV,且哪裡都不會紅——與 08-02
`syncManifest` 吃掉 `manifest.daemon` 同型)。回歸閘 `tests/init-seed-recipe-fields.test.ts`
3 項,**拿掉修復會紅、補回會綠**(實測過會擋)。
實例端到端(1.4.4 youlin 帳號,**零 API 金鑰**):問答鏈全綠、有答案有出處。
選型實測見種子檔註解(llama-4-scout 2.2s vs Gemini gemma-4-31b **16.87s**)。
⚠️ 仍 ◐ 未 ✅:haiku 場景(缺件時只寫 recipe 就補全、零 JS)=features/09 stage 端到端未驗。
◐ 08-01:本地驗收綠(`tests/step5-acceptance.test.ts` 3 項),實跑輸出=
**舊寫法 1201 字元 / if×8 → 新寫法 350 字元 / if×0(下降 71%**
且分流工作流 `success=true`、零 code 節點。
⚠️ **誠實標記**:線上那顆 `assemble`5509 字元、if×23)住在 arcrun-rag 實例,
本 repo 無其定義 ⇒ 本次是把它的**判斷骨架**以新能力重建成等價工作流證明
「判斷不必寫在 JS 裡」,**不是**直接改寫線上節點。
真正的改寫與 haiku 場景(逐顆查、只寫 recipe 補全、零 JS)=**stage 端到端**
features/09),未驗前不得標 ✅。
〔原始描述〕:拿現行 `assemble` 節點
(5509 字元、if×23)用新能力重寫 → code 大幅下降且仍 `verdict=success`
貼改寫前後字元數與實跑輸出。另附 haiku 場景:缺件時只寫 recipe 就補全、零 JS。
---
## 跨任務鐵律提醒
- 強制填 / 搜尋 / 回填全是**能力 → 落 API**CLI/MCP 只暴露(rule 07)。
- **不假綠**:未開 Vectorize 就老實降級 + hint,不假裝語義(mindset §7)。
- **不自動編造 description**:強制是逼真的描述,自動填 = 假裝有(誠實)。
- **flag 紅線**search/backfill 都是主動 pull,無 cron/輪詢/fan-outC2)。
- 框架級改動 → 端到端實證(leo21c)才算完成,不是 tsc 綠就宣布。