From fa4842b0710f130a915f5ae0cea755b17503825f Mon Sep 17 00:00:00 2001 From: clover caruso Date: Tue, 8 Sep 2026 13:50:06 -0700 Subject: [PATCH] feat: reconcile offline subtree moves and deletion Queue stable tree intents with observed placement, raw deletion fingerprints and replacement identities. Preserve independent remote content, require explicit review for changed deletion targets, and retain uncertain revision evidence across retries and recovery export. Migrate caches to schema eight without dropping queued work or receipts. Validated with 95 offline tests, 144 Python tests, 60 seeded twelve-client schedules and 802 ASan schedules. Three cold OneNote captures retain all 793 active objects across 39 pages. iPhone and Simulator checks with SMB, workspace Clippy and example builds pass. Assisted-by: gpt-6-astra --- corpus/outline-edit/README.md | 18 + .../offline-tree/candidate/synthetic.one | Bin 0 -> 152736 bytes corpus/outline-edit/offline-tree/cases.json | 72 ++ .../cell-delete/candidate/synthetic.one | Bin 0 -> 88240 bytes .../cell-delete/cold/commands.jsonl | 3 + .../cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../cell-delete/cold/notebook/synthetic.one | Bin 0 -> 92992 bytes .../cell-delete/cold/read/environment.json | 7 + .../cell-delete/cold/read/hierarchy.xml | 2 + .../cell-delete/cold/read/page-000.xml | 5 + .../cell-delete/cold/read/page-001.xml | 5 + .../cell-delete/cold/read/page-002.xml | 5 + .../cell-delete/cold/read/page-003.xml | 5 + .../cell-delete/cold/read/page-004.xml | 2 + .../cell-delete/cold/read/page-005.xml | 5 + .../cell-delete/cold/read/page-006.xml | 20 + .../cell-delete/cold/read/page-007.xml | 4 + .../cell-delete/cold/read/page-008.xml | 5 + .../cell-delete/cold/read/page-009.xml | 5 + .../cell-delete/cold/read/page-010.xml | 5 + .../cell-delete/cold/read/page-011.xml | 5 + .../cell-delete/cold/read/payloads.json | 1 + .../offline-tree/cell-delete/cold/run.json | 18 + .../cell-delete/cold/scripts/cold.ps1 | 1 + .../cell-delete/cold/scripts/read.ps1 | 1 + .../offline-tree/cell-delete/cold/source.json | 8 + .../cell-delete/cold/teardown.json | 1 + .../cell-move/candidate/synthetic.one | Bin 0 -> 88104 bytes .../cell-move/cold/commands.jsonl | 3 + .../cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../cell-move/cold/notebook/synthetic.one | Bin 0 -> 92856 bytes .../cell-move/cold/read/environment.json | 7 + .../cell-move/cold/read/hierarchy.xml | 2 + .../cell-move/cold/read/page-000.xml | 5 + .../cell-move/cold/read/page-001.xml | 5 + .../cell-move/cold/read/page-002.xml | 5 + .../cell-move/cold/read/page-003.xml | 5 + .../cell-move/cold/read/page-004.xml | 20 + .../cell-move/cold/read/page-005.xml | 4 + .../cell-move/cold/read/page-006.xml | 5 + .../cell-move/cold/read/page-007.xml | 4 + .../cell-move/cold/read/page-008.xml | 5 + .../cell-move/cold/read/page-009.xml | 5 + .../cell-move/cold/read/page-010.xml | 5 + .../cell-move/cold/read/page-011.xml | 5 + .../cell-move/cold/read/payloads.json | 1 + .../offline-tree/cell-move/cold/run.json | 18 + .../cell-move/cold/scripts/cold.ps1 | 1 + .../cell-move/cold/scripts/read.ps1 | 1 + .../offline-tree/cell-move/cold/source.json | 8 + .../offline-tree/cell-move/cold/teardown.json | 1 + .../offline-tree/cold/commands.jsonl | 3 + .../cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 4800 bytes .../offline-tree/cold/notebook/synthetic.one | Bin 0 -> 152736 bytes .../offline-tree/cold/read/environment.json | 7 + .../offline-tree/cold/read/hierarchy.xml | 2 + .../offline-tree/cold/read/page-000.xml | 2 + .../offline-tree/cold/read/page-001.xml | 2 + .../offline-tree/cold/read/page-002.xml | 20 + .../offline-tree/cold/read/page-003.xml | 2 + .../offline-tree/cold/read/page-004.xml | 5 + .../offline-tree/cold/read/page-005.xml | 2 + .../offline-tree/cold/read/page-006.xml | 2 + .../offline-tree/cold/read/page-007.xml | 2 + .../offline-tree/cold/read/page-008.xml | 2 + .../offline-tree/cold/read/page-009.xml | 5 + .../offline-tree/cold/read/page-010.xml | 2 + .../offline-tree/cold/read/page-011.xml | 4 + .../offline-tree/cold/read/page-012.xml | 2 + .../offline-tree/cold/read/page-013.xml | 2 + .../offline-tree/cold/read/page-014.xml | 2 + .../offline-tree/cold/read/payloads.json | 1 + .../outline-edit/offline-tree/cold/run.json | 18 + .../offline-tree/cold/scripts/cold.ps1 | 1 + .../offline-tree/cold/scripts/read.ps1 | 1 + .../offline-tree/cold/source.json | 8 + .../offline-tree/cold/teardown.json | 1 + crates/onestore-offline/README.md | 22 +- .../onestore-offline/examples/cache_probe.rs | 3 +- crates/onestore-offline/src/lib.rs | 5 +- crates/onestore-offline/src/schema.rs | 2 +- crates/onestore-offline/src/sync.rs | 25 + crates/onestore-offline/src/tree.rs | 370 +++++++++ crates/onestore-offline/tests/cache.rs | 8 +- .../tests/support/tree_schedule.rs | 246 ++++++ crates/onestore-offline/tests/sync.rs | 6 + crates/onestore-offline/tests/sync/outline.rs | 4 +- crates/onestore-offline/tests/sync/tree.rs | 716 ++++++++++++++++++ crates/onestore/src/objects.rs | 1 + crates/onestore/src/tree.rs | 12 + fuzz/Cargo.toml | 7 + fuzz/fuzz_targets/offline_tree.rs | 9 + tools/test_outline_edit.py | 10 +- 93 files changed, 1847 insertions(+), 15 deletions(-) create mode 100644 corpus/outline-edit/offline-tree/candidate/synthetic.one create mode 100644 corpus/outline-edit/offline-tree/cases.json create mode 100644 corpus/outline-edit/offline-tree/cell-delete/candidate/synthetic.one create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/commands.jsonl create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/notebook/Open Notebook.onetoc2 create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/notebook/synthetic.one create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/environment.json create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/hierarchy.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-000.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-001.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-002.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-003.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-004.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-005.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-006.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-007.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-008.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-009.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-010.xml create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/read/page-011.xml create mode 120000 corpus/outline-edit/offline-tree/cell-delete/cold/read/payloads.json create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/run.json create mode 120000 corpus/outline-edit/offline-tree/cell-delete/cold/scripts/cold.ps1 create mode 120000 corpus/outline-edit/offline-tree/cell-delete/cold/scripts/read.ps1 create mode 100644 corpus/outline-edit/offline-tree/cell-delete/cold/source.json create mode 120000 corpus/outline-edit/offline-tree/cell-delete/cold/teardown.json create mode 100644 corpus/outline-edit/offline-tree/cell-move/candidate/synthetic.one create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/commands.jsonl create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/notebook/Open Notebook.onetoc2 create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/notebook/synthetic.one create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/environment.json create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/hierarchy.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-000.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-001.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-002.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-003.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-004.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-005.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-006.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-007.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-008.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-009.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-010.xml create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/read/page-011.xml create mode 120000 corpus/outline-edit/offline-tree/cell-move/cold/read/payloads.json create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/run.json create mode 120000 corpus/outline-edit/offline-tree/cell-move/cold/scripts/cold.ps1 create mode 120000 corpus/outline-edit/offline-tree/cell-move/cold/scripts/read.ps1 create mode 100644 corpus/outline-edit/offline-tree/cell-move/cold/source.json create mode 120000 corpus/outline-edit/offline-tree/cell-move/cold/teardown.json create mode 100644 corpus/outline-edit/offline-tree/cold/commands.jsonl create mode 100644 corpus/outline-edit/offline-tree/cold/notebook/Open Notebook.onetoc2 create mode 100644 corpus/outline-edit/offline-tree/cold/notebook/synthetic.one create mode 100644 corpus/outline-edit/offline-tree/cold/read/environment.json create mode 100644 corpus/outline-edit/offline-tree/cold/read/hierarchy.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-000.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-001.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-002.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-003.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-004.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-005.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-006.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-007.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-008.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-009.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-010.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-011.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-012.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-013.xml create mode 100644 corpus/outline-edit/offline-tree/cold/read/page-014.xml create mode 120000 corpus/outline-edit/offline-tree/cold/read/payloads.json create mode 100644 corpus/outline-edit/offline-tree/cold/run.json create mode 120000 corpus/outline-edit/offline-tree/cold/scripts/cold.ps1 create mode 120000 corpus/outline-edit/offline-tree/cold/scripts/read.ps1 create mode 100644 corpus/outline-edit/offline-tree/cold/source.json create mode 120000 corpus/outline-edit/offline-tree/cold/teardown.json create mode 100644 crates/onestore-offline/src/tree.rs create mode 100644 crates/onestore-offline/tests/support/tree_schedule.rs create mode 100644 crates/onestore-offline/tests/sync/tree.rs create mode 100644 fuzz/fuzz_targets/offline_tree.rs diff --git a/corpus/outline-edit/README.md b/corpus/outline-edit/README.md index a0ee8573986ceefb25f5f676ddf57ee9dae3748d..289eb81d93d2539ecd768a063bc11f0dfea1b3f6 100644 --- a/corpus/outline-edit/README.md +++ b/corpus/outline-edit/README.md @@ -128,3 +128,21 @@ plus the `tree::tests::group_normalization_preserves_unequal_indentation_and_ove unit test. Cold-open the resulting `ordinary`, `groups-cells`, `cross-container` and `unequal-groups` notebooks with expected page counts 15, 12, 12 and 1, respectively, using `tools/native_runner.py --collect-notebook`. + +`offline-tree` reconciles moves/deletions and dependent text edits against the +fourteen ordinary native controls. Three already-converged moves confirm without +publication, seven competing structure/content changes require explicit review, +and four deleted targets retain the complete local branch. The cold capture +preserves all 247 active graph objects across fifteen pages, three tags, and +6,497 explicit character-format comparisons per image. Its `cases.json` records +the native input cases and outcomes. Regenerate with the offline sync test +`native_tree_and_layout_changes_reconcile_without_discarding_unreviewed_content`, +setting `ONESTORE_OFFLINE_TREE_OUTPUT` to a new absolute directory, then cold-open +its `candidate` with `--expected-pages 15 --collect-notebook`. + +Its `cell-delete` and `cell-move` captures additionally verify local edits to an +emptied cell's replacement paragraph while preserving remote text in the other +cell. They retain 272 and 274 active objects, respectively, with 8,201 and 8,377 +explicit format comparisons per image. Regenerate with the offline sync test +`emptied_cell_replacement_is_durable_and_cannot_be_silently_omitted_on_replay`, +using the same output variable; cold-open each candidate with twelve expected pages. diff --git a/corpus/outline-edit/offline-tree/candidate/synthetic.one b/corpus/outline-edit/offline-tree/candidate/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..685ee81cbcd88ee73564b37f6e8118bc42803213 GIT binary patch literal 152736 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 US7hK8)#dXE`E0Dm$MZ7IRQ%tmj}k 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ϕ?Ja<5PD)i+llP^b&oh^zJ`QI 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 E19B$6TL1t6 literal 0 HcmV?d00001 diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/environment.json b/corpus/outline-edit/offline-tree/cell-delete/cold/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..57f6f05726c48c3876e2a8002e33edf10ddc1bb3 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-37ACD671", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/hierarchy.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..377ee3f31f458c230ecc475dc8abc7066cc65779 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-000.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..5b596ba0cb694a935fd463c1669b51242d3bb544 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-000.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-001.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..ef35bd7d297ba0f0b5725c70f3a1b2e38986772e --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-001.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-002.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e3e1a9aeeb1cfb1545433d80ed7543a98b84903 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-002.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-003.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..91c27de6d6060425ae6c54c035cedd9d87c4596c --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-003.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-004.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..e1b4293c682ad863ef826df86205f1501a380e5d --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-004.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-005.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..28bd3aaffb53138691a0a0c0274ac6189af15863 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-005.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-006.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-006.xml new file mode 100644 index 0000000000000000000000000000000000000000..6db2eb3af060b96524dd1cb35b0387bd43c48e84 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-006.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-007.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-007.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ff4c27aa74a5bc66687b4fd112675d297eefdcf --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-007.xml @@ -0,0 +1,4 @@ + +Target 🦀 é Link label]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-008.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-008.xml new file mode 100644 index 0000000000000000000000000000000000000000..d1192626314920b26ae68505cab85dc39ca6999c --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-008.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-009.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-009.xml new file mode 100644 index 0000000000000000000000000000000000000000..2efd5ef0591f702be1709aa514214ac97c956bd3 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-009.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-010.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-010.xml new file mode 100644 index 0000000000000000000000000000000000000000..e66be2846ed280e83f5b57fbe02750ddababbac6 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-010.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-011.xml b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-011.xml new file mode 100644 index 0000000000000000000000000000000000000000..174806a0ca3f05c5e56ed253b2a1a9fd485c2943 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/page-011.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/read/payloads.json b/corpus/outline-edit/offline-tree/cell-delete/cold/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..28e766c3d4f4499afc8ee14682bf4467ff3087cd --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/read/payloads.json @@ -0,0 +1 @@ +../../../../../paragraph-edit/before/read/payloads.json \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/run.json b/corpus/outline-edit/offline-tree/cell-delete/cold/run.json new file mode 100644 index 0000000000000000000000000000000000000000..94b34a8c1b76c8573dd004991339daef6ad62693 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-tree-native-01/cell-delete/candidate", + "expected_pages": 12, + "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/outline-edit/offline-tree/cell-delete/cold/scripts/cold.ps1 b/corpus/outline-edit/offline-tree/cell-delete/cold/scripts/cold.ps1 new file mode 120000 index 0000000000000000000000000000000000000000..9b4c65b63ddad6e65d7acb85fb7d0accbb23d030 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/scripts/cold.ps1 @@ -0,0 +1 @@ +../../../../../paragraph-edit/reconciliation/keyboard/scripts/cold.ps1 \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/scripts/read.ps1 b/corpus/outline-edit/offline-tree/cell-delete/cold/scripts/read.ps1 new file mode 120000 index 0000000000000000000000000000000000000000..113263f9c23ecc3cafa21407510de560fdc964a8 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/scripts/read.ps1 @@ -0,0 +1 @@ +../../../../../paragraph-edit/reconciliation/keyboard/scripts/read.ps1 \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/source.json b/corpus/outline-edit/offline-tree/cell-delete/cold/source.json new file mode 100644 index 0000000000000000000000000000000000000000..7baa2ca5d5742c75adb26f380f51d8279111a589 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 88240, + "sha256": "963f5c960c690ff21451787f2a0028573cdc3ce4edeb887a8ed115997fcda194", + "mtime_ns": 1788901194571318513 + } +] diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/teardown.json b/corpus/outline-edit/offline-tree/cell-delete/cold/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..f87f229e17cdf751396fcf149ad2624727a29624 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-delete/cold/teardown.json @@ -0,0 +1 @@ +../../../offline/cold/teardown.json \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-move/candidate/synthetic.one b/corpus/outline-edit/offline-tree/cell-move/candidate/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..a803314f1105069601bb012294d0722b18e1b10d GIT binary patch literal 88104 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 literal 0 HcmV?d00001 diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/commands.jsonl b/corpus/outline-edit/offline-tree/cell-move/cold/commands.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..81ecca46b8bb05edac92ed89d4e159e008835478 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/commands.jsonl @@ -0,0 +1,3 @@ +{"command": "powershell -NoProfile -Command \"Expand-Archive -LiteralPath C:\\one-tests\\transfer.zip -DestinationPath C:\\one-tests\\runs\\capture\\notebook\"", "exit": 0, "stdout": "", "stderr": "", "error": null} +{"command": "powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\\one-tests\\read-current.ps1 -Root C:\\one-tests\\runs\\capture -CloneHost ONE-M6-B3E79CAE -ExpectedPages 12", "exit": 0, "stdout": "Read 1 sections and 12 pages.\r\n", "stderr": "", "error": null} +{"command": "powershell -NoProfile -Command \"Compress-Archive -Force -Path C:\\one-tests\\runs\\capture\\* -DestinationPath C:\\one-tests\\captured.zip\"", "exit": 0, "stdout": "", "stderr": "", "error": null} diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/notebook/Open Notebook.onetoc2 b/corpus/outline-edit/offline-tree/cell-move/cold/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..ea8defc64e1d250d13f34869bf8c6a720fd221e1 GIT binary patch literal 4800 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 LD5StYMuGnUO17iK literal 0 HcmV?d00001 diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/environment.json b/corpus/outline-edit/offline-tree/cell-move/cold/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..5f9e3bff82977d360ee0e0c0fe8be18ce8df7562 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-B3E79CAE", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/hierarchy.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..b1ec5d7d4a92fcdadbcefffbe6a3d93a9ac9470a --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-000.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..38a5fe2bc583842c23c5f3c5d06c4fdb7498fca2 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-000.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-001.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c7868edb0e5ad2e0da9c32d46da4a5c71dab36c --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-001.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-002.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..d87dec3e9ec72b23d1da613f0bc6ac5d7d8a4741 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-002.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-003.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..61258b17bd3b4696470e45fd15b2238e85102c8c --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-003.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-004.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..77144bad3020ab4aea23da62a3a7fb2bf2442ec4 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-004.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-005.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6691b8df4f4c92c62bd3dc9ca08b5399205b54e --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-005.xml @@ -0,0 +1,4 @@ + +Target 🦀 é Link label]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-006.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-006.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc9c3f123f7066f05b7badef1177ef90c5866da5 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-006.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-007.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-007.xml new file mode 100644 index 0000000000000000000000000000000000000000..2043c5c8487baf35d348cc326f6cd4f6150c0ba1 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-007.xml @@ -0,0 +1,4 @@ + +Target 🦀 é Link label]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-008.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-008.xml new file mode 100644 index 0000000000000000000000000000000000000000..815993c199fc421ebf87eb5d7d4ae31ecbbef2bb --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-008.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-009.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-009.xml new file mode 100644 index 0000000000000000000000000000000000000000..53301e198094d41179ff16c32690f920984e389a --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-009.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-010.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-010.xml new file mode 100644 index 0000000000000000000000000000000000000000..8d83e900f90dc4d3d4673b33832070e3b1f88f54 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-010.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/page-011.xml b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-011.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a31def0593f8b0ea52c4f12eb9b9c2fcd79f512 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/page-011.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/read/payloads.json b/corpus/outline-edit/offline-tree/cell-move/cold/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..28e766c3d4f4499afc8ee14682bf4467ff3087cd --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/read/payloads.json @@ -0,0 +1 @@ +../../../../../paragraph-edit/before/read/payloads.json \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/run.json b/corpus/outline-edit/offline-tree/cell-move/cold/run.json new file mode 100644 index 0000000000000000000000000000000000000000..90033d1c9018364ba72c03d6e54278b7b2e33c12 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-tree-native-01/cell-move/candidate", + "expected_pages": 12, + "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/outline-edit/offline-tree/cell-move/cold/scripts/cold.ps1 b/corpus/outline-edit/offline-tree/cell-move/cold/scripts/cold.ps1 new file mode 120000 index 0000000000000000000000000000000000000000..9b4c65b63ddad6e65d7acb85fb7d0accbb23d030 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/scripts/cold.ps1 @@ -0,0 +1 @@ +../../../../../paragraph-edit/reconciliation/keyboard/scripts/cold.ps1 \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/scripts/read.ps1 b/corpus/outline-edit/offline-tree/cell-move/cold/scripts/read.ps1 new file mode 120000 index 0000000000000000000000000000000000000000..113263f9c23ecc3cafa21407510de560fdc964a8 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/scripts/read.ps1 @@ -0,0 +1 @@ +../../../../../paragraph-edit/reconciliation/keyboard/scripts/read.ps1 \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/source.json b/corpus/outline-edit/offline-tree/cell-move/cold/source.json new file mode 100644 index 0000000000000000000000000000000000000000..d521823056591867a7a1141208e263d8ee1c447d --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 88104, + "sha256": "0d50bcef1e1b80d7920777e4734412e7549c484972aac0d9fbb313757ff85929", + "mtime_ns": 1788901195424267841 + } +] diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/teardown.json b/corpus/outline-edit/offline-tree/cell-move/cold/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..f87f229e17cdf751396fcf149ad2624727a29624 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cell-move/cold/teardown.json @@ -0,0 +1 @@ +../../../offline/cold/teardown.json \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cold/commands.jsonl b/corpus/outline-edit/offline-tree/cold/commands.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..1a23ac47beb5b14ed3a96021c3be08de87442207 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/commands.jsonl @@ -0,0 +1,3 @@ +{"command": "powershell -NoProfile -Command \"Expand-Archive -LiteralPath C:\\one-tests\\transfer.zip -DestinationPath C:\\one-tests\\runs\\capture\\notebook\"", "exit": 0, "stdout": "", "stderr": "", "error": null} +{"command": "powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\\one-tests\\read-current.ps1 -Root C:\\one-tests\\runs\\capture -CloneHost ONE-M6-7605A4F1 -ExpectedPages 15", "exit": 0, "stdout": "Read 1 sections and 15 pages.\r\n", "stderr": "", "error": null} +{"command": "powershell -NoProfile -Command \"Compress-Archive -Force -Path C:\\one-tests\\runs\\capture\\* -DestinationPath C:\\one-tests\\captured.zip\"", "exit": 0, "stdout": "", "stderr": "", "error": null} diff --git a/corpus/outline-edit/offline-tree/cold/notebook/Open Notebook.onetoc2 b/corpus/outline-edit/offline-tree/cold/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..9bcfeb67122a90d8d83001106c707f0fe7bbaebe GIT binary patch literal 4800 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 IxsUJv0eT0c5dZ)H literal 0 HcmV?d00001 diff --git a/corpus/outline-edit/offline-tree/cold/read/environment.json b/corpus/outline-edit/offline-tree/cold/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..09566e094a43f1176d82def6c60999341cb85f71 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-7605A4F1", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/outline-edit/offline-tree/cold/read/hierarchy.xml b/corpus/outline-edit/offline-tree/cold/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..8c6ea32186c6f9c27481a971ee09b04fe417bcac --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-000.xml b/corpus/outline-edit/offline-tree/cold/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..f7088b5d78d77ba3aa02e2ffb7b32689e46ac4b1 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-000.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-001.xml b/corpus/outline-edit/offline-tree/cold/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..38017a1d7fcc9df5640c30590885df703022fecb --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-001.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-002.xml b/corpus/outline-edit/offline-tree/cold/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..67c2e52e667222d5ed459ddbd833d3fb2f74a0aa --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-002.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/outline-edit/offline-tree/cold/read/page-003.xml b/corpus/outline-edit/offline-tree/cold/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..e91b1202b3ef808c70f19f6c39458a644cb3f514 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-003.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-004.xml b/corpus/outline-edit/offline-tree/cold/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..c2da7d7bb0f0b72af82e63c463aa418226fa5334 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-004.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cold/read/page-005.xml b/corpus/outline-edit/offline-tree/cold/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..b97a3beace587830b849c7b2f0a035e8c0330211 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-005.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-006.xml b/corpus/outline-edit/offline-tree/cold/read/page-006.xml new file mode 100644 index 0000000000000000000000000000000000000000..8504acda4447ca06dfe8de1184aabbe2473016db --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-006.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-007.xml b/corpus/outline-edit/offline-tree/cold/read/page-007.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa15f615fbd3e6a0371999a8c6e01b504db9384b --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-007.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-008.xml b/corpus/outline-edit/offline-tree/cold/read/page-008.xml new file mode 100644 index 0000000000000000000000000000000000000000..547b18ec2cd492e08b9301773a695a682eb7a913 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-008.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-009.xml b/corpus/outline-edit/offline-tree/cold/read/page-009.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c09d1e66df39b3e75ebc3e209dfcd66b8bcee0c --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-009.xml @@ -0,0 +1,5 @@ + +Target 🦀 é Link label]]>Child]]> diff --git a/corpus/outline-edit/offline-tree/cold/read/page-010.xml b/corpus/outline-edit/offline-tree/cold/read/page-010.xml new file mode 100644 index 0000000000000000000000000000000000000000..91d86124956dc049a7c3d38d991faa64ac14088f --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-010.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-011.xml b/corpus/outline-edit/offline-tree/cold/read/page-011.xml new file mode 100644 index 0000000000000000000000000000000000000000..08fc27b702e86ce0c9489b31480b77f1ea191e60 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-011.xml @@ -0,0 +1,4 @@ + +Target 🦀 é Link label]]> diff --git a/corpus/outline-edit/offline-tree/cold/read/page-012.xml b/corpus/outline-edit/offline-tree/cold/read/page-012.xml new file mode 100644 index 0000000000000000000000000000000000000000..8352935a309b73e0da8789b9b9a19c7b9116875a --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-012.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-013.xml b/corpus/outline-edit/offline-tree/cold/read/page-013.xml new file mode 100644 index 0000000000000000000000000000000000000000..7dc3e80cd912dc5034c0d493d5ec9ff103fe088c --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-013.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/page-014.xml b/corpus/outline-edit/offline-tree/cold/read/page-014.xml new file mode 100644 index 0000000000000000000000000000000000000000..5c5c21da02c4028ec2c40f07a2c615607d1f3c63 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/page-014.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/outline-edit/offline-tree/cold/read/payloads.json b/corpus/outline-edit/offline-tree/cold/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..9e1be3e2b6d87478e7c48d278ecac8ee6c97f6d0 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/read/payloads.json @@ -0,0 +1 @@ +../../../../paragraph-edit/before/read/payloads.json \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cold/run.json b/corpus/outline-edit/offline-tree/cold/run.json new file mode 100644 index 0000000000000000000000000000000000000000..c416e28bcfe053dd9dafaed85cdcc408f344d922 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/evidence/m10/offline-tree-native-01/candidate", + "expected_pages": 15, + "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/outline-edit/offline-tree/cold/scripts/cold.ps1 b/corpus/outline-edit/offline-tree/cold/scripts/cold.ps1 new file mode 120000 index 0000000000000000000000000000000000000000..5bc2f1837e1f0b639923a80b79c517c98c5c519a --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/scripts/cold.ps1 @@ -0,0 +1 @@ +../../../../paragraph-edit/reconciliation/keyboard/scripts/cold.ps1 \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cold/scripts/read.ps1 b/corpus/outline-edit/offline-tree/cold/scripts/read.ps1 new file mode 120000 index 0000000000000000000000000000000000000000..85257c76cede599f47da88e69419a767dd6b99ee --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/scripts/read.ps1 @@ -0,0 +1 @@ +../../../../paragraph-edit/reconciliation/keyboard/scripts/read.ps1 \ No newline at end of file diff --git a/corpus/outline-edit/offline-tree/cold/source.json b/corpus/outline-edit/offline-tree/cold/source.json new file mode 100644 index 0000000000000000000000000000000000000000..1e424af0fe0483cb5c76015ea425e248ea4d25bb --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/source.json @@ -0,0 +1,8 @@ +[ + { + "path": "synthetic.one", + "bytes": 152736, + "sha256": "c724b5590d30d8a2ba5d12a25ba1e62bb05792947fd5405b65e68e9b2ae7c256", + "mtime_ns": 1788900756034686311 + } +] diff --git a/corpus/outline-edit/offline-tree/cold/teardown.json b/corpus/outline-edit/offline-tree/cold/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..a9088cc9e6bf00c88849f584d2a4967ba2372903 --- /dev/null +++ b/corpus/outline-edit/offline-tree/cold/teardown.json @@ -0,0 +1 @@ +../../offline/cold/teardown.json \ No newline at end of file diff --git a/crates/onestore-offline/README.md b/crates/onestore-offline/README.md index 7d0731b71d643b3b794b88222bb4926d578e6961..a283e6034e093233f7b14a5c2680b71fee2dc49f 100644 --- a/crates/onestore-offline/README.md +++ b/crates/onestore-offline/README.md @@ -31,7 +31,8 @@ its styles as one intent and one publication. Keep that value across retries; it the new text for subsequent offline edits. Pending entries expose `Operation::Text(TextEdit)`, `Operation::Insert(Insertion)`, `Operation::Format(FormatEdit)`, `Operation::Split(SplitEdit)`, -`Operation::Join(JoinEdit)` and `Operation::Outline(OutlineEdit)` through their +`Operation::Join(JoinEdit)`, `Operation::Outline(OutlineEdit)` and +`Operation::Tree(TreeEdit)` 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. @@ -98,8 +99,23 @@ reserved wrapping width that they clear. Missing targets preserve the local bran against both current images, preserving dependent intents. An uncertain layout attempt requires its original revision; converged values cannot establish its receipt. -Recognized earlier caches migrate transactionally to version seven, which adds -layout intents and layout conflicts. The migration retains +`tree` accepts the core `onestore::TreeEdit`. Moves preserve independent remote +text, formatting and descendants. A competing ancestor, indentation or sibling +crossing produces `StructureChanged`; unrelated sibling insertions/deletions can +merge. An anchor must remain a direct child of the requested destination. An +already satisfied move still requires guarded confirmation before acknowledgement. +Deletion compares the selected raw property graph, including referenced styles, +tags, unknown fields and internal attachments. Changed content produces +`ContentChanged`; property order, CompactID numbering and modification timestamps +do not affect that comparison. Missing targets retain `TargetUnavailable`. +`rebase_tree_conflict(id, local, remote)` reviews the original move/deletion against +both current images. An emptied cell's replacement paragraph/text identities must +remain the same before replay or review; later queued edits keep their targets. +Uncertain tree attempts require their original revision for confirmation, even +when an independent move or deletion has the same visible effect. + +Recognized earlier caches migrate transactionally to version eight, which adds +tree intents and content 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 4d5b54d41d963123843e4bbea3e58f1abeffbff8..d7ab493d9e48d0f610994266a1a9cc32b6cb2f68 100644 --- a/crates/onestore-offline/examples/cache_probe.rs +++ b/crates/onestore-offline/examples/cache_probe.rs @@ -140,7 +140,8 @@ fn main() -> Result<(), Box> { } onestore_offline::Operation::Split(_) | onestore_offline::Operation::Join(_) - | onestore_offline::Operation::Outline(_) => { + | onestore_offline::Operation::Outline(_) + | onestore_offline::Operation::Tree(_) => { panic!("Unexpected operation for this fixture") } }; diff --git a/crates/onestore-offline/src/lib.rs b/crates/onestore-offline/src/lib.rs index 37944b6343929b25dd30da6648ff374dd40137e3..28746754a78fe2c29ed534a70270b6ddf6b31434 100644 --- a/crates/onestore-offline/src/lib.rs +++ b/crates/onestore-offline/src/lib.rs @@ -15,10 +15,12 @@ mod paragraph; mod rebase; mod recovery; mod schema; +mod tree; pub use formatting::FormatEdit; pub use outline::OutlineEdit; pub use paragraph::{JoinEdit, SplitEdit}; pub use recovery::{Recovery, RecoverySummary}; +pub use tree::TreeEdit; mod sync; pub use sync::{ConflictKind, EditStatus, Remote}; mod worker; @@ -49,7 +51,7 @@ pub enum Error { type Result = std::result::Result; const APPLICATION_ID: u32 = 0x4f4e454f; -const SCHEMA_VERSION: u32 = 7; +const SCHEMA_VERSION: u32 = 8; /// Text and its observed precondition, retained across cache reopen and rebasing. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] @@ -70,6 +72,7 @@ pub enum Operation { Split(SplitEdit), Join(JoinEdit), Outline(OutlineEdit), + Tree(TreeEdit), } /// A locally acknowledged intent; its ID remains stable across cache reopen. diff --git a/crates/onestore-offline/src/schema.rs b/crates/onestore-offline/src/schema.rs index 224fc70e06b40e9c55b14d76acb3dddb4733293c..ecbbb5b526c81f4247c9e7cbb1942f49223d89bf 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 5) + kind INTEGER NOT NULL CHECK(kind BETWEEN 0 AND 6) ) STRICT;"; const ASSETS: &str = "CREATE TABLE assets ( diff --git a/crates/onestore-offline/src/sync.rs b/crates/onestore-offline/src/sync.rs index dc58cfc652e30f1c51dd4f479a8e8fdb95428027..1e550bf9bc31a836be899bb3ee07648c2eedf46c 100644 --- a/crates/onestore-offline/src/sync.rs +++ b/crates/onestore-offline/src/sync.rs @@ -20,6 +20,7 @@ pub enum ConflictKind { FormattingChanged = 3, StructureChanged = 4, LayoutChanged = 5, + ContentChanged = 6, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -136,6 +137,7 @@ impl Replica { Operation::Split(edit) => edit.prepare(&snapshot, intent.space)?, Operation::Join(edit) => edit.prepare(&snapshot, intent.space)?, Operation::Outline(edit) => edit.prepare(&snapshot, intent.space)?, + Operation::Tree(edit) => edit.prepare(&snapshot, intent.space)?, Operation::Insert(insertion) => { PreparedEdit::insert(&snapshot, intent.space, insertion) .map_err(|_| ConflictKind::UnsupportedEdit) @@ -306,6 +308,13 @@ impl Replica { ) .into()); } + Operation::Tree(_) => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Review the subtree edit using rebase_tree_conflict", + ) + .into()); + } Operation::Insert(_) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -398,6 +407,21 @@ impl Replica { }) } + /// Reviews the original subtree intent against both current cache images. + /// Replacement paragraph identities must remain unchanged for dependent edits. + pub fn rebase_tree_conflict(&self, id: u64, local: &[u8], remote: &[u8]) -> Result<()> { + self.resolve_conflict(id, local, remote, |intent| { + let Operation::Tree(edit) = intent.operation else { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Select a subtree move or deletion conflict", + ) + .into()); + }; + Ok(Operation::Tree(edit.review(remote, intent.space)?)) + }) + } + fn resolve_conflict( &self, id: u64, @@ -519,6 +543,7 @@ pub(crate) fn status(connection: &Connection, id: u64) -> Result ConflictKind::FormattingChanged, 4 => ConflictKind::StructureChanged, 5 => ConflictKind::LayoutChanged, + 6 => ConflictKind::ContentChanged, _ => { return Err(io::Error::new( io::ErrorKind::InvalidData, diff --git a/crates/onestore-offline/src/tree.rs b/crates/onestore-offline/src/tree.rs new file mode 100644 index 0000000000000000000000000000000000000000..614f6f3b7597263331c76c8b45392a6a8d247e83 --- /dev/null +++ b/crates/onestore-offline/src/tree.rs @@ -0,0 +1,370 @@ +use super::*; +use onestore::{FileDataReference, IdStream, ObjectData, PropertySets, ResolvedRevision, Value}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::collections::{BTreeMap, BTreeSet}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct Observed { + path: Vec<(ExGuid, u8)>, + siblings: BTreeMap, + destination: Vec<(ExGuid, u8)>, + content: Option<[u8; 32]>, +} + +/// A subtree intent with observed placement, deletion content and replacement identities. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TreeEdit { + pub intent: onestore::TreeEdit, + observed: Observed, + created: BTreeSet, +} + +fn fingerprint(store: &Store<'_>, raw: &ResolvedRevision<'_>, root: ExGuid) -> Result<[u8; 32]> { + let mut objects = BTreeMap::new(); + let mut pending = vec![root]; + while let Some(id) = pending.pop() { + if objects.contains_key(&id) { + continue; + } + let object = &raw.objects[&id]; + let references = object.references()?; + pending.extend(&references.objects); + let mut hash = Sha256::new(); + hash.update(object.jcid.to_le_bytes()); + match object.data { + ObjectData::Properties(bytes) => { + hash.update([0]); + let properties = PropertySets::parse(bytes)?; + let mut objects = references.objects.into_iter(); + let mut spaces = references.object_spaces.into_iter(); + let mut contexts = references.contexts.into_iter(); + let mut fields = Vec::new(); + for set in &properties.sets { + let mut values = BTreeMap::new(); + for property in set { + let mut value = Sha256::new(); + match &property.value { + Value::NoData => {} + Value::Bytes(bytes) => value.update(bytes), + Value::References { + stream, + compact_ids, + } => { + let references = match stream { + IdStream::Objects => &mut objects, + IdStream::ObjectSpaces => &mut spaces, + IdStream::Contexts => &mut contexts, + }; + for reference in references.take(compact_ids.len() / 4) { + value.update(reference.guid); + value.update(reference.n.to_le_bytes()); + } + } + Value::Sets(_) => {} + } + if property.id != 0x14001d7a { + values.insert(property.id, value); + } + } + fields.push(values); + } + // Arena indices and CompactIDs can change without changing property content. + let mut sets = vec![[0; 32]; properties.sets.len()]; + for at in (0..properties.sets.len()).rev() { + for property in &properties.sets[at] { + if let Value::Sets(children) = &property.value { + let value = fields[at].get_mut(&property.id).unwrap(); + for child in children.clone() { + value.update(sets[child]); + } + } + } + let mut set = Sha256::new(); + for (id, value) in &fields[at] { + set.update(id.to_le_bytes()); + set.update(value.clone().finalize()); + } + sets[at] = set.finalize().into(); + } + hash.update(sets[0]); + } + ObjectData::File { + reference, + extension, + } => { + hash.update([1]); + hash.update(Sha256::digest(reference)); + hash.update(Sha256::digest(extension)); + if let Some(FileDataReference::Internal(guid)) = object.file_reference()? { + hash.update(Sha256::digest(store.file_data(guid)?)); + } + } + ObjectData::Encrypted(_) => unreachable!("references rejected encrypted content"), + } + objects.insert(id, <[u8; 32]>::from(hash.finalize())); + } + let mut hash = Sha256::new(); + for (id, value) in objects { + hash.update(id.guid); + hash.update(id.n.to_le_bytes()); + hash.update(value); + } + Ok(hash.finalize().into()) +} + +fn observe(source: &[u8], space: ExGuid, intent: &onestore::TreeEdit) -> 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(rid) = section.contexts.get(&ExGuid::default()) else { + return Ok(None); + }; + let view = §ion.revisions[rid]; + let pages: Vec<_> = document + .pages()? + .into_iter() + .filter_map(|(sid, page)| (sid == space).then_some(page)) + .collect(); + if pages.len() != 1 { + return Ok(None); + } + let object = intent.object(); + let mut targets = vec![object]; + if let Some((parent, _)) = intent.destination() { + targets.push(parent); + } + let Some(paths) = active_paths(view, &pages, &targets) else { + return Ok(None); + }; + let Some(parent) = paths[0].first() else { + return Ok(None); + }; + let children = &view.nodes[parent].children; + let Some(position) = children.iter().position(|id| *id == object) else { + return Ok(None); + }; + let levels = |path: &[ExGuid]| { + path.iter() + .map(|id| (*id, view.nodes[id].child_level.unwrap_or(1))) + .collect::>() + }; + let destination = if let Some((parent, _)) = intent.destination() { + levels(&[&[parent], paths[1].as_slice()].concat()) + } else { + Vec::new() + }; + Ok(Some(Observed { + path: levels(&paths[0]), + siblings: children + .iter() + .enumerate() + .filter_map(|(at, id)| (*id != object).then_some((*id, at < position))) + .collect(), + destination, + content: if intent.destination().is_none() { + Some(fingerprint(&store, &index.resolve(space, *rid)?, object)?) + } else { + None + }, + })) +} + +fn mutable_objects(source: &[u8], space: ExGuid) -> Result> { + let store = Store::parse(source)?; + let index = RevisionIndex::parse(&store)?; + let raw = index.resolve(space, index.spaces[&space].labels[&(ExGuid::default(), 1)])?; + Ok(raw + .reachable()? + .into_iter() + .filter(|id| raw.objects[id].jcid & 0x100000 == 0) + .collect()) +} + +impl Replica { + /// Queues a move or deletion, retaining content changes for explicit deletion review. + pub fn tree( + &self, + source: &[u8], + space: ExGuid, + intent: &onestore::TreeEdit, + ) -> Result> { + let (edit, prepared) = TreeEdit::capture(source, space, intent)?; + self.record(source, space, Operation::Tree(edit), &prepared) + } +} + +impl TreeEdit { + pub(crate) fn capture<'a>( + source: &'a [u8], + space: ExGuid, + intent: &onestore::TreeEdit, + ) -> Result<(Self, PreparedEdit<'a>)> { + let prepared = PreparedEdit::tree(source, space, intent)?; + let observed = observe(source, space, intent)?.ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidData, + "Prepared subtree edit has no active target", + ) + })?; + let before = mutable_objects(source, space)?; + let after = mutable_objects(prepared.as_bytes(), space)?; + Ok(( + Self { + intent: intent.clone(), + observed, + created: &after - &before, + }, + prepared, + )) + } + + pub(crate) fn prepare<'a>( + &self, + source: &'a [u8], + space: ExGuid, + ) -> Result, ConflictKind>> { + let Some(current) = observe(source, space, &self.intent)? else { + return Ok(Err(ConflictKind::TargetUnavailable)); + }; + let prepared = match PreparedEdit::tree(source, space, &self.intent) { + Ok(prepared) => prepared, + Err(_) => return Ok(Err(ConflictKind::UnsupportedEdit)), + }; + let after = mutable_objects(prepared.as_bytes(), space)?; + if prepared.as_bytes() == source { + return Ok(if self.created.is_subset(&after) { + Ok(prepared) + } else { + Err(ConflictKind::StructureChanged) + }); + } + if current.path != self.observed.path + || current.destination != self.observed.destination + || current.siblings.iter().any(|(id, before)| { + self.observed + .siblings + .get(id) + .is_some_and(|was_before| before != was_before) + }) + || &after - &mutable_objects(source, space)? != self.created + { + return Ok(Err(ConflictKind::StructureChanged)); + } + if current.content != self.observed.content { + return Ok(Err(ConflictKind::ContentChanged)); + } + Ok(Ok(prepared)) + } + + pub(crate) fn review(&self, source: &[u8], space: ExGuid) -> Result { + let (reviewed, _) = Self::capture(source, space, &self.intent)?; + if reviewed.created != self.created { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "The subtree edit would change its replacement paragraph identities", + ) + .into()); + } + Ok(reviewed) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use onestore::Object; + use std::sync::Arc; + + fn set(fields: &[(u32, Vec)]) -> Vec { + let mut bytes = u16::try_from(fields.len()).unwrap().to_le_bytes().to_vec(); + for (id, _) in fields { + bytes.extend(id.to_le_bytes()); + } + for (_, value) in fields { + bytes.extend(value); + } + bytes + } + + #[test] + fn deletion_fingerprint_resolves_references_and_nested_sets_without_storage_order() { + let source = onestore::create_section("fingerprint.one", "Original", "Author").unwrap(); + let store = Store::parse(&source).unwrap(); + let root = ExGuid { + guid: [1; 16], + n: 1, + }; + let child = ExGuid { + guid: [2; 16], + n: 7, + }; + let hash = |reverse: bool, global: u32, timestamp: u32, change: usize| { + let mut fields = vec![ + (0x14001d7a, timestamp.to_le_bytes().to_vec()), + (0x20000001, vec![]), + ( + 0x44000002, + set(&[(0x14000003, (u32::from(change == 1)).to_le_bytes().to_vec())]), + ), + ( + 0x44000004, + set(&[(if change == 2 { 0x08000005 } else { 0x88000005 }, vec![])]), + ), + ]; + if reverse { + fields.reverse(); + } + let mut bytes = 0x80000001_u32.to_le_bytes().to_vec(); + bytes.extend(((global << 8) | child.n).to_le_bytes()); + bytes.extend(set(&fields)); + let mut child_bytes = 0x80000000_u32.to_le_bytes().to_vec(); + child_bytes.extend(set(&[( + 0x14000006, + (u32::from(change == 3)).to_le_bytes().to_vec(), + )])); + let ids = Arc::new(BTreeMap::from([( + global, + if change == 4 { [3; 16] } else { child.guid }, + )])); + let target = ExGuid { + guid: ids[&global], + ..child + }; + let raw = ResolvedRevision { + roots: BTreeMap::from([(1, root)]), + objects: BTreeMap::from([ + ( + root, + Object { + jcid: 0x6000d, + reference_count: 1, + data: ObjectData::Properties(&bytes), + global_ids: ids.clone(), + }, + ), + ( + target, + Object { + jcid: 0x6000e, + reference_count: 1, + data: ObjectData::Properties(&child_bytes), + global_ids: ids, + }, + ), + ]), + }; + fingerprint(&store, &raw, root).unwrap() + }; + let original = hash(false, 0, 1, 0); + assert_eq!(original, hash(true, 137, 2, 0)); + for change in 1..=4 { + assert_ne!(original, hash(true, 137, 2, change)); + } + } +} diff --git a/crates/onestore-offline/tests/cache.rs b/crates/onestore-offline/tests/cache.rs index 53fc7a27210003c8bc9faed284c3987f4fd75a0a..ab72febb3523fb4460b9eeb790d3709f98a96d46 100644 --- a/crates/onestore-offline/tests/cache.rs +++ b/crates/onestore-offline/tests/cache.rs @@ -796,8 +796,8 @@ fn unrecognized_persisted_operations_are_rejected_without_dropping_fields() { } #[test] -fn prior_schema_migrations_retain_queue_evidence_assets_and_enable_layout_conflicts() { - for (version, ceiling) in [(5, 3), (6, 4)] { +fn prior_schema_migrations_retain_queue_evidence_assets_and_enable_content_conflicts() { + for (version, ceiling) in [(5, 3), (6, 4), (7, 5)] { use onestore_offline::{ConflictKind, EditStatus, Recovery}; use sha2::{Digest, Sha256}; let directory = tempfile::tempdir().unwrap(); @@ -903,13 +903,13 @@ fn prior_schema_migrations_retain_queue_evidence_assets_and_enable_layout_confli .unwrap(), current_version ); - db.execute("INSERT INTO conflicts VALUES (1001,5)", []) + db.execute("INSERT INTO conflicts VALUES (1001,6)", []) .unwrap(); drop(db); let cache = Replica::open(&path).unwrap(); assert_eq!( cache.status(1001).unwrap(), - Some(EditStatus::Conflict(ConflictKind::LayoutChanged)) + Some(EditStatus::Conflict(ConflictKind::ContentChanged)) ); } } diff --git a/crates/onestore-offline/tests/support/tree_schedule.rs b/crates/onestore-offline/tests/support/tree_schedule.rs new file mode 100644 index 0000000000000000000000000000000000000000..015711a85d75145ba36d6ec292eadbe16996fd38 --- /dev/null +++ b/crates/onestore-offline/tests/support/tree_schedule.rs @@ -0,0 +1,246 @@ +use crate::disk; +use onestore::{ + CommitError, ExGuid, Insertion, PreparedEdit, RevisionIndex, Store, TreeEdit, + document::{Document, Kind}, +}; +use onestore_offline::{EditStatus, Operation, Remote, Replica}; +use std::{io, sync::LazyLock}; + +static SOURCE: LazyLock<(Vec, ExGuid, ExGuid)> = LazyLock::new(|| { + let mut source = + onestore::create_section("tree-schedule.one", "Original 🦀 é 0", "Author").unwrap(); + let store = Store::parse(&source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let (sid, page) = document.pages().unwrap()[0]; + let space = &document.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(); + for at in 1..12 { + let insert = + Insertion::paragraph(outline, None, &format!("Original 🦀 é {at}"), "Author").unwrap(); + source = PreparedEdit::insert(&source, sid, &insert) + .unwrap() + .as_bytes() + .to_vec(); + } + (source, sid, outline) +}); + +fn rows(source: &[u8]) -> Vec<(ExGuid, ExGuid, String)> { + let (_, sid, outline) = &*SOURCE; + let store = Store::parse(source).unwrap(); + assert!(store.checksum_mismatches.is_empty()); + let index = RevisionIndex::parse(&store).unwrap(); + index.validate_current().unwrap(); + let document = Document::parse(&index).unwrap(); + let space = &document.spaces[sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let (_, page) = document + .pages() + .unwrap() + .into_iter() + .find(|(space, _)| space == sid) + .unwrap(); + if !view.nodes[&page].children.contains(outline) { + return Vec::new(); + } + let node = &view.nodes[outline]; + let mut rows = Vec::new(); + for paragraph in &node.children { + let node = &view.nodes[paragraph]; + assert!(node.children.is_empty()); + let [text] = node.content.as_slice() else { + panic!() + }; + let Kind::RichText { text: value, .. } = &view.nodes[text].kind else { + panic!() + }; + rows.push((*paragraph, *text, value.clone())); + } + rows +} + +struct Session<'a> { + disk: &'a mut disk::Disk, + operation: Option<&'a Operation>, +} + +impl Remote for Session<'_> { + fn read(&mut self) -> io::Result> { + Ok(self.disk.visible.clone()) + } + fn publish(&mut self, edit: &PreparedEdit<'_>) -> Result<(), CommitError> { + let before = rows(&self.disk.visible); + let mut expected = before.clone(); + match self.operation.unwrap() { + Operation::Tree(edit) => { + let at = expected + .iter() + .position(|(id, _, _)| *id == edit.intent.object()) + .unwrap(); + let row = expected.remove(at); + if let Some((parent, anchor)) = edit.intent.destination() { + assert_eq!(parent, SOURCE.2); + let at = anchor + .map(|anchor| { + expected + .iter() + .position(|(id, _, _)| *id == anchor) + .unwrap() + }) + .unwrap_or(expected.len()); + expected.insert(at, row); + } + } + Operation::Text(edit) => { + assert_eq!(edit.range, 0..1); + let (_, _, text) = expected + .iter_mut() + .find(|(_, id, _)| *id == edit.object) + .unwrap(); + text.replace_range(0..1, &edit.replacement); + } + _ => panic!(), + } + assert_eq!(rows(edit.as_bytes()), expected); + let result = edit.commit(self.disk); + let durable = rows(&self.disk.durable); + assert!(durable == before || durable == expected); + if result.is_ok() { + assert_eq!(durable, expected); + } + result + } + fn confirm(&mut self, snapshot: &[u8]) -> Result<(), CommitError> { + onestore::confirm_snapshot(self.disk, snapshot) + } +} + +pub fn run(input: &[u8]) { + let (source, sid, outline) = &*SOURCE; + let directory = tempfile::tempdir().unwrap(); + let mut replicas: [Option; 12] = std::array::from_fn(|_| None); + let mut disk = 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(48) { + 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 local = rows(&snapshot); + match step[1] % 8 { + 0..=2 if !local.is_empty() => { + let target = usize::from(step[2]) % local.len(); + let id = match step[1] % 8 { + 0 => { + let before = + (step[3] & 1 == 0).then(|| local[usize::from(step[4]) % local.len()].0); + cache + .tree( + &snapshot, + *sid, + &TreeEdit::move_to(local[target].0, *outline, before, "Offline") + .unwrap(), + ) + .unwrap() + } + 1 => cache + .tree( + &snapshot, + *sid, + &TreeEdit::delete(local[target].0, "Offline").unwrap(), + ) + .unwrap(), + _ => cache + .edit_text( + &snapshot, + *sid, + local[target].1, + 0..1, + &char::from(b'A' + step[3] % 26).to_string(), + ) + .unwrap(), + }; + let next = cache.pending().unwrap(); + assert_eq!(next[..pending.len()], pending); + assert_eq!(next.len(), pending.len() + usize::from(id.is_some())); + } + 3 | 4 => { + disk.operation = 0; + disk.fail_at = (step[4] != 0) + .then_some(usize::from(u16::from_le_bytes([step[4], step[5]])) % 2048 + 1); + disk.write_limit = if step[6] & 1 == 0 { 17 } else { 4096 }; + disk.random = u64::from(step[7]) + 1; + let _ = cache.sync_once(&mut Session { + disk: &mut disk, + operation: pending.first().map(|p| &p.operation), + }); + let next = cache.pending().unwrap(); + if next.len() == pending.len() { + assert_eq!(next, pending); + } else { + assert_eq!(next, pending[1..]); + let Some(EditStatus::Published { revision }) = + cache.status(pending[0].id).unwrap() + else { + panic!() + }; + let store = Store::parse(&disk.durable).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + assert!(index.spaces[sid].revisions.contains_key(&revision)); + } + if !next.is_empty() { + assert!(cache.snapshot().unwrap() == snapshot); + } + disk.visible.clone_from(&disk.durable); + } + 5 => { + let mut expected = rows(&disk.visible); + if !expected.is_empty() { + let target = usize::from(step[2]) % expected.len(); + let (_, text, content) = &mut expected[target]; + let at = u32::try_from(content.encode_utf16().count()).unwrap(); + content.push('R'); + let snapshot = disk.visible.clone(); + let edit = PreparedEdit::text(&snapshot, *sid, *text, at..at, "R").unwrap(); + disk.fail_at = None; + edit.commit(&mut disk).unwrap(); + assert_eq!(rows(&disk.durable), expected); + } + } + _ => { + if step[1] % 8 == 6 + && let Some(first) = pending.first() + && matches!(first.operation, Operation::Tree(_)) + && matches!( + cache.status(first.id).unwrap(), + Some(EditStatus::Conflict(_)) + ) + { + let remote = cache.remote_snapshot().unwrap(); + let _ = cache.rebase_tree_conflict(first.id, &snapshot, &remote); + } + let pending = cache.pending().unwrap(); + drop(replicas[actor].take()); + let cache = Replica::open(&path).unwrap(); + assert!(cache.snapshot().unwrap() == snapshot); + assert_eq!(cache.pending().unwrap(), pending); + replicas[actor] = Some(cache); + } + } + rows(&disk.durable); + rows(&replicas[actor].as_ref().unwrap().snapshot().unwrap()); + } +} diff --git a/crates/onestore-offline/tests/sync.rs b/crates/onestore-offline/tests/sync.rs index 5cfe32abc28e3a5c351f0763c60d72859e2c2f40..97b0459683cbff4c92c13acd022e7a3d8cebaf8b 100644 --- a/crates/onestore-offline/tests/sync.rs +++ b/crates/onestore-offline/tests/sync.rs @@ -5,8 +5,14 @@ use onestore::{ use onestore_offline::{ConflictKind, EditStatus, Error, Remote, Replica}; use std::io; +#[path = "../../onestore/tests/support/disk.rs"] +mod disk; #[path = "sync/outline.rs"] mod outline; +#[path = "sync/tree.rs"] +mod tree; +#[path = "support/tree_schedule.rs"] +mod tree_schedule; mod paragraph { use super::*; diff --git a/crates/onestore-offline/tests/sync/outline.rs b/crates/onestore-offline/tests/sync/outline.rs index 5f7cb4c9aa997256b49387f2f6339443f03f4d34..87e6e1156c054bfc53acb7ad9b0d4ae8edc96ba5 100644 --- a/crates/onestore-offline/tests/sync/outline.rs +++ b/crates/onestore-offline/tests/sync/outline.rs @@ -1,7 +1,7 @@ use super::*; use onestore::OutlineEdit as Change; -fn fixture() -> (Vec, ExGuid, ExGuid, ExGuid, ExGuid) { +pub(super) fn fixture() -> (Vec, ExGuid, ExGuid, ExGuid, ExGuid) { let source = onestore::create_section("layout.one", "Original 🦀 é", "Author").unwrap(); let (sid, text, _) = text(&source); let store = Store::parse(&source).unwrap(); @@ -24,7 +24,7 @@ fn fixture() -> (Vec, ExGuid, ExGuid, ExGuid, ExGuid) { (source, sid, outline, paragraph, text) } -fn node(source: &[u8], sid: ExGuid, object: ExGuid) -> serde_json::Value { +pub(super) fn node(source: &[u8], sid: ExGuid, object: ExGuid) -> serde_json::Value { let store = Store::parse(source).unwrap(); let index = RevisionIndex::parse(&store).unwrap(); index.validate_current().unwrap(); diff --git a/crates/onestore-offline/tests/sync/tree.rs b/crates/onestore-offline/tests/sync/tree.rs new file mode 100644 index 0000000000000000000000000000000000000000..51047122949425ea702d954bdc09ce80da481c70 --- /dev/null +++ b/crates/onestore-offline/tests/sync/tree.rs @@ -0,0 +1,716 @@ +use super::*; +use onestore::{Insertion, TreeEdit}; + +#[test] +fn twelve_offline_clients_reconcile_tree_text_and_interrupted_publication() { + let mut random = 1940_u64; + for _ in 0..60 { + let input: Vec<_> = (0..384) + .map(|_| { + random ^= random << 13; + random ^= random >> 7; + random ^= random << 17; + random as u8 + }) + .collect(); + tree_schedule::run(&input); + } +} + +fn fixture() -> (Vec, ExGuid, ExGuid, [ExGuid; 4], [ExGuid; 4]) { + let (mut source, sid, outline, first, text) = super::outline::fixture(); + let mut paragraphs = [first; 4]; + let mut texts = [text; 4]; + for at in 1..4 { + let insertion = + Insertion::paragraph(outline, None, &format!("Sibling {at}"), "Author").unwrap(); + source = PreparedEdit::insert(&source, sid, &insertion) + .unwrap() + .as_bytes() + .to_vec(); + paragraphs[at] = insertion.object(); + texts[at] = insertion.text_object(); + } + (source, sid, outline, paragraphs, texts) +} + +fn children(source: &[u8], sid: ExGuid, object: ExGuid) -> Vec { + let store = Store::parse(source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + index.validate_current().unwrap(); + let document = Document::parse(&index).unwrap(); + let space = &document.spaces[&sid]; + space.revisions[&space.contexts[&ExGuid::default()]].nodes[&object] + .children + .clone() +} + +#[test] +fn move_preserves_remote_content_and_dependent_edits_through_reopen() { + let (source, sid, outline, paragraphs, texts) = fixture(); + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("cache.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let intent = TreeEdit::move_to(paragraphs[0], outline, None, "Offline").unwrap(); + let id = cache.tree(&source, sid, &intent).unwrap().unwrap(); + let dependent = cache + .edit_text(&cache.snapshot().unwrap(), sid, texts[0], 0..0, "Local ") + .unwrap() + .unwrap(); + let local = cache.snapshot().unwrap(); + let queue = cache.pending().unwrap(); + drop(cache); + let cache = Replica::open(&path).unwrap(); + assert_eq!(cache.pending().unwrap(), queue); + assert_eq!(cache.snapshot().unwrap(), local); + let edited = PreparedEdit::format( + &source, + sid, + texts[0], + 0..8, + &[onestore::TextAttribute::Bold(true)], + ) + .unwrap(); + let descendant = + Insertion::paragraph(paragraphs[0], None, "New remote child", "Remote").unwrap(); + let remote = PreparedEdit::insert(edited.as_bytes(), sid, &descendant).unwrap(); + let mut server = Server::new(remote.as_bytes()); + for expected in [id, dependent] { + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == expected) + ); + } + assert_eq!( + children(&server.durable, sid, outline), + [paragraphs[1], paragraphs[2], paragraphs[3], paragraphs[0]] + ); + assert_eq!( + children(&server.durable, sid, paragraphs[0]), + [descendant.object()] + ); + let node = super::outline::node(&server.durable, sid, texts[0]); + assert_eq!(node["kind"]["text"], "Local Original 🦀 é"); + let store = Store::parse(&server.durable).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let space = &document.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + assert_eq!(view.text_runs(texts[0]).unwrap()[0].format.bold, Some(true)); + assert!(cache.pending().unwrap().is_empty()); + assert_eq!(server.publications, 2); +} + +#[test] +fn deletion_requires_review_of_remote_content_and_preserves_later_work() { + let (source, sid, outline, paragraphs, texts) = fixture(); + let child = Insertion::paragraph(paragraphs[0], None, "Descendant", "Author").unwrap(); + let source = PreparedEdit::insert(&source, sid, &child) + .unwrap() + .as_bytes() + .to_vec(); + for remote in [ + PreparedEdit::text(&source, sid, texts[0], 0..0, "Remote ") + .unwrap() + .as_bytes() + .to_vec(), + PreparedEdit::text(&source, sid, child.text_object(), 0..0, "Remote ") + .unwrap() + .as_bytes() + .to_vec(), + PreparedEdit::format( + &source, + sid, + child.text_object(), + 0..10, + &[onestore::TextAttribute::Italic(true)], + ) + .unwrap() + .as_bytes() + .to_vec(), + PreparedEdit::insert( + &source, + sid, + &Insertion::paragraph(paragraphs[0], None, "New child", "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec(), + ] { + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("cache.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let intent = TreeEdit::delete(paragraphs[0], "Offline").unwrap(); + let id = cache.tree(&source, sid, &intent).unwrap().unwrap(); + let dependent = cache + .edit_text(&cache.snapshot().unwrap(), sid, texts[1], 0..0, "Local ") + .unwrap() + .unwrap(); + let queue = cache.pending().unwrap(); + let local = cache.snapshot().unwrap(); + let mut server = Server::new(&remote); + assert_eq!( + cache.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(ConflictKind::ContentChanged))) + ); + assert_eq!(server.publications, 0); + assert_eq!(cache.pending().unwrap(), queue); + assert_eq!(cache.snapshot().unwrap(), local); + assert!(cache.rebase_tree_conflict(id, &source, &remote).is_err()); + assert!(cache.rebase_tree_conflict(id, &local, &source).is_err()); + assert!( + cache + .rebase_tree_conflict(dependent, &local, &remote) + .is_err() + ); + assert!(cache.rebase_conflict(id, &local, &remote, 0..0).is_err()); + let archive = directory.path().join("recovery.sqlite"); + cache.export_recovery(&archive).unwrap(); + let recovery = onestore_offline::Recovery::open(&archive).unwrap(); + assert_eq!(recovery.pending().unwrap(), queue); + assert_eq!(recovery.status(id).unwrap(), cache.status(id).unwrap()); + assert!(recovery.snapshot().unwrap() == local); + drop(cache); + let cache = Replica::open(&path).unwrap(); + assert_eq!( + cache.status(id).unwrap(), + Some(EditStatus::Conflict(ConflictKind::ContentChanged)) + ); + cache.rebase_tree_conflict(id, &local, &remote).unwrap(); + assert_eq!(cache.pending().unwrap()[1], queue[1]); + assert_eq!(cache.snapshot().unwrap(), local); + for expected in [id, dependent] { + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == expected) + ); + } + assert_eq!(children(&server.durable, sid, outline), paragraphs[1..]); + assert_eq!( + super::outline::node(&server.durable, sid, texts[1])["kind"]["text"], + "Local Sibling 1" + ); + } +} + +#[test] +fn sibling_and_ancestry_changes_have_explicit_merge_or_conflict() { + let (source, sid, outline, p, texts) = fixture(); + let insertion = Insertion::paragraph(outline, Some(p[0]), "New sibling", "Remote").unwrap(); + let cases = [ + ( + PreparedEdit::insert(&source, sid, &insertion) + .unwrap() + .as_bytes() + .to_vec(), + None, + ), + ( + PreparedEdit::tree(&source, sid, &TreeEdit::delete(p[1], "Remote").unwrap()) + .unwrap() + .as_bytes() + .to_vec(), + None, + ), + ( + PreparedEdit::tree( + &source, + sid, + &TreeEdit::move_to(p[1], outline, None, "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec(), + None, + ), + ( + PreparedEdit::tree( + &source, + sid, + &TreeEdit::move_to(p[0], outline, Some(p[2]), "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec(), + Some(ConflictKind::StructureChanged), + ), + ( + PreparedEdit::tree( + &source, + sid, + &TreeEdit::move_to(p[0], p[1], None, "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec(), + Some(ConflictKind::StructureChanged), + ), + ( + PreparedEdit::tree(&source, sid, &TreeEdit::delete(p[0], "Remote").unwrap()) + .unwrap() + .as_bytes() + .to_vec(), + Some(ConflictKind::TargetUnavailable), + ), + ]; + for (remote, expected) in cases { + let directory = tempfile::tempdir().unwrap(); + let cache = Replica::create(directory.path().join("cache.sqlite"), &source).unwrap(); + let intent = TreeEdit::move_to(p[0], outline, None, "Offline").unwrap(); + let id = cache.tree(&source, sid, &intent).unwrap().unwrap(); + let mut server = Server::new(&remote); + let result = cache.sync_once(&mut server).unwrap().unwrap(); + assert_eq!(result.0, id); + if let Some(kind) = expected { + assert_eq!(result.1, EditStatus::Conflict(kind)); + assert_eq!(server.publications, 0); + } else { + assert!(matches!(result.1, EditStatus::Published { .. })); + assert_eq!(children(&server.durable, sid, outline).last(), Some(&p[0])); + assert_eq!( + super::outline::node(&server.durable, sid, texts[0])["kind"]["text"], + "Original 🦀 é" + ); + } + } +} + +#[test] +fn moved_destination_and_missing_anchor_retain_conflicts_but_unrelated_text_does_not() { + let (source, sid, outline, p, texts) = fixture(); + let child = Insertion::paragraph(p[1], None, "Anchor", "Author").unwrap(); + let source = PreparedEdit::insert(&source, sid, &child) + .unwrap() + .as_bytes() + .to_vec(); + let intent = TreeEdit::move_to(p[0], p[1], Some(child.object()), "Offline").unwrap(); + let cases = [ + ( + PreparedEdit::tree( + &source, + sid, + &TreeEdit::move_to(p[1], p[2], None, "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec(), + ConflictKind::StructureChanged, + ), + ( + PreparedEdit::tree( + &source, + sid, + &TreeEdit::move_to(child.object(), outline, None, "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec(), + ConflictKind::UnsupportedEdit, + ), + ]; + for (remote, kind) in cases { + let directory = tempfile::tempdir().unwrap(); + let cache = Replica::create(directory.path().join("cache.sqlite"), &source).unwrap(); + let id = cache.tree(&source, sid, &intent).unwrap().unwrap(); + let mut server = Server::new(&remote); + assert_eq!( + cache.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(kind))) + ); + assert_eq!(server.publications, 0); + } + let directory = tempfile::tempdir().unwrap(); + let cache = Replica::create(directory.path().join("cache.sqlite"), &source).unwrap(); + let id = cache + .tree(&source, sid, &TreeEdit::delete(p[0], "Offline").unwrap()) + .unwrap() + .unwrap(); + let remote = PreparedEdit::text(&source, sid, texts[1], 0..0, "Remote ").unwrap(); + let mut server = Server::new(remote.as_bytes()); + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((n, EditStatus::Published { .. })) if n == id) + ); + assert_eq!( + super::outline::node(&server.durable, sid, texts[1])["kind"]["text"], + "Remote Sibling 1" + ); +} + +#[test] +fn unknown_tree_attempts_require_revision_evidence_even_when_effect_is_visible() { + let (source, sid, outline, p, _) = fixture(); + for deletion in [false, true] { + for fault in [ + Fault::UnknownBefore, + Fault::UnknownAfter, + Fault::Before, + Fault::Committed, + ] { + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("cache.sqlite"); + let cache = Replica::create(&path, &source).unwrap(); + let intent = if deletion { + TreeEdit::delete(p[0], "Offline") + } else { + TreeEdit::move_to(p[0], outline, None, "Offline") + } + .unwrap(); + let id = cache.tree(&source, sid, &intent).unwrap().unwrap(); + let mut server = Server::new(&source); + server.fault = fault; + assert!(cache.sync_once(&mut server).is_err()); + let local = cache.snapshot().unwrap(); + let before = cache.status(id).unwrap(); + drop(cache); + let cache = Replica::open(&path).unwrap(); + assert_eq!(cache.status(id).unwrap(), before); + if matches!(fault, Fault::UnknownBefore) { + let independent = if deletion { + TreeEdit::delete(p[0], "Other") + } else { + TreeEdit::move_to(p[0], outline, None, "Other") + } + .unwrap(); + server = Server::new( + PreparedEdit::tree(&source, sid, &independent) + .unwrap() + .as_bytes(), + ); + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((n, EditStatus::AwaitingConfirmation { .. })) if n == id) + ); + assert!( + cache + .rebase_tree_conflict(id, &local, &server.visible) + .is_err() + ); + assert_eq!(server.publications, 0); + assert_eq!(cache.snapshot().unwrap(), local); + } else if matches!(fault, Fault::Committed) { + assert!(matches!( + cache.status(id).unwrap(), + Some(EditStatus::Published { .. }) + )); + } else { + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((n, EditStatus::Published { .. })) if n == id) + ); + assert_eq!( + server.publications, + if matches!(fault, Fault::Before) { 2 } else { 1 } + ); + let saved = cache.snapshot().unwrap(); + assert!(saved[..212] == server.durable[..212]); + assert!(saved[252..] == server.durable[252..]); + assert_eq!( + children(&saved, sid, outline), + children(&server.durable, sid, outline) + ); + } + } + } +} + +#[test] +fn independently_satisfied_move_confirms_without_republication() { + let (source, sid, outline, p, _) = fixture(); + let directory = tempfile::tempdir().unwrap(); + let cache = Replica::create(directory.path().join("cache.sqlite"), &source).unwrap(); + let id = cache + .tree( + &source, + sid, + &TreeEdit::move_to(p[0], outline, None, "Offline").unwrap(), + ) + .unwrap() + .unwrap(); + let remote = PreparedEdit::tree( + &source, + sid, + &TreeEdit::move_to(p[0], outline, None, "Remote").unwrap(), + ) + .unwrap(); + let mut server = Server::new(remote.as_bytes()); + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((n, EditStatus::Published { .. })) if n == id) + ); + assert_eq!(server.publications, 0); + assert_eq!(server.confirmations, 1); +} + +#[test] +fn emptied_cell_replacement_is_durable_and_cannot_be_silently_omitted_on_replay() { + let source = + include_bytes!("../../../../corpus/outline-edit/tree/before/notebook/synthetic.one"); + let store = Store::parse(source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let (sid, page) = document.pages().unwrap().into_iter().find(|(sid, _)| { + let space = &document.spaces[sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + matches!(&view.nodes[&view.roots[&2]].kind, Kind::Metadata { title: Some(title), .. } if title == "Delete sole cell paragraph") + }).unwrap(); + let space = &document.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let mut pending = vec![page]; + let mut selected = None; + let mut other = None; + while let Some(id) = pending.pop() { + let node = &view.nodes[&id]; + pending.extend(&node.children); + pending.extend(&node.content); + if matches!(node.kind, Kind::Cell { .. }) { + let paragraph = node.children[0]; + let text = view.nodes[¶graph].content[0]; + if matches!(&view.nodes[&text].kind, Kind::RichText { text, .. } if text.starts_with("Target ")) + { + selected = Some((id, paragraph)); + } else { + other = Some((id, text)); + } + } + } + let (cell, target) = selected.unwrap(); + let (other_cell, other_text) = other.unwrap(); + for move_out in [false, true] { + for competing_child in [false, true] { + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("cell.sqlite"); + let cache = Replica::create(&path, source).unwrap(); + let intent = if move_out { + TreeEdit::move_to(target, other_cell, None, "Offline") + } else { + TreeEdit::delete(target, "Offline") + } + .unwrap(); + let id = cache.tree(source, sid, &intent).unwrap().unwrap(); + let local = cache.snapshot().unwrap(); + let replacement = children(&local, sid, cell); + assert_eq!(replacement.len(), 1); + assert_ne!(replacement[0], target); + let replacement_text: ExGuid = + super::outline::node(&local, sid, replacement[0])["content"][0] + .as_str() + .unwrap() + .parse() + .unwrap(); + let dependent = cache + .edit_text(&local, sid, replacement_text, 0..0, "Local replacement") + .unwrap() + .unwrap(); + let local = cache.snapshot().unwrap(); + let queue = cache.pending().unwrap(); + drop(cache); + let cache = Replica::open(&path).unwrap(); + assert_eq!(cache.pending().unwrap(), queue); + assert_eq!(cache.snapshot().unwrap(), local); + let remote = if competing_child { + PreparedEdit::insert( + source, + sid, + &Insertion::paragraph(cell, None, "Remote sibling", "Remote").unwrap(), + ) + .unwrap() + .as_bytes() + .to_vec() + } else { + PreparedEdit::text(source, sid, other_text, 0..0, "Remote ") + .unwrap() + .as_bytes() + .to_vec() + }; + let mut server = Server::new(&remote); + if competing_child { + assert_eq!( + cache.sync_once(&mut server).unwrap(), + Some((id, EditStatus::Conflict(ConflictKind::StructureChanged))) + ); + assert_eq!(server.publications, 0); + assert!(cache.rebase_tree_conflict(id, &local, &remote).is_err()); + assert_eq!(cache.pending().unwrap(), queue); + assert_eq!(cache.snapshot().unwrap(), local); + } else { + for expected in [id, dependent] { + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == expected) + ); + } + assert_eq!(children(&server.durable, sid, cell), replacement); + assert_eq!( + super::outline::node(&server.durable, sid, replacement_text)["kind"]["text"], + "Local replacement" + ); + assert_eq!( + super::outline::node(&server.durable, sid, other_text)["kind"]["text"], + "Remote Other cell" + ); + if let Some(output) = std::env::var_os("ONESTORE_OFFLINE_TREE_OUTPUT") { + let output = std::path::PathBuf::from(output) + .join(if move_out { "cell-move" } else { "cell-delete" }) + .join("candidate"); + std::fs::create_dir_all(&output).unwrap(); + std::fs::write(output.join("synthetic.one"), &server.durable).unwrap(); + } + } + } + } +} + +#[test] +fn native_tree_and_layout_changes_reconcile_without_discarding_unreviewed_content() { + let source = include_bytes!("../../../../corpus/outline-edit/before/notebook/synthetic.one"); + let native = include_bytes!("../../../../corpus/outline-edit/after/notebook/synthetic.one"); + let store = Store::parse(source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let mut server = Server::new(native); + let mut counts = [0; 3]; + let mut records = Vec::new(); + for (sid, page) in document.pages().unwrap() { + let space = &document.spaces[&sid]; + let view = &space.revisions[&space.contexts[&ExGuid::default()]]; + let Kind::Metadata { + title: Some(name), .. + } = &view.nodes[&view.roots[&2]].kind + else { + continue; + }; + if name == "Unicode rich text" { + continue; + } + let outlines: Vec<_> = view.nodes[&page] + .children + .iter() + .copied() + .filter(|id| matches!(view.nodes[id].kind, Kind::Outline { .. })) + .collect(); + if outlines.len() != 2 { + continue; + } + let outline = outlines[0]; + let other = view.nodes[&outlines[1]].children[0]; + let dependent_text = view.nodes[&other].content[0]; + let mut pending = vec![outline]; + let mut paragraphs = std::collections::BTreeMap::new(); + while let Some(id) = pending.pop() { + let node = &view.nodes[&id]; + pending.extend(&node.children); + if let Some(text) = node.content.first() + && let Kind::RichText { text, .. } = &view.nodes[text].kind + { + paragraphs.insert(text.as_str(), id); + } + } + let target = *paragraphs + .iter() + .find(|(text, _)| text.starts_with("Target ")) + .unwrap() + .1; + let (intent, conflict) = match name.as_str() { + "Move leaf down" | "Move subtree down" => { + (TreeEdit::move_to(target, outline, None, "Offline"), None) + } + "Move subtree up" => ( + TreeEdit::move_to(target, outline, Some(paragraphs["Anchor"]), "Offline"), + None, + ), + "Indent subtree" | "Outdent subtree" => ( + TreeEdit::delete(target, "Offline"), + Some(ConflictKind::StructureChanged), + ), + "Collapse subtree" | "Expand subtree" => ( + TreeEdit::delete(target, "Offline"), + Some(ConflictKind::ContentChanged), + ), + "Delete leaf" | "Delete subtree" | "Delete only paragraph" => ( + TreeEdit::delete(target, "Offline"), + Some(ConflictKind::TargetUnavailable), + ), + "Delete outline" => ( + TreeEdit::delete(outline, "Offline"), + Some(ConflictKind::TargetUnavailable), + ), + "Move outline" | "Resize outline" | "Automatic outline size" => ( + TreeEdit::delete(outline, "Offline"), + Some(ConflictKind::ContentChanged), + ), + _ => panic!("{name}"), + }; + let intent = intent.unwrap(); + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("native.sqlite"); + let cache = Replica::create(&path, source).unwrap(); + let id = cache.tree(source, sid, &intent).unwrap().unwrap(); + let dependent = cache + .edit_text( + &cache.snapshot().unwrap(), + sid, + dependent_text, + 0..0, + "Offline ", + ) + .unwrap() + .unwrap(); + let local = cache.snapshot().unwrap(); + let queue = cache.pending().unwrap(); + let old_publications = server.publications; + let (actual, status) = cache.sync_once(&mut server).unwrap().unwrap(); + assert_eq!(actual, id); + if let Some(kind) = conflict { + assert_eq!(status, EditStatus::Conflict(kind), "{name}"); + assert_eq!(server.publications, old_publications); + assert_eq!(cache.pending().unwrap(), queue); + assert!(cache.snapshot().unwrap() == local); + drop(cache); + let cache = Replica::open(&path).unwrap(); + assert_eq!(cache.status(id).unwrap(), Some(status)); + if kind == ConflictKind::TargetUnavailable { + counts[2] += 1; + assert!( + cache + .rebase_tree_conflict(id, &local, &server.visible) + .is_err() + ); + records.push(serde_json::json!({"page": name, "space": sid, "result": "retained"})); + continue; + } + counts[1] += 1; + cache + .rebase_tree_conflict(id, &local, &server.visible) + .unwrap(); + assert_eq!(cache.pending().unwrap()[1], queue[1]); + for expected in [id, dependent] { + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == expected) + ); + } + } else { + counts[0] += 1; + assert!(matches!(status, EditStatus::Published { .. }), "{name}"); + assert_eq!(server.publications, old_publications); + assert!( + matches!(cache.sync_once(&mut server).unwrap(), Some((actual, EditStatus::Published { .. })) if actual == dependent) + ); + } + assert_eq!( + super::outline::node(&server.durable, sid, dependent_text)["kind"]["text"], + format!( + "Offline {}", + match &view.nodes[&dependent_text].kind { + Kind::RichText { text, .. } => text, + _ => panic!(), + } + ) + ); + records.push(serde_json::json!({"page": name, "space": sid, "result": if conflict.is_some() { "reviewed" } else { "converged" }})); + } + assert_eq!(counts, [3, 7, 4]); + if let Some(output) = std::env::var_os("ONESTORE_OFFLINE_TREE_OUTPUT") { + let output = std::path::PathBuf::from(output); + std::fs::create_dir_all(output.join("candidate")).unwrap(); + std::fs::write(output.join("candidate/synthetic.one"), &server.durable).unwrap(); + std::fs::write( + output.join("manifest.json"), + serde_json::to_vec_pretty(&records).unwrap(), + ) + .unwrap(); + } +} diff --git a/crates/onestore/src/objects.rs b/crates/onestore/src/objects.rs index 3900af9f53ba01a38cb4f41907d90a43beb1514d..02d0e02dcea389d053a1cb5724a6162d8233ad10 100644 --- a/crates/onestore/src/objects.rs +++ b/crates/onestore/src/objects.rs @@ -34,6 +34,7 @@ pub struct ResolvedRevision<'a> { } /// Occurrences retain multiplicity for native reference counts. +/// Each stream follows property arena order, including nested sets. #[derive(Debug, Default)] pub struct ObjectReferences { pub objects: Vec, diff --git a/crates/onestore/src/tree.rs b/crates/onestore/src/tree.rs index 64a24dcf2624a172bba3fe8dcf631f39e35f420c..04a19f7240b3467ccae01078b17a0db0a91bf492 100644 --- a/crates/onestore/src/tree.rs +++ b/crates/onestore/src/tree.rs @@ -38,6 +38,18 @@ pub struct TreeEdit { } impl TreeEdit { + pub fn object(&self) -> ExGuid { + self.object + } + + /// Move destination and direct sibling anchor; deletion has no destination. + pub fn destination(&self) -> Option<(ExGuid, Option)> { + match self.placement { + Placement::Delete => None, + Placement::Move { parent, before } => Some((parent, before)), + } + } + /// Removes a paragraph or ordinary outline and its descendants from the active tree. /// Historical objects remain available; an emptied table cell receives an empty paragraph. pub fn delete(object: ExGuid, author: &str) -> Result { diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index ba1cb1402bc1864d3c6c46ed5cd72ef809231bdd..05afdb31cbee19b3952f956d79943754d5acb87a 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -107,3 +107,10 @@ path = "fuzz_targets/tree.rs" test = false doc = false bench = false + +[[bin]] +name = "offline_tree" +path = "fuzz_targets/offline_tree.rs" +test = false +doc = false +bench = false diff --git a/fuzz/fuzz_targets/offline_tree.rs b/fuzz/fuzz_targets/offline_tree.rs new file mode 100644 index 0000000000000000000000000000000000000000..5463e3709d22564ad0e2e12b0e5ee14aa6cb4d6a --- /dev/null +++ b/fuzz/fuzz_targets/offline_tree.rs @@ -0,0 +1,9 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +#[path = "../../crates/onestore/tests/support/disk.rs"] +mod disk; +#[path = "../../crates/onestore-offline/tests/support/tree_schedule.rs"] +mod tree_schedule; + +fuzz_target!(|input: &[u8]| tree_schedule::run(input)); diff --git a/tools/test_outline_edit.py b/tools/test_outline_edit.py index fe7a48d6c203e31b2e2be004b74e7285e8eb9fd7..4a02c4778c67229a5af116b6159993e0c25868ec 100644 --- a/tools/test_outline_edit.py +++ b/tools/test_outline_edit.py @@ -20,8 +20,12 @@ compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare'] class OutlineEditTest(unittest.TestCase): def test_rust_subtree_moves_and_deletions_survive_cold_native_reopen(self): - for name, pages in [('ordinary', 15), ('groups-cells', 12), ('cross-container', 12), ('unequal-groups', 1)]: - fixture = FIXTURE / 'rust-tree' / name + for name, pages in [ + ('rust-tree/ordinary', 15), ('rust-tree/groups-cells', 12), + ('rust-tree/cross-container', 12), ('rust-tree/unequal-groups', 1), + ('offline-tree', 15), ('offline-tree/cell-delete', 12), ('offline-tree/cell-move', 12), + ]: + fixture = FIXTURE / name with self.subTest(case=name), TemporaryDirectory() as temporary: models = {} for phase, notebook in [('candidate', fixture / 'candidate'), ('cold', fixture / 'cold/notebook')]: @@ -42,7 +46,7 @@ class OutlineEditTest(unittest.TestCase): for _, node in walk(old, page): for oid in node['kind'].get('lists', []): self.assertEqual(old['nodes'][oid], saved['nodes'][oid]) - if name == 'unequal-groups': + if name == 'rust-tree/unequal-groups': capture, = (fixture / 'cold/read').glob('page-*.xml') root = ET.parse(capture).getroot() self.assertEqual([(group.get('indent'), ''.join(Text(group.find('one:OE/one:T', ns).text or '').parts)) -- 2.54.0