Promote: the gateway follows the build it serves - #28
Merged
Merged
Conversation
It failed on develop and passed on the pull request, on identical trees. Both readings were honest; the check was not. Largest paint. The gate did not threshold it, on the stated grounds that the number swings with the load, and then failed a route for reporting no paint at all on the stated grounds that "that answer does not move with the load". It does. On the busy runner the Dogecoin transaction route fired its load event at ten and a half seconds, and the six seconds the probe waited after that were not enough for a contentful paint to land, so it read zero on a build that measured twelve seconds on a quiet machine. Two changes. The paint is now waited for, up to twenty seconds, instead of read once and taken as final. And when it still has not arrived the page is asked what is on it: a screenful of text with no paint entry is a measurement problem and is reported as one, while a page with nothing on it is the fault the check exists for. That distinction genuinely does not move with the load, which is the property the old comment claimed and did not have. Layout shift. The header called it "nearly deterministic, a property of the stylesheet rather than of the clock". It is less deterministic than that: the same tree measured 0.042, 0.046 and 0.069 on the blocks route across three machines, because a busier machine delivers content later and a shift that lands after the first paint counts while the same shift before it does not. Load can only add shifts, never remove one, so the smallest of several readings is the closest available estimate of the shift the stylesheet is actually responsible for. A route over its ceiling is now measured again, up to twice, and judged on the minimum. The table says when a route was measured more than once, because a gate that quietly retries until it passes is worse than one that fails. Neither change lowers a threshold. The eager payload budget, the 0.1 layout budget and the recorded exception on the transaction route are all unchanged.
…the-runner A gate that fails on a busy machine is measuring the machine
A release changed the document's inline theme bootstrap and left gateway.mjs byte identical. The cutover therefore did the right thing and left the gateway running, and the running gateway went on allowing the previous build's script hash while refusing the one it was itself serving: Executing inline script violates the following Content Security Policy directive 'script-src 'self' 'sha256-TLx68/+2SeR3+dZreFBX1fiMo91olqe4aVTfKFd48Ik='' Every page loaded with the theme bootstrap blocked. The only sign was a console error, which is why this is the second defect this week whose whole visible symptom was something nobody was looking at. The cause is a contradiction inside this file. The static root is a fixed path whose contents a release swaps underneath it, and that is deliberate: it is exactly why a frontend change needs no gateway restart, and the release script says so in as many words. The policy was computed once at start-up and did not follow that swap. One half of the file tracked the build behind the path and the other half remembered the build that was there when the process began. It follows the file now, keyed on size and modification time, so a document costs one stat and a hash is computed only when the file actually changes. The test writes two builds behind the same path and asserts the policy names the second and not the first, including the case where both land in the same second, which is a window a release fits inside. Against the previous start-up-pinned version it fails.
The first version of this fix cached the policy against the document's size and modification time. That key is wrong in a way that would have been very hard to find afterwards: two builds of the same length restored to the same instant share it, which is exactly what a tar extraction preserving mtimes can produce, and the resulting failure is a blocked script and nothing else. The test asserted that case and passed for the wrong reason. `utimesSync` takes a Date, so it wrote a millisecond-truncated time while `mtimeMs` carries finer precision, and the keys differed by an accident of rounding rather than by anything the code intended. The document is 3.4 kilobytes and is the same file the response is about to serve. The saving was never worth the class of bug it kept open, so it is read each time. The test now covers both dimensions on purpose: a build that changes the length and the time, and a build of exactly the same length with the modification time put back. Neither may be load bearing on its own. Against a start-up-pinned policy it still fails.
…ows-the-build The gateway refused the script it was serving
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.
Promotes #27 to
main,and with it the release that was rolled back at 03:43:35Z.
What happened
ac2bcfaf5was cut over at 03:42:50Z and rolled back 45 seconds later. Thechain page smoke against the public origin caught the reason:
Two different hashes: the one the gateway allowed and the one the document it
was serving actually needed. The theme bootstrap was blocked on every page, and
that console error was the entire visible symptom. The routes answered, the
component identities matched the manifest, the visual matrix was green, and the
page rendered.
ROOTis a fixed path whose contents a release swaps underneath it, which iswhy
release.shaleaves the gateway running when only the frontend changed.The policy was computed once at start-up and did not follow that swap. #27
makes it read the file per document, with a test that fails against the
previous behaviour.
Release
ac2bcfaf5is still installed on the host and is not being reused. Theartifact is rebuilt from this merge commit, installed beside the running
release, preflighted, cut over with a continuous probe, and then verified
through the public origin with
synthetic-check.mjs,release-manifest.mjs verifyandvisual-qa/chain-page-smoke.mjs. That lastone is the check that caught this, and it is the one that has to pass before
the cutover stands.
mempool-1b12b26f3is the rollback target and has been serving cleanly forninety minutes with zero restarts and zero errors.
🤖 Generated with Claude Code