Source: PRD-018 SC-2 audit, Logic [W1] + Security [W1].
template/src/widgets/health-bar/ui/HealthBar.svelte:39-48
async function onToggleNotify(next: boolean) {
if (next && permission === 'default') {
const result = await Notification.requestPermission();
permission = result;
notify = result === 'granted';
return;
}
notify = next && permission === 'granted';
}
Between await Notification.requestPermission() and the assignment to notify, the user can re-toggle the Toggle. The second invocation reads stale permission and may write the wrong final state. bits-ui will also optimistically flip pressed → true during the await, then snap back if denied — which feels glitchy.
Repro
- Click "🔔 Notify" with
permission === 'default'.
- Before the permission prompt resolves, click again.
- Observe inconsistent final state vs the actual permission outcome.
Fix
- Disable the Toggle while a request is in flight (
disabled={requesting}); set requesting = true before await, false after.
- Bind
pressed strictly to a $derived of notify && permission === 'granted' so it never optimistically flips.
- Confirm
Toggle.pressed non-bindable usage matches the primitive's contract (declared pressed = $bindable(false) — see Logic [W2]).
Acceptance
- Rapid double-click on the Toggle during the permission prompt cannot produce a state where
pressed and permission disagree.
- No visual flicker between optimistic
pressed=true and the final value.
Audit traceability
- Reviewers: Logic, Security
Source: PRD-018 SC-2 audit, Logic [W1] + Security [W1].
template/src/widgets/health-bar/ui/HealthBar.svelte:39-48Between
await Notification.requestPermission()and the assignment tonotify, the user can re-toggle the Toggle. The second invocation reads stalepermissionand may write the wrong final state. bits-ui will also optimistically flippressed → trueduring the await, then snap back if denied — which feels glitchy.Repro
permission === 'default'.Fix
disabled={requesting}); setrequesting = truebeforeawait,falseafter.pressedstrictly to a$derivedofnotify && permission === 'granted'so it never optimistically flips.Toggle.pressednon-bindable usage matches the primitive's contract (declaredpressed = $bindable(false)— see Logic [W2]).Acceptance
pressedandpermissiondisagree.pressed=trueand the final value.Audit traceability