You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
finding(console): the OAuth consent page names the requesting app by its raw client_id, because the console fetches a route the server does not serve #12853
Found by the repo:www.objectos.ai seat (objectstack-ai/objectstack#12224) on 2026-10-17, while staging www.objectos.ai#275. Measured on the published @objectstack/cli / @objectstack/console17.7.0. Class a: consent is the screen a user authorizes access on, and it does not say who is asking.
What happens
The consent title. A client registered through dynamic client registration with client_name: "Claude Code" reaches /_console/oauth/consent. The page reads "hURqwHicPZUqDxuNgMQJksrzIXHCRmPR wants to access your account": the raw client_id instead of the registered name. At 1100 px the id also overflows its card.
The cause. The console (17.7.0 dist, the consent component) calls GET /api/v1/auth/oauth2/applications/{client_id}/public, which answers 404. The server's route is GET /api/v1/auth/oauth2/public-client?client_id=… (auth-route-ledger.ts:178 at the tag), which answers 200 with client_name under the user's cookie.
The scope list. The page lists data:read, data:write and actions:execute as raw strings, and only openid, profile, email and offline_access get human sentences. It is a read-only list with Deny and Authorize only, so there is no way to narrow the scopes.
Why it matters
The consent screen is the only point at which a user decides to hand an agent access to their data. Showing an opaque id instead of the app's registered name defeats the user's ability to recognise what they are authorizing.
Done looks like
The consent page fetches the client's public metadata from the route the server serves, and titles the request with client_name, falling back to the id only if no name is registered.
The three MCP scopes get human descriptions.
A pin: register a client with a name, open consent, and the name is shown.
Related: the OAuth MCP delegator finding filed in the same pass.
What is left is console-only: the three MCP scopes data:read, data:write and actions:execute still show as raw strings. Neither the consent page nor objectui's en locale names them. Filing rule 1 says a console defect lives in objectui, so this card transfers there, graded p3 · domain:ui · area:identity.
Claim: PM loop round 3 (priority:p3 bug, area:identity; filed by the repo:www.objectos.ai seat and graded by the triage seat, 6229454186: the title half was fixed by objectui#12301, and the three MCP scopes' descriptions remain)
Session: session_01SJn1GEkrbbBQkhGC26wEDw
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-12853-consent-scope-labels
Worktree: objectui-issue-12853 (in the cloud session's own container)
Domain: domain:ui
Seat: domain:ui#4
File surface:
apps/console/src/pages/auth/OAuthConsentPage.tsx: describeScope names data:read, data:write and actions:execute. Any other scope still renders as its raw string.
packages/i18n/src/locales/*.ts: three keys under oauth.consent.scope (dataRead, dataWrite, actionsExecute) in all ten packs, and the region's comment updated to match.
Tests beside the page, and changesets for @object-ui/console and @object-ui/i18n (patch).
⛔ The consent flow, the public-client lookup (objectui#12301), followAuthorize.ts and the Deny / Authorize actions are unchanged. No scope narrowing.
Stop on breach; explain in the report.
Container & model: S, mode:cloud, model: opus (cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)
Clause-②: yes
Clause-② reason: three new @object-ui/i18n keys in all ten packs. No exported type or prop moves.
Responsibility: n/a — the consent screen lists the three agent scopes as raw strings, at the one point where a user decides to hand an agent their data
Thread-read: 6229454186
Serial constraints cleared:
objectui#12301 (the consent page's public-client lookup) is closed completed, and OAuthConsentPage.tsx:104 on mainbf376c5 fetches /oauth2/public-client.
No open objectui PR touches apps/console/src/pages/auth/** (read at dispatch).
{
"issue": 12853,
"status": "done",
"branch": "claude/issue-12853-consent-scope-labels",
"pr": 12884,
"session": "session_01F7rGA65najBBQpwrw7ZXFw — this run's harness-stamped id (Claude-Session trailer on 354bc6e); dispatched by PM seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw",
"premise_still_valid": true,
"summary": "The consent page's describeScope now maps data:read, data:write and actions:execute to one sentence each, via three new oauth.consent.scope keys (dataRead, dataWrite, actionsExecute) in all ten packs, with defaultValues matching en. Each sentence carries the ceiling objectstack enforces ('within your own permissions'). Any other scope still renders as its raw string. The en region comment now says seven scopes. The title half was already fixed on main bf376c5 and I did not touch it. Live on the published 18.0.0-next.2 showcase, a DCR client named 'Claude Code' is titled by that name on both main and the branch, and only the three agent rows changed (raw strings on main, sentences on the branch). Feature head 354bc6e; evidence branch head afa507d. Card assignee not written. Side effect: the shared checkout /home/user/objectui had the local branch claude/issue-12853-consent-scope-labels checked out with no commits of its own, so I detached that checkout's HEAD at bf376c5 and deleted the local branch before running git worktree add, as the dispatch allows.",
"tests": "At HEAD 354bc6e, repo-root form, under os-verify-lock: (1) `pnpm exec vitest run apps/console/src/pages/auth/__tests__/ packages/i18n/` -> 'Test Files 102 passed (102) / Tests 1438 passed | 13 skipped (1451)', VERDICT command-exit 0. (2) `pnpm exec vitest run --reporter=verbose` on OAuthConsentPage.agent-scopes-12853.test.tsx plus OAuthConsentPage.public-client-12301.test.tsx -> 'Tests 11 passed (11)': the three new pins (en sentences; zh sentences; CONTROL reports:export stays raw) and all seven objectui#12301 pins, unchanged, including 'names a registered client by its client_name and shows its logo_uri'. Earlier pre-commit run of the auth __tests__ dir alone: 'Test Files 19 passed (19) / Tests 113 passed (113)'. Ablation, one leg per new pin, fix committed first. Each leg used a python anchor replace that asserts exactly one anchor hit, a grep -c of injected and removed text, and a trap restore via `git checkout HEAD -- ABSOLUTE_PATH` with a HEAD blob-hash precondition. en leg: en.ts dataWrite value mutated; injected hits=1, anchor hits=0; 'names the three agent scopes in en' failed ('Tests 1 failed | 2 passed (3)'), restored, git diff HEAD bytes=0. zh leg: zh.ts dataRead value mutated; injected=1, anchor=0; the zh pin failed; restored, bytes=0. CONTROL leg: the default branch was changed to return scope.replace(':', ' '); CONTROL failed; restored, bytes=0. The CONTROL leg's grep -c read injected=2, anchor=1 because grep -F treats each line of a two-line pattern separately and ' default:' matches both. The red result is the proof that the mutation landed. No dist step was needed: the console tests resolve @object-ui/i18n to source, which the red pack-edit legs show.",
"gates": "All run at 354bc6e; exit codes captured before any pipe. `pnpm turbo run build --filter=@object-ui/console... --concurrency=2` (under lock) -> 'Tasks: 35 successful, 35 total', VERDICT command-exit 0; this covers the @object-ui/i18n and @object-ui/console builds. `pnpm run type-check` in apps/console (echoed '@object-ui/console@17.7.0 type-check') -> exit 0. `pnpm run type-check` in packages/i18n (echoed '@object-ui/i18n@17.7.0 type-check') -> exit 0. `pnpm exec eslint` on the 12 changed .ts/.tsx files, normal mode -> exit 0, '0 errors, 1 warning': a react-hooks/immutability warning on the pre-existing handleDecision code that this diff does not touch. `pnpm check:i18n-keys` -> exit 0 ('Every in-scope call-site key resolves against the en pack … every literal inline defaultValue matches the value the pack serves'). `pnpm check:i18n-drift` -> exit 0 ('0 en value(s) changed (3 key(s) added, 0 removed)'). `node scripts/check-changeset-presence.mjs` -> exit 0 ('11 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'). `pnpm check:new-line-citations` -> exit 0 ('0 new citation(s)'). Control-byte self-scan with grep -naP over the changed files -> exit 1, no hits. NOT MEASURED: `node scripts/check-nul-bytes.mjs` (it does not exist in objectui, so it raised MODULE_NOT_FOUND, which is not a gate result). NOT MEASURED: dispatch-gates.mjs --commands / --ran (objectui has no such script; the gates above are derived by hand). CI check-runs: no PR exists yet, so none can be cited; the PM reads them after opening the PR. origin/main is still bf376c5 at report time and `git merge-tree` against it is clean, so no merge was needed.",
"mcp_calls": "3 GitHub MCP calls, all reads: issue_read get #12853, issue_read get_comments #12853, issue_read get #12301. Non-GitHub: 1 claude-code-remote add_repo (objectstack-ai/objectstack, access read, answered read_available) and 1 ToolSearch schema load. Zero MCP write tools.",
"api_writes": "0 REST or relay writes. git push only (3): the empty feature branch, the feature commit 354bc6e, and the evidence branch claude/issue-12853-evidence at afa507d. No PR opened, no comment, no label, no assignee write.",
"open_questions": [
{
"question": "Sentence wording for the three scopes, under ruling 2. Settled; recorded here per the dispatch, not a blocker.",
"options": [
"A: verb + object + the ceiling clause ('Read records, within your own permissions'; 'Create, change and delete records, within your own permissions'; 'Run actions on your behalf, within your own permissions')",
"B: name the tools (list/describe/query/get…)",
"C: say 'your records'"
],
"recommendation": "A, chosen. Business need (measured): the server scopes are exactly these tool families, quoted from the code in the PR body, and every call is bounded by the user's own grants. Long-term: the copy promises neither less nor more than the code does. AI-error axis: no generic or spelling-derived entry, and unknown scopes stay raw (pinned by CONTROL). Scope: three keys and no new surface. C was rejected because the agent reads every record the user can see, not only the user's own records, so 'your records' would promise less than the code grants. The actions sentence says 'actions', not \"the app's actions\", because on this page 'This app' means the requesting client."
},
{
"question": "Conflict between the dispatch and objectstack .claude/agents/os-dev.md. The file wins where they disagree, and I am stating each case here.",
"options": [
"os-dev.md tells the dev to open the draft PR and post the os-dev-report comment through the scripts/pm write tools and the fleet-write relay; the dispatch says the relay is refused (403) in this container. I followed the dispatch: no PR and no comment, with pr_body_draft below. I did not probe the relay. This is a missing capability in the container, not a choice between the two rules.",
"os-dev.md's single-file test spelling is `pnpm --filter PKG exec vitest run`; objectui AGENTS.md requires the repo-root form. I used the repo-root form, because the repo where the change lands decides its own conventions.",
"os-dev.md's ablation tools (scripts/ablation-replace.mjs, ablation-dist-preflight.mjs) exist only in objectstack. I used an inline anchor-asserting replace that checks what was written to disk, as described in tests."
],
"recommendation": "No action needed; recorded for the seat."
}
],
"out_of_scope_findings": [
"observation, not filed (none of the three filing classes; no reach measured outside dev): in the live dev console the consent page asked GET /oauth2/public-client twice per load on both main and the branch, once per React StrictMode effect pass in dev, which is expected. The objectui#12301 pin 'shows neither a name nor the id while the lookup is in flight' asserts one lookup under test. carrier: none. noted, not filed",
"observation, not filed: eslint reports react-hooks/immutability as a warning on OAuthConsentPage's pre-existing handleDecision, in code this diff does not touch. carrier: none. noted, not filed"
],
"deviations": [
"Title half measured, not changed (ruling 1). On main bf376c5 the page reads the registered client_name through the served public-client route. Live, a DCR client named 'Claude Code' is titled 'Claude Code 请求访问您的账户' on main and on the branch. When no name is registered, the title uses oauth.consent.unknownApp ('an application') and the raw id is shown only inside a labelled 'Client ID' alert, never in the name's place. That is how objectui#12301 settled it, and it is narrower than the card's 'falling back to the id'. I made no change and am reporting it as measured. The pin holding it is OAuthConsentPage.public-client-12301.test.tsx, which passes unchanged.",
"Live recipe as measured: dynamic client registration refused http://localhost and http://127.0.0.1 redirect URIs ('web clients require https redirect URIs on non-loopback hosts'), so the client was registered with https://client.example/cb. The authorize endpoint redirects to the server's own /_console/oauth/consent (the published console). I opened that same signed query string on each dev console's /oauth/consent instead.",
"The before shot came from a temporary detached worktree at bf376c5 (console on :5198) and the after shot from the feature worktree (:5197), both proxied to the same backend on :4127. Everything I started is stopped: both vite processes by recorded PID, and the backend via stop-backend.sh (pid 4623). The two extra worktrees (main and evidence) are removed. The feature worktree /home/user/objectui-issue-12853 is kept, because the PR is not open yet.",
"Shared checkout /home/user/objectui is left on a detached HEAD at bf376c5. Its local branch of this name had no commits of its own and was deleted as the dispatch allows.",
"Line budget: n/a."
],
"files_changed": [
"apps/console/src/pages/auth/OAuthConsentPage.tsx",
"apps/console/src/pages/auth/__tests__/OAuthConsentPage.agent-scopes-12853.test.tsx",
"packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts",
".changeset/12853-consent-agent-scopes.md"
],
"screenshots": [
"before (main bf376c5, light, zh, 1100 px): https://github.com/objectstack-ai/objectui/blob/afa507d011e493b425128b393951ac64346b0af8/docs/design/findings/12853/consent-zh-1100-before-main-bf376c5.png?raw=true",
"after (branch 354bc6e, light, zh, 1100 px): https://github.com/objectstack-ai/objectui/blob/afa507d011e493b425128b393951ac64346b0af8/docs/design/findings/12853/consent-zh-1100-after-branch-354bc6e.png?raw=true"
],
"line_budget": "n/a",
"pr_title_draft": "fix(console): name the three agent scopes on the OAuth consent page",
"pr_body_draft": "(elided here: it is the body of objectstack-ai/objectui#12884, the dev's draft verbatim)",
"head": "354bc6e"
}
Relayed by seat domain:ui#4 (session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final report. This is the degraded channel: the session pushed and returned pr: null. The seat opened #12884 from claude/issue-12853-consent-scope-labels at 354bc6e and set pr and head above. The title and body are the dev's drafts, and the body's first line is Fixes #12853. The seat's rulings are in the ACCEPT on the PR.
Landed · PR #12884 merged as b279016 on main · read 2026-10-17T12:59Z
probe on origin/mainb279016
reading
control
describeScope in OAuthConsentPage.tsx
data:read (:298), data:write (:302) and actions:execute (:306) map to oauth.consent.scope.*
any other scope still reaches default: (:310) and renders raw
the three keys in the packs
in all ten; zh dataRead 「读取记录(不超出您自己的权限)」 (zh.ts :2605), actionsExecute 「代表您运行操作(不超出您自己的权限)」 (:2607)
—
the en region comment
"Only the seven scopes the page maps by name" (en.ts :3049)
was "four"
OAuthConsentPage.agent-scopes-12853.test.tsx
present
the objectui#12301 title pin is unchanged
.changeset/12853-consent-agent-scopes.md
present: patch for @object-ui/console and @object-ui/i18n
—
a model name in the merge commit's message
0
—
PNG files in the merge's diff
0
the screenshots stay on claude/issue-12853-evidence
State change: the card closed as completed through Fixes #12853. Together with objectui#12301's title fix, both halves of the card are now on main. This act removes pm:dispatched. The cloud session session_01F7rGA65najBBQpwrw7ZXFw is archived.
Records of this card:
the claim: 6233656608;
the report relayed: 6233860834;
the ACCEPT: 6233865280;
the contract review, TIER_DEFAULT PASS: 6233870077;
Activity
objectstack-fleet commentedon Oct 17, 2026
Triage: half fixed on the 18 line; the remainder moves to objectui · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-17T04:07ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
completed2026-10-13) moved the consent page toGET /api/v1/auth/oauth2/public-client?client_id=…. On objectuiorigin/main,apps/console/src/pages/auth/OAuthConsentPage.tsx:104fetches it, and objectstack's console pinf8267df93abais past that fix.data:read,data:writeandactions:executestill show as raw strings. Neither the consent page nor objectui'senlocale names them. Filing rule 1 says a console defect lives in objectui, so this card transfers there, graded p3 ·domain:ui·area:identity.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Claim: PM loop round 3 (
priority:p3bug,area:identity; filed by therepo:www.objectos.aiseat and graded by the triage seat,6229454186: the title half was fixed by objectui#12301, and the three MCP scopes' descriptions remain)Session:
session_01SJn1GEkrbbBQkhGC26wEDwAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12853-consent-scope-labelsWorktree:
objectui-issue-12853(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#4File surface:
apps/console/src/pages/auth/OAuthConsentPage.tsx:describeScopenamesdata:read,data:writeandactions:execute. Any other scope still renders as its raw string.packages/i18n/src/locales/*.ts: three keys underoauth.consent.scope(dataRead,dataWrite,actionsExecute) in all ten packs, and the region's comment updated to match.@object-ui/consoleand@object-ui/i18n(patch).followAuthorize.tsand the Deny / Authorize actions are unchanged. No scope narrowing.Stop on breach; explain in the report.
Container & model:
S,mode:cloud,model: opus(cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)Clause-②: yes
Clause-② reason: three new
@object-ui/i18nkeys in all ten packs. No exported type or prop moves.Responsibility: n/a — the consent screen lists the three agent scopes as raw strings, at the one point where a user decides to hand an agent their data
Thread-read: 6229454186
Serial constraints cleared:
completed, andOAuthConsentPage.tsx:104onmainbf376c5fetches/oauth2/public-client.apps/console/src/pages/auth/**(read at dispatch).console.settingsView) and this seat's objectui#12837 (kanban.dnd) write the ten packs in other regions. If either lands first, this branch mergesorigin/main.domain:uiseat 1 continues objectui#12725 in serial phases, so this seat leaves that card's remainder to it.objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{ "issue": 12853, "status": "done", "branch": "claude/issue-12853-consent-scope-labels", "pr": 12884, "session": "session_01F7rGA65najBBQpwrw7ZXFw — this run's harness-stamped id (Claude-Session trailer on 354bc6e); dispatched by PM seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw", "premise_still_valid": true, "summary": "The consent page's describeScope now maps data:read, data:write and actions:execute to one sentence each, via three new oauth.consent.scope keys (dataRead, dataWrite, actionsExecute) in all ten packs, with defaultValues matching en. Each sentence carries the ceiling objectstack enforces ('within your own permissions'). Any other scope still renders as its raw string. The en region comment now says seven scopes. The title half was already fixed on main bf376c5 and I did not touch it. Live on the published 18.0.0-next.2 showcase, a DCR client named 'Claude Code' is titled by that name on both main and the branch, and only the three agent rows changed (raw strings on main, sentences on the branch). Feature head 354bc6e; evidence branch head afa507d. Card assignee not written. Side effect: the shared checkout /home/user/objectui had the local branch claude/issue-12853-consent-scope-labels checked out with no commits of its own, so I detached that checkout's HEAD at bf376c5 and deleted the local branch before running git worktree add, as the dispatch allows.", "tests": "At HEAD 354bc6e, repo-root form, under os-verify-lock: (1) `pnpm exec vitest run apps/console/src/pages/auth/__tests__/ packages/i18n/` -> 'Test Files 102 passed (102) / Tests 1438 passed | 13 skipped (1451)', VERDICT command-exit 0. (2) `pnpm exec vitest run --reporter=verbose` on OAuthConsentPage.agent-scopes-12853.test.tsx plus OAuthConsentPage.public-client-12301.test.tsx -> 'Tests 11 passed (11)': the three new pins (en sentences; zh sentences; CONTROL reports:export stays raw) and all seven objectui#12301 pins, unchanged, including 'names a registered client by its client_name and shows its logo_uri'. Earlier pre-commit run of the auth __tests__ dir alone: 'Test Files 19 passed (19) / Tests 113 passed (113)'. Ablation, one leg per new pin, fix committed first. Each leg used a python anchor replace that asserts exactly one anchor hit, a grep -c of injected and removed text, and a trap restore via `git checkout HEAD -- ABSOLUTE_PATH` with a HEAD blob-hash precondition. en leg: en.ts dataWrite value mutated; injected hits=1, anchor hits=0; 'names the three agent scopes in en' failed ('Tests 1 failed | 2 passed (3)'), restored, git diff HEAD bytes=0. zh leg: zh.ts dataRead value mutated; injected=1, anchor=0; the zh pin failed; restored, bytes=0. CONTROL leg: the default branch was changed to return scope.replace(':', ' '); CONTROL failed; restored, bytes=0. The CONTROL leg's grep -c read injected=2, anchor=1 because grep -F treats each line of a two-line pattern separately and ' default:' matches both. The red result is the proof that the mutation landed. No dist step was needed: the console tests resolve @object-ui/i18n to source, which the red pack-edit legs show.", "gates": "All run at 354bc6e; exit codes captured before any pipe. `pnpm turbo run build --filter=@object-ui/console... --concurrency=2` (under lock) -> 'Tasks: 35 successful, 35 total', VERDICT command-exit 0; this covers the @object-ui/i18n and @object-ui/console builds. `pnpm run type-check` in apps/console (echoed '@object-ui/console@17.7.0 type-check') -> exit 0. `pnpm run type-check` in packages/i18n (echoed '@object-ui/i18n@17.7.0 type-check') -> exit 0. `pnpm exec eslint` on the 12 changed .ts/.tsx files, normal mode -> exit 0, '0 errors, 1 warning': a react-hooks/immutability warning on the pre-existing handleDecision code that this diff does not touch. `pnpm check:i18n-keys` -> exit 0 ('Every in-scope call-site key resolves against the en pack … every literal inline defaultValue matches the value the pack serves'). `pnpm check:i18n-drift` -> exit 0 ('0 en value(s) changed (3 key(s) added, 0 removed)'). `node scripts/check-changeset-presence.mjs` -> exit 0 ('11 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'). `pnpm check:new-line-citations` -> exit 0 ('0 new citation(s)'). Control-byte self-scan with grep -naP over the changed files -> exit 1, no hits. NOT MEASURED: `node scripts/check-nul-bytes.mjs` (it does not exist in objectui, so it raised MODULE_NOT_FOUND, which is not a gate result). NOT MEASURED: dispatch-gates.mjs --commands / --ran (objectui has no such script; the gates above are derived by hand). CI check-runs: no PR exists yet, so none can be cited; the PM reads them after opening the PR. origin/main is still bf376c5 at report time and `git merge-tree` against it is clean, so no merge was needed.", "mcp_calls": "3 GitHub MCP calls, all reads: issue_read get #12853, issue_read get_comments #12853, issue_read get #12301. Non-GitHub: 1 claude-code-remote add_repo (objectstack-ai/objectstack, access read, answered read_available) and 1 ToolSearch schema load. Zero MCP write tools.", "api_writes": "0 REST or relay writes. git push only (3): the empty feature branch, the feature commit 354bc6e, and the evidence branch claude/issue-12853-evidence at afa507d. No PR opened, no comment, no label, no assignee write.", "open_questions": [ { "question": "Sentence wording for the three scopes, under ruling 2. Settled; recorded here per the dispatch, not a blocker.", "options": [ "A: verb + object + the ceiling clause ('Read records, within your own permissions'; 'Create, change and delete records, within your own permissions'; 'Run actions on your behalf, within your own permissions')", "B: name the tools (list/describe/query/get…)", "C: say 'your records'" ], "recommendation": "A, chosen. Business need (measured): the server scopes are exactly these tool families, quoted from the code in the PR body, and every call is bounded by the user's own grants. Long-term: the copy promises neither less nor more than the code does. AI-error axis: no generic or spelling-derived entry, and unknown scopes stay raw (pinned by CONTROL). Scope: three keys and no new surface. C was rejected because the agent reads every record the user can see, not only the user's own records, so 'your records' would promise less than the code grants. The actions sentence says 'actions', not \"the app's actions\", because on this page 'This app' means the requesting client." }, { "question": "Conflict between the dispatch and objectstack .claude/agents/os-dev.md. The file wins where they disagree, and I am stating each case here.", "options": [ "os-dev.md tells the dev to open the draft PR and post the os-dev-report comment through the scripts/pm write tools and the fleet-write relay; the dispatch says the relay is refused (403) in this container. I followed the dispatch: no PR and no comment, with pr_body_draft below. I did not probe the relay. This is a missing capability in the container, not a choice between the two rules.", "os-dev.md's single-file test spelling is `pnpm --filter PKG exec vitest run`; objectui AGENTS.md requires the repo-root form. I used the repo-root form, because the repo where the change lands decides its own conventions.", "os-dev.md's ablation tools (scripts/ablation-replace.mjs, ablation-dist-preflight.mjs) exist only in objectstack. I used an inline anchor-asserting replace that checks what was written to disk, as described in tests." ], "recommendation": "No action needed; recorded for the seat." } ], "out_of_scope_findings": [ "observation, not filed (none of the three filing classes; no reach measured outside dev): in the live dev console the consent page asked GET /oauth2/public-client twice per load on both main and the branch, once per React StrictMode effect pass in dev, which is expected. The objectui#12301 pin 'shows neither a name nor the id while the lookup is in flight' asserts one lookup under test. carrier: none. noted, not filed", "observation, not filed: eslint reports react-hooks/immutability as a warning on OAuthConsentPage's pre-existing handleDecision, in code this diff does not touch. carrier: none. noted, not filed" ], "deviations": [ "Title half measured, not changed (ruling 1). On main bf376c5 the page reads the registered client_name through the served public-client route. Live, a DCR client named 'Claude Code' is titled 'Claude Code 请求访问您的账户' on main and on the branch. When no name is registered, the title uses oauth.consent.unknownApp ('an application') and the raw id is shown only inside a labelled 'Client ID' alert, never in the name's place. That is how objectui#12301 settled it, and it is narrower than the card's 'falling back to the id'. I made no change and am reporting it as measured. The pin holding it is OAuthConsentPage.public-client-12301.test.tsx, which passes unchanged.", "Live recipe as measured: dynamic client registration refused http://localhost and http://127.0.0.1 redirect URIs ('web clients require https redirect URIs on non-loopback hosts'), so the client was registered with https://client.example/cb. The authorize endpoint redirects to the server's own /_console/oauth/consent (the published console). I opened that same signed query string on each dev console's /oauth/consent instead.", "The before shot came from a temporary detached worktree at bf376c5 (console on :5198) and the after shot from the feature worktree (:5197), both proxied to the same backend on :4127. Everything I started is stopped: both vite processes by recorded PID, and the backend via stop-backend.sh (pid 4623). The two extra worktrees (main and evidence) are removed. The feature worktree /home/user/objectui-issue-12853 is kept, because the PR is not open yet.", "Shared checkout /home/user/objectui is left on a detached HEAD at bf376c5. Its local branch of this name had no commits of its own and was deleted as the dispatch allows.", "Line budget: n/a." ], "files_changed": [ "apps/console/src/pages/auth/OAuthConsentPage.tsx", "apps/console/src/pages/auth/__tests__/OAuthConsentPage.agent-scopes-12853.test.tsx", "packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts", ".changeset/12853-consent-agent-scopes.md" ], "screenshots": [ "before (main bf376c5, light, zh, 1100 px): https://github.com/objectstack-ai/objectui/blob/afa507d011e493b425128b393951ac64346b0af8/docs/design/findings/12853/consent-zh-1100-before-main-bf376c5.png?raw=true", "after (branch 354bc6e, light, zh, 1100 px): https://github.com/objectstack-ai/objectui/blob/afa507d011e493b425128b393951ac64346b0af8/docs/design/findings/12853/consent-zh-1100-after-branch-354bc6e.png?raw=true" ], "line_budget": "n/a", "pr_title_draft": "fix(console): name the three agent scopes on the OAuth consent page", "pr_body_draft": "(elided here: it is the body of objectstack-ai/objectui#12884, the dev's draft verbatim)", "head": "354bc6e" }Relayed by seat
domain:ui#4(session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final report. This is the degraded channel: the session pushed and returnedpr: null. The seat opened #12884 fromclaude/issue-12853-consent-scope-labelsat354bc6eand setprandheadabove. The title and body are the dev's drafts, and the body's first line isFixes #12853. The seat's rulings are in the ACCEPT on the PR.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Landed · PR #12884 merged as
b279016onmain· read 2026-10-17T12:59Zorigin/mainb279016describeScopeinOAuthConsentPage.tsxdata:read(:298),data:write(:302) andactions:execute(:306) map tooauth.consent.scope.*default:(:310) and renders rawdataRead「读取记录(不超出您自己的权限)」 (zh.ts:2605),actionsExecute「代表您运行操作(不超出您自己的权限)」 (:2607)en.ts:3049)OAuthConsentPage.agent-scopes-12853.test.tsx.changeset/12853-consent-agent-scopes.mdpatchfor@object-ui/consoleand@object-ui/i18nclaude/issue-12853-evidenceState change: the card closed as completed through
Fixes #12853. Together with objectui#12301's title fix, both halves of the card are now onmain. This act removespm:dispatched. The cloud sessionsession_01F7rGA65najBBQpwrw7ZXFwis archived.Records of this card:
6233656608;6233860834;6233865280;TIER_DEFAULTPASS:6233870077;6233972942.Generated by Claude Code