fix(worker): fail the image build on a stale or missing lockfile - #31
Merged
Conversation
The worker image was built with:
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* turbo.json ./
RUN pnpm install --frozen-lockfile || pnpm install
Both halves defeat the lockfile. The `pnpm-lock.yaml*` glob makes the COPY
succeed when the lockfile is absent, and the `|| pnpm install` fallback
re-resolves every dependency from scratch whenever `--frozen-lockfile` fails.
Between them, a build with a stale or missing lockfile still went green, and
shipped a dependency set nobody had reviewed. The deployed image was therefore
not reproducible from the commit it claimed to come from, and lockfile drift
was invisible rather than loud.
Copy the lockfile without the glob and drop the fallback. A stale lockfile is
now a change to make in the repository, which is where it belongs.
Verified before committing: `pnpm install --frozen-lockfile` succeeds against
the committed lockfile (494 packages, 0 downloaded, exit 0), and the full image
builds on Fly's remote builder with the exact command `Deploy Worker` runs:
flyctl deploy --config apps/worker/fly.toml \
--dockerfile apps/worker/Dockerfile --remote-only --build-only
That produced registry.fly.io/wright-worker:deployment-01KZ103D4RXNBE1NQKK9Q1N9JS
(815 MB) and created no release, so wright-worker.fly.dev stayed on v18
throughout.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM
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.
What
apps/worker/Dockerfilebuilt the image with two independent escapes from the lockfile:The
pnpm-lock.yaml*glob lets theCOPYsucceed with no lockfile at all, and|| pnpm installre-resolves every dependency whenever--frozen-lockfilefails. A build with a stale or missing lockfile therefore went green and shipped an unreviewed dependency set. The deployed image was not reproducible from the commit it claimed to come from, and lockfile drift was invisible.This copies the lockfile without the glob and drops the fallback.
Why now
Deploy Workerhas never had a successful run: 9 for 9 failures in March 2026, all becauseFLY_API_TOKENdid not exist. The token now exists on theproductionenvironment and #30 proved it authenticates read-only. The workflow triggers only on a push touchingapps/worker/**, and nothing has touched those paths sincee99cdbe(2026-03-19) — the very commit whose deploy failed. So the deploy path is credential-complete but still entirely unexercised.This change is a real defect fix that also happens to touch
apps/worker/**, so merging it exercisesDeploy Workerend to end for the first time.Verification done before opening this
pnpm install --frozen-lockfilesucceeds against the committed lockfile: 494 packages resolved, 0 downloaded, exit 0. Removing the fallback breaks nothing.The full image builds on Fly's remote builder with the exact command the deploy job runs, minus the release:
Result:
registry.fly.io/wright-worker:deployment-01KZ103D4RXNBE1NQKK9Q1N9JS, 815 MB. No release was created;flyctl releasesstill shows v18 from 2026-03-19 andwright-worker.fly.dev/healthkept answering{"status":"ok"}throughout.Deploy risk and rollback
Merging releases a freshly built image over the live worker. The app was idle at merge time (
activeJobs: 0) and Fly health checks gate the rollout. The currently live image is recorded for rollback:Known, not fixed here
The image is still not reproducible in other ways:
node:22-slim,ghcr.io/astral-sh/uv:latest,npm@latest,@anthropic-ai/claude-codeandrustup ... stableare all floating. Pinning them changes the runtime materially and deserves its own reviewed change; this PR fixes only the lockfile escapes.🤖 Generated with Claude Code
https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM