From 4cd338a8b4d4e4acf3fc1f4e48cf94ac7596e5ea Mon Sep 17 00:00:00 2001 From: clover caruso Date: Tue, 8 Sep 2026 03:14:00 -0700 Subject: [PATCH] feat: reconcile durable offline paragraph splits and joins Retain allocated split identities and observed paragraph structure through queue reopen, boundary rebasing and explicit conflict review. Preserve uncertain publication evidence and migrate existing cache receipts and operation ordering to schema 6. Validate dependent edits and structural conflicts with production SQLite replicas, fault schedules and native OneNote keyboard controls. Cold reopening verifies 32 operations across 38 pages; the public gate passes 192 Rust tests, 8 doctests and 131 Python tests. Add a twelve-replica stateful ASan target. Assisted-by: gpt-6-astra --- corpus/paragraph-edit/README.md | 8 + .../inheritance/candidate/synthetic.one | Bin 0 -> 59016 bytes .../offline/inheritance/manifest.json | 62 +++ .../native/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../inheritance/native/notebook/synthetic.one | Bin 0 -> 61448 bytes .../inheritance/native/read/environment.json | 7 + .../inheritance/native/read/hierarchy.xml | 2 + .../inheritance/native/read/page-000.xml | 5 + .../inheritance/native/read/page-001.xml | 5 + .../inheritance/native/read/page-002.xml | 20 + .../inheritance/native/read/page-003.xml | 5 + .../inheritance/native/read/page-004.xml | 5 + .../inheritance/native/read/page-005.xml | 5 + .../inheritance/native/read/payloads.json | 1 + .../offline/inheritance/native/run.json | 18 + .../offline/inheritance/native/source.json | 8 + .../offline/inheritance/native/teardown.json | 1 + .../offline/joins/candidate/synthetic.one | Bin 0 -> 150648 bytes .../offline/joins/manifest.json | 146 +++++ .../native/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../joins/native/notebook/synthetic.one | Bin 0 -> 150648 bytes .../joins/native/read/environment.json | 7 + .../offline/joins/native/read/hierarchy.xml | 2 + .../offline/joins/native/read/page-000.xml | 5 + .../offline/joins/native/read/page-001.xml | 3 + .../offline/joins/native/read/page-002.xml | 2 + .../offline/joins/native/read/page-003.xml | 5 + .../offline/joins/native/read/page-004.xml | 5 + .../offline/joins/native/read/page-005.xml | 6 + .../offline/joins/native/read/page-006.xml | 5 + .../offline/joins/native/read/page-007.xml | 5 + .../offline/joins/native/read/page-008.xml | 20 + .../offline/joins/native/read/page-009.xml | 5 + .../offline/joins/native/read/page-010.xml | 3 + .../offline/joins/native/read/page-011.xml | 5 + .../offline/joins/native/read/page-012.xml | 5 + .../offline/joins/native/read/page-013.xml | 5 + .../offline/joins/native/read/payloads.json | 1 + .../offline/joins/native/run.json | 18 + .../offline/joins/native/source.json | 8 + .../offline/joins/native/teardown.json | 1 + .../offline/splits/candidate/synthetic.one | Bin 0 -> 119736 bytes .../offline/splits/manifest.json | 374 +++++++++++++ .../native/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../splits/native/notebook/synthetic.one | Bin 0 -> 119736 bytes .../splits/native/read/environment.json | 7 + .../offline/splits/native/read/hierarchy.xml | 2 + .../offline/splits/native/read/page-000.xml | 3 + .../offline/splits/native/read/page-001.xml | 5 + .../offline/splits/native/read/page-002.xml | 6 + .../offline/splits/native/read/page-003.xml | 2 + .../offline/splits/native/read/page-004.xml | 5 + .../offline/splits/native/read/page-005.xml | 6 + .../offline/splits/native/read/page-006.xml | 6 + .../offline/splits/native/read/page-007.xml | 6 + .../offline/splits/native/read/page-008.xml | 5 + .../offline/splits/native/read/page-009.xml | 6 + .../offline/splits/native/read/page-010.xml | 6 + .../offline/splits/native/read/page-011.xml | 3 + .../offline/splits/native/read/page-012.xml | 20 + .../offline/splits/native/read/page-013.xml | 6 + .../offline/splits/native/read/payloads.json | 1 + .../offline/splits/native/run.json | 18 + .../offline/splits/native/source.json | 8 + .../offline/splits/native/teardown.json | 1 + .../offline/tags/candidate/synthetic.one | Bin 0 -> 42688 bytes .../paragraph-edit/offline/tags/manifest.json | 38 ++ .../native/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../tags/native/notebook/synthetic.one | Bin 0 -> 44792 bytes .../offline/tags/native/read/environment.json | 7 + .../offline/tags/native/read/hierarchy.xml | 2 + .../offline/tags/native/read/page-000.xml | 20 + .../offline/tags/native/read/page-001.xml | 5 + .../offline/tags/native/read/page-002.xml | 5 + .../offline/tags/native/read/page-003.xml | 5 + .../offline/tags/native/read/payloads.json | 1 + .../offline/tags/native/run.json | 18 + .../offline/tags/native/source.json | 8 + .../offline/tags/native/teardown.json | 1 + crates/onestore-offline/README.md | 29 +- .../onestore-offline/examples/cache_probe.rs | 3 + crates/onestore-offline/src/lib.rs | 6 +- crates/onestore-offline/src/paragraph.rs | 241 ++++++++ crates/onestore-offline/src/schema.rs | 12 +- crates/onestore-offline/src/sync.rs | 45 +- crates/onestore-offline/tests/cache.rs | 123 +++- crates/onestore-offline/tests/sync.rs | 524 +++++++++++++++++- crates/onestore/README.md | 5 +- crates/onestore/src/paragraph.rs | 18 + fuzz/Cargo.lock | 303 ++++++++++ fuzz/Cargo.toml | 9 + fuzz/fuzz_targets/offline_paragraph.rs | 165 ++++++ tools/test_paragraph_edit.py | 71 ++- 93 files changed, 2534 insertions(+), 40 deletions(-) create mode 100644 corpus/paragraph-edit/offline/inheritance/candidate/synthetic.one create mode 100644 corpus/paragraph-edit/offline/inheritance/manifest.json create mode 100644 corpus/paragraph-edit/offline/inheritance/native/notebook/Open Notebook.onetoc2 create mode 100644 corpus/paragraph-edit/offline/inheritance/native/notebook/synthetic.one create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/environment.json create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/hierarchy.xml create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/page-000.xml create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/page-001.xml create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/page-002.xml create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/page-003.xml create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/page-004.xml create mode 100644 corpus/paragraph-edit/offline/inheritance/native/read/page-005.xml create mode 120000 corpus/paragraph-edit/offline/inheritance/native/read/payloads.json create mode 100644 corpus/paragraph-edit/offline/inheritance/native/run.json create mode 100644 corpus/paragraph-edit/offline/inheritance/native/source.json create mode 120000 corpus/paragraph-edit/offline/inheritance/native/teardown.json create mode 100644 corpus/paragraph-edit/offline/joins/candidate/synthetic.one create mode 100644 corpus/paragraph-edit/offline/joins/manifest.json create mode 100644 corpus/paragraph-edit/offline/joins/native/notebook/Open Notebook.onetoc2 create mode 100644 corpus/paragraph-edit/offline/joins/native/notebook/synthetic.one create mode 100644 corpus/paragraph-edit/offline/joins/native/read/environment.json create mode 100644 corpus/paragraph-edit/offline/joins/native/read/hierarchy.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-000.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-001.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-002.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-003.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-004.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-005.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-006.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-007.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-008.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-009.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-010.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-011.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-012.xml create mode 100644 corpus/paragraph-edit/offline/joins/native/read/page-013.xml create mode 120000 corpus/paragraph-edit/offline/joins/native/read/payloads.json create mode 100644 corpus/paragraph-edit/offline/joins/native/run.json create mode 100644 corpus/paragraph-edit/offline/joins/native/source.json create mode 120000 corpus/paragraph-edit/offline/joins/native/teardown.json create mode 100644 corpus/paragraph-edit/offline/splits/candidate/synthetic.one create mode 100644 corpus/paragraph-edit/offline/splits/manifest.json create mode 100644 corpus/paragraph-edit/offline/splits/native/notebook/Open Notebook.onetoc2 create mode 100644 corpus/paragraph-edit/offline/splits/native/notebook/synthetic.one create mode 100644 corpus/paragraph-edit/offline/splits/native/read/environment.json create mode 100644 corpus/paragraph-edit/offline/splits/native/read/hierarchy.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-000.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-001.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-002.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-003.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-004.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-005.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-006.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-007.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-008.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-009.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-010.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-011.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-012.xml create mode 100644 corpus/paragraph-edit/offline/splits/native/read/page-013.xml create mode 120000 corpus/paragraph-edit/offline/splits/native/read/payloads.json create mode 100644 corpus/paragraph-edit/offline/splits/native/run.json create mode 100644 corpus/paragraph-edit/offline/splits/native/source.json create mode 120000 corpus/paragraph-edit/offline/splits/native/teardown.json create mode 100644 corpus/paragraph-edit/offline/tags/candidate/synthetic.one create mode 100644 corpus/paragraph-edit/offline/tags/manifest.json create mode 100644 corpus/paragraph-edit/offline/tags/native/notebook/Open Notebook.onetoc2 create mode 100644 corpus/paragraph-edit/offline/tags/native/notebook/synthetic.one create mode 100644 corpus/paragraph-edit/offline/tags/native/read/environment.json create mode 100644 corpus/paragraph-edit/offline/tags/native/read/hierarchy.xml create mode 100644 corpus/paragraph-edit/offline/tags/native/read/page-000.xml create mode 100644 corpus/paragraph-edit/offline/tags/native/read/page-001.xml create mode 100644 corpus/paragraph-edit/offline/tags/native/read/page-002.xml create mode 100644 corpus/paragraph-edit/offline/tags/native/read/page-003.xml create mode 120000 corpus/paragraph-edit/offline/tags/native/read/payloads.json create mode 100644 corpus/paragraph-edit/offline/tags/native/run.json create mode 100644 corpus/paragraph-edit/offline/tags/native/source.json create mode 120000 corpus/paragraph-edit/offline/tags/native/teardown.json create mode 100644 crates/onestore-offline/src/paragraph.rs create mode 100644 fuzz/fuzz_targets/offline_paragraph.rs diff --git a/corpus/paragraph-edit/README.md b/corpus/paragraph-edit/README.md index 162562834f34293f17959d97333e96bee9d54e71..a8ed082d25ee9a53dda45247767161dabf90562a 100644 --- a/corpus/paragraph-edit/README.md +++ b/corpus/paragraph-edit/README.md @@ -60,3 +60,11 @@ XML, preserve exact child/content identities across reopening, and compare the native-rendered result to the corresponding keyboard-generated control. `export_native_paragraph_joins` regenerates candidates in a new directory specified by `ONESTORE_PARAGRAPH_JOIN_OUTPUT`. + +`offline` retains reconciled split/join candidates and cold native captures. +The cache queues edits before observing independent remote `☂` prefixes, reopens +between acknowledgements, and confirms modeled lost replies without replaying +operations. Tests compare native text/styles to the original keyboard controls, +account for the remote prefixes, and retain exact graph identities after reopening. +The ignored offline test `export_native_offline_paragraphs` regenerates candidates +in a new directory specified by `ONESTORE_OFFLINE_PARAGRAPH_OUTPUT`. diff --git a/corpus/paragraph-edit/offline/inheritance/candidate/synthetic.one b/corpus/paragraph-edit/offline/inheritance/candidate/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..e64cafc0ec2e467c73f2709679fe0acfda707323 GIT binary patch literal 59016 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 literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/inheritance/manifest.json b/corpus/paragraph-edit/offline/inheritance/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..8905aa0adf6878941da6efe2ffbf7aebf840af61 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/manifest.json @@ -0,0 +1,62 @@ +[ + { + "case": "Join inherited styles", + "id": 1, + "intent": { + "author": "Rust join author", + "left": "{10952FC5-A849-0DE5-03A7-5D9304627DA7},44", + "right": "{10952FC5-A849-0DE5-03A7-5D9304627DA7},50" + }, + "remote_prefix": true, + "revision": "{E109048E-057D-41DC-B2A8-B9F11839B9C9},1", + "space": "{D6CEB12D-D1B7-033B-20A2-E9B6FF501602},1" + }, + { + "case": "Join empty left tag", + "id": 2, + "intent": { + "author": "Rust join author", + "left": "{8BAFC64A-8457-0253-3906-57D27F8546B7},45", + "right": "{8BAFC64A-8457-0253-3906-57D27F8546B7},51" + }, + "remote_prefix": false, + "revision": "{19A52AE8-D897-467C-956F-26CA42CEDA1B},1", + "space": "{F6E7A6F0-805F-0858-2B5A-4B1260940CF9},1" + }, + { + "case": "Join right tag", + "id": 3, + "intent": { + "author": "Rust join author", + "left": "{2E9A20A9-1E0E-0F04-0FCE-8497CF032068},44", + "right": "{2E9A20A9-1E0E-0F04-0FCE-8497CF032068},49" + }, + "remote_prefix": true, + "revision": "{BDDFFFE4-439A-4466-9D85-20B88D5A5E61},1", + "space": "{04EE80E5-584B-04E0-1F05-07D86902DFA1},1" + }, + { + "case": "Join both tags", + "id": 4, + "intent": { + "author": "Rust join author", + "left": "{7A5195E3-F792-0C49-1F3C-EBBFCE774FE6},44", + "right": "{7A5195E3-F792-0C49-1F3C-EBBFCE774FE6},50" + }, + "remote_prefix": true, + "revision": "{694A9A93-E1AA-48DD-AD67-6BD2C0EF5D6F},1", + "space": "{631A0B54-DBB1-0988-22E1-96E8B1202B59},1" + }, + { + "case": "Join both children", + "id": 5, + "intent": { + "author": "Rust join author", + "left": "{0384F5F6-5F0B-0164-32C6-6E97A4F1B661},49", + "right": "{0384F5F6-5F0B-0164-32C6-6E97A4F1B661},54" + }, + "remote_prefix": true, + "revision": "{B3100F21-58B5-4417-9797-B397AC0F7BE3},1", + "space": "{D7D982D1-A3D3-0690-1181-A9703CF717E5},1" + } +] \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/inheritance/native/notebook/Open Notebook.onetoc2 b/corpus/paragraph-edit/offline/inheritance/native/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..8ecc576e8f13a07ffe261f2fdbe028a37cb11351 GIT binary patch literal 4800 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 literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/environment.json b/corpus/paragraph-edit/offline/inheritance/native/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..9ce6d758f071c4bb49737eb8104c0ee15ce86363 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-6061365E", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/hierarchy.xml b/corpus/paragraph-edit/offline/inheritance/native/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..92079e1969cd7a99c75f19db52f7e085a591b431 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/page-000.xml b/corpus/paragraph-edit/offline/inheritance/native/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ec799793802bacdd3ab47100a46821273f490bd --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/page-000.xml @@ -0,0 +1,5 @@ + +☂LeftBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/page-001.xml b/corpus/paragraph-edit/offline/inheritance/native/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..e7da941a9f1ab49daedf6b4599443ae39a0269b6 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/page-001.xml @@ -0,0 +1,5 @@ + +☂LeftBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/page-002.xml b/corpus/paragraph-edit/offline/inheritance/native/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f7ebac7baae2c38efceca18ccd5d33d6fa668e9 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/page-002.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/page-003.xml b/corpus/paragraph-edit/offline/inheritance/native/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..b4d1f59c82406908740081c4710a489002085ac2 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/page-003.xml @@ -0,0 +1,5 @@ + +☂LeftRight italic]]> diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/page-004.xml b/corpus/paragraph-edit/offline/inheritance/native/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f7e50d49be4739acae06d0e4fb7c70663d60644 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/page-004.xml @@ -0,0 +1,5 @@ + +☂Left childBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/page-005.xml b/corpus/paragraph-edit/offline/inheritance/native/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..82c73e5a1daf3735d8e9a40de6251a3f839b6a89 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/page-005.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/inheritance/native/read/payloads.json b/corpus/paragraph-edit/offline/inheritance/native/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..787b4bae85038cda922f8befac6c8ed361fa8035 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/read/payloads.json @@ -0,0 +1 @@ +../../../../before/read/payloads.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/inheritance/native/run.json b/corpus/paragraph-edit/offline/inheritance/native/run.json new file mode 100644 index 0000000000000000000000000000000000000000..2fbf78ac8b624e29cbc1ef5a140dc7bb0c388002 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-paragraph-native-01/inheritance/candidate", + "expected_pages": 6, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/paragraph-edit/offline/inheritance/native/source.json b/corpus/paragraph-edit/offline/inheritance/native/source.json new file mode 100644 index 0000000000000000000000000000000000000000..02e8e0326bf665e52ba695484dafd587f263b7c0 --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 59016, + "sha256": "828e330b0dfda41ecd5ade77ea65398cf5a070170757b3f650ca4600520d99bb", + "mtime_ns": 1788863184799153800 + } +] diff --git a/corpus/paragraph-edit/offline/inheritance/native/teardown.json b/corpus/paragraph-edit/offline/inheritance/native/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..47a1192a30ea7da90676d631bb9a2687d829b43e --- /dev/null +++ b/corpus/paragraph-edit/offline/inheritance/native/teardown.json @@ -0,0 +1 @@ +../../../joined/teardown.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/joins/candidate/synthetic.one b/corpus/paragraph-edit/offline/joins/candidate/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..b3fefe96ad2e3c9de97a136f760b521bcb11bda4 GIT binary patch literal 150648 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 Gr+)#gu<()q literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/joins/manifest.json b/corpus/paragraph-edit/offline/joins/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..9931ce4a575276ec439d92ff937a49dfcf9b79f1 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/manifest.json @@ -0,0 +1,146 @@ +[ + { + "case": "Split middle", + "id": 1, + "intent": { + "author": "Rust join author", + "left": "{DFE950EF-6BEB-0F5B-2403-7B74F1AE5002},44", + "right": "{0BA342F5-0690-087C-24FE-8EE6D81C2041},12" + }, + "remote_prefix": true, + "revision": "{D3E40C30-D3F7-48FC-8163-10191C9874A2},1", + "space": "{FE224563-B517-023E-0D75-9904B1952A26},1" + }, + { + "case": "Split style boundary", + "id": 2, + "intent": { + "author": "Rust join author", + "left": "{5FB484E2-1E3E-0A9D-1989-271A3EBBEC42},44", + "right": "{051BC1DE-5AE6-0D04-0CEF-9D05F53C8EAE},12" + }, + "remote_prefix": true, + "revision": "{B4AD652D-1152-4BFB-9F7C-3F5A37D526CC},1", + "space": "{DED48A05-0DB1-0712-086D-09237C982341},1" + }, + { + "case": "Split start", + "id": 3, + "intent": { + "author": "Rust join author", + "left": "{012ED94B-43B3-079A-3050-B1CBE25C1C09},44", + "right": "{B230A510-9428-0CE7-1B89-7CA970F8F676},12" + }, + "remote_prefix": false, + "revision": "{14C83ACF-0D2F-4D6C-8A85-D4B883407F57},1", + "space": "{7919E933-0809-00D8-1754-A21684215860},1" + }, + { + "case": "Split end", + "id": 4, + "intent": { + "author": "Rust join author", + "left": "{DAF723A3-C2A3-0798-2EAB-34613166A794},44", + "right": "{601DAE0A-2A53-0C28-3077-1FE8FCB26FC2},12" + }, + "remote_prefix": true, + "revision": "{BAE72407-55A9-4703-922B-67E6B8ADE435},1", + "space": "{927F2809-173C-036E-37B6-60A6568F7723},1" + }, + { + "case": "Split empty", + "id": 5, + "intent": { + "author": "Rust join author", + "left": "{0B467F31-D287-08CD-09F4-A6FBB2F5418F},45", + "right": "{EACB4A2C-2444-0A1F-03D6-68187F2FB345},12" + }, + "remote_prefix": false, + "revision": "{28937B4C-67BC-4ED8-A531-E63A6FB99F38},1", + "space": "{E4D8C4CC-508B-04D2-36CE-C5B8C9D2FEC4},1" + }, + { + "case": "Split parent", + "id": 6, + "intent": { + "author": "Rust join author", + "left": "{3860EA13-D444-0598-35D6-CF96769C6A21},44", + "right": "{C84CA5DB-61A8-0F9B-3F91-D6E0C74536F7},12" + }, + "remote_prefix": true, + "revision": "{E154B8F7-C84E-4AED-B436-D610448E37F1},1", + "space": "{7A363D4C-73C2-0ABE-0931-E6F62A90B95E},1" + }, + { + "case": "Split child", + "id": 7, + "intent": { + "author": "Rust join author", + "left": "{B587CBC6-0BCC-0A23-16F6-E1B0B3C5D061},49", + "right": "{DC240C63-FC8E-0267-0AFD-A53062C25702},12" + }, + "remote_prefix": true, + "revision": "{01D54762-D53E-4DF2-AD44-7789FAE785CE},1", + "space": "{3CC2C4DC-651A-07C9-2F7B-375C6663F3CA},1" + }, + { + "case": "Split bullet", + "id": 8, + "intent": { + "author": "Rust join author", + "left": "{8C65E427-477C-02ED-1807-2F10E277019D},44", + "right": "{28F3F5EC-E687-02CA-2CFD-E73A184B875F},12" + }, + "remote_prefix": true, + "revision": "{BE53841B-A5D6-447A-B1F3-C1E2D11EBBCE},1", + "space": "{942EF5E4-FFD1-0FE4-23D2-7429899577BD},1" + }, + { + "case": "Split number", + "id": 9, + "intent": { + "author": "Rust join author", + "left": "{D4ABBE4F-2165-0122-1F9F-ACE3FE92C703},44", + "right": "{DD3FA0E7-15A6-01C4-1B77-F85F779BCBC8},12" + }, + "remote_prefix": true, + "revision": "{53CAB283-B0D5-4D3A-B325-9FD8B214FE21},1", + "space": "{A4AE40FF-DD80-0003-2856-17D8295C1B91},1" + }, + { + "case": "Split tag", + "id": 10, + "intent": { + "author": "Rust join author", + "left": "{37AA5877-2980-0227-169F-8B1E8EE0795A},44", + "right": "{1480427A-E9ED-04EC-0409-0653AE11FF78},12" + }, + "remote_prefix": true, + "revision": "{BC2C9E0D-BA56-48ED-8510-CFBF7FCBDEED},1", + "space": "{739DB38B-4239-0A7C-2652-4E525D219638},1" + }, + { + "case": "Split cell", + "id": 11, + "intent": { + "author": "Rust join author", + "left": "{F0832BC9-1578-0A96-08AF-99344644FFB8},50", + "right": "{1E353497-5C26-0459-3C0C-0E8D29ED8C5A},12" + }, + "remote_prefix": true, + "revision": "{392FD304-233C-4A9C-A90E-16EA8F916073},1", + "space": "{4432E3EC-5E5F-0A04-2108-E9A2C17BDBEC},1" + }, + { + "case": "Split soft break", + "id": 12, + "intent": { + "author": "Rust join author", + "left": "{88189BA1-2F19-0282-05ED-A0B83153F143},44", + "right": "{C1568E82-003F-016B-041A-CA304E1A5138},12" + }, + "remote_prefix": true, + "revision": "{D3D41323-E06E-4253-BAA5-B69A3AAA40E5},1", + "space": "{D8E15673-A45E-0914-291A-7767C3222F19},1" + } +] \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/joins/native/notebook/Open Notebook.onetoc2 b/corpus/paragraph-edit/offline/joins/native/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..dbc25757edc4679de12642bd8cb897bfff94488f GIT binary patch literal 4800 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 H literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/joins/native/read/environment.json b/corpus/paragraph-edit/offline/joins/native/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..552ef9a6189225c2022dccd1e57702c7939ff4da --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-37FF299E", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/paragraph-edit/offline/joins/native/read/hierarchy.xml b/corpus/paragraph-edit/offline/joins/native/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a5218400d4c87069f2b31b2c580618a7d756a3d --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-000.xml b/corpus/paragraph-edit/offline/joins/native/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..9201082b94066f46a988d536c2ef7494840dfbf2 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-000.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-001.xml b/corpus/paragraph-edit/offline/joins/native/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..62fe84b91cb277cec1462d1a02afd2446f6dee21 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-001.xml @@ -0,0 +1,3 @@ + + +soft break]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-002.xml b/corpus/paragraph-edit/offline/joins/native/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..bf17bb70560f2566974524307321791177e331a1 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-002.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-003.xml b/corpus/paragraph-edit/offline/joins/native/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..adec3d788188349daf59a08d4d872658c04ef724 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-003.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-004.xml b/corpus/paragraph-edit/offline/joins/native/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..fe7660933a9e562a29e298825fb22266375d80c8 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-004.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-005.xml b/corpus/paragraph-edit/offline/joins/native/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..4227be5eb03a241bf6ce0dfe0fbb1ece9965dade --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-005.xml @@ -0,0 +1,6 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-006.xml b/corpus/paragraph-edit/offline/joins/native/read/page-006.xml new file mode 100644 index 0000000000000000000000000000000000000000..167287870795f4b510eebf42241cafb673ad0940 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-006.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-007.xml b/corpus/paragraph-edit/offline/joins/native/read/page-007.xml new file mode 100644 index 0000000000000000000000000000000000000000..402252d7c06456b9a4f6d4461f03bcbd71640661 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-007.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-008.xml b/corpus/paragraph-edit/offline/joins/native/read/page-008.xml new file mode 100644 index 0000000000000000000000000000000000000000..552b927b47f79cfc1a3d1cd2e2b46c2c79adcff7 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-008.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-009.xml b/corpus/paragraph-edit/offline/joins/native/read/page-009.xml new file mode 100644 index 0000000000000000000000000000000000000000..4301ba0550eaa621005b78bc9e7aeba3f76a2f6e --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-009.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-010.xml b/corpus/paragraph-edit/offline/joins/native/read/page-010.xml new file mode 100644 index 0000000000000000000000000000000000000000..dae5fdb3cbcd6aaa85cd91b2ab029238544058b3 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-010.xml @@ -0,0 +1,3 @@ + +Link label
tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-011.xml b/corpus/paragraph-edit/offline/joins/native/read/page-011.xml new file mode 100644 index 0000000000000000000000000000000000000000..b31bc7ec4baddcf2e98da0146a56658a8ad390f8 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-011.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-012.xml b/corpus/paragraph-edit/offline/joins/native/read/page-012.xml new file mode 100644 index 0000000000000000000000000000000000000000..9fcb04f0bd3028c095bfaaab0c8cbf2add4e8c6c --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-012.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/page-013.xml b/corpus/paragraph-edit/offline/joins/native/read/page-013.xml new file mode 100644 index 0000000000000000000000000000000000000000..6dd7d0276272223468796769d7447b6b7d25fc04 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/page-013.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/joins/native/read/payloads.json b/corpus/paragraph-edit/offline/joins/native/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..787b4bae85038cda922f8befac6c8ed361fa8035 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/read/payloads.json @@ -0,0 +1 @@ +../../../../before/read/payloads.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/joins/native/run.json b/corpus/paragraph-edit/offline/joins/native/run.json new file mode 100644 index 0000000000000000000000000000000000000000..d6d739820dca141e877c521937893a9db95b9010 --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-paragraph-native-01/joins/candidate", + "expected_pages": 14, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/paragraph-edit/offline/joins/native/source.json b/corpus/paragraph-edit/offline/joins/native/source.json new file mode 100644 index 0000000000000000000000000000000000000000..699cc709a58444d4fb5d3cdaaf8e4edece01bf0c --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 150648, + "sha256": "2fd036cddb33de5e42f66cb6a6b7647cbfeac374a4055e9afc15bf3b0d6ec1b2", + "mtime_ns": 1788863184056850411 + } +] diff --git a/corpus/paragraph-edit/offline/joins/native/teardown.json b/corpus/paragraph-edit/offline/joins/native/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..47a1192a30ea7da90676d631bb9a2687d829b43e --- /dev/null +++ b/corpus/paragraph-edit/offline/joins/native/teardown.json @@ -0,0 +1 @@ +../../../joined/teardown.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/splits/candidate/synthetic.one b/corpus/paragraph-edit/offline/splits/candidate/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..66148d4f93647580dd893d2c5fcdac50745a26bb GIT binary patch literal 119736 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 C@X@gV literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/splits/manifest.json b/corpus/paragraph-edit/offline/splits/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..262dff2900ded1a50e82606439626bb8b6212703 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/manifest.json @@ -0,0 +1,374 @@ +[ + { + "case": "Split middle", + "id": 1, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 228, + 60, + 65, + 246, + 194, + 244, + 184, + 76, + 170, + 5, + 19, + 130, + 32, + 122, + 148, + 241 + ], + "offset": 2, + "text": "{DFE950EF-6BEB-0F5B-2403-7B74F1AE5002},44" + }, + "remote_prefix": true, + "revision": "{BF0EE2EB-19D1-47B7-B28D-A9ABD19EBAAE},1", + "space": "{FE224563-B517-023E-0D75-9904B1952A26},1" + }, + { + "case": "Split style boundary", + "id": 2, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 163, + 91, + 197, + 73, + 195, + 225, + 53, + 68, + 140, + 152, + 83, + 168, + 172, + 124, + 226, + 213 + ], + "offset": 4, + "text": "{5FB484E2-1E3E-0A9D-1989-271A3EBBEC42},44" + }, + "remote_prefix": true, + "revision": "{167F0C99-70D5-4B0C-8339-4A5D4FA8D101},1", + "space": "{DED48A05-0DB1-0712-086D-09237C982341},1" + }, + { + "case": "Split start", + "id": 3, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 135, + 16, + 214, + 248, + 73, + 35, + 2, + 69, + 148, + 213, + 125, + 28, + 43, + 124, + 81, + 35 + ], + "offset": 0, + "text": "{012ED94B-43B3-079A-3050-B1CBE25C1C09},44" + }, + "remote_prefix": false, + "revision": "{F45BB0FF-3E33-4039-B5DE-C436C126C52E},1", + "space": "{7919E933-0809-00D8-1754-A21684215860},1" + }, + { + "case": "Split end", + "id": 4, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 37, + 220, + 149, + 138, + 85, + 3, + 106, + 69, + 168, + 172, + 49, + 82, + 247, + 99, + 160, + 139 + ], + "offset": 22, + "text": "{DAF723A3-C2A3-0798-2EAB-34613166A794},44" + }, + "remote_prefix": true, + "revision": "{B408F227-A7DE-4350-8068-D91005E0B8E5},1", + "space": "{927F2809-173C-036E-37B6-60A6568F7723},1" + }, + { + "case": "Split empty", + "id": 5, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 232, + 204, + 91, + 132, + 180, + 27, + 239, + 79, + 158, + 115, + 213, + 165, + 40, + 35, + 189, + 93 + ], + "offset": 0, + "text": "{0B467F31-D287-08CD-09F4-A6FBB2F5418F},45" + }, + "remote_prefix": false, + "revision": "{4F8EB252-1808-40AA-9B37-DB3DE1C5C3F2},1", + "space": "{E4D8C4CC-508B-04D2-36CE-C5B8C9D2FEC4},1" + }, + { + "case": "Split parent", + "id": 6, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 54, + 186, + 114, + 171, + 44, + 189, + 95, + 71, + 135, + 190, + 71, + 95, + 23, + 246, + 37, + 157 + ], + "offset": 2, + "text": "{3860EA13-D444-0598-35D6-CF96769C6A21},44" + }, + "remote_prefix": true, + "revision": "{A291D6A6-08A8-4E06-BF29-0479851E9E12},1", + "space": "{7A363D4C-73C2-0ABE-0931-E6F62A90B95E},1" + }, + { + "case": "Split child", + "id": 7, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 160, + 247, + 235, + 152, + 30, + 98, + 166, + 77, + 157, + 204, + 141, + 45, + 114, + 151, + 225, + 195 + ], + "offset": 2, + "text": "{B587CBC6-0BCC-0A23-16F6-E1B0B3C5D061},49" + }, + "remote_prefix": true, + "revision": "{FFE1F804-FA27-4EFD-B53C-9E1D07384DA6},1", + "space": "{3CC2C4DC-651A-07C9-2F7B-375C6663F3CA},1" + }, + { + "case": "Split bullet", + "id": 8, + "intent": { + "author": "Rust split author", + "created": 1473324660, + "guid": [ + 53, + 245, + 214, + 76, + 159, + 56, + 134, + 76, + 178, + 90, + 131, + 182, + 74, + 114, + 31, + 24 + ], + "offset": 2, + "text": "{8C65E427-477C-02ED-1807-2F10E277019D},44" + }, + "remote_prefix": true, + "revision": "{822FBEAD-035E-47B5-9ED6-CDAE96AA5837},1", + "space": "{942EF5E4-FFD1-0FE4-23D2-7429899577BD},1" + }, + { + "case": "Split number", + "id": 9, + "intent": { + "author": "Rust split author", + "created": 1473324661, + "guid": [ + 196, + 133, + 251, + 251, + 193, + 175, + 8, + 65, + 175, + 180, + 126, + 16, + 31, + 185, + 237, + 66 + ], + "offset": 2, + "text": "{D4ABBE4F-2165-0122-1F9F-ACE3FE92C703},44" + }, + "remote_prefix": true, + "revision": "{F5ABC207-F9C7-45A3-B213-AA675126A592},1", + "space": "{A4AE40FF-DD80-0003-2856-17D8295C1B91},1" + }, + { + "case": "Split tag", + "id": 10, + "intent": { + "author": "Rust split author", + "created": 1473324661, + "guid": [ + 40, + 122, + 110, + 77, + 185, + 255, + 122, + 69, + 128, + 15, + 14, + 166, + 54, + 156, + 154, + 91 + ], + "offset": 2, + "text": "{37AA5877-2980-0227-169F-8B1E8EE0795A},44" + }, + "remote_prefix": true, + "revision": "{8021DAB3-4163-49C4-A7A1-898ACCAB3981},1", + "space": "{739DB38B-4239-0A7C-2652-4E525D219638},1" + }, + { + "case": "Split cell", + "id": 11, + "intent": { + "author": "Rust split author", + "created": 1473324661, + "guid": [ + 150, + 222, + 89, + 134, + 80, + 167, + 167, + 67, + 179, + 23, + 93, + 176, + 27, + 184, + 119, + 185 + ], + "offset": 2, + "text": "{F0832BC9-1578-0A96-08AF-99344644FFB8},50" + }, + "remote_prefix": true, + "revision": "{0E8285DD-840A-4C8E-BFDB-CA3589436ECD},1", + "space": "{4432E3EC-5E5F-0A04-2108-E9A2C17BDBEC},1" + }, + { + "case": "Split soft break", + "id": 12, + "intent": { + "author": "Rust split author", + "created": 1473324661, + "guid": [ + 199, + 62, + 94, + 81, + 29, + 157, + 236, + 77, + 159, + 34, + 22, + 137, + 163, + 57, + 215, + 79 + ], + "offset": 2, + "text": "{88189BA1-2F19-0282-05ED-A0B83153F143},44" + }, + "remote_prefix": true, + "revision": "{89D96DD2-2D50-433E-B54B-50018E3C2108},1", + "space": "{D8E15673-A45E-0914-291A-7767C3222F19},1" + } +] \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/splits/native/notebook/Open Notebook.onetoc2 b/corpus/paragraph-edit/offline/splits/native/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..e6462b78708e6fcff91d8fb9b4059776e8c1e932 GIT binary patch literal 4800 zcmZ3e|KIuM`!b(-j|5(YE0x7Bnk;*I@@09ab(dp(8j^pVU_b-*cV`JmPyFh+^n&=r zw;)KmcO1!UUi+OdL%Zg$q&x0$@Q7s1ys324N5Y(hwC8H3x(s!Z6Y@ z&XW5f$1jhjBCd_UH1`E^LnWN^ZbkL(b@SOCf30cjmk^jROdATlMROrPGDeXc<&1{F zFbRPpU%r3cSQWNJ0O}u(9EPb4j4B{LTUj)ie(eZKzGDpE^2#kinAPoUn{SV6DAi#s8k{6I+n7V{f1)^w} zlGw^eSopxY7$OC@8$r@98XA-zbvu5w{OUZdChA)(Yw;~mS&0o4cwIkHV}F+sBCjaY z(7>Pq40@2#bC*w8{+3(gIQ7}}2KD|e>>2_M4Lv})hBn>P{Fg+$d!**8%z7%a7^GF# zgQ52XBO|N?2A0h&DGWWx9s!vM0_!6U8X92gWPnEg7hq@r%MeW*;Dah3$5)s0UH;-Y zx%0V$mhFc!kUkk8E@r4?$YUsB$Y4kXl9>$240;UtK#^3S9LR$}3J8$n2c#1e2YaGa zW*VolyR9|KlH}y>>ja5oix+`{zqsPSN=~T$`_nG3*+~o6{c5_lToo92KvTd~A1pqk zS2XTUvG?-bCjG!hV7m8RkTszAILpWl3umAPM+1i5lZ-4}Kv`C-aZ{to@Cy_lAmc~D RXb6mk0Im=~F4kb>4**p%M)d#y literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/splits/native/notebook/synthetic.one b/corpus/paragraph-edit/offline/splits/native/notebook/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..82323b80ecdf4626a8e3d11bda99eb0013358efd GIT binary patch literal 119736 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 + diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-000.xml b/corpus/paragraph-edit/offline/splits/native/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..552bdb1a543eab002e577f984ca924481b2c0415 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-000.xml @@ -0,0 +1,3 @@ + + +soft break]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-001.xml b/corpus/paragraph-edit/offline/splits/native/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..d23d6f76d2f1ee76c8e096c59bacda45afb3626b --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-001.xml @@ -0,0 +1,5 @@ + +☂Bold]]> italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-002.xml b/corpus/paragraph-edit/offline/splits/native/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..302f68bcfd20c4f470d4442980f39ff29626f744 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-002.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-003.xml b/corpus/paragraph-edit/offline/splits/native/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a6966323f4370b6414fa6d324ed432fc6dee0fd --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-003.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-004.xml b/corpus/paragraph-edit/offline/splits/native/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..5f29ed91e8c01061ac3d14843d92c35a9d8a5024 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-004.xml @@ -0,0 +1,5 @@ + +☂Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-005.xml b/corpus/paragraph-edit/offline/splits/native/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..47a49619f20d80f0cd3ec8a191e25c3ae776898d --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-005.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-006.xml b/corpus/paragraph-edit/offline/splits/native/read/page-006.xml new file mode 100644 index 0000000000000000000000000000000000000000..20a04fd89bdc80ba54ac6d41499b42fa651fa476 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-006.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-007.xml b/corpus/paragraph-edit/offline/splits/native/read/page-007.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8e34a6b4409d0ca62fd300775ae8ab05e8e187e --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-007.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-008.xml b/corpus/paragraph-edit/offline/splits/native/read/page-008.xml new file mode 100644 index 0000000000000000000000000000000000000000..c98920929247120cedf4f5d8821acde295b9ddd8 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-008.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-009.xml b/corpus/paragraph-edit/offline/splits/native/read/page-009.xml new file mode 100644 index 0000000000000000000000000000000000000000..239094503552c6db3c0ad713177654e64e916fe3 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-009.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-010.xml b/corpus/paragraph-edit/offline/splits/native/read/page-010.xml new file mode 100644 index 0000000000000000000000000000000000000000..7589342d47d156ffa1b91da04b0d26bbb452e12a --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-010.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-011.xml b/corpus/paragraph-edit/offline/splits/native/read/page-011.xml new file mode 100644 index 0000000000000000000000000000000000000000..44401c90c4c34eed1906e8886f606578698472d7 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-011.xml @@ -0,0 +1,3 @@ + +Link label tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-012.xml b/corpus/paragraph-edit/offline/splits/native/read/page-012.xml new file mode 100644 index 0000000000000000000000000000000000000000..94b7c097ba40e651efb699b7b83e8f31997e3fbc --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-012.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/paragraph-edit/offline/splits/native/read/page-013.xml b/corpus/paragraph-edit/offline/splits/native/read/page-013.xml new file mode 100644 index 0000000000000000000000000000000000000000..b45f6367cbe094cff50050a691df1a253377e0df --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/page-013.xml @@ -0,0 +1,6 @@ + +☂Bo]]>ld italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/splits/native/read/payloads.json b/corpus/paragraph-edit/offline/splits/native/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..787b4bae85038cda922f8befac6c8ed361fa8035 --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/read/payloads.json @@ -0,0 +1 @@ +../../../../before/read/payloads.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/splits/native/run.json b/corpus/paragraph-edit/offline/splits/native/run.json new file mode 100644 index 0000000000000000000000000000000000000000..b59c126e1d874ea3b45cc19732aef5e66ac457ba --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-paragraph-native-01/splits/candidate", + "expected_pages": 14, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/paragraph-edit/offline/splits/native/source.json b/corpus/paragraph-edit/offline/splits/native/source.json new file mode 100644 index 0000000000000000000000000000000000000000..efa07a806149800f245ae2315d9a27dcb421ff6e --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 119736, + "sha256": "ea8264bf8df579b69755c47918ab45f77a7fdd4a4cc7564ab84813220def9322", + "mtime_ns": 1788863181033354746 + } +] diff --git a/corpus/paragraph-edit/offline/splits/native/teardown.json b/corpus/paragraph-edit/offline/splits/native/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..47a1192a30ea7da90676d631bb9a2687d829b43e --- /dev/null +++ b/corpus/paragraph-edit/offline/splits/native/teardown.json @@ -0,0 +1 @@ +../../../joined/teardown.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/tags/candidate/synthetic.one b/corpus/paragraph-edit/offline/tags/candidate/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..f14e719947b2b79e1a76d8c9e320f66d883af1c9 GIT binary patch literal 42688 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 literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/tags/manifest.json b/corpus/paragraph-edit/offline/tags/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..91e171dadf3b1b404da916620fe17ee5242e4838 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/manifest.json @@ -0,0 +1,38 @@ +[ + { + "case": "Join empty left right tag", + "id": 1, + "intent": { + "author": "Rust join author", + "left": "{0D11242E-6A38-0F74-261A-A6FC444FA262},45", + "right": "{0D11242E-6A38-0F74-261A-A6FC444FA262},50" + }, + "remote_prefix": false, + "revision": "{E906B028-AA9F-4772-877F-CCBED45A8645},1", + "space": "{FC64EF0A-5CCB-0557-20E0-6C847015B691},1" + }, + { + "case": "Join empty left two tags", + "id": 2, + "intent": { + "author": "Rust join author", + "left": "{84061027-77E3-03F1-3E0D-A8F744B19C18},45", + "right": "{84061027-77E3-03F1-3E0D-A8F744B19C18},51" + }, + "remote_prefix": false, + "revision": "{98BB5C37-4F68-408F-AE2F-4D9EFD75022F},1", + "space": "{A05CB25D-C95D-043F-3B9A-CE333AD171AD},1" + }, + { + "case": "Join different tags", + "id": 3, + "intent": { + "author": "Rust join author", + "left": "{4FBF7D4A-6F4D-048E-0913-5BD9A184C25B},44", + "right": "{4FBF7D4A-6F4D-048E-0913-5BD9A184C25B},50" + }, + "remote_prefix": true, + "revision": "{AA6105EC-5A3B-4038-887A-DDADB2911713},1", + "space": "{6F0F6556-17D3-03AF-20EF-C465A856A153},1" + } +] \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/tags/native/notebook/Open Notebook.onetoc2 b/corpus/paragraph-edit/offline/tags/native/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..0dda8d5a7eefbb1b6b34b03bd871912e528d9d9a GIT binary patch literal 4800 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 LutEVj{qg?+eNY|G literal 0 HcmV?d00001 diff --git a/corpus/paragraph-edit/offline/tags/native/read/environment.json b/corpus/paragraph-edit/offline/tags/native/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..b348dd06a6fd4897cb12c8e784c1cf7817fe7da6 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-C920A6E7", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/paragraph-edit/offline/tags/native/read/hierarchy.xml b/corpus/paragraph-edit/offline/tags/native/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..aae999471c108dab6b93ccdf7922138bcc4e42f4 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/offline/tags/native/read/page-000.xml b/corpus/paragraph-edit/offline/tags/native/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b852a0b5177c4b307766f1da26fd363570f79f2 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/page-000.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/paragraph-edit/offline/tags/native/read/page-001.xml b/corpus/paragraph-edit/offline/tags/native/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..a518cfa62728716735c00eba3f549cd8ceed68ed --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/page-001.xml @@ -0,0 +1,5 @@ + +☂LeftBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/tags/native/read/page-002.xml b/corpus/paragraph-edit/offline/tags/native/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c9bad30a1ce9ab4890efd523db2c4d8686fa73d --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/page-002.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/tags/native/read/page-003.xml b/corpus/paragraph-edit/offline/tags/native/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..f8a75604a6d26a6ae036923d879551df7dbf6ee9 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/page-003.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/offline/tags/native/read/payloads.json b/corpus/paragraph-edit/offline/tags/native/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..787b4bae85038cda922f8befac6c8ed361fa8035 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/read/payloads.json @@ -0,0 +1 @@ +../../../../before/read/payloads.json \ No newline at end of file diff --git a/corpus/paragraph-edit/offline/tags/native/run.json b/corpus/paragraph-edit/offline/tags/native/run.json new file mode 100644 index 0000000000000000000000000000000000000000..5a64074979038e3aff0716e3caf13ae9c03b43f3 --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-paragraph-native-01/tags/candidate", + "expected_pages": 4, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/paragraph-edit/offline/tags/native/source.json b/corpus/paragraph-edit/offline/tags/native/source.json new file mode 100644 index 0000000000000000000000000000000000000000..5253d2f66a6d0335f7eac687493ecba83043724c --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 42688, + "sha256": "4d6efc70b84628a281d1a64dbb3cf96d7c682d558ed7fbef708b493c51b01794", + "mtime_ns": 1788863185189921064 + } +] diff --git a/corpus/paragraph-edit/offline/tags/native/teardown.json b/corpus/paragraph-edit/offline/tags/native/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..47a1192a30ea7da90676d631bb9a2687d829b43e --- /dev/null +++ b/corpus/paragraph-edit/offline/tags/native/teardown.json @@ -0,0 +1 @@ +../../../joined/teardown.json \ No newline at end of file diff --git a/crates/onestore-offline/README.md b/crates/onestore-offline/README.md index bae1c8bdb444b6cdb1156697916e728d9da5077f..cc8593c7be7f02433d59f2c70d3d78e73d59ef0d 100644 --- a/crates/onestore-offline/README.md +++ b/crates/onestore-offline/README.md @@ -1,7 +1,7 @@ # onestore-offline Durable local editing for a OneNote file, in an optional sibling crate. The current -foundation stores a complete working image and typed text, insertion and formatting intents in a local +foundation stores a complete working image and typed editing intents in a local SQLite database. `sync_once` provides a reconciliation step and `start_sync` owns automatic polling and reconnects. Local success does not acknowledge publication to a shared notebook. @@ -29,12 +29,30 @@ assert_eq!(pending.last().map(|edit| edit.id), local_id); intent identities. `Insertion::with_formatting` queues text and its styles as one intent and one publication. Keep that value across retries; its `text_object()` identifies the new text for subsequent offline edits. Pending entries expose -`Operation::Text(TextEdit)`, `Operation::Insert(Insertion)` or -`Operation::Format(FormatEdit)` through their +`Operation::Text(TextEdit)`, `Operation::Insert(Insertion)`, +`Operation::Format(FormatEdit)`, `Operation::Split(SplitEdit)` and +`Operation::Join(JoinEdit)` through their `operation` field. Synchronization applies these in queue order, so an inserted outline can precede its paragraphs and their later edits. Missing anchors or existing insertion identities preserve a conflict and the complete local image. +`split` and `join` accept the core `ParagraphSplit` and `ParagraphJoin` intents. +Splits retain allocated identities when the original UTF-16 boundary rebases; +dependent edits can address `ParagraphSplit::text_object()` immediately after +local acknowledgement. Both operations retain observed parent paths, children, +indentation, paragraph/list state and tags. Changed structure produces +`StructureChanged`. Remote text changes must leave unambiguous boundary mappings; +current remote character styles are preserved. Reconciliation does not silently +discard a newly added right tag or move an unobserved child. + +`rebase_conflict` accepts a zero-length reviewed range for a split, preserving its +allocated identities. `rebase_join_conflict(id, local, remote)` reviews the original +join against current images. It rejects a change in which text identity survives, +because dependent edits still address that identity. As with other conflict +reviews, stale images, pending operations and uncertain attempts cannot be rebased. +An uncertain structural operation requires its original attempted revision for +confirmation; matching text or structure does not establish a receipt. + `rebase_paragraph_conflict(id, local, remote, parent, before)` and `rebase_outline_conflict(id, local, remote, page, x, y)` accept reviewed replacement placements for the oldest insertion conflict. They preserve creation time, text, @@ -70,8 +88,9 @@ requested value is accepted. Enabling superscript or subscript also checks the opposite attribute that the operation clears. If the remote image already satisfies the whole operation, guarded confirmation still precedes a durable receipt. -Recognized version-one through version-three caches migrate transactionally to the typed -queue. The migration retains images, local IDs, publication attempts, conflicts, +Recognized earlier caches migrate transactionally to version six, which adds +paragraph split/join intents and structural conflicts. The migration retains +images, local IDs, publication attempts, conflicts, receipts and the autoincrement sequence; it does not reuse acknowledged IDs when the pending queue is empty. diff --git a/crates/onestore-offline/examples/cache_probe.rs b/crates/onestore-offline/examples/cache_probe.rs index abd7ff2cf78c670c46635acf394fdd001aba39ff..8f016e89f1cee8b67dc9f82b971ec26e1cce240b 100644 --- a/crates/onestore-offline/examples/cache_probe.rs +++ b/crates/onestore-offline/examples/cache_probe.rs @@ -138,6 +138,9 @@ fn main() -> Result<(), Box> { font_size = Some(*value); *value as u64 - 6 } + onestore_offline::Operation::Split(_) | onestore_offline::Operation::Join(_) => { + panic!("This fixture does not generate paragraph boundary edits") + } }; assert!(operations.last().is_none_or(|last| *last < operation)); assert!(ids.last().is_none_or(|last| *last < pending.id)); diff --git a/crates/onestore-offline/src/lib.rs b/crates/onestore-offline/src/lib.rs index 31c7c9505ecf1fbc406f82fe2ac3df17ef9c0407..47dc8da3c60b5fcf2cba95c2ea33775402a11ea0 100644 --- a/crates/onestore-offline/src/lib.rs +++ b/crates/onestore-offline/src/lib.rs @@ -10,10 +10,12 @@ use std::{fs::OpenOptions, io, ops::Range, path::Path, sync::Mutex, time::Durati mod assets; mod formatting; +mod paragraph; mod rebase; mod recovery; mod schema; pub use formatting::FormatEdit; +pub use paragraph::{JoinEdit, SplitEdit}; pub use recovery::{Recovery, RecoverySummary}; mod sync; pub use sync::{ConflictKind, EditStatus, Remote}; @@ -45,7 +47,7 @@ pub enum Error { type Result = std::result::Result; const APPLICATION_ID: u32 = 0x4f4e454f; -const SCHEMA_VERSION: u32 = 5; +const SCHEMA_VERSION: u32 = 6; /// Text and its observed precondition, retained across cache reopen and rebasing. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] @@ -63,6 +65,8 @@ pub enum Operation { Text(TextEdit), Insert(Insertion), Format(FormatEdit), + Split(SplitEdit), + Join(JoinEdit), } /// A locally acknowledged intent; its ID remains stable across cache reopen. diff --git a/crates/onestore-offline/src/paragraph.rs b/crates/onestore-offline/src/paragraph.rs new file mode 100644 index 0000000000000000000000000000000000000000..4454bc7c110c4dba5a7c196ad982a0318886ab5a --- /dev/null +++ b/crates/onestore-offline/src/paragraph.rs @@ -0,0 +1,241 @@ +use super::*; +use onestore::{ParagraphJoin, ParagraphSplit}; +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; +use std::collections::{BTreeMap, BTreeSet}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct Observed { + text: String, + structure: Value, +} + +/// A stable split intent and the paragraph state observed before local publication. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct SplitEdit { + pub intent: ParagraphSplit, + observed: Observed, +} + +/// A join intent and both paragraphs' observed text, placement and tag ownership. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct JoinEdit { + pub intent: ParagraphJoin, + observed: [Observed; 2], +} + +fn observe(source: &[u8], space: ExGuid, texts: &[ExGuid]) -> Result>> { + let store = Store::parse(source)?; + let index = RevisionIndex::parse(&store)?; + let document = Document::parse(&index)?; + let Some(section) = document.spaces.get(&space) else { + return Ok(None); + }; + let Some(view) = section + .contexts + .get(&ExGuid::default()) + .and_then(|id| section.revisions.get(id)) + else { + return Ok(None); + }; + let mut pending: Vec<_> = document + .pages()? + .into_iter() + .filter_map(|(sid, page)| (sid == space).then_some(page)) + .collect(); + let pages = pending.clone(); + let mut seen = BTreeSet::new(); + let mut parents = BTreeMap::<_, Vec<_>>::new(); + while let Some(id) = pending.pop() { + if !seen.insert(id) { + continue; + } + let node = &view.nodes[&id]; + for child in node + .children + .iter() + .chain(&node.content) + .chain(&node.structure) + { + parents.entry(*child).or_default().push(id); + pending.push(*child); + } + } + let mut observed = Vec::new(); + for text in texts { + let Some(node) = view.nodes.get(text).filter(|_| seen.contains(text)) else { + return Ok(None); + }; + let Kind::RichText { text: content, .. } = &node.kind else { + return Ok(None); + }; + let mut path = Vec::new(); + let mut at = *text; + while !pages.contains(&at) { + let Some([parent]) = parents.get(&at).map(Vec::as_slice) else { + return Ok(None); + }; + if path.len() >= view.nodes.len() { + return Ok(None); + } + path.push(*parent); + at = *parent; + } + let Some(paragraph) = path.first().and_then(|id| view.nodes.get(id)) else { + return Ok(None); + }; + let Kind::Paragraph { lists, .. } = ¶graph.kind else { + return Ok(None); + }; + if paragraph.content != [*text] { + return Ok(None); + } + let lists: Vec<_> = lists.iter().map(|id| (*id, &view.nodes[id].kind)).collect(); + observed.push(Observed { + text: content.clone(), + structure: json!({ + "path": path, + "children": paragraph.children, + "child_level": paragraph.child_level, + "paragraph": paragraph.kind, + "lists": lists, + "tags": node.tags, + }), + }); + } + Ok(Some(observed)) +} + +impl Replica { + /// Durably queues a split with stable new identities and observed structural preconditions. + pub fn split( + &self, + source: &[u8], + space: ExGuid, + intent: &ParagraphSplit, + ) -> Result> { + let (operation, prepared) = SplitEdit::capture(source, space, intent)?; + self.record(source, space, Operation::Split(operation), &prepared) + } + + /// Durably queues a join; changed placement, children or tags require conflict review. + pub fn join( + &self, + source: &[u8], + space: ExGuid, + intent: &ParagraphJoin, + ) -> Result> { + let (operation, prepared) = JoinEdit::capture(source, space, intent)?; + self.record(source, space, Operation::Join(operation), &prepared) + } +} + +impl SplitEdit { + pub(crate) fn capture<'a>( + source: &'a [u8], + space: ExGuid, + intent: &ParagraphSplit, + ) -> Result<(Self, PreparedEdit<'a>)> { + let prepared = PreparedEdit::split(source, space, intent)?; + let Some(mut observed) = observe(source, space, &[intent.position().0])? else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Select text in an active paragraph", + ) + .into()); + }; + Ok(( + Self { + intent: intent.clone(), + observed: observed.remove(0), + }, + prepared, + )) + } + + pub(crate) fn prepare<'a>( + &self, + source: &'a [u8], + space: ExGuid, + ) -> Result, ConflictKind>> { + let (text, offset) = self.intent.position(); + let Some(observed) = observe(source, space, &[text])? else { + return Ok(Err(ConflictKind::TargetUnavailable)); + }; + if observed[0].structure != self.observed.structure { + return Ok(Err(ConflictKind::StructureChanged)); + } + let Some(range) = rebase::rebase(&self.observed.text, &observed[0].text, offset..offset) + else { + return Ok(Err(ConflictKind::TextChanged)); + }; + Ok( + PreparedEdit::split(source, space, &self.intent.reposition(range.start)) + .map_err(|_| ConflictKind::UnsupportedEdit), + ) + } +} + +impl JoinEdit { + pub(crate) fn review(&self, source: &[u8], space: ExGuid) -> Result { + let (reviewed, _) = Self::capture(source, space, &self.intent)?; + if reviewed.observed[0].text.is_empty() != self.observed[0].text.is_empty() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "The join would change its surviving text identity", + ) + .into()); + } + Ok(reviewed) + } + + pub(crate) fn capture<'a>( + source: &'a [u8], + space: ExGuid, + intent: &ParagraphJoin, + ) -> Result<(Self, PreparedEdit<'a>)> { + let prepared = PreparedEdit::join(source, space, intent)?; + let Some(observed) = observe(source, space, &intent.texts())? else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Select text in two active paragraphs", + ) + .into()); + }; + Ok(( + Self { + intent: intent.clone(), + observed: observed.try_into().unwrap(), + }, + prepared, + )) + } + + pub(crate) fn prepare<'a>( + &self, + source: &'a [u8], + space: ExGuid, + ) -> Result, ConflictKind>> { + let Some(observed) = observe(source, space, &self.intent.texts())? else { + return Ok(Err(ConflictKind::TargetUnavailable)); + }; + for (i, (old, new)) in self.observed.iter().zip(&observed).enumerate() { + if old.structure != new.structure { + return Ok(Err(ConflictKind::StructureChanged)); + } + let at = if i == 0 { + u32::try_from(old.text.encode_utf16().count()).map_err(io::Error::other)? + } else { + 0 + }; + if rebase::rebase(&old.text, &new.text, at..at).is_none() { + return Ok(Err(ConflictKind::TextChanged)); + } + } + Ok(PreparedEdit::join(source, space, &self.intent) + .map_err(|_| ConflictKind::UnsupportedEdit)) + } +} diff --git a/crates/onestore-offline/src/schema.rs b/crates/onestore-offline/src/schema.rs index 32b8f454dc8f969a687d9412dd5cd01f74238b56..766da91f0e860c4ea378fe250a4c57771368d34b 100644 --- a/crates/onestore-offline/src/schema.rs +++ b/crates/onestore-offline/src/schema.rs @@ -3,7 +3,7 @@ use rusqlite::{OptionalExtension, Transaction}; const CONFLICTS: &str = "CREATE TABLE conflicts ( edit_id INTEGER PRIMARY KEY REFERENCES edits(id) ON DELETE CASCADE, - kind INTEGER NOT NULL CHECK(kind BETWEEN 0 AND 3) + kind INTEGER NOT NULL CHECK(kind BETWEEN 0 AND 4) ) STRICT;"; const ASSETS: &str = "CREATE TABLE assets ( @@ -35,17 +35,15 @@ pub(crate) fn create(transaction: &Transaction<'_>) -> Result<()> { } pub(crate) fn migrate(transaction: &Transaction<'_>, version: u32) -> Result<()> { - if version == 4 { - transaction.execute_batch(ASSETS)?; - return Ok(()); - } - if version == 3 { + if version >= 3 { transaction.execute_batch("ALTER TABLE conflicts RENAME TO old_conflicts;")?; transaction.execute_batch(CONFLICTS)?; transaction.execute_batch( "INSERT INTO conflicts SELECT * FROM old_conflicts; DROP TABLE old_conflicts;", )?; - transaction.execute_batch(ASSETS)?; + if version < 5 { + transaction.execute_batch(ASSETS)?; + } return Ok(()); } diff --git a/crates/onestore-offline/src/sync.rs b/crates/onestore-offline/src/sync.rs index 286fca19a5c4bb7456eafbdf1eba69cd789ef114..9f18010cb7bddce1cddcbbf0e442f6692dd5f4fc 100644 --- a/crates/onestore-offline/src/sync.rs +++ b/crates/onestore-offline/src/sync.rs @@ -18,6 +18,7 @@ pub enum ConflictKind { TargetUnavailable = 1, UnsupportedEdit = 2, FormattingChanged = 3, + StructureChanged = 4, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -131,6 +132,8 @@ impl Replica { } let candidate = match &intent.operation { Operation::Format(edit) => edit.prepare(&snapshot, intent.space)?, + Operation::Split(edit) => edit.prepare(&snapshot, intent.space)?, + Operation::Join(edit) => edit.prepare(&snapshot, intent.space)?, Operation::Insert(insertion) => { PreparedEdit::insert(&snapshot, intent.space, insertion) .map_err(|_| ConflictKind::UnsupportedEdit) @@ -222,7 +225,7 @@ impl Replica { Ok(Some((intent.id, EditStatus::Published { revision }))) } - /// Places the oldest text or formatting conflict at a reviewed remote UTF-16 range. + /// Places the oldest text, formatting or split conflict at a reviewed remote UTF-16 range. /// The requested replacement/attributes, local image, intent ID and later edits are preserved. /// Both supplied images must match `snapshot` and `remote_snapshot`; stale review /// returns `Io(ResourceBusy)`. Uncertain publication attempts cannot be rebased. @@ -270,6 +273,30 @@ impl Replica { )? .0, ), + Operation::Split(edit) => { + if !range.is_empty() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Choose a single split boundary", + ) + .into()); + } + Operation::Split( + crate::paragraph::SplitEdit::capture( + remote, + intent.space, + &edit.intent.reposition(range.start), + )? + .0, + ) + } + Operation::Join(_) => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Review the paragraph join using rebase_join_conflict", + ) + .into()); + } Operation::Insert(_) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -281,6 +308,21 @@ impl Replica { }) } + /// Reviews a join against both current cache images, retaining its original text identities. + /// The surviving text identity must remain the same for dependent edits. + pub fn rebase_join_conflict(&self, id: u64, local: &[u8], remote: &[u8]) -> Result<()> { + self.resolve_conflict(id, local, remote, |intent| { + let Operation::Join(edit) = intent.operation else { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Select a paragraph join conflict", + ) + .into()); + }; + Ok(Operation::Join(edit.review(remote, intent.space)?)) + }) + } + /// Repositions the oldest paragraph insertion conflict against reviewed cache images. /// Object identities and dependent edits are retained; uncertain attempts cannot be moved. pub fn rebase_paragraph_conflict( @@ -449,6 +491,7 @@ pub(crate) fn status(connection: &Connection, id: u64) -> Result ConflictKind::TargetUnavailable, 2 => ConflictKind::UnsupportedEdit, 3 => ConflictKind::FormattingChanged, + 4 => ConflictKind::StructureChanged, _ => { return Err(io::Error::new( io::ErrorKind::InvalidData, diff --git a/crates/onestore-offline/tests/cache.rs b/crates/onestore-offline/tests/cache.rs index a0f9025d8e4b3f02e6fc53ef6d45e8b9fe0aad2b..08a28a89bfd8eff88a926e1620a61d8a76bd394f 100644 --- a/crates/onestore-offline/tests/cache.rs +++ b/crates/onestore-offline/tests/cache.rs @@ -710,12 +710,19 @@ fn twelve_local_clients_preserve_inserted_identities_and_dependent_edits() { #[test] fn unrecognized_persisted_operations_are_rejected_without_dropping_fields() { - for operation in ["Text", "Insert", "Format"] { + for operation in ["Text", "Insert", "Format", "Split", "Join"] { let directory = tempfile::tempdir().unwrap(); let path = directory.path().join("unknown.sqlite"); - let source = onestore::create_section("unknown.one", "Original", "Author").unwrap(); - let cache = Replica::create(&path, &source).unwrap(); + let mut source = onestore::create_section("unknown.one", "Original", "Author").unwrap(); let (sid, oid, _) = target(&source); + let split = onestore::ParagraphSplit::new(oid, 3, "Author").unwrap(); + if operation == "Join" { + source = onestore::PreparedEdit::split(&source, sid, &split) + .unwrap() + .as_bytes() + .to_vec(); + } + let cache = Replica::create(&path, &source).unwrap(); if operation == "Insert" { let store = Store::parse(&source).unwrap(); let index = RevisionIndex::parse(&store).unwrap(); @@ -726,6 +733,16 @@ fn unrecognized_persisted_operations_are_rejected_without_dropping_fields() { cache.insert(&source, sid, &insertion).unwrap(); } else if operation == "Text" { cache.edit_text(&source, sid, oid, 0..0, "New ").unwrap(); + } else if operation == "Split" { + cache.split(&source, sid, &split).unwrap(); + } else if operation == "Join" { + cache + .join( + &source, + sid, + &onestore::ParagraphJoin::new(oid, split.text_object(), "Author").unwrap(), + ) + .unwrap(); } else { cache .format( @@ -746,7 +763,7 @@ fn unrecognized_persisted_operations_are_rejected_without_dropping_fields() { value[operation]["future_option"] = true.into(); db.execute("UPDATE edits SET operation=?1", [value.to_string()]) .unwrap(); - if operation != "Format" { + if matches!(operation, "Text" | "Insert") { db.execute_batch("DROP TABLE assets; DROP TABLE conflicts; CREATE TABLE conflicts (edit_id INTEGER PRIMARY KEY REFERENCES edits(id) ON DELETE CASCADE, kind INTEGER NOT NULL CHECK(kind BETWEEN 0 AND 2)) STRICT; PRAGMA user_version=3;").unwrap(); } drop(db); @@ -757,3 +774,101 @@ fn unrecognized_persisted_operations_are_rejected_without_dropping_fields() { assert_eq!(fs::read(&path).unwrap(), before); } } + +#[test] +fn version_five_migration_retains_queue_evidence_and_enables_structural_conflicts() { + use onestore_offline::{ConflictKind, EditStatus, Recovery}; + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("version-five.sqlite"); + let source = onestore::create_section("migration.one", "Original", "Author").unwrap(); + let (sid, oid, _) = target(&source); + let cache = Replica::create(&path, &source).unwrap(); + let first = cache + .edit_text(&source, sid, oid, 0..0, "New ") + .unwrap() + .unwrap(); + let second = cache + .format( + &cache.snapshot().unwrap(), + sid, + oid, + 0..3, + &[onestore::TextAttribute::Bold(true)], + ) + .unwrap() + .unwrap(); + let queue = cache.pending().unwrap(); + let local = cache.snapshot().unwrap(); + let store = Store::parse(&local).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let revision = index.spaces[&sid].labels[&(ExGuid::default(), 1)]; + drop(cache); + let db = rusqlite::Connection::open(&path).unwrap(); + db.execute_batch( + "DROP TABLE conflicts; CREATE TABLE conflicts ( + edit_id INTEGER PRIMARY KEY REFERENCES edits(id) ON DELETE CASCADE, + kind INTEGER NOT NULL CHECK(kind BETWEEN 0 AND 3)) STRICT; + PRAGMA user_version=5; + UPDATE sqlite_sequence SET seq=1000 WHERE name='edits';", + ) + .unwrap(); + db.execute( + "INSERT INTO conflicts VALUES (?1,3)", + [i64::try_from(second).unwrap()], + ) + .unwrap(); + db.execute( + "INSERT INTO attempt VALUES (1,?1,?2)", + rusqlite::params![i64::try_from(first).unwrap(), revision.to_string()], + ) + .unwrap(); + db.execute( + "INSERT INTO receipts VALUES (999,?1)", + [revision.to_string()], + ) + .unwrap(); + drop(db); + let cache = Replica::open(&path).unwrap(); + assert_eq!(cache.pending().unwrap(), queue); + assert!(cache.snapshot().unwrap() == local); + assert!(cache.remote_snapshot().unwrap() == source); + assert_eq!( + cache.status(first).unwrap(), + Some(EditStatus::AwaitingConfirmation { revision }) + ); + assert_eq!( + cache.status(second).unwrap(), + Some(EditStatus::Conflict(ConflictKind::FormattingChanged)) + ); + assert_eq!( + cache.status(999).unwrap(), + Some(EditStatus::Published { revision }) + ); + let split = onestore::ParagraphSplit::new(oid, 3, "Author").unwrap(); + assert_eq!(cache.split(&local, sid, &split).unwrap(), Some(1001)); + let pending = cache.pending().unwrap(); + let archive = directory.path().join("recovery.sqlite"); + cache.export_recovery(&archive).unwrap(); + let recovery = Recovery::open(&archive).unwrap(); + assert_eq!(recovery.pending().unwrap(), pending); + assert_eq!( + recovery.status(first).unwrap(), + cache.status(first).unwrap() + ); + assert_eq!(recovery.receipts().unwrap().get(&999), Some(&revision)); + drop(cache); + let db = rusqlite::Connection::open(&path).unwrap(); + assert_eq!( + db.pragma_query_value(None, "user_version", |row| row.get::<_, u32>(0)) + .unwrap(), + 6 + ); + db.execute("INSERT INTO conflicts VALUES (1001,4)", []) + .unwrap(); + drop(db); + let cache = Replica::open(&path).unwrap(); + assert_eq!( + cache.status(1001).unwrap(), + Some(EditStatus::Conflict(ConflictKind::StructureChanged)) + ); +} diff --git a/crates/onestore-offline/tests/sync.rs b/crates/onestore-offline/tests/sync.rs index 52d1f6b8a2115edf0fcc2d43fc41408c7c0ff349..3b991310b001555db1d28de3590002f3c01b078a 100644 --- a/crates/onestore-offline/tests/sync.rs +++ b/crates/onestore-offline/tests/sync.rs @@ -5,6 +5,528 @@ use onestore::{ use onestore_offline::{ConflictKind, EditStatus, Error, Remote, Replica}; use std::io; +mod paragraph { + use super::*; + use onestore::{Insertion, ParagraphJoin, ParagraphSplit, TextAttribute}; + + fn fixture() -> (Vec, ExGuid, ExGuid, ExGuid) { + let source = onestore::create_section("paragraph.one", "ab🦀cd", "Fixture").unwrap(); + let (sid, left, _) = text(&source); + let store = Store::parse(&source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let doc = Document::parse(&index).unwrap(); + let space = &doc.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let parent = *view + .nodes + .iter() + .find(|(_, node)| node.content == [left]) + .unwrap() + .0; + (source, sid, left, parent) + } + + #[test] + fn split_join_dependencies_reopen_and_rebase_with_remote_text_and_styles() { + let (source, sid, left, parent) = fixture(); + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("paragraph.sqlite"); + let mut cache = Replica::create(&path, &source).unwrap(); + let split = ParagraphSplit::new(left, 2, "Local").unwrap(); + let child = Insertion::paragraph(split.object(), None, "Child", "Local").unwrap(); + let join = ParagraphJoin::new(left, split.text_object(), "Local").unwrap(); + let mut ids = Vec::new(); + for step in 0..6 { + let current = cache.snapshot().unwrap(); + let id = match step { + 0 => cache.split(¤t, sid, &split), + 1 => cache.edit_text(¤t, sid, split.text_object(), 0..2, "🦋"), + 2 => cache.format( + ¤t, + sid, + split.text_object(), + 2..3, + &[TextAttribute::Bold(true)], + ), + 3 => cache.insert(¤t, sid, &child), + 4 => cache.join(¤t, sid, &join), + 5 => cache.edit_text(¤t, sid, left, 5..6, "D"), + _ => unreachable!(), + } + .unwrap() + .unwrap(); + ids.push(id); + let saved = cache.snapshot().unwrap(); + let pending = cache.pending().unwrap(); + drop(cache); + cache = Replica::open(&path).unwrap(); + assert_eq!(cache.snapshot().unwrap(), saved); + assert_eq!(cache.pending().unwrap(), pending); + } + let remote = onestore::replace_text(&source, sid, left, 0..0, "Z").unwrap(); + let remote = + PreparedEdit::format(&remote, sid, left, 1..2, &[TextAttribute::Italic(true)]).unwrap(); + let mut server = Server::new(remote.as_bytes()); + let local = cache.snapshot().unwrap(); + for (i, id) in ids.iter().enumerate() { + let (published, state) = cache.sync_once(&mut server).unwrap().unwrap(); + assert_eq!(published, *id); + assert!(matches!(state, EditStatus::Published { .. }), "{state:?}"); + drop(cache); + cache = Replica::open(&path).unwrap(); + assert_eq!(cache.status(*id).unwrap(), Some(state)); + if i != ids.len() - 1 { + assert_eq!(cache.snapshot().unwrap(), local); + } + } + assert_eq!(server.publications, ids.len()); + assert_eq!(server.visible, server.durable); + assert_eq!(cache.snapshot().unwrap(), server.durable); + let store = Store::parse(&server.durable).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + index.validate_current().unwrap(); + let doc = Document::parse(&index).unwrap(); + let space = &doc.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + assert!( + matches!(&view.nodes[&left].kind, Kind::RichText { text, .. } if text == "Zab🦋cD") + ); + assert_eq!(view.nodes[&parent].children, [child.object()]); + assert_eq!(view.nodes[&parent].content, [left]); + let runs = view.text_runs(left).unwrap(); + let chars: Vec<_> = runs + .iter() + .flat_map(|run| { + run.text + .chars() + .map(|c| (c, run.format.bold, run.format.italic)) + }) + .collect(); + assert_eq!(chars.iter().find(|v| v.0 == 'a').unwrap().2, Some(true)); + assert_eq!(chars.iter().find(|v| v.0 == 'c').unwrap().1, Some(true)); + } + + #[test] + fn changed_split_children_require_fresh_review_without_reallocating_dependents() { + let (source, sid, left, parent) = fixture(); + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("paragraph.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let split = ParagraphSplit::new(left, 2, "Local").unwrap(); + let id = cache.split(&source, sid, &split).unwrap().unwrap(); + let dependent = cache + .edit_text( + &cache.snapshot().unwrap(), + sid, + split.text_object(), + 0..2, + "🦋", + ) + .unwrap() + .unwrap(); + let local = cache.snapshot().unwrap(); + let child = Insertion::paragraph(parent, None, "Remote child", "Remote").unwrap(); + let remote = PreparedEdit::insert(&source, sid, &child).unwrap(); + let mut server = Server::new(remote.as_bytes()); + assert_eq!( + cache.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(ConflictKind::StructureChanged))) + ); + assert_eq!(server.publications, 0); + assert_eq!(cache.snapshot().unwrap(), local); + assert!( + cache + .rebase_conflict(id, &source, &server.visible, 2..2) + .is_err() + ); + assert!( + cache + .rebase_conflict(id, &local, &server.visible, 2..3) + .is_err() + ); + cache + .rebase_conflict(id, &local, &server.visible, 2..2) + .unwrap(); + let pending = cache.pending().unwrap(); + let onestore_offline::Operation::Split(edit) = &pending[0].operation else { + panic!() + }; + assert_eq!(edit.intent, split); + assert_eq!(pending[1].id, dependent); + drop(cache); + let cache = Replica::open(&path).unwrap(); + for expected in [id, dependent] { + let (actual, state) = cache.sync_once(&mut server).unwrap().unwrap(); + assert_eq!(actual, expected); + assert!(matches!(state, EditStatus::Published { .. })); + } + let store = Store::parse(&server.durable).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let doc = Document::parse(&index).unwrap(); + let space = &doc.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + assert_eq!(view.nodes[&split.object()].children, [child.object()]); + assert!( + matches!(&view.nodes[&split.text_object()].kind, Kind::RichText { text, .. } if text == "🦋cd") + ); + } + + #[test] + fn uncertain_paragraph_operations_keep_the_original_attempt_across_reopen() { + for join in [false, true] { + for fault in [ + Fault::Before, + Fault::UnknownBefore, + Fault::UnknownAfter, + Fault::Committed, + ] { + let (source, sid, left, _) = fixture(); + let split = ParagraphSplit::new(left, 2, "Local").unwrap(); + let source = if join { + PreparedEdit::split(&source, sid, &split) + .unwrap() + .as_bytes() + .to_vec() + } else { + source + }; + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("paragraph.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let id = if join { + cache.join( + &source, + sid, + &ParagraphJoin::new(left, split.text_object(), "Local").unwrap(), + ) + } else { + cache.split(&source, sid, &split) + } + .unwrap() + .unwrap(); + let local = cache.snapshot().unwrap(); + let intent = cache.pending().unwrap(); + let mut server = Server::new(&source); + server.fault = fault; + assert!(cache.sync_once(&mut server).is_err()); + let state = cache.status(id).unwrap().unwrap(); + drop(cache); + let cache = Replica::open(&path).unwrap(); + assert_eq!(cache.status(id).unwrap(), Some(state)); + if matches!(fault, Fault::UnknownBefore | Fault::UnknownAfter) { + assert!(matches!(state, EditStatus::AwaitingConfirmation { .. })); + assert_eq!(cache.pending().unwrap(), intent); + assert_eq!(cache.snapshot().unwrap(), local); + if matches!(fault, Fault::UnknownBefore) { + assert_eq!(cache.sync_once(&mut server).unwrap(), Some((id, state))); + assert_eq!(server.publications, 1); + continue; + } + server.fault = Fault::Confirm; + assert!(cache.sync_once(&mut server).is_err()); + assert_eq!(cache.status(id).unwrap(), Some(state)); + let (_, state) = cache.sync_once(&mut server).unwrap().unwrap(); + assert!(matches!(state, EditStatus::Published { .. })); + assert_eq!(server.publications, 1); + } else if matches!(fault, Fault::Before) { + assert_eq!(state, EditStatus::Pending); + assert!(matches!( + cache.sync_once(&mut server).unwrap().unwrap().1, + EditStatus::Published { .. } + )); + assert_eq!(server.publications, 2); + } else { + assert!(matches!(state, EditStatus::Published { .. })); + assert_eq!(server.publications, 1); + } + assert!(cache.pending().unwrap().is_empty()); + let saved = cache.snapshot().unwrap(); + if matches!(fault, Fault::UnknownAfter) { + // Confirmation refreshes version metadata after reading the acknowledged snapshot. + assert!(saved[..212] == server.durable[..212]); + assert!(saved[252..] == server.durable[252..]); + assert_eq!( + Store::parse(&server.durable).unwrap().header.generation, + Store::parse(&saved).unwrap().header.generation + 1 + ); + } else { + assert!(saved == server.durable); + } + assert_eq!(cache.sync_once(&mut server).unwrap(), None); + assert!(cache.snapshot().unwrap() == server.durable); + } + } + } + + #[test] + fn join_reviews_preserve_survivors_and_require_current_child_placement() { + for empty in [false, true] { + let (source, sid, left, _) = fixture(); + let split = ParagraphSplit::new(left, if empty { 0 } else { 2 }, "Local").unwrap(); + let source = PreparedEdit::split(&source, sid, &split) + .unwrap() + .as_bytes() + .to_vec(); + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("join.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let intent = ParagraphJoin::new(left, split.text_object(), "Local").unwrap(); + let id = cache.join(&source, sid, &intent).unwrap().unwrap(); + let survivor = if empty { split.text_object() } else { left }; + let dependent = cache + .edit_text(&cache.snapshot().unwrap(), sid, survivor, 0..0, "Local ") + .unwrap() + .unwrap(); + let local = cache.snapshot().unwrap(); + let child = + Insertion::paragraph(split.object(), None, "Remote child", "Remote").unwrap(); + let remote = PreparedEdit::insert(&source, sid, &child) + .unwrap() + .as_bytes() + .to_vec(); + let mut server = Server::new(&remote); + assert_eq!( + cache.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(ConflictKind::StructureChanged))) + ); + assert!(cache.rebase_join_conflict(id, &source, &remote).is_err()); + assert_eq!(server.publications, 0); + cache.rebase_join_conflict(id, &local, &remote).unwrap(); + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == id) + ); + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == dependent) + ); + let store = Store::parse(&server.durable).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let doc = Document::parse(&index).unwrap(); + let space = &doc.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let parent = view + .nodes + .values() + .find(|node| node.content == [survivor]) + .unwrap(); + assert_eq!(parent.children, [child.object()]); + assert!( + matches!(&view.nodes[&survivor].kind, Kind::RichText { text, .. } if text == "Local ab🦀cd") + ); + } + + let (source, sid, left, _) = fixture(); + let split = ParagraphSplit::new(left, 0, "Local").unwrap(); + let source = PreparedEdit::split(&source, sid, &split) + .unwrap() + .as_bytes() + .to_vec(); + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("identity.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let intent = ParagraphJoin::new(left, split.text_object(), "Local").unwrap(); + let id = cache.join(&source, sid, &intent).unwrap().unwrap(); + let local = cache.snapshot().unwrap(); + let remote = onestore::replace_text(&source, sid, left, 0..0, "Remote").unwrap(); + let mut server = Server::new(&remote); + assert_eq!( + cache.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(ConflictKind::TextChanged))) + ); + assert!(cache.rebase_join_conflict(id, &local, &remote).is_err()); + assert!(cache.snapshot().unwrap() == local); + assert_eq!(server.publications, 0); + assert_eq!(cache.pending().unwrap().len(), 1); + } + + #[test] + fn overlapping_clients_retain_each_local_branch_without_replaying_removed_targets() { + let (source, sid, left, _) = fixture(); + let split = ParagraphSplit::new(left, 2, "Seed").unwrap(); + let source = PreparedEdit::split(&source, sid, &split) + .unwrap() + .as_bytes() + .to_vec(); + let directory = tempfile::tempdir().unwrap(); + let first = Replica::create(directory.path().join("first.sqlite"), &source).unwrap(); + let second_path = directory.path().join("second.sqlite"); + let second = Replica::create(&second_path, &source).unwrap(); + let join = ParagraphJoin::new(left, split.text_object(), "First").unwrap(); + first.join(&source, sid, &join).unwrap(); + let right_split = ParagraphSplit::new(split.text_object(), 2, "Second").unwrap(); + let id = second.split(&source, sid, &right_split).unwrap().unwrap(); + second + .edit_text( + &second.snapshot().unwrap(), + sid, + right_split.text_object(), + 0..0, + "Second ", + ) + .unwrap(); + let local = second.snapshot().unwrap(); + let pending = second.pending().unwrap(); + let mut server = Server::new(&source); + assert!(matches!( + first.sync_once(&mut server).unwrap().unwrap().1, + EditStatus::Published { .. } + )); + assert_eq!( + second.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(ConflictKind::TargetUnavailable))) + ); + drop(second); + let second = Replica::open(&second_path).unwrap(); + assert_eq!(second.pending().unwrap(), pending); + assert!(second.snapshot().unwrap() == local); + assert_eq!(server.publications, 1); + assert_eq!( + second.status(id).unwrap(), + Some(EditStatus::Conflict(ConflictKind::TargetUnavailable)) + ); + } + + #[test] + #[ignore = "exports reconciled paragraph edits for independent native validation"] + fn export_native_offline_paragraphs() { + use std::{fs, path::PathBuf}; + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../corpus/paragraph-edit"); + let output = PathBuf::from(std::env::var_os("ONESTORE_OFFLINE_PARAGRAPH_OUTPUT").unwrap()); + assert!(output.is_absolute()); + fs::create_dir(&output).unwrap(); + for (name, source, manifest, split) in [ + ( + "splits", + "before/notebook/synthetic.one", + "rust-split/manifest.json", + true, + ), + ( + "joins", + "split/notebook/synthetic.one", + "rust-join/split/manifest.json", + false, + ), + ( + "inheritance", + "join-edges/before/notebook/synthetic.one", + "rust-join/inheritance/manifest.json", + false, + ), + ( + "tags", + "join-tags/before/notebook/synthetic.one", + "rust-join/tags/manifest.json", + false, + ), + ] { + let source = fs::read(root.join(source)).unwrap(); + let folder = output.join(name); + fs::create_dir(&folder).unwrap(); + let path = folder.join("cache.sqlite"); + let mut cache = Replica::create(&path, &source).unwrap(); + let mut server = Server::new(&source); + let manifest: serde_json::Value = + serde_json::from_slice(&fs::read(root.join(manifest)).unwrap()).unwrap(); + let cases = if split { &manifest["cases"] } else { &manifest }; + let mut recorded = Vec::new(); + for case in cases + .as_array() + .unwrap() + .iter() + .filter(|case| case.get("intent").is_some()) + { + let local = cache.snapshot().unwrap(); + let (text, offset) = if split { + serde_json::from_value::(case["intent"].clone()) + .unwrap() + .position() + } else { + ( + serde_json::from_value::(case["intent"].clone()) + .unwrap() + .texts()[0], + 1, + ) + }; + let store = Store::parse(&local).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let doc = Document::parse(&index).unwrap(); + let (sid, space) = doc + .spaces + .iter() + .find(|(_, space)| { + space.revisions[&space.contexts[&ExGuid::default()]] + .nodes + .contains_key(&text) + }) + .unwrap(); + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let Kind::RichText { text: content, .. } = &view.nodes[&text].kind else { + panic!() + }; + let remote_prefix = offset > 0 && !content.is_empty(); + assert!(!content.contains('☂')); + if remote_prefix { + server.visible = + onestore::replace_text(&server.visible, *sid, text, 0..0, "☂").unwrap(); + server.durable.clone_from(&server.visible); + } + let id = if split { + cache.split( + &local, + *sid, + &serde_json::from_value(case["intent"].clone()).unwrap(), + ) + } else { + cache.join( + &local, + *sid, + &serde_json::from_value(case["intent"].clone()).unwrap(), + ) + } + .unwrap() + .unwrap(); + recorded.push(serde_json::json!({"case": case["case"], "id": id, + "space": sid, "intent": case["intent"], "remote_prefix": remote_prefix})); + drop(cache); + cache = Replica::open(&path).unwrap(); + } + for case in &mut recorded { + let id = case["id"].as_u64().unwrap(); + if id % 2 == 0 { + server.fault = Fault::UnknownAfter; + assert!(cache.sync_once(&mut server).is_err()); + assert!(matches!( + cache.status(id).unwrap(), + Some(EditStatus::AwaitingConfirmation { .. }) + )); + drop(cache); + cache = Replica::open(&path).unwrap(); + } + let (actual, status) = cache.sync_once(&mut server).unwrap().unwrap(); + assert_eq!(actual, id); + let EditStatus::Published { revision } = status else { + panic!("{name}: {status:?}") + }; + case["revision"] = serde_json::to_value(revision).unwrap(); + } + assert_eq!(server.publications, recorded.len()); + assert_eq!(cache.sync_once(&mut server).unwrap(), None); + assert!(cache.snapshot().unwrap() == server.durable); + cache + .export_recovery(folder.join("recovery.sqlite")) + .unwrap(); + fs::create_dir(folder.join("candidate")).unwrap(); + fs::write(folder.join("candidate/synthetic.one"), &server.durable).unwrap(); + fs::write( + folder.join("manifest.json"), + serde_json::to_vec_pretty(&recorded).unwrap(), + ) + .unwrap(); + } + } +} + #[derive(Clone, Copy, Default)] enum Fault { #[default] @@ -739,7 +1261,7 @@ fn version_one_cache_migration_preserves_images_intents_and_local_ids() { assert_eq!( db.pragma_query_value(None, "user_version", |row| row.get::<_, u32>(0)) .unwrap(), - 5 + 6 ); } diff --git a/crates/onestore/README.md b/crates/onestore/README.md index 3bc5ce49fa5859bd51d2f536a316032009bcddf4..ba65490e12ddb14398b00f73bc25e4c9851c179d 100644 --- a/crates/onestore/README.md +++ b/crates/onestore/README.md @@ -95,8 +95,9 @@ Ambiguous ancestry, unsupported indentation transitions and unknown implicit font/language inheritance reject before I/O. This is a logical join, so keyboard actions that only change list or indentation state remain separate operations. Generated fields, protected targets and unsupported run-data boundary changes are -rejected before publication. Local caches expose text, insertion and formatting edits; -the [document-writer acceptance](../../evidence/MILESTONE9.md#document-writer-and-offline-acceptance) +rejected before publication. The [offline crate](../onestore-offline/README.md) +documents durable local operations and reconciliation. The +[document-writer acceptance](../../evidence/MILESTONE9.md#document-writer-and-offline-acceptance) includes twelve mixed native/Rust clients, outages, lost replies and native revision retirement. External `.onebin` references identify payloads for the caller to obtain. Cloud diff --git a/crates/onestore/src/paragraph.rs b/crates/onestore/src/paragraph.rs index d122deeebd33fee4774f7559c2d732aa6293a0f7..88b96ec981b077a4aef5eef3358577b812d17805 100644 --- a/crates/onestore/src/paragraph.rs +++ b/crates/onestore/src/paragraph.rs @@ -61,6 +61,19 @@ impl ParagraphSplit { } } + /// Original text identity and UTF-16 split boundary. + pub fn position(&self) -> (ExGuid, u32) { + (self.text, self.offset) + } + + /// Changes the split boundary while retaining allocated identities and creation time. + /// Preparing the edit validates the offset against the supplied text. + pub fn reposition(&self, offset: u32) -> Self { + let mut split = self.clone(); + split.offset = offset; + split + } + pub(crate) fn apply(&self, source: &[u8], space: ExGuid) -> Result, Error> { if self.guid == [0; 16] || self.text.guid == [0; 16] || self.author.contains('\0') { return Err(invalid( @@ -418,6 +431,11 @@ pub struct ParagraphJoin { } impl ParagraphJoin { + /// Ordered left and right text identities. + pub fn texts(&self) -> [ExGuid; 2] { + [self.left, self.right] + } + /// Select the preceding leaf paragraph's text and the following paragraph's text. pub fn new(left: ExGuid, right: ExGuid, author: &str) -> Result { if left == right || left.guid == [0; 16] || right.guid == [0; 16] || author.contains('\0') { diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index a2e4232b1ca6977f055ff4674e78bbf2830dfce9..4761c1d148069c58d00c94f6cffd3d36b55fe192 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -51,6 +51,12 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + [[package]] name = "cbc" version = "0.2.1" @@ -138,12 +144,46 @@ dependencies = [ "zeroize", ] +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + [[package]] name = "find-msvc-tools" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "getrandom" version = "0.4.3" @@ -155,6 +195,33 @@ dependencies = [ "r-efi", ] +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a596f1b20ed2cc5ecac41a164aaebc7258057060f06c0cf7a2ba3991ee7990fb" +dependencies = [ + "hashbrown 0.17.1", +] + [[package]] name = "hybrid-array" version = "0.4.14" @@ -191,6 +258,16 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.189" @@ -207,6 +284,23 @@ dependencies = [ "cc", ] +[[package]] +name = "libsqlite3-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "md5" version = "0.8.1" @@ -231,6 +325,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + [[package]] name = "onestore" version = "0.1.0" @@ -255,9 +355,40 @@ dependencies = [ "libfuzzer-sys", "md5", "onestore", + "onestore-offline", "serde_json", + "tempfile", ] +[[package]] +name = "onestore-notebook" +version = "0.1.0" +dependencies = [ + "onestore", + "serde", + "thiserror", +] + +[[package]] +name = "onestore-offline" +version = "0.1.0" +dependencies = [ + "onestore", + "onestore-notebook", + "rusqlite", + "serde", + "serde_json", + "sha2", + "tempfile", + "thiserror", +] + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + [[package]] name = "proc-macro2" version = "1.0.107" @@ -291,6 +422,50 @@ dependencies = [ "memchr", ] +[[package]] +name = "rsqlite-vfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c" +dependencies = [ + "hashbrown 0.16.1", + "thiserror", +] + +[[package]] +name = "rusqlite" +version = "0.40.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f2a97da3e3873c73cb2a2e71b35c40ff95e0b1eefa8d72d8499a6928c3b5b3" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + [[package]] name = "serde" version = "1.0.229" @@ -345,12 +520,41 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +[[package]] +name = "smallvec" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" + +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + [[package]] name = "subtle" version = "2.6.1" @@ -368,6 +572,39 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" version = "1.20.1" @@ -380,6 +617,72 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "zeroize" version = "1.9.0" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 3c0a6bb007fa7d2349e20ebf0db8b3539a536c65..8030aaced5f9bd27b8999e7e3a26402a8d929126 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -10,6 +10,8 @@ cargo-fuzz = true [dependencies] libfuzzer-sys = "0.4" onestore = { path = "../crates/onestore", features = ["protected"] } +onestore-offline = { path = "../crates/onestore-offline" } +tempfile = "3" md5 = "0.8.1" serde_json = "1" @@ -91,3 +93,10 @@ path = "fuzz_targets/paragraph.rs" test = false doc = false bench = false + +[[bin]] +name = "offline_paragraph" +path = "fuzz_targets/offline_paragraph.rs" +test = false +doc = false +bench = false diff --git a/fuzz/fuzz_targets/offline_paragraph.rs b/fuzz/fuzz_targets/offline_paragraph.rs new file mode 100644 index 0000000000000000000000000000000000000000..b826400660dbcc2ca393a2c005adfef6887fa229 --- /dev/null +++ b/fuzz/fuzz_targets/offline_paragraph.rs @@ -0,0 +1,165 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; +use onestore::{ + CommitError, ExGuid, ParagraphJoin, ParagraphSplit, PreparedEdit, RevisionIndex, Store, + document::{Document, Kind}, +}; +use onestore_offline::{EditStatus, Remote, Replica}; +use std::{io, sync::LazyLock}; + +#[path = "../../crates/onestore/tests/support/disk.rs"] +mod disk; + +const TEXT: &str = "a🦀 e\u{301} 東京\rEnd"; + +static SOURCE: LazyLock<(Vec, ExGuid, ExGuid)> = LazyLock::new(|| { + let source = onestore::create_section("offline-paragraph.one", TEXT, "Fixture").unwrap(); + let store = Store::parse(&source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let doc = Document::parse(&index).unwrap(); + let (sid, page) = doc.pages().unwrap()[0]; + let space = &doc.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let outline = *view.nodes[&page] + .children + .iter() + .find(|id| matches!(view.nodes[id].kind, Kind::Outline { .. })) + .unwrap(); + (source, sid, outline) +}); + +struct Server(disk::Disk); + +impl Remote for Server { + fn read(&mut self) -> io::Result> { + Ok(self.0.visible.clone()) + } + fn publish(&mut self, edit: &PreparedEdit<'_>) -> Result<(), CommitError> { + edit.commit(&mut self.0) + } + fn confirm(&mut self, snapshot: &[u8]) -> Result<(), CommitError> { + onestore::confirm_snapshot(&mut self.0, snapshot) + } +} + +fn paragraphs(source: &[u8], sid: ExGuid, outline: ExGuid) -> Vec<(ExGuid, String)> { + let store = Store::parse(source).unwrap(); + assert!(store.checksum_mismatches.is_empty()); + let index = RevisionIndex::parse(&store).unwrap(); + index.validate_current().unwrap(); + let doc = Document::parse(&index).unwrap(); + let space = &doc.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let mut output = Vec::new(); + for paragraph in &view.nodes[&outline].children { + let node = &view.nodes[paragraph]; + assert!(node.children.is_empty()); + let [text] = node.content.as_slice() else { + panic!() + }; + let Kind::RichText { text: content, .. } = &view.nodes[text].kind else { + panic!() + }; + output.push((*text, content.clone())); + } + assert_eq!( + output + .iter() + .map(|(_, text)| text.as_str()) + .collect::(), + TEXT + ); + output +} + +fuzz_target!(|input: &[u8]| { + if input.len() < 8 { + return; + } + let (source, sid, outline) = &*SOURCE; + let directory = tempfile::tempdir().unwrap(); + let mut replicas: [Option; 12] = std::array::from_fn(|_| None); + let mut server = Server(disk::Disk { + visible: source.clone(), + durable: source.clone(), + operation: 0, + fail_at: None, + write_limit: 4096, + random: 1, + }); + for step in input.chunks_exact(8).take(24) { + let actor = usize::from(step[0]) % replicas.len(); + let path = directory.path().join(format!("{actor}.sqlite")); + let cache = replicas[actor].get_or_insert_with(|| Replica::create(&path, source).unwrap()); + let snapshot = cache.snapshot().unwrap(); + let pending = cache.pending().unwrap(); + let rows = paragraphs(&snapshot, *sid, *outline); + match step[1] % 5 { + 0 => { + let (text, content) = &rows[usize::from(step[2]) % rows.len()]; + let offsets: Vec = std::iter::once(0) + .chain(content.chars().scan(0, |at, c| { + *at += c.len_utf16() as u32; + Some(*at) + })) + .collect(); + let offset = offsets[usize::from(step[3]) % offsets.len()]; + let intent = ParagraphSplit::new(*text, offset, "Fuzz").unwrap(); + let id = cache.split(&snapshot, *sid, &intent).unwrap().unwrap(); + assert_eq!(cache.status(id).unwrap(), Some(EditStatus::Pending)); + let next = cache.pending().unwrap(); + assert_eq!(next[..pending.len()], pending); + assert_eq!(next.len(), pending.len() + 1); + } + 1 if rows.len() > 1 => { + let pair = usize::from(step[2]) % (rows.len() - 1); + let intent = ParagraphJoin::new(rows[pair].0, rows[pair + 1].0, "Fuzz").unwrap(); + let id = cache.join(&snapshot, *sid, &intent).unwrap().unwrap(); + assert_eq!(cache.status(id).unwrap(), Some(EditStatus::Pending)); + let next = cache.pending().unwrap(); + assert_eq!(next[..pending.len()], pending); + assert_eq!(next.len(), pending.len() + 1); + } + 2 | 3 => { + server.0.operation = 0; + server.0.fail_at = + (step[4] != 0).then_some(usize::from(u16::from_le_bytes([step[4], step[5]]))); + server.0.write_limit = if step[6] & 1 == 0 { 17 } else { 4096 }; + server.0.random = u64::from(step[7]) + 1; + let _ = cache.sync_once(&mut server); + let after = cache.pending().unwrap(); + assert!(after.len() == pending.len() || after.len() + 1 == pending.len()); + if after.len() == pending.len() { + assert_eq!(after, pending); + } else { + assert_eq!(after, pending[1..]); + let Some(EditStatus::Published { revision }) = + cache.status(pending[0].id).unwrap() + else { + panic!() + }; + let store = Store::parse(&server.0.durable).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + assert!(index.spaces[sid].revisions.contains_key(&revision)); + } + if !after.is_empty() { + assert!(cache.snapshot().unwrap() == snapshot); + } + server.0.visible.clone_from(&server.0.durable); + } + _ => { + drop(replicas[actor].take()); + let reopened = Replica::open(&path).unwrap(); + assert!(reopened.snapshot().unwrap() == snapshot); + assert_eq!(reopened.pending().unwrap(), pending); + replicas[actor] = Some(reopened); + } + } + paragraphs(&server.0.durable, *sid, *outline); + paragraphs( + &replicas[actor].as_ref().unwrap().snapshot().unwrap(), + *sid, + *outline, + ); + } +}); diff --git a/tools/test_paragraph_edit.py b/tools/test_paragraph_edit.py index dd58f808b585e7a2b4e84e921ab4decab224f1bd..62bfe9cd08b5214d27602dd37f5b6e0f5a2cf497 100644 --- a/tools/test_paragraph_edit.py +++ b/tools/test_paragraph_edit.py @@ -17,31 +17,64 @@ compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare'] class ParagraphEditTest(unittest.TestCase): + def assert_cold_graph(self, fixture): + with TemporaryDirectory() as temporary: + models = [] + for source in ('candidate', 'native/notebook'): + folder = Path(temporary) / source.replace('/', '-') + shutil.copytree(fixture / 'native/read', folder / 'read') + compare(fixture / source, folder / 'read') + subprocess.run([EXPORTER, fixture / source / 'synthetic.one', folder / 'model'], check=True) + model = json.loads((folder / 'model/document.json').read_text()) + models.append({r['nodes'][r['roots']['2']]['kind']['title']: (r, page) + for _, _, r, page in ordered_pages(model)}) + self.assertEqual(models[0].keys(), models[1].keys()) + for title, (old, page) in models[0].items(): + saved, saved_page = models[1][title] + self.assertEqual(saved_page, page) + for outline in old['nodes'][page]['children']: + if old['nodes'][outline]['kind']['type'] != 'Outline': continue + for oid, node in walk(old, outline): + self.assertEqual(saved['nodes'][oid]['children'], node['children']) + self.assertEqual(saved['nodes'][oid]['content'], node['content']) + + def test_offline_boundaries_retain_remote_edits_and_match_native_controls(self): + groups = [('splits', 'cold-split/read', 12), ('joins', 'joined/read', 12), + ('inheritance', 'join-edges/joined/read', 5), ('tags', 'join-tags/joined/read', 3)] + for name, control, count in groups: + fixture = FIXTURE / 'offline' / name + manifest = json.loads((fixture / 'manifest.json').read_text()) + self.assertEqual(len(manifest), count) + with self.subTest(group=name): + self.assert_cold_graph(fixture) + captures = [] + for folder in (FIXTURE / control, fixture / 'native/read'): + captures.append({page.get('name'): native_characters(page, page.findall('one:Outline', ns)) + for path in folder.glob('page-*.xml') for page in [ET.parse(path).getroot()]}) + for case in manifest: + self.assertTrue(case['revision']) + original = captures[0][case['case']] + current = captures[1][case['case']] + markers = 0 + for old, new in zip(original, current, strict=True): + if new and new[0][0] == '☂': + markers += 1 + new = new[1:] + for (a, left), (b, right) in zip(old, new, strict=True): + self.assertEqual(a, b) + for key in left.keys() | right.keys(): + default = 'automatic' if key in ('color', 'highlight') else False + self.assertEqual(left.get(key, default), right.get(key, default)) + self.assertEqual(markers, int(case['remote_prefix'])) + def test_rust_joins_match_native_controls_and_retain_cold_graph_identities(self): for name, control in [('split', FIXTURE / 'joined/read'), ('inheritance', FIXTURE / 'join-edges/joined/read'), ('tags', FIXTURE / 'join-tags/joined/read')]: fixture = FIXTURE / 'rust-join' / name manifest = json.loads((fixture / 'manifest.json').read_text()) - with self.subTest(fixture=name), TemporaryDirectory() as temporary: - models = [] - for source in ('candidate', 'native/notebook'): - folder = Path(temporary) / source.replace('/', '-') - shutil.copytree(fixture / 'native/read', folder / 'read') - compare(fixture / source, folder / 'read') - subprocess.run([EXPORTER, fixture / source / 'synthetic.one', folder / 'model'], check=True) - document = json.loads((folder / 'model/document.json').read_text()) - models.append({r['nodes'][r['roots']['2']]['kind']['title']: (r, page) - for _, _, r, page in ordered_pages(document)}) - self.assertEqual(models[0].keys(), models[1].keys()) - for title, (old, page) in models[0].items(): - saved, saved_page = models[1][title] - self.assertEqual(page, saved_page) - for outline in old['nodes'][page]['children']: - if old['nodes'][outline]['kind']['type'] != 'Outline': continue - for oid, node in walk(old, outline): - self.assertEqual(saved['nodes'][oid]['children'], node['children']) - self.assertEqual(saved['nodes'][oid]['content'], node['content']) + with self.subTest(fixture=name): + self.assert_cold_graph(fixture) captures = [] for folder in (control, fixture / 'native/read'): captures.append({page.get('name'): native_characters(page, page.findall('one:Outline', ns)) -- 2.54.0