🔴 修教材反向教壞:skill §7 自打臉+補「分支怎麼算成功」+刪 publish 死代碼
端到端 haiku 考 0/3、1/3,**斷點在教材不在引擎**(另一 agent 取證,別重查): 探針零 code 實測 n=10→TRUE、n=1→FALSE 兩次 success;**考生的作品其實會動** (amount=5000→true、amount=100→false 條件求值全對),但它以為跑不通而放棄改寫 code; 考生第二次自己指認「MCP 說明聲稱不支援 ON_TRUE/ON_FALSE,與實際系統行為不符」。 ① skill `write_intent_workflow` **同一份前後打架**(我 08-01 只改了 §2 沒掃全篇): §2.1 教用 ON_TRUE,§7 第 1 條卻把 ON_TRUE 列為「不存在的邊」⇒ 教材自我否定。 改:§7 只留 ON_FAILURE(真的沒有),並明寫「ON_TRUE/ON_FALSE/ON_BRANCH 是存在的, 見 §2.1,本行舊世代已更正」。全篇 grep 過確認無其他矛盾。 ② **補 §2.2「怎麼確認分支真的走對」**——這是「看到對的結果卻以為失敗」的直接解: 看 verdict,且**走 true 路時 false 路節點不出現=正確行為不是失敗**; 附 08-01 實撞案例,明講「只有一條路有輸出」不該判定壞掉。 MCP instructions 同步加這段(比 skill 更前置,AI 一連上就讀到)。 ③ #23 殘留清除(leo 08-01:「已經沒有 publish 了,零件等級一律走 PR,這條路封了」): `git rm mcp/src/tools/arcrun_publish_component.ts`+拔掉 registry.ts 的 import (註冊呼叫本來就已註解掉=純死代碼配活 import)。刪前 grep 全 repo 呼叫方: 除本檔與 registry.ts 外,其餘命中全是 md/SDD 的歷史記載(不需動)。tsc 綠。 替代路徑=`Leo/arcrun-components` fork→PR→人審,已寫進 registry.ts 註解。 SDD: workflow-discovery 3.11|CP: arcrun-usable 步驟 5
This commit is contained in:
@@ -46,6 +46,9 @@ export async function handleMcpRequest(
|
||||
"(配 `switch` 的每個 case/`try_catch` 的 try·catch)。",
|
||||
"🔴 **需要判斷時用分支邊,不要寫 code 判斷**——查零件的回應會附 `branch_hint`",
|
||||
"(哪些邊型+可照抄範例),照著接即可。",
|
||||
"🔴 **分支跑完怎麼判斷成功**:看 `verdict`(`arcrun_get_execution_trace` 或",
|
||||
"`GET /workflows/<name>/executions`)。**走 true 路時 false 路的節點不出現=正確行為**,",
|
||||
"不是失敗——別因為「只有一條路有輸出」就以為壞掉而改寫成 code(2026-08-01 實撞)。",
|
||||
"第一個節點固定是 `input`。",
|
||||
].join("\n");
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { toolName } from "../brand.js";
|
||||
import { z } from "zod";
|
||||
import { Env } from "../types.js";
|
||||
|
||||
/**
|
||||
* arcrun_publish_component — 提交 TinyGo WASM 零件至 Component Registry
|
||||
*
|
||||
* AI 工作流:
|
||||
* 1. 先呼叫 arcrun_get_component_guide 取得開發指引
|
||||
* 2. 依指引用 TinyGo 撰寫零件(stdin/stdout JSON I/O)
|
||||
* 3. 編譯為 .wasm,base64 編碼後提交
|
||||
* 4. Registry 自動執行沙盒驗收(體積、syscall 掃描、Gherkin 測試)
|
||||
*/
|
||||
export function registerPublishComponent(server: McpServer, env: Env, orgNamespace: string) {
|
||||
server.tool(
|
||||
toolName("publish_component"),
|
||||
"提交 TinyGo WASM 零件至 Component Registry。需提供 component.contract.yaml 內容與編譯後的 .wasm base64。提交前請先呼叫 arcrun_get_component_guide 取得開發規範。",
|
||||
{
|
||||
contract: z.object({
|
||||
canonical_id: z.string().describe("零件功能名稱(小寫底線,如 validate_json)"),
|
||||
display_name: z.string().describe("顯示名稱(可自由命名)"),
|
||||
category: z.enum(["logic", "api", "ui", "style", "anim"]).describe("零件分類"),
|
||||
version: z.string().describe("版本(格式 vN,如 v1)"),
|
||||
wasi_target: z.literal("preview1"),
|
||||
stability: z.enum(["floating", "stable", "pinned"]).default("floating"),
|
||||
runtime_compat: z.array(z.string()).describe("相容 runtime,如 [\"cf-workers\",\"wazero\"]"),
|
||||
constraints: z.object({
|
||||
max_size_kb: z.number().default(2048),
|
||||
max_cold_start_ms: z.number().default(50),
|
||||
no_network_syscall: z.boolean().default(true),
|
||||
io_model: z.literal("stdin_stdout_json"),
|
||||
}),
|
||||
input_schema: z.record(z.unknown()).describe("JSON Schema"),
|
||||
output_schema: z.record(z.unknown()).describe("JSON Schema"),
|
||||
gherkin_tests: z.array(z.object({
|
||||
scenario: z.string(),
|
||||
given: z.string().describe("JSON 字串"),
|
||||
then_contains: z.string().describe("預期輸出包含的字串"),
|
||||
})).min(2).describe("至少一個 happy path 和一個 error path"),
|
||||
description: z.string().optional(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
}).describe("component.contract.yaml 內容"),
|
||||
wasm_base64: z.string().describe("編譯後的 .wasm 檔案 base64 編碼"),
|
||||
},
|
||||
async ({ contract, wasm_base64 }) => {
|
||||
try {
|
||||
if (!env.COMPONENT_REGISTRY) {
|
||||
return {
|
||||
content: [{ type: "text", text: "Error: COMPONENT_REGISTRY service binding is not configured." }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
const response = await env.COMPONENT_REGISTRY.fetch("http://component-registry/components", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ contract, wasm_base64 }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
return {
|
||||
content: [{ type: "text", text: `Publish failed: ${errorText}` }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
const result = await response.json() as Record<string, unknown>;
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `零件 ${contract.canonical_id} v${contract.version} 提交成功:\n${JSON.stringify(result, null, 2)}`,
|
||||
}],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { Env } from "../types.js";
|
||||
import { registerSearchComponents } from "./arcrun_search_components.js";
|
||||
import { registerPublishComponent } from "./arcrun_publish_component.js";
|
||||
import { registerSearchWorkflows } from "./arcrun_search_workflows.js";
|
||||
import { registerListComponents } from "./arcrun_list_components.js";
|
||||
import { registerGetComponent } from "./arcrun_get_component.js";
|
||||
@@ -25,10 +24,10 @@ import { registerWhoami } from "./arcrun_whoami.js";
|
||||
export function registerAllTools(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) {
|
||||
registerSearchComponents(server, env, orgNamespace);
|
||||
// 🔴 2026-07-21 leo 拍板停用:零件走 PR、專業等級;recipe/workflow/app 誰都可以做。
|
||||
// 這兩個工具對一般使用者是「誤導危機」——搜不到東西時把人推向「去造零件」,
|
||||
// 那是最難、最該擋的那條路(總管實測:問 foreach 怎麼用,回傳 TinyGo 寫 WASM 教學)。
|
||||
// 想貢獻零件 → 見 Arcrun repo 的 CONTRIBUTING-components.md。
|
||||
// registerPublishComponent(server, env, orgNamespace);
|
||||
// 零件貢獻**只有一條路=PR 人審**(leo 2026-08-01:「已經沒有 publish 了,
|
||||
// 零件等級一律走 PR,這條路封了」;Arcrun#23 已關)。實作路徑已 git rm
|
||||
// (arcrun_publish_component.ts),不留死代碼當錯誤環境信號。
|
||||
// 想貢獻零件 → repo `Leo/arcrun-components` fork→PR→人審,見 CONTRIBUTING-components.md。
|
||||
registerSearchWorkflows(server, env, orgNamespace, partnerToken); // workflow-discovery R2
|
||||
registerListComponents(server, env, orgNamespace);
|
||||
registerGetComponent(server, env, orgNamespace);
|
||||
|
||||
@@ -60,6 +60,25 @@ input >> ON_SUCCESS >> <第一步> >> ... → 丟 /cypher/search → 系統回
|
||||
|
||||
⚠️ 仍然**不要寫 `ON_FAILURE`**(沒有這種邊;要處理失敗用 `try_catch` + `ON_BRANCH(catch)`)。
|
||||
|
||||
### 2.2 怎麼確認分支真的走對了(**別看不懂就以為壞掉**)
|
||||
|
||||
分支工作流「有沒有成功」看兩件事,**不是看某條沒走的路沒有輸出**:
|
||||
|
||||
1. **`verdict`**:`GET /workflows/<name>/executions?limit=1`
|
||||
→ `data.executions[0].verdict === "success"` 就是成功了。
|
||||
2. **`trace` 裡有沒有出現該走的節點**:走 TRUE 路時 FALSE 路的節點**本來就不該出現**
|
||||
——**那是正確行為,不是失敗**。
|
||||
|
||||
```
|
||||
# 條件成立 → 只有 true 那條的節點在 trace
|
||||
{"amount": 5000} → if_control 回 branch="true" → 走 ON_TRUE 那條
|
||||
{"amount": 100} → if_control 回 branch="false" → 走 ON_FALSE 那條
|
||||
```
|
||||
|
||||
🔴 **實撞(2026-08-01 考試)**:有考生的分支工作流**其實完全正常**
|
||||
(`amount=5000`→true、`amount=100`→false 都對),但它以為「跑不通」而放棄改寫成 code。
|
||||
**看到只有一條路有輸出=分支正在正確運作**,不要因此判定失敗。
|
||||
|
||||
## 3. 第一個節點固定是 `input`
|
||||
|
||||
所有真範本都以 `input` 起頭——那是「觸發時帶進來的資料」。
|
||||
@@ -151,7 +170,9 @@ curl -s -X POST https://arcrun-cypher-executor.<subdomain>.workers.dev/cypher/se
|
||||
|
||||
## 7. 常犯的錯
|
||||
|
||||
1. **用不存在的邊**(`ON_FAILURE`/`ON_TRUE`)→ 只有 `ON_SUCCESS` 與 `對每個 X`
|
||||
1. **用不存在的邊**(`ON_FAILURE`)→ 沒有這種邊;要處理失敗用 `try_catch` + `ON_BRANCH(catch)`
|
||||
⚠️ `ON_TRUE`/`ON_FALSE`/`ON_BRANCH` **是存在的**(2026-08-01 起),見 §2.1——
|
||||
本行以前寫「ON_TRUE 不存在」是舊世代,已更正
|
||||
2. **第一個節點不是 `input`**
|
||||
3. **把 recipe 當零件寫**——`telegram_send`/`gmail`/`kbdb_get` 是 **recipe** 不是零件
|
||||
→ 寫成 `http_request` + 該 recipe
|
||||
|
||||
Reference in New Issue
Block a user