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