Skip to content

feat(template): add the enable_changelog layer and dogfood it - #26

Merged
maybebyte merged 5 commits into
mainfrom
feat/changelog-check
Sep 13, 2026
Merged

feat(template): add the enable_changelog layer and dogfood it#26
maybebyte merged 5 commits into
mainfrom
feat/changelog-check

Conversation

@maybebyte

@maybebyte maybebyte commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Summary

The release step ("promote the Unreleased entries before tagging") is only as good as the entries people remembered to write, and nothing enforced writing them. This adds the changelog check as a template layer first, then dogfoods it here: the first Phase 2 layer of the dogfooding audit, and the first template change since v0.2.0 (so it becomes v0.3.0).

Changes

  • New enable_changelog toggle (default true) shipping a Keep-a-Changelog CHANGELOG.md, a PR-only changelog.yml, and a two-line AGENTS.md section. The check fails when src/ or pyproject.toml change without a CHANGELOG.md change; the skip-changelog label bypasses it. CI-only, no recipe, since a base-ref diff has no local form.
  • Three mechanics are deliberate, each verified against primary docs and pinned by a test: types: lists all five activity types (it replaces the defaults, and a bare pull_request never re-runs on a label change); the label is honoured inside the step, not a job-level if:, so the check reports pass rather than "skipped"; and github.base_ref reaches the script through env:, which zizmor requires.
  • Hardened after an adversarial review of the branch: "an entry" means at least one non-empty added line (a deleted or whitespace-only CHANGELOG.md no longer passes); the base ref is verified first, so a shallow checkout errors instead of passing vacuously; nested-repo renders no longer cite the workflow they do not get; and the maintainer copy's literals are pinned by the policy suite.
  • Maintainer dogfood: the same workflow on template/** and copier.yml (maintainer CI changes need no entry, so Renovate's Action bumps pass untouched), AGENTS.md section, README row, Unreleased entry, audit status update. run_in gains an env kwarg for the new gate test.

Testing

  • just fmt-check lint typecheck policy — all pass; policy suite 7 passed (was 6).
  • Targeted pytest -k 'changelog or existing_repo_layer or all_toggles_on or rendered_workflows_pass_zizmor or agent_contract or ci_workflows' — 7 passed. The gate test runs the rendered script against a scratch clone: blocks a src/ change with no entry, a whitespace-only touch, and a deleted changelog; errors on an unresolvable base; passes with the label, with a real entry, and for a README-only change.
  • uvx zizmor@1.26.1 --persona=regular --offline .github/workflows — no findings.
  • The maintainer script run locally against this branch: prints changelog: ok; a scratch commit touching only copier.yml exits 1 with the expected ::error::; BASE_REF=nope exits 1 with cannot resolve.
  • CI on the final commit (f57560b): all 11 checks pass — the six-leg test matrix (full generation suite), lint, typecheck, scan, zizmor, and the new changelog job.

Notes for reviewers

  • The skip-changelog label already exists on this repo. Downstreams create theirs once, per the generated AGENTS.md.
  • After merge: promote the Unreleased entry under 0.3.0 and tag, then run the first real copier update on the two nested renders in fix-wifi-issues.
  • Decision: no repository_url answer for compare links in the generated changelog. A new required answer for a hyperlink is not worth the update-prompt cost; downstreams add links at their first release.

Related

  • Audit: docs/superpowers/plans/2026-07-01-dogfood-gap-audit.md, section 6 group C and Phase 2 item 8.

Ships a Keep-a-Changelog CHANGELOG.md and a PR-only changelog.yml that
fails when src/ or pyproject.toml change without a CHANGELOG.md change,
unless the PR carries the skip-changelog label. CI-only; no recipe, since
a base-ref diff has no local form.

Three mechanics are deliberate and tested: `types:` lists all five
activity types because it replaces the defaults and a bare pull_request
never re-runs on a label change; the label is honoured inside the step
rather than a job-level `if:` so the check reports pass, never
"skipped"; and github.base_ref reaches the script through env:, which
zizmor requires.

The generation suite asserts present-when-on, absent-when-off, and runs
the rendered script against a scratch clone in the blocking, labelled,
and entry-added cases. run_in gains an env kwarg for that.
Same workflow as the template layer, on the maintainer's own pins, with
the trigger paths template/ and copier.yml: the CHANGELOG describes
generated-project behaviour only, so maintainer CI changes (including
Renovate's Action bumps) need no entry. Documents the layer in AGENTS.md
and marks Phase 2 of the dogfooding audit as started.
With in_existing_repo the .github/ directory is never rendered, so the
AGENTS.md section and the justfile ci comment must not cite a
changelog.yml that does not exist. The authoring rule and CHANGELOG.md
itself still ship; only the CI references are conditional. The same
condition now also guards the comment's scan.yml reference, which had
the same dangling problem.
A deleted or whitespace-only CHANGELOG.md satisfied the check, because
it only tested that the path appeared in the diff. It now requires at
least one non-empty added line. An unresolvable base ref (a shallow
checkout) made both git diff calls fail inside the test condition, which
bash -e ignores, so the check printed ok and exited 0; the base is now
verified first and the step errors.

The gate test covers the whitespace touch, the deletion, the bad base,
and a change outside the trigger paths (pinning the pathspec). The
policy suite pins the maintainer copy's literals, since the generation
suite only runs the rendered template's script. The nested-repo test
asserts nothing rendered cites the omitted workflow, and the all-toggles
renders include the new layer.
…rantees

No v0.3.0 tag exists yet; the entry is still under Unreleased. The
Release section claimed the check guarantees an entry, but the
skip-changelog label bypasses it, so promotion needs a look at labelled
PRs. Also records that the changelog workflow is the one exception to
folding maintainer CI into test-template.yml, and describes the
fail-closed base check.
@maybebyte
maybebyte merged commit f1e43bc into main Sep 13, 2026
11 checks passed
@maybebyte
maybebyte deleted the feat/changelog-check branch September 13, 2026 18:10
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