fix(connection): a failed app-label fetch is retried, not cached as a miss (t55)

The Current App sensor and media_player.app_name showed a package id in
the live run. Root cause was in the manifest-label tier: `_fetch_app_label`
returned early (no poller, ADB down) or logged and returned on a shell
error WITHOUT touching the cache, but `app_label` had already put the
package in `_app_label_requests`; the drain then threw the request away,
so a render between the failure and the next cycle re-enqueued — while
nothing distinguished "the device answered, this package has no label"
from "we never got an answer". Nothing was visibly retried, and the label
tier could stay silent indefinitely.

The cache is now (label, stamp, resolved) and records the FETCH, not the
wishful result:

  * a fetch that RAN caches its outcome for APP_LABEL_TTL — the label, or
    the empty string for a genuinely label-less package. Definitive: no
    re-enqueue, so the t24 F1 per-heartbeat round-trip tax stays closed.
  * a fetch that could NOT run stamps nothing, logs at debug (so a
    package id in the UI is diagnosable), and the next render retries.
  * a queued or in-flight fetch is not enqueued twice, so a burst of
    renders still costs one `pm dump` per watchdog cycle.

`cache_app_label()` is the one public writer of the cache (tests and any
future out-of-band reader no longer poke the private tuple), and
`app_label_requests`/`app_label_inflight` expose the queue for tests.

The old 2-tuple seeds in the label tests move to `cache_app_label`.
This commit is contained in:
James Mackay committed 2026-10-12 06:53:09 +01:00
1 parent ccde3cff71
commit 0c7e405108
4 files changed
+200 -35

No files matched your search

+1 -1
View File
@@ -1241,7 +1241,7 @@ class TestAppNameMapResolution:
player, _s, _i = _cmd_player(modules)
player._entry.options["app_name_map"] = {} # no override
manager = player._manager
manager._app_labels["ar.tvplayer.tv"] = ("TiviMate", manager._clock())
manager.cache_app_label("ar.tvplayer.tv", "TiviMate")
manager._on_current_app("ar.tvplayer.tv")
await asyncio.sleep(0.05)