Repository navigation
fix(console): the OAuth consent screen explains metadata:write and never shows an unknown scope bare - #26659
Conversation
…nces an unknown scope as unrecognised The agent-scope sentences come from @objectstack/spec's MCP_OAUTH_SCOPE_CONSENT_COPY through an exhaustive switch over McpOauthScope, and every locale pack gains metadataWrite and unrecognised. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUZATdbPBDkvjTyX8D
…et for the consent screen Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUZATdbPBDkvjTyX8D
Contract reviewServed-tier: Face: declaration. The face is owed only because of the ① Derived judgments
② Semver levelThe changeset declares ③ Boundary flagsThe dev raised four deviations. Each is answered below.
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对ACCEPT · seat
Landing: the seat marks the PR ready and arms auto-merge. On MERGED, Generated by Claude Code |
Requested by Steedos · project thread
Fixes #26587
Clause-②: yes
Metadata-protocol: none
维护者速读
/oauth/consent)现在把metadata:write讲成一句话:「以草稿形式构建和修改此应用的元数据(不超出您自己的权限),由人来发布」,十种语言都有。页面不认识的 scope 显示为「无法识别的权限:xxx」,不再裸露原始字符串。metadata:write,它是唯一能让 AI 客户端改动环境元数据的授权,却是同意页上唯一没有解释、只显示原始字符串的一项;用户在不知道授予了什么的情况下点「授权」。@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 todefault: return scope, sometadata:write(added by #26550) reached the user as its raw spelling. Now:describeScoperoutes every member ofMCP_OAUTH_SCOPEStodescribeAgentScope, a switch that is exhaustive overMcpOauthScopewith no default. Each case reads its own pack key and passesMCP_OAUTH_SCOPE_CONSENT_COPY[scope](from@objectstack/spec/ai) as thedefaultValue. A scope the spec adds without a case here fails the Console type-check instead of rendering unexplained.defaultbranch rendersoauth.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 underoauth.consent.scope:metadataWrite(theenvalue is byte-identical to the spec's sentence) andunrecognised(one{{scope}}placeholder). Theencomment above the block now says where the agent-scope English comes from.TranslationKeys = typeof enwidens by these two keys, henceClause-②: 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-Authenticatescopelist carry (packages/runtime/src/domains/mcp.tsjoinsMCP_OAUTH_SCOPES), steps[5] says "four", and the variants matrix gains themetadata:writerow (the host-injected authoring tools, served only to an OAuth grant naming the scope, perpackages/mcp/src/mcp-http-tools.ts). History row added.Changeset:
.changeset/26587-consent-metadata-write.md,patchfor@object-ui/i18nand@object-ui/console.Tests
ui/apps/console/src/pages/auth/__tests__/OAuthConsentPage.mcp-scopes-26587.test.tsx. It walksMCP_OAUTH_SCOPES, so a scope the spec adds is a subject the moment it lands. Inenthe rows equalMCP_OAUTH_SCOPE_CONSENT_COPYin order. In each of the nine other built-in languages (catalogue loaded before the instance, so a missing key cannot hide behind theenfallback), no row contains the raw scope and no row equals the English sentence. An unknown scope renders through theunrecognisedpack value inen, and inzhas a translated line that still names the scope.CONTROLcase ofOAuthConsentPage.agent-scopes-12853.test.tsxpinned the old raw-string behaviour; it now asserts the unrecognised line.Gates
Local subset at
3f2b32c8: the 41 commandsnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives for this diff, each run with its exit code captured before any pipe, all 41 exit 0.--ranreconciliation: "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.The 41 derived commands and their exit codes
Also run, outside the derivation (ui gates no root workflow runs today):
node scripts/check-i18n-call-site-keys.mjsexit 0 (every call-site key resolves, interpolation parity holds),node scripts/check-i18n-en-drift.mjsexit 0 ("No en value changed in this range"),node scripts/check-new-cross-file-line-citations.mjsexit 0 ("0 new citation(s)").Acceptance notes
metadataWrite,unrecognised).zh/ja/ … sentences formetadataWritefollow 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.@objectstack/spec/aifrom 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.Tests
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(underos-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.Type-check
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^buildclosure). VERDICT command-exit 0.Ablations (one-shot, through scripts/ablation-replace.mjs, restored to HEAD each time)
zhpack'smetadataWriteline: "anchor 1 -> 0, blob 4a8ff35cd28f -> 0d88d403f28e"; the walk goes red on thezhcase only ("Tests 1 failed | 11 passed (12)"); restore: "blob == HEAD (4a8ff35cd28f) andgit diff HEADis empty".metadata:writepast the agent-scope routing indescribeScope(it falls to the unrecognised branch): "anchor 1 -> 0"; theenwalk and all nine language cases go red ("Tests 10 failed | 2 passed (12)"); restore: "blob == HEAD (935b2c4ded21) andgit diff HEADis empty".Generated by Claude Code