| author | |
| committer | |
| log | 44df465c5e6e99c1a98916fa6cbcbde01a666164 |
| tree | e55e5901c921828f860e25c5fbfea16dcdc9d528 |
| parent | cffb05d4803d38e6fbc9acef1aff140f067a5ede |
| signature | Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU |
Retain page identities and publish the new space with section navigation in one transaction. Cover empty and duplicate Unicode titles, native edits and Rust follow-ups, 521-page checkpoint/counter stress, historical asset preservation, and interrupted publication.
Validation: 137 core, 99 offline and 150 Python tests; 29,328 ASan executions; workspace Clippy/formatting; both iOS targets compile. Five native clones removed. Acceptance: evidence/m10/PAGE-CREATION.md.
Assisted-by: gpt-6-astra76 files changed, 1417 insertions(+), 73 deletions(-)
corpus/page-lifecycle/creation/README.md created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | # Page creation | ||
| 2 | |||
| 3 | `candidate` adds four pages to `../03-renamed/notebook/Lifecycle.one`: an appended | ||
| 4 | page without a title node, a prepended page with an empty title field, and two | ||
| 5 | appended pages titled `New 🦋 é`. All thirteen ordered page identities survive | ||
| 6 | each fresh OneNote 2010 reopen. Identical artifacts are relative symlinks. | ||
| 7 | |||
| 8 | `cold` captures the first reopen. `native` adds a distinct body paragraph to each | ||
| 9 | duplicate-title page through `tools/native/created-pages.ps1`; `native/cold` | ||
| 10 | reopens that result in another cache. `followup` prefixes those bodies with | ||
| 11 | `Rust + ` and the titles with `Reviewed `; `followup/cold` reopens that result. | ||
| 12 | The retained `provenance.json` records the native capture inputs and clone removal. | ||
| 13 | |||
| 14 | After building workspace examples, run `python -m unittest discover -s tools | ||
| 15 | -p test_page_creation.py -v`. It compares native XML content and character formats, | ||
| 16 | ordered identities, and complete active object graphs across each cold reopen. | ||
| 17 | These thirteen-page comparisons need no graph normalization. | ||
| 18 | |||
| 19 | Export fresh Rust candidates by setting each variable to a new output directory: | ||
| 20 | |||
| 21 | | Core integration test (`cargo test -p onestore --test page TEST -- --exact`) | Variable | | ||
| 22 | | --- | --- | | ||
| 23 | | `native_section_accepts_empty_and_titled_pages_with_preserved_history` | `ONESTORE_PAGE_CREATION_OUTPUT` | | ||
| 24 | | `native_changes_on_created_pages_accept_rust_followups` | `ONESTORE_PAGE_FOLLOWUP_OUTPUT` | | ||
| 25 | | `repeated_page_creation_crosses_root_fragments_counters_and_section_checkpoints` | `ONESTORE_PAGE_STRESS_OUTPUT` | | ||
| 26 | |||
| 27 | The last test produces 521 pages, crosses a section revision checkpoint and | ||
| 28 | transaction-counter rollover, and checks that every unpublished candidate still | ||
| 29 | exposes the complete preceding page order. Its large native capture is local | ||
| 30 | evidence. Reproduce with `tools/native_runner.py INPUT OUTPUT --expected-pages 521 | ||
| 31 | --collect-notebook`, then `PYTHONPATH=tools python tools/verify_page_creation.py | ||
| 32 | INPUT OUTPUT`. That comparison permits only exact native materialization of a | ||
| 33 | previously absent section metadata copy; all other graph fields compare exactly. | ||
| 34 | |||
| 35 | This core operation deliberately creates one optional title outline without | ||
| 36 | generated date/time text or template content. MS-ONE 2.2.50 permits a title with | ||
| 37 | one or two outlines. The fixture establishes this explicit empty-page contract. | ||
corpus/page-lifecycle/creation/candidate/Lifecycle.one created| Binary files /dev/null and b/corpus/page-lifecycle/creation/candidate/Lifecycle.one differ | |||
corpus/page-lifecycle/creation/cold/notebook/Lifecycle.one created| Binary files /dev/null and b/corpus/page-lifecycle/creation/cold/notebook/Lifecycle.one differ | |||
corpus/page-lifecycle/creation/cold/read/hierarchy.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Notebook xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" name="notebook" nickname="notebook" ID="{3BFEF56D-B4F8-4F2E-A1BC-468DDA94A2D5}{1}{B0}" path="C:\one-tests\runs\capture\notebook" lastModifiedTime="2026-09-09T04:23:59.000Z" color="#B49EDE"><one:Section name="Lifecycle" ID="{C65593FF-0E35-0BF7-1FC3-16CBBB799594}{1}{B0}" path="C:\one-tests\runs\capture\notebook\Lifecycle.one" lastModifiedTime="2026-09-09T04:23:59.000Z" color="#91BAAE"><one:Page ID="{39C1FCAE-45F8-0FA4-3FC6-46AF3A75DC8A}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{266FCA0A-41B5-03F0-0ADE-86136233B704}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{6C02B3F9-D11E-0A62-1E9D-86328FA37C2A}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{4C0D72CA-D8C6-0D40-0E00-40C67411544F}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{58C13BB3-DE03-4816-B303-087ACC456B97}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{054D1020-5845-4210-8DEE-30AE886FFF66}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{5891D2E3-C28F-4C4F-91C8-E802A2DDA3B0}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{8B5220CE-1103-4F42-AD6F-443875AA4EFC}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"/><one:Page ID="{E0B7DA6E-27FF-4573-92CF-4663E293DAE6}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"/><one:Page ID="{9BFEBE8D-72F6-4211-B975-2E62E65AF7D7}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"/><one:Page ID="{3894C714-5BE5-03FC-208C-EFB4E9A37951}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"/><one:Page ID="{067A6101-C793-0F15-0101-74668CB91D5E}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"/><one:Page ID="{C6BB9F1B-5105-064D-086F-0B103A30C43B}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"/></one:Section></one:Notebook> | ||
corpus/page-lifecycle/creation/cold/read/page-000.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{054D1020-5845-4210-8DEE-30AE886FFF66}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{8F196553-BA68-46B8-A5A9-2FFC33D426C2}{28}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[child]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{8F196553-BA68-46B8-A5A9-2FFC33D426C2}{35}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="149.6102294921875" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{8F196553-BA68-46B8-A5A9-2FFC33D426C2}{36}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body child &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-001.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{067A6101-C793-0F15-0101-74668CB91D5E}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{067A6101-C793-0F15-0101-74668CB91D5E}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[New &#129419; é]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-002.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{266FCA0A-41B5-03F0-0ADE-86136233B704}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{E81ABB11-7D00-0B97-2159-DD23F8403BFB}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-003.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{3894C714-5BE5-03FC-208C-EFB4E9A37951}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-004.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{39C1FCAE-45F8-0FA4-3FC6-46AF3A75DC8A}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{39C1FCAE-45F8-0FA4-3FC6-46AF3A75DC8A}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-005.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{4C0D72CA-D8C6-0D40-0E00-40C67411544F}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-006.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{5891D2E3-C28F-4C4F-91C8-E802A2DDA3B0}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{C844F950-C3B5-4FE0-ADCD-588A8B55C0F1}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[grandchild]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{C844F950-C3B5-4FE0-ADCD-588A8B55C0F1}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="175.9715728759766" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{C844F950-C3B5-4FE0-ADCD-588A8B55C0F1}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body grandchild &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-007.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{58C13BB3-DE03-4816-B303-087ACC456B97}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:27.000Z" objectID="{5ADAA2C9-8AA5-4283-813C-C275E2BE752A}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Same title]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{5ADAA2C9-8AA5-4283-813C-C275E2BE752A}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="158.2952728271484" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{5ADAA2C9-8AA5-4283-813C-C275E2BE752A}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body parent &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-008.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{6C02B3F9-D11E-0A62-1E9D-86328FA37C2A}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{43E67622-7E4B-067B-35F7-FE8CA3C5A2A8}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-009.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{8B5220CE-1103-4F42-AD6F-443875AA4EFC}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:23:58.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{A6AAC17A-F7B8-4832-BB11-A47AA3FCCB83}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Renamed &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{EDDDEAD0-9F85-44A8-BE51-3B1A009C7ABD}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="170.2942504882812" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{EDDDEAD0-9F85-44A8-BE51-3B1A009C7ABD}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body duplicate &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-010.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{9BFEBE8D-72F6-4211-B975-2E62E65AF7D7}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{2C80C4C5-DA5C-4DF0-BBB7-F55CC50454C4}{14}{B0}"><one:Position x="36.0" y="14.40000057220459" z="0"/><one:Size width="174.3547973632812" height="13.42771625518799"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{2C80C4C5-DA5C-4DF0-BBB7-F55CC50454C4}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body automatic &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-011.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{C6BB9F1B-5105-064D-086F-0B103A30C43B}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{C6BB9F1B-5105-064D-086F-0B103A30C43B}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[New &#129419; é]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/cold/read/page-012.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{E0B7DA6E-27FF-4573-92CF-4663E293DAE6}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:23:59.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{A539CBE3-2AB2-40C1-871E-FA63AE8FCA56}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{7186FA13-086F-4F43-A09A-2487C41430AA}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="160.1752014160156" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{7186FA13-086F-4F43-A09A-2487C41430AA}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body trailing &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/Lifecycle.one created| Binary files /dev/null and b/corpus/page-lifecycle/creation/followup/Lifecycle.one differ | |||
corpus/page-lifecycle/creation/followup/cold/notebook/Lifecycle.one created| Binary files /dev/null and b/corpus/page-lifecycle/creation/followup/cold/notebook/Lifecycle.one differ | |||
corpus/page-lifecycle/creation/followup/cold/read/hierarchy.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Notebook xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" name="notebook" nickname="notebook" ID="{6DFB689D-2E8E-4686-9997-32046753F9FD}{1}{B0}" path="C:\one-tests\runs\capture\notebook" lastModifiedTime="2026-09-09T04:44:45.000Z" color="#B49EDE"><one:Section name="Lifecycle" ID="{C3953BFE-3B75-0740-087B-6C4AD8A1EE03}{1}{B0}" path="C:\one-tests\runs\capture\notebook\Lifecycle.one" lastModifiedTime="2026-09-09T04:44:45.000Z" color="#91BAAE"><one:Page ID="{3C0154AF-70B8-0313-287E-3C2E59ADA71D}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{23AF620B-74F5-0F47-1D66-FC9201EBCC93}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{69C21BF8-E45E-06D5-0925-FCB3EC7B07BD}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{49CDDACB-ED86-01F7-19B8-3A4717C92FD8}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{5D0193B2-EB43-44A1-A4BB-72FBAF9D1000}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{008DB821-6D05-4EA7-9A56-4A2FEBB784F1}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{5D517AE2-F7CF-40F8-8670-9283C105D827}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{8E9288CF-2443-43F5-BAD7-3EB91672356B}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{E577726F-12BF-49C4-8577-3CE2814BA171}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{9E3E168C-47B6-4EA6-AECD-54E385828C40}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{3D546F15-6EA5-0F4B-3734-95358A7B02C6}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{03BAC900-F2D3-03A2-16B9-0EE7EF6166C9}{1}{B0}" name="Reviewed New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/><one:Page ID="{C37B371A-6445-0AFA-1FD7-719159E8BFAC}{1}{B0}" name="Reviewed New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"/></one:Section></one:Notebook> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-000.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{008DB821-6D05-4EA7-9A56-4A2FEBB784F1}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{8AD9CD52-8F28-4A0F-B211-557D500C5D55}{28}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[child]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{8AD9CD52-8F28-4A0F-B211-557D500C5D55}{35}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="149.6102294921875" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{8AD9CD52-8F28-4A0F-B211-557D500C5D55}{36}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body child &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-001.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{03BAC900-F2D3-03A2-16B9-0EE7EF6166C9}{1}{B0}" name="Reviewed New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:QuickStyleDef index="1" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:42:47.000Z" objectID="{03BAC900-F2D3-03A2-16B9-0EE7EF6166C9}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Reviewed New &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T04:42:47.000Z" objectID="{80CDD07A-F21F-468D-A2FA-A92C4EC6F53F}{10}{B0}"><one:Position x="72.0" y="144.0" z="0"/><one:Size width="244.6467742919922" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T04:33:45.000Z" lastModifiedTime="2026-09-09T04:42:47.000Z" objectID="{80CDD07A-F21F-468D-A2FA-A92C4EC6F53F}{11}{B0}" alignment="left" quickStyleIndex="1"><one:T><![CDATA[Rust + Native body 0 after Rust page creation.]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-002.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{23AF620B-74F5-0F47-1D66-FC9201EBCC93}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{EDDA1310-4840-0720-36E1-A7A29B98406C}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-003.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{3C0154AF-70B8-0313-287E-3C2E59ADA71D}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{3C0154AF-70B8-0313-287E-3C2E59ADA71D}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-004.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{3D546F15-6EA5-0F4B-3734-95358A7B02C6}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-005.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{49CDDACB-ED86-01F7-19B8-3A4717C92FD8}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-006.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{5D0193B2-EB43-44A1-A4BB-72FBAF9D1000}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:27.000Z" objectID="{5F1A0AC8-BFE5-4E34-9684-B8F481660EBD}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Same title]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{5F1A0AC8-BFE5-4E34-9684-B8F481660EBD}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="158.2952728271484" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{5F1A0AC8-BFE5-4E34-9684-B8F481660EBD}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body parent &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-007.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{5D517AE2-F7CF-40F8-8670-9283C105D827}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{CD845151-F6F5-4357-BA75-220BE88DBB66}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[grandchild]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{CD845151-F6F5-4357-BA75-220BE88DBB66}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="175.9715728759766" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{CD845151-F6F5-4357-BA75-220BE88DBB66}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body grandchild &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-008.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{69C21BF8-E45E-06D5-0925-FCB3EC7B07BD}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{4626DE23-4B0B-0ACC-224F-840DC01DD93F}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-009.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{8E9288CF-2443-43F5-BAD7-3EB91672356B}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{A36A697B-C2F8-4485-ACA9-DEFBC024B014}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Renamed &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{E81D42D1-AAC5-481F-A9E9-419B6344012A}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="170.2942504882812" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{E81D42D1-AAC5-481F-A9E9-419B6344012A}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body duplicate &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-010.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{9E3E168C-47B6-4EA6-AECD-54E385828C40}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{29406CC4-EF1C-4147-AC0F-8FDDA6DC2F53}{14}{B0}"><one:Position x="36.0" y="14.40000057220459" z="0"/><one:Size width="174.3547973632812" height="13.42771625518799"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{29406CC4-EF1C-4147-AC0F-8FDDA6DC2F53}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body automatic &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-011.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{C37B371A-6445-0AFA-1FD7-719159E8BFAC}{1}{B0}" name="Reviewed New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:QuickStyleDef index="1" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:42:47.000Z" objectID="{C37B371A-6445-0AFA-1FD7-719159E8BFAC}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Reviewed New &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T04:42:47.000Z" objectID="{DA84E582-1E18-4AD2-984E-701D70B4CB24}{10}{B0}"><one:Position x="72.0" y="144.0" z="0"/><one:Size width="244.6467742919922" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T04:33:45.000Z" lastModifiedTime="2026-09-09T04:42:47.000Z" objectID="{DA84E582-1E18-4AD2-984E-701D70B4CB24}{11}{B0}" alignment="left" quickStyleIndex="1"><one:T><![CDATA[Rust + Native body 1 after Rust page creation.]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/followup/cold/read/page-012.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{E577726F-12BF-49C4-8577-3CE2814BA171}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:44:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{A0F963E2-1FF2-4C76-90A6-80E2CD57B1C1}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{74465212-3D2F-43F4-B722-5E06A7CC4B3D}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="160.1752014160156" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{74465212-3D2F-43F4-B722-5E06A7CC4B3D}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body trailing &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/notebook/Lifecycle.one created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | ../../notebook/Lifecycle.one | ||
| \ No newline at end of file | |||
corpus/page-lifecycle/creation/native/cold/read/hierarchy.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Notebook xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" name="notebook" nickname="notebook" ID="{89446429-1F4A-475B-A18F-A3C179D6E0AB}{1}{B0}" path="C:\one-tests\runs\capture\notebook" lastModifiedTime="2026-09-09T04:37:57.000Z" color="#B49EDE"><one:Section name="Lifecycle" ID="{82D2B6AE-B1AA-0F47-17A3-639D555107BE}{1}{B0}" path="C:\one-tests\runs\capture\notebook\Lifecycle.one" lastModifiedTime="2026-09-09T04:37:57.000Z" color="#91BAAE"><one:Page ID="{7D46D9FF-FA67-0B14-37A6-33F9D45D4EA0}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{62E8EF5B-FE2A-0740-02BE-F3458C1B252E}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{288596A8-6E81-0ED2-16FD-F364618BEE00}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{088A579B-6759-09F0-0660-35909A39C665}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{1C461EE2-619C-4CA6-BB63-7D2C226DF9BD}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{41CA3571-E7DA-46A0-858E-45F866476D4C}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{1C16F7B2-7D10-48FF-99A8-9D544CF5319A}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{CFD5059F-AE9C-4BF2-A50F-316E9B82DCD6}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{A430FF3F-9860-41C3-9AAF-33350CBB48CC}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{DF799BDC-CD69-46A1-B115-5B34087265FD}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{7C13E245-E47A-074C-28EC-9AE2078BEB7B}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{42FD4450-780C-0BA5-0961-013062918F74}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/><one:Page ID="{823CBA4A-EE9A-02FD-000F-7E46D4185611}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"/></one:Section></one:Notebook> | ||
corpus/page-lifecycle/creation/native/cold/read/page-000.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{088A579B-6759-09F0-0660-35909A39C665}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-001.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{1C16F7B2-7D10-48FF-99A8-9D544CF5319A}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{8CC3DC01-7C2A-4B50-A5AD-2DDC657D52DB}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[grandchild]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{8CC3DC01-7C2A-4B50-A5AD-2DDC657D52DB}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="175.9715728759766" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{8CC3DC01-7C2A-4B50-A5AD-2DDC657D52DB}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body grandchild &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-002.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{1C461EE2-619C-4CA6-BB63-7D2C226DF9BD}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:27.000Z" objectID="{1E5D8798-353A-4633-895C-B7230C96E700}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Same title]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{1E5D8798-353A-4633-895C-B7230C96E700}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="158.2952728271484" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{1E5D8798-353A-4633-895C-B7230C96E700}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body parent &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-003.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{288596A8-6E81-0ED2-16FD-F364618BEE00}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{07615373-C1D4-02CB-3D97-8BDA4DED3082}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-004.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{41CA3571-E7DA-46A0-858E-45F866476D4C}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{CB9E4002-05F7-4208-ADC9-5AAADDFCB4E8}{28}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[child]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{CB9E4002-05F7-4208-ADC9-5AAADDFCB4E8}{35}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="149.6102294921875" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{CB9E4002-05F7-4208-ADC9-5AAADDFCB4E8}{36}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body child &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-005.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{42FD4450-780C-0BA5-0961-013062918F74}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:QuickStyleDef index="1" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{42FD4450-780C-0BA5-0961-013062918F74}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[New &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{C18A5D2A-78C0-4E8A-BD22-A6FBC3361C82}{10}{B0}"><one:Position x="72.0" y="144.0" z="0"/><one:Size width="214.4557342529297" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T04:33:45.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{C18A5D2A-78C0-4E8A-BD22-A6FBC3361C82}{11}{B0}" alignment="left" quickStyleIndex="1"><one:T><![CDATA[Native body 0 after Rust page creation.]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-006.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{62E8EF5B-FE2A-0740-02BE-F3458C1B252E}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{AC9D9E40-C29F-0F27-2939-A8751668A9D1}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-007.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{7C13E245-E47A-074C-28EC-9AE2078BEB7B}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-008.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{7D46D9FF-FA67-0B14-37A6-33F9D45D4EA0}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{7D46D9FF-FA67-0B14-37A6-33F9D45D4EA0}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-009.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{823CBA4A-EE9A-02FD-000F-7E46D4185611}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:QuickStyleDef index="1" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{823CBA4A-EE9A-02FD-000F-7E46D4185611}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[New &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{9BC368D2-94C7-42D5-8796-7FCAFD442299}{10}{B0}"><one:Position x="72.0" y="144.0" z="0"/><one:Size width="214.4557342529297" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T04:33:45.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{9BC368D2-94C7-42D5-8796-7FCAFD442299}{11}{B0}" alignment="left" quickStyleIndex="1"><one:T><![CDATA[Native body 1 after Rust page creation.]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-010.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{A430FF3F-9860-41C3-9AAF-33350CBB48CC}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{E1BEEEB2-952D-4471-8F7E-8F3540A7587C}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{3501DF42-B7F0-4BF3-A8FA-51D12A3CA280}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="160.1752014160156" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{3501DF42-B7F0-4BF3-A8FA-51D12A3CA280}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body trailing &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-011.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{CFD5059F-AE9C-4BF2-A50F-316E9B82DCD6}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{E22DE42B-4827-4C82-B371-D12C4DD459A9}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Renamed &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{A95ACF81-201A-4018-B631-4E4CEEB4E897}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="170.2942504882812" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{A95ACF81-201A-4018-B631-4E4CEEB4E897}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body duplicate &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/cold/read/page-012.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{DF799BDC-CD69-46A1-B115-5B34087265FD}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:37:57.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{6807E194-65C3-4940-B3D7-800A2B2CC6EE}{14}{B0}"><one:Position x="36.0" y="14.40000057220459" z="0"/><one:Size width="174.3547973632812" height="13.42771625518799"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{6807E194-65C3-4940-B3D7-800A2B2CC6EE}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body automatic &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/notebook/Lifecycle.one created| Binary files /dev/null and b/corpus/page-lifecycle/creation/native/notebook/Lifecycle.one differ | |||
corpus/page-lifecycle/creation/native/read/hierarchy.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Notebook xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" name="notebook" nickname="notebook" ID="{477DD477-3150-478E-84D1-0D30A0CB781D}{1}{B0}" path="C:\one-tests\runs\capture\notebook" lastModifiedTime="2026-09-09T04:35:14.000Z" color="#B49EDE"><one:Section name="Lifecycle" ID="{2E7A04FF-1560-053C-194A-E3E92C86F3EF}{1}{B0}" path="C:\one-tests\runs\capture\notebook\Lifecycle.one" lastModifiedTime="2026-09-09T04:35:14.000Z" color="#91BAAE"><one:Page ID="{D1EE6BAE-5EAD-016F-394F-B38DAD8ABAF1}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{CE405D0A-5AE0-0D3B-0C57-7331F5CCD17F}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{842D24F9-CA4B-04A9-1814-7310185C1A51}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{A422E5CA-C393-038B-0889-B5E4E3EE3234}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{B0EEACB3-C556-46DD-B58A-FD585BBA0DEC}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{ED628720-4310-4CDB-8B67-C58C1F90991D}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{B0BE45E3-D9DA-4284-9741-1D203522C5CB}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"/><one:Page ID="{637DB7CE-0A56-4189-ABE6-B11AE2552887}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1"/><one:Page ID="{08984D6E-3CAA-4BB8-9446-B341756CBC9D}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1"/><one:Page ID="{73D1298D-69A3-4CDA-BFFC-DB4071A591AC}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1"/><one:Page ID="{D0BB5014-40B0-0D37-2605-1A967E5C1F2A}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1"/><one:Page ID="{EE55F601-DCC6-01DE-0788-81441B467B25}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" pageLevel="1"/><one:Page ID="{2E94081B-4A50-0886-0EE6-FE32ADCFA240}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" pageLevel="1"/></one:Section></one:Notebook> | ||
corpus/page-lifecycle/creation/native/read/page-000.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{08984D6E-3CAA-4BB8-9446-B341756CBC9D}{1}{B0}" name="Body trailing 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{4D165CE3-31E7-4E0A-8197-0F413970AC2D}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{99A96D13-133A-4188-A613-D1A553EB56D1}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="160.1752014160156" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{99A96D13-133A-4188-A613-D1A553EB56D1}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body trailing &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-001.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{2E94081B-4A50-0886-0EE6-FE32ADCFA240}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:QuickStyleDef index="1" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{2E94081B-4A50-0886-0EE6-FE32ADCFA240}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[New &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{376BDA83-300D-48AE-897F-FFBE8493D6C8}{10}{B0}"><one:Position x="72.0" y="144.0" z="0"/><one:Size width="214.4557342529297" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T04:33:45.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{376BDA83-300D-48AE-897F-FFBE8493D6C8}{11}{B0}" alignment="left" quickStyleIndex="1"><one:T><![CDATA[Native body 1 after Rust page creation.]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-002.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{637DB7CE-0A56-4189-ABE6-B11AE2552887}{1}{B0}" name="Renamed 🦋 é" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:34.000Z" lastModifiedTime="2026-09-09T03:09:34.000Z" objectID="{4E85567A-ECED-46F9-BD98-51583403ADF8}{16}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Renamed &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{05F27DD0-84D0-4A63-B8D8-CE3897631CC6}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="170.2942504882812" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{05F27DD0-84D0-4A63-B8D8-CE3897631CC6}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body duplicate &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-003.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{73D1298D-69A3-4CDA-BFFC-DB4071A591AC}{1}{B0}" name="Body automatic 🦀 é preserved" dateTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{C4AF53C5-C109-433B-BD3E-007E52FB32BF}{14}{B0}"><one:Position x="36.0" y="14.40000057220459" z="0"/><one:Size width="174.3547973632812" height="13.42771625518799"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{C4AF53C5-C109-433B-BD3E-007E52FB32BF}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body automatic &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-004.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{842D24F9-CA4B-04A9-1814-7310185C1A51}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{ABC9E122-651E-08B0-337E-0BAE343AC4D3}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-005.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{A422E5CA-C393-038B-0889-B5E4E3EE3234}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-006.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{B0BE45E3-D9DA-4284-9741-1D203522C5CB}{1}{B0}" name="grandchild" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{206B6E50-D8E0-412B-AB44-ADA81CAAA68A}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[grandchild]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{206B6E50-D8E0-412B-AB44-ADA81CAAA68A}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="175.9715728759766" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:30.000Z" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{206B6E50-D8E0-412B-AB44-ADA81CAAA68A}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body grandchild &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-007.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{B0EEACB3-C556-46DD-B58A-FD585BBA0DEC}{1}{B0}" name="Same title" dateTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:27.000Z" objectID="{B2F535C9-91F0-4C48-87B5-375775411351}{32}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[Same title]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{B2F535C9-91F0-4C48-87B5-375775411351}{39}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="158.2952728271484" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:27.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{B2F535C9-91F0-4C48-87B5-375775411351}{40}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body parent &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-008.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{CE405D0A-5AE0-0D3B-0C57-7331F5CCD17F}{1}{B0}" name="Untitled page" dateTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="17.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:19.000Z" lastModifiedTime="2026-09-09T03:09:19.000Z" objectID="{00352C11-6655-055C-27D0-28016FBF5D80}{15}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-009.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{D0BB5014-40B0-0D37-2605-1A967E5C1F2A}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:42.000Z" pageLevel="1"><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-010.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{D1EE6BAE-5EAD-016F-394F-B38DAD8ABAF1}{1}{B0}" name="Untitled page" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{D1EE6BAE-5EAD-016F-394F-B38DAD8ABAF1}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[]]></one:T></one:OE></one:Title></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-011.xml created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{ED628720-4310-4CDB-8B67-C58C1F90991D}{1}{B0}" name="child" dateTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T04:33:41.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title lang="en-US"><one:OE author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{6736F253-A13D-4873-A320-DADEA42B40B9}{28}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[child]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T03:09:30.000Z" objectID="{6736F253-A13D-4873-A320-DADEA42B40B9}{35}{B0}"><one:Position x="36.0" y="86.4000015258789" z="0"/><one:Size width="149.6102294921875" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T03:09:29.000Z" lastModifiedTime="2026-09-09T03:09:29.000Z" objectID="{6736F253-A13D-4873-A320-DADEA42B40B9}{36}{B0}" alignment="left" quickStyleIndex="0"><one:T><![CDATA[<span | ||
| 3 | style='font-weight:bold' lang=en-US>Body child &#129408; é</span><span | ||
| 4 | lang=en-US> </span><span style='font-style:italic' lang=x-none>preserved</span>]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/native/read/page-012.xml created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | <?xml version="1.0"?> | ||
| 2 | <one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote" ID="{EE55F601-DCC6-01DE-0788-81441B467B25}{1}{B0}" name="New 🦋 é" dateTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" pageLevel="1" lang="en-US"><one:QuickStyleDef index="0" name="PageTitle" font="Calibri" fontSize="17.0"/><one:QuickStyleDef index="1" name="p" fontColor="automatic" highlightColor="automatic" font="Calibri" fontSize="11.0" spaceBefore="0.0" spaceAfter="0.0"/><one:PageSettings RTL="false" color="automatic"><one:PageSize><one:Automatic/></one:PageSize><one:RuleLines visible="false"/></one:PageSettings><one:Title showDate="false" showTime="false" lang="en-US"><one:OE author="Rust author" lastModifiedBy="Rust author" creationTime="2026-09-09T04:22:39.000Z" lastModifiedTime="2026-09-09T04:22:39.000Z" objectID="{EE55F601-DCC6-01DE-0788-81441B467B25}{15}{B0}" alignment="left" quickStyleIndex="0" style="font-family:Calibri;font-size:17.0pt"><one:T><![CDATA[New &#129419; é]]></one:T></one:OE></one:Title><one:Outline author="virtual" authorInitials="V" lastModifiedBy="virtual" lastModifiedByInitials="V" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{6D22EF7B-DC0A-44F1-B3CB-268FBAE1E8D3}{10}{B0}"><one:Position x="72.0" y="144.0" z="0"/><one:Size width="214.4557342529297" height="13.42771339416504"/><one:OEChildren><one:OE creationTime="2026-09-09T04:33:45.000Z" lastModifiedTime="2026-09-09T04:33:45.000Z" objectID="{6D22EF7B-DC0A-44F1-B3CB-268FBAE1E8D3}{11}{B0}" alignment="left" quickStyleIndex="1"><one:T><![CDATA[Native body 0 after Rust page creation.]]></one:T></one:OE></one:OEChildren></one:Outline></one:Page> | ||
corpus/page-lifecycle/creation/provenance.json created+115| ... | @@ -0,0 +1,115 @@ | ||
| 1 | { | ||
| 2 | "cold": { | ||
| 3 | "capture": "evidence/m10/page-create-cold", | ||
| 4 | "run": { | ||
| 5 | "notebook": "/Users/clo/dev/one/evidence/m10/page-create-candidate", | ||
| 6 | "expected_pages": 13, | ||
| 7 | "author": null, | ||
| 8 | "author_timeout_seconds": 600, | ||
| 9 | "inspect": false, | ||
| 10 | "collect_notebook": true, | ||
| 11 | "base": { | ||
| 12 | "file": "win7-office-base.qcow2", | ||
| 13 | "format": "qcow2", | ||
| 14 | "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", | ||
| 15 | "virtual_size": 68719476736 | ||
| 16 | }, | ||
| 17 | "scripts": { | ||
| 18 | "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", | ||
| 19 | "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" | ||
| 20 | } | ||
| 21 | }, | ||
| 22 | "machine": { | ||
| 23 | "name": "m6-4b25125e", | ||
| 24 | "hostname": "ONE-M6-4B25125E" | ||
| 25 | }, | ||
| 26 | "teardown": { | ||
| 27 | "absent": true | ||
| 28 | } | ||
| 29 | }, | ||
| 30 | "native": { | ||
| 31 | "capture": "evidence/m10/page-create-native-edit", | ||
| 32 | "run": { | ||
| 33 | "notebook": "/Users/clo/dev/one/evidence/m10/page-create-cold/notebook", | ||
| 34 | "expected_pages": 13, | ||
| 35 | "author": "tools/native/created-pages.ps1", | ||
| 36 | "author_timeout_seconds": 600, | ||
| 37 | "inspect": false, | ||
| 38 | "collect_notebook": true, | ||
| 39 | "base": { | ||
| 40 | "file": "win7-office-base.qcow2", | ||
| 41 | "format": "qcow2", | ||
| 42 | "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", | ||
| 43 | "virtual_size": 68719476736 | ||
| 44 | }, | ||
| 45 | "scripts": { | ||
| 46 | "author.ps1": "f7d94cfa418a971c2911bb3f57b9a9991c9e0b91d0f7d9c7526ca7c8cd5adc42", | ||
| 47 | "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", | ||
| 48 | "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" | ||
| 49 | } | ||
| 50 | }, | ||
| 51 | "machine": { | ||
| 52 | "name": "m6-71dafa89", | ||
| 53 | "hostname": "ONE-M6-71DAFA89" | ||
| 54 | }, | ||
| 55 | "teardown": { | ||
| 56 | "absent": true | ||
| 57 | } | ||
| 58 | }, | ||
| 59 | "native/cold": { | ||
| 60 | "capture": "evidence/m10/page-create-native-edit-cold", | ||
| 61 | "run": { | ||
| 62 | "notebook": "/Users/clo/dev/one/evidence/m10/page-create-native-edit/notebook", | ||
| 63 | "expected_pages": 13, | ||
| 64 | "author": null, | ||
| 65 | "author_timeout_seconds": 600, | ||
| 66 | "inspect": false, | ||
| 67 | "collect_notebook": true, | ||
| 68 | "base": { | ||
| 69 | "file": "win7-office-base.qcow2", | ||
| 70 | "format": "qcow2", | ||
| 71 | "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", | ||
| 72 | "virtual_size": 68719476736 | ||
| 73 | }, | ||
| 74 | "scripts": { | ||
| 75 | "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", | ||
| 76 | "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" | ||
| 77 | } | ||
| 78 | }, | ||
| 79 | "machine": { | ||
| 80 | "name": "m6-eabc83c1", | ||
| 81 | "hostname": "ONE-M6-EABC83C1" | ||
| 82 | }, | ||
| 83 | "teardown": { | ||
| 84 | "absent": true | ||
| 85 | } | ||
| 86 | }, | ||
| 87 | "followup/cold": { | ||
| 88 | "capture": "evidence/m10/page-create-rust-followup-cold", | ||
| 89 | "run": { | ||
| 90 | "notebook": "/Users/clo/dev/one/evidence/m10/page-create-rust-followup", | ||
| 91 | "expected_pages": 13, | ||
| 92 | "author": null, | ||
| 93 | "author_timeout_seconds": 600, | ||
| 94 | "inspect": false, | ||
| 95 | "collect_notebook": true, | ||
| 96 | "base": { | ||
| 97 | "file": "win7-office-base.qcow2", | ||
| 98 | "format": "qcow2", | ||
| 99 | "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", | ||
| 100 | "virtual_size": 68719476736 | ||
| 101 | }, | ||
| 102 | "scripts": { | ||
| 103 | "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", | ||
| 104 | "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" | ||
| 105 | } | ||
| 106 | }, | ||
| 107 | "machine": { | ||
| 108 | "name": "m6-5a91d9d1", | ||
| 109 | "hostname": "ONE-M6-5A91D9D1" | ||
| 110 | }, | ||
| 111 | "teardown": { | ||
| 112 | "absent": true | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
crates/onestore/README.md+8| ... | @@ -45,6 +45,7 @@ harness also accepts `--client-profile release`. | ... | @@ -45,6 +45,7 @@ harness also accepts `--client-profile release`. |
| 45 | | `document::Document`, `Revision::text_runs` | Interpret document objects and inherited text formatting while retaining unknown properties and revision identities | | 45 | | `document::Document`, `Revision::text_runs` | Interpret document objects and inherited text formatting while retaining unknown properties and revision identities | |
| 46 | | `protected::UnlockedSection` (optional feature) | Own decoded buffers for explicit known-password inspection; clear those buffers on drop; derived document strings/exports remain caller-owned | | 46 | | `protected::UnlockedSection` (optional feature) | Own decoded buffers for explicit known-password inspection; clear those buffers on drop; derived document strings/exports remain caller-owned | |
| 47 | | `create_section` | Create one page containing one plain-text paragraph and an author, including Unicode | | 47 | | `create_section` | Create one page containing one plain-text paragraph and an author, including Unicode | |
| 48 | | `PageCreation`, `PreparedEdit::create_page` | Add an empty top-level page and its section entry atomically, retaining page identities across retries | | ||
| 48 | | `create_table_of_contents` | Create ordered section entries from filenames and file identities | | 49 | | `create_table_of_contents` | Create ordered section entries from filenames and file identities | |
| 49 | | `replace_property_bytes` | Append one scalar-property revision; preserve prior revisions and unrelated property values and references | | 50 | | `replace_property_bytes` | Append one scalar-property revision; preserve prior revisions and unrelated property values and references | |
| 50 | | `replace_text`, `commit_text`, `commit_file_text` | Replace a UTF-16 range across ordinary text runs; publish text, run boundaries and modification time together | | 51 | | `replace_text`, `commit_text`, `commit_file_text` | Replace a UTF-16 range across ordinary text runs; publish text, run boundaries and modification time together | |
| ... | @@ -73,6 +74,13 @@ sections retain their encrypted structure and payloads. With the optional | ... | @@ -73,6 +74,13 @@ sections retain their encrypted structure and payloads. With the optional |
| 73 | AES-128/CBC, SHA-1 password wrappers into a borrowed document view. Incorrect | 74 | AES-128/CBC, SHA-1 password wrappers into a borrowed document view. Incorrect |
| 74 | passwords, unsupported protection profiles and work-limit failures remain distinct. | 75 | passwords, unsupported protection profiles and work-limit failures remain distinct. |
| 75 | The source stays encrypted; protected writes are rejected. | 76 | The source stays encrypted; protected writes are rejected. |
| 77 | `PageCreation::new` appends, or inserts before the first page space of an existing | ||
| 78 | series. `Some("")` creates an empty title field; `None` omits the title node. | ||
| 79 | The page has no body outlines, generated date/time text or applied template. | ||
| 80 | Retain the intent to preserve its page, title and space identities; existing | ||
| 81 | identities require reconciliation before retry. Body insertion and title edits | ||
| 82 | use those identities through the existing APIs. [Native page-creation fixtures](../../corpus/page-lifecycle/creation/README.md) | ||
| 83 | cover duplicate Unicode titles, native edits and Rust follow-up edits. | ||
| 76 | Insertions update child references, reference counts, modification times and automatic | 84 | Insertions update child references, reference counts, modification times and automatic |
| 77 | titles atomically. Paragraphs can be nested or inserted into table cells; outline | 85 | titles atomically. Paragraphs can be nested or inserted into table cells; outline |
| 78 | coordinates use points. `Insertion::with_formatting` includes nonoverlapping UTF-16 | 86 | coordinates use points. `Insertion::with_formatting` includes nonoverlapping UTF-16 |
crates/onestore/src/commit.rs+8| ... | @@ -183,6 +183,14 @@ pub struct PreparedEdit<'a> { | ... | @@ -183,6 +183,14 @@ pub struct PreparedEdit<'a> { |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | impl<'a> PreparedEdit<'a> { | 185 | impl<'a> PreparedEdit<'a> { |
| 186 | /// Creates a page and its section entry in one transaction, retaining the intent's identities. | ||
| 187 | pub fn create_page(source: &'a [u8], page: &crate::PageCreation) -> Result<Self, crate::Error> { | ||
| 188 | Ok(Self { | ||
| 189 | source, | ||
| 190 | written: page.apply(source)?, | ||
| 191 | }) | ||
| 192 | } | ||
| 193 | |||
| 186 | /// Moves or removes a subtree and normalizes its containers in one revision. | 194 | /// Moves or removes a subtree and normalizes its containers in one revision. |
| 187 | pub fn tree( | 195 | pub fn tree( |
| 188 | source: &'a [u8], | 196 | source: &'a [u8], |
crates/onestore/src/lib.rs+2| ... | @@ -12,6 +12,7 @@ mod formatting; | ... | @@ -12,6 +12,7 @@ mod formatting; |
| 12 | mod insertion; | 12 | mod insertion; |
| 13 | mod objects; | 13 | mod objects; |
| 14 | mod outline; | 14 | mod outline; |
| 15 | mod page; | ||
| 15 | mod paragraph; | 16 | mod paragraph; |
| 16 | mod properties; | 17 | mod properties; |
| 17 | #[cfg(feature = "protected")] | 18 | #[cfg(feature = "protected")] |
| ... | @@ -35,6 +36,7 @@ pub use formatting::TextAttribute; | ... | @@ -35,6 +36,7 @@ pub use formatting::TextAttribute; |
| 35 | pub use insertion::Insertion; | 36 | pub use insertion::Insertion; |
| 36 | pub use objects::{Object, ObjectData, ObjectReferences, ResolvedRevision}; | 37 | pub use objects::{Object, ObjectData, ObjectReferences, ResolvedRevision}; |
| 37 | pub use outline::OutlineEdit; | 38 | pub use outline::OutlineEdit; |
| 39 | pub use page::PageCreation; | ||
| 38 | pub use paragraph::{ParagraphJoin, ParagraphSplit}; | 40 | pub use paragraph::{ParagraphJoin, ParagraphSplit}; |
| 39 | pub use properties::{IdStream, Property, PropertySets, Value}; | 41 | pub use properties::{IdStream, Property, PropertySets, Value}; |
| 40 | pub use revisions::{ExGuid, ObjectSpace, Revision, RevisionIndex}; | 42 | pub use revisions::{ExGuid, ObjectSpace, Revision, RevisionIndex}; |
crates/onestore/src/page.rs created+260| ... | @@ -0,0 +1,260 @@ | ||
| 1 | use crate::{ | ||
| 2 | Error, ExGuid, | ||
| 3 | create::{current_timestamps, properties, string}, | ||
| 4 | document::{Document, Kind}, | ||
| 5 | write::{PropertyObject, RevisionEdit, fresh_guid, write_revisions}, | ||
| 6 | }; | ||
| 7 | use serde::{Deserialize, Serialize}; | ||
| 8 | use std::{collections::BTreeMap, sync::Arc}; | ||
| 9 | |||
| 10 | fn invalid(message: &'static str) -> Error { | ||
| 11 | Error { offset: 0, message } | ||
| 12 | } | ||
| 13 | |||
| 14 | /// An empty top-level page with stable identities and creation time. | ||
| 15 | /// Retain the intent across retries; an existing page identity rejects duplicate creation. | ||
| 16 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
| 17 | #[serde(deny_unknown_fields)] | ||
| 18 | pub struct PageCreation { | ||
| 19 | guid: [u8; 16], | ||
| 20 | series_guid: [u8; 16], | ||
| 21 | before: Option<ExGuid>, | ||
| 22 | title: Option<String>, | ||
| 23 | author: String, | ||
| 24 | created: u32, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl PageCreation { | ||
| 28 | /// Appends a page, or inserts before the first page space of an existing series. | ||
| 29 | /// `Some("")` creates an empty title field; `None` creates a page without a title node. | ||
| 30 | /// The page has no body outlines or generated date/time text and does not apply a template. | ||
| 31 | pub fn new(before: Option<ExGuid>, title: Option<&str>, author: &str) -> Result<Self, Error> { | ||
| 32 | let page = Self { | ||
| 33 | guid: fresh_guid()?, | ||
| 34 | series_guid: fresh_guid()?, | ||
| 35 | before, | ||
| 36 | title: title.map(str::to_owned), | ||
| 37 | author: author.to_owned(), | ||
| 38 | created: current_timestamps()?.0, | ||
| 39 | }; | ||
| 40 | page.validate()?; | ||
| 41 | Ok(page) | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn space(&self) -> ExGuid { | ||
| 45 | ExGuid { | ||
| 46 | guid: self.guid, | ||
| 47 | n: 1, | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | pub fn object(&self) -> ExGuid { | ||
| 52 | ExGuid { | ||
| 53 | guid: self.guid, | ||
| 54 | n: 12, | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | pub fn title_object(&self) -> Option<ExGuid> { | ||
| 59 | self.title.as_ref().map(|_| ExGuid { | ||
| 60 | guid: self.guid, | ||
| 61 | n: 16, | ||
| 62 | }) | ||
| 63 | } | ||
| 64 | |||
| 65 | fn validate(&self) -> Result<(), Error> { | ||
| 66 | if self.guid == [0; 16] | ||
| 67 | || self.series_guid == [0; 16] | ||
| 68 | || self.guid == self.series_guid | ||
| 69 | || self.author.contains('\0') | ||
| 70 | || self.before.is_some_and(|id| id.guid == [0; 16]) | ||
| 71 | || self | ||
| 72 | .title | ||
| 73 | .as_ref() | ||
| 74 | .is_some_and(|title| title.contains(['\0', '\r', '\n', '\u{fffc}', '\u{fddf}'])) | ||
| 75 | { | ||
| 76 | return Err(invalid( | ||
| 77 | "Use a new page identity, an existing page anchor, and ordinary single-line title text", | ||
| 78 | )); | ||
| 79 | } | ||
| 80 | Ok(()) | ||
| 81 | } | ||
| 82 | |||
| 83 | pub(crate) fn apply(&self, source: &[u8]) -> Result<Vec<u8>, Error> { | ||
| 84 | self.validate()?; | ||
| 85 | write_revisions(source, |index| { | ||
| 86 | if index.spaces.contains_key(&self.space()) { | ||
| 87 | return Err(invalid( | ||
| 88 | "This page identity already exists; reconcile the original creation", | ||
| 89 | )); | ||
| 90 | } | ||
| 91 | let document = Document::parse(index)?; | ||
| 92 | document.pages()?; | ||
| 93 | let section = &document.spaces[&document.root]; | ||
| 94 | let view = &section.revisions[&section.contexts[&ExGuid::default()]]; | ||
| 95 | let section_id = view.roots[&1]; | ||
| 96 | let section_node = &view.nodes[&section_id]; | ||
| 97 | if !matches!(section_node.kind, Kind::Section { .. }) | ||
| 98 | || section_node.extra[0] | ||
| 99 | .iter() | ||
| 100 | .any(|field| field.id == 0x88001cde) | ||
| 101 | { | ||
| 102 | return Err(invalid("Choose an editable section for the new page")); | ||
| 103 | } | ||
| 104 | let position = match self.before { | ||
| 105 | None => section_node.children.len(), | ||
| 106 | Some(before) => section_node | ||
| 107 | .children | ||
| 108 | .iter() | ||
| 109 | .position(|id| view.nodes[id].spaces.first() == Some(&before)) | ||
| 110 | .ok_or_else(|| { | ||
| 111 | invalid("Insert before the first page of an existing series, or append") | ||
| 112 | })?, | ||
| 113 | }; | ||
| 114 | let raw = index.resolve(document.root, section.contexts[&ExGuid::default()])?; | ||
| 115 | let id = |n| ExGuid { guid: self.guid, n }; | ||
| 116 | let reference = |n: u32| n.to_le_bytes().to_vec(); | ||
| 117 | let timestamp = ((u64::from(self.created) + 315532800 + 11644473600) * 10000000) | ||
| 118 | .to_le_bytes() | ||
| 119 | .to_vec(); | ||
| 120 | let modified = || (0x14001d7a, self.created.to_le_bytes().to_vec()); | ||
| 121 | let mut table = BTreeMap::from([(0, self.guid)]); | ||
| 122 | let mut metadata_id = id(1); | ||
| 123 | for (byte, salt) in metadata_id.guid.iter_mut().zip([ | ||
| 124 | 0x31, 0xc0, 0xa8, 0x22, 0, 0x36, 0xee, 0x42, 0xb7, 0x14, 0xd7, 0xac, 0xda, 0x24, | ||
| 125 | 0x35, 0xe8, | ||
| 126 | ]) { | ||
| 127 | *byte ^= salt; | ||
| 128 | } | ||
| 129 | table.insert(1, metadata_id.guid); | ||
| 130 | let table = Arc::new(table); | ||
| 131 | let object = |jcid, values: Vec<_>| -> Result<_, Error> { | ||
| 132 | Ok(PropertyObject { | ||
| 133 | jcid, | ||
| 134 | bytes: properties(&values)?, | ||
| 135 | global_ids: Arc::clone(&table), | ||
| 136 | }) | ||
| 137 | }; | ||
| 138 | let title = self.title.as_deref().unwrap_or_default().trim_start(); | ||
| 139 | let metadata = vec![ | ||
| 140 | (0x1c001c30, self.guid.to_vec()), | ||
| 141 | (0x1c001cf3, string(title)), | ||
| 142 | (0x14001d82, reference(40)), | ||
| 143 | (0x1400348b, reference(40)), | ||
| 144 | (0x14001dff, reference(1)), | ||
| 145 | (0x18001c65, timestamp.clone()), | ||
| 146 | ]; | ||
| 147 | let mut page = vec![ | ||
| 148 | modified(), | ||
| 149 | (0x1c001d75, string(&self.author)), | ||
| 150 | (0x1c001d3c, string("")), | ||
| 151 | ]; | ||
| 152 | if self.title.is_some() { | ||
| 153 | page.push((0x24001d5f, reference(13))); | ||
| 154 | } | ||
| 155 | let mut objects = BTreeMap::from([ | ||
| 156 | (id(10), object(0x60037, vec![(0x24001c1f, reference(12))])?), | ||
| 157 | (id(11), object(0x20030, metadata.clone())?), | ||
| 158 | (id(12), object(0x6000b, page)?), | ||
| 159 | ]); | ||
| 160 | if let Some(title) = &self.title { | ||
| 161 | for (n, jcid, values) in [ | ||
| 162 | ( | ||
| 163 | 13, | ||
| 164 | 0x6002c, | ||
| 165 | vec![ | ||
| 166 | modified(), | ||
| 167 | (0x24001c20, reference(14)), | ||
| 168 | (0x14001c14, 0_f32.to_le_bytes().to_vec()), | ||
| 169 | (0x14001c15, 0_f32.to_le_bytes().to_vec()), | ||
| 170 | ], | ||
| 171 | ), | ||
| 172 | ( | ||
| 173 | 14, | ||
| 174 | 0x6000c, | ||
| 175 | vec![ | ||
| 176 | modified(), | ||
| 177 | (0x24001c20, reference(15)), | ||
| 178 | (0x0c001c03, vec![1]), | ||
| 179 | ], | ||
| 180 | ), | ||
| 181 | ( | ||
| 182 | 15, | ||
| 183 | 0x6000d, | ||
| 184 | vec![ | ||
| 185 | modified(), | ||
| 186 | (0x24001c1f, reference(16)), | ||
| 187 | (0x0c001c03, vec![1]), | ||
| 188 | (0x20001d78, reference(17)), | ||
| 189 | (0x20001d79, reference(17)), | ||
| 190 | (0x14001d09, self.created.to_le_bytes().to_vec()), | ||
| 191 | (0x88001cb4, vec![]), | ||
| 192 | ], | ||
| 193 | ), | ||
| 194 | ( | ||
| 195 | 16, | ||
| 196 | 0x6000e, | ||
| 197 | vec![ | ||
| 198 | modified(), | ||
| 199 | (0x1c001c22, string(title)), | ||
| 200 | (0x24001e13, reference(19)), | ||
| 201 | (0x2000342c, reference(18)), | ||
| 202 | (0x10001cfe, 0x409_u16.to_le_bytes().to_vec()), | ||
| 203 | (0x88001cb4, vec![]), | ||
| 204 | ], | ||
| 205 | ), | ||
| 206 | (17, 0x120001, vec![(0x1c001d75, string(&self.author))]), | ||
| 207 | ( | ||
| 208 | 18, | ||
| 209 | 0x12004d, | ||
| 210 | vec![ | ||
| 211 | (0x1c00345a, string("PageTitle")), | ||
| 212 | (0x1c001c0a, string("Calibri")), | ||
| 213 | (0x10001c0b, 34_u16.to_le_bytes().to_vec()), | ||
| 214 | ], | ||
| 215 | ), | ||
| 216 | (19, 0x12004d, vec![(0x14001c3b, reference(0x409))]), | ||
| 217 | ] { | ||
| 218 | objects.insert(id(n), object(jcid, values)?); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | let series = object( | ||
| 222 | 0x60008, | ||
| 223 | vec![ | ||
| 224 | (0x1c001c30, self.series_guid.to_vec()), | ||
| 225 | (0x18001c65, timestamp), | ||
| 226 | (0x2c001d63, reference(1)), | ||
| 227 | (0x24003442, reference(257)), | ||
| 228 | ], | ||
| 229 | )?; | ||
| 230 | if raw.objects.contains_key(&id(2)) || raw.objects.contains_key(&metadata_id) { | ||
| 231 | return Err(invalid("The new page's section identities already exist")); | ||
| 232 | } | ||
| 233 | let mut parent = PropertyObject::from_object(&raw.objects[&section_id])?; | ||
| 234 | let mut children = section_node.children.clone(); | ||
| 235 | children.insert(position, id(2)); | ||
| 236 | let mut references = Vec::new(); | ||
| 237 | for child in children { | ||
| 238 | references.extend_from_slice(&parent.reference(child)?); | ||
| 239 | } | ||
| 240 | parent.set(&[(0x24001c20, &references)])?; | ||
| 241 | Ok(BTreeMap::from([ | ||
| 242 | ( | ||
| 243 | document.root, | ||
| 244 | RevisionEdit::Update(BTreeMap::from([ | ||
| 245 | (section_id, parent), | ||
| 246 | (id(2), series), | ||
| 247 | (metadata_id, object(0x20030, metadata)?), | ||
| 248 | ])), | ||
| 249 | ), | ||
| 250 | ( | ||
| 251 | self.space(), | ||
| 252 | RevisionEdit::Create { | ||
| 253 | roots: BTreeMap::from([(1, id(10)), (2, id(11))]), | ||
| 254 | objects, | ||
| 255 | }, | ||
| 256 | ), | ||
| 257 | ])) | ||
| 258 | }) | ||
| 259 | } | ||
| 260 | } | ||
crates/onestore/src/write.rs+159-69| ... | @@ -354,6 +354,14 @@ pub(crate) struct PropertyObject { | ... | @@ -354,6 +354,14 @@ pub(crate) struct PropertyObject { |
| 354 | pub global_ids: Arc<BTreeMap<u32, [u8; 16]>>, | 354 | pub global_ids: Arc<BTreeMap<u32, [u8; 16]>>, |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | pub(crate) enum RevisionEdit { | ||
| 358 | Update(BTreeMap<ExGuid, PropertyObject>), | ||
| 359 | Create { | ||
| 360 | roots: BTreeMap<u32, ExGuid>, | ||
| 361 | objects: BTreeMap<ExGuid, PropertyObject>, | ||
| 362 | }, | ||
| 363 | } | ||
| 364 | |||
| 357 | impl PropertyObject { | 365 | impl PropertyObject { |
| 358 | pub fn from_object(object: &crate::Object<'_>) -> Result<Self> { | 366 | pub fn from_object(object: &crate::Object<'_>) -> Result<Self> { |
| 359 | let ObjectData::Properties(bytes) = object.data else { | 367 | let ObjectData::Properties(bytes) = object.data else { |
| ... | @@ -597,13 +605,49 @@ pub(crate) fn write_revision( | ... | @@ -597,13 +605,49 @@ pub(crate) fn write_revision( |
| 597 | message: "Object space has no active default revision", | 605 | message: "Object space has no active default revision", |
| 598 | })?; | 606 | })?; |
| 599 | let revision = index.resolve(space, rid)?; | 607 | let revision = index.resolve(space, rid)?; |
| 600 | Ok(BTreeMap::from([(space, edit(&revision)?)])) | 608 | Ok(BTreeMap::from([( |
| 609 | space, | ||
| 610 | RevisionEdit::Update(edit(&revision)?), | ||
| 611 | )])) | ||
| 601 | }) | 612 | }) |
| 602 | } | 613 | } |
| 603 | 614 | ||
| 615 | fn append_fragment( | ||
| 616 | source: &[u8], | ||
| 617 | output: &mut Vec<u8>, | ||
| 618 | list: &crate::NodeList, | ||
| 619 | nodes: &[Vec<u8>], | ||
| 620 | ) -> Result<(u32, usize)> { | ||
| 621 | let last_fragment = *list.fragments.last().unwrap(); | ||
| 622 | let list_start = usize::try_from(last_fragment.offset).unwrap(); | ||
| 623 | let list_id = u32::from_le_bytes(source[list_start + 8..list_start + 12].try_into().unwrap()); | ||
| 624 | let chunk = append_list(output, list_id, nodes)?; | ||
| 625 | let start = usize::try_from(chunk.offset).unwrap(); | ||
| 626 | let sequence = u32::try_from(list.fragments.len()).map_err(|_| Error { | ||
| 627 | offset: list_start, | ||
| 628 | message: "File-node fragment sequences are exhausted", | ||
| 629 | })?; | ||
| 630 | output[start + 12..start + 16].copy_from_slice(&sequence.to_le_bytes()); | ||
| 631 | let last_node = list.nodes.last().unwrap(); | ||
| 632 | let node_header = u32::from_le_bytes( | ||
| 633 | source[last_node.offset..last_node.offset + 4] | ||
| 634 | .try_into() | ||
| 635 | .unwrap(), | ||
| 636 | ); | ||
| 637 | let nodes_end = last_node.offset + usize::try_from((node_header >> 10) & 0x1fff).unwrap(); | ||
| 638 | let tail = list_start + usize::try_from(last_fragment.length).unwrap() - 20; | ||
| 639 | if tail - nodes_end >= 4 { | ||
| 640 | output[nodes_end..nodes_end + 4].copy_from_slice(&node(0xff, None, &[])?); | ||
| 641 | } | ||
| 642 | output[tail..tail + 8].copy_from_slice(&chunk.offset.to_le_bytes()); | ||
| 643 | output[tail + 8..tail + 12].copy_from_slice(&(chunk.length as u32).to_le_bytes()); | ||
| 644 | |||
| 645 | Ok((list_id, list.nodes.len() + nodes.len())) | ||
| 646 | } | ||
| 647 | |||
| 604 | pub(crate) fn write_revisions( | 648 | pub(crate) fn write_revisions( |
| 605 | source: &[u8], | 649 | source: &[u8], |
| 606 | edit: impl FnOnce(&RevisionIndex<'_>) -> Result<BTreeMap<ExGuid, BTreeMap<ExGuid, PropertyObject>>>, | 650 | edit: impl FnOnce(&RevisionIndex<'_>) -> Result<BTreeMap<ExGuid, RevisionEdit>>, |
| 607 | ) -> Result<Vec<u8>> { | 651 | ) -> Result<Vec<u8>> { |
| 608 | let store = Store::parse(source)?; | 652 | let store = Store::parse(source)?; |
| 609 | let is_section = store.header.file_type == FileType::Section; | 653 | let is_section = store.header.file_type == FileType::Section; |
| ... | @@ -617,25 +661,63 @@ pub(crate) fn write_revisions( | ... | @@ -617,25 +661,63 @@ pub(crate) fn write_revisions( |
| 617 | index.validate_current()?; | 661 | index.validate_current()?; |
| 618 | let changes = edit(&index)?; | 662 | let changes = edit(&index)?; |
| 619 | let mut output = source.to_vec(); | 663 | let mut output = source.to_vec(); |
| 620 | let maximum = store | 664 | let mut maximum = store |
| 621 | .transaction_fragments | 665 | .transaction_fragments |
| 622 | .iter() | 666 | .iter() |
| 623 | .flat_map(|fragment| fragment.entries.chunks_exact(8)) | 667 | .flat_map(|fragment| fragment.entries.chunks_exact(8)) |
| 624 | .map(|entry| u32::from_le_bytes(entry[..4].try_into().unwrap())) | 668 | .map(|entry| u32::from_le_bytes(entry[..4].try_into().unwrap())) |
| 625 | .max() | 669 | .max() |
| 626 | .unwrap(); | 670 | .unwrap(); |
| 671 | let mut allocate_list = || { | ||
| 672 | maximum = maximum.checked_add(1).ok_or(Error { | ||
| 673 | offset: 0, | ||
| 674 | message: "File-node list identities are exhausted", | ||
| 675 | })?; | ||
| 676 | Ok::<_, Error>(maximum) | ||
| 677 | }; | ||
| 627 | let mut counts = Vec::new(); | 678 | let mut counts = Vec::new(); |
| 628 | for (space, mut replacements) in changes { | 679 | let mut root_nodes = Vec::new(); |
| 629 | let rid = *index | 680 | for (space, change) in changes { |
| 630 | .spaces | 681 | let (rid, mut revision, mut replacements) = match change { |
| 631 | .get(&space) | 682 | RevisionEdit::Update(objects) => { |
| 632 | .and_then(|space| space.labels.get(&(ExGuid::default(), 1))) | 683 | let rid = *index |
| 633 | .ok_or(Error { | 684 | .spaces |
| 634 | offset: 0, | 685 | .get(&space) |
| 635 | message: "Object space has no active default revision", | 686 | .and_then(|space| space.labels.get(&(ExGuid::default(), 1))) |
| 636 | })?; | 687 | .ok_or(Error { |
| 637 | let mut revision = index.resolve(space, rid)?; | 688 | offset: 0, |
| 638 | let reachable = revision.reachable()?; | 689 | message: "Object space has no active default revision", |
| 690 | })?; | ||
| 691 | (Some(rid), index.resolve(space, rid)?, objects) | ||
| 692 | } | ||
| 693 | RevisionEdit::Create { roots, objects } => { | ||
| 694 | if !is_section || space.guid == [0; 16] || index.spaces.contains_key(&space) { | ||
| 695 | return Err(Error { | ||
| 696 | offset: 0, | ||
| 697 | message: "Choose a new object-space identity in a section file", | ||
| 698 | }); | ||
| 699 | } | ||
| 700 | if roots.is_empty() || objects.is_empty() { | ||
| 701 | return Err(Error { | ||
| 702 | offset: 0, | ||
| 703 | message: "New object space needs roots and objects", | ||
| 704 | }); | ||
| 705 | } | ||
| 706 | ( | ||
| 707 | None, | ||
| 708 | crate::ResolvedRevision { | ||
| 709 | roots, | ||
| 710 | objects: BTreeMap::new(), | ||
| 711 | }, | ||
| 712 | objects, | ||
| 713 | ) | ||
| 714 | } | ||
| 715 | }; | ||
| 716 | let reachable = if rid.is_some() { | ||
| 717 | revision.reachable()? | ||
| 718 | } else { | ||
| 719 | BTreeSet::new() | ||
| 720 | }; | ||
| 639 | for (id, replacement) in &replacements { | 721 | for (id, replacement) in &replacements { |
| 640 | if let Some(object) = revision.objects.get(id) { | 722 | if let Some(object) = revision.objects.get(id) { |
| 641 | if !reachable.contains(id) { | 723 | if !reachable.contains(id) { |
| ... | @@ -769,11 +851,10 @@ pub(crate) fn write_revisions( | ... | @@ -769,11 +851,10 @@ pub(crate) fn write_revisions( |
| 769 | } | 851 | } |
| 770 | 852 | ||
| 771 | // Native cold-open fails on long dependency chains; cap their depth at 512. | 853 | // Native cold-open fails on long dependency chains; cap their depth at 512. |
| 772 | let checkpoint = std::iter::successors(Some(rid), |id| { | 854 | let checkpoint = rid.is_none() |
| 773 | index.spaces[&space].revisions[id].dependency | 855 | || std::iter::successors(rid, |id| index.spaces[&space].revisions[id].dependency) |
| 774 | }) | 856 | .nth(511) |
| 775 | .nth(511) | 857 | .is_some(); |
| 776 | .is_some(); | ||
| 777 | let selected: Vec<_> = revision | 858 | let selected: Vec<_> = revision |
| 778 | .objects | 859 | .objects |
| 779 | .iter() | 860 | .iter() |
| ... | @@ -821,13 +902,25 @@ pub(crate) fn write_revisions( | ... | @@ -821,13 +902,25 @@ pub(crate) fn write_revisions( |
| 821 | }; | 902 | }; |
| 822 | let mut start = Vec::new(); | 903 | let mut start = Vec::new(); |
| 823 | new_rid.encode(&mut start); | 904 | new_rid.encode(&mut start); |
| 824 | if checkpoint { ExGuid::default() } else { rid }.encode(&mut start); | 905 | if checkpoint { |
| 906 | ExGuid::default() | ||
| 907 | } else { | ||
| 908 | rid.unwrap() | ||
| 909 | } | ||
| 910 | .encode(&mut start); | ||
| 825 | if !is_section { | 911 | if !is_section { |
| 826 | start.extend_from_slice(&0_u64.to_le_bytes()); | 912 | start.extend_from_slice(&0_u64.to_le_bytes()); |
| 827 | } | 913 | } |
| 828 | start.extend_from_slice(&1_u32.to_le_bytes()); | 914 | start.extend_from_slice(&1_u32.to_le_bytes()); |
| 829 | start.extend_from_slice(&0_u16.to_le_bytes()); | 915 | start.extend_from_slice(&0_u16.to_le_bytes()); |
| 830 | let mut manifest = vec![node(if is_section { 0x1e } else { 0x1b }, None, &start)?]; | 916 | let mut manifest = Vec::new(); |
| 917 | if rid.is_none() { | ||
| 918 | let mut payload = Vec::new(); | ||
| 919 | space.encode(&mut payload); | ||
| 920 | payload.extend_from_slice(&0_u32.to_le_bytes()); | ||
| 921 | manifest.push(node(0x14, None, &payload)?); | ||
| 922 | } | ||
| 923 | manifest.push(node(if is_section { 0x1e } else { 0x1b }, None, &start)?); | ||
| 831 | for (table, objects) in groups { | 924 | for (table, objects) in groups { |
| 832 | let mut payload = Vec::new(); | 925 | let mut payload = Vec::new(); |
| 833 | let mut group = if is_section { | 926 | let mut group = if is_section { |
| ... | @@ -941,14 +1034,7 @@ pub(crate) fn write_revisions( | ... | @@ -941,14 +1034,7 @@ pub(crate) fn write_revisions( |
| 941 | } | 1034 | } |
| 942 | if is_section { | 1035 | if is_section { |
| 943 | group.push(node(0xb8, None, &[])?); | 1036 | group.push(node(0xb8, None, &[])?); |
| 944 | let group_id = u32::try_from(counts.len()) | 1037 | let group_id = allocate_list()?; |
| 945 | .ok() | ||
| 946 | .and_then(|n| n.checked_add(1)) | ||
| 947 | .and_then(|n| maximum.checked_add(n)) | ||
| 948 | .ok_or(Error { | ||
| 949 | offset: 0, | ||
| 950 | message: "File-node list identities are exhausted", | ||
| 951 | })?; | ||
| 952 | let chunk = append_list(&mut output, group_id, &group)?; | 1038 | let chunk = append_list(&mut output, group_id, &group)?; |
| 953 | counts.push((group_id, group.len())); | 1039 | counts.push((group_id, group.len())); |
| 954 | manifest.push(node(0xb0, Some(Reference::NodeList(chunk)), &payload)?); | 1040 | manifest.push(node(0xb0, Some(Reference::NodeList(chunk)), &payload)?); |
| ... | @@ -979,47 +1065,51 @@ pub(crate) fn write_revisions( | ... | @@ -979,47 +1065,51 @@ pub(crate) fn write_revisions( |
| 979 | } | 1065 | } |
| 980 | } | 1066 | } |
| 981 | manifest.push(node(0x1c, None, &[])?); | 1067 | manifest.push(node(0x1c, None, &[])?); |
| 982 | let root = store.list(store.header.root)?; | 1068 | if rid.is_none() { |
| 983 | let space_node = root | 1069 | let list_id = allocate_list()?; |
| 984 | .nodes | 1070 | let chunk = append_list(&mut output, list_id, &manifest)?; |
| 985 | .iter() | 1071 | counts.push((list_id, manifest.len())); |
| 986 | .find(|node| node.id == 8 && node.fields(&store).exguid() == Ok(space)) | 1072 | let mut payload = Vec::new(); |
| 987 | .ok_or(Error { | 1073 | space.encode(&mut payload); |
| 988 | offset: 0, | 1074 | let nodes = vec![ |
| 989 | message: "Object space is absent from the root list", | 1075 | node(0xc, None, &payload)?, |
| 990 | })?; | 1076 | node(0x10, Some(Reference::NodeList(chunk)), &[])?, |
| 991 | let space_list = space_node.referenced_list(&store)?; | 1077 | ]; |
| 992 | let revision_node = space_list.iter().rfind(|node| node.id == 0x10).unwrap(); | 1078 | let list_id = allocate_list()?; |
| 993 | let Some(Reference::NodeList(manifest_reference)) = revision_node.reference else { | 1079 | let chunk = append_list(&mut output, list_id, &nodes)?; |
| 994 | unreachable!() | 1080 | counts.push((list_id, nodes.len())); |
| 995 | }; | 1081 | root_nodes.push(node(8, Some(Reference::NodeList(chunk)), &payload)?); |
| 996 | let revision_list = store.list(manifest_reference)?; | 1082 | } else { |
| 997 | let last_fragment = *revision_list.fragments.last().unwrap(); | 1083 | let root = store.list(store.header.root)?; |
| 998 | let list_start = usize::try_from(last_fragment.offset).unwrap(); | 1084 | let space_node = root |
| 999 | let list_id = | 1085 | .nodes |
| 1000 | u32::from_le_bytes(source[list_start + 8..list_start + 12].try_into().unwrap()); | 1086 | .iter() |
| 1001 | let manifest_chunk = append_list(&mut output, list_id, &manifest)?; | 1087 | .find(|node| node.id == 8 && node.fields(&store).exguid() == Ok(space)) |
| 1002 | let manifest_start = usize::try_from(manifest_chunk.offset).unwrap(); | 1088 | .ok_or(Error { |
| 1003 | let sequence = u32::try_from(revision_list.fragments.len()).map_err(|_| Error { | 1089 | offset: 0, |
| 1004 | offset: list_start, | 1090 | message: "Object space is absent from the root list", |
| 1005 | message: "File-node fragment sequences are exhausted", | 1091 | })?; |
| 1006 | })?; | 1092 | let space_list = space_node.referenced_list(&store)?; |
| 1007 | output[manifest_start + 12..manifest_start + 16].copy_from_slice(&sequence.to_le_bytes()); | 1093 | let revision_node = space_list.iter().rfind(|node| node.id == 0x10).unwrap(); |
| 1008 | let last_node = revision_list.nodes.last().unwrap(); | 1094 | let Some(Reference::NodeList(manifest_reference)) = revision_node.reference else { |
| 1009 | let node_header = u32::from_le_bytes( | 1095 | unreachable!() |
| 1010 | source[last_node.offset..last_node.offset + 4] | 1096 | }; |
| 1011 | .try_into() | 1097 | let revision_list = store.list(manifest_reference)?; |
| 1012 | .unwrap(), | 1098 | counts.push(append_fragment( |
| 1013 | ); | 1099 | source, |
| 1014 | let nodes_end = last_node.offset + usize::try_from((node_header >> 10) & 0x1fff).unwrap(); | 1100 | &mut output, |
| 1015 | let tail = list_start + usize::try_from(last_fragment.length).unwrap() - 20; | 1101 | revision_list, |
| 1016 | if tail - nodes_end >= 4 { | 1102 | &manifest, |
| 1017 | output[nodes_end..nodes_end + 4].copy_from_slice(&node(0xff, None, &[])?); | 1103 | )?); |
| 1018 | } | 1104 | } |
| 1019 | output[tail..tail + 8].copy_from_slice(&manifest_chunk.offset.to_le_bytes()); | 1105 | } |
| 1020 | output[tail + 8..tail + 12].copy_from_slice(&(manifest_chunk.length as u32).to_le_bytes()); | 1106 | if !root_nodes.is_empty() { |
| 1021 | 1107 | counts.push(append_fragment( | |
| 1022 | counts.push((list_id, revision_list.nodes.len() + manifest.len())); | 1108 | source, |
| 1109 | &mut output, | ||
| 1110 | store.list(store.header.root)?, | ||
| 1111 | &root_nodes, | ||
| 1112 | )?); | ||
| 1023 | } | 1113 | } |
| 1024 | if counts.is_empty() { | 1114 | if counts.is_empty() { |
| 1025 | return Ok(source.to_vec()); | 1115 | return Ok(source.to_vec()); |
crates/onestore/src/write/tests/multi.rs+10-4| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | ExGuid, RevisionIndex, Store, | 2 | ExGuid, RevisionIndex, Store, |
| 3 | document::{Document, Kind}, | 3 | document::{Document, Kind}, |
| 4 | write::{PropertyObject, write_revisions}, | 4 | write::{PropertyObject, RevisionEdit, write_revisions}, |
| 5 | }; | 5 | }; |
| 6 | use std::collections::BTreeMap; | 6 | use std::collections::BTreeMap; |
| 7 | 7 | ||
| ... | @@ -90,7 +90,10 @@ fn nest(source: &[u8]) -> Vec<u8> { | ... | @@ -90,7 +90,10 @@ fn nest(source: &[u8]) -> Vec<u8> { |
| 90 | object.set(&[(0x24001c20, &children)])?; | 90 | object.set(&[(0x24001c20, &children)])?; |
| 91 | replacements.insert(root, object); | 91 | replacements.insert(root, object); |
| 92 | changes.insert(index.root, replacements); | 92 | changes.insert(index.root, replacements); |
| 93 | Ok(changes) | 93 | Ok(changes |
| 94 | .into_iter() | ||
| 95 | .map(|(sid, objects)| (sid, RevisionEdit::Update(objects))) | ||
| 96 | .collect()) | ||
| 94 | }) | 97 | }) |
| 95 | .unwrap() | 98 | .unwrap() |
| 96 | } | 99 | } |
| ... | @@ -213,7 +216,7 @@ fn empty_batches_and_invalid_spaces_do_not_produce_an_edit() { | ... | @@ -213,7 +216,7 @@ fn empty_batches_and_invalid_spaces_do_not_produce_an_edit() { |
| 213 | assert!( | 216 | assert!( |
| 214 | write_revisions(SOURCE, |_| Ok(BTreeMap::from([( | 217 | write_revisions(SOURCE, |_| Ok(BTreeMap::from([( |
| 215 | ExGuid::default(), | 218 | ExGuid::default(), |
| 216 | BTreeMap::new() | 219 | RevisionEdit::Update(BTreeMap::new()) |
| 217 | )]))) | 220 | )]))) |
| 218 | .is_err() | 221 | .is_err() |
| 219 | ); | 222 | ); |
| ... | @@ -247,7 +250,10 @@ fn repeated_multi_space_edits_cross_counter_carries_and_checkpoint_each_space() | ... | @@ -247,7 +250,10 @@ fn repeated_multi_space_edits_cross_counter_carries_and_checkpoint_each_space() |
| 247 | object.set(&[(property, &step.to_le_bytes())])?; | 250 | object.set(&[(property, &step.to_le_bytes())])?; |
| 248 | changes.insert(*sid, BTreeMap::from([(id, object)])); | 251 | changes.insert(*sid, BTreeMap::from([(id, object)])); |
| 249 | } | 252 | } |
| 250 | Ok(changes) | 253 | Ok(changes |
| 254 | .into_iter() | ||
| 255 | .map(|(sid, objects)| (sid, RevisionEdit::Update(objects))) | ||
| 256 | .collect()) | ||
| 251 | }) | 257 | }) |
| 252 | .unwrap(); | 258 | .unwrap(); |
| 253 | let store = Store::parse(&written).unwrap(); | 259 | let store = Store::parse(&written).unwrap(); |
crates/onestore/tests/page.rs created+356| ... | @@ -0,0 +1,356 @@ | ||
| 1 | use onestore::{ | ||
| 2 | ExGuid, Insertion, PageCreation, PreparedEdit, RevisionIndex, Store, | ||
| 3 | document::{Document, Kind}, | ||
| 4 | }; | ||
| 5 | |||
| 6 | #[path = "support/current.rs"] | ||
| 7 | mod current; | ||
| 8 | #[path = "support/disk.rs"] | ||
| 9 | mod disk; | ||
| 10 | |||
| 11 | const SOURCE: &[u8] = | ||
| 12 | include_bytes!("../../../corpus/page-lifecycle/03-renamed/notebook/Lifecycle.one"); | ||
| 13 | |||
| 14 | #[test] | ||
| 15 | fn native_section_accepts_empty_and_titled_pages_with_preserved_history() { | ||
| 16 | let original = Store::parse(SOURCE).unwrap(); | ||
| 17 | let old_index = RevisionIndex::parse(&original).unwrap(); | ||
| 18 | let original_pages = Document::parse(&old_index).unwrap().pages().unwrap(); | ||
| 19 | let mut expected = original_pages.clone(); | ||
| 20 | let mut source = SOURCE.to_vec(); | ||
| 21 | for (ordinal, title) in [None, Some(""), Some("New 🦋 é"), Some("New 🦋 é")] | ||
| 22 | .into_iter() | ||
| 23 | .enumerate() | ||
| 24 | { | ||
| 25 | let before = (ordinal == 1).then_some(original_pages[0].0); | ||
| 26 | let intent = PageCreation::new(before, title, "Rust author").unwrap(); | ||
| 27 | let serialized = serde_json::to_vec(&intent).unwrap(); | ||
| 28 | let retained = serde_json::from_slice(&serialized).unwrap(); | ||
| 29 | assert_eq!(intent, retained); | ||
| 30 | let prepared = PreparedEdit::create_page(&source, &retained).unwrap(); | ||
| 31 | let store = Store::parse(prepared.as_bytes()).unwrap(); | ||
| 32 | assert_eq!( | ||
| 33 | store.header.transaction_count, | ||
| 34 | original.header.transaction_count + ordinal as u32 + 1 | ||
| 35 | ); | ||
| 36 | assert_eq!(store.header.file_id, original.header.file_id); | ||
| 37 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 38 | index.validate_current().unwrap(); | ||
| 39 | let document = Document::parse(&index).unwrap(); | ||
| 40 | let at = if ordinal == 1 { 0 } else { expected.len() }; | ||
| 41 | expected.insert(at, (intent.space(), intent.object())); | ||
| 42 | assert_eq!(document.pages().unwrap(), expected); | ||
| 43 | let view = &document.spaces[&intent.space()]; | ||
| 44 | let view = &view.revisions[&view.contexts[&ExGuid::default()]]; | ||
| 45 | assert!(view.nodes[&intent.object()].children.is_empty()); | ||
| 46 | assert_eq!( | ||
| 47 | view.nodes[&intent.object()].structure.len(), | ||
| 48 | usize::from(title.is_some()) | ||
| 49 | ); | ||
| 50 | let Kind::Metadata { | ||
| 51 | title: actual, | ||
| 52 | level, | ||
| 53 | } = &view.nodes[&view.roots[&2]].kind | ||
| 54 | else { | ||
| 55 | panic!() | ||
| 56 | }; | ||
| 57 | assert_eq!(actual.as_deref(), Some(title.unwrap_or_default())); | ||
| 58 | assert_eq!(*level, Some(1)); | ||
| 59 | if let Some(text) = intent.title_object() { | ||
| 60 | let Kind::RichText { | ||
| 61 | text, boilerplate, .. | ||
| 62 | } = &view.nodes[&text].kind | ||
| 63 | else { | ||
| 64 | panic!() | ||
| 65 | }; | ||
| 66 | assert_eq!(text, title.unwrap()); | ||
| 67 | assert!(!boilerplate); | ||
| 68 | } | ||
| 69 | for (sid, space) in &old_index.spaces { | ||
| 70 | for rid in space.revisions.keys() { | ||
| 71 | assert_eq!( | ||
| 72 | format!("{:?}", old_index.resolve(*sid, *rid).unwrap()), | ||
| 73 | format!("{:?}", index.resolve(*sid, *rid).unwrap()) | ||
| 74 | ); | ||
| 75 | } | ||
| 76 | if *sid != old_index.root { | ||
| 77 | assert_eq!(space.labels, index.spaces[sid].labels); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | assert!(PreparedEdit::create_page(prepared.as_bytes(), &intent).is_err()); | ||
| 81 | source = prepared.as_bytes().to_vec(); | ||
| 82 | } | ||
| 83 | if let Some(output) = std::env::var_os("ONESTORE_PAGE_CREATION_OUTPUT") { | ||
| 84 | std::fs::create_dir(&output).unwrap(); | ||
| 85 | std::fs::write(std::path::Path::new(&output).join("Lifecycle.one"), &source).unwrap(); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | #[test] | ||
| 90 | fn created_pages_support_title_edits_and_body_insertion() { | ||
| 91 | let mut source = onestore::create_section("pages.one", "Original", "Author").unwrap(); | ||
| 92 | for title in [None, Some(""), Some("Explicit 🦋 é")] { | ||
| 93 | let intent = PageCreation::new(None, title, "Author").unwrap(); | ||
| 94 | source = PreparedEdit::create_page(&source, &intent) | ||
| 95 | .unwrap() | ||
| 96 | .as_bytes() | ||
| 97 | .to_vec(); | ||
| 98 | let insertion = | ||
| 99 | Insertion::outline(intent.object(), 36.0, 36.0, "Body 🦀 é", "Author").unwrap(); | ||
| 100 | source = PreparedEdit::insert(&source, intent.space(), &insertion) | ||
| 101 | .unwrap() | ||
| 102 | .as_bytes() | ||
| 103 | .to_vec(); | ||
| 104 | let store = Store::parse(&source).unwrap(); | ||
| 105 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 106 | let document = Document::parse(&index).unwrap(); | ||
| 107 | let view = &document.spaces[&intent.space()]; | ||
| 108 | let view = &view.revisions[&view.contexts[&ExGuid::default()]]; | ||
| 109 | let Kind::Metadata { title: actual, .. } = &view.nodes[&view.roots[&2]].kind else { | ||
| 110 | panic!() | ||
| 111 | }; | ||
| 112 | assert_eq!( | ||
| 113 | actual.as_deref(), | ||
| 114 | Some(title.filter(|s| !s.is_empty()).unwrap_or("Body 🦀 é")) | ||
| 115 | ); | ||
| 116 | if let Some(text) = intent.title_object() { | ||
| 117 | source = PreparedEdit::text( | ||
| 118 | &source, | ||
| 119 | intent.space(), | ||
| 120 | text, | ||
| 121 | 0..title.unwrap().encode_utf16().count() as u32, | ||
| 122 | "Renamed", | ||
| 123 | ) | ||
| 124 | .unwrap() | ||
| 125 | .as_bytes() | ||
| 126 | .to_vec(); | ||
| 127 | let store = Store::parse(&source).unwrap(); | ||
| 128 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 129 | let document = Document::parse(&index).unwrap(); | ||
| 130 | let view = &document.spaces[&intent.space()]; | ||
| 131 | let view = &view.revisions[&view.contexts[&ExGuid::default()]]; | ||
| 132 | let Kind::Metadata { title, .. } = &view.nodes[&view.roots[&2]].kind else { | ||
| 133 | panic!() | ||
| 134 | }; | ||
| 135 | assert_eq!(title.as_deref(), Some("Renamed")); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | #[test] | ||
| 141 | fn invalid_page_intents_and_nonleading_anchors_reject_before_publication() { | ||
| 142 | for title in ["a\nb", "\r", "\0", "\u{fffc}", "\u{fddf}"] { | ||
| 143 | assert!(PageCreation::new(None, Some(title), "Author").is_err()); | ||
| 144 | } | ||
| 145 | assert!(PageCreation::new(None, None, "\0").is_err()); | ||
| 146 | assert!(PageCreation::new(Some(ExGuid::default()), None, "Author").is_err()); | ||
| 147 | let source = include_bytes!("../../../corpus/page-lifecycle/04-nested/notebook/Lifecycle.one"); | ||
| 148 | let store = Store::parse(source).unwrap(); | ||
| 149 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 150 | let pages = Document::parse(&index).unwrap().pages().unwrap(); | ||
| 151 | let intent = PageCreation::new(Some(pages[4].0), Some("Child"), "Author").unwrap(); | ||
| 152 | assert!(PreparedEdit::create_page(source, &intent).is_err()); | ||
| 153 | let mut value = serde_json::to_value(PageCreation::new(None, None, "Author").unwrap()).unwrap(); | ||
| 154 | value["guid"] = serde_json::to_value([0_u8; 16]).unwrap(); | ||
| 155 | let invalid: PageCreation = serde_json::from_value(value.clone()).unwrap(); | ||
| 156 | assert!(PreparedEdit::create_page(source, &invalid).is_err()); | ||
| 157 | value["unknown"] = true.into(); | ||
| 158 | assert!(serde_json::from_value::<PageCreation>(value).is_err()); | ||
| 159 | } | ||
| 160 | |||
| 161 | #[test] | ||
| 162 | fn new_space_and_section_entry_publish_as_one_complete_action() { | ||
| 163 | let source = onestore::create_section("pages.one", "Original", "Author").unwrap(); | ||
| 164 | let intent = PageCreation::new(None, Some("New 🦋 é"), "Author").unwrap(); | ||
| 165 | let prepared = PreparedEdit::create_page(&source, &intent).unwrap(); | ||
| 166 | let old = current::current(&source); | ||
| 167 | let new = current::current(prepared.as_bytes()); | ||
| 168 | assert_eq!(new.len(), old.len() + 1); | ||
| 169 | for write_limit in [1, 17, 4096] { | ||
| 170 | let mut complete = disk::Disk { | ||
| 171 | visible: source.clone(), | ||
| 172 | durable: source.clone(), | ||
| 173 | operation: 0, | ||
| 174 | fail_at: None, | ||
| 175 | write_limit, | ||
| 176 | random: 1954, | ||
| 177 | }; | ||
| 178 | prepared.commit(&mut complete).unwrap(); | ||
| 179 | assert_eq!(complete.durable, prepared.as_bytes()); | ||
| 180 | for fail_at in 1..=complete.operation { | ||
| 181 | let mut interrupted = disk::Disk { | ||
| 182 | visible: source.clone(), | ||
| 183 | durable: source.clone(), | ||
| 184 | operation: 0, | ||
| 185 | fail_at: Some(fail_at), | ||
| 186 | write_limit, | ||
| 187 | random: 1954 + fail_at as u64, | ||
| 188 | }; | ||
| 189 | prepared.commit(&mut interrupted).unwrap_err(); | ||
| 190 | let observed = current::current(&interrupted.durable); | ||
| 191 | assert!( | ||
| 192 | observed == old || observed == new, | ||
| 193 | "{write_limit}:{fail_at}" | ||
| 194 | ); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | #[test] | ||
| 200 | fn repeated_page_creation_crosses_root_fragments_counters_and_section_checkpoints() { | ||
| 201 | let mut source = onestore::create_section("PageStress.one", "Original", "Author").unwrap(); | ||
| 202 | let original = source.clone(); | ||
| 203 | let original_store = Store::parse(&original).unwrap(); | ||
| 204 | let original_index = RevisionIndex::parse(&original_store).unwrap(); | ||
| 205 | let mut expected = Document::parse(&original_index).unwrap().pages().unwrap(); | ||
| 206 | let mut checkpoints = 0; | ||
| 207 | for step in 1..=520 { | ||
| 208 | let title = format!("Page {} 🦋 é", step % 7); | ||
| 209 | let intent = PageCreation::new( | ||
| 210 | None, | ||
| 211 | (step % 2 != 0).then_some(title.as_str()), | ||
| 212 | "Stress author", | ||
| 213 | ) | ||
| 214 | .unwrap(); | ||
| 215 | let prepared = PreparedEdit::create_page(&source, &intent).unwrap(); | ||
| 216 | let mut unpublished = prepared.as_bytes().to_vec(); | ||
| 217 | unpublished[96..100].copy_from_slice(&source[96..100]); | ||
| 218 | let old_store = Store::parse(&unpublished).unwrap(); | ||
| 219 | let old_index = RevisionIndex::parse(&old_store).unwrap(); | ||
| 220 | assert_eq!( | ||
| 221 | Document::parse(&old_index).unwrap().pages().unwrap(), | ||
| 222 | expected | ||
| 223 | ); | ||
| 224 | let store = Store::parse(prepared.as_bytes()).unwrap(); | ||
| 225 | assert_eq!(store.header.root, original_store.header.root); | ||
| 226 | assert_eq!( | ||
| 227 | store.header.transaction_count, | ||
| 228 | original_store.header.transaction_count + step | ||
| 229 | ); | ||
| 230 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 231 | assert_eq!( | ||
| 232 | index.spaces.len(), | ||
| 233 | original_index.spaces.len() + step as usize | ||
| 234 | ); | ||
| 235 | expected.push((intent.space(), intent.object())); | ||
| 236 | assert_eq!(Document::parse(&index).unwrap().pages().unwrap(), expected); | ||
| 237 | let section = &index.spaces[&index.root]; | ||
| 238 | let rid = section.labels[&(ExGuid::default(), 1)]; | ||
| 239 | checkpoints += usize::from(section.revisions[&rid].dependency.is_none()); | ||
| 240 | for (sid, space) in &original_index.spaces { | ||
| 241 | for rid in space.revisions.keys() { | ||
| 242 | assert_eq!( | ||
| 243 | format!("{:?}", original_index.resolve(*sid, *rid).unwrap()), | ||
| 244 | format!("{:?}", index.resolve(*sid, *rid).unwrap()) | ||
| 245 | ); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | source = prepared.as_bytes().to_vec(); | ||
| 249 | } | ||
| 250 | assert_eq!(checkpoints, 1); | ||
| 251 | if let Some(output) = std::env::var_os("ONESTORE_PAGE_STRESS_OUTPUT") { | ||
| 252 | std::fs::create_dir(&output).unwrap(); | ||
| 253 | std::fs::write( | ||
| 254 | std::path::Path::new(&output).join("PageStress.one"), | ||
| 255 | &source, | ||
| 256 | ) | ||
| 257 | .unwrap(); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | #[test] | ||
| 262 | fn native_changes_on_created_pages_accept_rust_followups() { | ||
| 263 | let initial = include_bytes!( | ||
| 264 | "../../../corpus/page-lifecycle/creation/native/cold/notebook/Lifecycle.one" | ||
| 265 | ); | ||
| 266 | let store = Store::parse(initial).unwrap(); | ||
| 267 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 268 | let document = Document::parse(&index).unwrap(); | ||
| 269 | let mut targets = Vec::new(); | ||
| 270 | for (sid, _) in document.pages().unwrap() { | ||
| 271 | let space = &document.spaces[&sid]; | ||
| 272 | let view = &space.revisions[&space.contexts[&ExGuid::default()]]; | ||
| 273 | let mut title = None; | ||
| 274 | let mut body = None; | ||
| 275 | for (id, node) in &view.nodes { | ||
| 276 | if let Kind::RichText { text, .. } = &node.kind { | ||
| 277 | if text == "New 🦋 é" { | ||
| 278 | title = Some(*id); | ||
| 279 | } | ||
| 280 | if text.starts_with("Native body ") { | ||
| 281 | body = Some(*id); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 285 | if let (Some(title), Some(body)) = (title, body) { | ||
| 286 | targets.push((sid, title, body)); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | assert_eq!(targets.len(), 2); | ||
| 290 | let mut source = initial.to_vec(); | ||
| 291 | for (sid, title, body) in targets { | ||
| 292 | for (object, prefix) in [(body, "Rust + "), (title, "Reviewed ")] { | ||
| 293 | source = PreparedEdit::text(&source, sid, object, 0..0, prefix) | ||
| 294 | .unwrap() | ||
| 295 | .as_bytes() | ||
| 296 | .to_vec(); | ||
| 297 | } | ||
| 298 | let store = Store::parse(&source).unwrap(); | ||
| 299 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 300 | let document = Document::parse(&index).unwrap(); | ||
| 301 | let view = &document.spaces[&sid]; | ||
| 302 | let view = &view.revisions[&view.contexts[&ExGuid::default()]]; | ||
| 303 | assert!( | ||
| 304 | matches!(&view.nodes[&title].kind, Kind::RichText { text, .. } if text == "Reviewed New 🦋 é") | ||
| 305 | ); | ||
| 306 | assert!( | ||
| 307 | matches!(&view.nodes[&body].kind, Kind::RichText { text, .. } if text.starts_with("Rust + Native body ")) | ||
| 308 | ); | ||
| 309 | assert!( | ||
| 310 | matches!(&view.nodes[&view.roots[&2]].kind, Kind::Metadata { title: Some(title), .. } if title == "Reviewed New 🦋 é") | ||
| 311 | ); | ||
| 312 | } | ||
| 313 | if let Some(output) = std::env::var_os("ONESTORE_PAGE_FOLLOWUP_OUTPUT") { | ||
| 314 | std::fs::create_dir(&output).unwrap(); | ||
| 315 | std::fs::write(std::path::Path::new(&output).join("Lifecycle.one"), &source).unwrap(); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | #[test] | ||
| 320 | fn page_creation_preserves_native_features_and_file_data() { | ||
| 321 | for source in [ | ||
| 322 | include_bytes!("../../../corpus/native-ink/20260905-ui/notebook/synthetic.one").as_slice(), | ||
| 323 | include_bytes!("../../../corpus/native-external-assets/notebook/synthetic.one").as_slice(), | ||
| 324 | include_bytes!("../../../corpus/m6/native-features-01/notebook/Features.one").as_slice(), | ||
| 325 | ] { | ||
| 326 | let before = Store::parse(source).unwrap(); | ||
| 327 | let old = RevisionIndex::parse(&before).unwrap(); | ||
| 328 | let original = Document::parse(&old).unwrap(); | ||
| 329 | let intent = PageCreation::new(None, Some("Preserved features"), "Author").unwrap(); | ||
| 330 | let prepared = PreparedEdit::create_page(source, &intent).unwrap(); | ||
| 331 | let after = Store::parse(prepared.as_bytes()).unwrap(); | ||
| 332 | let new = RevisionIndex::parse(&after).unwrap(); | ||
| 333 | let document = Document::parse(&new).unwrap(); | ||
| 334 | assert_eq!( | ||
| 335 | document.pages().unwrap().len(), | ||
| 336 | original.pages().unwrap().len() + 1 | ||
| 337 | ); | ||
| 338 | for (sid, space) in &old.spaces { | ||
| 339 | for rid in space.revisions.keys() { | ||
| 340 | let original = old.resolve(*sid, *rid).unwrap(); | ||
| 341 | let retained = new.resolve(*sid, *rid).unwrap(); | ||
| 342 | assert_eq!(format!("{original:?}"), format!("{retained:?}")); | ||
| 343 | for object in original.objects.values() { | ||
| 344 | if let Some(onestore::FileDataReference::Internal(id)) = | ||
| 345 | object.file_reference().unwrap() | ||
| 346 | { | ||
| 347 | assert_eq!(before.file_data(id).unwrap(), after.file_data(id).unwrap()); | ||
| 348 | } | ||
| 349 | } | ||
| 350 | } | ||
| 351 | if *sid != old.root { | ||
| 352 | assert_eq!(space.labels, new.spaces[sid].labels); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
fuzz/Cargo.toml+7| ... | @@ -114,3 +114,10 @@ path = "fuzz_targets/offline_tree.rs" | ... | @@ -114,3 +114,10 @@ path = "fuzz_targets/offline_tree.rs" |
| 114 | test = false | 114 | test = false |
| 115 | doc = false | 115 | doc = false |
| 116 | bench = false | 116 | bench = false |
| 117 | |||
| 118 | [[bin]] | ||
| 119 | name = "page" | ||
| 120 | path = "fuzz_targets/page.rs" | ||
| 121 | test = false | ||
| 122 | doc = false | ||
| 123 | bench = false |
fuzz/fuzz_targets/page.rs created+138| ... | @@ -0,0 +1,138 @@ | ||
| 1 | #![no_main] | ||
| 2 | use libfuzzer_sys::fuzz_target; | ||
| 3 | use onestore::{ | ||
| 4 | CommitState, ExGuid, Insertion, PageCreation, PreparedEdit, RevisionIndex, Store, | ||
| 5 | document::{Document, Kind}, | ||
| 6 | }; | ||
| 7 | use std::sync::LazyLock; | ||
| 8 | |||
| 9 | #[path = "../../crates/onestore/tests/support/current.rs"] | ||
| 10 | mod current; | ||
| 11 | #[path = "../../crates/onestore/tests/support/disk.rs"] | ||
| 12 | mod disk; | ||
| 13 | |||
| 14 | static SOURCE: LazyLock<Vec<u8>> = LazyLock::new(|| { | ||
| 15 | onestore::create_section("pages.one", "Original 🦀 é 東京", "Author").unwrap() | ||
| 16 | }); | ||
| 17 | |||
| 18 | fuzz_target!(|input: &[u8]| { | ||
| 19 | if let Ok(intent) = serde_json::from_slice::<PageCreation>(input) | ||
| 20 | && let Ok(prepared) = PreparedEdit::create_page(&SOURCE, &intent) | ||
| 21 | { | ||
| 22 | current::current(prepared.as_bytes()); | ||
| 23 | } | ||
| 24 | let mut persisted = SOURCE.clone(); | ||
| 25 | let mut caches = std::array::from_fn::<_, 12, _>(|_| SOURCE.clone()); | ||
| 26 | for step in input.chunks_exact(8).take(24) { | ||
| 27 | let actor = usize::from(step[0]) % caches.len(); | ||
| 28 | if step[1] % 3 == 0 { | ||
| 29 | caches[actor].clone_from(&persisted); | ||
| 30 | } | ||
| 31 | let source = &caches[actor]; | ||
| 32 | let store = Store::parse(source).unwrap(); | ||
| 33 | let index = RevisionIndex::parse(&store).unwrap(); | ||
| 34 | let document = Document::parse(&index).unwrap(); | ||
| 35 | let mut pages = document.pages().unwrap(); | ||
| 36 | let (sid, page) = pages[usize::from(step[2]) % pages.len()]; | ||
| 37 | let space = &document.spaces[&sid]; | ||
| 38 | let view = &space.revisions[&space.contexts[&ExGuid::default()]]; | ||
| 39 | let text = ["", "Same title", "é 🦋 東京", " spaces "][usize::from(step[3]) % 4]; | ||
| 40 | let titles: Vec<_> = view | ||
| 41 | .nodes | ||
| 42 | .iter() | ||
| 43 | .filter_map(|(id, node)| { | ||
| 44 | (node.extra[0].iter().any(|field| field.id == 0x88001cb4) | ||
| 45 | && matches!( | ||
| 46 | node.kind, | ||
| 47 | Kind::RichText { | ||
| 48 | boilerplate: false, | ||
| 49 | .. | ||
| 50 | } | ||
| 51 | )) | ||
| 52 | .then_some(*id) | ||
| 53 | }) | ||
| 54 | .collect(); | ||
| 55 | let (edit, title_update) = if step[1] & 8 != 0 && !titles.is_empty() { | ||
| 56 | let object = titles[0]; | ||
| 57 | let Kind::RichText { text: original, .. } = &view.nodes[&object].kind else { | ||
| 58 | unreachable!() | ||
| 59 | }; | ||
| 60 | ( | ||
| 61 | PreparedEdit::text( | ||
| 62 | source, | ||
| 63 | sid, | ||
| 64 | object, | ||
| 65 | 0..original.encode_utf16().count() as u32, | ||
| 66 | text, | ||
| 67 | ) | ||
| 68 | .unwrap(), | ||
| 69 | Some((sid, object, text)), | ||
| 70 | ) | ||
| 71 | } else if step[1] & 16 != 0 { | ||
| 72 | let intent = Insertion::outline(page, 36.0, 36.0, text, "Page fuzz").unwrap(); | ||
| 73 | ( | ||
| 74 | PreparedEdit::insert(source, sid, &intent).unwrap(), | ||
| 75 | Some((sid, intent.text_object(), text)), | ||
| 76 | ) | ||
| 77 | } else { | ||
| 78 | let before = (step[2] & 1 != 0).then_some(sid); | ||
| 79 | let title = (step[3] & 4 == 0).then_some(text); | ||
| 80 | let intent = PageCreation::new(before, title, "Page fuzz").unwrap(); | ||
| 81 | let restored = serde_json::from_value(serde_json::to_value(&intent).unwrap()).unwrap(); | ||
| 82 | assert_eq!(intent, restored); | ||
| 83 | let edit = PreparedEdit::create_page(source, &restored).unwrap(); | ||
| 84 | let position = before.map_or(pages.len(), |sid| { | ||
| 85 | pages.iter().position(|p| p.0 == sid).unwrap() | ||
| 86 | }); | ||
| 87 | pages.insert(position, (intent.space(), intent.object())); | ||
| 88 | ( | ||
| 89 | edit, | ||
| 90 | intent | ||
| 91 | .title_object() | ||
| 92 | .map(|object| (intent.space(), object, text)), | ||
| 93 | ) | ||
| 94 | }; | ||
| 95 | let after_store = Store::parse(edit.as_bytes()).unwrap(); | ||
| 96 | let after_index = RevisionIndex::parse(&after_store).unwrap(); | ||
| 97 | let after_document = Document::parse(&after_index).unwrap(); | ||
| 98 | assert_eq!(after_document.pages().unwrap(), pages); | ||
| 99 | if let Some((sid, object, text)) = title_update { | ||
| 100 | let space = &after_document.spaces[&sid]; | ||
| 101 | let view = &space.revisions[&space.contexts[&ExGuid::default()]]; | ||
| 102 | assert!( | ||
| 103 | matches!(&view.nodes[&object].kind, Kind::RichText { text: actual, .. } if actual == text) | ||
| 104 | ); | ||
| 105 | } | ||
| 106 | for (sid, space) in &index.spaces { | ||
| 107 | let rid = space.labels[&(ExGuid::default(), 1)]; | ||
| 108 | assert_eq!( | ||
| 109 | format!("{:?}", index.resolve(*sid, rid).unwrap()), | ||
| 110 | format!("{:?}", after_index.resolve(*sid, rid).unwrap()) | ||
| 111 | ); | ||
| 112 | } | ||
| 113 | let before = current::current(&persisted); | ||
| 114 | let after = current::current(edit.as_bytes()); | ||
| 115 | let mut disk = disk::Disk { | ||
| 116 | visible: persisted.clone(), | ||
| 117 | durable: persisted.clone(), | ||
| 118 | operation: 0, | ||
| 119 | fail_at: (step[4] != 0).then_some(usize::from(u16::from_le_bytes([step[4], step[5]]))), | ||
| 120 | write_limit: if step[6] & 1 == 0 { 17 } else { 4096 }, | ||
| 121 | random: u64::from(step[7]) + 1, | ||
| 122 | }; | ||
| 123 | let result = edit.commit(&mut disk); | ||
| 124 | let observed = current::current(&disk.durable); | ||
| 125 | match result { | ||
| 126 | Ok(()) => assert_eq!(observed, after), | ||
| 127 | Err(error) => { | ||
| 128 | assert!(observed == before || observed == after); | ||
| 129 | match error.state { | ||
| 130 | CommitState::NotCommitted => assert_eq!(observed, before), | ||
| 131 | CommitState::Committed => assert_eq!(observed, after), | ||
| 132 | CommitState::Unknown => {} | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | persisted = disk.durable; | ||
| 137 | } | ||
| 138 | }); | ||
tools/native/created-pages.ps1 created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | param([Parameter(Mandatory=$true)][string]$Root, [Parameter(Mandatory=$true)][string]$CloneHost) | ||
| 2 | Set-StrictMode -Version Latest | ||
| 3 | $ErrorActionPreference = 'Stop' | ||
| 4 | & "$PSScriptRoot\cold-current.ps1" -Root $Root -CloneHost $CloneHost | ||
| 5 | $app = New-Object -ComObject OneNote.Application | ||
| 6 | $notebook = '' | ||
| 7 | try { | ||
| 8 | $app.OpenHierarchy((Join-Path $Root 'notebook'), '', [ref]$notebook, 0) | ||
| 9 | $section = '' | ||
| 10 | $app.OpenHierarchy('Lifecycle.one', $notebook, [ref]$section, 0) | ||
| 11 | $deadline = [DateTime]::UtcNow.AddSeconds(30) | ||
| 12 | do { | ||
| 13 | $hierarchy = '' | ||
| 14 | $app.GetHierarchy($section, 4, [ref]$hierarchy, 1) | ||
| 15 | [xml]$tree = $hierarchy | ||
| 16 | $pages = @($tree.SelectNodes('//*[local-name()="Page"]')) | ||
| 17 | if ($pages.Count -eq 13) { break } | ||
| 18 | Start-Sleep -Milliseconds 200 | ||
| 19 | } while ([DateTime]::UtcNow -lt $deadline) | ||
| 20 | $targets = @($pages | Where-Object { $_.GetAttribute('name').StartsWith('New ') }) | ||
| 21 | if ($pages.Count -ne 13 -or $targets.Count -ne 2) { throw 'Expected thirteen pages and two created title controls.' } | ||
| 22 | $inputs = Join-Path $Root 'inputs' | ||
| 23 | [void](New-Item -ItemType Directory -Path $inputs) | ||
| 24 | for ($i = 0; $i -lt $targets.Count; $i++) { | ||
| 25 | $pageId = [Security.SecurityElement]::Escape($targets[$i].GetAttribute('ID')) | ||
| 26 | $xml = "<one:Page xmlns:one='http://schemas.microsoft.com/office/onenote/2010/onenote' ID='$pageId'><one:Outline><one:Position x='72' y='144'/><one:OEChildren><one:OE><one:T>Native body $i after Rust page creation.</one:T></one:OE></one:OEChildren></one:Outline></one:Page>" | ||
| 27 | [IO.File]::WriteAllText((Join-Path $inputs ("native-$i.xml")), $xml, [Text.Encoding]::UTF8) | ||
| 28 | $app.UpdatePageContent($xml, [DateTime]::MinValue, 1, $false) | ||
| 29 | } | ||
| 30 | $app.SyncHierarchy($notebook) | ||
| 31 | } finally { | ||
| 32 | [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) | ||
| 33 | [GC]::Collect() | ||
| 34 | [GC]::WaitForPendingFinalizers() | ||
| 35 | } | ||
tools/test_page_creation.py created+48| ... | @@ -0,0 +1,48 @@ | ||
| 1 | import json | ||
| 2 | from pathlib import Path | ||
| 3 | import subprocess | ||
| 4 | from tempfile import TemporaryDirectory | ||
| 5 | import unittest | ||
| 6 | |||
| 7 | from document_model import EXPORTER, ordered_pages, walk | ||
| 8 | from verify_page_creation import compare | ||
| 9 | |||
| 10 | FIXTURE = Path(__file__).resolve().parent.parent / 'corpus/page-lifecycle/creation' | ||
| 11 | |||
| 12 | |||
| 13 | class PageCreationTest(unittest.TestCase): | ||
| 14 | def test_created_pages_and_both_writers_survive_native_cold_reopens(self): | ||
| 15 | for source, capture in [('candidate', 'cold'), ('native/notebook', 'native/cold'), ('followup', 'followup/cold')]: | ||
| 16 | with self.subTest(source=source): | ||
| 17 | compare(FIXTURE / source, FIXTURE / capture) | ||
| 18 | |||
| 19 | def test_duplicate_titles_keep_distinct_pages_through_native_and_rust_edits(self): | ||
| 20 | with TemporaryDirectory() as temporary: | ||
| 21 | identities = None | ||
| 22 | for ordinal, path in enumerate(('candidate', 'native/cold/notebook', 'followup/cold/notebook')): | ||
| 23 | output = Path(temporary) / str(ordinal) | ||
| 24 | subprocess.run([EXPORTER, FIXTURE / path / 'Lifecycle.one', output], check=True) | ||
| 25 | document = json.loads((output / 'document.json').read_text()) | ||
| 26 | pages = list(ordered_pages(document)) | ||
| 27 | self.assertEqual(len(pages), 13) | ||
| 28 | current = [(sid, page) for sid, _, _, page in pages] | ||
| 29 | self.assertEqual(len(set(current)), 13) | ||
| 30 | if identities is None: | ||
| 31 | identities = current | ||
| 32 | self.assertEqual(identities, current) | ||
| 33 | for index, (_, _, view, page) in enumerate(pages[-2:]): | ||
| 34 | title = ('Reviewed ' if ordinal == 2 else '') + 'New 🦋 é' | ||
| 35 | self.assertEqual(view['nodes'][view['roots']['2']]['kind']['title'], title) | ||
| 36 | expected = [title] | ||
| 37 | if ordinal: | ||
| 38 | expected.append(('Rust + ' if ordinal == 2 else '') + f'Native body {index} after Rust page creation.') | ||
| 39 | self.assertEqual([node['kind']['text'] for _, node in walk(view, page) | ||
| 40 | if node['kind']['type'] == 'RichText'], expected) | ||
| 41 | for at, titled in [(0, True), (10, False)]: | ||
| 42 | _, _, view, page = pages[at] | ||
| 43 | self.assertEqual(bool(view['nodes'][page]['structure']), titled) | ||
| 44 | self.assertEqual(view['nodes'][page]['children'], []) | ||
| 45 | |||
| 46 | |||
| 47 | if __name__ == '__main__': | ||
| 48 | unittest.main() | ||
tools/verify_page_creation.py created+73| ... | @@ -0,0 +1,73 @@ | ||
| 1 | """Compare created pages with native XML and cold-reopened object graphs.""" | ||
| 2 | import argparse | ||
| 3 | from copy import deepcopy | ||
| 4 | import json | ||
| 5 | from pathlib import Path | ||
| 6 | import runpy | ||
| 7 | import shutil | ||
| 8 | import subprocess | ||
| 9 | from tempfile import TemporaryDirectory | ||
| 10 | from uuid import UUID | ||
| 11 | |||
| 12 | from document_model import EXPORTER, ordered_pages, view | ||
| 13 | |||
| 14 | compare_document = runpy.run_path(str(Path(__file__).with_name('verify-document.py')))['compare'] | ||
| 15 | |||
| 16 | |||
| 17 | def compare(source, capture): | ||
| 18 | files = list(source.glob('*.one')) | ||
| 19 | assert len(files) == 1 | ||
| 20 | with TemporaryDirectory() as temporary: | ||
| 21 | temporary = Path(temporary) | ||
| 22 | native = temporary / 'native/read' | ||
| 23 | shutil.copytree(capture / 'read', native) | ||
| 24 | notebook = temporary / 'notebook' | ||
| 25 | notebook.mkdir() | ||
| 26 | (notebook / files[0].name).symlink_to(files[0].resolve()) | ||
| 27 | compare_document(notebook, native) | ||
| 28 | models = [] | ||
| 29 | for ordinal, file in enumerate((files[0], capture / 'notebook' / files[0].name)): | ||
| 30 | output = temporary / str(ordinal) | ||
| 31 | subprocess.run([EXPORTER, file, output], check=True) | ||
| 32 | models.append(json.loads((output / 'document.json').read_text())) | ||
| 33 | before, after = models | ||
| 34 | pages = list(ordered_pages(before)) | ||
| 35 | assert [(sid, page) for sid, _, _, page in pages] == [ | ||
| 36 | (sid, page) for sid, _, _, page in ordered_pages(after)] | ||
| 37 | assert before['root'] == after['root'] | ||
| 38 | assert before['spaces'].keys() == after['spaces'].keys() | ||
| 39 | filled = 0 | ||
| 40 | for sid in before['spaces']: | ||
| 41 | _, original = view(before, sid) | ||
| 42 | _, observed = view(after, sid) | ||
| 43 | expected = deepcopy(original['nodes']) | ||
| 44 | if sid == before['root']: | ||
| 45 | for series_id in original['nodes'][original['roots']['1']]['children']: | ||
| 46 | series = expected[series_id] | ||
| 47 | existing = [p for p in series['extra'][0] if p['id'] == 0x24003442] | ||
| 48 | added = [p for p in observed['nodes'][series_id]['extra'][0] if p['id'] == 0x24003442] | ||
| 49 | if existing or not added: | ||
| 50 | continue | ||
| 51 | copies = [] | ||
| 52 | for page_sid in series['spaces']: | ||
| 53 | (_, _, page_view, _), = [p for p in pages if p[0] == page_sid] | ||
| 54 | # Native uses the space GUID when it differs from the page-node GUID. | ||
| 55 | guid = UUID(page_sid.split('}')[0].strip('{')).bytes_le | ||
| 56 | salt = UUID('22a8c031-3600-42ee-b714-d7acda2435e8').bytes_le | ||
| 57 | metadata = '{' + str(UUID(bytes_le=bytes(a ^ b for a, b in zip(guid, salt, strict=True)))).upper() + '},1' | ||
| 58 | assert metadata not in expected | ||
| 59 | expected[metadata] = page_view['nodes'][page_view['roots']['2']] | ||
| 60 | copies.append(metadata) | ||
| 61 | filled += 1 | ||
| 62 | series['extra'][0].append({'id': 0x24003442, 'value': {'Objects': copies}}) | ||
| 63 | assert original['roots'] == observed['roots'] | ||
| 64 | assert expected == observed['nodes'], sid | ||
| 65 | print(f'Passed: {len(pages)} ordered pages and preserved active graphs; {filled} missing section metadata copies filled natively') | ||
| 66 | |||
| 67 | |||
| 68 | if __name__ == '__main__': | ||
| 69 | parser = argparse.ArgumentParser(description=__doc__) | ||
| 70 | parser.add_argument('source', type=Path) | ||
| 71 | parser.add_argument('capture', type=Path) | ||
| 72 | args = parser.parse_args() | ||
| 73 | compare(args.source, args.capture) | ||