feat(build): stamp a self build with the release it anticipates - #213
Merged
Conversation
`build:self` reported the committed package version, so on a `main` carrying unreleased work it wrote `install.cliVersion: "0.10.2"` into the committed `.taskless/taskless.json` — a release that predates the tree, and a value indistinguishable from what a real install of that release would write, so the file silently lost whatever it held. That happened twice in one afternoon, each time caught only because someone read the diff before staging. A self build now stamps `<next>-self`, where `<next>` is what the pending changesets propose. `scripts/next-version.ts` reads it from `changeset status` and falls back to the committed version when nothing is pending, which is the state of `main` for the whole window after a release. Selection is by package name rather than `releases[0]`: the six `@taskless/vale-*` packages share the changesets workspace, so the index is the CLI only until something ships alongside it. Unlike the nightly resolver this falls back rather than throwing, and the asymmetry is deliberate. A nightly that guesses sends agents to the wrong published package, so a wrong string is worse than a failed build. A self build is local, its invocation is a path rather than a package specifier, and the suffix is what carries the meaning, so an unset env degrades instead of blocking someone's local build. The suffix is safe for the ledger: `reconcile-marker` compares the numeric core, so `0.11.0-self` and `0.11.0` are the same version to a reconciliation walk, exactly as a nightly and its release are. A test pins that. Commits the resulting `0.11.0-self`, and verified the prod build still reports `0.10.2`, so the suffix does not leak.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
build:selfreported the committed package version. Its second step isinit --no-interactive, which writesinstall.cliVersioninto the committed.taskless/taskless.json— so on amaincarrying 35 pending changesets, a local dogfood build wrote0.10.2.That is wrong twice over. It names a release that predates the tree the build came from, and it is byte-identical to what a real install of that release would write, so the file silently loses whatever it held with nothing to signal it.
Not hypothetical: this bit two separate agents in one afternoon, each time noticed only because someone read the diff before staging.
The fix
A self build now stamps
<next>-self, where<next>is what the pending changesets propose. Today that is0.11.0-self, which this PR commits.scripts/next-version.tsderives it fromchangeset status, with two details that are easy to get wrong:releases[0]. The six@taskless/vale-*packages share the changesets workspace, so the index is the CLI only until something ships alongside it.nightly-pack.cjsdocuments the same trap.--output=resolves against the CWD.--output=/tmp/x.jsonsilently writes<cwd>/tmp/x.json; I hit this while building the script.It falls back to the committed version when no changesets are pending, which is the state of
mainfor the whole window after a release. A self build has to keep working there.Why this falls back where nightly throws
resolveNightlyVersionrefuses to guess, because a nightly with a wrong version sends agents to the wrong published package — a wrong string is worse than a failed build.A self build is the opposite case. It is local, its invocation is a filesystem path rather than a package specifier, and nothing it emits is fetched by anyone. The
-selfsuffix is what carries the meaning; the base is a convenience. So an unset or malformed env degrades to<committed>-selfrather than blocking someone's local build. The asymmetry is spelled out in the code so it does not read as an oversight.The suffix is safe for the ledger
reconcile-markercompares the numeric core (version.split("-")[0]), so0.11.0-selfand0.11.0are the same version to a reconciliation walk — exactly as a nightly and its release already are. A test pins that rather than leaving it as an assumption.Verification
pnpm build:selfinstall.cliVersion: "0.11.0-self"dist-self/index.jstaskless v0.11.0-selfpnpm build(prod)0.10.2— the suffix does not leaktaskless.json, no stray rewritespnpm testNew tests cover the stamped value, the fallback with no base, four shapes of malformed base, and the numeric-core equality the ledger depends on.
Notes
0.11.0-selfis the point rather than a side effect: it records that a self build last wrote the scaffold, and it is unmistakable in a diff if one does so again.