1# Conflict pages
2
3What OneNote 2010 does when a sync finds that two clients changed the same object, and
4that it reads and deletes the conflict pages Rust writes. `tools/native_conflict.py`
5made every capture; `tools/test_conflict_page.py` checks them without a VM.
6
7`native` is two OneNote clients on one Samba notebook (`native_conflict.py sync`, fixture
8`native-ink/cold-ui-ink`): client A, offline, rewrote the first outline's paragraph and the
9second outline's; client B rewrote the same first paragraph and the left table cell and
10published (`b-published`); A reconnected and synced (`conflict`). A kept B's version of the
11paragraph both changed and merged its own disjoint edit into the page; its own version of the
12page became a conflict page:
13
14- its own object space, listed only in the page manifest's `ChildGraphSpaceElementNodes`
15 (`0x2c001d63`), never in the page series, with a copy of its metadata in the manifest's
16 `0x24003442` whose identity is the space's XOR the metadata salt (MS-ONE 2.2.81);
17- metadata root `jcidConflictPageMetaData` (`0x20038`): `CachedTitleString`, a fresh
18 `NotebookManagementEntityGuid`, `PageLevel`, both schema revisions (`0x28`),
19 `TopologyCreationTimeStamp` of the merge, `ConflictingUserName` and
20 `ConflictingUserInitials` of the client whose version it is;
21- a page node with `IsReadOnly`, `Deletable` and `IsConflictPage`, holding A's whole page;
22 only the rich text of the paragraph both changed has `IsConflictObjectForSelection` and
23 `IsConflictObjectForRender`;
24- the page's metadata and the section's copy of it gain `HasConflictPages`.
25
26Both clients show the same UI (`a/`, `b/`): the page's tab carries a conflict mark and a
27yellow bar reads "This page has changes that could not be merged during synchronization.
28Click here to show versions of the page with unmerged changes." Clicking it lists the
29conflict pages under the page, each as its date and user ("9/26/2026 snow"), and opens the
30first; that page's bar reads "Conflicting changes are highlighted in red. This page cannot be
31edited, but you can copy changes to the primary page. Click here for more options." over a
32light red highlight (RGB 255, 214, 214), and its menu offers Delete Conflict Page, Copy Page
33To..., Select Previous/Next Conflicting Change and Collapse Conflict Pages.
34
35`native-three` is `evidence/m8/conflict-abrupt-cold-01`: three clients' conflict pages under
36one page. OneNote appends each to `ChildGraphSpaceElementNodes` and lists them last first
37(`conflicts.png`); the metadata copies are in their own order.
38
39`native-delete` is OneNote's Delete Conflict Page on `native/conflict` in a fresh clone
40(`native_conflict.py cold --delete`): the manifest loses `ChildGraphSpaceElementNodes` (its
41last entry) but keeps the metadata copy, the page's metadata and the section's copy lose
42`HasConflictPages`, and the conflict page's space is left as it was.
43
44`native-pages` and `native-restore` are page-list merges (`native_conflict.py pages`,
45`restore`): client A, offline, moved pages through COM and edited `Target`'s body while
46client B moved pages and deleted `Target`; A reconnected (`merged`, both clients' `listed.json`
47and screenshots). OneNote merges page series, not page positions. A page a client moves
48gets a series of its own, and a COM move also re-series every page it jumps over (a drag
49re-series only the dragged pages, `page-lifecycle/movement`). The merge keeps each page in
50the series of the client that re-seriesed it, the server's where both did, leaving the
51other's series empty (`native-pages` keeps two, which MS-ONE's one-page minimum does not
52allow); series only A made go after the server's. `Target` comes back as a new page space
53holding A's edit, in a new series where A had it; B's version stays in the recycle bin.
54
55- `native-pages`: from One, Two, Three, Four, Target, A moved Four before One and Two last
56 (re-seriesing One, Two, Three), B moved Four last and Three before One (re-seriesing One,
57 Two, Four): One, Two, Four, Three, Target.
58- `native-restore`: from One, Two, Target, Three, Four, A moved Four before One
59 (re-seriesing One, Two, Target, Three) and B deleted Target: Four, One, Two, Target, Three.
60
61`series-move` is `a_move_after_a_native_merge_drops_its_empty_series`
62(`crates/onestore/tests/page_movement.rs`, `ONESTORE_EMPTY_SERIES_EXPORT`): Rust moves a
63page of `native-pages/merged`, giving it a series of its own and dropping the empty
64series; OneNote's cold read (`cold`) keeps every byte after the header.
65
66`page_moves_and_a_removed_page_merge_as_onenote_merges_them` in
67`crates/notebook/tests/sync_pages.rs` replays both with Snowbound's queue, A's moves as
68moves of the pages A re-seriesed, and reaches OneNote's order.
69
70`candidate` is `a_conflict_page_is_stored_as_onenote_stores_one` in
71`crates/onestore/tests/conflict.rs` (`ONESTORE_CONFLICT_EXPORT`): the remote renamed the
72first word of the fixture's first paragraph, this machine did too, and `SectionOp::Conflict`
73kept this machine's page for "Clover Snow", whose author objects carry her initials beside
74her name as OneNote's do. `cold` is OneNote's fresh read and the same UI
75walk, ending in Delete Conflict Page on the Rust-written page: its bar and list entry show,
76the conflict page opens (window title) with the paragraph highlighted, and the deletion
77stores what `native-delete` did.
78
79`candidate-delete` is `deleting_a_conflict_page_stores_what_onenote_stores`
80(`ONESTORE_CONFLICT_DELETE_EXPORT`): `SectionOp::Delete` of `native/conflict`'s conflict page,
81which stores the objects OneNote's deletion did; `cold-delete` is its fresh read, without a
82bar.