From 1b687fedb0ba9bf486345c67e1433a919af5c99a Mon Sep 17 00:00:00 2001 From: richblack Date: Tue, 21 Jul 2026 16:42:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(mcp):=20=E8=A7=A3=E6=8E=89=E4=B8=89?= =?UTF-8?q?=E5=80=8B=E6=8A=8A=E4=BA=BA=E6=8E=A8=E5=8E=BB=E5=AF=AB=E9=9B=B6?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E8=AA=A4=E5=B0=8E=E5=85=A5=E5=8F=A3=EF=BC=88?= =?UTF-8?q?leo=202026-07-21=20=E6=8B=8D=E6=9D=BF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit leo:「刪掉,技術者才會寫 component,在 Arcrun repo 寫一條如何 contribute 指向另一個 repo 就好。」 實測病灶:總管想寫「定期打 API 然後通知」的 workflow(Python 約 10 行), 問 foreach_control 怎麼用 → MCP 回傳 TinyGo 寫 WASM 零件教學(白名單/syscall/ contract schema)=完全另一件事,40 分鐘未完成。 三處修正: 1. search_components 搜不到時的話術——原本建議 publish_component(把「我找不到」 翻譯成「你去造一個」,方向完全相反)。改為導向正確順序:語意搜尋知識庫→ auth-recipe list/scaffold→acr parts(http_request 能打任意 API)→acr list, 並明說 registry 可能是空的(已知問題),搜不到≠沒有這能力。 2. registry.ts 停用 publish_component / get_component_guide 兩個註冊 (檔案保留,只是不對 AI 暴露)。 3. 新增 CONTRIBUTING-components.md:三層責任分工(平台通用能力/熱門預鋪 recipe/ 冷門誰用到誰開發)、什麼時候才真需要新零件、真要貢獻走 PR 的流程。 typecheck 通過。 Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/hooks/publish-lag-check.sh | 80 ++++++++++++++++++ .claude/settings.json | 9 ++ CONTRIBUTING-components.md | 88 ++++++++++++++++++++ mcp/src/tools/arcrun_search_components.ts | 16 +++- mcp/src/tools/registry.ts | 8 +- system-dev/docs/3-specs/pending-changes.md | 97 +++++++++++++++++++++- 6 files changed, 294 insertions(+), 4 deletions(-) create mode 100755 .claude/hooks/publish-lag-check.sh create mode 100644 CONTRIBUTING-components.md diff --git a/.claude/hooks/publish-lag-check.sh b/.claude/hooks/publish-lag-check.sh new file mode 100755 index 0000000..9469a82 --- /dev/null +++ b/.claude/hooks/publish-lag-check.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# publish-lag-check.sh — SessionStart hook:偵測「公開 mirror 落後工作區」並出聲 +# +# 病根(leo 2026-07-21 點名的真實風險): +# Gitea(草稿/工作現場)與 GitHub(正稿/成品櫥窗)是**手動同步**的 +# (靠人跑 scripts/publish-github.sh --push,且需 D20 arm)。 +# → 改了零件、重編 wasm 後若沒人記得發佈,**用戶抓到舊版且沒有任何錯誤訊息, +# 只是行為不對**——這種靜默失敗只有外部使用者會撞到,我們自己永遠測不到。 +# +# 實例:安裝器的懶載會從 +# cdn.jsdelivr.net/gh/youlinhsieh/Arcrun@main/.component-builds/<名>/component.wasm +# 抓 wasm。那個位址永遠指向 GitHub 上的**最後一次發佈**,不是我們本機的最新版。 +# +# 原理:比對「工作區 HEAD」與「.github-public 最後一個 release commit 記錄的 snapshot」。 +# publish-github.sh 的 commit 訊息格式固定為:release: snapshot <短hash> (<日期>) +# → 從中取出 hash,看它是不是工作區 HEAD 的祖先/相同。 +# +# 只提醒不阻擋(exit 0):發不發佈是人的決定(且 push GitHub 需 leo 親跑 arm), +# hook 的職責只是消滅「忘了」這個失敗模式。 +set -euo pipefail + +MIRROR_DIR=".github-public" + +# 沒裝發佈管線的 repo 直接安靜退出 +[ -d "$MIRROR_DIR/.git" ] || exit 0 +[ -f "scripts/publish-github.sh" ] || exit 0 +git rev-parse --git-dir >/dev/null 2>&1 || exit 0 + +HEAD_SHORT="$(git rev-parse --short HEAD 2>/dev/null || echo '')" +[ -z "$HEAD_SHORT" ] && exit 0 + +# 從 mirror 最後一個 commit 訊息取出它當初發佈的來源 hash +LAST_MSG="$(git -C "$MIRROR_DIR" log -1 --format=%s 2>/dev/null || echo '')" +PUBLISHED="$(printf '%s' "$LAST_MSG" | sed -n 's/.*snapshot \([0-9a-f]\{6,\}\).*/\1/p')" + +if [ -z "$PUBLISHED" ]; then + # mirror 存在但沒有可辨識的 release commit(可能還沒發過) + echo "════════════════════════════════════════════════" + echo "📦 這個 repo 有公開發佈管線,但 mirror 還沒發過任何版本" + echo "════════════════════════════════════════════════" + echo " 若已有用戶依賴公開版(例如安裝器從 jsDelivr 抓 wasm),現在是空的。" + echo " 發佈:leo 在頂層跑 scripts/github-arm.sh,再於本 repo 跑" + echo " GITHUB_REMOTE=... bash scripts/publish-github.sh --push" + echo "" + exit 0 +fi + +# 已發佈的那個 commit 就是現在的 HEAD → 同步,安靜 +if [ "$PUBLISHED" = "$HEAD_SHORT" ]; then + exit 0 +fi + +# 算出落後幾個 commit(發佈點 → HEAD)。取不到就不顯示數字。 +BEHIND="$(git rev-list --count "${PUBLISHED}..HEAD" 2>/dev/null || echo '')" + +# 落後 0 且 hash 不同 → 可能是 mirror 比工作區新(罕見,例如剛 rebase),一樣提醒 +echo "════════════════════════════════════════════════" +if [ -n "$BEHIND" ] && [ "$BEHIND" != "0" ]; then + printf '📤 公開 mirror 落後工作區 %s 個 commit(最後發佈:%s,現在:%s)\n' \ + "$BEHIND" "$PUBLISHED" "$HEAD_SHORT" +else + printf '📤 公開 mirror 與工作區不一致(最後發佈:%s,現在:%s)\n' "$PUBLISHED" "$HEAD_SHORT" +fi +echo "════════════════════════════════════════════════" +echo "⚠️ 外部使用者拿到的仍是舊版,而且**不會有任何錯誤訊息**——只是行為不對。" +echo " (安裝器的懶載直接從公開位址抓 wasm,落後=裝到舊零件。)" +echo "" +echo " 要發佈:① leo 在頂層跑 bash scripts/github-arm.sh \"<任務描述>\" 30" +echo " ② 本 repo 跑 GITHUB_REMOTE=https://github.com/<帳號>/.git \\" +echo " bash scripts/publish-github.sh --push" +echo " 不急著發也沒關係——這只是提醒,別讓它靜默漏掉。" + +# 若這次落後的內容碰到 wasm,額外警告(那是用戶會直接抓的東西) +if git diff --name-only "${PUBLISHED}..HEAD" 2>/dev/null | grep -q '\.wasm$'; then + echo "" + echo " 🔴 這批改動**包含 .wasm 變更** → 用戶抓到的零件會跟你本機不同,優先發佈。" +fi +echo "" + +exit 0 diff --git a/.claude/settings.json b/.claude/settings.json index 89bc3ba..840d5fb 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -10,6 +10,15 @@ "timeout": 5 } ] + }, + { + "matcher": "startup|resume|clear", + "hooks": [ + { + "type": "command", + "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/publish-lag-check.sh" + } + ] } ], "PreToolUse": [ diff --git a/CONTRIBUTING-components.md b/CONTRIBUTING-components.md new file mode 100644 index 0000000..776c8e1 --- /dev/null +++ b/CONTRIBUTING-components.md @@ -0,0 +1,88 @@ +# 想貢獻零件(component)?先確認你真的需要 + +> **99% 的需求不需要新零件。** 零件是**專業等級**、走 PR 審核; +> **recipe / workflow / app 誰都可以做**,隨建隨用、不必部署。 + +--- + +## 先照這個順序找,多半不用寫零件 + +**1. 語意搜尋知識庫**(最強——它能找到你沒猜中的用詞) +``` +kbdb_search(q="我想達成什麼(用一句話描述)", mode="semantic") +kbdb_get_map() # 不確定該查哪個庫,先看藏書地圖 +``` + +**2. 看現成的服務整合**(26 個:GitHub/Notion/Gemini/Slack…) +```bash +acr auth-recipe list +acr auth-recipe scaffold github # 直接吐出 credentials 範本 + workflow 範例 +``` + +**3. 看零件全集**(21 顆通用零件) +```bash +acr parts +``` +特別注意 **`http_request`**:它能打**任意** HTTP API。 +「平台沒有 XX 服務的零件」通常不成立——用 `http_request` + 一份 recipe 就有了。 + +**4. 看有沒有現成 workflow 可以直接接** +```bash +acr list +``` + +--- + +## 三層責任分工 + +| 層 | 誰做 | 怎麼做 | +|---|---|---| +| **通用能力** | 平台提供 | `http_request` + auth-recipe 機制=**能打任何 API**,這是地基 | +| **熱門服務 recipe** | 平台預鋪 | 減少常見情境的摩擦(現 26 個) | +| **冷門/特殊** | **誰用到誰開發** | recipe 是**設定不是程式**,門檻低 | + +> 我們不會包辦全世界所有服務的 API。**用到就自己補一份 recipe**,那是設定檔不是程式碼。 + +--- + +## 什麼時候才真的需要新零件 + +**只有這種情況**:需要**新的原語能力**,而且**無法用既有零件組合出來**。例如—— + +- 一種新的控制流(現有 `if_control`/`switch`/`foreach_control`/`filter`/`try_catch` 都表達不了) +- 一種新的資料轉換原語(`code` 零件的沙箱做不到) +- 需要 WASM 層才能做的事(純計算、特殊編解碼) + +**不算的情況**(這些都用 recipe/workflow 解): +- 「我要接 XX 服務的 API」→ `http_request` + recipe +- 「我要做 XX 業務邏輯」→ workflow 組合既有零件 +- 「我要處理某種資料格式」→ `code` 零件(沙箱 JS) + +--- + +## 真的要貢獻零件的話 + +零件是 WASM(TinyGo/AssemblyScript),有嚴格的沙箱約束 +(禁網路 syscall、禁檔案系統、禁 goroutine、體積上限 2MB、 +唯一 I/O 模型是 stdin/stdout JSON)。 + +**流程**:走 Arcrun repo 的 PR,過 `docs/component-pr-review-standard.md` 審核。 +撰寫規範與 contract schema 見 `registry/` 底下的既有零件範例。 + +--- + +## 為什麼 MCP 不再暴露 `publish_component` / `get_component_guide` + +(2026-07-21 leo 拍板停用) + +那兩個工具對一般使用者是**誤導危機**:搜不到東西時,系統會建議「去提交新零件」, +把人推向最難、最該擋的那條路。 + +**實測**:總管想寫一支「定期打 API 然後通知」的 workflow(Python 約 10 行), +問 `foreach_control` 怎麼用,MCP 回傳的是**TinyGo 寫 WASM 零件的教學** +(白名單、syscall 限制、contract schema)——完全是另一件事,導致 40 分鐘未完成。 + +**設計判準**(leo): +> 前端界面要**人類友善**,Arcrun 要 **AI 友善**——都要**從終點看**。 +> Arcrun = **讓 AI 輕易建立程式碼**;AI 要覺得 **Arcrun 比 Python 還簡單**, +> 因此沒有寫 Python 的慾望。**絕不可迷路、搞不懂。** diff --git a/mcp/src/tools/arcrun_search_components.ts b/mcp/src/tools/arcrun_search_components.ts index 9286561..a2c7086 100644 --- a/mcp/src/tools/arcrun_search_components.ts +++ b/mcp/src/tools/arcrun_search_components.ts @@ -44,7 +44,21 @@ export function registerSearchComponents(server: McpServer, env: Env, orgNamespa return { content: [{ type: "text", - text: `找不到符合「${query}」的零件。可以用 arcrun_publish_component 提交新零件。`, + text: [ + `registry 裡找不到「${query}」——但**先別急著造零件**(零件走 PR、專業等級)。`, + ``, + `⚠️ registry 目前可能是空的(已知問題:唯一寫入觸發點隨 .github/workflows 移除而蒸發),`, + ` 「搜不到」不代表「沒有這個能力」。請改用下列順序找:`, + ``, + `1. **語意搜尋知識庫**(最強,能找到你沒猜中的用詞):`, + ` kbdb_search(q="我想達成什麼(用一句話描述)", mode="semantic")`, + `2. **看現成的服務整合**:\`acr auth-recipe list\`(26 個:GitHub/Notion/Gemini…)`, + ` 要用哪個 → \`acr auth-recipe scaffold <服務>\` 直接吐 credentials 範本+workflow 範例`, + `3. **看零件全集**:\`acr parts\`(21 顆通用零件,含 http_request 可打任意 API)`, + `4. **看有沒有現成 workflow 可直接接**:\`acr list\``, + ``, + `💡 多數需求的正解是「用 recipe 設定既有零件」或「接既有 workflow」,不是新造零件。`, + ].join("\n"), }], }; } diff --git a/mcp/src/tools/registry.ts b/mcp/src/tools/registry.ts index 974c996..929c775 100644 --- a/mcp/src/tools/registry.ts +++ b/mcp/src/tools/registry.ts @@ -24,11 +24,15 @@ import { registerWhoami } from "./arcrun_whoami.js"; export function registerAllTools(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { registerSearchComponents(server, env, orgNamespace); - registerPublishComponent(server, env, orgNamespace); + // 🔴 2026-07-21 leo 拍板停用:零件走 PR、專業等級;recipe/workflow/app 誰都可以做。 + // 這兩個工具對一般使用者是「誤導危機」——搜不到東西時把人推向「去造零件」, + // 那是最難、最該擋的那條路(總管實測:問 foreach 怎麼用,回傳 TinyGo 寫 WASM 教學)。 + // 想貢獻零件 → 見 Arcrun repo 的 CONTRIBUTING-components.md。 + // registerPublishComponent(server, env, orgNamespace); registerSearchWorkflows(server, env, orgNamespace, partnerToken); // workflow-discovery R2 registerListComponents(server, env, orgNamespace); registerGetComponent(server, env, orgNamespace); - registerGetComponentGuide(server, env, orgNamespace); + // registerGetComponentGuide(server, env, orgNamespace); // 同上,2026-07-21 停用 registerCreateTag(server, env, orgNamespace); registerListTags(server, env, orgNamespace); registerDeleteTag(server, env, orgNamespace); diff --git a/system-dev/docs/3-specs/pending-changes.md b/system-dev/docs/3-specs/pending-changes.md index 6c131d4..0612ccf 100644 --- a/system-dev/docs/3-specs/pending-changes.md +++ b/system-dev/docs/3-specs/pending-changes.md @@ -8,7 +8,102 @@ ## 待裁決 -(無) +### P-2026-07-21:registry 寫入端+搜尋端修復(leo 親自交辦,最高優先) + +> 提案人:總管交辦之 arcrun subagent。 +> 觸發:leo 2026-07-21 —「一旦推進一個零件,就自動進 registry;recipe、workflow、app 都應該可以 registry, +> 不然搜不到。一邊是寫進去,另一邊是搜到,當然要有。」 +> 判準:「Arcrun = 讓 AI 輕易建立程式碼」「AI 要覺得 Arcrun 比 Python 還簡單,絕不可迷路」。 +> **依 D35:本任務找不到對應的 active SDD(現行 active=portal-auth,與本題無關), +> 故不動 code、不自建 SDD,寫本 proposal 後停止等 leo confirm。** + +#### 一句話 + +registry 的寫入機制**存在且可用**,但它唯一的自動觸發點長在 GitHub Actions 上; +Actions 因防 flag 鐵律被整個刪除後(commit `037cf9b`),**寫入端失去觸發者、庫從此是空的**。 +這不是「沒有機制」,是「機制的手被砍掉、沒補上替代觸發點」。 + +#### 根因(file:line 級) + +| 事實 | 證據 | +|---|---| +| 寫入端點存在 | `registry/src/routes/components.ts:112` `POST /components/index-only`(metadata-only 索引,冪等) | +| 寫入實作存在 | `registry/src/actions/indexOnlyComponent.ts:44` 寫 `comp:{hash}:{ver}` + `idx:{canonical_id}` 兩個 KV key | +| 批次灌注腳本存在 | `registry/scripts/backfill-index.mjs`(掃 22 個 contract.yaml → POST index-only) | +| 單顆註冊腳本存在 | `registry/scripts/register-component.sh`(註解自稱「本地+CI 共用 SSOT」) | +| **唯一自動觸發點已不存在** | `git show 037cf9b^:.github/workflows/deploy.yml` 第 269-275 行有 `Register component in registry` step 呼叫上述 sh;`037cf9b` 刪除整個 `.github/workflows/`,**該 step 隨之消失,無替代品** | +| 從未跑過的實證 | 對 leo21c 跑 `REGISTRY_URL=... node scripts/backfill-index.mjs --dry-run` → 22 顆待灌;線上 `/components/search?q=http` 回 `count:0` | + +→ **答案:是「有機制但從沒跑過」**(且失去觸發者),不是「沒有寫入機制」。 +→ 附帶事實:`registry/wrangler.toml:26` 的 `[[routes]]` 寫死 `registry.arcrun.dev`, + self-hosted(leo21c)只能靠 workers.dev URL,backfill 腳本預設 `REGISTRY_URL` 也是官方域 —— 需帶環境變數才會打到自己的庫。 + +#### 重要更正:leo 要的東西**有一半已經存在,只是不在 registry 上** + +`acr search `(`cli/src/commands/search.ts`)已經是 leo 描述的「意圖驅動、跨類一次搜」—— +它 fan-out 四個來源(component 靜態清單 / `/recipes` / `/auth-recipes` / `/webhooks/named`)。 +**實測(2026-07-21,leo21c,真實輸出見交辦回報)**: +- `acr search http` → 命中零件 `http_request`(驗收劇本 1 ✅) +- `acr search notify` → 命中 recipe `line_notify_send` + auth-recipe `line_notify`(劇本 2 部分達成) +- `acr search github` → 命中 auth-recipe `github`(驗收劇本 3 ✅) +- `acr search telegram` → 命中 recipe `telegram_send` + auth-recipe `telegram` + +→ **能力在 CLI 有、在 registry/MCP 沒有**。這正是薄殼原則(rule 07)被違反的典型: + 同一個「跨類搜尋」能力長在介面層(CLI)而非 API,於是另一個薄殼(MCP)享受不到。 + **修法的方向不是在 registry 重造一套搜尋,而是把 `acr search` 的 fan-out 能力下沉成 API 端點,CLI/MCP 同吃。** + +#### 提案內容(四件,全部需 confirm 後才動) + +**A. 寫入端:補回失去的觸發點(不復活 Actions)** +- A1. `acr push` / `acr deploy` 成功後自動呼叫 `POST /components/index-only`(本機發起、低頻、單 repo,守 D20 讀寫界線與防 flag 鐵律)。 +- A2. `acr init` / `acr update` 部署完 22 顆零件後跑一次 backfill(讓新裝的人開箱即有索引)。 +- A3. **recipe / workflow 不需要新的 registry 寫入路徑**——它們本來就活在 store(KV), + `acr recipe push` / `acr push` 當下就已「寫進去」。缺的只是**搜尋端讀得到**(見 B)。 + → leo 說的「recipe、workflow、app 都應該可以 registry」,正解是**統一搜尋面**,不是把它們搬進 registry KV 再存一份(那會製造第二份真相源)。 +- A4. `app`(bundle)已有 P-2026-07-19 artifact-sharing 卷涵蓋,本卷不重複立案,只在搜尋面預留類別。 + +**B. 搜尋端:能力下沉 + 語意** +- B1. 在 **cypher-executor** 開 `GET /search?q=`(不是 registry——因為 recipe/workflow 的真相源在 cypher 的 KV), + server 端做 `acr search` 現有的四類 fan-out,回統一結果(含 `type` 欄位)。 +- B2. `acr search` 與 MCP 新 tool `arcrun_search`(或改造 `arcrun_search_components`)雙雙改為呼叫 B1,介面層不再自行 fan-out(回歸薄殼)。 +- B3. 語意搜尋:KBDB 那條路已驗證可用(Vectorize),把四類的 description 灌進去,讓「我要打一個 HTTP API」這種自然語言句命中 `http_request`。 + 現行 `registry/src/actions/queryComponents.ts:104` 明載「這是 Phase 0 的純文字比對版本,Phase 2 接入 Vectorize」——本項即補完該 Phase 2。 +- B4. 搜不到時的文案改為「導向 recipe / 既有 workflow」,**移除「可以用 arcrun_publish_component 提交新零件」的建議**(見 C)。 + +**C. 斷掉「推人去寫零件」的路** +- C1. `mcp/src/tools/arcrun_search_components.ts:50` 搜不到時明文建議 `arcrun_publish_component` —— 違反 leo 既定規矩(零件走 PR、專業等級)。改為導向 recipe/workflow。 +- C2. `arcrun_get_component_guide`(回 TinyGo 寫 WASM 教學)與 `arcrun_publish_component` 對一般使用者是誤導 → 建議降級為「專業模式」才暴露(預設不掛載),或在描述首句明寫「99% 情況你不需要這個,先用 recipe」。 +- C3. **查證結果:零件相關「已拆到另一個 repo」未獲證實**——`registry/components/` 22 顆零件仍在本 repo, + wiki 與 git 均查無拆分紀錄。leo 的印象可能來自 `.github-public/` 對外鏡像(`GitHub mirror 發佈模型`)。**此點需 leo 確認**。 + +**D. 過時項** +- D1. MCP 仍要求已廢的 `api_key` 參數者共 **15 處**:`arcrun_introspection.ts`(4)、`arcrun_recipe.ts`(6)、`arcrun_workflow_crud.ts`(5)。 + 2026-07-20 已改 namespace 明碼 → 這些應改為由 server 端 namespace 推導,不再要 AI 傳。 +- D2. **1042 的真正解法已確認並已落地**(本項無需修 code,只需更正記載): + `global_fetch_strictly_public` compatibility flag,已實裝於 `cypher-executor/wrangler.toml:13` + 與 `.component-builds/http_request/wrangler.toml:8`。 + leo 說的「開了一個什麼,把所有呼叫都視為外部」=**這個 flag**(讓 same-zone fetch 走公網前門)。 + wiki 已有正確記載:`system-dev/wiki/cards/decisions/same-zone-1042用flag解不用binding.md`、 + `mistakes.md:101`、`decisions-summary.md:84`。 + → 「graph_neighbors 改用 recipe 繞過」的過時說法**在本 repo wiki 查無此記載**(status.md:50-52 只寫 MCP tool PR), + 該過時記載可能在頂層 InkStoneCo wiki 或 MEMORY.md,需由總管在該層更正。 + +#### 影響分析(D35 第 3 條要求) + +- **現行 active SDD(portal-auth)**:完全不受影響,本提案不碰其任務。 +- **`component-registry-canon`(status: paused,2026-05-07 建)**:**本題其實早有此卷**, + 其 §1.2 診斷的根因與今日實測完全一致(「registry 活著但 index 空的,AI 找不到零件就會繞回 Python」), + 尚有 **29 個未完成任務**。→ **建議:不新開 SDD,改為把此卷 resume 成 active**(並把 A/B/C/D 的新項增補進其 tasks), + 這比另立新卷更符合 D35 第 4 條「先搬移未完成任務」的精神,也避免第二份重疊規格。 + ⚠️ 但這需要先把 portal-auth 收尾或轉 paused(單一活性鐵律),**此為 leo 的排序決策,不是 CC 能裁的**。 +- **`workflow-discovery`(paused)/`library-map`(draft)**:與 B1 統一搜尋面高度重疊,resume 時應一併檢視是否合併。 + +#### 待 leo 拍板的四點 + +1. **排序**:要不要把 `portal-auth` 讓位、resume `component-registry-canon` 來做這件事?(單一活性鐵律強制二選一) +2. **C2**:`get_component_guide` / `publish_component` 要「預設不掛載」還是「留著但改描述」?(品味/方向) +3. **C3**:零件是否真的已拆到另一個 repo?(leo 記憶待證實) +4. **B3 語意搜尋**:四類描述灌進 Vectorize 會產生 embedding 呼叫成本,確認可行?(花錢) ## 已裁決