Skip to content

fix(template): stabilize copier update and unbreak the first commit - #345

Merged
ichoosetoaccept merged 4 commits into
mainfrom
template-stability
Aug 5, 2026
Merged

fix(template): stabilize copier update and unbreak the first commit#345
ichoosetoaccept merged 4 commits into
mainfrom
template-stability

Conversation

@ichoosetoaccept

@ichoosetoaccept ichoosetoaccept commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

Four commits that make copier update safe to run on a released project, plus the
dependency bump they were tested against.

Commit What
dcf0f7f Upgrade dependencies; raise floors to the tested versions (ruff 0.16.1, ty 0.0.66, prek 0.4.12). Carries copier 9.17.1, a security release.
b40cc5a Preserve project.version and tool.semantic_release.tag_format across updates.
1fc4bbc Match uv's own uv_build pin; raise the floor to 0.12.1.
a68a425 Stop coverage's sysmon core breaking the first commit in a fresh project.

Why

b40cc5a is the one worth reading closely. sync_marked_sections.py regenerates
pyproject.toml in full from the template and splices back only marked regions.
project.version and tag_format are owned by neither the template nor the user but
by python-semantic-release, which rewrites them in the project between updates — so a
fresh render resets them to the seed 0.0.0 / {version}.

Markers cannot fix this. A project updating from a marker-less version has no
snapshot to splice, so its first update — the one that matters — would still reset
them. Preservation is therefore by key path, which needs no downstream action.

