Separate current state from North Star across the release and versioning docs - #637
Separate current state from North Star across the release and versioning docs#637ChrisonSimtian wants to merge 10 commits into
Conversation
c9e2da7 to
6ec4cc2
Compare
release.branchName was release/{version}, which generates release/10.5 —
missing the v that every existing production branch (release/v10.4,
support/v10) and the validate-ref job's regex both expect.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tFlow ADR-0004 decided calendar versioning in 2026 and it was never implemented. No release/YYYY branch was ever cut, no YYYY.x tag ever pushed, and version.json never carried a CalVer core — while AGENTS.md, the runbook, the agent reference, and both workflow headers all described that world as current. The runbook also claimed GitLab Flow, which was never the intent. The versioning practice itself is healthy and self-correcting: the preview core is rolled forward as part of each cut, and the rc counter was moved off git height once it jumped rc.3 to rc.23. None of that was written down. Records the split the documentation now follows — Current state is kept true and falsifiable against the repo; North Star (CalVer + full GitFlow, including a long-lived develop) is explicitly unimplemented. Notes that GitFlow's develop reopens what ADR-0008 closed and will need to supersede it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Captures knowledge that lived only in commit messages: git height is automatic and preview-only, a release branch pins the full version literally (rc counter included) because height tracked promotion size rather than release intent, and support/v10 carries the one hand-set versionHeightOffset. Documents both traps that have shipped bugs — main's preview core must roll forward in the same sitting as a cut or previews strand below the release, and tag builds run detached so they match no publicReleaseRefSpec entry, which is why the release workflow sets PublicRelease: true. Adds the end-to-end cut commands and the branch naming patterns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the GitLab Flow opener with the trunk-based model we actually run, and moves GitFlow into a North Star section with a develop-based diagram. Keeps the existing pipeline, upmerge and cherry-pick diagrams as-is. Closes the three TODOs: branch naming patterns and the release CLI sequence now live in versioning.md, and the branch diagram the last TODO asked for is the GitFlow one. Flags that adopting develop reopens the drift problem ADR-0008 removed the experimental branch to solve. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AGENTS.md and the release reference described calendar versions, release/YYYY production lines and a yearly major cut, none of which exist. Restates them on semver 10.x with a clearly-marked North Star, and points at versioning.md for the mechanics. Also fixes three claims the repository contradicts: GitVersion is no longer referenced at all, main requires 0 approving reviews rather than CODEOWNER review, and the v* tag ruleset is active rather than pending under milestone 13. Records that 11.0.1-11.0.18 are burned on nuget.org. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CONTRIBUTING.md and the README described stable releases shipping from calendar-year branches. Restates them on release/v<major>.<minor> so a first-time contributor is not told to target a branch pattern that has never existed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both headers documented a 2026.1.0 version shape and release/YYYY trigger
branches. Comment-only — the validate-ref regex already matched the
release/v<major>.<minor> branches actually in use, and its \d{4}
alternatives are retained for the CalVer North Star.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6ec4cc2 to
d13256a
Compare
There was a problem hiding this comment.
❓ Do you think AI agents are using all that documentation under docs/agents? I was expecting this to be in an .agents folder or .agents.md. Or is this meant to be read by normal people as well?
⛏️ IMHO, the language in these ADRs and conventions docs is still ridiculously convoluted.
| @@ -26,7 +26,7 @@ | |||
| # - nuget.org is OPT-IN. Tag pushes do NOT auto-publish there. To publish | |||
There was a problem hiding this comment.
❓ What does this mean?
There was a problem hiding this comment.
probably the approval step in the gh environment representing nuget.org
Definitely need to look into this though, I have a feeling the CI there is slightly off too
The idea was:
build -> test -> pack -> publish to gh (because we can delete here if things go BOOM)
and then have approval gated the likes of nuget.org (because we cant just undo things here, so I would like to have a human approve aka HITL: Human-in-the-Loop)
| # (release/2026 → tag v2026.1.3) or gitflow support lines (support/v10 → v10.x, | ||
| # support/2026 → v2026.x). main is NEVER tagged for release. | ||
| # (release/v10.5 → tag v10.5.3) or legacy support lines (support/v10 → v10.x). | ||
| # main is NEVER tagged for release. |
There was a problem hiding this comment.
🤔 In GitFlow, the release/v10.5 branch is only used to stabilize the release and push rc packages. Releasing means merging to main and tagging main with v10.5.3.
| - **Consumers must explicitly opt in.** `ExperimentalAttribute` is an *error-by-default* diagnostic: code that touches the API fails to compile until the consumer suppresses the exact ID — `#pragma warning disable FALLOUT001` around the call site, or `<NoWarn>$(NoWarn);FALLOUT001</NoWarn>` in their project. Opting into instability is therefore a conscious, per-API choice — which is right for a *framework* (a product devs build on), not an app. | ||
| - **Promoting to stable = removing the attribute.** Because the feature already rode the `main` test lane, deleting the `[Experimental]` line is the whole promotion — no special cross-branch dance. This is what lets stabilised work feed into the production line without a divergent fork. Adding *or* removing `[Experimental]` is **not** a breaking change. | ||
| - **Channel discipline differs.** On the `main` (preview) test lane, churn is expected and the attribute is a courtesy. On a `release/YYYY` **production line**, any risky-but-shipped public surface **must** wear `[Experimental]` — that contract is what keeps the stable line trustworthy while still carrying new work. With the `experimental` branch retired ([ADR-0008](../adr/0008-collapse-experimental-into-main.md)), `[Experimental]` is now the primary mechanism for isolating unstable surface on `main` — including breaking changes batched toward the yearly major. | ||
| - **Channel discipline differs.** On the `main` (preview) test lane, churn is expected and the attribute is a courtesy. On a `release/v<major>.<minor>` **production line**, any risky-but-shipped public surface **must** wear `[Experimental]` — that contract is what keeps the stable line trustworthy while still carrying new work. With the `experimental` branch retired ([ADR-0008](../adr/0008-collapse-experimental-into-main.md)), `[Experimental]` is now the primary mechanism for isolating unstable surface on `main` — including breaking changes batched toward the next major. |
There was a problem hiding this comment.
🤔 Why would you have experimental changes on a release/ branch? It is meant to stabilize a release.
| - `support/v10` (+ `hotfix/v10.1`, `hotfix/v10.2`) — **legacy semver maintenance line**, `10.x`, **security and critical fixes only, no new features** (renamed from `release/v10`). Not renumbered into CalVer. Coexists indefinitely. | ||
| - `support/YYYY` — a **retired** year production line (e.g. `support/2026` once 2027 supersedes it). Security/critical fixes only. | ||
| - `release/v11` — **retired.** Nothing clean shipped under it (the `11.0.x` packages were unlisted); its rebrand/plugin work re-homed onto the `2026` line. Kept for archaeology, marked EoL — not a release target. Not renamed to `support/` (not a maintained line). | ||
| - `main` — the **integration trunk *and* the sole prerelease lane.** Default branch. **Both** deliberate improvements + bug fixes **and** faster/AI-assisted work land here. Every push publishes an NB.GV-native prerelease `MAJOR.MINOR.PATCH-preview.<height>.g<commit>` (currently `10.5.0-preview.<height>.g<commit>`) to **GitHub Packages only — never nuget.org.** Ordinary review. |
There was a problem hiding this comment.
🔧 No, main represents the last production version shipped to Nuget.
| - `release/v<major>.<minor>` (currently `release/v10.4`; next `release/v10.5`) — the **production line**. **Cut from `main` on demand at the first release of the line, not preemptively** ([ADR-0007](../adr/0007-cut-release-branch-on-demand.md)); until then `main` (`-preview`) is the most-stable line. Hardened deliberately (slow crowd's domain, rigorous review), `-rc.N` → GA. After the cut it takes **non-breaking minors + patches only** — never a breaking change. Tag-triggered releases fire from here (the nuget.org tier). Protected per the policy below. | ||
| - `support/v10` (+ `hotfix/v10.x`) — **legacy maintenance line**, pinned `"10.3"` with `versionHeightOffset: 24`, **security and critical fixes only, no new features** (renamed from `release/v10`). Coexists indefinitely and does **not** retire when a newer line is cut. |
There was a problem hiding this comment.
🔧 We only need a support branch when main receives breaking changes (and thus becomes 11.x)
| - `main` — the **integration trunk *and* the sole prerelease lane.** Default branch. **Both** deliberate improvements + bug fixes **and** faster/AI-assisted work land here. Every push publishes an NB.GV-native prerelease `MAJOR.MINOR.PATCH-preview.<height>.g<commit>` (currently `10.5.0-preview.<height>.g<commit>`) to **GitHub Packages only — never nuget.org.** Ordinary review. | ||
| - `release/v<major>.<minor>` (currently `release/v10.4`; next `release/v10.5`) — the **production line**. **Cut from `main` on demand at the first release of the line, not preemptively** ([ADR-0007](../adr/0007-cut-release-branch-on-demand.md)); until then `main` (`-preview`) is the most-stable line. Hardened deliberately (slow crowd's domain, rigorous review), `-rc.N` → GA. After the cut it takes **non-breaking minors + patches only** — never a breaking change. Tag-triggered releases fire from here (the nuget.org tier). Protected per the policy below. | ||
| - `support/v10` (+ `hotfix/v10.x`) — **legacy maintenance line**, pinned `"10.3"` with `versionHeightOffset: 24`, **security and critical fixes only, no new features** (renamed from `release/v10`). Coexists indefinitely and does **not** retire when a newer line is cut. | ||
| - `release/v11` — **retired.** Nothing clean shipped under it (the `11.0.x` packages were unlisted); its rebrand/plugin work re-homed onto the `10.x` line. Not a release target. **`11.0.1`–`11.0.18` are burned** — nuget.org never frees a version that has existed, so that range can never be reused. |
There was a problem hiding this comment.
❓ Then why do we need it?
| - `release/v11` — **retired.** Nothing clean shipped under it (the `11.0.x` packages were unlisted); its rebrand/plugin work re-homed onto the `10.x` line. Not a release target. **`11.0.1`–`11.0.18` are burned** — nuget.org never frees a version that has existed, so that range can never be reused. | ||
|
|
||
| Short-lived branches (rebase-merged via PR): `feature/<slug>`, `bugfix/<slug>`, `chore/<slug>`, `docs/<slug>`, `pr/<num>-<slug>`. They target `main`. Breaking work that cannot be gated behind `[Experimental("FALLOUT0xx")]` waits for the year cut on a short-lived topic branch off `main`. | ||
| Short-lived branches (rebase-merged via PR): `feature/<slug>`, `bugfix/<slug>`, `chore/<slug>`, `docs/<slug>`, `pr/<num>-<slug>`. They target `main`. Breaking work that cannot be gated behind `[Experimental("FALLOUT0xx")]` waits for the next major cut on a short-lived topic branch off `main`. |
There was a problem hiding this comment.
🔧 This should all go to the forks
There was a problem hiding this comment.
agreed, and this needs to be explicitely stated out here because otherwise AI keeps tripping over it and starts creating branches here again
| Short-lived branches (rebase-merged via PR): `feature/<slug>`, `bugfix/<slug>`, `chore/<slug>`, `docs/<slug>`, `pr/<num>-<slug>`. They target `main`. Breaking work that cannot be gated behind `[Experimental("FALLOUT0xx")]` waits for the next major cut on a short-lived topic branch off `main`. | ||
|
|
||
| No `develop` (literal) or `master` branches. The ladder flows **forward-only**: `main → release/YYYY`. The `support/*` lines are maintenance-only — security/critical fixes land via a PR targeting (or cherry-pick to) `support/v10` / `support/YYYY` (or the relevant `hotfix/v10.x`) and are tagged from there. | ||
| No `develop` (literal) or `master` branches **today** — note that the GitFlow North Star would introduce `develop`, but it is not implemented. The ladder flows **forward-only**: `main → release/v<major>.<minor>`. The `support/*` lines are maintenance-only — security/critical fixes land via a PR targeting (or cherry-pick to) `support/v10` (or the relevant `hotfix/v10.x`) and are tagged from there. |
There was a problem hiding this comment.
We do need develop as that is where all the new stuff lands.
| @@ -47,22 +49,24 @@ Tag protection for `v*` tags is a separate ruleset ([17017817](https://github.co | |||
|
|
|||
| ## Versioning | |||
|
|
|||
| **Calendar versioning: `YYYY.MINOR.PATCH`** (see [ADR-0004](../adr/0004-calendar-versioning-and-dual-pace-channels.md), as amended by [ADR-0008](../adr/0008-collapse-experimental-into-main.md)). It is mechanically valid SemVer 2.0 — all three components are numeric — so [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning), NuGet, and version ordering all work unchanged. The major *is* the calendar year. | |||
| **Semantic versioning on the `10.x` line.** Full mechanics — git height, `-rc.N` pinning, and the two traps that have shipped bugs — are in **[docs/versioning.md](../versioning.md)**. Read that before touching `version.json` or cutting a release. The essentials: | |||
|
|
|||
| - **`MAJOR` = year**, hand-set in `version.json` at the yearly cut. **`MINOR`** = feature drop within the year. **`PATCH`** = git-height fixes. | |||
| - Per-branch via `version.json`. The preview lane is a **non-public ref** carrying the next planned version with a prerelease tag: `main` → `"10.5.0-preview.{height}"` (`firstUnstableTag` is `preview`). Each `release/YYYY` carries `"version": "YYYY.x"`; the current `release/v10.4` pins its prerelease literally (`"version": "10.4.0-rc.N"` — a manual counter, see the runbook); `support/v10` keeps `"version": "10.x"`; `support/YYYY` keeps `"version": "YYYY.x"`. `publicReleaseRefSpec` matches the four production patterns: `^refs/heads/release/\d{4}$`, `^refs/heads/release/v\d+\.\d+$`, `^refs/heads/support/\d{4}$`, `^refs/heads/support/v\d+$` (**not** `main`). | |||
| - Preview-lane builds carry the height + commit in the **prerelease segment** (`10.5.0-preview.<height>.g<commit>`), never the version core — a core like `2026.05.29` would parse as a *stable* release, not a nightly. `main` is a non-public ref, so NB.GV appends the `.g<commit>` suffix. The ladder orders cleanly: `-preview` < `-rc` < GA. | |||
| - Per-branch via `version.json`. The preview lane is a **non-public ref** carrying the next planned version with a prerelease tag: `main` → `"10.5.0-preview.{height}"` (`firstUnstableTag` is `preview`). A release branch pins the **full** version literally, prerelease segment included — `"10.4.0-rc.4"`, then `"10.4.0"` at GA. `support/v10` carries `"10.3"` + `versionHeightOffset: 24`. | |||
There was a problem hiding this comment.
support/v10carries"10.3"+versionHeightOffset: 24.
No, it should be just support/v10
There was a problem hiding this comment.
yep.... claude keeps tripping over us doing v10 and matthias having done v10 as well, so it tries to narrow it down to minor (because it does the same thing elsewhere, but it doesnt understand that this one is different... manual hands-on)
| ### Why nuget.org stays opt-in | ||
|
|
||
| **GitHub Packages is the default channel for the preview lane and for stable tag pushes.** nuget.org is reserved for the deliberate publish of a stabilised `release/YYYY` (or a `support/v10` legacy security patch). To publish Fallout.* to nuget.org you must run `workflow_dispatch` with `publish-to-nugetorg=true` — a conscious "this release is ready for nuget.org" switch. Tag pushes alone publish to GitHub Packages + GitHub Releases only. | ||
| **GitHub Packages is the default channel for the preview lane and for stable tag pushes.** nuget.org is reserved for the deliberate publish of a stabilised production line (or a `support/v10` legacy security patch). To publish Fallout.* to nuget.org you must run `workflow_dispatch` with `publish-to-nugetorg=true` — a conscious "this release is ready for nuget.org" switch. Tag pushes alone publish to GitHub Packages + GitHub Releases only. |
There was a problem hiding this comment.
❓ What does it mean to run workflow_dispatch?
There was a problem hiding this comment.
ah thats probably the gh workflow, iirc then thats the cli way of invoking it. Language there is too complex, this definitely needs a human hand before merging
No and I feel like Claude keeps tripping over it and just floods everything with overly verbose explainations. Just trying to shape out the whole gitflow thing and get everything ready before changing the repo settings :-) |
Splits every process doc into Current state (kept true, falsifiable against the repo) and North Star (explicitly unimplemented), because the two were written in the same assertive voice and the false half went unnoticed for months.
What changed
10.x; CalVer and full GitFlow (long-liveddevelop) are the North Star. ADR-0004 §1 is deferred, not abandoned.docs/versioning.md— nbgv mechanics that previously lived only in commit messages:{height}is automatic and preview-only, a release branch pins the full version literally, and the two traps that have shipped bugs (preview core must roll forward at the cut; tag builds are detached, hencePublicRelease: true).branching-and-release.mdreworked for readability with three mermaid diagrams, split into the two halves. The GitLab Flow opener is gone — it was never the intent.release-and-versioning.md/ CONTRIBUTING / README restated onrelease/v<major>.<minor>. Norelease/YYYY,support/YYYY, "yearly major" or "calendar versions" remains as a current-state claim.version.json:release.branchNamewasrelease/{version}, which generatesrelease/10.5— missing thevthat every production branch andvalidate-refexpect.validate-refregex already matched the live branches).Why
ADR-0004 decided calendar versioning in 2026 and it was never implemented — no
release/YYYYbranch was ever cut, noYYYY.xtag ever pushed. Meanwhile the docs described that world as fact.Three stale claims are also corrected against the repo: GitVersion is no longer referenced at all, and the
v*tag ruleset is active rather than pending.Worth a reviewer's attention: the GitFlow North Star reopens what ADR-0008 closed. A long-lived
developtakes on the same forward-port obligation that sawexperimentaldrift ~17 commits behindmain. That's called out in both the ADR and the runbook rather than glossed — adopting it means superseding ADR-0008 with an answer for why the back-merge sticks this time.Verification
upstream/main(was 19 behind); conflicts in README,branching-and-release.md, AGENTS.md,release-and-versioning.mdand CONTRIBUTING resolved by hand, preferring upstream's newer facts (ruleset IDs,dismiss_stale_reviews: false, squash-still-enabled, retiredCHANGELOG.md) over my earlier edits where they conflicted.validate-refregex unchanged.Follow-ups
{height}core andpublicReleaseRefSpecexclusion both move frommaintodevelop.11.0.1–11.0.18are burned on nuget.org. Moot under the CalVer North Star (next major is a year), but it binds if a breaking change lands on the10.xline first.