Release: develop -> main - #1245
Merged
Merged
Conversation
…1244) * Stop a wrong asset response from outliving the deploy that caused it A missing /static/* asset used to be answered by the SPA fallback with the app shell, and the path-based header rule stamped that HTML with the lifetime meant for fingerprinted assets: public, max-age=31536000, immutable. Because immutable forbids revalidation, the wrong answer was pinned for a year in every cache that had fetched it. Customers hit an error screen instead of the buy page; one case stayed stuck for roughly 40 minutes on a fixed-line connection, and the edge had to be purged by hand to clear it. Missing assets already answer 404. This adds the parts that keep a single mistake from becoming a year-long outage: - drop immutable from /static/*, so a user-triggered reload can revalidate and correct a poisoned entry. The long max-age stays; shared caches are unaffected and still need purging, which the comment now says plainly. - route /favicon.ico and /logo.png through the content check as well. They carried the same path-not-content assumption with a 24h lifetime and never reached the function. - treat a missing content-type on an ok response as the fallback case instead of defaulting it away, and compare case-insensitively. - verify after every production deploy that an absent asset really answers a bare 404 with the exact headers the function emits. A run-specific marker is polled first so the check runs against a live deploy; the step states plainly what it can and cannot prove, since marker and asset are separate requests. - pin the route list in a test, so dropping an entry cannot pass silently. * Close the same gap on the remaining non-fingerprinted paths, and tighten the checks Review follow-ups on the same failure class: - robots.txt, manifest.json and asset-manifest.json go through the content check too. no-cache still stores the response — it only forces revalidation before reuse — so a later 304 can confirm a wrongly stored app shell under those URLs. / and /index.html stay out: they are the fallback. - the route-list test now pins include and exclude exactly, so an entry cannot be added or dropped unnoticed, and reads the file as a typed import like the rest of the suite. - compare the media type before the parameters instead of scanning the whole header, so a content type that merely mentions text/html in a parameter is not mistaken for the fallback. - separate the transport-failure conclusion from the wrong-answer one in the verify step, and qualify three comment claims that promised more than HTTP caching guarantees. * Cover version.json too, and fail closed on an empty content type - version.json goes through the content check as well. It is written by the build and an e2e test expects real JSON from it, so a missing file would have been served as the app shell under that URL — the same failure class the rest of this change closes. It gets the same revalidation rule as the other manifests. - an empty content-type is now treated like a missing one. The claim was that the check fails closed; it only did so for an absent header. - the verify step tracks whether any response was received at all, so an aborted final attempt is no longer reported as 'never got a response' after eleven wrong-but-received ones, and a non-matching response is no longer asserted to be the incident's failure mode when it could be an unrelated error. The empty-content-type test sets the header after construction on purpose: passing '' in the init is discarded and the platform fills in text/plain, so the constructor route cannot produce the case the test is named after. * Say only what the checks actually establish Two diagnostic texts promised more than the code observes: - the marker loop reported 'new deploy did not become active' whenever no matching marker body came back, though all it establishes is that no marker matching this run was seen — the deploy may well be live with the marker endpoint misbehaving. - the version.json comment claimed a new commit hash on every build. The hash only moves when HEAD does; a rebuild of the same commit reuses it, and only the build time is always fresh. It is also written by the main-app build, not by the widget build. * Note that the version hash can be unknown generate-version.js falls back to the literal 'unknown' when git metadata is unavailable, so the comment describing what version.json holds should not promise a commit hash unconditionally.
github-actions
Bot
requested review from
TaprootFreak and
davidleomay
as code owners
August 2, 2026 20:23
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.
Automatic Release PR
This PR was automatically created after changes were pushed to develop.
Commits: 1 new commit(s)
Checklist