1# Native outline editing controls
2
3`empty-children` retains a mixed-client deletion regression: `before.one` exposes
4transaction 22 of the retained local image; `remote.one` was observed after native
5OneNote removed an empty child-list property and coalesced equivalent immutable
6styles. The retained intent addresses the same subtree in both files. The offline
7test requires deletion and its dependent edit to publish after reopening the
8cache, while an actual remote text change retains a content conflict.
9
10OneNote 2010 authored fourteen cases plus an unchanged source page. `before`,
11`after`, and `cold` retain notebook bytes and independent native XML. The final
12phase uses a fresh application cache. Cases preserve Unicode, hyperlinks, tags,
13nested descendants, siblings, and a separate outline.
14
15The controls cover leaf/subtree reordering, subtree indentation/outdentation,
16stored collapse/expansion, deletion of a leaf/subtree/sole paragraph/outline,
17outline position, fixed width, and automatic width. Keyboard subtree operations
18explicitly select descendants. Deleting the sole paragraph removes its empty
19outline. The native application sometimes advances unchanged text timestamps
20and adds `0x880034dd`; the test permits only those observed bookkeeping changes.
21
22COM outline replacement reallocates contained rich-text identities. Keyboard
23movement retains them. Native XML can reorder outlines by their positions while
24the file's page child order remains unchanged. Explicit width sets its native
25user-size flag; automatic width clears that flag. OneNote regenerates height
26from content instead of retaining the requested height. These observations
27constrain typed operations independently of the native COM replacement behavior.
28
29Persisted collapse values survive a cold open. Native keyboard collapse/expand
30can instead change only the client's cached view, so warm COM XML alone does
31not prove a stored-property edit. The controls here explicitly change the
32persisted default through COM.
33
34To regenerate, run `tools/native_runner.py` on
35`corpus/formatted-insertion/native-paragraph/candidate` with a new output directory,
36`--author tools/native/outline-editing.ps1 --expected-pages 15 --inspect
37--collect-notebook`. After inspection is ready, run
38`tools/native_outline_editing.py OUTPUT`. It freezes the before-image, records
39the actual keyboard/XML inputs, and requests final capture; the runner removes
40its clone. Move the returned `before-read` directory into `before/read`.
41Cold-open `OUTPUT/notebook` into another new output directory with the runner,
42`--expected-pages 15 --collect-notebook`. Public verification lives in
43`tools/test_outline_edit.py`.
44
45The controller selects the target again after activating the native window and
46transfers XML as UTF-8 data. Captured authoring scripts retain their exact source;
47identical immutable artifacts link to one canonical corpus copy.
48
49`layout/candidate` applies Rust outline edits to the five geometry and saved
50collapse cases in `before`. `layout/cold` captures that Rust output through a fresh
51OneNote cache. Every active identity, child/content/structure reference, child level,
52and collapse default survives; text, fields, tags and explicit formatting compare
53against native XML. Fixed width renders at 144 points. The automatic 360-point hint
54renders narrower for this content. Stored height remains a hint; native XML reports
55the content-derived height. All fourteen associated tags and 9,577 explicit format
56comparisons pass for both candidate and native-saved images.
57
58Regenerate the layout candidate with the ignored `export_native_outline_candidates`
59test in `crates/onestore/tests/outline.rs`, setting `ONESTORE_OUTLINE_OUTPUT` to a
60new absolute directory. Cold-open that directory with `tools/native_runner.py`,
61`--expected-pages 15 --collect-notebook`. The captured clone is removed by the runner.
62
63`reserved-width` starts from native `after`, whose moved outline has a reserved
64wrapping width. Rust replaces it with an explicit 144-point width and clears the
65obsolete reservation. Native renders at 144 points after a cold reopen, retaining
66all 304 active graph objects, ten tags and 8,457 explicit formatting comparisons.
67To regenerate, run `resizing_a_native_reserved_width_preserves_content` with
68`ONESTORE_RESERVED_WIDTH_OUTPUT` set to a new absolute directory, then cold-open
69it with the same runner arguments.
70
71`offline` reconciles one page-model save per page, carrying a layout or collapse
72change and a dependent text edit, against all fourteen native changes. Seven
73merge automatically; seven are reviewed against the remote page and then
74publish, including the four whose target the native side deleted, where the
75review keeps only the dependent text. The `cases.json` records each page's
76outcome, the changed object, the change and the dependent text object used by
77the public test.
78
79Regenerate by running the sync test
80`native_moves_deletions_and_layout_changes_merge_or_require_review` in
81`crates/notebook/tests/sync_outline.rs` with `ONESTORE_OFFLINE_OUTLINE_OUTPUT`
82set to a new absolute directory, then cold-open its `candidate` with
83`--expected-pages 15 --collect-notebook`. Uncertain revision retention, stale
84review and twelve offline writers are exercised in the same file.
85
86`tree` extends the native controls with eleven cases involving outline groups,
87indentation gaps, numbered/bulleted subtrees, and table cells. The stored graphs,
88identities, tags, fields, and formatting survive a fresh-cache reopen. Deleting
89a group's last subtree removes the empty group. Removing the last unindented
90sibling unwraps the preceding group and transfers its indentation to the outline.
91Deleting a cell's only paragraph creates new empty paragraph/text identities;
92the cell and table remain intact. Outdenting across a two-level gap reduces the
93gap and reparents a following sibling beneath the outdented target, preserving
94that sibling's indentation. Native bullet indentation additionally substitutes
95its list marker; it is distinct from moving a subtree with unchanged formatting.
96
97These keyboard controls retain rich-text identities. Eight edits also establish
98a 423.75-point reserved wrapping width on the selected outline in the captured
99800×600 desktop. The test permits that specific property separately from
100timestamp/bookkeeping changes and verifies all other retained object fields.
101Before/after/cold native comparisons cover twelve pages, eleven/six/six tags,
102and 8,321/7,081/7,081 explicit character-format values.
103
104Regenerate using the same source notebook and runner, with
105`--author corpus/outline-edit/tree/scripts/author.ps1 --expected-pages 12
106--inspect --collect-notebook`. Run the shared `tools/native_outline_editing.py`
107controller at inspection readiness, move `before-read` to `before/read`, then
108cold-open the returned notebook with `--expected-pages 12 --collect-notebook`.
109The exact authoring script has one home in the reference corpus.
110
111`rust-tree` retains four Rust-generated notebooks and their fresh-cache OneNote
112captures. `ordinary` and `groups-cells` apply eighteen moves/deletions from the
113native controls. Explicit bullet-subtree movement preserves its original marker.
114`cross-container` moves content between cells and outlines, moves a whole table,
115and moves a sibling beneath a paragraph while its enclosing group is normalized.
116`unequal-groups` deletes a trailing paragraph after two differently indented
117groups; native XML reports the surviving paragraphs at indentation levels three
118and two. Every surviving content identity, field, tag and table remains intact;
119an emptied cell receives new empty paragraph/text identities.
120
121The four captures cover forty pages. Public tests compare native text and
122formatting, the complete active graphs before/after cold reopen, metadata, and
123list objects. Core tests additionally compare eighteen native transformations,
124every historical object's property bytes, selected move attribution, protected
125content, reused intents, and interrupted publication. The shared stateful model
126in `crates/onestore/tests/support/tree_model.rs` checks paragraph order,
127indentation, content, automatic titles and old/new publication outcomes across
128twelve cached clients; `fuzz/fuzz_targets/tree.rs` runs that oracle under ASan.
129
130Set `ONESTORE_TREE_OUTPUT` to a new absolute directory and run the
131`native_subtree_controls_match_with_preserved_fields_and_history` and
132`cross_container_moves_keep_tables_and_replace_emptied_cells` integration tests,
133plus the `tree::tests::group_normalization_preserves_unequal_indentation_and_overlapping_moves`
134unit test. Cold-open the resulting `ordinary`, `groups-cells`, `cross-container`
135and `unequal-groups` notebooks with expected page counts 15, 12, 12 and 1,
136respectively, using `tools/native_runner.py --collect-notebook`.
137
138`offline-tree` reconciles page-model saves carrying a move or deletion and a
139dependent text edit against the fourteen ordinary native controls. Seven merge
140automatically and seven are reviewed against the remote page before publishing.
141Its `cases.json` records the native input cases and outcomes. Regenerate with
142the sync test
143`native_tree_and_layout_changes_reconcile_without_discarding_unreviewed_content`
144in `crates/notebook/tests/sync/tree.rs`, setting `ONESTORE_OFFLINE_TREE_OUTPUT`
145to a new absolute directory, then cold-open its `candidate` with
146`--expected-pages 15 --collect-notebook`.
147
148Its `cell-delete` and `cell-move` captures additionally verify local edits to an
149emptied cell's replacement paragraph while preserving remote text in the other
150cell. Regenerate with the sync test
151`emptied_cell_replacement_is_durable_and_cannot_be_silently_omitted_on_replay`,
152using the same output variable; cold-open each candidate with twelve expected pages.