# workflow-discovery — Tasks

> **狀態**：方向待確認，**尚未實作**（全部 `[ ]`）。確認後才動 code。
> 對應 `design.md`。**tasks.md 是唯一進度來源**，每完成一個立刻標 `[x]`，不批次。
> 建立：2026-06-27（issue #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：強制 description（R1，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 非 YAML，YAML→graph 編排現在寫在 CLI push.ts 介面層；MCP 複製＝違 rule 07。等總管定 ①-a（複製）/①-b（編排下沉新 /workflows/deploy 吃 YAML，CLI 也改用）/①-c（先 a 通、b 另開 issue）。**注**：無論哪個，MCP 最終打 /webhooks/named（已強制 description，1.1 完成）→ description 強制目標三選項都達成。
- [x] 1.3b（方向①前置，三選項共需）`GET /webhooks/named` 補回 description/created_at/cron_expr 欄位，讓 MCP list 改讀本端點時欄位齊 — webhooks-named.ts，tsc 綠
- [ ] 1.4 驗證：兩條路徑各跑一次「無 description 部署」→ 都被擋（端到端，非只 tsc）— CLI 路徑已可驗，MCP 待 ①-a/b/c 收

## Phase 2：可搜 entry 雙寫（R2 資料層）

- [x] 2.1 cypher 部署 handler：record 寫完後雙寫一個 `entry_type=workflow` entry（content=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` filter（base 通用，不寫死 workflow）— 改 4 處：searchEntries(entry-crud.ts) + semanticSearch(embed.ts，entry_type 已 index) + route(entries.ts) + cypher kbdb-proxy `/kbdb/search` 透傳。kbdb+cypher tsc 綠
- [ ] 2.3 驗證：部署一個帶 description 的 workflow → KBDB 查得到對應 entry（owner_id 正確）

## Phase 3：search_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=keyword（Vectorize 未開）：LIKE 命中 + 回 capability_hint「叫 CC 幫你開語義查詢」
- [ ] 3.4 驗證 mode=semantic（Vectorize 開，需 self-hosted leo21c）：語意命中，限本租戶
- [ ] 3.5 租戶隔離驗證：A 租戶搜不到 B 租戶的 workflow（count=0）

## Phase 4：既有工作流回填（R3）

- [x] 4.1 cypher `POST /workflows/backfill-search-entries`（限本租戶）：有 description 的 record → 補寫 entry；無 description 的 → 列出回報，不自動編造 — webhooks-named.ts，tsc 綠
- [ ] 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_encrypt／google_slides_create 兩題，
> 現對實例跑全紅＝正確標記）。**行為綠過才准佔用 arm 部署**（頂層 mistakes 07-31 條）。

- [x] 3.6 recipe 納入 `/cypher/search` 存在性查詢（現只查零件 registry ⇒ 說不出「某 recipe 沒有」）
      — 2026-07-31 search-nodes.ts：registry 落空後查 RECIPES KV（resolveRecipe），
      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 01＋03 組 9/9 全綠（部署後要對真實例重驗）
- [x] 3.8 寫 `write_recipe` skill（registry/skills/）——「怎麼寫 recipe」的 playbook 目前是空地，
      3.7 的 recipe 指路沒有目的地；寫完納入安裝器 seed 清單（compile-skills.mjs 自動收）
      — 2026-07-31 完成：內容從真 code 反推（RecipeDefinition schema／api-recipe-seeds 的
      telegram_send+gmail_send 真範例／auth-recipes 必填欄位／acr recipe push 打通檢查），
      比照 write_intent_workflow 風格；INDEX.md＋write_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
      原樣（graph＋config＋description）——與既有 list 同認證（X-Arcrun-API-Key）、
      同租戶 key 前綴，**零新資料模型**。062757f 已入 staging bundle 試點。
      KBDB 牆自證：讀的是 WEBHOOKS KV（workflow 記錄），不碰 KBDB。
- [ ] 3.9b `acr workflow export/import` CLI 接線（命令已寫 cli/commands/workflow.ts，
      **未接進 index.ts**——D35 ③：新命令面屬規格層，已走 pending-changes 提案，
      confirm 後才接）。import＝graph 直 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 強命中×10＋description/tags 弱命中，需至少一強命中且
      分數唯一最高；「aes_encrypt」無強命中不換）。換到＝status `resolved`＋`substitution`
      欄（from/componentId/recipe/reason），cypher 圖節點直接帶真實 componentId、不列
      missing；換不到照舊 not_found＋3.7 指路＋候選。**只動 discover**——compile（部署/
      推送複製路徑）零替換零查詢（t158 邊界不動）。
      驗（本地 wrangler dev，registry 種 20 合約＋/init/seed 10 recipe）：
      「判斷有沒有新資料 >> ON_SUCCESS >> 傳到 telegram」→ if_control（resolved）＋
      telegram_send（resolved，substitution.componentId=http_request）＝feature 06 驗法過；
      機械考 27/27 全綠（01 組 5＋03 組 4 迴歸＋06 組 8＋target 8＋compile 迴歸 2）；
      冷啟第一發 94ms、熱 8–13ms（t158 病史對照：舊 25.7s）
- [x] 3.10 `/cypher/search` 加 `target` 指定搜尋對象（leo 07-31：「難道我不能指定要搜尋
      工作流或節點或 recipe 嗎？」）— component／recipe／workflow：
      triplets＋target=component|recipe＝只查該庫；query＋target＝名字搜尋，各走**既有**
      機制不新造（component→registry /components/search＝MCP arcrun_search_components
      同一條路；recipe→私庫 RECIPES KV 同 discover 第二庫讀法，回應註明公庫走
      arcrun_recipe_search；workflow→新抽 lib/workflow-search.ts，GET /workflows/search
      與 target=workflow 共用同一 KBDB 轉發＝MCP arcrun_search_workflows 同一條路）。
      防呆：mode=compile＋target → 400；target=workflow 吃 query 不吃 triplets（400 指路）；
      非法 target → 400。已知缺口如實透傳：workflow 無 description 搜不到（capability_hint
      照舊），補救仍走 /workflows/backfill-search-entries。
      MCP 三分型工具盤點：search_components／search_workflows／recipe_search 均註冊活著；
      前兩者與 target 走同一條路；recipe_search 搜公庫 vs target=recipe 搜私庫＝語料不同
      是設計（installed vs marketplace），回應互相指路，非行為漂移

- [x] 3.11 `acr install-harness` 交付內容升級到現世代（CP arcrun-usable **步驟 1** 最後一筆；
      頂層交棒）— **管道本來就好的，過時的是內容**：`cli/harness/skills/arcrun-mindset/SKILL.md`
      （4066B）grep「意圖」「>>」＝**0 命中**，只講世界觀／別寫 Python，
      新裝封測者拿不到步驟 1 的核心教材（`>>` 意圖語法）。
      - **單一真相源**：harness skill 改為**建置期由 `registry/skills/write_intent_workflow.md`
        複製**（`cli/scripts/build-harness-skill.mjs`，head＋registry 正文＋tail 三段拼接）。
        選建置期複製而非 symlink／npm 引用：npm `files` 只收 `harness/`，registry 不進套件；
        symlink 在 npm pack 與 Windows 不可靠。產物 commit 進 repo（npm 裝的是產物，不跑 build）。
        head/tail 為 harness 專屬（CLI 語境入口／`acr` 指令表／暴露同意／誠實鐵律），
        `install-harness` 的 `copyTree` 跳過 `.head`／`.tail` 不鋪給用戶。
      - **其餘三件同步升級**：`CLAUDE.block.md`（補 `>>` 意圖語法＋`not_found` 兩條路＋
        零件 vs recipe 分型＋腹語術紅線＋金鑰只拿名字）；`commands/arcrun.md`（步驟改成
        「先寫意圖→丟去查→再寫 YAML」，補 `acr search`／`acr validate`）；
        `hooks/arcrun-guard.sh`（**正路提示改為指向 arcrun-mindset Skill ＋意圖語法**，
        呼應「hook 沒提 skill 反而把 AI 導向 repo 文件」的教訓；新增 code 節點腹語術提醒，
        settings.fragment 補 `Write|Edit|MultiEdit` matcher）。
      - **世代閘**（防再度脫節）：`cli/scripts/check-harness-generation.mjs` 檢查四件交付物的
        現世代指紋（`>>`／`ON_SUCCESS`／`對每個`／`not_found`／腹語術／`arcrun-mindset`），
        缺指紋 exit 1；掛進 `npm run build`（故 `prepublishOnly` 也擋）。
        反向驗證：把 skill／CLAUDE.block 換回上一代 → 兩者都被擋下並逐條點名缺哪個指紋。
      - **驗收**（考生 haiku／受測物＝環境）：乾淨臨時目錄跑 `acr install-harness`
        → 四件鋪好、重跑冪等（全檔 md5 不變、CLAUDE.md 66 行不變、hooks 條目 2 不變、
        arcrun 區塊仍 1 個）；haiku 只讀該目錄的 CLAUDE.md＋SKILL.md（明令禁讀 ~/.claude、
        禁上網；兩份教材 md5 與大小均不同可證非考本機那支）答十題
        → `grade-step1.sh` **10 / 10 通過**（判分器同時反向驗證仍會抓 ON_TRUE／ON_FAILURE／
        第一節點非 input）

---

## 3.y 追加（2026-08-01，leo 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-mvp／recipe-system**——兩本 paused 的未完成任務
>    （core-mvp 14 筆＝credential 注入／auth-worker／multi-tenant KV／analytics；
>    recipe-system 10 筆＝prompt_recipe 的 MCP tool 與 mira wiki 端到端）
>    **與本次兩缺口零交集**。升任一本為 active 就得先收掉 workflow-discovery（16 筆
>    未完成、正在服務 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/false；switch→case 名/default_branch；try_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），
      四條回應路徑全 wire（catalog found／legacy 逐顆／步驟4 substitution／target=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 剔除 thought／answer_marker 用 lastIndexOf／strip_prefixes 循環剝殼），
      `RecipeDefinition` 加四個**全選填**欄位 body_template／response_map／auth／binding_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-03（t152，**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-out（C2）。
- 框架級改動 → 端到端實證（leo21c）才算完成，不是 tsc 綠就宣布。
