Files
gstack/ship/sections/changelog.md
T
Garry Tanandcapy-ai[bot] 914e7b6fb3 Write PR titles, commit messages and branch names in plain English (GST-1825) (#4146)
* Add a check that keeps tracker codes and internal jargon out of PR titles and branch names

gstack-plain-title checks the readable front of a title, branch name, PR opening or changelog entry against the repository's .gstack/plain-titles.json; one trailing issue code stays allowed. A Plain title workflow runs it on every new pull request, and /ship's push refuses a never-pushed branch whose name fails it.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Move the PR body's machine-read lines into a closing Agent notes section

The ship receipt, its runs block and the Plan line now live in one collapsed section at the end of the body, and every reader looks there first while still accepting the old receipt-at-top layout. gstack-post refuses to post a title the plain-title check refuses, and land uses the checked PR title as main's commit title.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Teach /ship to write plain titles, PR openings, commit messages and changelog entries

The README now lists what gstack is for, so a PR opening can name the goal it serves.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Keep tests, size budgets and generated files in step with plain titles and Agent notes

Copy lists that install result-code modules now include the plain-title codes, the ship goldens and size ledger are refreshed, the new workflow is classified, and the pinned prose tests read the new title and body layout.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Record the test-profile list change as non-behavioral for the shared test harness

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Keep text people add below the PR notes, and fix three smaller review findings

The notes section now ends at its own closing tag, so a collapsible added after it survives the next post. The opening check splits the body the same way the notes reader does. Wave PR titles no longer name the area, which the plain-title check could refuse. The Capy line in the PR-body steps now puts Approvals in the notes.

Review-Finding: p1/specialist-batched#1 reader=testing
Review-Finding: p1/red-team#1 reader=red-team
Review-Finding: p1/red-team#2 reader=red-team
Review-Finding: p1/red-team#3 reader=red-team
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Mask credentials in refused-title lines and keep older PRs' plan lines readable

A refused title's printed match is masked by the secret scanner first. The Plan line reader falls back to the whole body when the Agent notes section has none, so a body written before this change keeps its plan when its first receipt lands. The notes section also ends at its own closing tag when its opener is split or marked open, or when a collapsible inside it is left unclosed.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Print a fixed placeholder when a credential in a refused title cannot be masked

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Keep a plain-title policy edit from scheduling every paid eval

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Record the paid-eval list change as non-behavioral for the shared test harness

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Recheck the PR title on every edit so a base change cannot turn a refused title green

Review-Finding: s11/targeted#1 reader=targeted
Review-Finding: s11/adversarial-native#1 reader=adversarial-native
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-11-08 00:59:38 +00:00

3.3 KiB

Step 13: CHANGELOG (auto-generate)

  1. Read CHANGELOG.md header to know the format.

  2. First, enumerate every commit on the branch:

    git log origin/<base>..HEAD --oneline
    

    Copy the full list. Count the commits. You will use this as a checklist.

  3. Read the full diff to understand what each commit actually changed:

    git diff origin/<base>
    
  4. Group commits by theme before writing anything. Common themes:

    • New features / capabilities
    • Performance improvements
    • Bug fixes
    • Dead code removal / cleanup
    • Infrastructure / tooling / tests
    • Refactoring
  5. Write the CHANGELOG entry covering ALL groups:

    • If existing CHANGELOG entries on the branch already cover some commits, replace them with one unified entry for the new version
    • Categorize changes into applicable sections:
      • ### Added — new features
      • ### Changed — changes to existing functionality
      • ### Fixed — bug fixes
      • ### Removed — removed features
    • Write concise, descriptive bullet points
    • Insert after the observed file header, before the first release entry, dated today
    • Format: ## [X.Y.Z.W] - YYYY-MM-DD
    • Voice: Lead with what the user can now do that they couldn't before. Use plain language, not implementation details. Never mention TODOS.md, internal tracking, or contributor-facing details: no tracker codes (GST-123, R-numbers) anywhere in the entry, and a bold lead a user of the project understands without the repository's coined terms (docs/ship-policy.md#plain-titles).
  6. Cross-check: Compare your CHANGELOG entry against the commit list from step 2. Every user-facing change in that list must be represented; add any that is missing. Commits with no user-facing effect (merges, version bumps, fixes to work introduced earlier on this branch) need no bullet. The entry must reflect every user-facing theme.

Do NOT ask the user to describe changes. Infer from the diff and commit history.

  1. Lint the entry: ~/.claude/skills/gstack/bin/gstack-prose-lint CHANGELOG.md --base origin/<base> --gate reads only the lines this branch added; rewrite each PROSE: line it names and rerun until the trailer is PROSE_LINT: ok. A fragment file (policy changelog_fragments) also runs ~/.claude/skills/gstack/bin/gstack-plain-title check --changelog <fragment> until its last line is ok, exempt or none: no tracker code in the entry and a plain bold lead.

NO_VERSION (Step 12): skip this step; write no CHANGELOG entry or version header.

Kept (Step 12 VERSION: <v> kept): no version header. Put the entry where the repo's own rule puts unit-PR notes (its CHANGELOG preamble or a fragment directory it names), else under ## [Unreleased], never under a released heading.

No CHANGELOG: when the policy's changelog is null, or the file it names (CHANGELOG.md by default) is absent at HEAD, print one line, CHANGELOG: skipped (none at <path>), write nothing and never create the file; Step 19's PR body carries the release notes instead. A repository with neither a version source nor a CHANGELOG ships with both lines printed and a receipt whose version is "none" (docs/ship-policy.md#ship-receipt).