Skip to content

Version Packages - #460

Merged
chee merged 1 commit into
mainfrom
changeset-release/main
Oct 23, 2026
Merged

chee merged 1 commit into
mainfrom
changeset-release/main

Conversation

@patchcrow

@patchcrow patchcrow commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@inkandswitch/patchwork-bootloader@0.8.5

Patch Changes

  • 3d2d0b0: The service worker no longer mistakes a booting automerge worker for a missing one. The worker only asked for its lock once its whole import graph (most of a megabyte) had loaded, so asset requests made in that window found no lock and logged "no automerge worker; asking tabs to start one". Each tab then dropped its connection to the booting worker and reconnected sync. In a single tab that happened on every reload.

    The worker's script, automerge-protocol-handler-worker.js, is now a small module that takes the lock and holds on to connecting tabs before it imports the worker itself, now @inkandswitch/patchwork-bootloader/automerge-protocol-handler. The vite plugin emits that as a second file, automerge-protocol-handler.js, beside the first. As a backstop, the service worker waits three seconds before nudging, and only nudges if the request is still unanswered and there's still no lock. The nudge is throttled to once every five seconds, however many requests are waiting. Before, every request that raced the same cold start got past the throttle and logged its own nudge.

    The e2e suite gains automerge-worker.spec.ts, which checks that the worker holds its lock once a tab is up and that a request racing a cold worker boot isn't reported as a missing worker.

  • 3d2d0b0: Package heads lookups no longer pile up on a busy automerge worker. A package doc that's still syncing, as everything is on a fresh login, reports a change with every batch that arrives. The ModuleWatcher started a lookup for each one, and the automerge worker ran each as a full resolve with its own 30-second timeout. A worker slowed by the login sync then timed them all out, and each logged its own 557.

    The ModuleWatcher now runs one change-triggered lookup per package at a time. Changes that land while one is in flight collapse into a single lookup after it. The automerge worker shares one resolve between concurrent requests for the same package url without heads, so tabs asking at once wait on the same lookup.

  • Only cache resolved paths when the root and every followed link pin their document heads.

  • Updated dependencies [3d2d0b0]

  • Updated dependencies [3d2d0b0]

  • Updated dependencies

    • @inkandswitch/patchwork-filesystem@0.2.14

@inkandswitch/patchwork-filesystem@0.2.14

Patch Changes

  • 3d2d0b0: Package heads lookups no longer pile up on a busy automerge worker. A package doc that's still syncing, as everything is on a fresh login, reports a change with every batch that arrives. The ModuleWatcher started a lookup for each one, and the automerge worker ran each as a full resolve with its own 30-second timeout. A worker slowed by the login sync then timed them all out, and each logged its own 557.

    The ModuleWatcher now runs one change-triggered lookup per package at a time. Changes that land while one is in flight collapse into a single lookup after it. The automerge worker shares one resolve between concurrent requests for the same package url without heads, so tabs asking at once wait on the same lookup.

  • 3d2d0b0: When the service worker can't redirect a package url to its heads, the error now includes the automerge worker's reason (the first line of its 557 body — e.g. the doc is unavailable, or the resolve timed out) instead of only the status.

  • Only cache resolved paths when the root and every followed link pin their document heads.

@inkandswitch/patchwork@0.8.7

Patch Changes

  • 3d2d0b0: The service worker no longer mistakes a booting automerge worker for a missing one. The worker only asked for its lock once its whole import graph (most of a megabyte) had loaded, so asset requests made in that window found no lock and logged "no automerge worker; asking tabs to start one". Each tab then dropped its connection to the booting worker and reconnected sync. In a single tab that happened on every reload.

    The worker's script, automerge-protocol-handler-worker.js, is now a small module that takes the lock and holds on to connecting tabs before it imports the worker itself, now @inkandswitch/patchwork-bootloader/automerge-protocol-handler. The vite plugin emits that as a second file, automerge-protocol-handler.js, beside the first. As a backstop, the service worker waits three seconds before nudging, and only nudges if the request is still unanswered and there's still no lock. The nudge is throttled to once every five seconds, however many requests are waiting. Before, every request that raced the same cold start got past the throttle and logged its own nudge.

    The e2e suite gains automerge-worker.spec.ts, which checks that the worker holds its lock once a tab is up and that a request racing a cold worker boot isn't reported as a missing worker.

  • Updated dependencies [3d2d0b0]

  • Updated dependencies [3d2d0b0]

  • Updated dependencies [3d2d0b0]

  • Updated dependencies

    • @inkandswitch/patchwork-bootloader@0.8.5
    • @inkandswitch/patchwork-filesystem@0.2.14

@inkandswitch/patchwork-e2e@0.2.3

Patch Changes

  • 3d2d0b0: The service worker no longer mistakes a booting automerge worker for a missing one. The worker only asked for its lock once its whole import graph (most of a megabyte) had loaded, so asset requests made in that window found no lock and logged "no automerge worker; asking tabs to start one". Each tab then dropped its connection to the booting worker and reconnected sync. In a single tab that happened on every reload.

    The worker's script, automerge-protocol-handler-worker.js, is now a small module that takes the lock and holds on to connecting tabs before it imports the worker itself, now @inkandswitch/patchwork-bootloader/automerge-protocol-handler. The vite plugin emits that as a second file, automerge-protocol-handler.js, beside the first. As a backstop, the service worker waits three seconds before nudging, and only nudges if the request is still unanswered and there's still no lock. The nudge is throttled to once every five seconds, however many requests are waiting. Before, every request that raced the same cold start got past the throttle and logged its own nudge.

    The e2e suite gains automerge-worker.spec.ts, which checks that the worker holds its lock once a tab is up and that a request racing a cold worker boot isn't reported as a missing worker.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Benchmarks: Patchwork with this PR against main

