frontend-patterns/research/walkthroughs/VC02-OfflineFieldNotes.md
tegwick d7b2ea49ce Inspect frontend recovery implementations and refine operation lifecycles
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
2026-09-25 10:41:59 +02:00

141 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# VC-02 — Offline field notes, restart and reconnect
Status: drafted and editorially self-reviewed, 2026-09-25, codex.
Synthetic reasoning exercise; no application or storage engine was fault-tested.
Evidence baseline: repository `ad6f8fa`; candidate additions in this change.
No canonical pattern admission or M1 completion is implied.
## Fixed brief and assumptions
Preserve VC-02: create/edit offline; restart without losing acknowledged work; later
multi-device sync; conflicting edits possible. Additional assumptions for this exercise:
- Two authorized devices edit plain-text notes. Both start with note N, revision r0.
- A completed local storage transaction survives ordinary process restart. The engine
and flush policy are undecided; power-loss survival is explicitly not established.
- Stable document and operation identities plus revision ancestry detect divergent
changes. Wall-clock timestamps alone are not assumed sufficient.
- The sync receiver deduplicates operation IDs and acknowledges a specific revision.
Acknowledgement means this receiver accepted it, not that all devices have converged.
- Delete/edit conflicts, attachments and concurrent authorization changes are outside
this first trace. They remain gaps, not silently solved cases.
- UI must support keyboard use, non-color status and focus-preserving conflict review.
Sensitive note/conflict copies have equal access protection; content is excluded
from telemetry. Threat model, device encryption and key recovery remain open.
- Interaction feedback should remain responsive offline; local commit and replication
latency are measured separately. No invented numerical performance target.
## Baseline narrative without the catalog
Save notes and pending uploads in a local transaction. Show unsaved versus locally
saved status, upload on reconnection, and retain remote acknowledgements. When the
same base revision has diverged, preserve both versions, expose the discrepancy and
let the user merge. Save and synchronize the result. Back up data separately.
This baseline already expresses a plausible architecture. Pattern names must improve
review of boundaries and missing guarantees; they do not get credit merely for naming it.
## Decisions and provisional connections
| Order | Context and forces | Candidate and decision | Alternative rejected for this brief | Resulting context / evidence |
| --- | --- | --- | --- | --- |
| 1 | Offline availability vs recoverability | [Local Commit Boundary](../candidates/LocalCommitBoundary.md): acknowledge only after document plus pending intent commit | Server-only acknowledgement prevents offline save; memory-only save fails restart | Local saved state exists independently of sync; E01/E04 motivate this, atomicity is an assumption |
| 2 | Freshness vs intermittent network | [Pending Synchronization](../candidates/PendingSynchronization.md): retain identity, retry and confirm a specific revision | Fire-and-forget upload loses uncertainty on restart | Durable pending work; E05/E06 motivate separation, exact protocol is proposed |
| 3 | Divergent intent vs continued work | [Conflict Copy](../candidates/ConflictCopy.md): preserve alternate content and mark unresolved before selecting active content | Blind replacement discards an edit; assumed universal automatic merge lacks evidence | Two recoverable versions; E07/E08 document uses, crash-safe sequence is proposed |
| 4 | User control vs reconciliation effort | [Explicit Reconciliation](../candidates/ExplicitReconciliation.md): compare, commit a new revision and queue it | A conflict file alone does not establish user awareness or resolution | New decision can synchronize; E07/E08 support manual comparison, UI contract unverified |
| 5 | Device loss vs operational burden | Require separately recoverable backup and restoration procedure | Calling synchronization a backup does not meet the recovery goal | External recovery obligation; E11, not a newly invented pattern |
E references resolve in [the evidence review](../reviews/LocalFirstEvidenceExpansion.md).
Relations are provisional: local commit enables pending propagation; divergence may
create context for a conflict copy; preserved divergence enables explicit review;
review creates a new local commit. These are not admitted graph edges or a universal
ordering: quality/recovery requirements influence step 1, not only step 5.
## Restart/reconnect trace
| Step | Event | Local and remote state | User-visible statement / required invariant |
| --- | --- | --- | --- |
| 0 | A and B share r0 | Receiver has r0 | No pending edits under these assumptions |
| 1 | Offline A edits r0→a1 | Editor holds new text; transaction pending | Editing feedback, still unsaved; no persistence claim |
| 2 | A commits a1 + operation opA atomically | A has a1 and pending opA | Saved on this device; not yet synchronized |
| 3 | A restarts while offline | Reconstruct a1 and opA from storage | Same local-save and pending-sync states survive restart |
| 4 | B independently commits r0→b1, then uploads | Receiver acknowledges b1; A still has a1 | B has receiver confirmation only; A cannot yet know b1 |
| 5 | A reconnects | Ancestry shows a1 and b1 diverge from r0 | Do not mark divergence semantically resolved |
| 6 | A preserves a1 and selects b1 as active | One recoverable transaction stores conflict K, active b1, unresolved marker and blocks opA from automatic upload | Conflict needs review; remote selection does not establish remote semantic authority |
| 7 | A restarts again | K and unresolved marker remain | Both versions discoverable, keyboard review available |
| 8 | User reconciles to c1 | Commit c1 with parents a1/b1 and pending opC; supersede blocked opA atomically; retain history | Resolved locally; synchronization still pending |
| 9 | Receiver accepts opC, response is lost | c1 may be stored remotely; A still has pending opC | Do not claim failure or global success from timeout alone |
| 10 | A retries opC | Receiver deduplicates and confirms c1; A stores receipt | Synced to receiver at c1; other-device delivery and backup are separate |
A deterministic conflict identity derived from document and revision pair is one
proposed way to avoid multiplying copies on retry. The trace assumes that mechanism;
it is not verified product behavior. A crash before step 2 commit can lose unacknowledged
input; a crash within step 6 must leave either the previous state or the full conflict
state. A partial state would violate the chosen transaction contract and fail the design.
## Change one constraint
Change only concurrency: B may read, but only A may edit this note. Keep offline,
restart, sync, privacy and accessibility requirements fixed.
Steps 1–3 and 9–10 remain necessary. Under the single-writer assumption, steps 4–8
for concurrent edits are unnecessary: omit conflict-copy and reconciliation machinery
for that case. Stable IDs and retry handling remain. Do not claim conflicts impossible
if external editors, restoration or another writer later violate the assumption.
This branch shows that Conflict Copy is conditional, not a prerequisite of local storage.
## Failure and recovery boundaries
- Full disk or denied write: keep unsaved status and actionable error; never acknowledge.
- Missing local transaction guarantee: stop adoption until the storage contract is tested.
- Lost sync acknowledgement: preserve operation identity; duplicate requests must not
duplicate the edit. Network recovery alone does not prove this behavior.
- Revoked access: surface blocked synchronization, preserve local work according to
the agreed security policy; do not retry forever or invent offline authorization.
- Conflict notification failure: retained bytes do not satisfy discoverability.
- Device loss/corruption: conflict copies on that device are insufficient; restore from
separately retained data. Recovery point and key availability remain undecided.
## Editorial self-review
| Criterion | Outcome | Reason |
| --- | --- | --- |
| Traceability | pass for bounded reasoning | Documentary claims have E references; proposed transactions/protocols are labeled assumptions |
| Coherence | revise | Trace is consistent under stated assumptions; actual storage and idempotency contracts are unverified |
| Decision usefulness beyond baseline | unknown | Explicit boundary names expose review questions, but the baseline already contains the architecture; no independent comparison |
| Quality constraints | revise | Accessibility, privacy, errors and recovery enter initial decisions; acceptance tests and threat model are still missing |
| Changed-constraint branch | pass for synthetic reasoning | Removing concurrent writers removes two responsibilities while retaining persistence and propagation |
Disposition: retain four connected research drafts; no canonical promotion. Consider
merging Explicit Reconciliation into Conflict Copy if a second walkthrough cannot
justify separate retrieval/use. This is development evidence, not a held-out evaluation.
## Questions that justify the next research work
1. Which storage transaction/acknowledgement contract survives the required restart
modes? Obtain documentation plus a small crash test for a selected implementation.
2. What receiver protocol makes retries and divergent revision detection safe? Locate
an implementation and test lost acknowledgements before claiming correctness.
3. Can a user find, compare and resolve conflicts with keyboard/screen-reader use?
Define and exercise an accessibility acceptance scenario.
4. What changes in VC-01 when a local edit must satisfy a global transaction rule?
Perform that contrasting walkthrough before treating these connections as general.
These are owned by FEP-WP-0002-T02 (specific evidence) and T03 (walkthrough/corpus).
Broad source collection, more self-critique and additional provider calls would not
answer them without selecting an implementation or a comparison protocol.
## Recovery lifecycle clarification — 2026-09-25
opA is a durable pending-upload record with an immutable identity and payload for a1.
Conflict detection blocks its automatic retry; it is not acknowledged as synchronized.
The step 8 transaction marks opA superseded while recording c1 and opC. A delayed
receipt for opA updates only its history, never the current revision or opC status.
The receiver must enforce ancestry/preconditions on delayed submissions too; otherwise
an in-flight opA could overwrite c1 despite local queue retirement. This strengthens
an explicit protocol requirement; it is not an observed Joplin/Obsidian guarantee.
The crash before that transaction leaves opA blocked and the conflict unresolved;
a crash after it leaves opC pending and opA superseded.
See [recovery review](../reviews/RecoveryWalkthroughReview.md). These lifecycle rules
are design corrections, still awaiting implementation and fault-test evidence.