Files
Pavel LavrukhinandClaude Opus 5 cb53065994 feat(changelog): migrate to Keep a Changelog 1.1.0 (#3506)
* docs(adr): resolve the A-13 collision, zero-pad numbers and add an index

Two records carried the number A-13:

  docs/adr/A-13-expired-gpg-key-handling.md
  docs/adr/A-13-screenshot-build-tag.md

An ADR number is a stable identifier, so a duplicate makes every citation
ambiguous. A-13-expired-gpg-key-handling.md keeps the number: it is cited
from docs/commands/recipients.md, docs/usecases/team-workflows.md and
docs/adr/A-14-team-workflows.md. The screenshot record has no inbound
citations and is renumbered to A-15.

Zero-pad A-3 through A-9 to A-03 through A-09 so the directory sorts
correctly now that the set has passed ten entries. None of these has an
inbound citation from another document; the single reference in
internal/backend/storage/fs/rcs.go is updated in this commit.

Add docs/adr/README.md as the index, recording the naming rules, the status
and authoring date of every record, and three facts that are otherwise only
discoverable from git history:

- A-01 and A-02 are cited from the CHANGELOG unreleased section but no file
  was ever written for either; the numbers stay reserved.
- The A-13 collision and which record was renumbered.
- SECURITY_AUDIT_REPORT.md and CODE_QUALITY_REPORT.md, cited as the Source
  of A-03 through A-10, were removed in 77894053 and are not in the tree.

No record content is changed apart from the H1 lines, which must match the
file names.

Signed-off-by: Pavel Lavrukhin <46395539+dantte-lp@users.noreply.github.com>

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: add docs/conventions.md and adopt Conventional Commits

CONTRIBUTING.md required a bracketed [TAG] prefix on every commit subject.
That has not matched practice for some time: of the 344 commit subjects
since 2025-01-01, 225 are Conventional Commits and 67 use a [TAG]. The
CHANGELOG unreleased section uses a third set including [SECURITY] and
[PKG-BREAK], neither of which CONTRIBUTING.md lists.

Replace the [TAG] rule with Conventional Commits and add
docs/conventions.md as the single normative reference for:

- commit types (a closed list) and the scopes derived from the package
  layout, including the five values that appear as types in the history but
  are scopes: otp, age, bug, fscopy, openbsd;
- the distinction between a CLI break, which uses "!" and a
  BREAKING CHANGE: footer and forces a major release, and a break confined
  to pkg/gopass, which uses a PKG-BREAK: footer and does not (ADR A-12);
- Semantic Versioning, and which surfaces it does and does not cover;
- branch and tag names, including the release/ and prep/ prefixes owned by
  the release automation;
- file naming for ADRs, documentation and Go sources.

The Developer Certificate of Origin requirement is unchanged. Conventional
Commits governs the subject line and the DCO adds a trailer, so the two are
independent.

Also correct the API Stability section of ARCHITECTURE.md, which still
described pkg/gopass/doc.go as carrying "an explicit instability warning"
and instructed consumers to "treat any pkg/ type or function change as
potentially breaking". Both statements predate ADR A-12: doc.go now
declares the package best-effort stable and permits additive changes in any
release. The section also referred to issue #3414 as an open decision; that
decision is recorded in A-12 with status accepted.

Extend the folder list in AGENTS.md with the five pkg/ directories it does
not mention (otp, passkey, pinentry/cli, protect, qrcon), using each
package's own doc comment as the description.

Signed-off-by: Pavel Lavrukhin <46395539+dantte-lp@users.noreply.github.com>

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(changelog): migrate to Keep a Changelog 1.1.0

CHANGELOG.md used a bespoke format with three overlapping entry conventions:
the bracketed [TAG] prefixes CONTRIBUTING.md mandated, the Conventional
Commit subjects that have been in use since 2025, and a third set in the
unreleased section including [SECURITY] and [PKG-BREAK] that appeared in
neither. Release 1.16.0 contains the first two mixed together.

Adopt Keep a Changelog 1.1.0 and generate the entries from commit subjects.

New package helpers/commitmsg

  Parse and classify commit subjects. It is the single source of truth for
  both the changelog generator and any future commit linting, so the two
  cannot disagree about what a valid subject is. It implements the closed
  type list from docs/conventions.md, the Changelog-Section:, PKG-BREAK:,
  BREAKING CHANGE: and RELEASE_NOTES= footers, and the legacy [TAG] and
  bracketed-type forms so a release spanning the transition still classifies
  its older commits.

  Classify returns a disposition rather than a bare boolean, distinguishing
  a deliberate omission -- a dependency bump, a CI change -- from a subject
  it could not recognise. That distinction matters: over the 137 commits
  since v1.16.1 it classifies 47, omits 60 and cannot recognise 30. Among
  the 30 are real user-facing changes such as "otp: hide --snip flag when
  built with noscreenshot tag", which uses a scope where a type belongs.
  The release helper now prints those subjects instead of dropping them
  silently.

helpers/release: fix the section ordering defect

  writeChangelog inserted the new release before the first "## " heading.
  Once an unreleased section existed, that heading was the unreleased one,
  so the release landed above it and the hand-written entries below were
  orphaned -- never published, and silently carried into every subsequent
  release. The 30 entries currently under "## Next" are in exactly that
  state.

  The new implementation in helpers/release/changelog.go parses the file
  into header, unreleased block, released body and link references; merges
  the hand-written entries with the generated ones and de-duplicates;
  renders the release with only its non-empty subsections, in Keep a
  Changelog order; leaves an empty Unreleased section behind; and rewrites
  the two link references a release changes.

helpers/changelog: skip the unreleased section

  The extractor printed everything between the first and second "## "
  heading. After the migration the first heading is an empty
  "## [Unreleased]", which would have produced empty GitHub release notes.
  It now extracts the first *versioned* section.

CHANGELOG.md data migration

  The 30 entries under "## Next" move into "## [Unreleased]" and are
  distributed by their existing tags. Three are placed by meaning rather
  than by tag, because Keep a Changelog has sections their tags do not:
  the two [UX] entries that remove a CLI alias go to Removed, and the [UX]
  entry about the GOPASS_AUTOSYNC_INTERVAL deprecation goes to Deprecated.
  The bracketed prefixes are dropped; the trailing audit identifiers such
  as (A-1) and (B-8) are kept, since they are the only trace back to the
  audit that produced those entries.

  All 86 released headings become "## [X.Y.Z] - YYYY-MM-DD" with their
  entry text untouched. The two headings that carried no date, 1.10.0 and
  1.10.1, take theirs from their git tags. A link reference block is
  appended; every one of the 86 versions has a matching tag.

  The bullet count is unchanged at 837.

Verified end to end: "go run ./helpers/changelog" against the migrated file
extracts the 1.16.1 section and does not capture [Unreleased].

Signed-off-by: Pavel Lavrukhin <46395539+dantte-lp@users.noreply.github.com>

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(release): correct the swapped Next/Prev labels and fold duplicate entries

Two follow-ups found while verifying the changelog migration end to end.

The "Version overview" block printed by every release run labels its third
and fourth values "Next version flag" and "Prev version flag", but passes
them as prevVerFlag, nextVerFlag. Running

    go run helpers/release/main.go --dry-run v1.17.0

therefore reported "Next version flag: ''" and "Prev version flag: '1.17.0'"
for a flag that sets the next version. The values are swapped to match the
labels. Output only; no behaviour depends on it.

Changelog entries are now de-duplicated case-insensitively. A hand-written
unreleased entry and the subject of the commit that implemented it commonly
differ only in their first letter, for example "Add gopass doctor diagnostic
command (I-4)" against "add gopass doctor diagnostic command (I-4)". This
cannot catch two genuinely different wordings of the same change; those
still need a human pass before the release.

Signed-off-by: Pavel Lavrukhin <46395539+dantte-lp@users.noreply.github.com>

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(adr): align A-12 with the Keep a Changelog format

Three statements in A-12 no longer hold once CHANGELOG.md follows Keep a
Changelog:

- The entry goes in "## [Unreleased]", not "## Next".
- "The existing helpers/changelog generator reads CHANGELOG.md verbatim; no
  changes to that tool are needed" is false. The extractor had to learn to
  skip the unreleased section, and the release helper now classifies commits
  rather than copying subjects.
- "[SECURITY], [BUGFIX] and [FEATURE]" are no longer tags. They are the
  Security, Fixed and Added subsections.

State the mechanism instead: a PKG-BREAK: commit footer, which
helpers/commitmsg reads and helpers/release renders as a [PKG-BREAK]-prefixed
bullet inside the appropriate subsection. [PKG-BREAK] survives as a bullet
prefix because it qualifies an entry rather than categorising it, which is
exactly what a Keep a Changelog subsection cannot express.

Writing the prefix by hand into "## [Unreleased]" still works; the release
helper preserves it.

Signed-off-by: Pavel Lavrukhin <46395539+dantte-lp@users.noreply.github.com>

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 23:05:23 +02:00
..