Repository navigation
Description
Why now
Surfaced from #217: @dennisdoomen hit a real bug on 10.3.45 while migrating FluentAssertions. We fixed it in #226, which lands on 11.0.x. Dennis can hand-apply the patch to a 10.3.x checkout, but: should we have a documented release-management policy so this scales beyond "one prominent dev can hand-patch"?
Context: we just shipped v11 and have v12 (Public Plugin SDK) + v13 (Continuous Delivery) milestones queued. More consumers means more "I'm on 11.0 and can't move to 12.0 yet — can you backport this fix?" reports. We need a coherent answer.
Status quo (implicit)
All fixes land on main, released under the current major (e.g. 11.0.x). No backports. Consumers on older majors either:
- Upgrade to the current major (sometimes blocked by their own constraints).
- Pin to their 10.3.x and live with the bug.
- Maintain a private fork with hand-applied patches.
Fine for a small project; scales badly for "build framework with many enterprise consumers" — the v13 trajectory.
Options
A. Status quo — main only, roll forward
- Pros: zero process overhead. One branch. Every fix benefits from latest code.
- Cons: users on older majors can't get just-the-fix. Weak trust signal for enterprises planning multi-year LTS.
B. Release branches with version-locked patch releases
- Cut
release/v{major}at every major bump (e.g.release/v11at the11.0cut). - Backport-worthy fixes cherry-picked from
mainonto each active release branch. - Each branch ships its own patch line (
11.0.xfromrelease/v11,12.0.xfromrelease/v12). - Explicit support window — e.g. "security fixes to the previous major for N months after a new major ships; bug fixes to the current major only".
- Pros: clear contract. Enterprises can pin to a major and trust they'll get fixes. Matches how dotnet ships LTS branches.
- Cons: every fix needs triage ("backport to v10? v11?"). Cherry-pick conflicts accumulate. Needs automation (
backportlabel, GH bot).
C. Long-lived support branches with version in the branch name
- e.g.
release/v11.0.x,release/v11.1.x,release/v12.0.x. Branch name encodes the version line. - More granular than B — each minor gets its own branch.
- Pros: very explicit; easy to know what's where.
- Cons: branch proliferation. Best when minors are common, not pure-patch lines.
D. Hand-patch on request — current behaviour, documented
- Same as A, but published: "we support only
latestof the current major. Backports are not provided; consumers can hand-apply patches frommain." - README / CONTRIBUTING.md gets a short "Support policy" section.
- Pros: cheapest. Sets expectations honestly. Removes ambiguity.
- Cons: weaker enterprise story. Doesn't scale.
Open questions
- Minimum support window? "Current major only" / "Current + N-1" / "Current + N-1 + N-2 (LTS)".
- Who decides backport-worthiness? Maintainer call vs. label-driven (
backport:v10) vs. triage rules. - Tooling: a
backportlabel, GH workflow auto-cherry-picking labelled PRs, conflict-handling story. - CI cost: each active release branch costs CI minutes for its own ubuntu/macos/windows runs.
- CHANGELOG model: per-branch sections, or single CHANGELOG with version markers?
- Versioning: Nerdbank.GitVersioning's
publicReleaseRefSpecmust include the release branches. Branch-name pattern matters.
Recommendation (mine, for the record)
For v11→v12: start with (D) — document support as "main / current major only". Watch backport-request frequency. If 3+ enterprise-shaped consumers ask within a quarter, escalate to (B) with "security fixes to v(N-1) for 6 months after vN ships". Don't pre-build machinery before there's demand.
Refs
- Triggering issue: Fallout-migrate triggers some dependency confusion #217 (Dennis on 10.3.45 hit a bug fixed in 11.0.x).
- Triggering fix: fix(migrate): bump Nuke→Fallout PackageReference versions + strip stale Cryptography.Xml pin (#217) #226 (lands on
main→ 11.0.x only). - Semver context: chore(release)!: bump version.json 10.3 → 11.0 + add semver policy to CLAUDE.md #220,
CLAUDE.mdSemver policy.
Activity