One subtlety in the implementation: the table-end scan requires a whole-line bracketed
header. A bare ^\[ truncates [tool.semantic_release] at the column-0 shell guards
inside the multi-line build_command, which sit before tag_format — preservation
would have silently no-opped on the real template while passing synthetic tests. There
is a regression test for exactly that shape.

a68a425 fixes a live breakage. The first git commit in any freshly scaffolded
project currently fails. coverage selects the sys.monitoring core by default on
CPython 3.14+, that core cannot do dynamic contexts, pytest-testmon uses them, and
filterwarnings = ["error"] promotes coverage's warning into an INTERNALERROR.
Fixed by scoping COVERAGE_CORE=ctrace to the testmon hook via prek's per-hook env,
so pytest-cov keeps the faster core. Silencing the warning was rejected: testmon uses
those contexts to pick which tests to run, so incomplete data would keep the hook green
while selecting the wrong tests.

1fc4bbc changes nothing structural. uv 0.12 made uv init emit [build-system]
with uv_build by default, converging on what this template already generated. The
upper bound stays because it is uv's recommendation, not ours.

Test plan

  • pytest tests/test_template_lint.py — 39 passed (all boolean answer combinations render valid TOML/YAML)
  • pytest tests/test_template.py::TestIntegration::test_first_commit_succeeds_with_prek_hooks — passes; this is the test that was failing before a68a425
  • New regression tests: released version and tag_format survive an update; the table scan survives the build_command shell guards; an absent scalar keeps the fresh seed; the rendered pyproject.toml is both readable and rewritable by the preservation code
  • New fast guard asserting the rendered testmon hook carries COVERAGE_CORE=ctrace via prek's env key rather than an entry prefix (the CI matrix includes Windows, where an env VAR=value prefix would not work)
  • End-to-end: rendered a real project, confirmed 0.18.0 and v{version} survive an update while line-length still tracks the template

Refs DOT-620

Greptile Summary

This change updates generated-project dependency floors, raises the uv build-backend requirement, preserves semantic-release-managed version metadata during Copier updates, and configures the testmon hook to use coverage’s C tracer core on Python 3.14+.

A real Copier update from the pre-change template to this revision was exercised with a released project.version and a custom tool.semantic_release.tag_format. Both values remained intact after the update, while template-owned configuration—including the updated uv_build requirement—was refreshed. Focused tests also passed for scalar preservation, rendered configuration shape, and the multiline semantic-release build-command case.

No defects were found.

Confidence Score: 5/5

Safe to merge based on the exercised Copier update flow and focused regression coverage.

No defects remain after validating that release-managed metadata survives a real update while fresh template-owned configuration is applied.

Files Needing Attention: None.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the reproducible Copier semantic-release update-flow validator to generate a semantic-release-enabled project from the pre-change template, apply version and tag_format changes, and run a Copier update against the revision, and the updated project retained both release-managed values, adopted the uv_build>=0.12.1,<0.13 requirement, retained the multiline UV_CACHE_DIR build-command guard, and passed four focused tests.
  • Captured baseline and after-update states, plus focused regression-test output, to verify the update flow.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "fix(template): stop coverage sysmon core..." | Re-trigger Greptile

…ions

Floors track the version the template is actually exercised against, not the
oldest release that still happens to work: ruff 0.16.1, ty 0.0.66, prek 0.4.12.
Also carries copier 9.17.1 (security fixes) through uv.lock.

The ruff ci-group assertion now compares against required-version as a lower
bound instead of matching a literal string, so the ci floor can track the tested
release without the test having to be edited in lockstep.

prek 0.4.11 added the [priorities] alias tables; with the floor at 0.4.12 the
generated-config note about them being blocked no longer applies.
… across updates

`copier update` regenerates pyproject.toml in full from the template and splices
back only marked regions. `project.version` and `tool.semantic_release.tag_format`
are owned by neither the template nor the user but by python-semantic-release,
which rewrites them in the project between updates, so a fresh render resets them
to the seed `0.0.0` / `{version}`.

Markers cannot fix this: a project updating *from* a marker-less version has no
snapshot to splice, so its first update -- the one that matters -- would still
reset them. sync_marked_sections.py now snapshots both by key path from the
existing file and writes them back into the fresh render.

The table-end scan requires a whole-line bracketed header. A bare `^[` would
truncate [tool.semantic_release] at the column-0 shell guards inside the
multi-line build_command, which sit before tag_format -- preservation would have
silently no-opped on the real template while passing synthetic tests.

Refs DOT-620
uv 0.12.0 made `uv init` write a [build-system] block by default; on 0.12.1 it
emits `uv_build>=0.12.1,<0.13.0`. The template's window was `>=0.12,<0.13`, so
raise the floor to match uv verbatim.

The upper bound stays, and the docs now say why it is not ours to drop: uv_build
follows uv's versioning policy and uv's own build-backend docs ask for an upper
bound so packages keep building as new versions land. Also documents why a stale
window is never a breakage -- uv uses its bundled backend copy only when it
satisfies `requires`, and otherwise resolves uv_build from PyPI into an isolated
build env, so the project still builds, just without the bundled fast path.

No template machinery selects the backend; [build-system] is PEP 517's, and uv
has converged on the src/ layout the template already generated.
The first commit in a freshly scaffolded project fails. The pytest-testmon
pre-commit hook dies before running anything:

  INTERNALERROR> coverage.exceptions.CoverageWarning: Dynamic contexts aren't
  supported with core=sysmon; context data may be incomplete

Nothing in the template changed to cause this; four existing choices finally
lined up:

1. coverage selects the sys.monitoring core by default on CPython 3.14+
   (SYSMON_DEFAULT = CPYTHON and PYVERSION >= (3, 14)). This template requires
   3.14, so every generated project gets it.
2. That core cannot do dynamic contexts. coverage does fall back on its own --
   but only when dynamic_context is set in config, which it reads once, up front.
3. testmon never sets it in config; it calls switch_context() imperatively per
   test, long after coverage has committed to sysmon. All coverage can do is warn.
4. filterwarnings = ["error"] promotes that warning to an exception raised inside
   a pluggy hook, so pytest aborts with INTERNALERROR and exit 3.

Fixed by forcing COVERAGE_CORE=ctrace on the testmon hook only. Silencing the
warning was rejected: testmon uses those per-test contexts to decide which tests
a change affects, so incomplete context data would keep the hook green while
quietly selecting the wrong tests.

Scoped through prek's per-hook env rather than [tool.coverage.run] core, so the
pytest-cov hook and poe test-cov keep sysmon, the faster core on 3.14. env also
works on Windows, which the CI matrix covers -- an 'env VAR=value' prefix on
entry would not, since prek execs the entry without a shell.

Adds a fast assertion on the rendered hook; the existing integration test covers
the same ground end-to-end but is marked slow.
@linear-code

linear-code Bot commented Aug 5, 2026

Copy link
Copy Markdown

DOT-620

@ichoosetoaccept

Copy link
Copy Markdown
Member Author

@ichoosetoaccept ichoosetoaccept changed the title chore(deps): upgrade dependencies and raise floors to the tested versions fix(template): stabilize copier update and unbreak the first commit Aug 5, 2026
@ichoosetoaccept
ichoosetoaccept merged commit f7432c7 into main Aug 5, 2026
7 checks passed
@ichoosetoaccept
ichoosetoaccept deleted the template-stability branch August 5, 2026 10:51
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