Skip to content

add conformsTo to datatypes like uttype - #465

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

chee wants to merge 3 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

6a71295 against main at 14a88bd, 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.

Nothing changed by more than the runs vary.

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) 275 ms (274–282) 279 ms (274–285) +1%
chromium boot → server connected, first tab (1 tabs) 574 ms (568–583) 581 ms (574–587) +1%
chromium renderer memory, all tabs + workers (1 tabs) 360 MB (360–363) 362 MB (349–362) +1%
chromium renderer processes (1 tabs) 3 3
chromium boot → repo, first tab (3 tabs) 283 ms (272–290) 274 ms (263–275) −3%
chromium boot → repo, last tab (3 tabs) 207 ms (202–220) 195 ms (195–199) −6%
chromium boot → server connected, first tab (3 tabs) 607 ms (595–628) 602 ms (601–609) −1%
chromium renderer memory, all tabs + workers (3 tabs) 694 MB (690–709) 691 MB (689–692) −0%
chromium renderer processes (3 tabs) 5 5
chromium boot → repo, first tab (10 tabs) 282 ms (251–293) 268 ms (267–279) −5%
chromium boot → repo, last tab (10 tabs) 212 ms (208–212) 210 ms (198–210) −1%
chromium boot → server connected, first tab (10 tabs) 612 ms (580–627) 595 ms (582–601) −3%
chromium renderer memory, all tabs + workers (10 tabs) 1828 MB (1816–1832) 1826 MB (1825–1866) −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 200 ms (194–203) 202 ms (202–204) +1%
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 738 ms (726–776) 748 ms (741–759) +1%
chromium boot → doc open, tab 2 369 ms (358–392) 372 ms (366–374) +1%
chromium boot → doc open, tab 10 325 ms (315–326) 334 ms (319–383) +3%
chromium open 40 tabs, wall clock 10067 ms (10065–10128) 10005 ms (9964–11672) −1%
chromium boot → repo, last of 40 tabs 79 ms (77–85) 72 ms (71–92) −9%
chromium boot → linked, last of 40 tabs – –
chromium boot → server connected, last of 40 tabs 502 ms (502–508) 519 ms (497–556) +3%
chromium renderer memory, 40 tabs 7062 MB (7053–7077) 7069 MB (7046–7091) +0%
chromium renderer processes, 40 tabs 42 42
chromium 39 tabs find the doc: median 900 ms (832–904) 739 ms (692–875) −18%
chromium 39 tabs find the doc: slowest 1003 ms (946–1040) 1045 ms (982–1092) +4%
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 59 ms (59–60) 55 ms (53–65) −7%
chromium edit → seen in 39 tabs: slowest tab 144 ms (131–149) 137 ms (131–156) −5%
chromium …tabs that saw every edit (of 39) 39 39
chromium edit → server holds our heads (40 tabs) 221 ms (217–229) 209 ms (204–227) −5%
chromium …server confirmed every edit (40 tabs) ok ok
chromium …longest main-thread stall in tab 0 during the edits 40 ms (16–55) 28 ms (16–29) −30%
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 50 ms (38–52) 52 ms (50–59) +4%
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 56 ms (51–59) 56 ms (52–57) −1%
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 7 ms (7–8) 7 ms (7–7) −1%
chromium …every edit reached every other tab within 5s ok ok
chromium edit → server holds our heads 158 ms (145–159) 159 ms (158–160) +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 350 MB (349–352) 351 MB (348–351) +0%
chromium renderer memory, 10 tabs 1819 MB (1810–1822) 1816 MB (1807–1817) −0%
firefox boot → repo, first tab (1 tabs) 498 ms (497–512) 496 ms (485–536) −0%
firefox boot → server connected, first tab (1 tabs) 916 ms (908–999) 964 ms (923–971) +5%
firefox renderer memory, all tabs + workers (1 tabs) – –
firefox renderer processes (1 tabs) – –
firefox boot → repo, first tab (3 tabs) 494 ms (487–508) 503 ms (490–548) +2%
firefox boot → repo, last tab (3 tabs) 352 ms (351–376) 367 ms (346–367) +4%
firefox boot → server connected, first tab (3 tabs) 949 ms (923–1062) 977 ms (923–1051) +3%
firefox renderer memory, all tabs + workers (3 tabs) – –
firefox renderer processes (3 tabs) – –
firefox boot → repo, first tab (10 tabs) 543 ms (493–571) 495 ms (486–503) −9%
firefox boot → repo, last tab (10 tabs) 373 ms (343–392) 356 ms (355–363) −5%
firefox boot → server connected, first tab (10 tabs) 1085 ms (964–1121) 1049 ms (1025–1161) −3%
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 170 ms (169–180) 172 ms (167–175) +1%
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 1034 ms (996–1043) 1051 ms (1048–1067) +2%
firefox boot → doc open, tab 2 447 ms (442–458) 468 ms (461–599) +5%
firefox boot → doc open, tab 10 433 ms (418–436) 431 ms (405–686) −1%
firefox open 40 tabs, wall clock 23739 ms (22631–24705) 24382 ms (23775–29068) +3%
firefox boot → repo, last of 40 tabs 182 ms (161–221) 162 ms (154–201) −11%
firefox boot → linked, last of 40 tabs – –
firefox boot → server connected, last of 40 tabs 639 ms (609–735) 749 ms (597–751) +17%
firefox renderer memory, 40 tabs – –
firefox renderer processes, 40 tabs – –
firefox 39 tabs find the doc: median 373 ms (342–383) 364 ms (347–366) −2%
firefox 39 tabs find the doc: slowest 377 ms (354–395) 374 ms (355–381) −1%
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 105 ms (104–108) 107 ms (106–125) +2%
firefox edit → seen in 39 tabs: slowest tab 180 ms (175–181) 191 ms (182–224) +6%
firefox …tabs that saw every edit (of 39) 39 39
firefox edit → server holds our heads (40 tabs) 327 ms (321–340) 339 ms (331–369) +4%
firefox …server confirmed every edit (40 tabs) ok ok
firefox …longest main-thread stall in tab 0 during the edits 111 ms (104–131) 118 ms (109–147) +6%
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 27 ms (23–27) 23 ms (21–25) −15%
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 28 ms (27–29) 28 ms (27–29) −1%
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 14 ms (14–15) 15 ms (14–15) +3%
firefox …every edit reached every other tab within 5s ok ok
firefox edit → server holds our heads 126 ms (126–130) 126 ms (126–127) +0%
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) 337 ms (323–462) 330 ms (323–391) −2%
webkit boot → server connected, first tab (1 tabs) 558 ms (542–695) 549 ms (538–612) −2%
webkit renderer memory, all tabs + workers (1 tabs) – –
webkit renderer processes (1 tabs) – –
webkit boot → repo, first tab (3 tabs) 334 ms (334–352) 347 ms (337–356) +4%
webkit boot → repo, last tab (3 tabs) 258 ms (240–271) 260 ms (258–283) +1%
webkit boot → server connected, first tab (3 tabs) 523 ms (518–587) 549 ms (530–579) +5%
webkit renderer memory, all tabs + workers (3 tabs) – –
webkit renderer processes (3 tabs) – –
webkit boot → repo, first tab (10 tabs) 307 ms (305–338) 340 ms (321–345) +11%
webkit boot → repo, last tab (10 tabs) 254 ms (243–273) 276 ms (236–287) +9%
webkit boot → server connected, first tab (10 tabs) 504 ms (503–535) 537 ms (500–549) +7%
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 130 ms (124–136) 122 ms (116–139) −6%
webkit server link seen down while offline ok ok
webkit …and the server did not see the offline edits ok ok
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 601 ms (577–629) 630 ms (623–714) +5%
webkit boot → doc open, tab 2 343 ms (309–361) 338 ms (331–340) −1%
webkit boot → doc open, tab 10 340 ms (331–363) 370 ms (349–372) +9%
webkit open 40 tabs, wall clock 23201 ms (22158–23248) 23112 ms (22531–23912) −0%
webkit boot → repo, last of 40 tabs 132 ms (128–138) 141 ms (134–146) +7%
webkit boot → linked, last of 40 tabs – –
webkit boot → server connected, last of 40 tabs 461 ms (459–509) 475 ms (458–494) +3%
webkit renderer memory, 40 tabs – –
webkit renderer processes, 40 tabs – –
webkit 39 tabs find the doc: median 384 ms (343–505) 497 ms (458–531) +29%
webkit 39 tabs find the doc: slowest 604 ms (600–618) 614 ms (596–685) +2%
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 71 ms (68–75) 84 ms (69–86) +18%
webkit edit → seen in 39 tabs: slowest tab 239 ms (179–247) 188 ms (172–220) −21%
webkit …tabs that saw every edit (of 39) 39 39
webkit edit → server holds our heads (40 tabs) 273 ms (260–277) 276 ms (272–286) +1%
webkit …server confirmed every edit (40 tabs) ok ok
webkit …longest main-thread stall in tab 0 during the edits 68 ms (60–84) 90 ms (35–144) +32%
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 54 ms (38–55) 49 ms (41–68) −9%
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 32 ms (27–35) 29 ms (28–34) −8%
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 10 ms (9–10) 11 ms (9–12) +15%
webkit …every edit reached every other tab within 5s ok ok
webkit edit → server holds our heads 94 ms (94–94) 93 ms (89–105) −1%
webkit …the server confirmed every edit within 5s ok ok
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 6a71295.

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.

3 participants