Declare the runtime floor, and derive the release bump - #357
Conversation
…a script
`release` cut a patch unconditionally. On a 0.x line the minor is the break
slot, so the re-founding — a changelog entry that opens with BREAKING and
removes the package's only import entry point — would have gone out as 0.1.6
and resolved for anyone on `^0.1.5`.
`bunset` already refuses `--patch` when a commit carries a Conventional Commits
break marker, but that guard reads commit messages: none of the 27 commits since
v0.1.5 carries one, so it never fires for a break recorded as a changelog
heading. Rather than hand-roll changelog parsing here — four repos use bunset,
and it is the one that owns this question — `release` and `release-minor` now
run one shared `release-checks` gate set and differ only in the bump.
Also declares `engines: {node: ">=24", bun: ">=1.4.0"}`. The floor node:sqlite
needs was asserted in prose and nowhere a package manager reads, so installing
on Node 22 succeeded and failed later, inside the storage layer.
Drops the better-sqlite3 devDependency and its trustedDependencies entry, unused
since @workglow/sqlite moved to node:sqlite. That swap also left
isUniqueConstraintError matching a string only the native driver produced:
node:sqlite reports every failure as code "ERR_SQLITE_ERROR" and puts the
specific one in a numeric errcode, so SQLite had the English error message as
its only signal. Verified against Node 24.20 — UNIQUE index 2067, PRIMARY KEY
1555, and CHECK 275 / NOT NULL 1299 which must not match.
src/packageManifest.test.ts pins the floor, the absent driver, the binary-only
shape, and that both bump levels share one gate set.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWp6Z6wvAPDaDCjAFcTSj6
`release` cut a patch and `release-minor` was the second script to
remember when the changelog opened with BREAKING. That leaves the number
to whoever types the command, which is the failure it was meant to
prevent, one step further back.
bunset 1.1.1 derives it. `--auto` reads the bump off the commits since
the last tag AND off a diff of `package.json` against the one at that
tag — a lost `exports` subpath or `bin` entry, an `engines` floor that
appeared or moved up — and raises the derived bump to the break slot when
it finds one. That is the class of break no commit message describes,
because nothing about it looks like a breaking edit.
Both breaks in this release are exactly that class, and `--auto` finds
them without being told:
[entry-point-removed] no "exports", "main" or "module"
[engines-added] engines.node is now ">=24"
[engines-added] engines.bun is now ">=1.4.0"
derived bump = minor → 0.1.5 → 0.2.0
`release-minor` is removed rather than kept beside it: a script that
names a level is the choice `--auto` takes away, back in the place it was
made from. The shared `release-checks` gate set is unchanged.
The manifest ratchet follows — it now asserts the release script derives
rather than names, that no bump flag survives anywhere in it, and that
the pinned bunset is one that has `--auto` (an older pin does not fail
loudly; it takes the flag as unknown).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWp6Z6wvAPDaDCjAFcTSj6
|
Switched to
So the same 0.2.0 This narrows sroussey/bunset#8. I filed that asking for the changelog's leading unreleased heading as a second input to the break-slot guard. The manifest diff covers this release without it. What it still cannot see is a break with no manifest footprint and no commit marker — a changed function signature, or a removed CLI flag — so the ask stands, but it is smaller than I wrote it.
The PR body above is now out of date on this point; the commit message and the changelog entry carry the current story. Generated by Claude Code |
The conflict is the one this PR's merge note predicted: both sides append to the same `### Changed` list and neither edits the other's bullets, so both sets are kept. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWp6Z6wvAPDaDCjAFcTSj6
### Features - implement ITabularStorage.join for @WorkGlow 0.5.0 (#362) - implement CLI signal teardown and resource shutdown ### Bug Fixes - declare the embedding width beside the model instead of assuming it (#359) #### release - declare the runtime floor, and derive the release bump (#357) #### kb - stop --dry-run creating the index tables, and report them in db stats - bound `ask`'s implicit index, pin the embedding model, and let `db reset` drop the index #### ask - refuse rather than answer from model memory when nothing is retrieved #### adv - scope each Form ADV archive to its own folder and make ingest idempotent ### Performance #### status - read the newest ADV snapshot with one indexed row ### Tests #### coverage - make the README witness check capable of failing (#360) ### Chores - update deps - update dependencies to latest versions - migrate from Prettier to oxfmt for code formatting #### deps - upgrade Vitest to 5 (#342) ### Updated Dependencies - `@workglow/cli`: 0.5.0 - `typebox`: 1.3.29 - `workglow`: 0.5.0 - `@types/bun`: 1.4.2 - `bunset`: 1.1.1 - `oxlint`: ^1.82.0 - `vitest`: ^5.0.0
Closes #347. Closes #357.
The problem
releasecut a patch unconditionally. On a 0.x line the minor is the break slot, so the re-founding — a changelog entry that opens withBREAKINGand removes the package's only import entry point — would have gone out as 0.1.6 and resolved for anyone on^0.1.5.What I found that changes the fix
bunsetalready refuses--patchon a breaking change (assertBumpAllowsBreakingChanges,src/version.ts:36-44). But that guard reads commit messages — a trailing!or aBREAKING CHANGE:footer — and across the 27 commits sincev0.1.5there is not one:So the guard never fires for a break recorded only as a changelog heading. The issue's premise is confirmed.
Changes
The bump is derived, not chosen.
release-checksholds the gate set (format, lint, typecheck, build, prepack-check); onereleasescript runs it and thenbunset --auto.--autoreads the bump off the commits since the last tag and off a diff ofpackage.jsonagainst the one at that tag — a lostexportssubpath orbinentry, anenginesfloor that appeared or moved up — raising the derived bump to the break slot when it finds one. Both breaks in this release are exactly that class, and it finds them unaided:release-minoris removed rather than kept beside it: a script that names a level is the choice--autotakes away, back in the place it was made from.bunsetis pinned to1.1.1—--autoarrived in 1.1.0 and its 0.x table was corrected in 1.1.1, and an older pin does not fail loudly, it takes the flag as unknown.This also narrows sroussey/bunset#8, which I filed asking for the changelog's leading unreleased heading as a second input to the break-slot guard. The manifest diff covers this release without it. What it still cannot see is a break with no manifest footprint and no commit marker — a changed signature, a removed CLI flag — so the ask stands, smaller.
engines: {"node": ">=24", "bun": ">=1.4.0"}. The floornode:sqliteneeds was asserted in.claude/CLAUDE.mdand nowhere a package manager reads, sonpm i -g @workglow/secon Node 22 installed cleanly and failed later, inside the storage layer, reading as a storage bug.better-sqlite3dropped fromdevDependenciesandtrustedDependencies, unused since@workglow/sqlitemoved tonode:sqlite.A latent bug that swap left behind.
isUniqueConstraintErrormatchedcode === "SQLITE_CONSTRAINT_UNIQUE"— abetter-sqlite3spelling.node:sqlitereports every failure ascode: "ERR_SQLITE_ERROR"and puts the specific one in a numericerrcode, so that branch never fired and SQLite was left with the English error message as its only signal, against the two-signal design the function's own JSDoc states. Verified on Node 24.20:codeerrcodeERR_SQLITE_ERROR2067UNIQUE constraint failed: t.aERR_SQLITE_ERROR1555UNIQUE constraint failed: pk.aERR_SQLITE_ERROR275CHECK constraint failed: …ERR_SQLITE_ERROR1299NOT NULL constraint failed: …Both UNIQUE codes are now matched and both non-UNIQUE ones are asserted not to be.
Note for review:
isUniqueConstraintErrorhas no callers insrc/— it went dead with the identity tier. I fixed rather than deleted it because deletion belongs with #355, which enumerates the dead exports; I have commented there, since its list of nine missed this one.Docs. README's "Cutting a release" section explains the derivation, and states the binary-only package shape explicitly (the issue's ask 3), since a manifest with no
exports/main/typesotherwise reads as a field someone deleted by mistake.The ratchet
src/packageManifest.test.tspins the floor, the absent native driver, the binary-only shape, and the release script's shape: that it derives rather than names, that no bump flag survives in it, and that the pinned bunset has--auto. Written first — 6 of its assertions were red against the old manifest, the green ones being the package shape that already held.Verification
format-check,lint,typecheckclean.packageManifest.test.ts11/11,isUniqueConstraintError.test.ts17/17 (3 new assertions red before the fix).bunset --auto --dry-run --debugon this branch derives the minor and would tagv0.2.0.Merge note
Conflicts with
claude/p1-sec-352-dry-run-kbonCHANGELOG.mdonly — both append to the same### Changedlist. Resolution is to keep both bullet sets; no code overlap.🤖 Generated with Claude Code
https://claude.ai/code/session_01LWp6Z6wvAPDaDCjAFcTSj6