Skip to content

chore: sync v2/main to 2.2.0 + guidance to bump on v2/main before the milestone merge - #2011

Merged
cliffhall merged 4 commits into
v2/mainfrom
v2/chore/2010-version-sync
Aug 15, 2026
Merged

chore: sync v2/main to 2.2.0 + guidance to bump on v2/main before the milestone merge#2011
cliffhall merged 4 commits into
v2/mainfrom
v2/chore/2010-version-sync

Conversation

@cliffhall

@cliffhall cliffhall commented Aug 15, 2026

Copy link
Copy Markdown
Member

Closes #2010

v2/main has been at 2.0.0 since the v2.0.0 release while main and npm latest are at 2.2.0. This closes the existing gap and changes the procedure so it cannot reopen.

Root cause

The bump is created on the milestone-merge branch, which is cut from main — so it exists only downstream of v2/main, and nothing carries it back. Not an off-by-one from one missed step; it has happened every release:

Commit On main On v2/main
dedee5af chore: 2.1.0 yes no
27cd42b4 chore: 2.2.0 yes no

The fix — bump on v2/main, before the milestone merge

BEFORE                                  AFTER
v2/main ──────────────►  (2.0.0)        v2/main ──► chore: 2.3.0 ──►  2.3.0 ✓
          \                                       \
milestone  ├─ merge v2/main             milestone  ├─ merge v2/main (carries bump)
(from main)└─ chore: 2.2.0  ◄─ born                     \
                 \                      main ───────────►  2.3.0   tag 2.3.0
main ────────────►  2.2.0

The bump becomes part of the milestone's work and flows with it, so there is no back-merge and no sync step. The release tag is applied to the resulting main commit.

To be precise about the invariant (corrected during review): the branches do differ between step 1 and step 2 — v2/main reads the version being built, main the one currently released — and that is expected, not drift. What this removes is post-release drift: they converge when the milestone merge lands, and v2/main is never left behind main. Ahead means a release is in flight; behind means something went wrong.

The publish workflow needs no change. Its "Assert release tag matches package version" step runs at the release commit on main, which still carries the bump — I checked this before choosing the approach.

One sharp edge is called out prominently in the docs: npm version must be run with --no-git-tag-version. A bare npm version also tags, and that tag would land on a v2/main commit while the release must be cut from main — creating a tag on a commit that is never released.

Why not a back-merge