d26ede3 against main at 3d2d0b0, Patchwork as it ships (patchwork mode), measured one after the other on the same runner (run). Lower is better throughout. A row is in the table when every run of the PR came out on the same side of every run of main, with the medians more than 20% apart; every benchmark is below it.

benchmark main PR change
…server confirmed every edit (40 tabs) ok 2/3 ok fails 1 of 3
every benchmark: the median of 3 runs of main and 3 runs of the PR, their range in brackets
benchmark main PR change
boot → repo, first tab (1 tabs) 262 ms (260–280) 277 ms (257–319) +5%
boot → server connected, first tab (1 tabs) 484 ms (468–496) 476 ms (471–543) −2%
renderer memory, all tabs + workers (1 tabs) 400 MB (399–408) 401 MB (400–402) +0%
renderer processes (1 tabs) 3 3
boot → repo, first tab (3 tabs) 284 ms (275–296) 279 ms (266–279) −2%
boot → repo, last tab (3 tabs) 183 ms (181–192) 181 ms (179–182) −1%
boot → server connected, first tab (3 tabs) 563 ms (544–597) 552 ms (551–562) −2%
renderer memory, all tabs + workers (3 tabs) 739 MB (729–746) 733 MB (728–739) −1%
renderer processes (3 tabs) 5 5
boot → repo, first tab (10 tabs) 267 ms (251–276) 255 ms (250–256) −4%
boot → repo, last tab (10 tabs) 191 ms (190–204) 194 ms (186–194) +2%
boot → server connected, first tab (10 tabs) 647 ms (569–648) 648 ms (558–659) +0%
renderer memory, all tabs + workers (10 tabs) 1900 MB (1872–1918) 1894 MB (1884–1902) −0%
renderer processes (10 tabs) 12 12
sync still works after the first tab closes ok ok
edit → seen + confirmed, after first tab closed 93 ms (90–94) 83 ms (82–100) −11%
server link seen down while offline FAIL FAIL
…and the server did not see the offline edits FAIL FAIL
tabs converged while offline, over a local channel ok ok
offline edits in two tabs both survive reconnect ok ok
reconnect → tabs converged (only where they hadn't already) – –
…and a fresh tab sees both ok ok
boot → doc open, tab 1 606 ms (603–623) 613 ms (602–629) +1%
boot → doc open, tab 2 325 ms (315–325) 315 ms (314–315) −3%
boot → doc open, tab 10 315 ms (306–316) 304 ms (303–323) −4%
open 40 tabs, wall clock 9173 ms (9129–9181) 9224 ms (9144–9535) +1%
boot → repo, last of 40 tabs 68 ms (68–79) 67 ms (67–74) −1%
boot → linked, last of 40 tabs – –
boot → server connected, last of 40 tabs 186 ms (184–200) 191 ms (190–242) +3%
renderer memory, 40 tabs 7294 MB (7205–7362) 7226 MB (7005–7270) −1%
renderer processes, 40 tabs 42 42
39 tabs find the doc: median 822 ms (792–852) 830 ms (766–862) +1%
39 tabs find the doc: slowest 919 ms (909–959) 914 ms (905–954) −1%
…all 39 found it ok ok
…finds that needed a retry (of 39) 0 0
edit → seen in 39 tabs: median tab 37 ms (33–38) 41 ms (40–49) +9%
edit → seen in 39 tabs: slowest tab 83 ms (70–87) 77 ms (73–144) −7%
…tabs that saw every edit (of 39) 39 39
edit → server holds our heads (40 tabs) 164 ms (163–206) 185 ms (173–196) +13%
…server confirmed every edit (40 tabs) ok 2/3 ok fails 1 of 3
…longest main-thread stall in tab 0 during the edits 51 ms (49–63) 58 ms (45–74) +14%
sync rounds per sibling edit, non-editing tab 0 0
server bytes received per edit per tab – –
storage writes (saveBatch) per edit per tab – –
worker errors (40 tabs) 0 0
a fresh tab finds a closed tab's doc (no server) ok ok
…time to find it, from storage 46 ms (46–52) 45 ms (42–53) −2%
…and every edit made before the close is in it ok ok
edits from tabs closed right after editing all survive ok ok
…or at least 5s later ok ok
find a doc another tab just created 72 ms (69–97) 73 ms (63–83) +1%
…and every such find() succeeded within 5s ok ok
…and none settled unavailable first ok ok
edit → seen in 2 other tabs 7 ms (6–7) 6 ms (6–7) −13%
…every edit reached every other tab within 5s ok ok
edit → server holds our heads 63 ms (62–64) 63 ms (62–72) +0%
…the server confirmed every edit within 5s ok ok
…and a stranger gets the whole doc from the server ok ok
renderer memory, 1 tab 402 MB (398–407) 404 MB (399–404) +0%
renderer memory, 10 tabs 1877 MB (1860–1911) 1881 MB (1872–1905) +0%

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🪡 Patchwork

Torn down.

@github-actions
github-actions Bot force-pushed the changeset-release/main branch from ccae879 to d26ede3 Compare October 23, 2026 01:12
@chee
chee merged commit ccb32c6 into main Oct 23, 2026
10 checks passed
@chee
chee deleted the changeset-release/main branch October 23, 2026 09:29
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.

2 participants