Skip to content

Modernize Heroku build: template is re-rendered at deploy time with no CI guard for lock/render drift #511

Description

@whusterj

Background

Staging (and PR review-app) builds silently broke on Jul 10 and stayed broken for days while CI remained green. Root cause: the Jul 10 dependabot bumps (#507, #509) updated {{cookiecutter.project_slug}}/pyproject.toml but did not regenerate {{cookiecutter.project_slug}}/uv.lock. Immediate fix: #510 (regenerate the stale template lock).

This issue tracks the underlying fragility that let a routine dep bump take down deploys undetected.

Why it broke silently

Heroku does not deploy the committed my_project/. It re-renders the cookiecutter template at build time:

# scripts/buildpack_run.sh
uvx cookiecutter . --config-file cookiecutter/react_template.yaml --no-input -f

…then runs uv sync --locked on the freshly rendered project. So the real deploy artifact is a build-time render of {{cookiecutter.project_slug}}/, and CI never exercises that path — it renders + lints the template but never runs uv sync --locked on the render. Any drift between the template's pyproject.toml and its uv.lock breaks deploys with zero CI signal.

Problems to address

  1. No CI guard for the deploy path. Add a job that renders the template and runs uv sync --locked --no-default-groups (i.e. the exact Heroku step) so template lock/render drift fails CI, not the deploy.
  2. Dependabot doesn't keep the template lock in sync. Bumps touch {{cookiecutter.project_slug}}/pyproject.toml but not its uv.lock. Automate regenerating the template lock (render → uv lock → copy back) as part of dependency updates, or fold it into the CI guard above.
  3. Build-time cookiecutter render is a fragile deploy strategy. Reconsider re-rendering the template on every deploy. Options: deploy a committed rendered project, or at minimum gate the render behind a tested step.
  4. Duplicate heroku/python buildpacks + subdir relocation (app.json) make the build hard to reason about (two Python passes, one on the repo root's tooling deps, one on the rendered app). Simplify.
  5. uv version / lock-revision consistency. Heroku uses uv 0.11.28 (writes lock revision = 3); the repo's committed locks are revision = 1. Pin/standardize uv across Heroku + CI + local and normalize lock revision so a newer uv doesn't silently reintroduce drift.
  6. Review apps don't build reliably on PR open (had to be created/nudged manually for Add root worktree justfile; align worktree dir naming across justfiles + specs #504 and Fix: regenerate stale template uv.lock (unbreaks staging/review builds) #510). Verify Heroku review-app automation is correctly configured.

Immediate status

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions