Skip to content

Choose the version floor at standup instead of inheriting it - #488

Merged
ptr727 merged 6 commits into
developfrom
feature/version-floor-bootstrap
Aug 1, 2026
Merged

Choose the version floor at standup instead of inheriting it#488
ptr727 merged 6 commits into
developfrom
feature/version-floor-bootstrap

Conversation

@ptr727

@ptr727 ptr727 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

STANDUP.md step 2 lists version.json among the files a new repo carries and says nothing about the number inside it, so the file arrives carrying a floor that describes a release history the new repo does not have. WORKFLOW.md D3.3 makes that field the repo's own major.minor floor with NBGV appending the git height as the patch, so the carried value is a claim, not a default.

The failure is observed, not hypothetical

Four operational config repos run on a floor none of them chose, and each has already released against it:

Repo Floor Latest release
HomeAutomation-Config 2.0 2.0.14
ESPHome-Config 2.0 2.0.60
HomeAssistant-Config 2.0 2.0.23
Vantage-Config 2.0 2.0.13

The repos versioned deliberately show the rule already exists in practice and only lacked a statement. A project with history keeps its scheme (Utilities 4.0, PlexCleaner 3.22, NxWitness 2.15, LanguageTags 1.5, ESPHome-NonRoot 1.9, VSCode-Server-DotNetCore 1.1), and a new project starts at 1.0 (aiopurpleair, MediaTools, PhotoCleaner, homeassistant-purpleair) or at 0.1 while pre-release (Financial-Modeling). Whether a repo got this right depended on who stood it up.

What lands

Step 2 gains the three cases and requires the floor to be set before the first release:

  1. A new project starts at 1.0, or 0.1 while deliberately pre-release.
  2. A project with releases behind it keeps its established scheme, adapted to NBGV, with the floor at or above the highest published version, because a floor under an existing tag emits versions that sort backwards.
  3. A repo that ships no package still chooses. This is the case that produced all four above: an operational or source-only repo still releases a tag and a source archive, so having no consumer is not a reason to leave the carried number alone.

It also records that the decision is effectively one-way. Once a repo publishes against a floor, lowering it regresses the released version order, so the four keep the floor they have and this is prevention rather than a repair procedure.

Scope

Hub-only, and deliberately not in WORKFLOW.md. D3.3 already defines what the field means and is carried fleet-wide at intent fidelity, so restating the bootstrap rule there would add re-vendor debt for guidance that only ever applies while a repo is being stood up.

Two conformance findings surfaced by the same survey are not addressed here, since they are downstream repo changes rather than hub guidance: AudioCleaner and DevKitCIoT carry no version.json at all, which spec/files.json requires for every repo (appliesTo: "*").

Verification

  • Fleet survey run live against each repo's version.json and latest release via the GitHub API, so every number above is measured rather than recalled.
  • python3 scripts/prose_lint.py . --diff origin/develop clean, STANDUP.md clean whole.
  • python3 scripts/repo_gate.py clean, markdownlint-cli2 and editorconfig-checker clean.
  • CRLF-only by byte scan, diff is 8 inserted lines with nothing else touched.

🤖 Generated with Claude Code

Step 2 lists version.json among the files a new repo carries and says nothing
about the number inside it, so the file arrives with a floor that describes
someone else's release history. WORKFLOW.md D3.3 makes that field the repo's
own major.minor floor with NBGV appending the git height as the patch, which
means a carried floor is a claim the new repo cannot support.

Four operational config repos run on a floor none of them chose, and each has
released against it: HomeAutomation-Config at 2.0.14, ESPHome-Config at
2.0.60, HomeAssistant-Config at 2.0.23, and Vantage-Config at 2.0.13. The
repos that were versioned deliberately show the rule already exists in
practice and only lacked a statement. A project with history keeps its scheme,
as Utilities at 4.0, PlexCleaner at 3.22, NxWitness at 2.15, LanguageTags at
1.5, ESPHome-NonRoot at 1.9 and VSCode-Server-DotNetCore at 1.1 all do, and a
new project starts at 1.0, as aiopurpleair, MediaTools, PhotoCleaner and
homeassistant-purpleair do, or at 0.1 while it is pre-release, as
Financial-Modeling does.

