Skip to content

Upgrade Changesets to v3 and the benchmark harness to tinybench 6 - #259

Merged
SandroMaglione merged 2 commits into
mainfrom
changesets-3-and-tinybench-6
Nov 1, 2026
Merged

SandroMaglione merged 2 commits into
mainfrom
changesets-3-and-tinybench-6

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Summary

Two dependency majors that each need code or workflow changes, in separate commits.

tinybench 2.9.0 → 6.2.2 (runtime benchmark harness)

  • Bench no longer has warmup(). Bench.run() now warms each task up right before measuring it, using the same warmupTime/warmupIterations. The explicit bench.warmup() call is removed.
  • Samples are only kept with retainSamples: true, which is now set.
  • Results moved under task.result.latency and are discriminated by result.state. The harness throws on errored and on any state other than completed.
  • The report schema and definitions are unchanged, matching tinybench 2.9 exactly:
    • medianBatchMilliseconds, p95BatchMilliseconds, and p99BatchMilliseconds still use the harness's own percentile over the sorted samples. tinybench 2.9's p99 used the same index formula; tinybench 6's latency.p99 interpolates, so the harness does not use it.
    • meanThroughput is operations * 1000 / latency.mean. In 2.9, hz was defined as exactly 1000 / mean. tinybench 6's throughput.mean is a different estimator, so the harness does not use it.
    • relativeMarginOfError is latency.rme (percent, Student t), and sampleCount is the retained sample count.
  • Compatibility with the base-versus-PR workflow: the workflow runs the PR's harness against both checkouts. Both sides therefore use tinybench 6 from the PR's node_modules and are measured the same way. I reproduced the workflow locally: I ran the PR harness against an isolated git archive of origin/main (which still installs tinybench 2.9.0) and against this branch, three full interleaved runs each. compare-runtime-performance.mjs --check read all the reports and returned exit 0 with "No large, noise-adjusted throughput or heap regressions detected." Quick-mode runs are too noisy to judge. The CI comparison is authoritative.

@changesets/cli 2.31.0 → 3.0.3, with changesets/action v1 → v2.1.2

These two have to move together:

  • CLI v3 no longer prints the New tag: lines that changesets/action@v1 parses to set published. Under v1, published would stay false, so deploy-website and GitHub releases and tags would silently stop.
  • changesets/action@v2 refuses CLI v2.

release.yml changes:

  • version → version-script and publish → publish-script.
  • The GITHUB_TOKEN env is replaced by the github-token input. v2 fails if a GITHUB_TOKEN env differs from the input.
  • v2 has no floating v2 tag, so the action is pinned to v2.1.2.
  • The published output name is unchanged, so deploy-website keeps working.
  • v2 passes CHANGESETS_OUTPUT to the publish script. pnpm release → changeset publish inherits it, and CLI v3 reads it (process.env.CHANGESETS_OUTPUT) to report published packages.
  • New v2 defaults to know about: the action now pushes release commits and tags through the GitHub API, so they are signed and attributed to github-actions[bot]. The release PR is still authored by github-actions[bot] on changeset-release/main, so the changeset-policy exemption still matches. Trusted publishing (id-token: write, registry-url) is unchanged; v2 only dropped its own NPM_TOKEN .npmrc handling, which this repo does not use.

CLI v3 changes I checked against this repo:

  • Config: the $schema now points at @changesets/config@4.0.1. All keys in use (changelog: "@changesets/cli/changelog", commit, fixed, linked, access, baseBranch, updateInternalDependencies, ignore) are in the v4 schema, and @changesets/cli/changelog is still exported. There was no prettier key to migrate.
  • Provenance: this lives in each package's publishConfig.provenance, not in the Changesets config. CLI v3 still publishes with pnpm publish from the package directory, so publishConfig (provenance, access, and the devtools exports override) keeps applying.
  • Fixed group: a scratch pnpm version-packages with a sample changeset bumped all four packages to 0.47.0 and wrote all four changelogs. changeset publish-plan listed the four at 0.47.0 on latest. changeset pack produced tarballs where workspace:^ becomes ^0.47.0 and the devtools publishConfig.exports is applied.
  • Formatting: the default format: "auto" now detects dprint (dprint fmt --allow-no-files). New changeset files come out dprint-clean: changeset add --empty writes ---\n\n---, which v2 did not.
    • Changelog entries change slightly. v2 ran its bundled Prettier 2 over CHANGELOGs. dprint excludes packages/**/CHANGELOG.md, so v3 leaves them as written. Code samples keep the repo's no-semicolon style, and blank lines inside a list entry carry the two-space indent.
    • The site changelog parser strips that indent, so the rendered output is unchanged.
    • If the formatter is ever switched to oxfmt, auto follows it.
  • Other breaking changes, none used here: changeset tag → git-tag; status --sinceMaster removed; private packages are no longer versioned by default (the root is private and unnamed); Yarn Classic dropped; and changeset version exits 1 when there are no changesets. The action only runs version-script when changesets exist, and a scratch run with only an empty changeset exited 0. Engines are Node ^22.11 || ^24 || >=26 and pnpm >=10; the repo uses Node 24 and pnpm 10.17.1.
  • Not verifiable on a pull request: release.yml only runs on pushes to main, so the action itself cannot run here. I checked the inputs, outputs, and token handling against the v2.1.2 action.yml and src/index.ts/src/run.ts. Watch the first release run after merging.