mainv2/main is the conventional git-flow answer and is wrong here: main carries the entire pre-v2 v1 history (~230 commits v2/main lacks, retained through ec5d8e13 chore: replace main's tree with v2). Merging grafts all of it into the develop branch's log permanently in order to deliver a two-file change. A post-release sync commit avoids the graft but is still a forgettable extra step with a drift window; bumping first has neither. The README now says explicitly not to do this, so a future maintainer hitting a drift doesn't reach for the obvious tool.

Why it mattered

  • A branch cut from a milestone-merge branch silently carries the bump into an unrelated PR. Not hypothetical — fix: bind loopback by address and pin the sandbox port for containers #2009 arrived with package.json 2.0.0 → 2.2.0 in the diff of a container bugfix. Caught in review and rebased out, but it would have bumped the develop branch's version as a side effect of a bug fix.
  • Development builds report a two-release-old version via readInspectorVersion(), --version, and GET /api/config — so do bug reports filed from them.
  • It compounds: each release widens the gap.

Changes

  • package.json / package-lock.json2.2.0 (one-time catch-up; matches main and npm latest).
  • README.mdCutting a release rewritten as the three explicit steps, with the --no-git-tag-version warning, the rationale, and the do-not-back-merge note.
  • AGENTS.md — the branch-flow section now states the bump rides the same flow, plus a corollary that feature branches are cut from v2/main and never from a milestone-merge branch (the mistake that produced fix: bind loopback by address and pin the sandbox port for containers #2009's stray diff).

Verification

npm run ci passes (exit 0). Nothing in the repo asserts a specific version value — no test reads it — so the catch-up is a safe two-file change. I confirmed that before choosing this option rather than assuming it.

Not mirrored into .github/copilot-instructions.md: AGENTS.md lists release and publishing procedure among the things deliberately absent from that file.


Update (round 2 review): corrected tag v2.3.0tag 2.3.0 in the diagram above. This repo's release tags are bare x.y.z (2.2.0, 2.1.0, 2.0.0) — the same correction @cliffhall raised on the README, applied here and on #2010 as well so the description does not contradict the procedure it describes.

… merge

v2/main has been at 2.0.0 since the v2.0.0 release while main and npm `latest`
are at 2.2.0. The bump was created on the milestone-merge branch, which is cut
from main, so it only ever existed downstream of v2/main and nothing carried it
back — `chore: 2.1.0` and `chore: 2.2.0` are both on main and neither is on
v2/main.

That is not cosmetic. A branch cut from a milestone-merge branch silently
carries the bump into an unrelated PR — #2009 arrived with a 2.0.0 -> 2.2.0 diff
on a container bugfix — and anything reading the version in development
(readInspectorVersion, --version, GET /api/config) reported a version two
releases old.

Move the bump to v2/main, before the milestone merge, so it flows into main with
the rest of the milestone's work and the branches never disagree. The release
tag is applied to the resulting main commit instead. The publish workflow needs
no change: its tag-vs-package.json assertion runs at the release commit on main,
which still carries the bump.

Deliberately not a back-merge of main into v2/main: main holds the whole pre-v2
v1 history (~230 commits v2/main lacks, retained through `chore: replace main's
tree with v2`), so merging would graft all of it into the develop branch's log
permanently to deliver a two-file change.

Also sets v2/main to 2.2.0 as a one-time catch-up. Nothing in the repo asserts a
specific version value, so this is a safe two-file change.

Closes #2010

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Aug 15, 2026
Comment thread README.md Outdated
This repo's release tags are bare x.y.z (2.2.0, 2.1.0, 2.0.0), not v-prefixed.
Also notes why the manual tag matters: npm's tag-version-prefix defaults to 'v'
and the repo sets no .npmrc, so a bare `npm version` would have produced a tag
that doesn't match the convention.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Review response

Fixed in 9048e69 — dropped the v from the release tag step.

Verified against the actual tags rather than just taking the note: gh release list shows bare x.y.z for every release (2.2.0, 2.1.0, 2.0.0, plus the 2.0.0-rc.* pre-releases). My step 3 said git tag v<x.y.z>, which would have been the only v-prefixed tag in the repo.

While confirming, I found the reason this is worth a warning rather than a silent fix: npm's tag-version-prefix defaults to v, and the repo ships no .npmrc. So under the old procedure a bare npm version produced a v-prefixed tag locally, diverging from the convention the releases actually use. Now that step 3 tags by hand, that divergence goes away — but only if the docs say so, hence the ⚠️ note added alongside the fix.

It was never release-breaking, which is likely why it survived: the publish job asserts "${TAG#v}" != "$PKG", stripping a leading v before comparing. So a v-prefixed tag publishes fine — it is purely a consistency problem.

npm run ci passes (exit 0).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Synchronizes v2/main with release 2.2.0 and revises the release process to prevent post-release version drift.

Changes:

  • Updates root package metadata to version 2.2.0.
  • Moves future version bumps before milestone merges.
  • Documents branch and release-tagging rules.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
README.md Rewrites the v2 release procedure.
package.json Bumps the package version to 2.2.0.
package-lock.json Synchronizes root lockfile metadata.
AGENTS.md Documents release and branching conventions.
Suppressed comments (1)

README.md:347

  • In a Bash block, <x.y.z> is input-redirection syntax, so this documented command fails rather than creating a tag. Use the concrete release example already introduced below (or a shell variable) so the procedure is executable.
git tag <x.y.z> && git push origin <x.y.z>

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread AGENTS.md Outdated
Copilot review:

- `<x.y.z>` / `<major|minor|patch>` inside a bash block is shell redirection,
  so both documented commands were syntax errors if copied. Verified: `bash -n`
  rejects `git tag <x.y.z> && ...` and accepts `git tag 2.3.0 && ...`. Use a
  concrete 2.2.0 -> 2.3.0 example and say what to substitute.
- "agree on the version at every point" / "never disagree" overstated it. The
  procedure deliberately bumps v2/main first, so between the bump and the
  milestone merge the branches differ — v2/main reads the version being built,
  main the one released. Describe the real invariant: they converge when the
  release merge lands, and v2/main is never left behind main.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review round 1 — responses

All three accepted and fixed in 4d567c97. Mirroring inline replies here, since those threads go outdated once pushed.

✅ Angle-bracket placeholders break the bash blocks

A genuine syntax error, not a style nit — <x.y.z> is input redirection. Verified both ways:

$ bash -n -c "git tag <x.y.z> && git push origin <x.y.z>"
bash: -c: line 0: syntax error near unexpected token `&&`
$ bash -n -c "git tag 2.3.0 && git push origin 2.3.0"
(ok)

Both blocks now use a concrete 2.2.02.3.0 example with a line saying what to substitute. I checked no other bash block in the README still has an angle-bracket placeholder. (The npm version <major|minor|patch> form predated this PR — carried forward from the old procedure, fixed now.)

✅ "agree at every point" / "never disagree" overstated the invariant

The best catch of the three, because the wrong claim invites precisely the misdiagnosis it warns about. Bumping v2/main first guarantees an interval where the branches differ — v2/main on the version being built, main on the released one.

Both README.md and AGENTS.md now state the real invariant: they converge when the release merge lands, and v2/main is never left behind main. I added a directional cue so it is actionable — ahead means a release is in flight, behind means something went wrong.

npm run ci passes (exit 0).

Copilot AI left a comment

Copy link
Copy Markdown

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 3 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (1)

README.md:355

  • The PR body and linked #2010 still show v2.3.0 / git tag v2.3.0, while this procedure correctly requires the repository’s established bare tag (2.3.0). Update those descriptions to use bare tags so the release instructions do not conflict.
⚠️ **No `v` prefix.** This repo's release tags are bare `x.y.z` — `2.2.0`, `2.1.0`, `2.0.0` — so tag `2.3.0`, not `v2.3.0`. Note npm's own `tag-version-prefix` defaults to `v` and the repo sets no `.npmrc`, so a bare `npm version` would have produced a `v`-prefixed tag that does not match the convention. Tagging by hand (step 3) is what keeps it right. The workflow's assert step strips a leading `v` before comparing, so a `v`-prefixed tag would still publish — it would just be inconsistent with every previous release.

Copilot AI left a comment

Copy link
Copy Markdown

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 3 out of 4 changed files in this pull request and generated 1 comment.

Comment thread README.md Outdated
…commit

git checkout main && git pull resolves through the maintainer's configured
merge/rebase strategy, so a divergent local main can produce or replay local
commits. Tagging HEAD there tags a commit that is not on origin/main, and
pushing only the tag leaves a release whose commit was never published.

git tag <x> origin/main pins the tag to what the remote branch actually points
at, regardless of local state.

Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review round 3 — one finding, fixed

Fixed in d0143ef8. The release step could tag a commit that is not on origin/main.

git checkout main && git pull resolves through whatever merge/rebase strategy the maintainer has configured, so a divergent local main can produce a merge commit or replay local work. Tagging HEAD then names a commit nobody else has — and git push origin <tag> pushes only the tag, so the release points at an unpublished commit. The publish job would not catch it: its tag-vs-package.json assertion still passes on a locally-merged commit.

-git checkout main && git pull
-git tag 2.3.0 && git push origin 2.3.0
+git fetch origin main
+git tag 2.3.0 origin/main && git push origin 2.3.0

fetch instead of pull (no working-tree change, no strategy involved), and the tag names origin/main explicitly. As a bonus it no longer requires checking out main, so the release can be tagged from any branch.

Also from round 2's suppressed comment: the PR description and #2010 still showed tag v2.3.0, contradicting the bare-tag convention this PR establishes. Both bodies corrected — worth noting because a stale description outlives the review threads.

npm run ci passes (exit 0).

Copilot AI left a comment

Copy link
Copy Markdown

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 3 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (1)

README.md:345

  • The PR description still says this flow creates “no window in which the two disagree,” which contradicts the expected in-flight difference documented here. Please update the description to say it eliminates post-release drift so the PR’s central rationale matches the finalized procedure.
Between steps 1 and 2 the two branches **do** differ, and that is expected, not drift: `v2/main` reads the version being built while `main` still reads the one currently released. What this ordering removes is *post-release* drift — once the milestone merge lands they agree again, and `v2/main` is never left **behind** `main`. If you see `v2/main` ahead of `main`, a release is in flight; if you see it behind, something went wrong.

Copilot AI left a comment

Copy link
Copy Markdown

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 3 out of 4 changed files in this pull request and generated no new comments.

@cliffhall

Copy link
Copy Markdown
Member Author

Copilot rounds 4 and 5 — closed out

Completing the record; these two rounds were addressed but not written up here, so review 4944525585 reads as open when it is not.

Round 4 (4944525585, 19:07) — one suppressed finding, fixed

The PR description still says this flow creates "no window in which the two disagree," which contradicts the expected in-flight difference documented here.

Correct, and the same class as round 2's suppressed comment: the code and docs were fixed, but the PR description still carried the original overstated claim. A stale description outlives the review threads, so it is the version a future reader trusts.

The description now reads:

the branches do differ between step 1 and step 2 — v2/main reads the version being built, main the one currently released — and that is expected, not drift. What this removes is post-release drift: they converge when the milestone merge lands, and v2/main is never left behind main.

No code change — the README and AGENTS.md were already corrected in 4d567c97.

Round 5 (4944529733, 19:09) — clean

No new comments and no suppressed block. That is the confirmation round 4 was resolved.

Full tally across 5 rounds

Round Finding Outcome
1 <x.y.z> in bash blocks is shell redirection fixed 4d567c97
1 "agree at every point" overstated (README) fixed 4d567c97
1 same claim in AGENTS.md fixed 4d567c97
2 (suppressed) PR/issue bodies showed tag v2.3.0 both bodies corrected
3 git pull + git tag can tag a commit not on origin/main fixed d0143ef8
4 (suppressed) PR description carried the stale invariant claim description corrected
5 clean

Two of the seven arrived only in the suppressed block while the review header said "generated no new comments." Worth knowing for anyone reading a Copilot review here: the header is not the whole review.

npm run ci passes on the current head (exit 0).

@cliffhall cliffhall changed the title chore: sync v2/main to 2.2.0 and bump on v2/main before the milestone merge chore: sync v2/main to 2.2.0 + guidance to bump on v2/main before the milestone merge Aug 15, 2026
@cliffhall
cliffhall merged commit ebeaa14 into v2/main Aug 15, 2026
7 checks passed
@cliffhall
cliffhall deleted the v2/chore/2010-version-sync branch August 15, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v2/main's version drifts from main — bump on v2/main before the milestone merge

2 participants