Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 54 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ owned that content all along.)
| **`docs/SELF_HOSTED_RUNNER.md`** | Setup and operation of the self-hosted highcpu runner | CI policy, which lives in the workflows |
| **`src/docs/development/upstream-map.yaml`** | **Source of truth** for fork↔upstream mapping: fork branch/PR → upstream **PR**, with status | Editorial opinion (that is the `.adoc` beside it), and **upstream issues** - those live in the fork mirrors, `upstream-mirror` label |
| **`src/docs/development/upstream-pr-analysis.adoc`** | Editorial analysis of upstream PRs: rankings, verdicts, merge order | Facts - when they disagree, the manifest wins |
| **`CHANGELOG.adoc`** | Release notes. Frozen up to `== 0.6.0.0`; later sections are generated at release time from the commit log. `README.adoc` links to it and no longer embeds it | Anything invisible to users or operators - and **not** a per-PR chore: do not add entries in a feature PR |
| **`CHANGELOG.adoc`** | Release notes. Sections for **shipped** releases are frozen; the section for the release being cut - **`== 0.6.0.0` included** - is regenerated at release time from the commit log, so what is under it today is working text, not the notes v6 will publish. `README.adoc` links to it and no longer embeds it | Anything invisible to users or operators - and **not** a per-PR chore: a PR never *adds* an entry. Correcting a factual error in an existing one is the only edit it may make |

Rule of thumb: **is it happening now** → `docs/inflight/`; **should happen later** → `refactoring.md`;
**already happened** → `CHANGELOG.adoc` or `docs/solutions/`.
Expand Down Expand Up @@ -227,12 +227,35 @@ stack traces (see Testing).

## Changelog

`CHANGELOG.adoc` holds the release notes. **Nothing about it is a per-PR chore.** Do not add entries
in a feature PR, and do not maintain an `== Unreleased` section. Everything up to and including
`== 0.6.0.0` is hand-written and now frozen; from the next release on, each section is **generated at
release time from the commit log** and then frozen in turn.
`CHANGELOG.adoc` holds the release notes. **Nothing about it is a per-PR chore.**

This removes the file that every PR used to touch - it appeared in 30 of the last 30 master commits,
**Release-time generation is in effect now, and it covers `0.6.0.0` itself.** "Frozen" below is a
statement about *text already written in the file* - leave it alone - and never a claim that some
release's published notes are settled. What state a section is in follows from whether its release
has **shipped**:

| Section | State |
|---|---|
| `== 0.5.x` and below | Hand-written legacy from before the fork, and shipped. **Frozen.** |
| `== 0.6.0.0` - the release being cut | **Not shipped, so not settled.** Whatever sits under this heading now is working text. It will be **regenerated at release time from `git log <last-tag>..HEAD`**, replacing what is there, and frozen only once 0.6.0.0 ships. |
| Every release after it | Same treatment: generated when that release is cut, frozen once it ships. |

Two readings this is written to rule out. **`0.6.0.0` is not on the hand-written side of the line** -
generation does not start at some later release. And **the current contents of `== 0.6.0.0` are not
what v6 will publish** - do not cite them as the release notes, and do not treat the section as
appendable just because the release has not gone out. It is not yours to add to *or* to trust.

**In a PR the changelog is never added to.** No new entries, and no `== Unreleased` section - a
shipped section is finished, and the in-flight section belongs to the generator. There is no window
in which a PR contributes an entry.

