Repository navigation
Description
Problem
Almost every pull request adds to the same few places: a line in the version's section of CHANGELOG.md, the same line again in one or more of the four package changelogs, and claims in test/oracles/claims.json. When several pull requests are open at once, each merge can leave the rest conflicting. A conflicting pull request stops the merge train (it only runs update-branch on BEHIND and merges on CLEAN), so someone has to merge the base in by hand, resolve it, push and wait for the whole CI again. On 2026-10-25 a scripted resolution committed conflict markers into four changelogs, which #402 then had to fix.
Ports conflict more. A changelog line lands under ## [11.0.0-preview.N] on main and under ## [10.x.0] on release/10.x, so a cherry-pick of a commit that carries one almost never applies as it is.
Measured on 2026-10-29, since v10.0.0 (2026-10-19), by replaying each merge with git merge-tree --write-tree:
-
Base merged into a PR branch: 45 times. 36 were clean, needed only because both
mainandrelease/**require a branch to be up to date (strict: true, kept on purpose on 2026-10-25). 9 conflicted:File Conflicts CHANGELOG.md5 src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CHANGELOG.md5 test/oracles/claims.json4 src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CHANGELOG.md4 docs/efcore.md4 DeclaredNullabilityTests.cs1 -
Cherry-picks into
release/10.x: 57, each replayed onto its port's parent (--merge-base=<source>^ <port>^ <source>). 33 conflicted. 8 of those conflicted only in changelogs orclaims.json, and so would have applied cleanly.CHANGELOG.mdconflicted in 23, the EF Core changelog in 15, the EF NodaTime one in 9, the core one in 6 and the NodaTime one in 4. The rest are real overlaps:docs/migration.md(9),oracles.jsonandcandidates.json(4 each), and source files. -
Claims.
claims.jsonis 4,374 lines: 256 claims from 11 documents, sorted by id. An id's letter names a topic, not a document (Eis used indocs/efcore.md,docs/getting-started.mdand both NodaTime READMEs). 15 prefixes are taken twice, such asE46indocs/ranges.mdanddocs/efcore.md(both added 2026-10-18 on parallel branches). Nothing fails, because the slugs differ and only the whole id has to be unique.
Strict protection stays, so this doesn't remove the re-runs. What it removes is the hand resolution. With no textual conflict, every BEHIND pull request is brought up to date by update-branch, and the train runs to the end unattended.
Proposal
Changelog, one fragment per pull request. Each pull request adds changes/<issue>.md. There's no version in the path, so the same commit cherry-picks onto either line without a conflict. The fragment says which packages the change affects (the package/* label names) and which subsection it goes under (Breaking, Changed answers, Added, Fixed, …), then holds the line or lines. The root changelog and each named package's changelog are built from the same fragment, so the line is written once instead of copied by hand.
The fragments are joined into each changelog's ## [<version>] section by the "date the changelogs" pull request (like #519), and deleted in it. So a released version's section stays the one source, and the release workflow and the links at the tag don't change. The joiner also writes the text that is generated today by hand: the "Some calls answer differently" line above ### Changed answers, and "No change in this package." for a package with no fragment. Decide the line order inside a subsection (issue number, or a field in the fragment) and write it down in CONTRIBUTING.
Readers to change or confirm:
Directory.Build.targets(ChangelogReleaseNotes, Packages: show the version's changelog section as NuGet release notes #346). Packing an undated version, which every preview onmainand every CI run does, either reads the fragments or requires the joined section. Release notes must stay byte for byte what they are now..github/scripts/pr-hygiene.sh: asilentpull request into a minor needs its### Changed answersrow. That becomes a fragment with that subsection, linking the issue..github/workflows/release.yml,ChangelogConventionTests,ReleaseWiringConventionTests,ReleaseVersionTestsand the packaging metadata tests.test/consumer-smoke-test.sh, which checks that each nuspec's release notes open with the version's section.- CONTRIBUTING (
#changelog, the release steps), AGENTS.md (the Pack paragraph),.claude/skills/plain-docs/SKILL.md.
Claims, one file per document. Replace test/oracles/claims.json with test/oracles/claims/<document>.json, such as claims/docs-efcore.json or claims/src-CodoMetis.ValueRanges.NodaTime-README.json. Each file holds the claims whose source is that document, sorted by id, and ids stay unique across all of them. Two pull requests that add promises to different documents then touch different files. Readers: OracleCatalogue.cs, tools/oracles.cs, OracleCatalogueTests (unique and sorted), OracleSurfaceCoverageTests, OraclePostgresSurfaceTests, ApiSurface.cs, docs/oracles.md, test/oracles/README.md, test/oracles/axes.md, docs/architecture.md, docs/testing.md, CONTRIBUTING, AGENTS.md and the plain-docs skill.
Decide whether an id's prefix should mean anything. If a letter belongs to one file, a test can refuse a prefix taken twice, and the 15 existing duplicates get renamed. If not, say so in docs/oracles.md.
Out of scope: docs/migration.md, docs/efcore.md, oracles.json and candidates.json also conflict, but there two pull requests are editing the same text.
Lands on main first and is cherry-picked into release/10.x, so both lines read the same layout.
Done when
- Two pull requests branched from the same commit, each with a changelog fragment and claims for different documents, merge one after the other with only
update-branch, with no hand resolution. - A commit with a fragment cherry-picks from
mainontorelease/10.xwith no conflict. - Packing a version built from fragments gives the same release notes as today's hand-written section. Compare against the 10.4.0 nuspecs.
pr-hygiene.sh's silent rule,oracles.cs statusandoracles.cs seedsread the new layout. Each reader's test is seeded and caught.- CONTRIBUTING, AGENTS.md and
docs/oracles.mddescribe the layout, on both lines.
Same change as CaffeinatedCoder/CodoMetis.TypeKit#143, adapted: here there are five changelogs, two lines that port to each other, and strict up-to-date protection.
Activity