A new "Punktfunk" library shortcut on every plugin load (79dba7f9)
Reported from the field: each Steam start added another visible "Punktfunk" entry — plain to see in the desktop client's library.
Mechanism:db063792 (shipped in 0.26.0/0.27.0) made shortcutStillExists() actually answer for the first time, and its callers treat a null overview as "the user deleted the shortcut". But the plugin mounts while Steam is still starting up, before appStore has registered its overviews, so the remembered — perfectly live — appId looks up as null on every boot: mint a duplicate, remember the new id, orphan yesterday's.
The deleted verdict now has to be earned, and creation is a last resort:
shortcutStillExists() only believes "absent" once the store is demonstrably hydrated: wait out App.WaitForServicesInitialized (raced against the poll budget so a wedged signal can't hang the guard), poll until allApps is non-empty, then one grace recheck. Unverifiable within budget answers true: a false "alive" merely no-ops until the next ask, a false "dead" duplicates forever.
On a genuinely lost id, both ensure paths first adopt an existing same-named shortcut (excluding the other role's) instead of minting an N+1th — which also heals installs the old builds already littered.
Both ensures are single-flight: mount's fire-and-forget can now be mid-wait when a QAM press arrives, and two ensures racing past the liveness check would each AddShortcut.
"Recreate library shortcut" additionally sweeps surplus "Punktfunk" shortcuts (RemoveShortcut) and toasts the count — the cleanup path for piles already minted. Deliberately button-only, never mount.
Affected installs keep their pile until this ships and they press the button (or delete by hand).
Too many toasts (339a1d70)
Inventory of all 14 toast sites: almost all are rare, explicit-tap feedback. Two were routine-volume offenders:
startStream toasted "Starting stream — host" on every successful launch — the overwhelming majority of all toasts the plugin ever shows, repeating the button just pressed and landing on top of the starting stream. Gone; launch failures still toast.
useHosts.refresh() toasted "Couldn't list hosts" from its catch, and the panel remounts (and refreshes) on every QAM open — a broken backend nagged on each open. Now a third inline problem row next to the Refresh button that retries it, like the client-unavailable/outdated states.
Verification
tsc --noEmit and the rollup bundle pass (also re-run after merging main). The launch paths hit the fast path unchanged — a live overview answers the first query and nothing waits. Not yet exercised on a physical Deck; a boot-loop test there (deploy + two Steam restarts, count library entries) is the definitive check before tagging.
Two field complaints, both in the Decky plugin.
## A new "Punktfunk" library shortcut on every plugin load (`79dba7f9`)
Reported from the field: each Steam start added another visible "Punktfunk" entry — plain to see in the desktop client's library.
**Mechanism:** `db063792` (shipped in 0.26.0/0.27.0) made `shortcutStillExists()` actually answer for the first time, and its callers treat a null overview as "the user deleted the shortcut". But the plugin mounts while Steam is still starting up, **before `appStore` has registered its overviews**, so the remembered — perfectly live — appId looks up as null on every boot: mint a duplicate, remember the new id, orphan yesterday's.
The deleted verdict now has to be earned, and creation is a last resort:
- `shortcutStillExists()` only believes "absent" once the store is demonstrably hydrated: wait out `App.WaitForServicesInitialized` (raced against the poll budget so a wedged signal can't hang the guard), poll until `allApps` is non-empty, then one grace recheck. Unverifiable within budget answers **true**: a false "alive" merely no-ops until the next ask, a false "dead" duplicates forever.
- On a genuinely lost id, both ensure paths first **adopt** an existing same-named shortcut (excluding the other role's) instead of minting an N+1th — which also heals installs the old builds already littered.
- Both ensures are single-flight: mount's fire-and-forget can now be mid-wait when a QAM press arrives, and two ensures racing past the liveness check would each `AddShortcut`.
- "Recreate library shortcut" additionally **sweeps surplus "Punktfunk" shortcuts** (`RemoveShortcut`) and toasts the count — the cleanup path for piles already minted. Deliberately button-only, never mount.
Affected installs keep their pile until this ships **and** they press the button (or delete by hand).
## Too many toasts (`339a1d70`)
Inventory of all 14 toast sites: almost all are rare, explicit-tap feedback. Two were routine-volume offenders:
- `startStream` toasted "Starting stream — host" on **every successful launch** — the overwhelming majority of all toasts the plugin ever shows, repeating the button just pressed and landing on top of the starting stream. Gone; launch *failures* still toast.
- `useHosts.refresh()` toasted "Couldn't list hosts" from its catch, and the panel remounts (and refreshes) on **every QAM open** — a broken backend nagged on each open. Now a third inline `problem` row next to the Refresh button that retries it, like the client-unavailable/outdated states.
## Verification
`tsc --noEmit` and the rollup bundle pass (also re-run after merging main). The launch paths hit the fast path unchanged — a live overview answers the first query and nothing waits. Not yet exercised on a physical Deck; a boot-loop test there (deploy + two Steam restarts, count library entries) is the definitive check before tagging.
Field report: each Steam start added another visible "Punktfunk" entry
(spotted in the desktop client, where the pile is plain to see).
Mechanism: db063792 made shortcutStillExists() actually answer for the
first time — and its callers treat a null overview as "the user deleted
the shortcut" and AddShortcut a replacement. But the plugin mounts while
Steam is still starting up, BEFORE appStore has registered its overviews,
so the remembered (perfectly live) appId looks up as null on every boot:
mint a duplicate, remember the new id, orphan yesterday's. One new entry
per load, forever.
The deleted verdict now has to be earned, and creation is a last resort:
* shortcutStillExists() only believes "absent" once the store is
demonstrably hydrated: wait out App.WaitForServicesInitialized (raced
against the poll budget so a wedged signal can't hang the guard),
poll until allApps is non-empty, then one grace recheck — overview
registration can trail the bulk hydration. Unverifiable within budget
answers true: a false "alive" merely no-ops until the next ask, a
false "dead" duplicates forever.
* On a genuinely lost id, both ensure paths first ADOPT an existing
same-named shortcut (excluding the other role's) instead of minting
an N+1th — which also heals installs the old builds already littered.
* Both ensures are single-flight: mount's fire-and-forget can now be
mid-wait when a QAM press arrives, and two ensures racing past the
liveness check would each AddShortcut.
* "Recreate library shortcut" additionally sweeps surplus "Punktfunk"
shortcuts (RemoveShortcut) and toasts the count — cleanup for piles
already minted. Deliberately button-only, never mount: automatic
library deletion at boot is a bigger hazard than the mess.
Verified: tsc --noEmit and the rollup bundle both pass; the launch paths
(launchStream / launchGamepadUi) hit the fast path unchanged — a live
overview answers the first query and nothing waits.
Field complaint: the plugin toasts too much. Inventory of all 14 toast
sites says almost all are rare, explicit-tap feedback (pairing, update
buttons, recovery actions) — but two were routine-volume offenders:
* startStream toasted "Starting stream — <host>" on EVERY successful
launch, i.e. the overwhelming majority of all toasts the plugin ever
shows. It repeats the button the user just pressed, and lands ON TOP
of the starting stream after the QAM closes. Gone; launch FAILURES
still toast (the QAM may already be closed, so inline state would go
unseen).
* useHosts.refresh() toasted "Couldn't list hosts" from its catch —
and the panel remounts (and refreshes) on every QAM open, so a broken
backend nagged on each open. It's now a third inline `problem` row
("Couldn't scan for hosts"), sitting next to the Refresh button that
retries it, like the client-unavailable/client-outdated states
already did.
The update-flow, pairing, trust and recovery toasts stay: each is a rare,
single, information-carrying response to an explicit tap (or, for the
request-access hint, the only warning that the connect is about to park).
Verified: tsc --noEmit and the rollup bundle pass.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two field complaints, both in the Decky plugin.
A new "Punktfunk" library shortcut on every plugin load (
79dba7f9)Reported from the field: each Steam start added another visible "Punktfunk" entry — plain to see in the desktop client's library.
Mechanism:
db063792(shipped in 0.26.0/0.27.0) madeshortcutStillExists()actually answer for the first time, and its callers treat a null overview as "the user deleted the shortcut". But the plugin mounts while Steam is still starting up, beforeappStorehas registered its overviews, so the remembered — perfectly live — appId looks up as null on every boot: mint a duplicate, remember the new id, orphan yesterday's.The deleted verdict now has to be earned, and creation is a last resort:
shortcutStillExists()only believes "absent" once the store is demonstrably hydrated: wait outApp.WaitForServicesInitialized(raced against the poll budget so a wedged signal can't hang the guard), poll untilallAppsis non-empty, then one grace recheck. Unverifiable within budget answers true: a false "alive" merely no-ops until the next ask, a false "dead" duplicates forever.AddShortcut.RemoveShortcut) and toasts the count — the cleanup path for piles already minted. Deliberately button-only, never mount.Affected installs keep their pile until this ships and they press the button (or delete by hand).
Too many toasts (
339a1d70)Inventory of all 14 toast sites: almost all are rare, explicit-tap feedback. Two were routine-volume offenders:
startStreamtoasted "Starting stream — host" on every successful launch — the overwhelming majority of all toasts the plugin ever shows, repeating the button just pressed and landing on top of the starting stream. Gone; launch failures still toast.useHosts.refresh()toasted "Couldn't list hosts" from its catch, and the panel remounts (and refreshes) on every QAM open — a broken backend nagged on each open. Now a third inlineproblemrow next to the Refresh button that retries it, like the client-unavailable/outdated states.Verification
tsc --noEmitand the rollup bundle pass (also re-run after merging main). The launch paths hit the fast path unchanged — a live overview answers the first query and nothing waits. Not yet exercised on a physical Deck; a boot-loop test there (deploy + two Steam restarts, count library entries) is the definitive check before tagging.Field complaint: the plugin toasts too much. Inventory of all 14 toast sites says almost all are rare, explicit-tap feedback (pairing, update buttons, recovery actions) — but two were routine-volume offenders: * startStream toasted "Starting stream — <host>" on EVERY successful launch, i.e. the overwhelming majority of all toasts the plugin ever shows. It repeats the button the user just pressed, and lands ON TOP of the starting stream after the QAM closes. Gone; launch FAILURES still toast (the QAM may already be closed, so inline state would go unseen). * useHosts.refresh() toasted "Couldn't list hosts" from its catch — and the panel remounts (and refreshes) on every QAM open, so a broken backend nagged on each open. It's now a third inline `problem` row ("Couldn't scan for hosts"), sitting next to the Refresh button that retries it, like the client-unavailable/client-outdated states already did. The update-flow, pairing, trust and recovery toasts stay: each is a rare, single, information-carrying response to an explicit tap (or, for the request-access hint, the only warning that the connect is about to park). Verified: tsc --noEmit and the rollup bundle pass.