Repository navigation
Commit 7d9f1e9
fix(console): the skill download teaches delete_record confirm: true and mirrors the served SKILL.md (#31015)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoLpvyeWbGwXcuZzD8qyUXpu)_
Fixes #30865
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:Console 集成页「Download skill」下载的 SKILL.md 现在与 MCP
服务端下发的文本逐字一致:`delete_record` 带上 `confirm: true` 及拒收说明,并补上 `list_actions`
/ `run_action` / `resume_run` / `validate_expression` 和 OAuth 接入方式。
- 为什么改:服务端自 #30861 起拒绝不带 `confirm: true`
的删除(`ACTION_CONFIRMATION_REQUIRED`),照旧下载件操作的 AI
代理每次删除都会失败;下载件还漏教了业务动作工具。
- 风险与回滚:只改一个纯文本渲染函数和它的测试,不碰服务端;回滚即 revert 本 PR。
-
先看:`ui/apps/console/src/pages/developer/objectstack-skill.test.ts`(新的漂移钉:从源码导入服务端渲染函数逐字比对)、`objectstack-skill.ts`
的 Tools 段、changeset。
- 两分钟验证:`pnpm --dir ui exec vitest run
apps/console/src/pages/developer/objectstack-skill.test.ts`,预期 13 个测试全绿。
- 需要你做的:无,席位落地。
- **席位意见**:ui 席 2 对照 head `828224c8` 的 diff 复核:3 个文件、+158 /
−29,无受治理路径。控制台「下载技能」的 SKILL.md 改为与 MCP 服务端 `renderSkillMarkdown` 无 OAuth
范围时的文本逐字节一致(`delete_record` 带 `confirm: true` 及确认规则、补齐
`validate_expression`、`list_actions`/`run_action`/`resume_run`、OAuth 连接与
Bearer 密钥写法);测试在 node 环境按相对路径从源码导入服务端渲染器,五种参数逐字节比对,另钉住 11
个工具的顺序与删除调用形状,消融两侧各红。只改 `packages/mcp/src/skill-md.ts` 的 PR 不会触发这条比对(CI
过滤器缺口),已立卡 #31017。Clause-② no,不欠契约复审。同意落地。
## What changes
- `ui/apps/console/src/pages/developer/objectstack-skill.ts`: the mirror
now renders exactly what `renderSkillMarkdown`
(`packages/mcp/src/skill-md.ts`) serves to a caller with no OAuth scopes
(an API key or a session), which is the data skill with no authoring
section and no federation tools. It gains `OBJECTSTACK_MCP_SERVER_NAME`
for the `claude mcp add` snippet. The header says what it mirrors and
which test holds it.
- `objectstack-skill.test.ts`: a **drift pin**. The test runs in the
node environment, imports `renderSkillMarkdown` and the identity
constants from source by relative path (the console does not depend on
`@objectstack/mcp`, which is not browser-safe), and asserts byte
equality for five option shapes (none, URL, env name, both padded,
blank). Explicit pins sit beside it: the ordered tool list (11 tools)
and the `delete_record` call shape with its confirmation sentence. The
old "not Bearer" assertion is replaced by an x-api-key header assertion,
because the server now teaches `Authorization: Bearer` as an accepted
key form.
- `.changeset/30865-console-skill-download-confirm.md`:
`@object-ui/console` patch (the package is not private).
No mirror text differs from the canonical render on purpose, so the pin
is full-text equality rather than the tool-list fallback.
## Tests
<details><summary>Measured drift before the fix (mirror vs canonical,
same URL and env name, origin/main 8ae0ab9)</summary>
`diff mirror-before.md canonical.md` with `{ mcpUrl:
'https://acme.objectos.app/api/v1/mcp', envName: 'Acme CRM' }`: 85
insertions, 16 deletions, 9 hunks.
1. Intro: canonical names business **actions** as tools and the OAuth
consent-scope bound; the mirror said "runs as you" with data objects
only.
2. When to use: canonical adds "run a business action" and "an action is
always better than hand-editing".
3. Connect: canonical teaches two tracks, OAuth (with the `claude mcp
add --transport http objectstack URL` example) and API key; the mirror
taught the API key only.
4. Accepted headers: canonical accepts `Authorization: Bearer KEY` too;
the mirror named only `ApiKey`.
5. Discover: canonical adds step 3, `list_actions`.
6. Tools: the mirror lacked `validate_expression`.
7. Tools: the mirror taught `delete_record({ objectName, recordId })`
with no `confirm`; canonical teaches `delete_record({ objectName,
recordId, confirm })` and the `ACTION_CONFIRMATION_REQUIRED` refusal.
The mirror also lacked `list_actions`, `run_action` and `resume_run`.
8. Conventions: canonical adds "Prefer actions over hand-edits".
9. Recommended workflow: canonical adds `list_actions` in step 1 and
`run_action` in step 4.
Frontmatter (name, description) was already identical. After the fix:
the five equality cases pass, so the diff is empty for every shape
tested.
</details>
<details><summary>Test run (head 828224c)</summary>
`pnpm --dir ui exec vitest run
apps/console/src/pages/developer/objectstack-skill.test.ts` → Test Files
1 passed (1), Tests 13 passed (13).
</details>
<details><summary>Ablation (scripts/ablation-replace.mjs, both legs
restored to the HEAD blob)</summary>
- Leg 1, the confirm line: `- **delete_record({ objectName, recordId,
confirm })** — delete a record,` → `- **delete_record({ objectName,
recordId })** — delete a record,` in the mirror (anchor 1 → 0, blob
8612fda → 7cea2fc32802). Result: 6 failed, 7 passed. Red: "teaches
delete_record with confirm: true, which the server requires" and all
five "renders the canonical text for …" cases. Restored blob
8612fda == HEAD.
- Leg 2, a canonical-side edit (shows the pin catches drift from either
side): `- **Page large reads.** Use` → `- **Page large reads, always.**
Use` in `packages/mcp/src/skill-md.ts`. Result: 5 failed, 8 passed (the
five equality cases). Restored, `git diff HEAD` empty.
No build sits between the test and either mutated file: both are
imported from source.
</details>
## Verification
<details><summary>Local gates (derived with dispatch-gates.mjs
--commands against this diff)</summary>
Head `828224c88f`. 35 derived, 35 run, 0 NOT-MEASURED
(`dispatch-gates.mjs --ran` reconciliation exit 0). Every line exit 0:
```text
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/ci/snapshot-next.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
```
Also `pnpm --dir ui exec vitest run apps/console/src/pages/developer/`:
Test Files 20 passed (20), Tests 165 passed (165). `pnpm --dir ui exec
vitest run scripts/`: Test Files 170 passed, 2 skipped; Tests 4991
passed, 2 skipped.
</details>
<details><summary>Console type-check (the relative source import brings
packages/mcp/src/skill-md.ts into the console tsc program)</summary>
`pnpm exec turbo run type-check --concurrency=2
--filter=@object-ui/console` → `@object-ui/console:type-check: cache
miss, executing`, Tasks 73 successful, 73 total; lock VERDICT
command-exit 0. Also `pnpm --dir ui run check:phantom-deps`,
`check:self-import`, `check:unreferenced-sources`: exit 0 each.
</details>
## Acceptance notes
- **CI scoping blind spot (noted, not filed).** The drift pin lives in
Test UI. A later PR that changes only `packages/mcp/src/skill-md.ts`
matches neither the `ui` nor the `ui_consumers` filter in `ci.yml`
(`packages/mcp/**` is not among the seven `ui_consumers` packages), so
Test UI does not run on that PR or its queue entry; the pin goes red on
the next `main` scheduled or dispatched full run instead. Closing it
needs `packages/mcp/src/skill-md.ts` in the `ui` filter, which is root
`ci.yml` and out of this card's bounds. Carrier: seat.
- Open PRs checked for the serial rule: none touches
`objectstack-skill.ts`, its test or `packages/mcp/src/skill-md.ts`.
#30902 touches two other test files in
`ui/apps/console/src/pages/developer/`
(`consolePagesLocale-13460.test.tsx`,
`flowRunsClientDiagnostic-25916.test.tsx`), with no overlap.
<!-- signed: domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf
-->
Co-authored-by: Claude <noreply@anthropic.com>1 parent 584f7b8 commit 7d9f1e9
3 files changed
Lines changed: 158 additions & 29 deletions
File tree
- .changeset
- ui/apps/console/src/pages/developer
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
1 | 2 | | |
2 | 3 | | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
3 | 13 | | |
4 | 14 | | |
| 15 | + | |
5 | 16 | | |
6 | 17 | | |
7 | 18 | | |
| |||
17 | 28 | | |
18 | 29 | | |
19 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
20 | 37 | | |
21 | 38 | | |
22 | 39 | | |
| |||
34 | 51 | | |
35 | 52 | | |
36 | 53 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
| 54 | + | |
| 55 | + | |
41 | 56 | | |
42 | 57 | | |
43 | | - | |
| 58 | + | |
44 | 59 | | |
45 | | - | |
| 60 | + | |
46 | 61 | | |
47 | 62 | | |
| 63 | + | |
48 | 64 | | |
49 | 65 | | |
50 | 66 | | |
51 | 67 | | |
52 | 68 | | |
53 | | - | |
54 | | - | |
55 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
56 | 73 | | |
57 | 74 | | |
58 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
59 | 83 | | |
60 | 84 | | |
61 | 85 | | |
62 | 86 | | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
9 | 13 | | |
10 | 14 | | |
11 | 15 | | |
| |||
20 | 24 | | |
21 | 25 | | |
22 | 26 | | |
| 27 | + | |
| 28 | + | |
23 | 29 | | |
24 | 30 | | |
25 | 31 | | |
| |||
42 | 48 | | |
43 | 49 | | |
44 | 50 | | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
49 | 58 | | |
50 | 59 | | |
51 | 60 | | |
52 | 61 | | |
53 | 62 | | |
54 | | - | |
55 | | - | |
56 | | - | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
57 | 68 | | |
58 | 69 | | |
59 | 70 | | |
| |||
63 | 74 | | |
64 | 75 | | |
65 | 76 | | |
66 | | - | |
67 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
68 | 95 | | |
69 | 96 | | |
70 | 97 | | |
71 | 98 | | |
72 | 99 | | |
73 | | - | |
74 | | - | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
75 | 103 | | |
76 | 104 | | |
77 | 105 | | |
| |||
81 | 109 | | |
82 | 110 | | |
83 | 111 | | |
| 112 | + | |
| 113 | + | |
84 | 114 | | |
85 | 115 | | |
86 | 116 | | |
| |||
89 | 119 | | |
90 | 120 | | |
91 | 121 | | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
92 | 137 | | |
93 | 138 | | |
94 | 139 | | |
95 | 140 | | |
96 | 141 | | |
97 | 142 | | |
98 | | - | |
99 | | - | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
100 | 168 | | |
101 | 169 | | |
102 | 170 | | |
| |||
108 | 176 | | |
109 | 177 | | |
110 | 178 | | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
111 | 184 | | |
112 | 185 | | |
113 | 186 | | |
114 | | - | |
| 187 | + | |
| 188 | + | |
115 | 189 | | |
116 | 190 | | |
117 | | - | |
118 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
119 | 194 | | |
120 | 195 | | |
0 commit comments