From 1ccea006732aae743692b2bd4a30aed52dcb7519 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 1 May 2026 07:35:25 -0700 Subject: [PATCH] fix(ci): bust Cloudflare.Vite memo so prod tracks main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apps/web uses alchemy's Cloudflare.Vite, which content-hashes the Worker's working directory (apps/web/) to decide whether a rebuild + upload is needed. Workspace dependencies under packages/** (@stackpanel/api, @stackpanel/auth, @stackpanel/db, …) live outside that scope, so a push-to-main that only touches those packages hashes identically to the last deploy and alchemy short-circuits with "no change" — silently skipping the Vite build and the Worker upload. Evidence: the PR #25 merge (run 25216266546, sha 86bd256b) completed the "Deploy" step in ~10s with no Vite output and printed "✓ TanstackStart (Cloudflare.Worker) no change", whereas the PR #23 merge (run 25207387008) — which did touch apps/web/ — ran the full Vite build and uploaded a 28.20 MB worker. As a result, stackpanel.com is still running whatever bundle the last apps/web/-touching commit deployed, not `main`. Fix: write a SHA-stamped .build-info file inside apps/web/ before alchemy deploy. The file sits inside the default memo scope (and is *not* gitignored — doing so would make the default exclude rules filter it out), so every CI run produces a fresh hash and alchemy is forced to rebuild + upload. The file is ephemeral on the CI runner. docs/ and api/ are unaffected — docs already pre-builds with `bun run build:worker` and uses Cloudflare.Worker (hash = main bundle bytes, naturally covers upstream changes), and api has a separate open failure unrelated to the memo. --- .github/workflows/deploy-web.yaml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/deploy-web.yaml b/.github/workflows/deploy-web.yaml index 9a502e71..3a6ecbc4 100644 --- a/.github/workflows/deploy-web.yaml +++ b/.github/workflows/deploy-web.yaml @@ -88,6 +88,36 @@ jobs: with: path: apps/web/.alchemy key: alchemy-state-web-${{ needs.stage.outputs.stage }} + # Invalidate Cloudflare.Vite's content-hash memo on every push. + # + # `Cloudflare.Vite` hashes the Worker's working directory (`apps/web/`) + # to decide whether a rebuild + upload is needed. That scope does *not* + # include workspace dependencies under `packages/**` (`@stackpanel/api`, + # `@stackpanel/auth`, `@stackpanel/db`, …), so a push-to-`main` that + # only touches those packages hashes identically to the last deploy and + # alchemy short-circuits with "no change" — silently skipping the Vite + # build and the Worker upload. The apex then stays frozen on whichever + # commit last happened to touch `apps/web/`. + # + # Stamping a commit SHA (+ refs) file inside `apps/web/` forces a fresh + # memo hash on every run, so production tracks `main` even for diffs + # that live entirely in `packages/**`. The file must NOT be gitignored + # (the default memo `exclude` is the merged gitignore rules, which + # would otherwise filter it out). It's written only in CI — runners + # are ephemeral, so there's nothing to clean up — and contains no + # secrets. + - name: Stamp build info for memo invalidation + working-directory: apps/web + run: | + set -euo pipefail + cat > .build-info <