Repository navigation
fix(platform): address Cloudflare end-to-end deployment failures - #399
Merged
Merged
Conversation
Brooooooklyn
force-pushed
the
codex/platform-e2e-0261
branch
from
October 9, 2026 15:12
25f0271 to
50efd53
Compare
Brooooooklyn
marked this pull request as ready for review
October 9, 2026 15:53
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…-ups - Stop rejecting sslrootcert file paths when Void creates Hyperdrive. Main accepted these URLs, providers such as RDS and Supabase document them, and the only accepted alternative made the same require-mode Hyperdrive. The old advice (sslrootcert=system) also broke Void's own pg clients with ENOENT. - Document that Void-created Hyperdrive uses Cloudflare's default require mode. - List Containers and Cloudchamber Edit in the core runtime token table; every packaged runtime enables Sandbox. - Unfold MIME boundary headers on SP/HTAB only. - Correct the reason given for the inbound digest algorithm. - Cover legacyDigest through the signed admission route. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Remove the versioned digest and the second digest the proxy sent for direct sends. The API compares one digest again, and inbound actions use the same unfolding algorithm. The SDK rebuilds the MIME, with a new random boundary, on every send. So a retry of a text+HTML send recorded before the upgrade conflicts with or without a second digest; only a hand-sent, byte-identical resend would differ. A conflict and a replay both return before anything is sent or counted, and no upgrade step reads digests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Member
Author
|
@cpojer Thanks for 0512376. We decided to remove its digest compatibility path in 0d9c8a1: What the path changed Why we removed it
What stays
Visible effect: a retry of a text+HTML send made before the upgrade still returns |
…se URL Bug: When a database URL had an sslmode, the platform API sent Hyperdrive TLS settings set to require. On `void db set-url`, or when it adopted an existing Hyperdrive by name, this replaced TLS settings that an operator set by hand, such as verify-full with a CA. Cloudflare does not allow require with a CA, so the update could also fail with a 502. Cause: parseHyperdriveConnectionString mapped each accepted sslmode to an mtls block. Both create (POST) and update (PUT) sent that block. Fix: Send no mtls block. A new Hyperdrive gets Cloudflare's default require mode, which is the same Hyperdrive as before. A PUT keeps the TLS settings that are already on the Hyperdrive. The API still returns 400 for disable, prefer and no-verify, before it calls Cloudflare. Remove the mtls type field, variable and spread. Test: Unit tests check that no mtls is sent for each accepted sslmode, on create and on update. New rows check that disable, prefer and no-verify fail before fetch. Remove a create test that repeated the main create test, and move its sslrootcert URL into that test. The route tests for create and update compare the exact request body, now with a verify-full URL in both. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH
… databases on deploy
Bug:
A PostgreSQL or MySQL project whose Hyperdrive was created before
caching was turned off still cached reads. Hyperdrive does not drop
cached reads when the app writes, so a read right after a write could
return old rows for up to about 75 seconds. Only `void db set-url`
fixed it, and that asks for the full database URL again.
Cause:
The platform sent `caching: { disabled: true }` only on create and on
update. A deploy reused the project's Hyperdrive id as it was and never
looked at its caching setting.
Fix:
Add ensureHyperdriveCachingDisabled. It reads the Hyperdrive config
and sends a PATCH with only `caching: { disabled: true }` when caching
is still on. The PATCH carries no origin, so no password is needed.
Each deploy of a project with an existing Hyperdrive calls it, and the
binding resolves only after it succeeds, so a Cloudflare error fails
the deploy at the provisioning step. Create and update still turn
caching off. The database guide now says an existing connection is
updated on the project's next deploy.
Test:
Unit tests check that a config with caching off gets one GET and no
write, and that a config with caching on gets a PATCH whose body is
only `{ caching: { disabled: true } }`. provisionBindings tests check
that an existing Hyperdrive row runs the check before it returns the
binding, and that a failed check fails the deploy.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH
Brooooooklyn
removed this pull request from stack #401
October 12, 2026 08:38
Brooooooklyn
added a commit
that referenced
this pull request
Oct 12, 2026
…en source (#400) ## Problem Before open source, a review of the SDK, framework and CLI packages (`packages/*`) found 737 cleanup issues of four kinds: ``` over tests 322 tests of repo tooling, tests for tests, duplicate tests slop 241 needless defensive code, copies of helpers, pass-through wrappers, test-only seams over comments 113 bug-fix history, essays, stale line references, comments that repeat the code dead code 61 unused exports, branches, params, files ``` This PR removes them. It does not fix bugs or change behavior. The real bugs from the same review go in separate PRs. ## What this PR changes ``` packages/* 620 files +22.9k −63.1k (net −40k lines) ├─ tests +15.3k −43.7k └─ source +7.6k −19.5k 737 issues ──► 555 fixed 117 partly fixed (the safe part only) 56 skipped (public API, behavior change, or needs a new public export) 9 left for an owner decision ``` Larger items: ``` provision.ts 4,975 → 3,224 lines. A 440-line Proxy-safe redaction for a path that production never used is now a small helper. client.ts 2,479 → 1,918 lines. About 55 endpoints share one private request helper. installer phases 11 get/set accessor pairs → one run-state object config readers duplicate Wrangler config readers and record guards → shared internal ones tooling tests 10 SDK test files that tested repo scripts or test config → removed. vp run check now typechecks root test/ and .github/scripts instead. ``` ## Decisions | Topic | Decision | | --- | --- | | Behavior | No reachable change. Return values, thrown errors and messages, CLI output, exit codes, files written and network calls stay the same. | | Path patterns | `@void/edge` matches header, revalidate and routing patterns with a small parser instead of a RegExp built from the pattern. Results stay the same for every pattern the old code could run. Patterns too large for V8 now match instead of failing, and catastrophic backtracking is gone. | | User-visible text | Kept as it is on main, even where the wording is out of date (for example `void.json`, "Wrangler"). Wording changes need their own PRs. | | Public API | Every published export and documented feature stays. The generated Pages client entry still exports `router`. | | Deleted tests | Each one either tested tooling or config, or another test still asserts the same behavior. Unique assertions moved into the kept test. | | Shared helpers | Only internal modules. No new public exports, and no `packages/*` import from `platform/`. | ## Rollout ``` main ── #399 (Cloudflare e2e fixes) ── this PR (cleanup) ``` Stacked on #399, because both PRs touch the same installer and deploy files. Merge #399 first. ## Known limits - In one middle commit the typecheck fails until a later commit (`test(cli): pass explicit access ...`). This matters only for bisect, because the PR is squash-merged. - Independent review rounds found 35 places where the cleanup changed behavior or lost unique coverage. All 35 are restored here. - The removed tooling tests leave three scripts without tests: `.github/scripts/production-baseline.ts`, `.github/scripts/schema-compat-tests.ts` (CI only) and `packages/platform/scripts/source-revision.mjs` (build time, display only). ## Testing | Check | Result | | --- | --- | | `vp run build:all` + `node test/check-playground-build-artifacts.mjs` | pass | | `vp run check` (31 typecheck tasks) | pass | | `vp lint`, `vp fmt --check .` | pass (2,477 files formatted) | | `vp test run` (full suite) | 685 files, 12,942 tests pass (1 file, 30 tests skipped) | | `vp run test --base <previous head>` (latest restores) | 13 files, 497 tests pass | | Restored tests | Each one fails when its code is broken on purpose | 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Brooooooklyn
added a commit
that referenced
this pull request
Oct 12, 2026
## Problem The pre-open-source review of the SDK, framework and CLI packages confirmed 17 high-severity bugs. Each one breaks a documented command or a common setup: ``` database void db reset / seed / export on MySQL 8 · db reset after `void db connect` · TS seeds init pnpm build approvals lost · Windows paths with spaces deploy pinned-secret Cloudflare deploys · custom binding names on managed deploys runtime remote D1 sessions · MySQL migration breakpoints · MySQL auth migrations adapters React SSR errors hang · Solid remounts on every update · Svelte island CSS config BOM-prefixed wrangler.jsonc · Astro dev ignores src/middleware.ts for good ``` ## What this PR fixes One commit per bug. Each commit message has `Bug`, `Repro`, `Cause`, `Fix` and `Test` sections for review. The review found 17 bugs; this PR has 16 fixes. The Vite+ starter fix (pnpm pinned with no build policy) was dropped: `main` now installs Vite+ projects through `vp` and keeps the project's package manager (328c186), so the bug no longer occurs. | Area | What a user hits today | After this PR | | --- | --- | --- | | `void db reset` / `seed` | After `void db connect`, drops every table in the deployed PostgreSQL/MySQL database with no prompt | Asks first on a non-local host (`--yes` skips; localhost skips) | | `void db reset` (MySQL 8) | Drops nothing, still prints "Database reset" | Drops all tables | | `void db seed` (TS) | Crashes on `void gen model` barrels after the DB is already wiped | Loads extensionless imports | | `void db export` (MySQL 8) | `Table 'app.undefined' doesn't exist` | Exports every table; restore runs with FK checks off | | `void init` (pnpm) | Rewrites the user's `allowBuilds` / `onlyBuiltDependencies` | Merges into the user's list | | `void init` (Windows) | `node` spawned through a shell breaks on paths with spaces | Spawns `node` without a shell | | `void deploy --platform cloudflare` | Pinned-secret deploys reject `limits` / `placement` / `cache` | Uploads limits, smart placement and cache with the version | | Managed `void deploy` | Ignores custom D1/KV/R2 binding names | Sends them, as `docs/reference/config.md` says | | Astro dev | Leaves `src/middleware.ts` in `.gitignore` for good | Adds the line only while dev runs | | Remote mode (`remote: true`) | `void/db` and auth crash: no `withSession` | Remote D1 binding supports sessions | | MySQL migrations | Sends `--> statement-breakpoint` lines to MySQL | Splits on breakpoints | | MySQL auth migrations | Re-runs fail on MySQL 8 (uppercase info-schema keys) | Idempotent on MySQL 8 | | React Pages SSR | A page error hangs the request | Rejects → 500 page or dev overlay | | Solid Pages | Remounts page and layouts on every navigation and deferred update | Keeps layouts; GET navigation re-creates the page (same as Vue) | | Svelte islands | Production ships raw, unscoped `<style>` CSS (or the build fails) | Bundles the compiled CSS | | Root `wrangler.jsonc` with BOM | Read fails, file treated as missing | BOM is stripped, as Wrangler does | ## How each fix was made ``` verify reproduce on the #400 head (failing test or script) fix regression test first, then the smallest fix, one commit test independent tester: the test fails with the fix reverted, affected tests, typecheck review adversarial review of the commit → a verifier checks each claim → fix-up if needed ``` ## Decisions | Topic | Decision | | --- | --- | | Reset on a remote DB | `void db connect` still writes the URL to `.env`. Only reset/seed ask before they drop tables on a non-local host. | | Managed custom binding names | Projects that already set custom names get new resources under those names on the next deploy. The old `DB`/`KV`/`STORAGE` resources stay. | | Pinned-secret deploys | Targeted placement (`region`, `host`, `hostname`) still fails, now before any API request: Cloudflare's version endpoint can drop the target, and an `--atomic` upload is live at once. The error names the key and says what to do: remove `cloudflare.placement`, or set it to `{ mode: 'smart' }`. `logpush` and `tail_consumers` are accepted but not sent. No Cloudflare version upload applies them, with or without secrets (same as `observability`). With secrets, `--atomic` deploys and the first deploy after `void secret put` also keep the live values. Without secrets, those two paths apply them through `cf deploy`. | | React SSR errors | Errors before the shell is sent reject the render. Errors after the shell keep React's default client-render fallback. | | Solid navigation | Same as Vue: GET navigation re-creates the page; mutations, `router.refresh()` and `preserveState` keep it. | ## Known limits (not in this PR) - Astro: after a hard kill (SIGKILL, crash), or in apps that ran dev with an older Void, the `src/middleware.ts` line stays in `.gitignore` until you delete it by hand. - `void db seed`: the database is reset before the seed file loads, so a seed that fails to load leaves an empty database. Base has this too. - Remote D1 sessions: `withSession()` ignores constraints and bookmarks (#403). - Svelte islands: CSS of child components that render only on the server is still missing. - MySQL migrations: a failed multi-statement migration cannot resume. Base has this too. ## Rollout ``` main ── #399 (Cloudflare e2e fixes) ── #400 (cleanup) ── this PR (high-severity bugs) ``` Merge #399 and #400 first. ## Testing | Check | Result | | --- | --- | | `vp run build:all` + `node test/check-playground-build-artifacts.mjs` | pass | | `vp run check` | pass | | `vp run test --base <#400 head>` | pass (480 files, 10,261 tests) | | Windows CI (`test: windows`) | pass | | Regression tests | One per bug; each fails when its fix is reverted | 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH --------- Co-authored-by: Claude Opus 5.5 (1M context) <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.
Problem
A live end-to-end test of the platform on Cloudflare found these failures:
What this PR changes
Static routing
A standalone static/SPA deploy without a
routingconfig now reads_headersand_redirects, like the native deploy.Email idempotency
Inbound forward/reply uses the same digest. Each receipt runs its handler once, so deduplication does not change.
PostgreSQL / Hyperdrive
sslrootcertis not sent to Hyperdrive, as on main and in the native deploy. The URL is stored as given.requiremode.Other fixes
/:id/domainsroutes.Decisions
require.void db set-urlkeeps TLS settings already on the Hyperdrive, such as a CA an operator set by hand. Hyperdrive's verify modes need an uploaded CA ID, which a URL cannot carry. Rejecting would fail PlanetScale and Neon URLs as pasted. Wrangler and the native deploy also send none.sslrootcertfor Hyperdrive; do not reject itpgneeds the file. A rejection gave no production security: the only accepted URL makes the samerequireHyperdrive.{ ok: true }. A warning would fire for every PlanetScale or Neon user, who cannot act on it.sandboxDrain: 3), so a default install's token link already asks for both.Rollout
Known limits
sslrootcertpaths; Nodepgreadssslrootcert=systemas a file path;void devrequest handlers runpgin workerd, which cannot readsslrootcertfiles;GET /projects/:id/usagestill sits behind themanagedBuildscapability on a core platform;rollbackSafeFromhas no 0.26.1 or 0.27.0 entry, so a rollback to those versions is refused; directvoid deploy --platform cloudflarestill creates Hyperdrive with query caching on (Direct Cloudflare deploys create Hyperdrive with query caching on #404). Other URL TLS gaps that are also on main are tracked in PostgreSQL/MySQL URL TLS options: gaps between Void's clients and Hyperdrive #405.Testing
Live, on an isolated Cloudflare installation upgraded to
84706062d:No additional subscriptions were enabled.
Local, at
0d9c8a1af(this branch merged with main at2fc172db0, Release 0.27.0):vp run checkvp run test(affected, full fallback)vp fmt --checkandvp lintcf1.0.0-beta.14 output■/▲symbols, as beta.13. The installer diagnostic still matches.The email tests show that a rebuilt SDK boundary replays without a second provider send or quota debit, that changed content conflicts, and that only SP/HTAB counts as folding whitespace. The real MIME builders of all 21 released
voidversions (0.20.0–0.27.0) were also run against the new digest: retries of text+HTML and inline-image mail replay, and every changed message conflicts. The commits after84706062dwere verified locally only. The live E2E job runs on pushes to main.Hyperdrive follow-up commits (
486c12fd7,edc53b5c3):vp run test --base 0d9c8a1afvp run checkcaching.disabledis in the response; configs created before this PR showfalse, which the deploy check turns offLive run of the real
cloudflare-api.tsfunctions against Cloudflare, with a temporary Neon PostgreSQL database and scratch Hyperdrives (all deleted afterwards):🤖 Generated with Claude Code
https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH