Repository navigation
Commit 8222fa8
fix(console): the OAuth consent screen explains metadata:write and never shows an unknown scope bare (#26659)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9Ubb51xwoNvcyPQLyWAgj42Yro)_
Fixes #26587
Clause-②: yes
Metadata-protocol: none
## 维护者速读
- **改了什么:** Console 的 OAuth 授权同意页(`/oauth/consent`)现在把 `metadata:write`
讲成一句话:「以草稿形式构建和修改此应用的元数据(不超出您自己的权限),由人来发布」,十种语言都有。页面不认识的 scope
显示为「无法识别的权限:xxx」,不再裸露原始字符串。
- **为什么改:** #26550 上线了 `metadata:write`,它是唯一能让 AI
客户端改动环境元数据的授权,却是同意页上唯一没有解释、只显示原始字符串的一项;用户在不知道授予了什么的情况下点「授权」。
- **风险与回滚:** 低。只改同意页的文案渲染和语言包两个新键;授权流程、提交内容不变。四个 MCP scope 的英文句子改为直接取自
`@objectstack/spec` 的 `MCP_OAUTH_SCOPE_CONSENT_COPY`,与服务端声明一致。回滚即 revert
本 PR。
- **先看:** `ui/apps/console/src/pages/auth/OAuthConsentPage.tsx` 的
`describeAgentScope`(对 `McpOauthScope` 穷尽的 switch)与 `default`
分支;`ui/apps/console/src/pages/auth/__tests__/OAuthConsentPage.mcp-scopes-26587.test.tsx`。
- **两分钟验证:** `pnpm --dir ui exec vitest run
apps/console/src/pages/auth/__tests__/OAuthConsentPage.mcp-scopes-26587.test.tsx`,预期
12 个用例全绿(英文逐句等于 spec 文案,其余九种语言均不出现原始 scope,未知 scope 显示为「无法识别的权限」)。
- **需要你做的:** 无,席位落地。
## What changes
**`@object-ui/console` — `OAuthConsentPage`.** The consent list used to
map the three older agent scopes by hand and send everything else to
`default: return scope`, so `metadata:write` (added by #26550) reached
the user as its raw spelling. Now:
- `describeScope` routes every member of `MCP_OAUTH_SCOPES` to
`describeAgentScope`, a switch that is exhaustive over `McpOauthScope`
with no default. Each case reads its own pack key and passes
`MCP_OAUTH_SCOPE_CONSENT_COPY[scope]` (from `@objectstack/spec/ai`) as
the `defaultValue`. A scope the spec adds without a case here fails the
Console type-check instead of rendering unexplained.
- The `default` branch renders `oauth.consent.scope.unrecognised`
("Unrecognised permission: SCOPE"), per the triage ruling (comment
6438780502): "An unknown scope renders as an explicit "unrecognised
permission", ⛔ never as a bare string."
**`@object-ui/i18n` — all ten locale packs.** Two keys under
`oauth.consent.scope`: `metadataWrite` (the `en` value is byte-identical
to the spec's sentence) and `unrecognised` (one `{{scope}}`
placeholder). The `en` comment above the block now says where the
agent-scope English comes from. `TranslationKeys = typeof en` widens by
these two keys, hence `Clause-②: yes`.
**`docs/qa/platform-checklist/areas/ai.json` — `ai.mcp-http-surface`,
revision 6** (the second item the card carries; a devx file). Main at
c739de7 still said "three" scopes. The acceptance[5] clause and its
verify now name the four scopes the 403 body and the WWW-Authenticate
`scope` list carry (`packages/runtime/src/domains/mcp.ts` joins
`MCP_OAUTH_SCOPES`), steps[5] says "four", and the variants matrix gains
the `metadata:write` row (the host-injected authoring tools, served only
to an OAuth grant naming the scope, per
`packages/mcp/src/mcp-http-tools.ts`). History row added.
**Changeset:** `.changeset/26587-consent-metadata-write.md`, `patch` for
`@object-ui/i18n` and `@object-ui/console`.
## Tests
- New:
`ui/apps/console/src/pages/auth/__tests__/OAuthConsentPage.mcp-scopes-26587.test.tsx`.
It walks `MCP_OAUTH_SCOPES`, so a scope the spec adds is a subject the
moment it lands. In `en` the rows equal `MCP_OAUTH_SCOPE_CONSENT_COPY`
in order. In each of the nine other built-in languages (catalogue loaded
before the instance, so a missing key cannot hide behind the `en`
fallback), no row contains the raw scope and no row equals the English
sentence. An unknown scope renders through the `unrecognised` pack value
in `en`, and in `zh` as a translated line that still names the scope.
- Updated: the `CONTROL` case of
`OAuthConsentPage.agent-scopes-12853.test.tsx` pinned the old raw-string
behaviour; it now asserts the unrecognised line.
## Gates
Local subset at `3f2b32c8`: the 41 commands `node
scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives for this diff, each run with its
exit code captured before any pipe, all 41 exit 0. `--ran`
reconciliation: "41 derived famil(ies) accounted for — 41 run, 0
NOT-MEASURED (a DERIVED zero — all 41 recorded an exit code and none of
them is 3)". The type-check lanes, the artifact rosters and the
whole-tree families are CI's; their check-runs on this PR are the
reading.
<details><summary>The 41 derived commands and their exit codes</summary>
```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-adr-links.mjs :: exit 0
node scripts/check-adr-links.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-comment-mask-corpus.mjs :: 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/plan-test-core-shards.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 --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: 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:doc-authoring :: 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:platform-checklist :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: 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
```
</details>
Also run, outside the derivation (ui gates no root workflow runs today):
`node scripts/check-i18n-call-site-keys.mjs` exit 0 (every call-site key
resolves, interpolation parity holds), `node
scripts/check-i18n-en-drift.mjs` exit 0 ("No en value changed in this
range"), `node scripts/check-new-cross-file-line-citations.mjs` exit 0
("0 new citation(s)").
## Acceptance notes
- The claim's file surface said "one new consent key"; the card's route
also asks for a translated "unrecognised permission" line, so the packs
gain two keys (`metadataWrite`, `unrecognised`).
- The `zh` / `ja` / … sentences for `metadataWrite` follow each pack's
existing pattern for the other agent scopes (the permission bound in
parentheses) and add the "a person publishes" clause; they are hand
translations, not machine-checked.
- The Console now imports `@objectstack/spec/ai` from an eagerly loaded
page. The constants live in a spec chunk that `@objectstack/spec/system`
(already in the Console's dependency set) also reaches; the
eager-closure byte cost was not measured locally and is left to CI's
performance budget.
- `ai.json`: besides the clause the card names, steps[5] ("NONE of the
three MCP scopes") and the variants matrix were also stale for the same
reason and are corrected in the same revision.
## Verification
All readings at `3f2b32c8`.
<details><summary>Tests</summary>
- `cd ui && pnpm exec vitest run
apps/console/src/pages/auth/__tests__/OAuthConsentPage.mcp-scopes-26587.test.tsx
apps/console/src/pages/auth/__tests__/OAuthConsentPage.agent-scopes-12853.test.tsx
apps/console/src/pages/auth/__tests__/OAuthConsentPage.public-client-12301.test.tsx
--maxWorkers=1` (under `os-verify-lock.sh`): Test Files 3 passed (3),
Tests 23 passed (23).
- `cd ui && pnpm exec vitest run packages/i18n/ --maxWorkers=1`: Test
Files 89 passed (89), Tests 1373 passed, 13 skipped
(all-locales-key-parity among them).
- `pnpm --dir ui exec vitest run scripts/` (derived): Test Files 178
passed, 2 skipped; Tests 5065 passed, 2 skipped.
</details>
<details><summary>Type-check</summary>
`pnpm exec turbo run type-check --filter=@object-ui/i18n
--filter=@object-ui/console --concurrency=2`: Tasks 71 successful, 71
total, 0 cached (the two packages' `type-check`, which covers their
tests, plus the `^build` closure). VERDICT command-exit 0.
</details>
<details><summary>Ablations (one-shot, through
scripts/ablation-replace.mjs, restored to HEAD each time)</summary>
- Drop the `zh` pack's `metadataWrite` line: "anchor 1 -> 0, blob
4a8ff35 -> 0d88d403f28e"; the walk goes red on the `zh` case only
("Tests 1 failed | 11 passed (12)"); restore: "blob == HEAD
(4a8ff35) and `git diff HEAD` is empty".
- Send `metadata:write` past the agent-scope routing in `describeScope`
(it falls to the unrecognised branch): "anchor 1 -> 0"; the `en` walk
and all nine language cases go red ("Tests 10 failed | 2 passed (12)");
restore: "blob == HEAD (935b2c4) and `git diff HEAD` is empty".
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jUZATdbPBDkvjTyX8D)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 02b1392 commit 8222fa8
15 files changed
Lines changed: 229 additions & 32 deletions
File tree
- .changeset
- docs/qa/platform-checklist/areas
- ui
- apps/console/src/pages/auth
- __tests__
- packages/i18n/src/locales
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
136 | | - | |
| 136 | + | |
137 | 137 | | |
138 | 138 | | |
139 | 139 | | |
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
149 | | - | |
| 149 | + | |
| 150 | + | |
150 | 151 | | |
151 | 152 | | |
152 | 153 | | |
153 | 154 | | |
154 | 155 | | |
155 | 156 | | |
156 | 157 | | |
157 | | - | |
| 158 | + | |
158 | 159 | | |
159 | 160 | | |
160 | 161 | | |
| |||
189 | 190 | | |
190 | 191 | | |
191 | 192 | | |
192 | | - | |
| 193 | + | |
193 | 194 | | |
194 | | - | |
| 195 | + | |
195 | 196 | | |
196 | 197 | | |
197 | 198 | | |
| |||
215 | 216 | | |
216 | 217 | | |
217 | 218 | | |
218 | | - | |
| 219 | + | |
| 220 | + | |
219 | 221 | | |
220 | 222 | | |
221 | 223 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
37 | 46 | | |
38 | 47 | | |
39 | 48 | | |
| |||
271 | 280 | | |
272 | 281 | | |
273 | 282 | | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
278 | 291 | | |
279 | 292 | | |
280 | 293 | | |
| |||
292 | 305 | | |
293 | 306 | | |
294 | 307 | | |
295 | | - | |
296 | | - | |
297 | | - | |
298 | | - | |
299 | | - | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
310 | 311 | | |
311 | | - | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
312 | 339 | | |
313 | 340 | | |
314 | 341 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
19 | | - | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
106 | 108 | | |
107 | 109 | | |
108 | 110 | | |
109 | | - | |
| 111 | + | |
110 | 112 | | |
111 | 113 | | |
112 | 114 | | |
113 | 115 | | |
114 | | - | |
| 116 | + | |
115 | 117 | | |
116 | 118 | | |
117 | 119 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2960 | 2960 | | |
2961 | 2961 | | |
2962 | 2962 | | |
| 2963 | + | |
| 2964 | + | |
2963 | 2965 | | |
2964 | 2966 | | |
2965 | 2967 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2750 | 2750 | | |
2751 | 2751 | | |
2752 | 2752 | | |
| 2753 | + | |
| 2754 | + | |
2753 | 2755 | | |
2754 | 2756 | | |
2755 | 2757 | | |
| |||
0 commit comments