Repository navigation
Android settings permission response: one permissions list for changed ids, not permission: "a,b" #2701
Description
Purpose
Android reports which permission ids a call actually changed under two different field names, and one of them is comma-joined text inside a field typed singular. A consumer that wants the changed ids has to know which target shape produced the response and then split a string.
One Android target legitimately expands to several ids: location is ACCESS_FINE_LOCATION + ACCESS_COARSE_LOCATION, photos resolves to a media candidate at runtime. So "what I asked for" and "what changed" are different facts, and only all currently reports the second one as a list.
Current shape
packages/platform-android/src/settings-permission.ts:
| Path | Response |
|---|---|
| named target revoke (~L145) | { permission: revoked.join(','), priorGrantState, warnings? } |
declared pm target revoke (~L527) |
{ permission: [...values].join(','), priorGrantState, warnings? } |
target all (~L191) |
{ permission: 'all', applied, warnings? } |
| not-requested error details (~L506) | { appPackage, permission: values.join(',') } |
Input side, packages/contracts/src/client-settings.ts (~L59) declares the request as permission: PermissionTarget — a single target — while SettingOptions.permissionTarget (packages/contracts/src/settings.ts ~L50, src/daemon/handlers/snapshot-settings.ts ~L30) is a bare string. The wire carries one target; only the platform knows the expansion.
Required behavior
One field for "ids this call changed", named the same on every path:
// named target, multi-id expansion
{ permission: 'location', permissions: ['android.permission.ACCESS_FINE_LOCATION', 'android.permission.ACCESS_COARSE_LOCATION'], priorGrantState: 'granted' }
// target all
{ permission: 'all', permissions: [...], warnings?: [...] }permissions: string[]carries the ids actually mutated, in the order applied.permissionkeeps meaning the requested target.appliedfolds intopermissions; do not keep it as a long-lived alias.- Error details use
permissions: valuesinstead of a joined string. - Mirror the shape in the public client types and the versioned help, and update
website/docs/docs/commands.md— it currently documentspriorGrantState(L738) without stating the id-list field. - Add a CHANGELOG entry under Changed.
Before preserving any compatibility alias, run git tag --contains on the introducing commits in a clone with full history (AGENTS.md: unreleased API has no external compatibility obligation). cf1f91da49 introduced the joined permission for revoke; this could not be settled from a shallow clone, so decide it there rather than defaulting to an alias.
Observable completion
- No
.join(',')in a response or error-detail field insettings-permission.ts. pnpm vitest run packages/platform-android/src/__tests__/settings-permission.test.ts src/commands/capture/settings.test.tsgreen, with a new test asserting alocationdeny reports both location ids inpermissions.- The Android provider scenario for permissions asserts the list shape end to end, not a split of
permission. pnpm check:quick,pnpm check:command-docs,pnpm formatclean.
Dependencies
No blocker. Split out of #2363 so a maestro/iOS change did not also rewrite the Android response contract. Related to #2700 but independent: that issue owns skip-vs-abort classification, this one owns the response shape.
Activity
refactor(platform-android): report changed permission ids, not a join…
refactor(platform-android)!: report changed permission ids, not a joi…