Step 2 now states the three cases and requires the floor to be set before the
first release. It also states the case that produced the four, which is a repo
shipping no package: an operational or source-only repo still releases a tag
and a source archive, so having no consumer is not a reason to leave the
carried number alone.

The step is placed with the decision rather than with the repair because the
decision is one-way. Once a repo publishes against a floor, lowering it
regresses the released version order, so the four keep the floor they have.

The rule stays hub-only. WORKFLOW.md D3.3 already defines what the field means
and is carried fleet-wide, and how a floor is chosen the first time is
standup work rather than a fact any downstream repo re-reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 03:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the standup procedure to require choosing an explicit version.json major.minor floor during repository bootstrap, rather than inheriting the carried template value, to prevent accidental version histories and backward-sorting releases in newly created repos.

Changes:

  • Adds standup guidance clarifying that version.json is both carried and must be deliberately set before the first release.
  • Documents three scenarios for selecting the floor (new project, existing release history, no-package/operational repos).
  • Notes that floors become effectively one-way once releases exist, so prevention belongs in standup guidance.

Comment thread STANDUP.md Outdated
The continuing-scheme bullet said to put the floor at or above the highest
published version. The field carries major.minor only, so "above" a full
semver is not expressible, and the wording hid the mechanism that makes the
case fail.

NBGV counts the patch from the git height rather than from the last published
patch, so a floor matching the published major.minor emits a patch counted
from that floor's first commit. Wherever the published patch ran ahead of the
height, the computed version lands under an existing tag.

The bullet now says to set the floor above the highest published major.minor
rather than matching it, and names nbgv get-version as the check that the
computed version sorts above the latest tag before the first release.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 03:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

STANDUP.md:63

  • The sentence "so it cannot resume a published patch sequence" is overly absolute. The repo’s own audit reports note cases where versionHeightOffset is used (e.g., reports/homeassistant-purpleair/audit.md:41), so while NBGV doesn’t automatically continue an old patch sequence, it’s not strictly impossible to align/avoid regressions via configuration + verification. Suggest softening the claim to avoid a factual overstatement.
- **A project with releases behind it keeps its established scheme**, adapted to NBGV rather than restarted. The field carries a major.minor floor and NBGV counts the patch from the git height, so it cannot resume a published patch sequence. Set the floor to a major.minor **above** the highest one already published rather than matching it, because a matched floor emits a patch counted from that floor's first commit, which lands under an existing tag whenever the published patch ran ahead of the height. `nbgv get-version` prints the computed version, and it has to sort above the latest tag before the first release.

Copilot AI review requested due to automatic review settings August 1, 2026 03:29
ptr727 and others added 2 commits July 31, 2026 20:30
The bullet said NBGV cannot resume a published patch sequence. It does not
resume one on its own, but versionHeightOffset shifts the computed height, and
homeassistant-purpleair runs with an offset of -1 today, so the claim was an
overstatement that the fleet's own audit reports contradict.

The mechanism is unchanged and now stated as what it is. NBGV counts the patch
from the git height rather than from where the published sequence stopped, so
a matched floor lands under an existing tag whenever the published patch ran
ahead of the height.

Raising the minor stays the recommendation, because it clears the collision
and leaves nothing to maintain, and the offset is named as the alternative
with its cost rather than left out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
version.json carries nugetPackageVersion, which configures how a NuGet
publisher stamps a package version. A repo that publishes no package carries
the block anyway, because the file reads as mechanical and invites a straight
copy the way .editorconfig does, while its content is a per-repo decision.

Step 2 now says to drop it, and states that publicReleaseRefSpec names the
repo's own default branch, which D3.2 already requires the gate literal, the
prerelease expression and this file to agree on.

