Skip to content

Separate current state from North Star across the release and versioning docs - #637

Open
ChrisonSimtian wants to merge 10 commits into
Fallout-build:mainfrom
ChrisonSimtian:docs/rework-contribution-md
Open

Separate current state from North Star across the release and versioning docs#637
ChrisonSimtian wants to merge 10 commits into
Fallout-build:mainfrom
ChrisonSimtian:docs/rework-contribution-md

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

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

  • ADR-0012 records the split as policy: current state is semver 10.x; CalVer and full GitFlow (long-lived develop) are the North Star. ADR-0004 §1 is deferred, not abandoned.
  • New 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, hence PublicRelease: true).
  • branching-and-release.md reworked for readability with three mermaid diagrams, split into the two halves. The GitLab Flow opener is gone — it was never the intent.
  • AGENTS.md / release-and-versioning.md / CONTRIBUTING / README restated on release/v<major>.<minor>. No release/YYYY, support/YYYY, "yearly major" or "calendar versions" remains as a current-state claim.
  • version.json: release.branchName was release/{version}, which generates release/10.5 — missing the v that every production branch and validate-ref expect.
  • Workflow header comments corrected (comment-only; the validate-ref regex already matched the live branches).

Why

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. 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 develop takes on the same forward-port obligation that saw experimental drift ~17 commits behind main. 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

  • Rebased onto upstream/main (was 19 behind); conflicts in README, branching-and-release.md, AGENTS.md, release-and-versioning.md and CONTRIBUTING resolved by hand, preferring upstream's newer facts (ruleset IDs, dismiss_stale_reviews: false, squash-still-enabled, retired CHANGELOG.md) over my earlier edits where they conflicted.
  • Both publish workflows re-parsed as valid YAML; validate-ref regex unchanged.
  • All relative markdown links in the touched files resolve.

Follow-ups

  • CalVer + GitFlow have to land together — under GitFlow the {height} core and publicReleaseRefSpec exclusion both move from main to develop.
  • 11.0.111.0.18 are burned on nuget.org. Moot under the CalVer North Star (next major is a year), but it binds if a breaking change lands on the 10.x line first.

@ChrisonSimtian ChrisonSimtian added documentation Improvements or additions to documentation skip-changelog Dont add to the Github Release Notes labels Aug 16, 2026
@ChrisonSimtian
ChrisonSimtian marked this pull request as ready for review August 16, 2026 01:34
@ChrisonSimtian
ChrisonSimtian force-pushed the docs/rework-contribution-md branch from c9e2da7 to 6ec4cc2 Compare August 16, 2026 01:52
ChrisonSimtian and others added 10 commits August 16, 2026 13:53
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>
@ChrisonSimtian
ChrisonSimtian force-pushed the docs/rework-contribution-md branch from 6ec4cc2 to d13256a Compare August 16, 2026 01:54

@dennisdoomen dennisdoomen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ 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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ What does this mean?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 No, main represents the last production version shipped to Nuget.

Comment on lines +15 to +16
- `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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ 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`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 This should all go to the forks

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, and this needs to be explicitely stated out here because otherwise AI keeps tripping over it and starts creating branches here again

Comment on lines +19 to +21
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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do need develop as that is where all the new stuff lands.

Comment on lines 19 to +54
@@ -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`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

support/v10 carries "10.3" + versionHeightOffset: 24.

No, it should be just support/v10

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ What does it mean to run workflow_dispatch?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator Author

❓ Do you think AI agents are using all that documentation under docs/agents?

No and I feel like Claude keeps tripping over it and just floods everything with overly verbose explainations.
I think we should handle the AI side like you said via agent.md (needs to be a bit more hand-curated though) and through the other MD files.

Just trying to shape out the whole gitflow thing and get everything ready before changing the repo settings :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation skip-changelog Dont add to the Github Release Notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants