Cover endpoint had no negative cache: when every FTP path returned
550 for a print whose 3MF wasn't on the printer (typical SD-card
print), each frontend refresh re-ran the full 8-path fan-out. Add
_cover_404_cache keyed by (subtask_name, view_key) and short-circuit
to 404 on hit; clear alongside _cover_cache on print start. Only
populated on genuine 404 paths, not transient FTP errors, so flaky
network doesn't lock out future retries.
GitHub update-check had no backoff on 403 rate-limit. Add module-
level _github_rate_limit_until plus three helpers; check before
every api.github.com call in /updates/check and
_discover_target_release. Read X-RateLimit-Reset from the 403 with a
1-hour fallback when the header is absent and a 60-second floor to
guard against container/GitHub clock skew. Route surfaces
retry_after_seconds so the UI can display real wait time.
The "ffmpeg didn't terminate gracefully" line the reporter quoted
is the standard SIGTERM/SIGKILL pattern in camera.py and unrelated
to the FTP loop; it goes away on its own once the cover endpoint
stops hammering the printer.