Plan how an existing bench picks up template changes (copier update)

Problem

bench scaffold runs copier copy and nothing else — never copier update. That is the right call for the current slice (an update on a non-TTY prompts and fails, and --overwrite on the repo phase would clobber CI config, README and CODEOWNERS), but it means an existing bench can never pick up later template changes: migrations, base-image bumps, or a security fix to Dockerfile.assembly itself. Today the only path is a manual, undocumented one.

Raised by @theoretick in common-template-copier!880#note_3658291206, which asked for a tracked plan rather than a fix in that MR.

This matters more now than it did before !57 (merged): the image recipe used to be generated from a fixture compiled into the bench binary, so a bench picked up a new base image by upgrading bench. It is now a checked-in file, so an old bench keeps an old recipe indefinitely.

What already exists

  • The repo render is updatable in principle. It writes .copier-answers.yml at the repository root, recording _commit and _src_path, which is all copier update needs.
  • Renovate covers the case that worried the reviewer most. A scaffolded bench extends renovate-common, whose dockerfile manager bumps FROM pins in checked-in Dockerfiles — so a base-image CVE reaches an existing bench as an MR without any re-scaffold. That was a stated reason for moving the recipe into the template. It does not cover template changes to any other line, or _migrations.
  • Dockerfile.assembly is deliberately not in _skip_if_exists, so it is one of the files an update could carry, unlike /Dockerfile.

What blocks an update path

  • Component renders cannot be updated at all. The template's _exclude drops everything but the handler files in component mode, so no .copier-answers.yml is written into internal/<pkg>/ — verified on a scaffolded sandbox. Any update story is therefore repo-phase only, which is probably fine (the handler is user code by then) but should be stated rather than discovered.
  • _src_path records whatever BENCH_TEMPLATE_URL was. A bench scaffolded with the local-checkout override records a filesystem path, and an update from that answers file would read a directory that does not exist on anyone else's machine.
  • Non-TTY conflicts. An unchanged template and unchanged file report "identical" with no prompt, but a changed recipe or a user edit produces a conflict and an interactive prompt, which fails in CI. That is arguably the correct failure — your image recipe changed upstream, decide — but it means re-scaffolding cannot be automated as-is.
  • --trust re-runs hooks and _tasks on update, including the template's go mod tidy (currently gated off for labbench, !880).
  • Answers arrive as strings. bench passes every answer with -d, so a Jinja validator sees "false" rather than false; that already breaks a Rust bench on any template ref newer than v1.64.0 (the handler_func PascalCase validator) and would break an update the same way, since questions are re-asked. Possibly the same fix as switching to a typed --data-file.
  • Copier version floor. The template sets _min_copier_version: 9.12.0 because _skip_if_exists anchoring is only correct on update from that version; bench preflights that copier exists but not which version.

Options

  1. bench scaffold --update wrapping copier update for the repo phase only, with the answers-file and _src_path caveats handled explicitly.
  2. Document a manual procedure in the bench docs and keep bench out of it — cheapest, and enough while the number of benches is small.
  3. Lean on Renovate for pins and accept drift elsewhere, revisiting when a template _migration actually needs to reach a bench.

Deciding between these needs no code, so the first deliverable is a short decision note rather than an implementation.