Conversation
…to-reload An installed PWA could keep driving an old bundle after the daemon was rebuilt and restarted. The daemon now fingerprints client-dist at startup and reports it as client_build on /health; the SPA shell, manifest, and icon answer Cache-Control: no-store while Vite's content-hashed /assets/* stay immutable. The client remembers the fingerprint and re-checks on an interval plus pageshow/visibilitychange/online, reloading when it moves. Also repairs the SPA fallback regex: its ^ anchor sat inside the named group, so it never matched and every extension-less deep link (/settings, /editor, ...) 404'd on the daemon-served client. An auto-reload at a view path would have hit that immediately; the fallback now admits dot-free paths only, leaving dotted files to the static handler. See docs/adr/0011-client-freshness.md.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Installed PWA clients can no longer get stuck on a stale bundle. The daemon fingerprints its client dist into
/health, serves the shell uncached (no-store), keeps hashed assets immutable, and the client auto-reloads when the fingerprint changes.Changes
Client side:
client/src/update-check.ts: New module that polls/healthevery 30s (and on resume events likepageshoworonline) comparing the daemon'sclient_buildfingerprint against stored state. Reloads when the fingerprint changes.client/src/update-check.test.ts: Comprehensive unit tests for the update probe logic;probeForUpdateis pure so the decision table is testable without a daemon.client/src/main.tsx: Start the update check on app load.client/src/socket.ts: Exportresolve_health_url()so update-check can reach the health endpoint.Daemon side:
daemon/deckd/__main__.py:_client_build_id(dist): Hash every file in the client dist (relative path + bytes) into a stable 12-char fingerprint. Rebuilt bundle always yields a new id; computed once per daemon start._client_cache_headers: Middleware that setsCache-Control: no-storeon shell files andpublic, max-age=31536000, immutableon Vite's content-hashed/assets/*._add_client_routes(server, dist): Refactored SPA route setup. Fixes a regression in the fallback regex (was anchoring^inside the named group, breaking deep-link reloads).daemon/deckd/server.py: Store and exposeclient_buildon/health(absent when no--client-dist, dev server's "don't check" signal).tests/conftest.py: Addclient_buildparam to test server.tests/test_client_serving.py: Test fingerprinting, cache headers, deep-link SPA fallback, and/healthresponse.Documentation:
docs/adr/0011-client-freshness.md: ADR explaining the design, decisions (no service worker,no-storeshell, fingerprinted bundle), and out-of-scope items (protocol negotiation, offline mode, affordances).docs/GUIDE.md: Developer guidance on the freshness mechanism.docs/adr/README.md: Index entry for ADR-0011.README.md: PWA feature now links to ADR-0011.How it works
client_buildfingerprint, exposed on/health.Cache-Control: no-store; client always fetches fresh./healthevery 30s and on resume (pageshow, online, visibilitychange).client_builddiffers from stored state, the client records the new value before reloading (so a blocked reload can't loop) and reloads.client_buildfield) is treated as "don't check".Result
A phone gets a fresh shell within 30s of a daemon rebuild + restart. Installed PWAs resume to a live bundle instead of a stale one.