refactor(permissions): extract resolveWithStored — pure + unit-testable
The interaction between policy and stored decisions had a non-obvious
invariant ("stored decisions only override 'prompt'") that lived
inline in `permission-handler.ts`'s setPermissionRequestHandler
callback. That made it integration-testable but not unit-testable —
the only coverage for "stored allow can never override hard-deny"
was a Playwright run.
Extracted into `permission-policy.ts:resolveWithStored(url, permission,
lookupStored)`:
* Takes the same URL + permission as `resolveDecision`, plus a
pure callback that returns `boolean | null` for the stored
decision (no module-scoped state, no electron deps).
* Returns the FINAL `Decision` the request handler should act on.
* Skips the lookup entirely for hard-allow / hard-deny / empty
origin paths.
`permission-handler.ts` is now a one-line call into this helper +
the existing logging + callback + UI surface.
Unit coverage (`tests/unit/permission-handler.test.js` 22/22, +9):
* chrome-extension origin: stored deny is ignored (policy allow
wins).
* peek:// origin: stored deny is ignored (policy allow wins).
* hard-deny permission (e.g. usb): stored allow is ignored
(policy deny wins).
* prompt + stored allow: returns allow.
* prompt + stored deny: returns deny.
* prompt + no stored: returns prompt.
* prompt + empty origin: skips lookup (asserts the lookup
callback was NOT called), returns prompt.
* lookup is only called for prompt decisions (hard-allow + hard-
deny paths skip it — proven by tracking call count).
* lookup receives the parsed origin (not the full URL) and the
raw permission name.
Integration regression: permission-prompt 6/6 still green.