Repository navigation
chore(dcz): roll the shell and page dictionaries onto the deployed build - #178
Merged
Merged
Conversation
The last roll was 2026-07-30, and two releases have shipped since: #176 took View Transitions out of the shell and #175 moved the homepage grid fragment off the script discovery path. Between them they reminted luna.css, nav.js, notepad.js, lens.js and tooltip.js, so seven of nine shell assets had no dictionary matching the bytes a visitor now holds. Deltas kept working the whole time (they diff against the OLDER candidates, which is the point), but anyone who loaded the site since those deploys would have gone into the next release with nothing to diff against. Rolled from the deployed commit, 4f09a42, which is what origin/production points at and what aadhar.sh actually serves. All six /a/ URLs referenced by the live pages reproduce byte-exact from this build. Adopted 6 shell candidates and 41 page snapshots; pruned 3 and 28 by the keep-3 / keep-2 rules. Every shell asset now carries its current hash. One trap worth recording, because it cost the first attempt: the local build did NOT reproduce production for lens.js and tooltip.js, and the source tree was clean. The cause was oxc-minify 0.141.0 installed against a 0.142.0 lockfile; 0.142.0 constant-folds `1024*1024` to `1048576`, a two-byte difference that remints the content hash. Rolling on that build would have committed dictionaries for bytes no browser has ever held, which is the exact failure the "roll from the deployed build" rule exists to prevent, and it would have looked like a successful roll. `npm ci` before a roll, and verify the built /a/ hashes against the live ones before trusting the output. Gates: 67/67 contract tests, 78 routes, page contracts, perf budget, wrangler check. Build regenerates 12 shell deltas and 80 page deltas, and correctly emits no self-delta for a freshly adopted candidate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Understanding-first reviewThis is a prompt, not a score or merge gate. Before approving, reconstruct the change:
For docs and dependency changes, a compact answer is enough. For behavior or production changes, include the causal path and one concrete counterexample. The author’s claim card belongs in the PR description; this prompt is for the reviewer’s independent reconstruction. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
aadhar-sh | 27ccce6 | Jul 31 2026, 04:47 AM |
oddharsh
added a commit
that referenced
this pull request
Jul 31, 2026
Six releases landed after the last roll (#179 through #184), and between them they reminted nav.js, luna.css and tooltip.js. Those three were live with no matching candidate, so anyone loading the site right now would have gone into the next release with nothing to diff against. Adopted 3 shell candidates and 40 page snapshots; pruned 2 and 36 by the keep-3 / keep-2 rules. All nine shell assets carry their current hash again. This roll also makes the PREVIOUS one measurable, which is the thing #178's claim card listed as unprovable at the time. Its candidates are what the new shell diffs against, and they are carrying almost the whole file: nav.js vs 1df49c71 226 B against 13341 B plain brotli 98.3% off luna.css vs 76d1dbd8 75 B against 8479 B plain brotli 99.1% off tooltip.js vs 549f1cd0 351 B against 2651 B plain brotli 86.8% off A visitor who loaded the site during the 4f09a42 window now pays 226 bytes for a nav.js that would otherwise cost 13 KB. That is the whole point of the committed dictionary set, and it only becomes observable one release later. Rolled from 984804e, which is where origin/main and origin/production both point. `npm ci` first, then verified all six /a/ URLs referenced by the live pages reproduce byte-exact before adopting anything — the oxc-minify version skew that nearly poisoned #178 is still an unguarded footgun, so the check stays manual until roll-shell-dictionary.mjs does it itself. Gates: 74/74 contract tests, 78 routes, page contracts, perf budget. Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
oddharsh
added a commit
that referenced
this pull request
Aug 12, 2026
…stops rotting (#348) The dictionary sets are the one build input no build step may produce. A returning visitor holds whatever `/a/` asset and page production served them last, offers its hash, and earns a delta only if those exact bytes are committed here. build.mjs cannot derive that from source, so the sets are committed, and committing them is a step someone has to remember. Nobody remembered since #178 on 2026-07-30, 161 commits back. ## What was broken Every dictionary-carrying shell asset production serves was missing from `www/a-dict`: nav.1c6af07b, luna.1523f4f6, hoist.d9081560, tooltip.5dad2389, lens.88fba28b. Main built its six shell deltas against #178's candidates, which no living browser holds, so a returning visitor took plain brotli on the render-blocking path. After the roll, against the bytes browsers actually hold: | | stale | rolled | |---|--:|--:| | `luna` delta | 7,781 B (no match, plain br) | **155 B** | | `nav` delta | 5,973 B (no match, plain br) | **1,113 B** | Per-page deltas went 121,288 B over 92 to 74,337 B over 94, because the snapshots now match live pages rather than pages from twelve days ago. ## Why dcz:check said PASS the whole time Its shell probe picks an a-dict candidate that is NOT the live hash, offers it, and asserts dcz comes back. build.mjs builds a delta for every a-dict entry, so that is true by construction; the probe reads the live hash only to exclude it. It is the same self-agreeing shape as the Markdown-twin test in gotcha 24 and the page tier's old snapshot probe in gotcha 20. `live shell is covered by a-dict` asks the question a returning visitor asks: are the bytes THEY hold covered? Bases with no a-dict history are skipped, since a new asset cannot have a dictionary until it has been served once. Byte-compared, not filename-compared, because 8 hex of a sha256 is not the digest the browser keys on. Advisory on purpose: like infra:check's edge tier it reads production, so making it required would deadlock the release that would clear it. ## Why it can now run unattended `shell:roll` adopted from `.build/www/a`, which forced it to run from the deployed commit. `--live` (`pnpm run dict:roll`) reads production instead, the same way the page half has since gotcha 20. Adopting from a build can only capture THIS commit's shell, so a release that goes by without a roll is unrecoverable, and on an unramped tree it adopts bytes nobody holds while evicting one still in use (KEEP is 3). Whatever is live is protected from the prune. It refuses outright if production reads empty, since an empty read hands the prune an empty `current` set, which is exactly when it is free to evict what browsers are holding. `.github/workflows/dictionary-roll.yml` runs it nightly and opens a PR when anything moved. It holds no Cloudflare credential: `--live` is plain HTTPS and the PR goes out on GITHUB_TOKEN. It cannot merge, because `main` takes zero bypass actors and that property is the whole release model. ## CLAUDE.md Two paragraphs described a `.github/workflows/ramp.yml` running the ramp from a scoped environment secret. Verified 2026-08-12: no such workflow in any commit, the environments are `copilot` and `production` rather than the canary/full pair, and the only repo secret is the six-read-scope CLOUDFLARE_API_TOKEN. What landed on 2026-08-06 was the release-guard rewrite alone. Both blocks are relabelled as a PLAN rather than deleted, since the reasoning about where a secret lives is still right. Also corrected: "not urgent, a dictionary 11 days stale still gave 87-93%" is true of a STALE dictionary and false of an ABSENT one. The page tier degrades to the family corpus at ~26%; the shell tier has no fallback. ## Drive-by Four workflows bootstrapped pnpm@11.20.0 while package.json has pinned 11.21.0 since #310 two days ago, each under a comment calling package.json the source of truth. Behaviour-neutral (self-switching is on by default, so 11.21.0 already ran every time), but the gap stops being harmless the moment it crosses a major: pnpm 12 ships a native CLI that an older pnpm cannot exec, which is gotcha 30. A contract test now pins every workflow's bootstrap to package.json, and counts what it checked so a regex that stops matching cannot pass silently. Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
This was referenced Aug 12, 2026
This was referenced Aug 20, 2026
This was referenced Aug 27, 2026
This was referenced Sep 10, 2026
This was referenced Sep 17, 2026
This was referenced Sep 25, 2026
This was referenced Oct 13, 2026
This was referenced Oct 20, 2026
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.
Claim card
Per UNDERSTANDING-REVIEW.md. Scale: build input, no runtime code changes.
Intended model. Adopt the currently-deployed shell and pages as dictionary candidates. Two releases shipped since the last roll on 2026-07-30 (#176 removed View Transitions, #175 moved the homepage grid fragment off the script discovery path), and between them they reminted
luna.css,nav.js,notepad.js,lens.js, andtooltip.js. This is build input only: no worker code, no page markup, no runtime behavior.Prediction. Nothing changes for a visitor today. Deltas already worked, because they diff the current asset against older candidates. What changes is the next release: a visitor who loads the site now holds bytes that will have a matching dictionary then, instead of falling back to the family corpus or plain brotli. Concretely, 7 of 9 shell assets went from "current hash absent from the set" to present, and 11 pages that had no snapshot at all (
/bot,/photos,/restore,/updates,/lens,/pixel-peeper, 5 ×/writing/*) now have one.Likely misconception / first plausible failure. That a roll is safe to run from any green build. It is not, and this PR nearly demonstrated the failure.
shell:rollreads the local.build/holding/a, so it will happily adopt whatever the local toolchain emits. My first build producedlens.0407f2b8andtooltip.17839b04against a production servinglens.eed21892andtooltip.549f1cd0, with a clean source tree. The cause wasoxc-minify0.141.0 installed against a 0.142.0 lockfile: 0.142.0 constant-folds1024*1024into1048576, two bytes, which remints the content hash. Committing that would have filed dictionaries for bytes no browser has ever held, defeating the entire point, and it would have looked like a clean successful roll. The second misconception is reading a stale/luna.cssas evidence the deploy had not landed; that URL is the short-cached unhashed fallback, and the hashed/a/URL is the honest one (CLAUDE.md gotcha 12).Evidence.
4f09a42, which is where bothorigin/mainandorigin/productionpoint, and whose Workers Build completed successfully at 04:35:56Z./a/URLs referenced by the live pages (/,/garage/,/lwe/,/lens,/writing) reproduce byte-exact from this build afternpm ci. That equality is the precondition, and it is what failed before./a/luna.76d1dbd8.csscontains 0 occurrences each of@view-transition,view-transition-name, andaxp-window.shell:rollis idempotent: a second run adopted 0 and pruned 0.pages:check,perf-budget,check-wrangler.Remaining uncertainty.
npm run dcz:checkafter the next deploy.npm cirestored parity for this run, but nothing in the repo forces a roller to be on lockfile-exact dependencies, and the failure is silent. A guard inroll-shell-dictionary.mjsthat verifies built hashes against live before adopting would close it. I did not add one here, to keep this PR to the chore itself.What this is
The post-deploy half of #176. Routine dictionary maintenance, deliberately a human step because it writes into the source tree and
build.mjsmust never do that.Adopted 6 shell candidates and 41 page snapshots; pruned 3 and 28 by the keep-3 / keep-2 rules.
Shell coverage after the roll, every asset now carrying its current hash:
quizsitting at a single candidate from 2026-07-26 is correct rather than stale:quiz.jshas not changed since, so its lone candidate is the current one. Age and staleness are different things here.🤖 Generated with Claude Code