mirror of
https://github.com/gastownhall/beads.git
synced 2026-09-14 20:17:24 +08:00
b3ef65c854
* chore: bump version to 1.3.0
Runs scripts/update-versions.sh 1.3.0, the sanctioned path per RELEASING.md.
Covers everything scripts/check-versions.sh gates: cmd/bd/version.go, the
three plugin manifests plus the marketplace, the MCP pyproject/__init__/
uv.lock pin, npm-package/package.json, the tracked .githooks managed-section
markers, default.nix and the Windows PE resource metadata.
scripts/check-versions.sh passes at 1.3.0.
* docs(changelog): roll up [1.3.0] for 2026-08-28
Creates the [1.3.0] section dated 2026-08-28 and leaves [Unreleased] empty
but present.
- Rolls up everything that was under [Unreleased].
- Adds a 'Breaking changes for v1.2.2 users' section. v1.2.2 shipped the
v1.1.2 tree, so its users never received [1.2.1]; the five behavioral
breaks documented there are restated (close policy on bd update -s, search
including closed, the interactive-only last-touched fallback, bd human list
status handling, dolt push/sync remote-adoption consent) with a pointer to
the historical section rather than a copy of it. The two breaks new in
1.3.0 (BEADS_DOLT_PORT precedence, actor '--' decoding) are indexed here
and written up in full under Changed.
- Adds upgrade notes: first invocation auto-migrates v53 -> v66 (13
migrations, 0054..0066, verified against the embedded migrations dir);
per-step progress on stderr is TTY-gated, so CI sees nothing; back up
first; the forward skew guard means co-resident older binaries refuse the
store, so a shared-store fleet upgrades together; rollback via the recovery
runbook's cursor-rollback procedure.
- Adds entries for eight changes that had no changelog line at all, each
verified against the code on this branch: --profile -> --cpu-profile with
no alias (#5126); the one-time content-derived aux-row id rekey, main 0061
(#5150); events becoming clone-local, 0062 (#5162); the interactions.jsonl
sidecar becoming opt-in behind audit.enabled (#4688); bd import erroring on
redirected stdin with no source (#5171); auto-backup defaulting off under a
sql-server (wy-zrmqr); bd hooks install --chain/--force becoming no-ops
under marker sections (#5284); the new *.gate.lock workspace/physical-root
gate files (#5046, #5093); and purge/prune tier selection (#5995).
- Moves the 'sort on listIssues' entry (#5666) out of [1.2.2] and into
[1.3.0]. Its commit 8aaefe2d4 is not an ancestor of the v1.2.2 tag, so it
never shipped in that release.
* feat(info): add the 1.3.0 versionChanges entry
RELEASING.md makes cmd/bd/info.go a required release step: versionChanges is
the channel 'bd info --whats-new' uses to tell an agent what changed under it.
The entry matches the existing format and carries the same upgrade notes as
CHANGELOG's [1.3.0] — the v53->v66 migration and its cost, the fleet
implication of the forward skew guard, the rollback pointer, the seven
behavioral breaks a v1.2.2 user meets, and the headline changes.
* docs(releasing): document the release-branch process, fix the semver wording, close the audited checklist gaps
Release-branch process (now in use for 1.3.0): a new 'Release Branches'
section covers cutting release/x.y.z from a SHA green on both Main and
Nightly Full Tests, landing every release-targeted change as a PR based on
the release branch and labeled status/needs-review-auto, tagging from the
branch, and forward-porting to main afterwards. Hotfixes are folded into the
same shape rather than a parallel one.
Semver: MAJOR is now removals and incompatible interface changes; documented
behavioral breaks that ship with migration notes are a MINOR bump, with the
obligation that makes that legitimate (CHANGELOG entry naming the override,
plus an info.go summary). 1.3.0 is cited as the worked example.
Checklist gaps the audit found: cross-compiling every goreleaser target
before tagging (GH#5662 — PR CI builds none of them, and the freebsd break
burned the v1.2.0 tag), the docs cutover (cli-docs.pin bump plus regen, and
the hand-maintained release line on docs/index.md, which had gone stale at
1.1.0), a release-notes rollup check for both an unemptied [Unreleased] and
entries misfiled under a previous tag, an explicit check-versions.sh gate,
and the info.go entry.
Also retires the bump-version.sh instructions: that script has been a
deprecation stub that exits 1 for some time, so the document's primary
version-bump instruction could not work. Replaced with update-versions.sh
plus check-versions.sh, and the file list corrected against what the script
touches now (uv.lock, the copilot plugin, the .githooks markers, winres) —
the old list named cmd/bd/templates/hooks/* and PLUGIN.md, neither of which
it writes. 'The Easy Way' now names the release molecule; release.sh is a
gateway that prints it.
Fixes the drifted table of contents while in the area.
* fix(release-formula): bump via update-versions.sh, verify via check-versions.sh
The formula carried its own hand-rolled copy of the version bump, and it had
drifted from the scripts it was copied from. bump-plugin-json pointed at
claude-plugin/.claude-plugin/plugin.json, a path that has not existed since
the plugins moved under plugins/beads/ — so the step would have failed
outright — and the copy covered none of the files added to the gate since:
the codex and copilot plugin manifests, integrations/beads-mcp/uv.lock, and
the BEADS INTEGRATION markers in .githooks/*. A release driven by this
formula would either die on the stale path or ship inconsistent versions,
which is how the v1.1.1 tag burned (stale uv.lock, discovered only in the
tag-triggered run) and how the v1.2.0 bump reddened main (stale hook
markers).
Replaces the seven hand-rolled bump steps with one that runs
scripts/update-versions.sh, which is the sanctioned path and cannot drift
from itself, and turns verify-versions into scripts/check-versions.sh — the
same gate the release-tag pre-push hook and CI run — instead of a grep list
that has to be maintained in parallel with the real one. Both steps carry the
two failure modes worth knowing about: uv missing (leaves uv.lock stale, fails
only after the tag exists) and the hook markers being rewritten wholesale
rather than matched.
Also renames push-main to reflect the release-branch process now documented
in RELEASING.md, and adds the forward-port reminder there.
Verified: each listed file checked against scripts/update-versions.sh and
scripts/check-versions.sh as they exist on this branch, and against a real
./scripts/update-versions.sh 1.3.0 run. go test ./scripts/ -run Release
passes (the formula still parses, and the cleanup-stale-dolt-orphans,
verify-homebrew-core and local-install assertions are untouched).
* docs: point the release banner at 1.3.0 and tell 1.2.2 users what this upgrade costs
The docs homepage carries a hand-maintained 'These docs are for the X.Y.Z
release' line that nothing generates or validates, so it had gone stale at
1.1.0 while the CLI docs pin had already moved to v1.2.2. It now names 1.3.0
and sends the reader to Upgrading first, since this upgrade crosses a schema
migration. RELEASING.md now carries a checklist item for it.
docs/getting-started/upgrading.md was entirely version-agnostic: strong on
mechanism (install methods, hooks, the remote-migrate gate, backup-first,
the multi-clone flow) and silent on which release you are coming from. A
1.2.2 user could read the whole page without learning that their database is
at v53 and that this step crosses 13 migrations. Adds an 'Upgrading to 1.3.0'
section covering the v53->v66 jump and why it is bigger than a routine one,
the slower first invocation and its TTY-gated per-step progress, the
forward-skew consequence for a shared store (upgrade every client together),
and the cursor-rollback runbook. It links to the backup and multi-clone
procedures already on the page rather than restating them.
Also adds the schema-version-mismatch runbook to the Recovery index table.
It was reachable only from the sidebar and the CHANGELOG, and the new
Upgrading section links to it.
Generated docs untouched: scripts/check-cli-docs-drift.sh passes against the
v1.2.2 pin, and the pin bump is a post-tag step (generate-cli-docs.sh builds
bd from the pinned tag, which does not exist until v1.3.0 is pushed).
go test ./test/docsync and scripts/check-doc-freshness.sh pass.
* fix(release-notes): correct the backup advice, the migration count, and the breaks undercount
Review round on #6038. Four findings, all of which made the upgrade notes
actively misleading rather than merely incomplete.
CRITICAL — bare 'bd backup' takes no backup. backupCmd is a runless cobra
parent (no Run/RunE, children init/sync/restore/remove/status, no default),
so cobra prints usage and exits 0 without writing anything. A user following
'bd backup' before an irreversible 27-migration upgrade sees help text and
proceeds believing a snapshot exists; in a script, 'bd backup && ...' proceeds
on exit 0. Replaced with 'bd backup init <path>' then 'bd backup sync' in
CHANGELOG, info.go and upgrading.md, and said in each place that bare
'bd backup' takes no backup.
Also CRITICAL, same class: the backup had no ordering rule. Under 1.3.0
'bd export' triggers autoMigrateOnVersionBump before it exports, so a backup
taken after installing is a post-migration snapshot that cannot protect
against the migration going wrong. All three copies now say to back up with
the OLD binary before installing, and carry the neighbouring rule that
remote-backed stores must finish 'bd dolt push' first, since the
pending-migration gate refuses push/pull too.
Migration count: '13' was the main series only. schema.go runs the main
source then the ignored source through the same 'Applying migration %04d'
printer, and the ignored series moves 0011 -> 0025 here, so the run is ~27
migrations and the counter visibly restarts from 0066 back to 0012. That
backwards jump is exactly the signature an operator reads as a loop and
kills — while these same notes say 'do not interrupt it'. All three copies
now state ~27, show the restart in sample output with real migration names,
and label it as not a restart.
Breaks undercount: 'seven' read as an enumeration, but [1.2.1] carries three
more entries explicitly labelled BREAKING that a v1.2.2 user also meets.
Retitled as highlights with an explicit pointer to the full [1.2.1] section,
and added the three: '--readonly serve' now refused (load-bearing next to the
'restart any long-running bd serve' advice — it will not come back up), the
config kv-plane drop, and the backend package's orphan-handling removal. The
info.go entry gets the same pointer and the same three, since 'bd info' is the
only copy reachable after installing.
Upgrade-time reader is now pointed at 'bd upgrade review', which computes the
delta since the previously-run version via getVersionsSince, instead of
'bd info --whats-new', whose showWhatsNew loops the entire versionChanges
array with no cap (~80 entries) to deliver the ~11 relevant bullets.
* fix(check-versions): gate the copilot manifest and the winres files, stop overclaiming
Three review findings, all cases where the gate said more than it checked.
Copilot manifest was bumped but never gated. update-versions.sh:101 rewrites
plugins/beads/.copilot-plugin/plugin.json with a sed anchored on the OLD
version, and check-versions.sh never read the file — the string 'copilot' did
not appear in it. That is the same drift class that carried stale .githooks
markers through v1.2.0: once the file drifts the bump silently no-ops on it,
the green line prints, the pre-push hook and CI pass, and the Copilot plugin
ships advertising the previous version. Now gated. Verified it fails: drifting
the file to 1.2.2 reddens the run and exits 1.
winres was verified by nothing after the formula rewrite deleted the steps
that grepped it. Restored as real gates rather than formula prose, since
manifest.xml's <assemblyIdentity> version has no backstop at all —
gen-winres.sh re-derives winres.json's numeric fields from version.go at build
time, but the manifest's version is embedded verbatim, and update-versions.sh
rewrites it with a sed anchored on the old base version. Prerelease-correct:
file_version/product_version and the manifest's four-part version are checked
against the BASE version while FileVersion/ProductVersion are checked against
the full string, which is what update-versions.sh writes. The manifest grep is
anchored at line start because the XML declaration also carries a version=
attribute. Verified it fails on drift.
The success line claimed a 'released-docs policy pass' for a check that no
longer exists — the script reads no docs file — while this same release adds
a MANUAL docs-cutover checklist item precisely because nothing automated
covers docs. An operator reading that line would reasonably skip the manual
checks. Now says version files only, and names the manual steps. The two
vestigial echoes left behind by the deleted check are gone.
The failure remedy was also wrong, and wrong in the direction that loops the
operator: it said to re-run update-versions.sh, which derives CURRENT_VERSION
from cmd/bd/version.go (line 70) and substitutes old->new literally. After the
first bump version.go already holds the new version, so a re-run rewrites
new->new and no-ops on exactly the drifted file the gate just named. Verified
empirically — with the copilot manifest and manifest.xml drifted to 1.2.2,
'update-versions.sh 1.3.0' prints 'Bumping: 1.3.0 → 1.3.0' and leaves both at
1.2.2. Only the githooks markers (wholesale regex) and uv.lock (uv lock) heal
on a re-run, and the message now says so and gives the three remedies that
actually work.
shellcheck clean.
* docs(releasing): make the release-branch policy internally consistent
The policy landed in the previous commit but three procedures in the same
files still contradicted it, and the formula implemented the wrong one.
RELEASING.md said 'Nothing is pushed straight to the release branch' and then,
150 lines down, direct-pushed the release branch and minted the tag before the
merge. Two concrete failures: with branch protection the push is rejected
after the tag already exists locally, and with a squash merge the tag points
at a commit that is not an ancestor of release/x.y.z — goreleaser packages
CHANGELOG.md FROM THE TAG into every published archive, so the release ships
the pre-review notes. Both the CHANGELOG-commit block and the bump block now
open a PR, and tagging is a separate step against the merged commit. The
literal 'git push origin main' under the substitution blockquote is gone, as
is the direct push in the docs-pin block.
The formula implemented the wrong order too: commit-release -> create-tag ->
push-main. Reordered to commit-release -> push-main (land the PR) -> create-tag
(on the merged commit) -> push-tag, and create-tag now states why the order
matters.
preflight-pull was untouched by the last commit and still hard-coded main:
divergence recovery was 'git reset --hard origin/main'. Running the molecule on
a release branch and following that destroys the reviewed release-prep commit
and leaves the operator tagging an untested main SHA — precisely the failure
the policy exists to prevent. It now pins the release branch into a variable
first and resets to that; the backup branch moved to Option 1 rather than
Option 3.
'git push origin release/{{version}}' broke every prerelease run: the branch
convention is release/x.y.z, so an RC rendered release/1.3.0-rc.1 and failed
with 'src refspec does not match any', and the forward-port 'git log
main..release/{{version}}' then died on an unknown revision. Now derives the
base version and says why.
The RC workflow still cut tags from the tip of main, which is what the new
policy calls 'a SHA nobody has fully tested' — and worse, an RC exists to
validate the SHA the stable release ships, while the stable tag now comes off
the release branch, so it validated a different SHA by construction. RCs are
now cut on the base version's release branch, and promotion stays on it.
Accuracy fixes in the same pass: verify-versions no longer claims the (now
corrected) 'released-docs policy' string or tells the operator to re-run the
bump — a no-op after the first run, proven in the previous commit — and no
longer prints a prerelease-broken 'grep -c {{version}} winres.json # 4', which
yields 2 for an RC because the numeric PE fields carry the base version. It
now points at check-versions.sh, which gates winres correctly. The 'three
plugin manifests' and 'compares everything else against it' claims are
corrected to match what the script actually reads, and RELEASING.md names
default.nix and README.md as bumped-but-ungated.
go test ./scripts/ and ./test/docsync/ pass; formula still parses and the DAG
is acyclic.
* ci: run PR workflows on release/** branches
Release-targeted PRs currently run almost no CI. pr.yml, pr-risk.yml,
conformance.yml, regression.yml and cross-version-smoke.yml all declare
'pull_request: branches: [ main ]', and every push trigger in the repo is
'branches: [main]' or 'tags: v*'. So a push to release/1.3.0 fires zero
workflows, and a PR based on it gets only the three workflows with no branch
filter (migration-test, nix-build on its paths, docs-mintlify).
That puts the new release-branch policy on a contradiction: it routes the
version bump and 'any fix the release validation turns up' onto a branch where
they land with no unit, lint, conformance or regression coverage, and the
first full signal is the tag build — where a failure burns the tag by this
document's own rule. The policy was written to stop tagging untested SHAs and
was quietly producing them.
Adds release/** to the pull_request branch filter of those five. Push triggers
are deliberately left alone: release branches take changes through PRs, so the
pull_request event is the one that matters, and widening push would double
every run on merge.
cross-version-smoke is the highest-value of the five here — a release-targeted
PR is exactly where cross-version upgrade breakage is most expensive to find
at tag time.
This PR is the vehicle because it targets release/1.3.0, so the new filters
take effect for its own subsequent pushes.
All five files parse; go test ./scripts/ (which includes the workflow lint
tests) passes.
* docs: reconcile the 1.3.0 upgrade notes with the merged release set
Merging origin/release/1.3.0 changed three facts the upgrade notes assert.
Migration count. The merge added ignored/0026_dep_rekey_dedup_marker (#6045),
so the clone-local series now runs 0012 -> 0026, not 0012 -> 0025. Recounted
from the tree: 13 main-series (0054..0066, unchanged) + 15 clone-local = ~28,
not ~27. Corrected in CHANGELOG, cmd/bd/info.go and upgrading.md, including
the trailing line count in the 'counter restarts' explanation.
Shared servers. #6048 (#5920, #5043) means a shared dolt sql-server is no
longer auto-migrated at all — it waits for explicit consent via
'bd migrate schema'. The notes said flatly that 'the first invocation migrates
your schema in place', which is now true only for embedded/local stores and
would have sent a shared-server operator looking for a migration that never
runs. All three copies now scope that claim and point at the new 'Shared
servers' section upgrading.md gained in the same merge. Verified
'bd migrate schema' exists (cmd/bd/migrate.go:848) and that --global is a root
persistent flag (main.go:818), so the cited invocations are real.
#5896. The auto-export entry said #5896 'stays open for embedded mode, where
bd delete still wedges auto-export'. #6059 closed exactly that. Reworded to
point at the store-history heal rather than claiming a live bug.
check-versions.sh 25/25 green, go build ./... clean, go test ./scripts/... and
./test/docsync/ pass, check-cli-docs-drift and check-doc-freshness pass.
* docs(changelog): fold in the proposed changelog lines from the merged 1.3.0 set
Adds the 'proposed changelog' text carried in the bodies of the PRs that
merged into release/1.3.0 after this rollup was first written. Text is the
authors' own; where a body gave it in conventional-commit form rather than as
a bullet, the sentence is preserved and only the 'fix(scope):' prefix dropped
and a bold lead added to match the section.
Changed: #6048 (two bullets — shared-store consent, and the smart gate's
first-mover/fast-forward arms going embedded-only), #6036 (exported packages
marked EXPERIMENTAL), #6053's revision-token bullet, #6049 (migration-test and
upgrade-smoke wisp-plane coverage).
Fixed: #6040 (server-mode lost updates), #6044 (removed-backend rejection),
#6045 (convergent dependency rekey), #6046 (tracked ignored_schema_migrations
heal), #6054 (ignored-cursor floor clamp), #6059 (delete-wedge heal), #6057
(full GC after flatten/compact), #6060 (--storage-class routes), #6061
(journal actor attribution), #6062 (proxied/gateway init errors), and #6053's
two typed-JSON bullets.
Security: new subsection for #6047 (Go 1.26.7 toolchain bump closing seven
reachable stdlib advisories, plus the dependency bumps clearing all 25).
Placed after Fixed per Keep a Changelog ordering.
Documentation: #6052's multi-rig/proxied gate limitation. Its body calls it a
release-notes line rather than a changelog line, so it may want moving.
Contributor credit carried where the PR body gives it: #6040 keeps its
'Reported and fixed by @nova-submodules' sentence, and #6044 gains a note that
its detection helper is ported from @steveyegge's #4740. NOTE: #5064 (aux
row-key encoding drift) carries credit to @marcodelpin in its body but no
proposed changelog line, so it has no entry here — flagging rather than
inventing one.
#6043 was a REPLACEMENT, not an addition: it asked for the existing
MIGRATION-FREEZE bullet to be swapped for vendor-neutral text. Done — the old
bullet named the gt CLI, 'town root' and 'gt migrate thaw'; the new one
describes the generic marker discovery, exit code 14, and the wider set of
maintenance that stands down.
#6055 and #6056 were still OPEN at the time of writing. Their four proposed
lines are included but fenced in a PROVISIONAL HTML comment block that says to
delete it before tagging if either PR does not land.
check-versions.sh 25/25, go build clean, go test ./scripts/... and
./test/docsync/ pass, check-cli-docs-drift and check-doc-freshness pass.
* docs(changelog): credit the three carried contributor fixes
Adds the entries for the merged PRs that carried contributor work but shipped
no proposed changelog line of their own, in the maintainer's supplied wording,
expanded to the surrounding entries' voice.
ATTRIBUTION CORRECTED on #5064. The supplied wording read 'Reported by
@marcodelpin, fixed by @maphew'; the PR body says the opposite. Its '## Credit'
section: 'The fix is @marcodelpin's, from 767d5dcd on their fork... The
diagnosis behind it — the chunk-level characterisation, the negative result on
the minimised fixture, the dolt 2.1.10 re-test, the recover-rows verification —
is theirs too... isSchemaEncodingDriftErr and its table-driven test come from
that commit.' @maphew (the PR author) absorbed it with a review-requested
semantic rework. Written as 'Diagnosis and fix by @marcodelpin, carried and
reworked by @maphew' so the contributor is not demoted to reporter of a bug
they also fixed.
Scope corrected on the same entry. The supplied wording reads as new behavior,
but git grep against the v1.1.2 tag finds both isSchemaEncodingDriftErr and
aux_row_rekey_drifted already present in internal/storage/schema/
aux_row_id_backfill.go — v1.2.2 is the v1.1.2 tree, so v1.2.2 users already
have this fix, and it is already documented under [1.1.2]. #5064 carries it
onto the main line. The entry says so, so a v1.2.2 reader does not conclude
they were exposed and go looking for a migration that does not concern them.
#5783 and #6037 verified against their PR bodies before writing; both supplied
claims hold. #5783: Config.LenientOpen reached server mode but newServerMode
never read it and the field's doc comment said 'Ignored in server mode', so the
dirty-table refusal's own recovery command could not run — and server mode has
no 'move the directory aside and re-bootstrap' alternative. #6037: bd init
persists a git-origin-derived sync.remote into the tracked config by design,
bootstrap rejected exactly that shape before the origin auto-detect, and
Action=='none' conflated 'already exists' with 'refused', printing a success
tick and exiting 0 having created nothing.
Also notes in the PROVISIONAL fence that the RC is gated on #6055/#6056
merging, so the fence comes off at RC-prep time rather than being an open
question.
check-versions.sh 25/25, go test ./test/docsync/ passes.
* fix(release): create release-prep branch before pushing it
The new release-branch/prep-PR flow pushed `release-prep/v<version>`
without ever creating that branch, so `push-main` (and the RELEASING.md
runbook) failed on first run with
`error: src refspec release-prep/v<version> does not match any`.
Add `git checkout -b` before each prep-branch push — the formula
`push-main` step and both RELEASING.md landing snippets — so the branch
exists before it is pushed, mirroring the existing `REL_BRANCH` guard in
the same step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>