Skip to content

v0.26.0 — The namespace, not the numbers

Latest

Choose a tag to compare

@github-actions github-actions released this 08 Aug 15:26
· 1 commit to main since this release
b71fb59

v0.26.0 — The namespace, not the numbers

Release date: 2026-08-08

Closes the root cause behind four consecutive releases of pinning.

What was actually wrong

The repository used one mechanism — git tags — for two incompatible
purposes
:

Purpose Requirement
Release-channel markers (v0.x) machine-sortable; only live releases
Frozen audit snapshots (v1.0.0v1.12.0) permanent; never resolved

Version-resolving tooling takes the highest-sorting tag. v1.12.0
outranked every v0.x release, so the April 2026 audit snapshot won every
unpinned resolution. That produced four defects in four releases — a
release that reached nobody, an incomplete docs fix, a destructive
copier update, and a fourth surface the guard's hand-written file list
could not see.

Every fix was a --vcs-ref pin. Pinning is correct and it treats the
symptom. The namespace collision was the disease.

The fix

v1.0.0v1.12.0archive/v1.0.0archive/v1.12.0. Same commits,
same trees, same signatures
— verified 15/15 by SHA, with git diff
confirming byte-identical trees.

It works because Copier filters tags through a PEP 440 check before
sorting (copier/_vcs.py:get_latest_tag):

all_tags = (tag for tag in all_tags if valid_version(tag))
sorted_tags = sorted(all_tags, key=version.parse, reverse=True)

archive/v1.12.0 is not a valid PEP 440 version, so it is discarded before
the sort ever runs. The same property protects sort -V, git describe
heuristics, "latest release" queries and dependency bots — this is not a
Copier-specific patch.

Measured, on the exact bare commands that caused every prior defect

Command Before After
get_latest_tag() v1.12.0 v0.25.0
copier copy (no ref) 435 files, no answers file 627 files, _commit: v0.25.0
copier update (no ref) 627 → 435, 582 deleted, answers file gone 627 → 627, 0 deleted, answers file present

Why not renumber

Jumping the active line past v1.12.0 (to v2.x) was the obvious
alternative and was rejected. RELEASING.md §2 reserves v1.0.0 for the
first cloud E2E validation, and the whole v0.x line exists to signal not
GA yet
. Inflating the version to outrank a dead tag would make the version
number misstate the project's maturity in order to satisfy a sorting
algorithm
— a worse lie than the bug it fixes.

The immutability rule, reinterpreted rather than quietly broken

ADR-014 and agentic/rules/18 declare the v1.x tags immutable. Renaming
them looks like a violation on the letter, so ADR-045 states the
distinction explicitly instead of leaving the gap for a future reader:

  • What the rule protects: that the past cannot be made to look better
    than it was — a tag must never move to a different commit, and history
    must never be re-signed to imply verification that did not happen.
  • What this change does: preserves every commit, tree, release note and
    signature. Only the reference name moved.
  • Therefore: immutability attaches to the commit and its content, not
    to the string used to reach it.

Deleting an archived snapshot outright remains forbidden. Archiving
preserves provenance; deletion destroys it.

Also fixed

agentic/rules/18 still required .gitleaks.toml to mirror the legacy
singular [allowlist] alongside [[allowlists]]. That mirror was removed
in v0.22.0 because gitleaks >= 8.25 refuses to load a config containing
both — the rule was mandating the exact state that breaks the scanner.

Known follow-ons (scoped, not regressions)

  • External links to /releases/tag/v1.12.0 now 404. The 15 releases
    were re-pointed to their archive/ tags and remain public; the old tag
    URLs are gone. Acceptable given the template has no adopters beyond the
    maintainer, and every body is duplicated in releases/v1.*.md.
  • Pins and guards are retained deliberately. --vcs-ref remains
    correct practice for any Copier template — the default resolves to
    whatever sorts highest, which is surprising in general. The trap is gone;
    the hygiene stays.
  • Carried forward: un-rehearsed MIGRATION recovery procedures, copier update across a real version gap, clock-allowlist brittleness keyed by
    file:line, ruff UP/B/S, mypypyright, shadow-lane precision
    data, codecov still linked to the pre-rename repository slug.

Verification

Evidence in VALIDATION_LOG.md Entry 020.