boardx / boardx/workspacex

tools/skills 可用性覆盖矩阵与缺口(实测 SHA 12b39e0cd)

Open
#3,301 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
0
Forks
0
Avg merge
1h 7m
Merged PRs (30d)
969

Description

> 实测 SHA:`12b39e0cd37e09a4f3c47875619eb1264a51b371`(`origin/main`,2026-09-10 08:25:23 +0800)
> 本 issue 只做**清单与缺口盘点**,不含实现修复。

## 0. 为什么需要这份清单

用户验收第二维要求「测试所有的 tools 和 skills 都可以工作」。盘点前,本仓回答不出
「一共有多少个 tool / 多少个 skill、哪些从来没在真实链路上被执行过」。
本仓在工具名这件事上已有前科(#3160 `web_fetch`、#3186 `write_todos`、#3159 `spawn_async_task`),
所以本清单一律从**实际注册/派发处**取数,不取注释与文档。

## 1. 权威清单:工具

工具有**两个执行档**,名字全集 = 两者并集。

### 1.1 原生执行档(`KERNEL_NATIVE_RUNTIME=1`,DevApp 生产路径)—— 45 个

唯一事实源:`apps/api/src/application/agent-run/native-invocation.ts` 的 `NATIVE_PROFILE_TOOLS`,
由 `apps/api/scripts/generate-native-profile-tools.ts` 生成到
`apps/deep-agent-service/src/deep_agent_service/generated/native_profile_tools.json`。

复现:
```bash
python3 -c "import json;print(len(json.load(open('apps/deep-agent-service/src/deep_agent_service/generated/native_profile_tools.json'))['tools']))"
# 45
```

### 1.2 旧 deepagents 图(`graph.py`,无 native key 时的默认档)—— 6 个

`apps/deep-agent-service/src/deep_agent_service/tools.py`:
`list_org_skills`(:215)、`call_skill`(:226)、`confirm_task_intent`(:267)、
`fill_run_params`(:294)、`choose_execution_option`(:329)、`spawn_async_task`(:359)。

复现(注意不能用 `grep -c "@tool"`,会把 docstring 里的两处也数进去 ⇒ 8):
```bash
python3 -c "import re;s=open('apps/deep-agent-service/src/deep_agent_service/tools.py').read();print(len(re.findall(r'@tool\s*(?:\([^)]*\)\s*)?\n\s*def\s+([a-z_][a-z0-9_]*)\s*\(',s)))"
# 6
```

### 1.3 合计

- 两档并集 **47 个**静态工具名(4 个交叠:`confirm_task_intent` / `fill_run_params` / `choose_execution_option` / `spawn_async_task`)。
- 第三档 `text-only` 图注册 **0** 个工具(`graph_selector.py:36`,`create_agent(model=_model, tools=[])`)。
- **另有动态工具**:`pg-native-session-owner.ts:37` 把 MCP snapshot 里的每个工具都并进准入表并**一律置 `interruptOn=true`**。所以运行时工具总数 = 47 + N(组织已接入的 MCP 工具),N 不可从仓库静态枚举。

## 2. 权威清单:Skill —— 内建 21 个

运行时播种入口:`apps/api/src/main.ts:212` → `ensurePlatformSkillCatalogSeeded()`
(`apps/api/src/infrastructure/skill/ensure-platform-skill-catalog.ts:286`)。
迁移 `20260827200000_platform_owned_skills.sql` 只加 RLS 策略,**不插数据**。

**A. 平台官方 Office skill —— 4 个**(`apps/api/src/domain/skill/platform-skill-catalog.ts:27-30`):
`pptx-create` / `docx-create` / `xlsx-create` / `pdf-create`
```bash
grep -c 'skillId: "skill-platform-' apps/api/src/domain/skill/platform-skill-catalog.ts # 4
```

**B. 标准 starter pack —— 9 包 / 17 skill**(`apps/api/src/infrastructure/skill/ensure-standard-skill-packs.ts:10-20`):
`web-research`, `web-artifact`, `data-analysis`, `data-visualization`, `interview-synthesis`,
`user-research-planning`, `maau-canvas`, `knowledge-grounded-answer`, `meeting-preparation`,
`internal-communications`, `project-status-report`, `diagram-and-canvas`, `document-understanding`,
`skill-authoring`, `visual-content`, `audio-transcription`, `meeting-minutes`
```bash
grep -c "packId:'" apps/api/src/infrastructure/skill/ensure-standard-skill-packs.ts # 9
find skills -name SKILL.md | wc -l # 17
```

**C. 组织/用户自建 skill**:动态,仓库内无可枚举清单。

⚠ `.agents/skills/*` 是 Claude Code 开发 harness 的 skill,**不是产品 skill**,不计入。
## 3. 缺口矩阵:工具

判据(严格):
- **① 有真实执行证据**:存在一条**会红**且**当前真的在 CI 里跑**的断言,证明该工具在真实图/真实沙箱/真实库上被派发并成功返回。
- **② 只有 mock/单测**:有单测、schema 断言、stub transport、或有真实证据但**被 skip / 被 env gate / 无任何 CI job 调用**。
- **③ 零覆盖**:只在定义/注册/生成物里出现,无任何行为断言。

### 45 个原生工具

| 档 | 数量 | 名单 |
|---|---|---|
| ① | **27** | `wx_artifact_download`, `wx_run_status`, `wx_run_cancel`, `confirm_task_intent`, `fill_run_params`, `choose_execution_option`, `read_file`, `task`, `write_todos`, `wx_memory_search`, `wx_memory_write`, `wx_memory_delete`, `wx_project_list`, `wx_project_read`, `wx_knowledge_search`, `wx_knowledge_read`, `wx_canvas_read`, `wx_canvas_update`, `wx_document_parse`, `sql_db_list_tables`, `sql_db_schema`, `sql_db_query_checker`, `sql_db_query`, `wx_schedule_create`, `wx_schedule_list`, `wx_schedule_cancel`, `spawn_async_task` |
| ② | **18** | `browser_navigate`, `browser_snapshot`, `browser_click`, `browser_fill_form`, `browser_take_screenshot`, `ls`, `write_file`, `edit_file`, `delete`, `glob`, `grep`, `execute`, `wx_artifact_publish`, `web_search`, `fetch_url`, `wx_skill_create_draft`, `wx_image_generate`, `wx_audio_transcribe` |
| ③ | **0** | —(每个名字至少有 `apps/deep-agent-service/tests/test_native_tool_dispatch.py` 的 `MockTransport` 派发测试兜底,所以没有真正的零覆盖) |

### 2 个仅存于旧图的工具

`call_skill` / `list_org_skills` → **②**。`apps/deep-agent-service/tests/test_harness.py:277-310, 928-929`
用的是**脚本化假模型**加本地定义的同名工具桩:编译图是真的,模型和技能执行器是替身。

### ② 档为什么是 ②:四个成组的原因(每组都是「有证据但不会跑」)

1. **真实浏览器套件全 skip** —— `playwright-mcp-browser-real.test.ts:39-44`
`const suite = enabled ? describe : describe.skip`(`WORKSPACEX_REAL_BROWSER === '1'`)。
只有 `pnpm test:browser-real` 会设它,**`.github/workflows/` 里没有任何 job 跑它**。
这是 5 个 browser 工具唯一接触真实 Chromium 的地方。
2. **真实沙箱文件/执行套件在 CI 里静默 skip** —— `native_sandbox_fixture.py:42-44` 在
缺 `WX_NATIVE_SANDBOX_CONTAINER` 时 `pytest.skip`;而 `deep-agent-tests.yml:63` 跑整个
pytest 套件时**不设这个变量** ⇒ `test_native_file_tools.py`(ls/write_file/edit_file/glob/grep/delete/execute)
全部静默跳过。native-runtime-lane job 虽然设了容器,却只跑 `test_native_skill_activity.py`
(`backend-gates.yml:326-328`)——**`read_file` 是 ① 而它的 7 个兄弟是 ②,差别仅在于此**。
3. **`native-full-chain.test.ts` 没有任何 CI job 调用** —— 它被 `vitest.config.ts:20` 排除,
有自己的 `vitest.native-chain.config.ts`,但没有 job 跑 `test:native-chain`。
它是 `wx_skill_create_draft` / `wx_image_generate` / `wx_audio_transcribe`
以及 `web_search` / `fetch_url` / `wx_artifact_publish` **真实派发**的唯一证据来源。
(它在缺容器时 `throw` 而非 skip,写法是诚实的——只是从来没被执行。)
4. **`*-real-model.live.ts` 全靠 `workflow_dispatch`** —— 见下一节。

### 一处 fixme
`apps/web/e2e/chat-path-c8-subtask-artifact-writeback.spec.ts:162` 是 `test.fixme(...)`,
`:50` 自述「not covered」。
## 4. Skill 侧执行证据

21 个内建 skill **每一个**都能 grep 到测试文件命中,但按「是否存在一条会红的断言」筛完之后结论翻转:

- 真实模型执行证据集中在 `apps/api/tests/agent-runtime/*-real-model.{cases,live}.ts`,由 13 个专用 vitest config 驱动。
- **13 个 config 里只有 2 个被任何 workflow 引用**(`vitest.asr-real-model.config.ts` → `s016-asr-real-evidence.yml`;`vitest.document-skills-real-model.config.ts` → `office-editing-real-model-evidence.yml`)。
- 这 5 条 real-model workflow **全部是 `workflow_dispatch`**,没有 `pull_request` / `push` / `schedule`。即:**没有任何 skill 的真实执行断言会在 PR 上变红**。
- 另外 11 个 config **既不在 CI 里、也没有 package.json script**(只有 `test:browser-skill-real-model` 与 `test:asr-real-model` 两个 script)。它们在仓库里的全部引用是 `docs/design/standard-capabilities/evidence/**` 下的**历史输出文本**——那是一次性快照,不是会再次执行的断言。

复现:
```bash
ls apps/api/vitest.*real-model*.config.ts | wc -l # 13
grep -rn "real-model" .github/workflows/ | grep -o "vitest\.[a-z-]*real-model[a-z-]*\.config\.ts" | sort -u # 2
grep -n "real-model" apps/api/package.json # 2 个 script
for w in s013-real-model-evidence s016-asr-real-evidence real-model-chat-evidence office-editing-real-model-evidence; do grep -n "workflow_dispatch\|pull_request\|push:" .github/workflows/$w.yml; done
```

**结论:21 个内建 skill 全部落在第 ② 档(有 mock/单测 + 有一次性人工真实证据,但无自动会红的端到端断言)。第 ① 档 = 0。**
## 5. 盘点中新发现的缺口(本次新增,尚无 issue)

### 5.1 45 个真实工具里有 22 个**从未登记进风险分级表**,静默落入默认 L2

`classifyToolRisk`(`apps/api/src/domain/agent-run/tool-risk-tier.ts`)三档白名单共登记 25 个名字,
其中 2 个(`call_skill`/`list_org_skills`)属于旧图。而
`nativeInterruptOn()`(`native-invocation.ts:22-24`)逐名调用它算 `interruptOn`:

```ts
return Object.fromEntries(NATIVE_PROFILE_TOOLS.map(name => [name, classifyToolRisk(name) === "L2"]));
```

结果:**45 个原生工具里 28 个 `interruptOn=true`**,其中 22 个只是因为「没人登记过」而按兜底 L2 处理:

`choose_execution_option, confirm_task_intent, delete, fill_run_params, spawn_async_task,
sql_db_list_tables, sql_db_query, sql_db_query_checker, sql_db_schema, task, web_search,
wx_artifact_publish, wx_audio_transcribe, wx_canvas_update, wx_document_parse, wx_image_generate,
wx_memory_delete, wx_memory_write, wx_schedule_cancel, wx_schedule_create, wx_schedule_list,
wx_skill_create_draft`

其中 `sql_db_list_tables` / `sql_db_schema` / `sql_db_query_checker` / `wx_schedule_list` / `web_search`
按性质是只读的,却每次调用都弹审批——这正是 #3160(`fetch_url`)与 #3186(`write_todos`)的**同一个形状**,
只是这次是 22 个而不是 1 个。

复现:
```bash
python3 - <<'EOF'
import json,re
tools=set(json.load(open('apps/deep-agent-service/src/deep_agent_service/generated/native_profile_tools.json'))['tools'])
src=open('apps/api/src/domain/agent-run/tool-risk-tier.ts').read()
b=lambda n:set(re.findall(r'"([^"]+)"',re.search(n+r'[^=]*=\s*new Set\(\[(.*?)\]\)',src,re.S).group(1)))
listed=b('L0_READ_ONLY_TOOLS')|b('L1_REVERSIBLE_WRITE_TOOLS')|b('L2_HIGH_RISK_TOOLS')
print(len(tools-listed), sorted(tools-listed))
EOF
```

### 5.2 门控只看一个方向,所以 5.1 永远不会红

`apps/api/tests/agent-run/tool-risk-tier-names-are-real.test.ts` 只有:
- **A**:白名单里的名字必须真实存在(死名字 → 红)
- **B**:注释点名的必须在集合里
- 一条针对 `fetch_url`/`write_todos` 的两工具回归钉

**没有反向断言**:「`NATIVE_PROFILE_TOOLS` 里的每个名字都必须被显式登记在某一档」。
所以新加一个工具而忘了分级,不会有任何东西变红——它只会安静地开始要求人工审批。
这是 5.1 得以存在 22 次的机制原因。

### 5.3 原生执行档的 CI 覆盖只到 provision,不到工具

`backend-gates.yml:268-293` 的 native-runtime job(#3052 补的)确实设了 `KERNEL_NATIVE_RUNTIME=1`,
但它只跑两件事:`vitest.native-runtime-lane.config.ts`(include 只有
`tests/agent-runtime/native-runtime-lane.test.ts`,测 pins → 真实沙箱会话)与
`pytest tests/test_native_skill_activity.py`。**45 个工具本身没有一个在这条车道上被逐个执行。**

⚠ 顺带更正一处**过期的静态痕迹**:`docs/reports/2026-09-08-chat-37-path-acceptance-report.md:182`
写「没有任何车道开 `KERNEL_NATIVE_RUNTIME=1`」,在本 SHA 上已不成立(#3052 已补)。
## 6. 三个已知 issue 的复核(按本 SHA 的代码,不按 issue 状态)

三个 issue **在 GitHub 上都还 OPEN**,但代码复核结论不同——这正是「静态痕迹 ≠ 动态事实」。

### #3084 非 `call_skill` 的 L2 工具中断没有审批入口 → **已修复,建议关闭**

- 引擎侧本就与工具名无关:`native_factory.py:157-161` 用整张 `resolved['interruptOn']` 策略图。
- 审批 API 不特判 `call_skill`:`decide-tool-permission.ts:70-78` 只分「permissionRequestId 是否新鲜」和「是否属于三个表单型 interrupt」。
- UI 已通用:`restored-run-approval.tsx:147-186` 对任意非表单待批工具渲染 `ToolPermissionCard`;`copilotkit-v2-panel-body.tsx:1144-1149,1640` 在实时路径上也只看 `status === "awaiting_tool_permission"`,无工具名条件。
- 有对应回归断言:`apps/web/tests/ui/workbench-restored-approval.test.tsx:112-121`,用 `wx_canvas_update` 断言「非 `call_skill` 的 L2 工具也渲染审批卡」。

### #572 MCP 8 条契约操作零 controller/零 UI/零断言 → **部分修复,标题已不准确**

契约在 `packages/contracts/src/agent-runtime.ts:1214-1552`。逐条:

| 操作 | controller | UI | 断言 |
|---|---|---|---|
| `registerMcpServer` POST `/mcp-servers` | ❌ | ❌(`mcp-screen.tsx:32,356` 明写「仍未接线」) | 仅 schema |
| `discoverMcpTools` POST `/mcp-servers/:id/discover` | ❌ | ❌ | ❌ |
| `setAuthScope` PUT `/mcp-servers/:id/auth-scope` | ❌ | ❌ | ❌ |
| `setToolAuthScope` PUT `/mcp-tools/:name/auth-scope` | ❌ | ❌ | ❌ |
| `authorizeToolCall` POST `/tool-calls/authorize` | ❌ | ❌ | ❌ |
| `listMcpTools` GET `/mcp-tools` | ❌ | ❌ | 仅 schema |
| `reviewMcpServer` POST `/mcp-servers/:id/review` | ✅ `mcp-execution-snapshot.controller.ts:12` | ❌ | ✅ 真库 |
| `reIsolateMcpServer` POST `/mcp-servers/:id/isolate` | ✅ 同上 `:20` | ❌ | ✅ 真库含 403 |
| `listMcpServers` GET `/mcp-servers` | ✅ `mcp-servers.controller.ts:21` | ✅ `mcp-screen.tsx:15` | ✅ |

另有契约外新接的 `discoverRemoteMcpTools`(controller + UI + test 齐全)。
**仍为零 controller / 零 UI 的是 5 条**(register / discover / setAuthScope / setToolAuthScope / authorizeToolCall)。
建议把 #572 标题与正文按此收窄,而不是继续挂着「8 条全零」。
(另:`agent-capability-graph.tsx:14` still 写着 `listMcpServers` 「零后端实现」,是过期注释。)

### #3020 能力 ID + 实现来源 + 耗时的 trace → **部分修复**

- **能力 ID + 实现来源:字段已存在且有断言,但只覆盖 8 个工具。**
`standard-capabilities.ts:16-32` 定义 `StandardCapabilityId` 与带 `source` 的 descriptor;
`execution-journal.ts:26-33` 把 `capability` 挂到 `tool_start`/`tool_end`;
生产者 `execute-run.ts:1148-1149`。但 `native-tool-identities.ts:4-18` 的
`nativeToolProvenance` 只认 **WX-T001..T008**(`ls`/`read_file`/`write_file`/`edit_file`/`glob`/`grep`/`delete`/`execute`),
其余一律返回 `{}`。即 37 个 WorkspaceX 自研工具 + 所有 MCP 工具的 trace 里仍无能力 ID、无实现来源。
断言:`packages/contracts/tests/native-tool-identities.test.ts`、`apps/api/tests/agent-run/gateway-forwarding.test.ts:119-120`。
- **耗时:仍然完全缺失。** `ToolCallEndFields` 无 `durationMs`;`agent_run_steps` 无 duration 列;
`tracing.py:118-160` 的 span 属性只有 run_id / run_type / parent_run_id / thread_id / error,且**无任何测试断言这些属性**。
唯一有一等公民耗时的是 subtask 投影(`subtask-run.ts:75`),而那条路径又不带 capability descriptor。
## 7. 分批补齐建议顺序

排序原则:**用户日常真的会碰到** > 影响面大 > 修起来便宜。

### P0 —— 用户日常路径,且现在处于「有实现、无会红断言」

- **P0-1|把 5 个 browser 工具接进 CI。**
`browser_navigate/snapshot/click/fill_form/take_screenshot` 是通用助手最常用的一类动作,
当前唯一真实证据整块 `describe.skip`,没有任何 job 打开 `WORKSPACEX_REAL_BROWSER`。
做法:给 `playwright-mcp-browser-real.test.ts` 建一条常跑车道(对齐 native-runtime-lane 的写法:
容器 + 变量都缺就 **throw**,不 skip)。
- **P0-2|让 `deep-agent-tests.yml` 真的跑沙箱文件工具。**
`ls/write_file/edit_file/glob/grep/delete/execute` 七个在 CI 里**静默跳过**。
`execute` 还是 L2 高风险工具,零真实回归。
做法:那条 job 起沙箱容器并设 `WX_NATIVE_SANDBOX_CONTAINER`;同时把 `pytest.skip`
换成「缺前置即失败」,否则这次补完下次照样静默。
- **P0-3|补第 5.2 节的反向门控。**
一条断言:`NATIVE_PROFILE_TOOLS` 的每个名字都必须显式登记在某一档白名单里。
这条最便宜(几行),却是 22 个工具静默要审批的**机制**成因;不补,后面每加一个工具都会复发。
- **P0-4|清掉第 5.1 节 22 个未分级工具里的只读误伤。**
`sql_db_list_tables` / `sql_db_schema` / `sql_db_query_checker` / `wx_schedule_list` / `web_search`
按性质只读,现在每次调用都弹审批框——与 #3160 / #3186 是同一个用户可感的毛病。
⚠ 顺序上必须在 P0-3 之后或同 PR,否则改完没有东西守着。

### P1 —— 用户会碰到,但缺的是「真实链路」而非「实现」

- **P1-1|`web_search` / `fetch_url` 的真实派发。** 现有 `standard-web-tools.test.ts` 质量很高
(真 TLS fixture、真 Readability、真 DNS-rebinding 防护),但它直接 new service,
工具从未被图派发过。补一条经 `/standard-web/invoke` 或图的用例即可升 ①。
- **P1-2|让 `native-full-chain.test.ts` 有车道跑。** 它一条就能把
`wx_skill_create_draft` / `wx_image_generate` / `wx_audio_transcribe` / `wx_artifact_publish` 四个从 ② 升 ①。
- **P1-3|21 个内建 skill 里挑 top-N 进常跑车道。** 建议先 `pdf-create` / `docx-create` /
`xlsx-create` / `pptx-create`(用户最常点)+ `web-research`。
不必上真实模型:先用可复现的替身把「skill 被挂载 → 被调用 → 产出文件非空且格式正确」钉死,
真实模型继续留在 `workflow_dispatch` 证据车道。

### P2 —— 治理与可观测

- **P2-1|#572 收窄**:把标题/正文改成「5 条仍零 controller 零 UI」,并顺手删掉
`agent-capability-graph.tsx:14` 的过期注释。
- **P2-2|#3020 的耗时字段**:`ToolCallEndFields` 加 `durationMs` + 断言;
`tracing.py` 的 span 属性目前**零断言**,同批补。
- **P2-3|`nativeToolProvenance` 覆盖面**:从 8 个扩到 45 个,否则「实现来源」对自研工具永远为空。
- **P2-4|关闭 #3084**(见第 6 节,代码已修且有回归断言)。

## 8. 本 issue 不做的事

不含任何实现修复,不新增 spec。上面每一条 P0/P1/P2 应各自开 issue 与 PR。

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reproducing the inventory commands and reading the named registration, CI workflow, test, and risk-tier files at SHA 12b39e0cd. Compare static tool and skill lists with executable CI evidence, then document any confirmed discrepancies and define the resulting coverage matrix as done.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, python, typescript
Domain
ci-cd, documentation, testing, tooling
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.