**The one edit a PR may make is correcting a factual error in text that is already there.** astubbs#198 did
exactly this: a Dependencies entry said the Kafka client stayed on `3.9.1` when the pom had moved to
`3.9.2`. A wrong statement in a published artefact does not get better by waiting for the next
generation pass, so fix it. The test is whether you are *changing an existing claim to be true*
(allowed) or *adding information about a change* (the generator's job, not yours).

The policy removes the file that every PR used to touch - it appeared in 30 of the last 30 master commits,
dragging the generated `README.adoc` with it - and removes the ordering problem where an entry had to
cite a PR number that did not exist when the entry was written.

Expand Down Expand Up @@ -267,10 +290,31 @@ section. The judgement it applies, and that a human should re-apply before freez
confluentinc; make issue links explicit (`.../issues/NN[#NN]`), since GitHub numbers issues and PRs
from one sequence.

**Still live, and now inert:** the `PR Checklist` gate's changelog rule
(`.github/scripts/changelog-ref-gate.js`) fails a human PR that *adds* a `CHANGELOG.adoc` entry citing
no issue. Since PRs no longer touch the file, it should never fire - it remains a guard for anyone
hand-editing the frozen sections.
### The `PR Checklist` changelog gate is a different, narrower check

`.github/scripts/changelog-ref-gate.js` fails a human PR that adds a `CHANGELOG.adoc` bullet under
`Breaking`, `Improvements`, `Fixes` or `Examples` without an explicit `/issues/NN` link. **Do not read
a green gate as compliance with the rule above** - it is neither a subset nor a superset of it, and it
is not dormant:

- It **passes** entries the policy forbids. The gate only cares about the *citation*, so an added
entry that links an issue sails through. astubbs#57's entries all cite issues.
- It **fires** on the one edit the policy allows. The gate cannot tell an edit from an addition - its
own header explains that matching removed bullets against added ones was tried and abandoned as the
subtlest code in the file - so a correction like astubbs#198's looks like a new entry. That is what
`changelog-ref: N/A - <reason>` on its own line in the PR body is for; the workflow names this case
explicitly.
- PRs **do** still touch the file. astubbs#51, astubbs#57, astubbs#105 and astubbs#106 were all open before this policy landed and
all modify `CHANGELOG.adoc`; every PR predating the policy is in the same position.

So the gate enforces the *citation convention* on entries, and a human author and reviewer enforce
"no entries in a PR". Tightening it to reject *every* addition was considered and rejected: "adds an
entry" and "corrects an existing one" are both `+*` lines and are not mechanically distinguishable -
the gate's own header records that matching removed bullets against added ones was built and then
abandoned as the subtlest code in the file. A blanket rule's only escape hatch would be a
self-declared `changelog-ref: N/A - <reason>` in the PR body, which legitimises a violating addition
exactly as easily as a legitimate correction: no enforcement the written rule does not already have,
at the cost of an opt-out on every correction.

## Issue references

Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ NOTE:: Routine/automated dependency bumps (e.g. Dependabot) are not listed here.

NOTE:: *Reference convention (this is a fork).* Links and bare `#NN` / commit hashes refer to this fork, https://github.com/astubbs/parallel-consumer[astubbs/parallel-consumer]. Upstream references are written explicitly as `upstream #NN` and link to https://github.com/confluentinc/parallel-consumer[confluentinc/parallel-consumer]. Entries below `0.6.0.0` predate the fork and their `#NN` refer to upstream.

NOTE:: *How this file is maintained.* Everything up to and including `0.6.0.0` is hand-written and frozen. From the next release on, each section is **generated at release time from the commit log** and then frozen in turn - so do not add entries here in a feature PR, and do not open an `== Unreleased` section. The judgement applied when generating (what earns an entry, and how long it may be) is in `AGENTS.md` -> Changelog.
NOTE:: *How this file is maintained.* A section is frozen once its release has **shipped** - `0.5.x` and below are hand-written legacy from before the fork, and are finished. The section for the release currently being cut is **generated at release time from the commit log**, replacing whatever text is under it, and is frozen in turn once that release ships. **That includes `0.6.0.0` below**: it has not shipped, so what you are reading there is working text and not the notes that release will publish. Consequently a PR never adds an entry here and never opens an `== Unreleased` section; the only edit a PR may make is correcting a factual error in text that is already present. The judgement applied when generating (what earns an entry, and how long it may be) is in `AGENTS.md` -> Changelog.

// git log --pretty="* %s" 0.3.0.2..HEAD

Expand Down
12 changes: 12 additions & 0 deletions bin/test-check-review-posted.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# 10. wrong argument count -> usage (2)
# 11. non-numeric run id -> usage (2)
# 12. empty review outcome -> usage (2)
# 13. match found, then >64 KiB of further comments -> pass (0)
#
# Case 4 is the one worth keeping honest: a plain substring search for "actions/runs/3096"
# matches run 30965089954, which would pass this run's check on a different run's review.
Expand Down Expand Up @@ -77,6 +78,17 @@ $POSTED_COMMENT" 30965089954 success)"
assert "run url at the very end of the stream" \
0 "$(run_checker "see https://github.com/astubbs/parallel-consumer/actions/runs/30965089954" 30965089954 success)"

# The live failure this script shipped with: the match is found, but >64 KiB of
# comments follow it, so `printf | grep -q` + pipefail turned success into exit 1.
# Cases 5 and 6 missed it - case 6 puts the match LAST, so nothing follows to
# fill the pipe buffer. Observed on astubbs#198, astubbs#199, astubbs#204 and
# astubbs#210; on astubbs#210 a 4.7 KB
# review comment was followed by a 127 KB similarity report.
LARGE_TRAILER="$(yes 'padding to exceed the 64 KiB pipe buffer, as a similarity report does' | head -n 2000)"
assert "match found, then >64 KiB of further comments (SIGPIPE regression)" \
0 "$(run_checker "$POSTED_COMMENT
$LARGE_TRAILER" 30965089954 success)"

for outcome in failure skipped cancelled; do
assert "review step '$outcome' is never a review, matching comment or not" \
1 "$(run_checker "$POSTED_COMMENT" 30965089954 "$outcome")"
Expand Down
9 changes: 5 additions & 4 deletions docs/inflight/release-0600-blockers.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ Release mechanics live in [`release-0.6.0.0.md`](release-0.6.0.0.md); the tracki
regenerate with `./mvnw -N asciidoc-template:build` (or `mvn process-sources`). Every README change
is therefore a two-file diff, and a PR that touches only the template has silently not changed the
published README.
- **`CHANGELOG.adoc` is frozen up to `== 0.6.0.0`.** It is not a per-PR chore (AGENTS.md → *Changelog*),
so a PR editing it is either fixing a factual error in a frozen section or is wrong. When several
agents work in parallel, exactly one may hold that file - it is the highest-collision file in the
repo and conflicts in it are pure noise.
- **`CHANGELOG.adoc` is not a per-PR chore, and the `== 0.6.0.0` section is not final** (AGENTS.md →
*Changelog*). It is regenerated from the commit log when the release is cut, so the text there now
is working text - do not quote it as the release notes. A PR editing the file is either fixing a
factual error in existing text or is wrong. When several agents work in parallel, exactly one may
hold that file - it is the highest-collision file in the repo and conflicts in it are pure noise.
- **Anything asserting a dependency version in prose can drift silently.** The `3.9.1`/`3.9.2` mismatch
arose because a Dependabot group bump moved `kafka.version` after the release note was written, and
nothing cross-checks prose against `pom.xml`. Re-read the `=== Dependencies` section against the pom
Expand Down
Loading