Raised from the Blog carry (#489, finding 5), whose first half this step
already covers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ptr727

ptr727 commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

Answering the suppressed finding from round 2, since it reaches no thread to resolve.

Accepted, and the claim was wrong. versionHeightOffset exists and the fleet already runs one: reports/homeassistant-purpleair/audit.md:41 records versionHeightOffset: -1 under D3.3. Saying NBGV "cannot resume a published patch sequence" was contradicted by this repo's own audit output, which is the worse kind of overstatement because the counter-evidence was already committed here.

Fixed in ebed0cf. The mechanism is unchanged and now stated as what it is: NBGV counts the patch from the git height rather than from where the published sequence stopped, so a matched floor lands under an existing tag whenever the published patch ran ahead of the height. Raising the minor stays the recommendation because it clears the collision and leaves nothing to maintain, and the offset is named as the alternative with its cost rather than omitted.

Also in this round, c01dee4 covers the second half of a finding raised independently from the Blog carry (#489, finding 5). That issue reached the same conclusion as this PR about the inherited floor, and adds the packaging half: nugetPackageVersion is configuration for a NuGet publisher, so a repo that publishes no package drops the block rather than carrying a setting nothing reads. Head is now c01dee407df4bc2787648effb274e8947f465163.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 1, 2026 03:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 1, 2026 04:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@ptr727
ptr727 merged commit 89e3868 into develop Aug 1, 2026
7 checks passed
@ptr727
ptr727 deleted the feature/version-floor-bootstrap branch August 1, 2026 04:56
ptr727 added a commit that referenced this pull request Aug 1, 2026
…to main (#498)

Promotes eight commits from `develop`. Every one traces to a defect
found in use rather than to a planned change, and five came from
downstream agents reporting what the procedure did not cover.

## What lands

| Commit | Change |
| --- | --- |
| `a0f6f24` (#487) | `docs/content-import.md`, the three capture-pass
findings from the Blog migration: an export is not a media capture, a
sitemap is not the URL contract, and an HTTP fetch is not the original |
| `8bdfa22` (#494) | The write-guard scopes by **owner** rather than
exact origin, with `GH_WRITE_GUARD_ALLOW` for a different owner. Four
target-flag spellings that silently bypassed rule 3 are closed |
| `981d92f` (#492) | The purpose is restated as agent enablement, in
`README.md`, `HISTORY.md` and `AGENTS.md` |
| `275705b` (#493) | `TODO.md` becomes the fleet backlog destination,
and `spec/readme-structure.md` stops mandating the construction
`GOVERNANCE.md` bans |
| `b6ab6db` (#491) | `STANDUP.md` step 0A names the maintainer-only
prerequisites, and step 4 asserts the remote |
| `89e3868` (#488) | The `version.json` floor is chosen at standup
rather than inherited |
| `eed2e00` (#495) | `README.md` gains "What It Achieves", the
objectives and the fidelity ladder |
| `f6dc5e6` (#497) | `CODESTYLE.md` stops claiming CI runs the same
checks as the clean-compile |

## Provenance

Five of the eight answer issues filed by downstream agents: #456 (Blog
intake), #489 and #490 (the Blog carry), and #496 (Financial-Modeling).
That loop is the one "What It Achieves" now describes, and this
promotion is it closing.

## Divergence, checked rather than assumed

`main...develop` reports `8 ahead, 102 behind, diverged`. **The 102 are
topology, not content.** They are 79 promotion merge commits, which are
main-only by construction because a promotion is a two-parent merge,
plus 23 `Update codegen files` bot commits from this repo's pre-2.0 life
as a .NET sample template. `git diff --name-status origin/develop
origin/main` returns exactly the 12 files these 8 commits touch, so
there is **no main-only content** to reconcile.

## Verification on the merged `develop`

Every gate re-run after the last merge, not inherited from the
individual PRs:

- `prose_lint.py . --check charset --check dupword --check spelling`
clean tree-wide.
- `repo_gate.py` clean (`eol`, `sha-pin`).
- `spec/validate.py` clean, 21 cataloged repos classify.
- `gh-write-guard.py --selftest` passes, including the nine new
repository-scope cases.
- `python3 -m unittest discover -s scripts`, 180 tests pass.
- The `README.md` objectives list verified as one continuous list of 8
bullets with the fidelity table nested, since an unindented table split
it in review.

## Merge mechanics

This is a promotion, so it merges as a **merge commit** with two
parents, never a squash. Its head **is** `develop`, so `--delete-branch`
must not be used.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants