Field report: "the decky plugin still seems to only update itself, and not the actual client."
The code has been on main since 21787ca6 (07-31, shipped in v0.25.0). What was broken is the detection — the QAM has offered to update the client since 0.24 and has answered "up to date" on every Deck, every time, including on a Deck whose client was a day out of date.
Root cause
The check compares the installed OSTree commit against the remote's, and it asked for the remote one with no branch:
flatpak remote-info --user punktfunk-origin io.unom.Punktfunk
→ error: Multiple branches available for io.unom.Punktfunk,
you must specify one of: …/stable, …/canary
remote-info resolves against the remote, and the punktfunk remote publishes both stable and canary, so the ref is ambiguous and flatpak refuses it rather than picking one. ⚠ Having only one branch installed does not help — the ambiguity is on the remote side. The Deck this was found on has only canary and still hit it.
Then _client_update_state treated the non-zero exit as "remote unreachable — treat as up to date, retry next check", so a call that failed 100 % of the time rendered as good news.
The tell was in the plugin's own log all along, and is easy to read past:
client-> is empty — no remote commit ever arrived. A genuine up-to-date has a commit there.
By contrast info <id> and update <id> resolve against installed refs, so those were fine with one branch installed and ambiguous only with two (the 08-05 stale-branch trap). This change qualifies all three, so both cases are covered.
What changed
New _flatpak_ref() resolves scope + branch once, off the exported tree (~/.local/share/flatpak/app/<id>/x86_64/<branch>/active, then /var/lib/flatpak). No subprocess — _client_argv is on the path of every headless call. The active symlink is what separates an install from the leftovers of one.
info / remote-info / update all take <scope> + io.unom.Punktfunk//<branch>.
The scope was hardcoded --user: a system-wide install was invisible to the check, andupdate_client would run a user-scope update that touched nothing and report "already up to date". Both scopes work now.
The launcher pins the same --branch= (app id stays last, so _cli_argv's --command= rewrite still holds) ⇒ the client we start is the client we check and the client we update. That also closes the stale-branch trap where a leftover stable silently won the launch.
A check that cannot run now reports client_error instead of "up to date" — the flatpak leg finally matches the contract the native leg already had. Dressing that failure up as good news is the entire reason this went unnoticed.
The button no longer promises "+ client" when the client is manual-only and the tap can only print a command.
Verification
Both code paths run against the real install on the Deck (192.168.1.253, canary, user scope), minutes apart:
available
remote
pre-fix (ships today)
False
''
post-fix
True
ca010668 (installed e22af40f)
flatpak {info,remote-info,update} all accept the id//branch form there. 37 backend checks pass, 6 of them new and about exactly this (python3.13 clients/decky/scripts/test-backend.py — macOS 3.9 chokes on X | None). Frontend tsc + rollup build green.
Not in scope, but found while checking
The native one-tap path (apt/dnf/pacman/rpm-ostree via the packaged root helper) has still never been exercised on real hardware — owed since the feature was built, not affected by this change. No box available has a packaged client.
pf_update_check::detect::update_command(Flatpak) emits flatpak update --user io.unom.Punktfunk, advertised in its own doc comment as "copy-pastable"; it breaks in the two-branches-installed case. Low severity (only reachable for a flatpak user not going through the plugin). /.flatpak-info carries branch=, so it can be fixed properly rather than by guessing a default.
Still owed
On-glass one-click run, which needs the fixed plugin installed on a Deck — ~/homebrew/plugins is root-owned and deck sudo wants a password.
Field report: *"the decky plugin still seems to only update itself, and not the actual client."*
The code has been on main since `21787ca6` (07-31, shipped in v0.25.0). What was broken is the **detection** — the QAM has offered to update the client since 0.24 and has answered "up to date" on every Deck, every time, including on a Deck whose client was a day out of date.
## Root cause
The check compares the installed OSTree commit against the remote's, and it asked for the remote one with no branch:
```
flatpak remote-info --user punktfunk-origin io.unom.Punktfunk
→ error: Multiple branches available for io.unom.Punktfunk,
you must specify one of: …/stable, …/canary
```
`remote-info` resolves against the **remote**, and the punktfunk remote publishes both `stable` and `canary`, so the ref is ambiguous and flatpak refuses it rather than picking one. ⚠ **Having only one branch installed does not help — the ambiguity is on the remote side.** The Deck this was found on has only `canary` and still hit it.
Then `_client_update_state` treated the non-zero exit as *"remote unreachable — treat as up to date, retry next check"*, so a call that failed 100 % of the time rendered as good news.
The tell was in the plugin's own log all along, and is easy to read past:
```
updates: plugin 0.25.11835->0.26.12264 (avail=True), client-> (avail=False)
```
`client->` is **empty** — no remote commit ever arrived. A genuine up-to-date has a commit there.
By contrast `info <id>` and `update <id>` resolve against *installed* refs, so those were fine with one branch installed and ambiguous only with two (the 08-05 stale-branch trap). This change qualifies all three, so both cases are covered.
## What changed
- New `_flatpak_ref()` resolves **scope + branch** once, off the exported tree (`~/.local/share/flatpak/app/<id>/x86_64/<branch>/active`, then `/var/lib/flatpak`). No subprocess — `_client_argv` is on the path of every headless call. The `active` symlink is what separates an install from the leftovers of one.
- `info` / `remote-info` / `update` all take `<scope>` + `io.unom.Punktfunk//<branch>`.
- The **scope** was hardcoded `--user`: a system-wide install was invisible to the check, *and* `update_client` would run a user-scope update that touched nothing and report "already up to date". Both scopes work now.
- The launcher pins the same `--branch=` (app id stays last, so `_cli_argv`'s `--command=` rewrite still holds) ⇒ the client we start is the client we check and the client we update. That also closes the stale-branch trap where a leftover `stable` silently won the launch.
- A check that cannot run now reports `client_error` instead of "up to date" — the flatpak leg finally matches the contract the native leg already had. Dressing that failure up as good news is the entire reason this went unnoticed.
- The button no longer promises "+ client" when the client is manual-only and the tap can only print a command.
## Verification
Both code paths run against the real install on the Deck (`192.168.1.253`, canary, user scope), minutes apart:
| | `available` | `remote` |
|---|---|---|
| pre-fix (ships today) | `False` | `''` |
| post-fix | `True` | `ca010668` (installed `e22af40f`) |
`flatpak {info,remote-info,update}` all accept the `id//branch` form there. 37 backend checks pass, 6 of them new and about exactly this (`python3.13 clients/decky/scripts/test-backend.py` — macOS 3.9 chokes on `X | None`). Frontend `tsc` + rollup build green.
## Not in scope, but found while checking
- The **native one-tap** path (apt/dnf/pacman/rpm-ostree via the packaged root helper) has still never been exercised on real hardware — owed since the feature was built, not affected by this change. No box available has a packaged client.
- `pf_update_check::detect::update_command(Flatpak)` emits `flatpak update --user io.unom.Punktfunk`, advertised in its own doc comment as "copy-pastable"; it breaks in the two-branches-installed case. Low severity (only reachable for a flatpak user not going through the plugin). `/.flatpak-info` carries `branch=`, so it can be fixed properly rather than by guessing a default.
## Still owed
On-glass one-click run, which needs the fixed plugin installed on a Deck — `~/homebrew/plugins` is root-owned and `deck` sudo wants a password.
The QAM has offered to update the client since 0.24, and on every Deck it has
answered "up to date" — including right now, with a client a day out of date.
The check asks flatpak for the remote's commit and compares it to the installed
one, and it named the app id with no branch: `flatpak remote-info punktfunk-origin
io.unom.Punktfunk`. The punktfunk remote publishes `stable` AND `canary`, so that
ref is ambiguous and flatpak refuses it — "Multiple branches available" — rather
than picking one. One branch INSTALLED does not help; the ambiguity is on the
remote. The call failed on every box, every time, and the failure returned
`available=False`, which the panel renders as good news. Hence: the plugin
appeared to update only itself.
Every query now names the ref in full, resolved once by `_flatpak_ref()` off the
exported tree (no subprocess — `_client_argv` is on the path of every headless
call). That resolution also carries the SCOPE, so a system-wide install is no
longer invisible to a check that hardcoded `--user`, and the launcher pins the
same `--branch=`, so the client we start is the client we check and update.
A check that cannot run now says so instead of reporting up-to-date: the flatpak
leg reports `client_error` exactly as the native leg already did. Dressing that
failure up as good news is the whole reason this went a week unnoticed.
Also: the button no longer promises "+ client" when the client is manual-only and
the tap can only print a command.
Verified on the Deck (192.168.1.253, canary, user scope) by running both code
paths against the real install, minutes apart:
pre-fix available=False remote=''
post-fix available=True remote=ca010668 (installed e22af40f)
and `flatpak {info,remote-info,update}` all accept the `id//branch` form there.
37 backend checks pass, 6 of them new and about exactly this.
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.
Field report: "the decky plugin still seems to only update itself, and not the actual client."
The code has been on main since
21787ca6(07-31, shipped in v0.25.0). What was broken is the detection — the QAM has offered to update the client since 0.24 and has answered "up to date" on every Deck, every time, including on a Deck whose client was a day out of date.Root cause
The check compares the installed OSTree commit against the remote's, and it asked for the remote one with no branch:
remote-inforesolves against the remote, and the punktfunk remote publishes bothstableandcanary, so the ref is ambiguous and flatpak refuses it rather than picking one. ⚠ Having only one branch installed does not help — the ambiguity is on the remote side. The Deck this was found on has onlycanaryand still hit it.Then
_client_update_statetreated the non-zero exit as "remote unreachable — treat as up to date, retry next check", so a call that failed 100 % of the time rendered as good news.The tell was in the plugin's own log all along, and is easy to read past:
client->is empty — no remote commit ever arrived. A genuine up-to-date has a commit there.By contrast
info <id>andupdate <id>resolve against installed refs, so those were fine with one branch installed and ambiguous only with two (the 08-05 stale-branch trap). This change qualifies all three, so both cases are covered.What changed
_flatpak_ref()resolves scope + branch once, off the exported tree (~/.local/share/flatpak/app/<id>/x86_64/<branch>/active, then/var/lib/flatpak). No subprocess —_client_argvis on the path of every headless call. Theactivesymlink is what separates an install from the leftovers of one.info/remote-info/updateall take<scope>+io.unom.Punktfunk//<branch>.--user: a system-wide install was invisible to the check, andupdate_clientwould run a user-scope update that touched nothing and report "already up to date". Both scopes work now.--branch=(app id stays last, so_cli_argv's--command=rewrite still holds) ⇒ the client we start is the client we check and the client we update. That also closes the stale-branch trap where a leftoverstablesilently won the launch.client_errorinstead of "up to date" — the flatpak leg finally matches the contract the native leg already had. Dressing that failure up as good news is the entire reason this went unnoticed.Verification
Both code paths run against the real install on the Deck (
192.168.1.253, canary, user scope), minutes apart:availableremoteFalse''Trueca010668(installede22af40f)flatpak {info,remote-info,update}all accept theid//branchform there. 37 backend checks pass, 6 of them new and about exactly this (python3.13 clients/decky/scripts/test-backend.py— macOS 3.9 chokes onX | None). Frontendtsc+ rollup build green.Not in scope, but found while checking
pf_update_check::detect::update_command(Flatpak)emitsflatpak update --user io.unom.Punktfunk, advertised in its own doc comment as "copy-pastable"; it breaks in the two-branches-installed case. Low severity (only reachable for a flatpak user not going through the plugin)./.flatpak-infocarriesbranch=, so it can be fixed properly rather than by guessing a default.Still owed
On-glass one-click run, which needs the fixed plugin installed on a Deck —
~/homebrew/pluginsis root-owned anddecksudo wants a password.The QAM has offered to update the client since 0.24, and on every Deck it has answered "up to date" — including right now, with a client a day out of date. The check asks flatpak for the remote's commit and compares it to the installed one, and it named the app id with no branch: `flatpak remote-info punktfunk-origin io.unom.Punktfunk`. The punktfunk remote publishes `stable` AND `canary`, so that ref is ambiguous and flatpak refuses it — "Multiple branches available" — rather than picking one. One branch INSTALLED does not help; the ambiguity is on the remote. The call failed on every box, every time, and the failure returned `available=False`, which the panel renders as good news. Hence: the plugin appeared to update only itself. Every query now names the ref in full, resolved once by `_flatpak_ref()` off the exported tree (no subprocess — `_client_argv` is on the path of every headless call). That resolution also carries the SCOPE, so a system-wide install is no longer invisible to a check that hardcoded `--user`, and the launcher pins the same `--branch=`, so the client we start is the client we check and update. A check that cannot run now says so instead of reporting up-to-date: the flatpak leg reports `client_error` exactly as the native leg already did. Dressing that failure up as good news is the whole reason this went a week unnoticed. Also: the button no longer promises "+ client" when the client is manual-only and the tap can only print a command. Verified on the Deck (192.168.1.253, canary, user scope) by running both code paths against the real install, minutes apart: pre-fix available=False remote='' post-fix available=True remote=ca010668 (installed e22af40f) and `flatpak {info,remote-info,update}` all accept the `id//branch` form there. 37 backend checks pass, 6 of them new and about exactly this.