Changeset

  • Added or updated for a library or package-metadata change
  • Not required because this PR does not change a publishable package

The PR includes an empty changeset (.changeset/changesets-3-and-tinybench-6.md, written by CLI v3's changeset add --empty) only because check-changeset.mjs requires one for root package.json changes. It releases nothing.

Validation

  • pnpm check passed in 4:22: 92 files / 901 tests, tstyche 1334 assertions, consumer, all pack checks, docs, and check:ci (31 tests).
  • pnpm changeset --help, changeset status, changeset add --empty, pnpm version-packages (scratch and on this branch, then reverted), changeset publish-plan, and changeset pack all ran with CLI v3.
  • Automated type-performance measurement passed: all 26 instantiation scenarios unchanged (0.0%).
  • Automated runtime- and memory-performance measurement passed on CI with the tinybench 6 harness on both sides: "No large, noise-adjusted throughput or heap regressions detected". For example, plan counter +0.9% and compound-state observer burst +1.8%.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Type performance

Measured with TypeScript 6.0.3 and skipLibCheck=true.

Scenario Base PR Difference
Effect only 55 55 0 (0.0%)
Import effect-machine 55 55 0 (0.0%)
Machine.state (3 children) 2,664 2,664 0 (0.0%)
Machine.make (3 states, 2 events) 8,932 8,932 0 (0.0%)
machine.handle (3 states, 2 transitions) 39,449 39,449 0 (0.0%)
declared transition (10 named branches) 60,402 60,402 0 (0.0%)
atomic construction, guards, and reentry 85,710 85,710 0 (0.0%)
registered invocation (input-taking Effect) 39,819 39,819 0 (0.0%)
machine.handle (depth 24) 194,531 194,531 0 (0.0%)
machine.handle (wide depth 16) 218,238 218,238 0 (0.0%)
machine.handle (parallel/history/choice) 91,642 91,642 0 (0.0%)
machine definition (3 independent implementations) 99,173 99,173 0 (0.0%)
machine exact input/output/error/services 82,941 82,941 0 (0.0%)
execution adapter readiness 71,428 71,428 0 (0.0%)

Marginal instantiations are measured against the matching setup without that API call:

Scenario Base PR Difference
Import effect-machine 0 0 0
Machine.state (3 children) 2,609 2,609 0 (0.0%)
Machine.make (3 states, 2 events) 6,260 6,260 0 (0.0%)
machine.handle (3 states, 2 transitions) 30,517 30,517 0 (0.0%)
declared transition (10 named branches) 51,849 51,849 0 (0.0%)
atomic construction, guards, and reentry 70,370 70,370 0 (0.0%)
registered invocation (input-taking Effect) 32,682 32,682 0 (0.0%)
machine.handle (depth 24) 177,222 177,222 0 (0.0%)
machine.handle (wide depth 16) 201,707 201,707 0 (0.0%)
machine.handle (parallel/history/choice) 79,144 79,144 0 (0.0%)
machine definition (3 independent implementations) 88,492 88,492 0 (0.0%)
machine exact input/output/error/services 70,732 70,732 0 (0.0%)
execution adapter readiness 31,922 31,922 0 (0.0%)
Check times (informational)
Scenario Base PR
Effect only 0.02s 0.02s
Import effect-machine 0.02s 0.02s
Machine.state (3 children) 0.06s 0.06s
Machine.make (3 states, 2 events) 0.12s 0.12s
machine.handle (3 states, 2 transitions) 0.23s 0.23s
declared transition (10 named branches) 0.29s 0.29s
atomic construction, guards, and reentry 0.39s 0.38s
registered invocation (input-taking Effect) 0.25s 0.23s
machine.handle (depth 24) 0.46s 0.47s
machine.handle (wide depth 16) 0.52s 0.52s
machine.handle (parallel/history/choice) 0.38s 0.40s
machine definition (3 independent implementations) 0.40s 0.40s
machine exact input/output/error/services 0.37s 0.36s
execution adapter readiness 0.32s 0.32s

Type instantiations are the comparison metric. Check time varies with runner load and is informational only.

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Runtime performance

Median of 5 independent benchmark processes on Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz with Node v24.22.1.

Pull request baseline

Scenario Effect Machine
Plan counter transitions 114,717 transitions/s
Drain burst with terminal fence 411,294 increments/s
Drain burst with a change observer 378,481 increments/s
Lookup and send to one child 307,306 increments/s
Start and stop a machine 118,273 machines/s
Start and stop a parent with one child 30,991 families/s
Complete an Effect invocation with tracing enabled 7,820 invocations/s
Complete an Effect invocation with tracing disabled 9,608 invocations/s
Plan transitions through a compound state 103,424 transitions/s
Plan transitions through parallel regions 83,207 transitions/s
Drain burst through a compound state 343,508 events/s
Drain burst through two parallel regions 306,857 events/s
Drain a compound-state burst with a change observer 316,569 events/s

Process runtime reference points

Scenario Effect Machine
Start and stop a raw generic process 28,371 processes/s
Start and stop a raw compiled process 67,893 processes/s
Memory profile Effect Machine
Idle machine 1.8 KiB
Raw generic managed process 11.4 KiB
Raw compiled process 3.1 KiB
Two independent idle machines 3.6 KiB
Idle parent with one child 6.0 KiB
Parent with observed child registry 9.6 KiB
Parent with observed invoked child snapshots 7.0 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 116,124 transitions/s 0.3% MAD 114,717 transitions/s 0.7% MAD -1.2%
Drain burst with terminal fence 406,908 increments/s 0.5% MAD 411,294 increments/s 0.4% MAD +1.1%
Drain burst with a change observer 374,530 increments/s 0.9% MAD 378,481 increments/s 0.2% MAD +1.1%
Lookup and send to one child 302,121 increments/s 1.1% MAD 307,306 increments/s 0.8% MAD +1.7%
Start and stop a machine 118,568 machines/s 0.5% MAD 118,273 machines/s 0.7% MAD -0.2%
Start and stop a parent with one child 31,539 families/s 0.2% MAD 30,991 families/s 0.6% MAD -1.7%
Complete an Effect invocation with tracing enabled 7,935 invocations/s 2.2% MAD 7,820 invocations/s 0.4% MAD -1.4%
Complete an Effect invocation with tracing disabled 9,730 invocations/s 1.2% MAD 9,608 invocations/s 2.2% MAD -1.3%
Plan transitions through a compound state 104,693 transitions/s 0.7% MAD 103,424 transitions/s 0.3% MAD -1.2%
Plan transitions through parallel regions 83,948 transitions/s 0.7% MAD 83,207 transitions/s 1.2% MAD -0.9%
Drain burst through a compound state 339,531 events/s 1.4% MAD 343,508 events/s 0.4% MAD +1.2%
Drain burst through two parallel regions 300,505 events/s 2.4% MAD 306,857 events/s 1.1% MAD +2.1%
Drain a compound-state burst with a change observer 315,625 events/s 1.3% MAD 316,569 events/s 1.0% MAD +0.3%
Idle machine heap per unit 1.9 KiB 0.4% MAD 1.8 KiB 0.2% MAD -2.9%
Raw generic managed process heap per unit 11.4 KiB 0.0% MAD 11.4 KiB 0.0% MAD -0.0%
Raw compiled process heap per unit 3.1 KiB 0.1% MAD 3.1 KiB 0.0% MAD -0.0%
Two independent idle machines heap per unit 3.6 KiB 0.1% MAD 3.6 KiB 0.1% MAD +0.1%
Idle parent with one child heap per unit 6.0 KiB 0.0% MAD 6.0 KiB 0.0% MAD -0.4%
Parent with observed child registry heap per unit 9.6 KiB 0.0% MAD 9.6 KiB 0.0% MAD -0.0%
Parent with observed invoked child snapshots heap per unit 7.0 KiB 0.3% MAD 7.0 KiB 0.0% MAD +0.4%

Process runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 28,328 processes/s 1.0% MAD 28,371 processes/s 1.4% MAD +0.2%
Start and stop a raw compiled process 65,837 processes/s 0.4% MAD 67,893 processes/s 1.0% MAD +3.1%

Regression guard

No large, noise-adjusted throughput or heap regressions detected.

Versions and interpretation
  • Effect Machine: 0.46.0

Higher throughput is better; lower heap is better. Variability is the median absolute deviation across independent processes, relative to their median. Small differences on shared GitHub-hosted hardware remain informational; the required guard rejects only large changes beyond the measured noise allowance.

SandroMaglione and others added 2 commits November 1, 2026 17:56
Bench.run now warms each task up itself and samples are retained explicitly.
Read statistics from the task's latency result while keeping the report
schema and definitions unchanged: median, p95, and p99 still come from the
sorted batch samples and mean throughput is still 1000 / mean latency.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changesets/cli 3 no longer prints the publish lines that changesets/action@v1
parsed, and changesets/action@v2 requires CLI v3, so both move together. Use
the renamed version-script, publish-script, and github-token inputs; the
action now passes CHANGESETS_OUTPUT to the publish script to detect published
packages. Point the config schema at @changesets/config 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@SandroMaglione
SandroMaglione merged commit b9289f3 into main Nov 1, 2026
8 checks passed
@SandroMaglione
SandroMaglione deleted the changesets-3-and-tinybench-6 branch November 1, 2026 09:11
@SandroMaglione
SandroMaglione force-pushed the changesets-3-and-tinybench-6 branch from 636c96b to 00f947a Compare November 1, 2026 09:59
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.

1 participant