feat(build): a control for bun, which builds this byte-identically and 2x faster - #307
Merged
Conversation
…d 2x faster Bun 1.4 is worth a real answer rather than a guess, so `npm run bun:check` measures one instead. Same idiom as `kitesurf:check`: three questions, run when a bun release lands, not in CI. Measured 2026-08-10, node v26.7.0 against bun 1.4.0-canary.1+827475e21: ok zstd honours `dictionary` — 73 none / 24 good / 73 wrong ok build output is byte-identical — 1975 files, node 14.4s vs bun 7.1s ok contract suite passes under bun — 206 pass, 0 fail BYTE-IDENTICAL is the bar, and it is a lot higher than "the build succeeds". /a/ and /i/ are content-addressed, so one differing byte mints a new URL, orphans every a-dict snapshot naming the old hash, and moves the CSP hashes the documents are served under. Not adopting it, for three reasons and only the first is about bun. The newest STABLE bun is 1.3.14, which predates the dictionary fix (oven-sh/bun#34427) and silently ignores `zstdCompressSync`'s `dictionary`. wrangler, miniflare and workerd are the deploy path and the route oracle, node-pinned. And the win is seconds on a step CI already spends longer on in dry-runs. The failure would be LOUD, which the check now says out loud: build.mjs already feature-detects the same collapse and throws, so 1.3.14 kills the build rather than shipping no-op deltas. The engine is silent; this build is not. Verified in both directions — canary all green, 1.3.14 fails at question 1 before spending two builds, and the tree comes back clean either way. Also fixes a real defect bun found in our own suite. `withSecurityHeaders` rebuilds every response as `new Response(response.body, …)`, which per Fetch LOCKS the body, and one contract test pushed the same four case objects through it twice. Bun throws `Body object should not be disturbed or locked`; node's undici allows it. The assertions are about headers, so the leniency was never load-bearing — it just made the suite depend on which runtime ran it. Cases are built fresh per pass now, and the test passes on both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
aadhar-sh | 2015f8b | Aug 10 2026, 04:13 PM |
Contributor
Wire-size diff vs merge base
Brotli q11, the quality the edge serves. Every number here is deterministic: Client assetsNo change. 12 files, 60.92 KiB Brotli total. PagesNo change. 46 files, 471.25 KiB Brotli total. Worker bundleNo change. 268.62 KiB gzip. Dictionary deltas (
|
Two more instances on 2026-08-10 (#305, #307), so four across four unrelated PRs, every one alongside a CodeQL pass. #305 is what makes this worth writing down rather than just recounting. It changed documentation, four code COMMENTS and one quiz string, and failed the check identically to a build-script PR, with `title: null` and a lone annotation at `.github:211`. A diff with no executable change cannot carry a security finding, so a check that reddens on it is reporting on itself. That is a sharper discriminator than the API tell when the API tell is ambiguous. Also records where to confirm the stakes: the ruleset, not the check list. `validate` is the only required context, so this has been red on four PRs while gating none of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
oddharsh
enabled auto-merge (squash)
August 10, 2026 16:12
oddharsh
added a commit
that referenced
this pull request
Aug 10, 2026
check-bun.mjs landed on main while this branch was in flight. Its usage strings say `npm run bun:check -- --bun <path>`, and under pnpm the `--` is passed THROUGH to the script rather than stripped, so the documented invocation would hand check-bun.mjs a literal `--` as its first argument.
This was referenced Aug 10, 2026
oddharsh
added a commit
that referenced
this pull request
Aug 10, 2026
#313 was CSS-only and failed `github-advanced-security` with the artifact's whole signature: title null, empty summary, one annotation, CodeQL green. Two things it added beyond the tally. The annotation sat at `.github:213`, the SAME line as #307 on a diff sharing no content with it, so the line number is a fingerprint of the harness rather than a location — do not go looking for what lives there. And `gh pr checks` did not list the failing check AT ALL: seven rows, every one pass or skipping, while `/commits/<sha>/check-runs` reported that same check as failure on the same head commit. Reproduced twice minutes apart, so it is not a timing gap. That matters because the convenient command reports the PR green while the notification says a check failed, which reads exactly like a stale alert and is not one. The `check-runs` call the note already recommends is the source of truth for this check. Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Curiosity about bun 1.4 deserved a measurement rather than a guess, so this adds one:
npm run bun:check, in the same idiom askitesurf:check. Three questions, run when a bun release lands, never in CI.Byte-identical is the bar
It is much higher than "the build succeeds".
/a/and/i/are content-addressed, so a single differing byte mints a new URL, orphans every committeda-dictsnapshot naming the old hash, and moves the CSP hashes the documents are served under. A build that is 2x faster and one byte different is not a faster build. This walks both trees and compares sha256 per file: 1975 files, 0 differing.Viable, and still not adopted
Three reasons, and only the first is about bun:
zstdCompressSync'sdictionary. Pinning the build path to a canary trades a correctness bug for an unreleased revision.The failure would be loud
Worth stating, because it reads scarier than it is:
build.mjsalready feature-detects the same collapse and throws (searchexpected a collapse), so bun 1.3.14 kills the build rather than shipping no-op deltas. That guard exists because the no-op shipped for a full deploy once. The engine is silent; this build is not.Bun found a real defect in our suite
The byproduct worth keeping even if bun is never adopted.
withSecurityHeadersrebuilds every response asnew Response(response.body, …), which per Fetch locks the body it was handed, and one contract test pushed the same four case objects through it twice:Bun is spec-correct; node's undici is lenient. The assertions there are about headers, so the leniency was never load-bearing, it just made the suite depend on which runtime ran it. Cases are built fresh per pass now and it passes on both.
Verified in both directions
That second run also caught two bugs in the check itself:
process.exit()skipsfinally, which had left a half-written.build/beside an orphan baseline, and running the comparison after a disqualifying probe just reproducesbuild.mjs's own throw 40 seconds later.Gotcha 28 records the numbers, the bar, and the re-check recipe.
🤖 Generated with Claude Code