Skip to content

fix(worker): fail the image build on a stale or missing lockfile - #31

Merged
abrichr merged 1 commit into
mainfrom
chore/worker-deploy-verify
Aug 2, 2026
Merged

fix(worker): fail the image build on a stale or missing lockfile#31
abrichr merged 1 commit into
mainfrom
chore/worker-deploy-verify

Conversation

@abrichr

@abrichr abrichr commented Aug 2, 2026

Copy link
Copy Markdown
Member

What

apps/worker/Dockerfile built the image with two independent escapes from the lockfile:

COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* turbo.json ./
RUN pnpm install --frozen-lockfile || pnpm install

The pnpm-lock.yaml* glob lets the COPY succeed with no lockfile at all, and || pnpm install re-resolves every dependency whenever --frozen-lockfile fails. 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 Worker has never had a successful run: 9 for 9 failures in March 2026, all because FLY_API_TOKEN did not exist. The token now exists on the production environment and #30 proved it authenticates read-only. The workflow triggers only on a push touching apps/worker/**, and nothing has touched those paths since e99cdbe (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 exercises Deploy Worker end to end for the first time.

Verification done before opening this

  • pnpm install --frozen-lockfile succeeds 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:

    flyctl deploy --config apps/worker/fly.toml --dockerfile apps/worker/Dockerfile --remote-only --build-only
    

    Result: registry.fly.io/wright-worker:deployment-01KZ103D4RXNBE1NQKK9Q1N9JS, 815 MB. No release was created; flyctl releases still shows v18 from 2026-03-19 and wright-worker.fly.dev/health kept 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:

registry.fly.io/wright-worker@sha256:0e4691c360d8df9cd4a3e34ae4dee1e966f65663577401fc01e3c6f84a852d31

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-code and rustup ... stable are 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

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
@abrichr
abrichr merged commit 54311b1 into main Aug 2, 2026
1 check passed
@abrichr
abrichr deleted the chore/worker-deploy-verify branch August 2, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant