1# Native paragraph editing
2
3OneNote 2010 authored 13 cases, split each through keyboard input, reopened the
4result in a fresh disposable VM, and joined each pair through keyboard input.
5The four phases retain notebook bytes and independent native XML: `before`,
6`split`, `cold-split`, and `joined`. A fourteenth control page remains unchanged.
7
8Cases cover mixed formatting, style/start/end/empty boundaries, nested children,
9bullets, numbering, completed tags, table cells, soft breaks, and splitting plain
10text before a hyperlink. The manifest records storage identities and split
11positions. Captured UI scripts and screenshots retain the actual native actions;
12`joined/first-backspace` records the intermediate list/indentation changes.
13
14The original paragraph stays on the left and children transfer to the new right
15paragraph. Completed tags remain on the left rich-text object. Joining an empty
16left paragraph retains its paragraph identity but adopts the right text object.
17Bullet, numbered, and nested cases require two Backspaces because the first
18changes list or indentation state. The native application also added flag
19`0x880034dd` and changed timestamps on some unrelated text objects; the manifest
20records those observations without assigning undocumented meaning to the flag.
21
22`tools/native/paragraphs.ps1` authors the cases. Use `tools/native_runner.py` with
23that author, `--expected-pages 14 --inspect --collect-notebook`, then navigate to
24each current page/object ID and send its recorded keys. Preserve the authored
25notebook before completing inspection. Cold-open the split notebook for the join
26pass. Captured COM IDs belong to their originating sessions; discover fresh IDs
27when regenerating the corpus.
28
29`rust-split` retains twelve Rust paragraph-split outputs, their cold native captures,
30and a second native session typing into four empty boundary paragraphs. The
31hyperlink case has no output: the operation rejected fields when this row was
32captured, and the writer now splits before a link as OneNote does. The Rust
33test `export_native_paragraph_splits` generates candidate notebooks; its output
34directory comes from `ONESTORE_PARAGRAPH_OUTPUT`. Native character/style comparisons
35use both the keyboard-generated controls and the Rust-written notebooks. Empty
36typing checks extend the preexisting empty run in an independent expected model.
37
38`tools/test_paragraph_edit.py` verifies these controls without a VM.
39Identical captured files link to one canonical copy within this corpus.
40
41`join-edges`, authored with `tools/native/paragraph-joins.ps1`, adds five native
42Backspace cases for differing inherited styles, tags on either side and children
43on both sides. A nonempty left paragraph keeps its own tags; right-only tags
44disappear from the active result. An empty tagged left paragraph transfers its
45tags onto the adopted right text. A left paragraph with children joins through
46its last descendant, and the right children become that descendant's peers.
47The untouched parent's text gains a timestamp and `0x880034dd`, as in the earlier
48native controls; its content and other properties stay unchanged. The test fixes
49these observed graph, identity and metadata effects alongside independent native
50character-style comparisons.
51
52`join-tags`, authored with `tools/native/paragraph-tag-joins.ps1`, confirms the
53left-tag rule for an empty untagged left paragraph, an empty tagged left paragraph
54with a different right tag, and two nonempty paragraphs with different tags.
55Right-side tags disappear in all three cases; only the left tag survives.
56
57`rust-join` retains twenty Rust joins across the original splits, inheritance
58edges and additional tag controls. Each group has a cold OneNote capture and
59saved notebook. Public tests compare the Rust and native-saved images to native
60XML, preserve exact child/content identities across reopening, and compare
61the native-rendered result to the corresponding keyboard-generated control.
62`export_native_paragraph_joins` regenerates candidates in a new directory specified
63by `ONESTORE_PARAGRAPH_JOIN_OUTPUT`.
64
65`offline` retains reconciled split/join candidates and cold native captures.
66The cache queues each recorded split or join as a page-model save before
67observing an independent remote `☂` prefix, reopens between acknowledgements,
68and confirms modeled lost replies without replaying a publication. The
69`inheritance` group has four cases: `Join inherited styles` joins runs whose
70language or spacing differ, which the page model cannot express, and is
71recorded as refused. Tests compare native text/styles to the original keyboard
72controls, account for the remote prefixes, and retain exact graph identities
73after reopening.
74The ignored offline test `export_native_offline_paragraphs` regenerates candidates
75in a new directory specified by `ONESTORE_OFFLINE_PARAGRAPH_OUTPUT`.