Skip to content

add conformsTo to datatypes like uttype - #465

Open
chee wants to merge 2 commits into
mainfrom
conforms-to
Open

chee wants to merge 2 commits into
mainfrom
conforms-to

Conversation

@chee

@chee chee commented Oct 27, 2026

Copy link
Copy Markdown
Member

similar to https://developer.apple.com/documentation/uniformtypeidentifiers

we could declare, like

type: javascript
conformsTo: file

or

type: space
conformsTo: folder, tldraw

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Benchmarks: Patchwork with this PR against main

279607e against main at 912c770, Patchwork as it ships (patchwork mode), in chromium, firefox and webkit, each on its own runner with main and the PR measured one after the other (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.

browser benchmark main PR change
webkit …and the server did not see the offline edits ok 2/3 ok fails 1 of 3 (the bench, not the PR)
webkit …the server confirmed every edit within 5s 2/3 ok ok fixed
every benchmark: the median of 3 runs of main and 3 runs of the PR, their range in brackets
browser benchmark main PR change
chromium boot → repo, first tab (1 tabs) 262 ms (253–270) 256 ms (245–256) −2%
chromium boot → server connected, first tab (1 tabs) 409 ms (400–420) 404 ms (397–413) −1%
chromium renderer memory, all tabs + workers (1 tabs) 363 MB (357–371) 366 MB (361–367) +1%
chromium renderer processes (1 tabs) 3 3
chromium boot → repo, first tab (3 tabs) 263 ms (258–272) 274 ms (268–279) +4%
chromium boot → repo, last tab (3 tabs) 193 ms (189–198) 193 ms (190–199) −0%
chromium boot → server connected, first tab (3 tabs) 436 ms (435–453) 444 ms (442–474) +2%
chromium renderer memory, all tabs + workers (3 tabs) 712 MB (696–724) 715 MB (713–735) +0%
chromium renderer processes (3 tabs) 5 5
chromium boot → repo, first tab (10 tabs) 259 ms (245–261) 256 ms (251–257) −1%
chromium boot → repo, last tab (10 tabs) 192 ms (184–209) 206 ms (195–217) +7%
chromium boot → server connected, first tab (10 tabs) 456 ms (423–499) 431 ms (427–437) −5%
chromium renderer memory, all tabs + workers (10 tabs) 1894 MB (1854–1930) 1898 MB (1835–1925) +0%
chromium renderer processes (10 tabs) 12 12
chromium sync still works after the first tab closes ok ok
chromium edit → seen + confirmed, after first tab closed 106 ms (104–114) 101 ms (94–119) −5%
chromium server link seen down while offline ok ok
chromium …and the server did not see the offline edits ok ok
chromium tabs converged while offline, over a local channel ok ok
chromium offline edits in two tabs both survive reconnect ok ok
chromium reconnect → tabs converged (only where they hadn't already) – –
chromium …and a fresh tab sees both ok ok
chromium boot → doc open, tab 1 529 ms (524–547) 532 ms (523–557) +1%
chromium boot → doc open, tab 2 352 ms (346–360) 341 ms (336–360) −3%
chromium boot → doc open, tab 10 303 ms (302–315) 304 ms (301–340) +0%
chromium open 40 tabs, wall clock 9652 ms (9637–9709) 9525 ms (9519–10895) −1%
chromium boot → repo, last of 40 tabs 70 ms (67–78) 68 ms (67–85) −4%
chromium boot → linked, last of 40 tabs – –
chromium boot → server connected, last of 40 tabs 341 ms (330–358) 349 ms (330–372) +2%
chromium renderer memory, 40 tabs 7265 MB (7227–7343) 7254 MB (7203–7321) −0%
chromium renderer processes, 40 tabs 42 42
chromium 39 tabs find the doc: median 828 ms (744–870) 841 ms (806–871) +2%
chromium 39 tabs find the doc: slowest 939 ms (933–952) 957 ms (918–1070) +2%
chromium …all 39 found it ok ok
chromium …finds that needed a retry (of 39) 0 0
chromium edit → seen in 39 tabs: median tab 58 ms (53–59) 56 ms (53–57) −3%
chromium edit → seen in 39 tabs: slowest tab 133 ms (131–158) 143 ms (135–150) +7%
chromium …tabs that saw every edit (of 39) 39 39
chromium edit → server holds our heads (40 tabs) 170 ms (169–172) 170 ms (169–171) +0%
chromium …server confirmed every edit (40 tabs) ok ok
chromium …longest main-thread stall in tab 0 during the edits 20 ms (11–38) 17 ms (16–22) −14%
chromium sync rounds per sibling edit, non-editing tab 0 0
chromium server bytes received per edit per tab – –
chromium storage writes (saveBatch) per edit per tab – –
chromium worker errors (40 tabs) – –
chromium a fresh tab finds a closed tab's doc (no server) ok ok
chromium …time to find it, from storage 46 ms (39–46) 39 ms (36–47) −15%
chromium …and every edit made before the close is in it ok ok
chromium edits from tabs closed right after editing all survive ok ok
chromium …or at least 5s later ok ok
chromium find a doc another tab just created 51 ms (51–54) 51 ms (51–54) −0%
chromium …and every such find() succeeded within 5s ok ok
chromium …finds that settled unavailable first (of 2) 0 0
chromium edit → seen in 2 other tabs 6 ms (6–7) 6 ms (6–6) +4%
chromium …every edit reached every other tab within 5s ok ok
chromium edit → server holds our heads 72 ms (71–75) 71 ms (70–78) −0%
chromium …the server confirmed every edit within 5s ok ok
chromium …and a stranger gets the whole doc from the server ok ok
chromium renderer memory, 1 tab 360 MB (343–370) 358 MB (355–364) −1%
chromium renderer memory, 10 tabs 1886 MB (1855–1909) 1880 MB (1849–1887) −0%
firefox boot → repo, first tab (1 tabs) 541 ms (523–580) 516 ms (513–544) −5%
firefox boot → server connected, first tab (1 tabs) 652 ms (597–692) 588 ms (586–623) −10%
firefox renderer memory, all tabs + workers (1 tabs) – –
firefox renderer processes (1 tabs) – –
firefox boot → repo, first tab (3 tabs) 511 ms (507–531) 527 ms (511–533) +3%
firefox boot → repo, last tab (3 tabs) 388 ms (378–389) 378 ms (374–387) −3%
firefox boot → server connected, first tab (3 tabs) 695 ms (674–743) 692 ms (674–770) −0%
firefox renderer memory, all tabs + workers (3 tabs) – –
firefox renderer processes (3 tabs) – –
firefox boot → repo, first tab (10 tabs) 572 ms (509–638) 576 ms (557–629) +1%
firefox boot → repo, last tab (10 tabs) 393 ms (385–394) 400 ms (396–411) +2%
firefox boot → server connected, first tab (10 tabs) 739 ms (675–798) 790 ms (745–797) +7%
firefox renderer memory, all tabs + workers (10 tabs) – –
firefox renderer processes (10 tabs) – –
firefox sync still works after the first tab closes ok ok
firefox edit → seen + confirmed, after first tab closed 64 ms (64–75) 64 ms (63–66)
firefox server link seen down while offline ok ok
firefox …and the server did not see the offline edits ok ok
firefox tabs converged while offline, over a local channel ok ok
firefox offline edits in two tabs both survive reconnect ok ok
firefox reconnect → tabs converged (only where they hadn't already) – –
firefox …and a fresh tab sees both ok ok
firefox boot → doc open, tab 1 671 ms (654–773) 687 ms (685–757) +2%
firefox boot → doc open, tab 2 621 ms (498–624) 502 ms (495–641) −19%
firefox boot → doc open, tab 10 616 ms (456–643) 475 ms (458–664) −23%
firefox open 40 tabs, wall clock 29670 ms (23899–30307) 24815 ms (24502–29810) −16%
firefox boot → repo, last of 40 tabs 207 ms (175–313) 170 ms (167–196) −18%
firefox boot → linked, last of 40 tabs – –
firefox boot → server connected, last of 40 tabs 599 ms (501–855) 439 ms (422–626) −27%
firefox renderer memory, 40 tabs – –
firefox renderer processes, 40 tabs – –
firefox 39 tabs find the doc: median 419 ms (415–443) 395 ms (368–445) −6%
firefox 39 tabs find the doc: slowest 445 ms (441–464) 426 ms (387–450) −4%
firefox …all 39 found it ok ok
firefox …finds that needed a retry (of 39) 0 0
firefox edit → seen in 39 tabs: median tab 127 ms (123–128) 126 ms (124–134) −1%
firefox edit → seen in 39 tabs: slowest tab 210 ms (200–219) 217 ms (201–224) +3%
firefox …tabs that saw every edit (of 39) 39 39
firefox edit → server holds our heads (40 tabs) 335 ms (323–345) 337 ms (320–352) +1%
firefox …server confirmed every edit (40 tabs) ok ok
firefox …longest main-thread stall in tab 0 during the edits 143 ms (140–147) 143 ms (136–146) −0%
firefox sync rounds per sibling edit, non-editing tab 0 0
firefox server bytes received per edit per tab – –
firefox storage writes (saveBatch) per edit per tab – –
firefox worker errors (40 tabs) – –
firefox a fresh tab finds a closed tab's doc (no server) ok ok
firefox …time to find it, from storage 31 ms (27–34) 32 ms (31–39) +3%
firefox …and every edit made before the close is in it ok ok
firefox edits from tabs closed right after editing all survive ok ok
firefox …or at least 5s later ok ok
firefox find a doc another tab just created 32 ms (32–34) 31 ms (31–32) −2%
firefox …and every such find() succeeded within 5s ok ok
firefox …finds that settled unavailable first (of 2) 0 0
firefox edit → seen in 2 other tabs 16 ms (16–17) 17 ms (16–17) +1%
firefox …every edit reached every other tab within 5s ok ok
firefox edit → server holds our heads 33 ms (32–33) 33 ms (32–35) −1%
firefox …the server confirmed every edit within 5s ok ok
firefox …and a stranger gets the whole doc from the server ok ok
webkit boot → repo, first tab (1 tabs) 347 ms (346–363) 353 ms (337–360) +2%
webkit boot → server connected, first tab (1 tabs) 669 ms (647–696) 656 ms (637–662) −2%
webkit renderer memory, all tabs + workers (1 tabs) – –
webkit renderer processes (1 tabs) – –
webkit boot → repo, first tab (3 tabs) 372 ms (338–373) 355 ms (355–358) −5%
webkit boot → repo, last tab (3 tabs) 291 ms (274–308) 284 ms (281–292) −2%
webkit boot → server connected, first tab (3 tabs) 679 ms (667–721) 687 ms (672–729) +1%
webkit renderer memory, all tabs + workers (3 tabs) – –
webkit renderer processes (3 tabs) – –
webkit boot → repo, first tab (10 tabs) 333 ms (331–350) 365 ms (349–369) +10%
webkit boot → repo, last tab (10 tabs) 305 ms (287–321) 283 ms (282–312) −7%
webkit boot → server connected, first tab (10 tabs) 640 ms (640–659) 681 ms (671–701) +6%
webkit renderer memory, all tabs + workers (10 tabs) – –
webkit renderer processes (10 tabs) – –
webkit sync still works after the first tab closes ok ok
webkit edit → seen + confirmed, after first tab closed 201 ms (200–211) 213 ms (202–236) +6%
webkit server link seen down while offline ok ok
webkit …and the server did not see the offline edits ok 2/3 ok fails 1 of 3 (the bench, not the PR)
webkit tabs converged while offline, over a local channel ok ok
webkit offline edits in two tabs both survive reconnect ok ok
webkit reconnect → tabs converged (only where they hadn't already) – –
webkit …and a fresh tab sees both ok ok
webkit boot → doc open, tab 1 822 ms (818–852) 809 ms (799–832) −2%
webkit boot → doc open, tab 2 380 ms (366–380) 371 ms (369–390) −2%
webkit boot → doc open, tab 10 403 ms (400–405) 396 ms (369–421) −2%
webkit open 40 tabs, wall clock 24808 ms (24706–25138) 24812 ms (24666–24893) +0%
webkit boot → repo, last of 40 tabs 155 ms (145–172) 161 ms (146–201) +4%
webkit boot → linked, last of 40 tabs – –
webkit boot → server connected, last of 40 tabs 629 ms (628–637) 622 ms (620–623) −1%
webkit renderer memory, 40 tabs – –
webkit renderer processes, 40 tabs – –
webkit 39 tabs find the doc: median 409 ms (383–507) 414 ms (383–531) +1%
webkit 39 tabs find the doc: slowest 719 ms (668–736) 743 ms (574–786) +3%
webkit …all 39 found it ok ok
webkit …finds that needed a retry (of 39) 0 0
webkit edit → seen in 39 tabs: median tab 76 ms (72–77) 77 ms (74–77) +1%
webkit edit → seen in 39 tabs: slowest tab 235 ms (180–240) 234 ms (219–280) −0%
webkit …tabs that saw every edit (of 39) 39 39
webkit edit → server holds our heads (40 tabs) 320 ms (299–342) 338 ms (326–342) +6%
webkit …server confirmed every edit (40 tabs) ok ok
webkit …longest main-thread stall in tab 0 during the edits 61 ms (58–80) 69 ms (67–78) +13%
webkit sync rounds per sibling edit, non-editing tab 0 0
webkit server bytes received per edit per tab – –
webkit storage writes (saveBatch) per edit per tab – –
webkit worker errors (40 tabs) – –
webkit a fresh tab finds a closed tab's doc (no server) ok ok
webkit …time to find it, from storage 51 ms (48–65) 59 ms (48–68) +16%
webkit …and every edit made before the close is in it ok ok
webkit edits from tabs closed right after editing all survive ok ok
webkit …or at least 5s later ok ok
webkit find a doc another tab just created 37 ms (36–38) 37 ms (35–38) +1%
webkit …and every such find() succeeded within 5s ok ok
webkit …finds that settled unavailable first (of 2) 0 0
webkit edit → seen in 2 other tabs 11 ms (11–12) 12 ms (11–12) +5%
webkit …every edit reached every other tab within 5s ok ok
webkit edit → server holds our heads 155 ms (154–157) 155 ms (154–161)
webkit …the server confirmed every edit within 5s 2/3 ok ok fixed
webkit …and a stranger gets the whole doc from the server ok ok

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

✅ Patchwork glance ready

https://patchwork-preview-465.patchwork.inkandswitch.com

A peek at inkandswitch/patchwork.inkandswitch.com, built with the @inkandswitch/patchwork- packages as of this PR at 279607e.

accidental commit
@chee
chee requested review from paulsonnentag and pvh and a balanced review from Copilot October 27, 2026 05:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Fallback ranking mishandles equally close supertypes, and datatype registration can fail to mount the appropriate tool.

3 open issues
What changed in this PR

Adds datatype conformance so Patchwork documents can use tools for their parent types, including transitive relationships.

Changes:

  • Introduces conformsTo metadata and getSupertypes.
  • Extends tool matching and fallback selection to include supertypes.
  • Updates legacy views to react to datatype registration, with integration tests and a changeset.
File Description
core/​plugins/​src/​tools.ts Adds supertype-aware tool matching and fallback ranking.
core/​plugins/​src/​datatypes.ts Defines conformance metadata and cycle-safe supertype traversal.
core/​elements/​test/​patchwork-view.test.ts Tests supertype selection and late datatype registration.
core/​elements/​src/​legacy-impl.ts Updates fallback handling for conformance and registration events.
.changeset/​datatype-conforms-to.md Records patch releases and describes the new behavior.

Review effort: Balanced

if (!type) return;
if (added.id != type && !getSupertypes(type).includes(added.id)) return;
const fallback = getFallbackTool(this.#handle.doc());
if (!fallback || fallback.id == this.#fallbackId) return;
Comment on lines +434 to +437
this.#fallbackId = fallback.id;
if (!fallback.module) {
// The "loaded" listener mounts it once it's in.
if (isLoadablePlugin(fallback)) toolRegistry.load(fallback.id);
Comment thread core/plugins/src/tools.ts
Comment on lines +71 to +72
const index = types.findIndex((type) => datatypes.includes(type));
if (index >= 0) return index;

This branch has not been deployed

No deployments
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