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
Binary files /dev/null and b/corpus/outline-edit/offline-tree/candidate/synthetic.one differ
diff --git a/corpus/outline-edit/offline-tree/cases.json b/corpus/outline-edit/offline-tree/cases.json
new file mode 100644
index 0000000000000000000000000000000000000000..f88e7b7ac84f4c18112867710fad315bfb7fec0b
--- /dev/null
+++ b/corpus/outline-edit/offline-tree/cases.json
@@ -0,0 +1,72 @@
+[
+ {
+ "page": "Move leaf down",
+ "result": "converged",
+ "space": "{B7267338-BF83-0893-27A7-37F606DD20C8},1"
+ },
+ {
+ "page": "Move subtree down",
+ "result": "converged",
+ "space": "{9B80D7CA-18B4-02B0-1E85-6E8AA0DAD827},1"
+ },
+ {
+ "page": "Move subtree up",
+ "result": "converged",
+ "space": "{7538095C-389B-07D8-2991-B2BC46EBD52A},1"
+ },
+ {
+ "page": "Indent subtree",
+ "result": "reviewed",
+ "space": "{651463E3-C768-0C93-363D-FCE642B07408},1"
+ },
+ {
+ "page": "Outdent subtree",
+ "result": "reviewed",
+ "space": "{8384083C-60ED-0F7C-2F15-8B20B878B3EB},1"
+ },
+ {
+ "page": "Collapse subtree",
+ "result": "reviewed",
+ "space": "{FF88B513-029C-00E2-0082-9E3DCE1D7796},1"
+ },
+ {
+ "page": "Expand subtree",
+ "result": "reviewed",
+ "space": "{850B34E4-D62A-042B-138A-B2A905CEE28E},1"
+ },
+ {
+ "page": "Delete leaf",
+ "result": "retained",
+ "space": "{363FE055-44E1-0B27-14A8-46278FD681FF},1"
+ },
+ {
+ "page": "Delete subtree",
+ "result": "retained",
+ "space": "{8BBAD88F-D248-0959-00B3-2438A7065330},1"
+ },
+ {
+ "page": "Delete only paragraph",
+ "result": "retained",
+ "space": "{A4CB3BA2-767F-0AE8-0916-AF142D995822},1"
+ },
+ {
+ "page": "Delete outline",
+ "result": "retained",
+ "space": "{80E80543-87A1-0C3A-0816-22B190BDFC87},1"
+ },
+ {
+ "page": "Move outline",
+ "result": "reviewed",
+ "space": "{16207F40-69C9-0CA1-09B5-DC5712DB2BBE},1"
+ },
+ {
+ "page": "Resize outline",
+ "result": "reviewed",
+ "space": "{CD420421-73F7-0F11-02EC-35FCA348998C},1"
+ },
+ {
+ "page": "Automatic outline size",
+ "result": "reviewed",
+ "space": "{F383096F-2121-0225-1E62-AB37C9B15B33},1"
+ }
+]
\ No newline at end of file
diff --git a/corpus/outline-edit/offline-tree/cell-delete/candidate/synthetic.one b/corpus/outline-edit/offline-tree/cell-delete/candidate/synthetic.one
new file mode 100644
index 0000000000000000000000000000000000000000..d436dd78487631e41e1449151855924eec9debf4
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cell-delete/candidate/synthetic.one differ
diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/commands.jsonl b/corpus/outline-edit/offline-tree/cell-delete/cold/commands.jsonl
new file mode 100644
index 0000000000000000000000000000000000000000..376f0fbbc073e2a0fde448f5a6d6a462e418c7e5
--- /dev/null
+++ b/corpus/outline-edit/offline-tree/cell-delete/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-37ACD671 -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-delete/cold/notebook/Open Notebook.onetoc2 b/corpus/outline-edit/offline-tree/cell-delete/cold/notebook/Open Notebook.onetoc2
new file mode 100644
index 0000000000000000000000000000000000000000..6aaa8771213ea8929090e4f9321a8f42a7909acc
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cell-delete/cold/notebook/Open Notebook.onetoc2 differ
diff --git a/corpus/outline-edit/offline-tree/cell-delete/cold/notebook/synthetic.one b/corpus/outline-edit/offline-tree/cell-delete/cold/notebook/synthetic.one
new file mode 100644
index 0000000000000000000000000000000000000000..fbc3b6f8b77f9917bc47778188e6de47e313f390
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cell-delete/cold/notebook/synthetic.one differ
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
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cell-move/candidate/synthetic.one differ
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
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cell-move/cold/notebook/Open Notebook.onetoc2 differ
diff --git a/corpus/outline-edit/offline-tree/cell-move/cold/notebook/synthetic.one b/corpus/outline-edit/offline-tree/cell-move/cold/notebook/synthetic.one
new file mode 100644
index 0000000000000000000000000000000000000000..5225bc6a0238f882b6df42b82c798290144f4901
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cell-move/cold/notebook/synthetic.one differ
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
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cold/notebook/Open Notebook.onetoc2 differ
diff --git a/corpus/outline-edit/offline-tree/cold/notebook/synthetic.one b/corpus/outline-edit/offline-tree/cold/notebook/synthetic.one
new file mode 100644
index 0000000000000000000000000000000000000000..a98e60962617853d8ccd44cca3d171abc4dc03e6
Binary files /dev/null and b/corpus/outline-edit/offline-tree/cold/notebook/synthetic.one differ
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