| ... | @@ -12,10 +12,13 @@ between Snowbound clients, with one owner process publishing the real `.one` | ... | @@ -12,10 +12,13 @@ between Snowbound clients, with one owner process publishing the real `.one` |
| 12 | files. Other builds exchange separate files instead of racing on those files. | 12 | files. Other builds exchange separate files instead of racing on those files. |
| 13 | Generic cloud mounts cannot be assumed to implement reliable distributed locks. | 13 | Generic cloud mounts cannot be assumed to implement reliable distributed locks. |
| 14 | This should cover Android/Linux provider-backed notebooks and improve iCloud | 14 | This should cover Android/Linux provider-backed notebooks and improve iCloud |
| 15 | coordination. Practical tests must determine the tradeoffs before selecting an | 15 | coordination. The selected direction is automatic takeover with retained branches |
| 16 | ownership/recovery policy. | 16 | and canonical repair. On 2026-10-11 Clover chose “whichever is the more resilient |
| | 17 | even if it's more complicated.” Resilience means keeping recoverable history and allowing an |
| | 18 | isolated capable device to progress; it does not mean promising exclusive cloud |
| | 19 | writes. The selection below is a design contract, not an implemented protocol. |
| 17 | | 20 | |
| 18 | ## The contract under investigation | 21 | ## Selected contract |
| 19 | | 22 | |
| 20 | ```text | 23 | ```text |
| 21 | Android / Linux / iOS editor | 24 | Android / Linux / iOS editor |
| ... | @@ -24,7 +27,7 @@ Android / Linux / iOS editor | ... | @@ -24,7 +27,7 @@ Android / Linux / iOS editor |
| 24 | .snowbound/ unique immutable request segments + blobs | 27 | .snowbound/ unique immutable request segments + blobs |
| 25 | │ validated complete bytes and causal dependencies | 28 | │ validated complete bytes and causal dependencies |
| 26 | ▼ | 29 | ▼ |
| 27 | owner existing merge and revision append | 30 | branch owner existing merge and revision append |
| 28 | ├── immutable decision/checkpoint evidence ──► other Snowbound replicas | 31 | ├── immutable decision/checkpoint evidence ──► other Snowbound replicas |
| 29 | └── ordinary .one / .onetoc2 files ─────────► eventual provider projection | 32 | └── ordinary .one / .onetoc2 files ─────────► eventual provider projection |
| 30 | ``` | 33 | ``` |
| ... | @@ -36,15 +39,15 @@ logical owner are three different facts. The design must retain enough immutable | ... | @@ -36,15 +39,15 @@ logical owner are three different facts. The design must retain enough immutable |
| 36 | evidence to repair the mutable file after a rollback even if every client has | 39 | evidence to repair the mutable file after a rollback even if every client has |
| 37 | already received a historical publication receipt. | 40 | already received a historical publication receipt. |
| 38 | | 41 | |
| 39 | Proposed safety requirements: | 42 | Required safety properties: |
| 40 | | 43 | |
| 41 | - An acknowledged local edit remains in retained local storage until its content | 44 | - An acknowledged local edit remains in retained local storage until its content |
| 42 | and outcome are recoverable elsewhere under an explicit retention contract. | 45 | and outcome are recoverable elsewhere under an explicit retention contract. |
| 43 | - Seeing a request, seeing a receipt, or seeing a matching file stamp does not | 46 | - Seeing a request, seeing a receipt, or seeing a matching file stamp does not |
| 44 | authorize deletion of the only recoverable request/base/blob. | 47 | authorize deletion of the only recoverable request/base/blob. |
| 45 | - Missing, stale, incomplete, repeated, or reordered provider observations never | 48 | - Missing, stale, incomplete, repeated, or reordered provider observations never |
| 46 | silently delete notes, select an owner, retire a branch, or establish a | 49 | silently delete notes, grant exclusive ownership, retire a branch, or |
| 47 | complete list of devices. | 50 | establish a complete list of devices. |
| 48 | - Every accepted request has a stable identity, complete validated payload, | 51 | - Every accepted request has a stable identity, complete validated payload, |
| 49 | known causal base, and a recorded disposition. Retried transport does not | 52 | known causal base, and a recorded disposition. Retried transport does not |
| 50 | repeat the user edit or create duplicate conflict pages. | 53 | repeat the user edit or create duplicate conflict pages. |
| ... | @@ -128,16 +131,44 @@ upload; the provider does not interpret that epoch. Chubby's sequencers address | ... | @@ -128,16 +131,44 @@ upload; the provider does not interpret that epoch. Chubby's sequencers address |
| 128 | precisely delayed operations by requiring validation at the recipient. | 131 | precisely delayed operations by requiring validation at the recipient. |
| 129 | [The Chubby lock service](https://research.google.com/archive/chubby-osdi06.pdf). | 132 | [The Chubby lock service](https://research.google.com/archive/chubby-osdi06.pdf). |
| 130 | | 133 | |
| 131 | **Investigation recommendation, not yet selected:** start with a fixed preferred | 134 | **Selected policy: branch-preserving automatic takeover.** Prefer one discovered |
| 132 | publisher, explicit handoff, and immutable recoverable inputs/outcomes. Other | 135 | publisher during ordinary connected operation. An isolated capable client may |
| 133 | clients keep editing from retained local replicas while that publisher is absent; | 136 | start a fresh recovery branch from its retained validated base, without waiting |
| 134 | publication waits. Preserve branches as the recovery fallback, and treat automatic | 137 | for the preferred device or pretending to revoke it. A delay/heartbeat can decide |
| 135 | takeover as separate policy work. Timeout takeover is not part of the strict | 138 | when to attempt recovery, but cannot authorize deletion, invalidate another |
| 136 | owner contract. Majority agreement remains an alternative with its stated | 139 | branch, or establish exclusive ownership. Explicit handoff remains the efficient |
| 137 | availability cost. This makes the sidecar necessary recovery authority for | 140 | connected path; a fixed publisher is not a prerequisite for progress. Do not add |
| 138 | accepted history when the mutable projection regresses; that authority/backup | 141 | majority membership to the first version: its loss of offline availability buys |
| 139 | contract needs owner review before production implementation. The recorded | 142 | logical serialization, while leaving the demonstrated physical rollback problem. |
| 140 | experiments below support the recovery requirement, not a finished owner protocol. | 143 | |
| | 144 | | Resilience dimension | Selected guarantee / cost | |
| | 145 | | --- | --- | |
| | 146 | | Local edit custody | Existing durable queue plus retained exact dependencies; takeover never discards an absent device's work | |
| | 147 | | Isolated-device progress | A capable unlocked device can retain decisions and attempt publication from its complete local closure; missing ancestry/keys still block interpretation | |
| | 148 | | Accepted-history recovery | All valid accepted branches and pending requests survive reconciliation, including losing projection versions | |
| | 149 | | Canonical availability | Ordinary `.one` remains readable when valid; stale uploads can regress it, and repair can be delayed | |
| | 150 | | Eventual convergence | Requires complete eventual delivery, stale writes to cease, compatible keys/versions and a running reconciler; reproducible selection rules must pass the gates below | |
| | 151 | | Physical exclusion | Not available on this storage model; no timeout, handoff receipt or sidecar epoch supplies it | |
| | 152 | | Storage/backup cost | Sidecar recovery history is essential for registered notebooks; initial version has no automatic GC | |
| | 153 | |
| | 154 | “One owner writes the real file” becomes **one logical publisher per branch**, |
| | 155 | with one locally serialized process owning each live branch incarnation. Peers |
| | 156 | send requests to it while it is reachable. A takeover opens a separate branch; |
| | 157 | it does not seize the old branch's namespace or credentials. During partitions |
| | 158 | there can be several physical publishers, plus provider-delayed uploads from |
| | 159 | retired ones. On rejoin, discovered publishers stop adding independent work, |
| | 160 | retain their unfinished attempts and coordinate through a reconciler. Its |
| | 161 | preference/order is a contention reduction rule, not a global lock. No generic |
| | 162 | file-only protocol can guarantee both isolated takeover and exclusive physical |
| | 163 | writes under these assumptions. |
| | 164 | |
| | 165 | Accepted branch outcomes are never revoked because another branch was preferred. |
| | 166 | They may become conflict/recovery alternatives in the integrated result. A |
| | 167 | publication receipt names its branch and covered input identities; it cannot |
| | 168 | claim a globally final order or that every offline branch has been seen. The |
| | 169 | registered notebook's recovery authority is the validated retained history, |
| | 170 | including pending closures, rather than whichever `.one` snapshot arrived last. |
| | 171 | Bare-file imports and intentional restores remain explicit operations below. |
| 141 | | 172 | |
| 142 | ## Identities and duplicate processes | 173 | ## Identities and duplicate processes |
| 143 | | 174 | |
| ... | @@ -156,7 +187,7 @@ Use distinct roles: | ... | @@ -156,7 +187,7 @@ Use distinct roles: |
| 156 | | Process/writer incarnation | Fresh random identity for each process run; disjoint message namespace | | 187 | | Process/writer incarnation | Fresh random identity for each process run; disjoint message namespace | |
| 157 | | Local edit identity | Existing durable replica edit ID plus its originating replica/writer identity | | 188 | | Local edit identity | Existing durable replica edit ID plus its originating replica/writer identity | |
| 158 | | Request segment identity | Stable once sealed, retries resend identical bytes | | 189 | | Request segment identity | Stable once sealed, retries resend identical bytes | |
| 159 | | Owner epoch identity | Chained ownership decision, not a timestamp or largest visible number | | 190 | | Owner epoch / branch identity | Unique branch incarnation plus exact parent frontier; no globally increasing epoch or revocation implied | |
| 160 | | Decision identity | Immutable owner result naming its predecessor and accepted request identities | | 191 | | Decision identity | Immutable owner result naming its predecessor and accepted request identities | |
| 161 | | Blob/checkpoint identity | Validated immutable bytes, content digest and exact byte length | | 192 | | Blob/checkpoint identity | Validated immutable bytes, content digest and exact byte length | |
| 162 | | 193 | |
| ... | @@ -166,18 +197,23 @@ new records. Retrying an old outbox may write its original namespace/bytes; it | ... | @@ -166,18 +197,23 @@ new records. Retrying an old outbox may write its original namespace/bytes; it |
| 166 | does not rekey old edits into the new process namespace. Otherwise deduplication | 197 | does not rekey old edits into the new process namespace. Otherwise deduplication |
| 167 | would turn an ordinary restart into a second user action. | 198 | would turn an ordinary restart into a second user action. |
| 168 | | 199 | |
| 169 | Two processes on one installation must not both publish because they share a | 200 | Two processes on one installation must not publish the same live branch because |
| 170 | device ID. A locally owned publisher database/socket may serialize processes | 201 | they share a device ID. A locally owned publisher database/socket serializes |
| 171 | sharing reliable private storage. A second process with a copied private profile | 202 | processes sharing reliable private storage. Every process run uses its own new |
| 172 | on another device is a different failure: distinguish incarnations, preserve | 203 | branch incarnation for newly admitted decisions, referencing retained predecessor |
| 173 | both claims, and stop automatic publication when contradictory ownership becomes | 204 | history and unresolved attempts. Recovery can confirm an old prepared attempt |
| 174 | visible. Absence of a contradiction in a stale view is not a uniqueness proof. | 205 | with its original identities; it cannot generate a second outcome for it merely |
| 175 | A backup of owner credentials is not permission to run both copies. | 206 | because the process restarted. |
| 176 | | 207 | |
| 177 | For fixed ownership, restart uses the retained durable owner state and a fresh | 208 | Copied private profiles on separate devices therefore create distinct new |
| 178 | process incarnation. For explicit handoff, the old state records retirement | 209 | branches, not competing continuations of one immutable namespace. Already sealed |
| 179 | before a successor becomes eligible. Losing the old durable state requires | 210 | outbox objects retain their original identity and bytes. Two different decisions |
| 180 | recovery; creating a fresh claim is not a transparent restart. | 211 | claiming the same immutable identity or contradictory dispositions for one exact |
| | 212 | prepared transaction remain a protocol contradiction: quarantine/preserve the |
| | 213 | evidence and stop automatic interpretation of the affected history. Valid |
| | 214 | independent branch claims are expected recovery inputs. A handoff records the |
| | 215 | old branch's retirement before its successor is eligible; stale cached retirement |
| | 216 | cannot be assumed visible elsewhere. |
| 181 | | 217 | |
| 182 | ## Proposed object namespace | 218 | ## Proposed object namespace |
| 183 | | 219 | |
| ... | @@ -332,12 +368,13 @@ publication. It cannot appear in an accepted edit list as though the note had | ... | @@ -332,12 +368,13 @@ publication. It cannot appear in an accepted edit list as though the note had |
| 332 | merged. A recoverable conflict outcome names the actual stored conflict page; | 368 | merged. A recoverable conflict outcome names the actual stored conflict page; |
| 333 | a retained foreign/unreadable branch names recovery evidence instead. | 369 | a retained foreign/unreadable branch names recovery evidence instead. |
| 334 | | 370 | |
| 335 | Owner decisions impose a durable selected order under the chosen ownership | 371 | Owner decisions impose an order within their branch. Concurrent branches remain |
| 336 | policy. Concurrent branches remain explicit inputs to the existing merge; do | 372 | explicit inputs to integration; never choose the newest wall clock or discard |
| 337 | not choose the newest wall clock or discard the branch with the smaller owner | 373 | content because its owner ID sorts later. Stable reconciliation ordering chooses |
| 338 | ID. An automatic recovery policy needs a stable, documented reconciliation of | 374 | presentation and replay order among already validated inputs. It is neither |
| 339 | multiple accepted decision histories. Deterministic sorting for processing is | 375 | consensus nor permission to edit. The same request accepted independently by two |
| 340 | not a consensus or permission rule. | 376 | branches still denotes one user action; section revision identity alone is not a |
| | 377 | complete cross-branch request deduplication scheme. |
| 341 | | 378 | |
| 342 | ## Owner state and write/ack ordering | 379 | ## Owner state and write/ack ordering |
| 343 | | 380 | |
| ... | @@ -381,9 +418,10 @@ observation must not downgrade its known accepted history. Keep that history | ... | @@ -381,9 +418,10 @@ observation must not downgrade its known accepted history. Keep that history |
| 381 | and recovery dependencies locally while repairing the projection. An explicit | 418 | and recovery dependencies locally while repairing the projection. An explicit |
| 382 | intentional restore is a new recorded operation, not a stale-file inference. | 419 | intentional restore is a new recorded operation, not a stale-file inference. |
| 383 | | 420 | |
| 384 | An owner-unavailable client still edits from its private replica. Requests wait | 421 | An owner-unavailable client still reads, navigates, edits and uses Undo from its |
| 385 | for owner processing without blocking local read/navigation/Undo. Publishing | 422 | private replica. A capable client may start a recovery branch; otherwise requests |
| 386 | status cannot report owner custody merely because local creation of a provider | 423 | wait for a capable publisher without blocking local use. Publishing status cannot |
| | 424 | report another device's custody merely because local creation of a provider |
| 387 | object succeeded. | 425 | object succeeded. |
| 388 | | 426 | |
| 389 | ## Explicit handoff, recovery takeover, and late uploads | 427 | ## Explicit handoff, recovery takeover, and late uploads |
| ... | @@ -407,27 +445,136 @@ not prove every cloud cache drained. Waiting an arbitrary duration is not a | ... | @@ -407,27 +445,136 @@ not prove every cloud cache drained. Waiting an arbitrary duration is not a |
| 407 | fence. A fixed owner with no ownership transitions avoids one source of late | 445 | fence. A fixed owner with no ownership transitions avoids one source of late |
| 408 | writes but still needs rollback repair for reordered uploads from its own run. | 446 | writes but still needs rollback repair for reordered uploads from its own run. |
| 409 | | 447 | |
| 410 | Automatic recovery experimentation must keep each candidate's decisions in its | 448 | Automatic takeover keeps each candidate's decisions in its own immutable branch. |
| 411 | own immutable branch. A candidate cannot overwrite another owner's mailbox or | 449 | Before admitting work it durably records the exact validated parent frontier, |
| 412 | checkpoint, and claims no exclusive owner authority based on silence. The | 450 | base/checkpoint closure, its fresh incarnation and any uncertain attempts. Missing |
| 413 | mutable `.one` projection may temporarily regress or produce provider conflict | 451 | dependencies remain pending; a candidate cannot claim complete recovery from an |
| 414 | versions. A later reconciler imports all valid branches, preserves incompatible | 452 | incomplete listing. It cannot overwrite another owner's mailbox/checkpoint or |
| 415 | results as conflict pages/recovery data, and republishes normal revisions. | 453 | claim exclusive authority based on silence. A branch may progress with a complete |
| 416 | This is a weaker, explicit safety/availability trade than a strict global | 454 | known subset while clearly retaining that subset's identity; it must not label |
| 417 | single publisher, and remains unselected pending the experiments. | 455 | it the complete notebook history. |
| | 456 | |
| | 457 | An old process resuming after takeover must inspect discovered branch/handoff |
| | 458 | state before new publication, preserve its old outbox, and join reconciliation |
| | 459 | when it can. A stale view can still hide that state, so this check is best effort |
| | 460 | contention control. The safety mechanism is retained branches and attempts, |
| | 461 | not an assertion that the old process can always be stopped. Ordinary canonical |
| | 462 | `.one` files may regress or produce provider conflict versions until reconciliation |
| | 463 | and delivery settle. |
| 418 | | 464 | |
| 419 | A quorum alternative can choose an ownership/decision chain if acceptor | 465 | A quorum alternative can choose an ownership/decision chain if acceptor |
| 420 | membership and durable promises are implemented. It still needs immutable | 466 | membership and durable promises are implemented. It still needs immutable |
| 421 | recovery and projection repair unless the actual provider enforces epochs on | 467 | recovery and projection repair unless the actual provider enforces epochs on |
| 422 | writes. Do not add a quorum merely to hide this physical fencing limitation. | 468 | writes. Do not add a quorum merely to hide this physical fencing limitation. |
| 423 | | 469 | |
| | 470 | ## Reconciliation and canonical repair |
| | 471 | |
| | 472 | The selected policy needs a decision DAG, not a fabricated globally monotonic |
| | 473 | epoch. Each branch decision names its predecessor, exact causal input frontier, |
| | 474 | prepared transaction/outcome and complete recovery closure. An integration |
| | 475 | decision names every covered source request/branch outcome and retained unresolved |
| | 476 | alternative. Its references can arrive in any order. Validation waits for the |
| | 477 | referenced closure; it never invents missing content from visible filenames. |
| | 478 | |
| | 479 | ```text |
| | 480 | retained seed ──► A decisions ──► A checkpoint ──┐ |
| | 481 | └► B decisions ──► B checkpoint ──┼► integration plan / checkpoint |
| | 482 | └► offline pending queue ─────────┘ │ |
| | 483 | ordinary append / repair |
| | 484 | ▼ |
| | 485 | mutable .one path |
| | 486 | ``` |
| | 487 | |
| | 488 | A candidate implements this sequence durably: |
| | 489 | |
| | 490 | 1. Gather validated known branch frontiers, pending requests, external versions |
| | 491 | and uncertain attempts. Follow references, preserving exact source bytes; |
| | 492 | listing completeness is never asserted. Keep the last valid local view if a |
| | 493 | newly observed frontier is incomplete, malformed, foreign or unsupported. |
| | 494 | 2. Resolve exact prepared-attempt identities before admitting a retry. Build a |
| | 495 | coverage map from `(originating replica, edit ID)` to source request digest, |
| | 496 | branch dispositions, named revisions and recovery closure. Identical transport |
| | 497 | retries are one action. Independently rebased outcomes of that action are not |
| | 498 | automatically identical: retain both, select one semantic application and |
| | 499 | record the other as an alternate or retained-unresolved. Selecting one outcome |
| | 500 | cannot discard its alternate's dependent descendants or reinterpret their ops |
| | 501 | against the chosen base. Require validated causal translation/rebase; otherwise |
| | 502 | retain the complete alternate-and-descendant closure unresolved. Contradictory |
| | 503 | bytes for one immutable identity halt automatic interpretation of that history. |
| | 504 | 3. Form a reproducible integration plan for the **complete known input set**. |
| | 505 | Its identity covers notebook lineage, named seed/base, source frontier and |
| | 506 | coverage, merge/codec version, stable causal processing order and all outcome |
| | 507 | dependencies. Dependency order comes first, then a specified byte order of |
| | 508 | immutable source identities for concurrent inputs. Clocks, directory order, |
| | 509 | local arrival order and largest epoch are excluded. A newly discovered input |
| | 510 | makes a new plan; it cannot make the old plan evidence disappear. |
| | 511 | 4. For incomparable histories, choose the same retained primary checkpoint under |
| | 512 | that ordering, then rebase the remaining original inputs through existing |
| | 513 | ops/retained-version merge. Preserve conflict pages and every opaque/unmergeable |
| | 514 | version. Do not integrate “whatever this device's mutable file currently is” |
| | 515 | as an unspecified primary. If normal incremental integration depends on |
| | 516 | arrival order, reproduce the plan from its named retained raw base in a |
| | 517 | disposable section and append normal transactions. No page-model reconstruction |
| | 518 | or whole-page diff/save shortcut is allowed. This may cost more I/O. |
| | 519 | 5. Persist exact prepared revisions, input coverage, result raw section/catalog |
| | 520 | checkpoint and external blobs before issuing a recoverability promise. An |
| | 521 | integration checkpoint is a result over source inputs, not another independent |
| | 522 | edit. Subsequent branches carry inherited coverage; replaying integrations as |
| | 523 | new source edits must not multiply conflicts. Same plan/outcome retries reuse |
| | 524 | their identities. Existing named-revision dedup alone does not solve every |
| | 525 | independently rebased or differently ordered plan. |
| | 526 | 6. Confirm/publish using the actual adapter's append and ambiguity rules. If a |
| | 527 | valid projection has rolled back, retain those bytes, import unknown external |
| | 528 | revisions as separate inputs, then restore the chosen raw checkpoint or append |
| | 529 | repair revisions as the adapter requires. Copying a validated raw checkpoint |
| | 530 | repairs a materialized store; it is not recreating notes from a page model. |
| | 531 | Retain the checkpoint even after local confirmation. Receipt coverage names |
| | 532 | the integrated inputs and retained alternatives, not a globally complete view. |
| | 533 | 7. Recheck after publication and on later observations. A delayed stale upload |
| | 534 | starts another repair with the same retained history; it does not reapply user |
| | 535 | edits. Once a fresh replica sees the chosen checkpoint and the same inputs, |
| | 536 | another reconciliation must produce no extra edit/conflict revisions. A |
| | 537 | publisher that cannot satisfy these steps retains work without claiming a |
| | 538 | recoverable integrated outcome. |
| | 539 | |
| | 540 | Stable ordering is a proposed integration mechanism to validate, not a claim that |
| | 541 | today's `resolve::merge` is commutative. The existing merge keeps the current |
| | 542 | branch as the main page when edits overlap. Its deterministic revision names help |
| | 543 | retry an original branch, but neither equal names nor presence of both texts |
| | 544 | proves equal primary/conflict placement, causal coverage or byte-identical files. |
| | 545 | Plan equivalence must compare source/outcome coverage, main and conflict page |
| | 546 | identities/content, tombstones, catalog and blob closure. Physical allocation, |
| | 547 | header bookkeeping and encoding can differ without a semantic disagreement; |
| | 548 | such differences must not trigger endless republishing. |
| | 549 | |
| | 550 | The implementation gate is stronger than static sorted input testing: two fresh |
| | 551 | replicas receiving the same branches in opposite orders, including intermediate |
| | 552 | integration checkpoints and new edits based on them, must converge to equivalent |
| | 553 | covered outcomes without duplicate conflict pages or silently repeated requests. |
| | 554 | Test at least three concurrent branches, ancestor/descendant arrivals, one request |
| | 555 | accepted on two branches, namespace operations and protected/opaque payloads. |
| | 556 | If the current merge cannot satisfy this, retain unresolved alternatives and fix |
| | 557 | the integration algorithm before claiming automatic convergence. Recovery custody |
| | 558 | can remain safe while automatic integration is unavailable. |
| | 559 | |
| | 560 | Eventual repair is conditional. For a finite settled input set, its complete |
| | 561 | closures must eventually reach a compatible unlocked reconciler; stale uploads |
| | 562 | must eventually stop replacing the path; and a successful repair must eventually |
| | 563 | be visible. A deterministic plan alone cannot guarantee these properties. |
| | 564 | Repeated infinite old uploads are an explicit liveness counterexample. No finite |
| | 565 | number of quiet reads proves that the last stale upload has arrived. Lack of |
| | 566 | quiescence must consume retry/backoff budget, not user history or retained bases. |
| | 567 | |
| 424 | ## Authority and disaster recovery | 568 | ## Authority and disaster recovery |
| 425 | | 569 | |
| 426 | The `.one` files remain the interoperable materialized section format. The | 570 | The `.one` files remain the interoperable materialized section format. For an |
| 427 | sidecar must preserve accepted history beyond those mutable files if it is to | 571 | explicitly registered coordinated notebook, validated retained sidecar history |
| 428 | repair demonstrated rollbacks. This is a proposed recovery requirement, not a | 572 | and its complete closures are authoritative for accepted/pending work when |
| 429 | silent declaration that an arbitrary `.snowbound` folder always overrides every | 573 | mutable files regress. Registration binds notebook lineage, section identities, |
| 430 | `.one` file found beside it. | 574 | protocol version and initial recovery closure; an arbitrary adjacent `.snowbound` |
| | 575 | folder has no authority over a bare import or a different section at the same |
| | 576 | path. This changes the backup contract for the selected mode, not the `.one` |
| | 577 | format or native/SMB modes. |
| 431 | | 578 | |
| 432 | Distinguish three recovery operations: | 579 | Distinguish three recovery operations: |
| 433 | | 580 | |
| ... | @@ -542,9 +689,9 @@ checkpoint does not automatically include external payload files. | ... | @@ -542,9 +689,9 @@ checkpoint does not automatically include external payload files. |
| 542 | | 689 | |
| 543 | ## Retention, compaction, and device rejoin | 690 | ## Retention, compaction, and device rejoin |
| 544 | | 691 | |
| 545 | The first safe implementation can retain immutable logs/checkpoints without | 692 | The first implementation retains immutable logs/checkpoints without automatic |
| 546 | automatic deletion. Storage use is real, so measure it and design compaction; | 693 | deletion. Storage use is real, so measure it and design compaction; finite retention |
| 547 | finite retention must not be disguised as a correctness proof. | 694 | must not be disguised as a correctness proof. |
| 548 | | 695 | |
| 549 | No “all devices have seen it” rule can be inferred from current listings or | 696 | No “all devices have seen it” rule can be inferred from current listings or |
| 550 | heartbeats. An offline device may hold unpublished edits indefinitely. Deleting | 697 | heartbeats. An offline device may hold unpublished edits indefinitely. Deleting |
| ... | @@ -676,6 +823,56 @@ without copying or changing them. The fixture is a disposable read of | ... | @@ -676,6 +823,56 @@ without copying or changing them. The fixture is a disposable read of |
| 676 | `corpus/conflict-page/native/initial/notebook/synthetic.one`; its input hash is | 823 | `corpus/conflict-page/native/initial/notebook/synthetic.one`; its input hash is |
| 677 | recorded. No commercial provider, emulator, or OneNote process ran in this lab. | 824 | recorded. No commercial provider, emulator, or OneNote process ran in this lab. |
| 678 | | 825 | |
| | 826 | ### Resilience policy follow-up |
| | 827 | |
| | 828 | The 2026-10-11 follow-up under |
| | 829 | `target/multi-file-sync-resilience-20261011/` tests the selected policy's recovery |
| | 830 | primitives and exposes limits of the current merge. Run 2 completed with exit 0 |
| | 831 | in 2.4 seconds after the initial compilation populated the shared cache. The |
| | 832 | first attempt failed to compile a lab-only immutable binding used by |
| | 833 | `Section::conflicts()`; its exact source/log/result remain preserved. Neither |
| | 834 | attempt changes production code. |
| | 835 | |
| | 836 | | Experiment | Observed outcome | |
| | 837 | | --- | --- | |
| | 838 | | Same overlapping ALICE/BOB branches, opposite primary bases | Both alternatives survive, but main/conflict placement differs; three replays of each original branch add zero publications and preserve exact bytes | |
| | 839 | | Cross-deliver those opposite integration artifacts directly to current merge | Both directions publish again, flip the primary text and retain two conflict pages, including an alternative repeating current main text; naïve integration-result exchange is not convergence | |
| | 840 | | Sort the same complete two-branch set before choosing a retained primary | Both arrival orders produce the same main/conflict identities and text; raw bytes and some active revision identities still differ | |
| | 841 | | Five successive stale canonical replacements, alternating seed/A/B images | Every finite round repairs to exact ALPHA BETA using retained originals/checkpoint; repair costs 2/1/1/2/1 publications, and settled same-database/fresh-replica retries add zero | |
| | 842 | | Fresh local recovery with a truncated canonical image | Cold parser rejects the image; retained raw source sections recover exact ALPHA BETA; observing only B lacks ALPHA and cannot establish complete history | |
| | 843 | |
| | 844 | Ten SQLite files pass integrity checks. Each saved valid `.one` is cold parsed |
| | 845 | through the existing store/index/document reader with checksum/current-revision |
| | 846 | validation; actual conflict pages are inspected separately from the ordinary |
| | 847 | page. The immutable archive stays unchanged across repair. These are disposable |
| | 848 | copies of the prior native-corpus fixture and actual production |
| | 849 | `Replica`/`resolve::merge`/transaction calls; provider replacements, visibility, |
| | 850 | source ordering and logical database reopen are simulated by the lab. |
| | 851 | |
| | 852 | The sorted-set result proves only a bounded presentation property for this |
| | 853 | complete two-branch fixture. It does not prove equivalent opaque/protected |
| | 854 | content, downstream causal translation, arbitrary incremental DAG convergence, |
| | 855 | namespace operations, request coverage deduplication, cloud custody or OS-crash |
| | 856 | durability. The opposite-integration result is why the selected algorithm must |
| | 857 | track source coverage and normalize from retained inputs instead of feeding |
| | 858 | integration artifacts back as new independent edits. No automatic convergence |
| | 859 | claim is justified by this investigation. |
| | 860 | |
| | 861 | Rerun from a clean new output directory with one granted build slot: |
| | 862 | |
| | 863 | ```sh |
| | 864 | nice -n 10 env CARGO_BUILD_JOBS=2 CARGO_TARGET_DIR="$PWD/target" cargo run --offline \ |
| | 865 | --manifest-path target/multi-file-sync-resilience-20261011/lab/Cargo.toml -- \ |
| | 866 | "$PWD/target/multi-file-sync-resilience-20261011/run-new" |
| | 867 | ``` |
| | 868 | |
| | 869 | The ignored standalone lab links the current source in |
| | 870 | `workspaces/sync-resilience` and reads three bound `.one` inputs from the original |
| | 871 | run 7 without modifying them. Its verification manifest binds lab/dependency |
| | 872 | sources, inputs, raw outputs, SQLite integrity checks, draft architecture review |
| | 873 | and document checks. No commercial provider, emulator or OneNote process runs |
| | 874 | in this follow-up. Native OneNote cold-open remains an implementation gate. |
| | 875 | |
| 679 | | Fault | Required result / investigation oracle | | 876 | | Fault | Required result / investigation oracle | |
| 680 | | --- | --- | | 877 | | --- | --- | |
| 681 | | Prefix/partial body, invalid length/digest | Reject/wait; last valid state untouched | | 878 | | Prefix/partial body, invalid length/digest | Reject/wait; last valid state untouched | |
| ... | @@ -713,14 +910,15 @@ recovery and normal append operations. Platform hosts adapt document/file APIs, | ... | @@ -713,14 +910,15 @@ recovery and normal append operations. Platform hosts adapt document/file APIs, |
| 713 | retained local directories and actual I/O/error callbacks. Android rendering and | 910 | retained local directories and actual I/O/error callbacks. Android rendering and |
| 714 | native IME/accessibility can ship independently of this protocol. | 911 | native IME/accessibility can ship independently of this protocol. |
| 715 | | 912 | |
| 716 | Before production protocol code, review practical evidence and select: | 913 | The owner has selected resilient branch-preserving takeover and retained recovery |
| | 914 | authority for registered coordinated notebooks. Before production protocol code, |
| | 915 | validate the reconciliation/receipt algorithm against the gates above and define: |
| 717 | | 916 | |
| 718 | - Fixed publisher/explicit handoff versus branch-preserving automatic recovery, | 917 | - Explicit registration, bare import, intentional restore and duplicate-copy flows |
| 719 | and whether majority membership offers enough benefit for its availability cost. | 918 | that preserve the stated lineage/custody boundaries. |
| 720 | - The authority/recovery contract for registered notebooks, bare imports, | | |
| 721 | intentional restores, duplicate notebook copies and copied owner credentials. | | |
| 722 | - Protected-key custody and unsupported-client migration/escape behavior. | 919 | - Protected-key custody and unsupported-client migration/escape behavior. |
| 723 | - Retention/compaction guarantees and a measured provider capability floor. | 920 | - Measured provider capability floor and storage cost. Initial automatic GC is |
| | 921 | excluded; later compaction requires its own recovery proof. |
| 724 | | 922 | |
| 725 | Unknown protocol/required-op versions must leave remote data untouched and keep | 923 | Unknown protocol/required-op versions must leave remote data untouched and keep |
| 726 | local edits recoverable. Enabling coordination requires an explicit migration | 924 | local edits recoverable. Enabling coordination requires an explicit migration |
| ... | @@ -730,6 +928,6 @@ needs an honest compatibility boundary and an opt-in/import path, not a claim | ... | @@ -730,6 +928,6 @@ needs an honest compatibility boundary and an opt-in/import path, not a claim |
| 730 | that an unsupported build will obey a new marker. | 928 | that an unsupported build will obey a new marker. |
| 731 | | 929 | |
| 732 | The next concrete deliverable after the draft is a narrow transport/owner lab | 930 | The next concrete deliverable after the draft is a narrow transport/owner lab |
| 733 | against real provider fixtures, then one selected policy implemented behind an | 931 | against real provider fixtures, then the selected policy implemented behind an |
| 734 | explicit storage mode and tested with actual notes. No timeout election or | 932 | explicit storage mode and tested with actual notes. No timeout election or |
| 735 | full-image save shortcut should land as an Android dependency. | 933 | full-image save shortcut should land as an Android dependency. |