From d7b2ea49cef683aeba10e2bf512aa883a912c997 Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 25 Sep 2026 10:41:59 +0200 Subject: [PATCH] Inspect frontend recovery implementations and refine operation lifecycles Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9 --- TREE.md | 12 + research/README.md | 2 + research/candidates/LocalDraftState.md | 9 + .../candidates/MutationOutcomeTracking.md | 11 + research/catalog/SourceCatalog.md | 10 + research/plan/OpenQuestions.md | 2 + .../FrontendRecoveryImplementations.md | 100 ++++++++ research/reviews/FrontendRecoverySources.json | 83 ++++++ research/reviews/RecoveryReviewMetrics.json | 26 ++ research/reviews/RecoveryWalkthroughReview.md | 55 ++++ research/reviews/VC01-VC02-Comparison.md | 9 + .../reviews/recovery-review-01/inputs.json | 8 + research/reviews/recovery-review-01/prompt.md | 235 +++++++++++++++++ .../reviews/recovery-review-01/receipt.json | 56 +++++ .../recovery-review-01/rejected-response.md | 56 +++++ .../reviews/recovery-review-02/inputs.json | 8 + research/reviews/recovery-review-02/prompt.md | 236 ++++++++++++++++++ .../reviews/recovery-review-02/receipt.json | 56 +++++ .../reviews/recovery-review-02/response.md | 17 ++ .../VC01-TransactionalAdministration.md | 20 ++ .../walkthroughs/VC02-OfflineFieldNotes.md | 19 +- .../FEP-WP-0002-seed-language-validation.md | 20 ++ 22 files changed, 1048 insertions(+), 2 deletions(-) create mode 100644 research/reviews/FrontendRecoveryImplementations.md create mode 100644 research/reviews/FrontendRecoverySources.json create mode 100644 research/reviews/RecoveryReviewMetrics.json create mode 100644 research/reviews/RecoveryWalkthroughReview.md create mode 100644 research/reviews/recovery-review-01/inputs.json create mode 100644 research/reviews/recovery-review-01/prompt.md create mode 100644 research/reviews/recovery-review-01/receipt.json create mode 100644 research/reviews/recovery-review-01/rejected-response.md create mode 100644 research/reviews/recovery-review-02/inputs.json create mode 100644 research/reviews/recovery-review-02/prompt.md create mode 100644 research/reviews/recovery-review-02/receipt.json create mode 100644 research/reviews/recovery-review-02/response.md diff --git a/TREE.md b/TREE.md index b9309d7..24b9d6b 100644 --- a/TREE.md +++ b/TREE.md @@ -264,11 +264,15 @@ research/plan/ResearchProtocol.md research/plan/ValidationCases.md research/reviews/AuthorityPilot.md research/reviews/CarniatoAdmissionRegression.json +research/reviews/FrontendRecoveryImplementations.md +research/reviews/FrontendRecoverySources.json research/reviews/JoplinConflictScreen.json research/reviews/LLMConnectPilot.md research/reviews/LocalFirstAdmissionScreen.json research/reviews/LocalFirstEvidenceExpansion.md research/reviews/ObsidianConflictScreen.json +research/reviews/RecoveryReviewMetrics.json +research/reviews/RecoveryWalkthroughReview.md research/reviews/ResearchOptimization.md research/reviews/ResearchPipelineRefinement.md research/reviews/SchemaAndSourcePreparation.md @@ -276,6 +280,14 @@ research/reviews/TransactionalEvidenceExpansion.md research/reviews/TransactionalLiveReview.yaml research/reviews/TruncationDiagnosis.md research/reviews/VC01-VC02-Comparison.md +research/reviews/recovery-review-01/inputs.json +research/reviews/recovery-review-01/prompt.md +research/reviews/recovery-review-01/receipt.json +research/reviews/recovery-review-01/rejected-response.md +research/reviews/recovery-review-02/inputs.json +research/reviews/recovery-review-02/prompt.md +research/reviews/recovery-review-02/receipt.json +research/reviews/recovery-review-02/response.md research/walkthroughs/VC01-TransactionalAdministration.md research/walkthroughs/VC02-OfflineFieldNotes.md scripts/research_admission.py diff --git a/research/README.md b/research/README.md index f38374e..3b4588c 100644 --- a/research/README.md +++ b/research/README.md @@ -30,3 +30,5 @@ Execute bounded source investigations with the [research bench](bench/README.md) Its checked-in fixture verifies the pipeline and is excluded from research evidence. Current contrast: [VC-01 server-validated editing](walkthroughs/VC01-TransactionalAdministration.md), [VC-02 offline editing](walkthroughs/VC02-OfflineFieldNotes.md), and [cross-case assessment](reviews/VC01-VC02-Comparison.md). + +Latest implementation evidence: [frontend recovery](reviews/FrontendRecoveryImplementations.md) and [walkthrough correction review](reviews/RecoveryWalkthroughReview.md). diff --git a/research/candidates/LocalDraftState.md b/research/candidates/LocalDraftState.md index c6c430c..ca51daa 100644 --- a/research/candidates/LocalDraftState.md +++ b/research/candidates/LocalDraftState.md @@ -31,3 +31,12 @@ Proposed connection: supports recovery from [Version-Checked Mutation](VersionCh T01–T05 refer to [TransactionalEvidenceExpansion](../reviews/TransactionalEvidenceExpansion.md). Connections are research proposals, not admitted graph edges. Reasoning exercise: [VC-01](../walkthroughs/VC01-TransactionalAdministration.md). + +## Implementation evidence update — 2026-09-25 + +[Frontend recovery review](../reviews/FrontendRecoveryImplementations.md) R01/R03 +locates Zulip and Element draft storage/restoration at exact commits. These are two +partial known uses of unsent-intent separation, not confirmation of the entire +base/draft/current merge contract. Full-pattern recurrence remains unknown. +A composer may hand submitted content to a separate pending record. Preserve the +recoverable intent across that handoff; do not require the input box to stay filled. diff --git a/research/candidates/MutationOutcomeTracking.md b/research/candidates/MutationOutcomeTracking.md index 8f885b3..6b565db 100644 --- a/research/candidates/MutationOutcomeTracking.md +++ b/research/candidates/MutationOutcomeTracking.md @@ -35,3 +35,14 @@ be valid there while remote propagation remains unacknowledged. T01–T05 refer to [TransactionalEvidenceExpansion](../reviews/TransactionalEvidenceExpansion.md). Connections are research proposals, not admitted graph edges. Reasoning exercise: [VC-01](../walkthroughs/VC01-TransactionalAdministration.md). + +## Implementation evidence update — 2026-09-25 + +[Frontend recovery review](../reviews/FrontendRecoveryImplementations.md) R02/R04–R06 +locates failed-send recovery and echo reconciliation in two frontend families. +These are partial uses, not verified implementations of all four proposed states. +NOT_SENT or failed_request may reflect missing confirmation, not proven rejection. +Correlation IDs, server deduplication and authoritative acceptance require separate +evidence. A later matching authoritative event can resolve uncertainty; stale errors +must not overwrite stronger evidence. Keep hypothesis maturity; assess whether this +is best retained as a shared review model rather than a standalone pattern. diff --git a/research/catalog/SourceCatalog.md b/research/catalog/SourceCatalog.md index 45596a1..a30896c 100644 --- a/research/catalog/SourceCatalog.md +++ b/research/catalog/SourceCatalog.md @@ -62,3 +62,13 @@ execution evidence and limitations. 2026-09-25: local-first `-06` completed after replacing padded claim tables with compact records. Its bounded negative result does not complete full-source review. Source state remains extracted; recurrence and independent implementations remain open. + +## Pinned frontend implementations — 2026-09-25 + +SRC-0013 Zulip, SRC-0014 Element Web, SRC-0015 Matrix JS SDK and SRC-0016 Matrix +client-server specification v1.15 are inspected in the +[frontend recovery review](../reviews/FrontendRecoveryImplementations.md). +The [manifest](../reviews/FrontendRecoverySources.json) records exact revisions, +file URLs and SHA-256 hashes. State: bounded static review; no runtime validation. +Element and its SDK are one implementation family. Complete-pattern recurrence +remains unproven despite two partial draft-preservation uses. diff --git a/research/plan/OpenQuestions.md b/research/plan/OpenQuestions.md index 2f5acbb..7196669 100644 --- a/research/plan/OpenQuestions.md +++ b/research/plan/OpenQuestions.md @@ -55,3 +55,5 @@ The failed provider runs are execution failures, not negative evidence for the m ## Transactional contrast — 2026-09-25 [VC-01/VC-02 assessment](../reviews/VC01-VC02-Comparison.md) sharpens Q02: local drafts do not imply local authority. Q03 lacks independent frontend uses; Q04 remains unknown despite two complete synthetic narratives. No question is closed by pattern count. + +2026-09-25 follow-up: [pinned frontend code](../reviews/FrontendRecoveryImplementations.md) supports two partial draft-separation uses, but not full-pattern recurrence. [Review attempt](../reviews/RecoveryWalkthroughReview.md) yielded no adopted model fixes; editorial lifecycle corrections do not resolve Q04 usefulness. diff --git a/research/reviews/FrontendRecoveryImplementations.md b/research/reviews/FrontendRecoveryImplementations.md new file mode 100644 index 0000000..a12b327 --- /dev/null +++ b/research/reviews/FrontendRecoveryImplementations.md @@ -0,0 +1,100 @@ +# Frontend recovery implementation review + +Codex, 2026-09-25. Static source inspection at pinned commits, not runtime or fault +injection. Selection: two independently developed chat frontends with inspectable +draft and retry code. Chat sends broaden evidence for proposal lifecycles; they do +not validate transactional approval, version checking or offline note durability. +Exact file hashes and URLs: [source manifest](FrontendRecoverySources.json). + +## Revisions and independence + +- SRC-0013 Zulip: `5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c`. +- SRC-0014 Element Web: `60b54fc8446ad1a88963660927cd7e1865905e63`. +- SRC-0015 Matrix JS SDK: `c0cf1015980b48a6f1332701cd731740d3f58272`. +- SRC-0016 [Matrix client-server specification v1.15](https://spec.matrix.org/v1.15/client-server-api/#transaction-identifiers), Transaction identifiers; accessed 2026-09-25. + +Element's [package declaration](https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/package.json#L84) +references SDK develop. The separately pinned SDK is an inspected mechanism snapshot, +not a verified lockfile resolution for this Element build. Element and its SDK count +as one implementation family, never two independent uses. No production release or +installed behavior is inferred from repository HEAD. + +## Located observations + +**R01 — Zulip drafts.** [compose_actions.hide_box](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/compose_actions.ts#L90) +saves the draft before hiding composition. [draft storage](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/drafts.ts#L207) +writes through its local-storage wrapper; [restore_message](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/drafts.ts#L388) +reconstructs compose arguments. This supports separating unsent intent from sent +messages. It does not prove crash durability or base/draft/current merge behavior. + +**R02 — Zulip failed send and later evidence.** [resend_message](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/echo.ts#L162) +retains content, marks a resend, snapshots the request and submits again. Its +[event handling](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/echo.ts#L540) matches local IDs, replaces temporary identity, +and can clear a failure indication when the server event arrives. The +[error path](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/echo.ts#L641) sets failed_request; this client flag is not a proof +of server non-commit. [transmit](https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/transmit.ts#L33) distinguishes acknowledgement +from later event receipt and restarts event polling if an acknowledged event is late. +These paths support asynchronous reconciliation, not a proven server deduplication +contract. No claim that Zulip duplicates messages or guarantees duplicate prevention +follows from these selected files. + +**R03 — Element drafts and handoff.** [SendMessageComposer](https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/src/components/views/rooms/SendMessageComposer.tsx#L514) +saves/restores editor state with a room/thread key using localStorage; unmount saves +state. Its [send path](https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/src/components/views/rooms/SendMessageComposer.tsx#L479) +hands content to sendMessage and clears reply context while retry is delegated to +the queued message. Retaining recoverable intent need not mean retaining composer +text. Storage errors, crash windows and complete queue persistence were not tested. + +**R04 — Element retry entry.** [Resend](https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/src/Resend.ts#L16) selects NOT_SENT pending +events and passes the existing event to client.resendEvent. Its success branch +announces message_sent; its failure branch logs the failure. This is a real frontend +retry entry, but says nothing by itself about authoritative rejection. + +**R05 — SDK identity and transport outcome.** [resendEvent](https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/client.ts#L2528) +reuses the event and changes its local status. [sendEventHttpRequest](https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/client.ts#L3120) +uses its existing transaction ID or assigns one, then places it in the ordinary +room-event PUT path. State-event paths differ: do not generalize this ID behavior to +all writes. The [send catch](https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/client.ts#L3004) sets NOT_SENT after an error; +that label alone cannot distinguish rejection from a lost response. +[Room remote-echo handling](https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/models/room.ts#L2916) merges the remote event into +the local event and removes transaction tracking. The SDK snapshot supports these +mechanisms, not the end-to-end correctness of a particular deployed client/server. + +**R06 — Protocol contract.** Matrix v1.15 specifies that retransmissions with matching +transaction identity and request path should return the original response. Scope is +device and endpoint; a new device changes that scope. This supplies a protocol +basis for ordinary event retries, distinct from local-echo matching. It does not +establish a tested server implementation, indefinite result retention, payload-change +rules for our approval application, or full frontend recovery after restart. + +## Synthesis and candidate decisions + +Local Draft State has two independent partial code uses (R01/R03) for unsent intent +separation. Neither implements the full base/draft/current contract of VC-01 in the +inspected paths. Keep hypothesis maturity and separate core-mechanism recurrence from +complete-pattern recurrence. + +Mutation Outcome Tracking has two partial recovery uses (R02/R04–R05). Neither proves +an explicit four-state model with unknown separated from rejected. Retain it as a +proposed review model for now, not an established implementation taxonomy. Add a +rule: preserve intent through a defined composer-to-pending handoff; classify states +by evidence rather than names in an enum. Idempotency, correlation and acceptance +must each have their own evidence. + +No new pattern is needed. Version-Checked Mutation, Local Commit Boundary and offline +reconciliation gain no direct implementation confirmation here. Optimistic display +is visible in the inspected messaging mechanisms, but approval-specific safety and +independent full-pattern review remain missing; its standalone draft stays deferred. + +## Review boundary and next experiment + +A second-model critique of frozen walkthroughs ran through llm-connect; see +[its editorial disposition](RecoveryWalkthroughReview.md). It is a separate model +opinion, not independent human review, runtime evidence or a controlled usefulness +comparison. All original inputs and outputs are retained. + +Next under FEP-WP-0002 T02: choose one exact client/SDK/server combination and replay +acceptance-with-lost-response plus delayed echo, checking operation identity and +content preservation across retry. Under T03: compare blinded, matched baseline and +pattern-guided decisions on new variants with an independent reviewer. The present +self-authored cases cannot establish that names improve decisions. diff --git a/research/reviews/FrontendRecoverySources.json b/research/reviews/FrontendRecoverySources.json new file mode 100644 index 0000000..8e3af25 --- /dev/null +++ b/research/reviews/FrontendRecoverySources.json @@ -0,0 +1,83 @@ +{ + "accessed": "2026-09-25", + "method": "GitHub commit/tree API then raw file reads at pinned commits; static inspection only", + "files": [ + { + "repository": "zulip/zulip", + "revision": "5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c", + "path": "web/src/compose.ts", + "sha256": "f0f13db545e2e27a6d38fe3f1e49ee12a289e45f068eadc144a2f21536ff3534", + "url": "https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/compose.ts#L1" + }, + { + "repository": "zulip/zulip", + "revision": "5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c", + "path": "web/src/compose_actions.ts", + "sha256": "a2cd35fd5512f8cca8f7a350ae1f273a91bf4c01a6408ed95e73934ff1e48d22", + "url": "https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/compose_actions.ts#L1" + }, + { + "repository": "zulip/zulip", + "revision": "5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c", + "path": "web/src/drafts.ts", + "sha256": "c1b9b800b5a9f0ee8e1eb8c4db5056709e9588d67b589da7f6469b761bc51dae", + "url": "https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/drafts.ts#L1" + }, + { + "repository": "zulip/zulip", + "revision": "5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c", + "path": "web/src/echo.ts", + "sha256": "2315ef455cd72c5d3584cd98cbcd6c3e641a43040aea627bf99cab655297d7ef", + "url": "https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/echo.ts#L1" + }, + { + "repository": "zulip/zulip", + "revision": "5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c", + "path": "web/src/transmit.ts", + "sha256": "5d4901a4b4c010e6c4449770ba7471532bd199c8f17e987f259ff642c9d406dd", + "url": "https://github.com/zulip/zulip/blob/5b06fa3d34f28fa01f459fbf3ba053e3c0858e9c/web/src/transmit.ts#L1" + }, + { + "repository": "element-hq/element-web", + "revision": "60b54fc8446ad1a88963660927cd7e1865905e63", + "path": "apps/web/package.json", + "sha256": "17799c032c71729832f68c024a82c86f5f65e59c57b9dcd31b0d06efc93c1b12", + "url": "https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/package.json#L1" + }, + { + "repository": "element-hq/element-web", + "revision": "60b54fc8446ad1a88963660927cd7e1865905e63", + "path": "apps/web/src/Resend.ts", + "sha256": "549928bf6268ace70eac3b0205a0abcd7fd2e95e33b75a7bad8fd53ae342e05a", + "url": "https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/src/Resend.ts#L1" + }, + { + "repository": "element-hq/element-web", + "revision": "60b54fc8446ad1a88963660927cd7e1865905e63", + "path": "apps/web/src/components/views/rooms/SendMessageComposer.tsx", + "sha256": "a23bd2620047b2cb964893adf67d23edb290bd9c50a0cba1c76e679702bd0d11", + "url": "https://github.com/element-hq/element-web/blob/60b54fc8446ad1a88963660927cd7e1865905e63/apps/web/src/components/views/rooms/SendMessageComposer.tsx#L1" + }, + { + "repository": "matrix-org/matrix-js-sdk", + "revision": "c0cf1015980b48a6f1332701cd731740d3f58272", + "path": "src/client.ts", + "sha256": "dd226544aa6e0e99d39f9c25066be3fab52776bcc08c09d0e3e4c6c7d7206a5d", + "url": "https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/client.ts#L1" + }, + { + "repository": "matrix-org/matrix-js-sdk", + "revision": "c0cf1015980b48a6f1332701cd731740d3f58272", + "path": "src/models/event-status.ts", + "sha256": "b078fba2106c6124a93ff4940c6806af1571583a66a438e244ab558d7a1e7320", + "url": "https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/models/event-status.ts#L1" + }, + { + "repository": "matrix-org/matrix-js-sdk", + "revision": "c0cf1015980b48a6f1332701cd731740d3f58272", + "path": "src/models/room.ts", + "sha256": "aa22abe07579a78cab787d0b498db0248bd9843f64e3bfbc6b50ec615c198867", + "url": "https://github.com/matrix-org/matrix-js-sdk/blob/c0cf1015980b48a6f1332701cd731740d3f58272/src/models/room.ts#L1" + } + ] +} diff --git a/research/reviews/RecoveryReviewMetrics.json b/research/reviews/RecoveryReviewMetrics.json new file mode 100644 index 0000000..c226131 --- /dev/null +++ b/research/reviews/RecoveryReviewMetrics.json @@ -0,0 +1,26 @@ +{ + "reviewer": "Codex", + "reviewed_at": "2026-09-25", + "model_findings_reviewed": 2, + "model_findings_adopted": 0, + "editorial_corrections": [ + "E01", + "E02", + "E03" + ], + "disposition": "reject-model-fixes; retain-editorial-revisions", + "runs": [ + { + "path": "research/reviews/recovery-review-01", + "receipt_sha256": "fd81e9851aaa213a1d051514acf1c4840f2d8cea6eb99fe72a99285f6112b20c", + "status": "failed" + }, + { + "path": "research/reviews/recovery-review-02", + "receipt_sha256": "cf1596f44dd3ffd3fcf7b852bd96e25cb3e913e014c63a8bee6d80a1dfa82e65", + "status": "completed" + } + ], + "reported_tokens": 10605, + "independent_human_review": false +} diff --git a/research/reviews/RecoveryWalkthroughReview.md b/research/reviews/RecoveryWalkthroughReview.md new file mode 100644 index 0000000..1949057 --- /dev/null +++ b/research/reviews/RecoveryWalkthroughReview.md @@ -0,0 +1,55 @@ +# Recovery walkthrough review + +Codex editorial review, 2026-09-25. Frozen inputs: repository `96d1143`, with +per-file and prompt hashes in the review runs. One separate model was asked to +challenge both cases through llm-connect. This is not independent human review or +an empirical comparison. The revised second prompt explicitly corrected errors in +the first response; this is not a blinded evaluation. + +## Execution and disposition + +[Attempt 01](recovery-review-01/receipt.json) exceeded its 2,500-token response cap. +The incomplete text is quarantined, never counted as a completed review. It confused +omniscient trace descriptions with client knowledge and treated intended idempotent +replay as problematic. Do not apply its proposed change from a write producing v12 +to a write against v12: that changes the scenario incorrectly. + +[Attempt 02](recovery-review-02/receipt.json) completed with a stricter prompt limiting +findings and total words. [Full response](recovery-review-02/response.md) is retained. +Across both attempts: two service calls, 10,605 reported tokens. No direct provider +calls, credential retrieval, or unrecorded retries. + +1. Reject the proposed VC-01 freshness correction. An obsolete read cannot confirm + that a later write superseded it. Allowing it to update freshness markers would + weaken the intended invariant. Discard here means not applying obsolete data. +2. Reject the proposed VC-02 retry correction as a defect finding. The trace retries + the same immutable opC under an explicit deduplication assumption. Changed payload + would be a different proposal; it must not be smuggled into that retry. A new ID + while the original outcome is unresolved risks an extra transition. The response's + conditional same-payload clause is already covered by the trace's contract. + +Two model findings reviewed, zero adopted. Its statement that baseline usefulness +is unknown is retained. This negative result is evidence about this review attempt, +not evidence that the walkthroughs are correct or that model reviews never help. + +## Editorial corrections supported by local reasoning + +E01: VC-02 steps 6/8 previously left opA's lifecycle unspecified. Block it on detected +conflict, atomically supersede it when opC is queued, and require the receiver to +reject stale delayed operations. Local queue retirement alone cannot stop an in-flight +write. Delayed opA receipts affect history only. These are proposed contracts, not +product guarantees. + +E02: VC-01 step 9 lacked an operational rule for discarding obsolete reads. Add local +read generations plus an explicit read-after-write/server-version requirement. +Generation orders local requests, not opaque server revisions or replica freshness. + +E03: Add operation-specific evidence handling: a late error cannot reverse confirmed +acceptance, and a previous operation's receipt cannot clear newer typing. Define +composer-to-pending handoff separately from storage durability, motivated by the +[pinned frontend code](FrontendRecoveryImplementations.md). + +These are Codex editorial changes, not adopted model findings. They sharpen the +contract but remain synthetic reasoning. No new tests of frontend runtime behavior +were performed. Independent review, usability, crash recovery and full-pattern +recurrence remain open under FEP-WP-0002 T02/T03. diff --git a/research/reviews/VC01-VC02-Comparison.md b/research/reviews/VC01-VC02-Comparison.md index 6d6f294..3387edf 100644 --- a/research/reviews/VC01-VC02-Comparison.md +++ b/research/reviews/VC01-VC02-Comparison.md @@ -30,3 +30,12 @@ Keep the structure stable for the next cycle. Seek implementation evidence for t weakest new claim (unknown-outcome recovery), then an independent comparison of both cases. Rendering/addressing can follow as a bounded new branch after that review; a graph export or broader schema would not resolve the current evidence gaps. + +## Pinned implementation and recovery follow-up — 2026-09-25 + +[Zulip/Element inspection](FrontendRecoveryImplementations.md) adds two partial uses +of unsent-intent preservation and asynchronous message reconciliation. They do not +prove the full approval or offline-note designs. [Review disposition](RecoveryWalkthroughReview.md) +records two rejected model findings and three separate editorial lifecycle corrections. +Q03 still needs complete-pattern evidence; Q04 remains unknown. A completed second-model +response does not satisfy independent empirical review. diff --git a/research/reviews/recovery-review-01/inputs.json b/research/reviews/recovery-review-01/inputs.json new file mode 100644 index 0000000..6043996 --- /dev/null +++ b/research/reviews/recovery-review-01/inputs.json @@ -0,0 +1,8 @@ +{ + "baseline": "96d11431dc929d4cc2e36862a764f02299dc9607", + "inputs": { + "research/walkthroughs/VC01-TransactionalAdministration.md": "bc46e8e8ba660a56e5151efa9a48f3c5cdf27c8cfad86b82d7d01d9eb661ee8b", + "research/walkthroughs/VC02-OfflineFieldNotes.md": "e24c5881a1d3dc878d993a2ca64589124cfad21633c86ccd92da14a1af3a658c" + }, + "prompt_sha256": "84d102beb2ea960d8c3efe894f7b8f77601f26c3b8c2c8ace4638978274633ec" +} diff --git a/research/reviews/recovery-review-01/prompt.md b/research/reviews/recovery-review-01/prompt.md new file mode 100644 index 0000000..9e815d7 --- /dev/null +++ b/research/reviews/recovery-review-01/prompt.md @@ -0,0 +1,235 @@ +Review these two synthetic architecture walkthroughs adversarially. This is a second-model critique, not independent empirical validation. You have no external sources or runtime. Do not invent evidence. Identify up to four concrete internal omissions or inconsistent state transitions, especially stale acknowledgements, operation lifecycle, and retries. Compare the named design with its plain narrative baseline: say unknown if usefulness cannot be established. Give exact section/step locators, a proposed correction, and which assumption makes each finding conditional. Do not use tables. Do not claim admission or tests passed. + +--- research/walkthroughs/VC01-TransactionalAdministration.md --- +# VC-01 — Transactional administration + +Status: synthetic draft, self-reviewed by Codex 2026-09-25. Baseline repository: +`cfa249a`. No application runtime or empirical usability result. Evidence references +T01–T05 resolve in [the source review](../reviews/TransactionalEvidenceExpansion.md). + +## Fixed brief and explicit assumptions + +Shared records, server-validated writes, concurrent edits, deep links, keyboard +operation and recoverable failed requests. Example: edit a shared approval record. +Only server acceptance can change its authoritative approval status. + +Additional design assumptions, not properties proven by the sources: each read has +an opaque version; the server atomically checks version, authorization and business +rules with the write. Each submitted attempt has an operation ID scoped to principal +and record, bound to its payload, with a durable result lookup and deduplication +retention covering the agreed recovery period. A modified proposal gets a new ID. +These backend capabilities must be verified before implementation. T03 motivates +bounded retry identity but does not establish this whole protocol. + +Drafts survive failed requests while the page remains open. Restart survival is not +required by this brief; adding it requires a separate persistence/privacy decision. +Record identity appears in the deep link; version and draft are separate state. +Authorization is checked on every write and on result access. Sensitive draft data +is not placed in URLs. No numerical latency target is assumed. + +## Baseline without pattern labels + +Load a record and its version. Keep edits apart from received data. Submit the edits +with the version they were based on. Keep them if validation fails. If someone else +changed the record, show the current record beside the proposal and ask the user to +review it. If the response disappears, investigate that operation before sending a +new one. Refresh affected views after acceptance without overwriting newer typing. + +## Ordered decisions and resulting contexts + +1. Establish server authority over approved records. Local typing gives feedback but + cannot approve a record. Offline acceptance is outside this case. +2. Use [Local Draft State](../candidates/LocalDraftState.md) to preserve user intent + independently of refreshed observations. This creates a base/draft/current comparison. +3. Use [Version-Checked Mutation](../candidates/VersionCheckedMutation.md) for the + conditional write (T01). Blind overwrite risks lost edits; GitLab's error ambiguity + (T02) demonstrates why adapters must preserve actual endpoint semantics. +4. Use [Mutation Outcome Tracking](../candidates/MutationOutcomeTracking.md) to keep + transport state separate from acceptance. A timeout is unknown, not rejection. + Retry only under the operation contract; a disabled button alone cannot deduplicate. +5. Use [Invalidate and Reproject](../candidates/InvalidateAndReproject.md) to refresh + affected observations after acceptance. Keep drafts intact and reject obsolete + responses. T04 shows why browser cancellation cannot enforce server ordering. +6. Defer optimistic approval display. Immediate input and pending feedback suffice; + T05's optimistic example does not justify claiming approval before validation. + +## Failure and recovery trace + +| Step | Observed state and action | Required invariant | +| --- | --- | --- | +| 1 | A and B read record R at v10; A types draft dA | Typing changes neither server record nor approval | +| 2 | B's valid conditional command commits v11 | Server atomically validates and advances version | +| 3 | A submits operation x against v10; explicit stale-version rejection arrives | dA remains; mark x rejected, not accepted | +| 4 | Read v11; user compares base v10, dA and v11, then proposes dA2 | No blind automatic resend that erases B's intent | +| 5 | Operation y against v11 fails a business rule before commit | Preserve dA2; explain the actual field/domain error | +| 6 | User corrects it; new operation z succeeds at v12 but response is lost | Mark z unknown; do not show approval as confirmed | +| 7 | Lookup z or replay the identical z within the deduplication contract | Resolve its stored result without a second transition | +| 8 | Accepted z identifies v12; refresh detail and relevant list | Acceptance and freshness remain separate facts | +| 9 | A late read of v11 arrives after v12; user has also started another draft | Discard obsolete observation; preserve new draft | + +Opaque versions are compared for equality or through a documented server ordering +contract, never sorted numerically by a generic client. The v10/v11/v12 labels above +are explanatory sequence labels. If another actor changes the record after z, a +read alone cannot establish whether z committed: use operation-specific evidence. +If retention expires before z can be resolved, stop automatic resubmission and show +an unresolved outcome with a reconciliation path. Never infer rejection from a 500, +timeout or browser cancellation alone. If refreshed data cannot be obtained, show +accepted-with-stale-view rather than converting acceptance into a failed mutation. + +Quality acceptance proposals: keyboard access to comparison, correction and retry; +text status that does not rely on color; an announced outcome and an error summary +linked to fields; stable focus when a refresh arrives; no silent draft replacement. +Revoked access yields an authorization outcome and prevents further submissions; +retention/export of sensitive drafts follows the product's explicit access policy. +These are requirements for later implementation review, not accessibility certification. + +## Change exactly one constraint + +Replace concurrent editors with a single authorized writer; all other requirements +remain. The competing-editor branch is omitted. Server validation, draft retention, +unknown-outcome recovery and refresh remain necessary. Multiple in-flight attempts +from that one writer can still race, so version checks are not automatically removed. +This branch weakens one motivation for version checking without erasing transport +uncertainty or turning the application into a local-authoritative editor. + +## Self-review + +| Criterion | Assessment | Reason | +| --- | --- | --- | +| Traceability | pass for reasoning | Each source claim is separated from proposed backend/UI contracts | +| Coherence | revise | Operation lookup, retention and atomic validation still need implementation evidence | +| Decision usefulness | unknown | Labels organize obligations; baseline reaches the same design; no independent comparison | +| Quality coverage | revise | Keyboard/privacy criteria specified but not exercised | +| Changed constraint | pass for reasoning | One writer removes cross-user conflict while preserving other failures | + +Next: inspect real frontend recovery implementations and review this case alongside +[VC-02](VC02-OfflineFieldNotes.md). No canonical admission or M1 completion follows +from completing a synthetic narrative. + +--- research/walkthroughs/VC02-OfflineFieldNotes.md --- +# 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 and unresolved marker | 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; retain recovery 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. diff --git a/research/reviews/recovery-review-01/receipt.json b/research/reviews/recovery-review-01/receipt.json new file mode 100644 index 0000000..27e4585 --- /dev/null +++ b/research/reviews/recovery-review-01/receipt.json @@ -0,0 +1,56 @@ +{ + "kind": "second-model-walkthrough-critique", + "empirical_validation": false, + "service_requests_attempted": 1, + "endpoint": "http://127.0.0.1:18081", + "config": { + "model_name": "custodian-triage-balanced", + "temperature": 0.2, + "max_tokens": 2500, + "model_params": {}, + "max_depth": 3, + "skip_if_exists": true, + "timeout_seconds": 300 + }, + "adapter_sha256": "1dade65e456ab7b85d17c2c4c9a6e9ecef245104177a8cad815a685d2c7cf427", + "status": "failed", + "error_type": "ValueError", + "responses": [ + { + "stage": "walkthrough-review", + "model": "google/gemini-2.5-flash", + "usage": { + "prompt_tokens": 3646, + "completion_tokens": 2500, + "total_tokens": 6146 + }, + "finish_reason": "length", + "provider": "openrouter", + "response_id": "gen-1790325508-sl1YfS0T5xCXJ2SjGhjM", + "latency_seconds": 15.14, + "profile": "custodian-triage-balanced", + "profile_model": "google/gemini-2.5-flash", + "profile_provider": "openrouter", + "diagnostics": { + "available": true, + "effective_settings": { + "temperature": 0.2, + "max_tokens": 2500, + "reasoning_effort_present": false, + "reasoning_present": false + }, + "provider_usage": { + "prompt_tokens": 3646, + "completion_tokens": 2500, + "total_tokens": 6146, + "cost": 0.0073438, + "completion_tokens_details": { + "reasoning_tokens": 0 + } + } + }, + "content_characters": 11015, + "content_sha256": "db53f22493233903d65bc42663354e87bd3b8e2fcfe880d706014c43ffb793d0" + } + ] +} diff --git a/research/reviews/recovery-review-01/rejected-response.md b/research/reviews/recovery-review-01/rejected-response.md new file mode 100644 index 0000000..603ad7c --- /dev/null +++ b/research/reviews/recovery-review-01/rejected-response.md @@ -0,0 +1,56 @@ +Here's an adversarial review of the two synthetic architecture walkthroughs, focusing on internal omissions, inconsistent state transitions, stale acknowledgements, operation lifecycle, and retries. + +--- + +## Review of VC-01 — Transactional administration + +**Overall Assessment:** The document clearly articulates a complex problem space and attempts to map it to named patterns. However, it struggles with the practical implications of operation lifecycle and the precise state transitions, particularly around acknowledgements and retries. The "unknown" usefulness of named patterns compared to the baseline is a significant self-critique. + +### Internal Omissions/Inconsistent State Transitions: + +1. **Stale Acknowledgement/Operation Lifecycle Inconsistency (Step 6 & 7):** + * **Locator:** "Step 6: User corrects it; new operation z succeeds at v12 but response is lost" and "Step 7: Lookup z or replay the identical z within the deduplication contract". + * **Omission/Inconsistency:** Step 6 states `z succeeds at v12` but `response is lost`. Step 7 then suggests `Lookup z or replay the identical z`. If `z succeeds at v12`, the server has already processed and committed the change. A "replay" of an *identical* `z` (implying the same operation ID and payload) should be deduplicated by the server, not re-executed. The narrative implies the client *doesn't know* if it succeeded, which contradicts "succeeds at v12". The state `Mark z unknown; do not show approval as confirmed` is correct for the client's perspective, but the server's state is definitively "succeeded". The transition from client `unknown` to server `succeeded` is not fully reconciled with the client's subsequent actions. The "replay" option is problematic if the server already committed. + * **Proposed Correction:** Step 6 should state "new operation z is sent against v12, but its response is lost, leaving the client's state for z as unknown." Step 7 should then clarify: "Client attempts to resolve the unknown state of z by querying its status (lookup) or, if lookup is unavailable/unsuccessful, resending the *same operation ID and payload* (replay), relying on server-side deduplication." This clarifies the client's uncertainty and the server's idempotent handling. + * **Conditional Assumption:** This finding is conditional on the "deduplication contract" (mentioned in the "Additional design assumptions") being robust and preventing re-execution of already successful operations. If "replay" implies a *new* operation ID for the same logical intent, then the "identical z" phrasing is misleading. + +2. **Stale Acknowledgement/Operation Lifecycle Inconsistency (Step 8 & 9):** + * **Locator:** "Step 8: Accepted z identifies v12; refresh detail and relevant list" and "Step 9: A late read of v11 arrives after v12; user has also started another draft". + * **Omission/Inconsistency:** Step 8 states `Accepted z identifies v12`. This implies the client has now confirmed `z`'s success and the record is at `v12`. Step 9 then describes `A late read of v11 arrives after v12`. This is a stale read. While the `Required invariant` correctly states `Discard obsolete observation; preserve new draft`, the walkthrough doesn't explicitly state *how* the client determines `v11` is obsolete relative to `v12` *after* `z` has been accepted. The "opaque versions are compared for equality or through a documented server ordering contract" is mentioned in the prose, but the trace doesn't show this comparison happening or the mechanism for it. The client's state after step 8 should include knowledge of `v12` as the current authoritative version. + * **Proposed Correction:** After Step 8, explicitly state that the client updates its known authoritative version to `v12`. In Step 9, the `Required invariant` should be expanded to: "Discard obsolete observation (v11 is older than known authoritative v12); preserve new draft." This makes the comparison explicit within the trace. + * **Conditional Assumption:** This finding is conditional on the client reliably tracking the *latest known authoritative version* of the record, not just the version it last successfully wrote against. + +3. **Operation Lifecycle/Retries (Implicit in "Change exactly one constraint" section):** + * **Locator:** "Change exactly one constraint" section, specifically "Multiple in-flight attempts from that one writer can still race, so version checks are not automatically removed." + * **Omission/Inconsistency:** The document correctly identifies that even with a single writer, multiple in-flight attempts can race. However, the initial "Baseline without pattern labels" and "Ordered decisions" sections, particularly "Mutation Outcome Tracking," don't fully elaborate on the client-side handling of *multiple in-flight operations from the same user on the same record*. If a user rapidly clicks "save" multiple times, or a retry mechanism is aggressive, how does the client manage the operation IDs and potential race conditions between its *own* operations? The trace focuses on *different* users or *lost responses* for a single operation. + * **Proposed Correction:** Add a step to the "Failure and recovery trace" or a specific note in "Mutation Outcome Tracking" addressing the scenario of a single user initiating multiple distinct (or logically identical but separately submitted) operations on the same record before the first one resolves. This would clarify how operation IDs are generated/managed in this scenario and how the client prevents its own operations from racing or overwriting each other's pending state. + * **Conditional Assumption:** This finding is conditional on the application allowing multiple concurrent submissions from a single user for the same record (e.g., rapid clicks, or background retries of different logical operations). If the UI strictly serializes all user-initiated operations, this is less critical. + +### Named Design vs. Plain Narrative Baseline: + +* **Decision usefulness:** The self-review states "unknown" for "Decision usefulness" because "Labels organize obligations; baseline reaches the same design; no independent comparison." This is a fair assessment. The named patterns (Local Draft State, Version-Checked Mutation, Mutation Outcome Tracking, Invalidate and Reproject, Defer optimistic approval display) *do* provide a structured vocabulary for discussing the design elements. However, the walkthrough itself doesn't demonstrate a scenario where the named patterns *clarify* or *prevent* an issue that the baseline narrative would miss. They primarily serve as organizational labels for concepts already present in the baseline. Their utility for *improving* the design or *identifying gaps* beyond what a careful reading of the baseline would achieve is not established within this document. + +--- + +## Review of VC-02 — Offline field notes, restart and reconnect + +**Overall Assessment:** This walkthrough is more detailed in its state transitions and explicitly addresses restart scenarios, which is a strength. However, it still exhibits some ambiguity around the precise lifecycle of operations and the client's knowledge state, particularly concerning acknowledgements and the "deduplication contract." + +### Internal Omissions/Inconsistent State Transitions: + +1. **Operation Lifecycle/Acknowledgement Inconsistency (Step 2 & 3):** + * **Locator:** "Step 2: A commits a1 + operation opA atomically" and "Step 3: A restarts while offline". + * **Omission/Inconsistency:** Step 2 states "A commits a1 + operation opA atomically" and the invariant is "Saved on this device; not yet synchronized." Step 3 states "Reconstruct a1 and opA from storage." This implies `opA` is a *pending* operation. However, the term "operation opA atomically" could be interpreted as `opA` being the *result* of the commit, or the *intent* to sync. If `opA` is merely the *intent* to sync `a1`, then it's clear. But if `opA` is meant to be the *specific operation ID* that will be sent to the server, then the client is generating this ID *before* network interaction. This is fine, but the lifecycle of `opA` as a pending item needs to be clearer. Is `opA` the *request* or the *record of the request*? + * **Proposed Correction:** Clarify that `opA` refers to the *record of the pending synchronization request* for `a1`, which includes a unique operation ID generated locally. This makes its reconstruction in Step 3 more explicit as a pending task. + * **Conditional Assumption:** This finding is conditional on the interpretation of "operation opA" as the specific network request rather than a general concept of "an operation." The "Pending Synchronization" candidate implies it's a durable record of the intent. + +2. **Stale Acknowledgement/Operation Lifecycle (Step 9 & 10):** + * **Locator:** "Step 9: Receiver accepts opC, response is lost" and "Step 10: A retries opC". + * **Omission/Inconsistency:** Similar to VC-01, Step 9 states "Receiver accepts opC" but "response is lost." The client's state is `A still has pending opC`. Step 10 then says "A retries opC." If the receiver *accepted* `opC`, then `opC` has already been processed and committed on the server. A "retry" of `opC` (implying the same operation ID) should be deduplicated. The trace correctly states "Receiver deduplicates and confirms c1," but the client's action of "retries opC" is slightly ambiguous. It should be "A attempts to resolve the status of opC (e.g., by re-sending the same operation ID or querying its status)." The current phrasing could imply a new execution attempt if not for the deduplication. + * **Proposed Correction:** In Step 10, rephrase "A retries opC" to "A attempts to resolve the status of opC (e.g., by re-sending the identical opC with its original ID, relying on deduplication)." This reinforces the idempotent nature of the operation and the client's uncertainty. + * **Conditional Assumption:** This finding is conditional on the "deduplication contract" (mentioned in the "Fixed brief and assumptions") being robust and preventing re-execution of already successful operations. + +3. **Inconsistent State Transition/Operation Lifecycle (Conflict Resolution):** + * **Locator:** "Step 6: A preserves a1 and selects b1 as active" and "Step 8: User reconciles to c1". + * **Omission/Inconsistency:** In Step 6, `A preserves a1 and selects b1 as active`. The invariant is `Conflict needs review; remote selection does not establish remote semantic authority`. This implies `b1` is now the *working copy* for the user, but `a1` is preserved as a conflict. Step 8 states `User reconciles to c1`. This implies the user *edited* `b1` (or `a1` or both) to produce `c1`. However, the trace doesn't explicitly show the state transition from `b1` being active to `c1` being the result of a user edit. It jumps from `b1` being active to `c1` being committed. + * **Proposed Correction:** Insert an intermediate \ No newline at end of file diff --git a/research/reviews/recovery-review-02/inputs.json b/research/reviews/recovery-review-02/inputs.json new file mode 100644 index 0000000..4cb4306 --- /dev/null +++ b/research/reviews/recovery-review-02/inputs.json @@ -0,0 +1,8 @@ +{ + "baseline": "96d11431dc929d4cc2e36862a764f02299dc9607", + "inputs": { + "research/walkthroughs/VC01-TransactionalAdministration.md": "bc46e8e8ba660a56e5151efa9a48f3c5cdf27c8cfad86b82d7d01d9eb661ee8b", + "research/walkthroughs/VC02-OfflineFieldNotes.md": "e24c5881a1d3dc878d993a2ca64589124cfad21633c86ccd92da14a1af3a658c" + }, + "prompt_sha256": "bf3cff209bc49e318e63c532ed2c0eee7bc185c9294ae7075f4ac5e47dbe8da7" +} diff --git a/research/reviews/recovery-review-02/prompt.md b/research/reviews/recovery-review-02/prompt.md new file mode 100644 index 0000000..b699616 --- /dev/null +++ b/research/reviews/recovery-review-02/prompt.md @@ -0,0 +1,236 @@ +STRICT OUTPUT BOUND: at most 400 words total; at most TWO findings across BOTH cases combined. Do not repeat the walkthrough. State locator, concrete defect, minimal fix. A trace may describe server truth unknown to the client; that is not a contradiction. Reusing an operation identity under the stated deduplication contract is intentional. Do not propose numeric ordering for opaque versions. End with one sentence about baseline usefulness. +Review these two synthetic architecture walkthroughs adversarially. This is a second-model critique, not independent empirical validation. You have no external sources or runtime. Do not invent evidence. Identify up to four concrete internal omissions or inconsistent state transitions, especially stale acknowledgements, operation lifecycle, and retries. Compare the named design with its plain narrative baseline: say unknown if usefulness cannot be established. Give exact section/step locators, a proposed correction, and which assumption makes each finding conditional. Do not use tables. Do not claim admission or tests passed. + +--- research/walkthroughs/VC01-TransactionalAdministration.md --- +# VC-01 — Transactional administration + +Status: synthetic draft, self-reviewed by Codex 2026-09-25. Baseline repository: +`cfa249a`. No application runtime or empirical usability result. Evidence references +T01–T05 resolve in [the source review](../reviews/TransactionalEvidenceExpansion.md). + +## Fixed brief and explicit assumptions + +Shared records, server-validated writes, concurrent edits, deep links, keyboard +operation and recoverable failed requests. Example: edit a shared approval record. +Only server acceptance can change its authoritative approval status. + +Additional design assumptions, not properties proven by the sources: each read has +an opaque version; the server atomically checks version, authorization and business +rules with the write. Each submitted attempt has an operation ID scoped to principal +and record, bound to its payload, with a durable result lookup and deduplication +retention covering the agreed recovery period. A modified proposal gets a new ID. +These backend capabilities must be verified before implementation. T03 motivates +bounded retry identity but does not establish this whole protocol. + +Drafts survive failed requests while the page remains open. Restart survival is not +required by this brief; adding it requires a separate persistence/privacy decision. +Record identity appears in the deep link; version and draft are separate state. +Authorization is checked on every write and on result access. Sensitive draft data +is not placed in URLs. No numerical latency target is assumed. + +## Baseline without pattern labels + +Load a record and its version. Keep edits apart from received data. Submit the edits +with the version they were based on. Keep them if validation fails. If someone else +changed the record, show the current record beside the proposal and ask the user to +review it. If the response disappears, investigate that operation before sending a +new one. Refresh affected views after acceptance without overwriting newer typing. + +## Ordered decisions and resulting contexts + +1. Establish server authority over approved records. Local typing gives feedback but + cannot approve a record. Offline acceptance is outside this case. +2. Use [Local Draft State](../candidates/LocalDraftState.md) to preserve user intent + independently of refreshed observations. This creates a base/draft/current comparison. +3. Use [Version-Checked Mutation](../candidates/VersionCheckedMutation.md) for the + conditional write (T01). Blind overwrite risks lost edits; GitLab's error ambiguity + (T02) demonstrates why adapters must preserve actual endpoint semantics. +4. Use [Mutation Outcome Tracking](../candidates/MutationOutcomeTracking.md) to keep + transport state separate from acceptance. A timeout is unknown, not rejection. + Retry only under the operation contract; a disabled button alone cannot deduplicate. +5. Use [Invalidate and Reproject](../candidates/InvalidateAndReproject.md) to refresh + affected observations after acceptance. Keep drafts intact and reject obsolete + responses. T04 shows why browser cancellation cannot enforce server ordering. +6. Defer optimistic approval display. Immediate input and pending feedback suffice; + T05's optimistic example does not justify claiming approval before validation. + +## Failure and recovery trace + +| Step | Observed state and action | Required invariant | +| --- | --- | --- | +| 1 | A and B read record R at v10; A types draft dA | Typing changes neither server record nor approval | +| 2 | B's valid conditional command commits v11 | Server atomically validates and advances version | +| 3 | A submits operation x against v10; explicit stale-version rejection arrives | dA remains; mark x rejected, not accepted | +| 4 | Read v11; user compares base v10, dA and v11, then proposes dA2 | No blind automatic resend that erases B's intent | +| 5 | Operation y against v11 fails a business rule before commit | Preserve dA2; explain the actual field/domain error | +| 6 | User corrects it; new operation z succeeds at v12 but response is lost | Mark z unknown; do not show approval as confirmed | +| 7 | Lookup z or replay the identical z within the deduplication contract | Resolve its stored result without a second transition | +| 8 | Accepted z identifies v12; refresh detail and relevant list | Acceptance and freshness remain separate facts | +| 9 | A late read of v11 arrives after v12; user has also started another draft | Discard obsolete observation; preserve new draft | + +Opaque versions are compared for equality or through a documented server ordering +contract, never sorted numerically by a generic client. The v10/v11/v12 labels above +are explanatory sequence labels. If another actor changes the record after z, a +read alone cannot establish whether z committed: use operation-specific evidence. +If retention expires before z can be resolved, stop automatic resubmission and show +an unresolved outcome with a reconciliation path. Never infer rejection from a 500, +timeout or browser cancellation alone. If refreshed data cannot be obtained, show +accepted-with-stale-view rather than converting acceptance into a failed mutation. + +Quality acceptance proposals: keyboard access to comparison, correction and retry; +text status that does not rely on color; an announced outcome and an error summary +linked to fields; stable focus when a refresh arrives; no silent draft replacement. +Revoked access yields an authorization outcome and prevents further submissions; +retention/export of sensitive drafts follows the product's explicit access policy. +These are requirements for later implementation review, not accessibility certification. + +## Change exactly one constraint + +Replace concurrent editors with a single authorized writer; all other requirements +remain. The competing-editor branch is omitted. Server validation, draft retention, +unknown-outcome recovery and refresh remain necessary. Multiple in-flight attempts +from that one writer can still race, so version checks are not automatically removed. +This branch weakens one motivation for version checking without erasing transport +uncertainty or turning the application into a local-authoritative editor. + +## Self-review + +| Criterion | Assessment | Reason | +| --- | --- | --- | +| Traceability | pass for reasoning | Each source claim is separated from proposed backend/UI contracts | +| Coherence | revise | Operation lookup, retention and atomic validation still need implementation evidence | +| Decision usefulness | unknown | Labels organize obligations; baseline reaches the same design; no independent comparison | +| Quality coverage | revise | Keyboard/privacy criteria specified but not exercised | +| Changed constraint | pass for reasoning | One writer removes cross-user conflict while preserving other failures | + +Next: inspect real frontend recovery implementations and review this case alongside +[VC-02](VC02-OfflineFieldNotes.md). No canonical admission or M1 completion follows +from completing a synthetic narrative. + +--- research/walkthroughs/VC02-OfflineFieldNotes.md --- +# 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 and unresolved marker | 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; retain recovery 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. diff --git a/research/reviews/recovery-review-02/receipt.json b/research/reviews/recovery-review-02/receipt.json new file mode 100644 index 0000000..ba23d32 --- /dev/null +++ b/research/reviews/recovery-review-02/receipt.json @@ -0,0 +1,56 @@ +{ + "kind": "second-model-walkthrough-critique", + "empirical_validation": false, + "service_requests_attempted": 1, + "endpoint": "http://127.0.0.1:18081", + "config": { + "model_name": "custodian-triage-balanced", + "temperature": 0.2, + "max_tokens": 1800, + "model_params": {}, + "max_depth": 3, + "skip_if_exists": true, + "timeout_seconds": 300 + }, + "retry_reason": "First response exceeded 2500 tokens; new prompt bounds total response to 400 words and two findings.", + "adapter_sha256": "1dade65e456ab7b85d17c2c4c9a6e9ecef245104177a8cad815a685d2c7cf427", + "status": "completed", + "responses": [ + { + "stage": "walkthrough-review", + "model": "google/gemini-2.5-flash", + "usage": { + "prompt_tokens": 3733, + "completion_tokens": 726, + "total_tokens": 4459 + }, + "finish_reason": "stop", + "provider": "openrouter", + "response_id": "gen-1790325609-YssyF5LCyv0oWTGYxJ1h", + "latency_seconds": 4.809, + "profile": "custodian-triage-balanced", + "profile_model": "google/gemini-2.5-flash", + "profile_provider": "openrouter", + "diagnostics": { + "available": true, + "effective_settings": { + "temperature": 0.2, + "max_tokens": 1800, + "reasoning_effort_present": false, + "reasoning_present": false + }, + "provider_usage": { + "prompt_tokens": 3733, + "completion_tokens": 726, + "total_tokens": 4459, + "cost": 0.0029349, + "completion_tokens_details": { + "reasoning_tokens": 0 + } + } + }, + "content_characters": 3201, + "content_sha256": "7504f2b343f327f94e155124f35ada16ab39fdfaa54a100c21215a46ed1d8382" + } + ] +} diff --git a/research/reviews/recovery-review-02/response.md b/research/reviews/recovery-review-02/response.md new file mode 100644 index 0000000..2061afb --- /dev/null +++ b/research/reviews/recovery-review-02/response.md @@ -0,0 +1,17 @@ +**Case VC01: Transactional Administration** + +* **Finding 1: Stale Acknowledgement Handling** + * **Locator:** "Failure and recovery trace", Step 9. + * **Concrete Defect:** The trace states "A late read of v11 arrives after v12; user has also started another draft. Discard obsolete observation; preserve new draft." This implies the client discards the v11 read. However, the "Required invariant" for Step 8 states "Acceptance and freshness remain separate facts." If the client discards v11, it loses the opportunity to confirm that v11 was indeed superseded by v12, which is crucial for maintaining the separation of acceptance and freshness. The client should process the v11 read to confirm its state, even if it's older, rather than discarding it. + * **Minimal Fix:** In Step 9, change "Discard obsolete observation" to "Process obsolete observation to confirm its state, then update local freshness markers." + * **Conditionality:** This finding is conditional on the interpretation that "discard" means completely ignore, rather than process and then not display. + +**Case VC02: Offline Field Notes** + +* **Finding 1: Operation Lifecycle and Deduplication** + * **Locator:** "Restart/reconnect trace", Step 9 and 10. + * **Concrete Defect:** Step 9 states "Receiver accepts opC, response is lost. c1 may be stored remotely; A still has pending opC." Step 10 states "A retries opC. Receiver deduplicates and confirms c1; A stores receipt." The narrative implies that "opC" is the *same* operation identity being retried. However, the "Fixed brief and assumptions" section states "Stable document and operation identities plus revision ancestry detect divergent changes." and "The sync receiver deduplicates operation IDs and acknowledges a specific revision." The "Additional design assumptions" in VC01 states "A modified proposal gets a new ID." If "opC" represents a *proposal* (which it does, as it's a reconciliation), and the response is lost, retrying it should ideally generate a *new* operation ID if any aspect of the proposal (even implicitly, like a timestamp) could have changed, to avoid ambiguity if the original opC was partially processed or if the client's state changed between attempts. Reusing the *exact* same `opC` identity for a retry, especially when the client's internal state might have evolved, could lead to subtle issues if the server's deduplication logic is not robust enough to handle potential client-side state changes between retries of the "same" logical operation. + * **Minimal Fix:** In Step 10, clarify that "A retries opC" means "A retries the *logical intent* of opC, generating a new operation ID (e.g., opC') if any aspect of the proposal has changed, or reusing opC if the proposal is strictly identical." + * **Conditionality:** This finding is conditional on the strict interpretation of "A modified proposal gets a new ID" from VC01 applying to all proposals, including retries of previously submitted ones, and the potential for client-side state changes between a lost response and a retry. + +The baseline usefulness is unknown for both cases as no independent comparison or empirical validation is provided. \ No newline at end of file diff --git a/research/walkthroughs/VC01-TransactionalAdministration.md b/research/walkthroughs/VC01-TransactionalAdministration.md index 1ad6f40..2cb60e9 100644 --- a/research/walkthroughs/VC01-TransactionalAdministration.md +++ b/research/walkthroughs/VC01-TransactionalAdministration.md @@ -102,3 +102,23 @@ uncertainty or turning the application into a local-authoritative editor. Next: inspect real frontend recovery implementations and review this case alongside [VC-02](VC02-OfflineFieldNotes.md). No canonical admission or M1 completion follows from completing a synthetic narrative. + +## Recovery lifecycle clarification — 2026-09-25 + +Retain the submitted payload in an operation record before clearing or reusing the +composer. This is a logical handoff in this page-session design, not a durability +claim. R01–R05 in the [implementation review](../reviews/FrontendRecoveryImplementations.md) +show why recoverable intent need not stay in the original input box. + +For step 9, tag reads with a local request generation. Confirming z advances the +generation and invalidates outstanding reads issued before that acceptance. Such an +old response cannot replace the current observation. A post-acceptance read must +meet a documented read-after-write consistency contract (or provide a comparable +server revision); request generation alone cannot repair stale replicas. Unequal +opaque versions do not reveal which is newer. Without that server contract, show +freshness as unresolved. Preserve newer typing independently of read generations. + +Correlate every acknowledgement, server event and error to its original operation. +Once authoritative evidence confirms z, a late transport error cannot regress it to +unknown; a receipt for z cannot clear a new draft or mark a later operation accepted. +A status label such as failed_request is not itself rejection evidence. diff --git a/research/walkthroughs/VC02-OfflineFieldNotes.md b/research/walkthroughs/VC02-OfflineFieldNotes.md index 057645d..cc1b32d 100644 --- a/research/walkthroughs/VC02-OfflineFieldNotes.md +++ b/research/walkthroughs/VC02-OfflineFieldNotes.md @@ -61,9 +61,9 @@ ordering: quality/recovery requirements influence step 1, not only step 5. | 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 and unresolved marker | Conflict needs review; remote selection does not establish remote semantic authority | +| 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; retain recovery history | Resolved locally; synchronization still pending | +| 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 | @@ -124,3 +124,18 @@ justify separate retrieval/use. This is development evidence, not a held-out eva 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. diff --git a/workplans/FEP-WP-0002-seed-language-validation.md b/workplans/FEP-WP-0002-seed-language-validation.md index 5696445..e5b5c4f 100644 --- a/workplans/FEP-WP-0002-seed-language-validation.md +++ b/workplans/FEP-WP-0002-seed-language-validation.md @@ -240,3 +240,23 @@ draft retention and unknown-outcome recovery at exact revisions. Under T03: obta independent review of both cases and their baselines. Existing offline atomicity, receiver ancestry/retry and accessible reconciliation evidence gaps remain active. Evidence: research/reviews/TransactionalEvidenceExpansion.md. + +## Pinned frontend recovery evidence — 2026-09-25 + +T02: inspected Zulip and Element at exact commits, with a separately pinned Matrix +SDK and Matrix v1.15 protocol reference (SRC-0013–0016). File hashes/locators retained. +Two partial uses support draft/intent separation; full-pattern recurrence and runtime +correctness remain unknown. Element/SDK count as one implementation family; deployed +dependency pairing is not verified. No new patterns or canonical admission. + +T03: reviewed frozen VC-01/VC-02 through llm-connect. First response truncated and was +quarantined; one shorter follow-up completed. Two calls, 10,605 reported tokens. +Both model fixes rejected editorially. Separately corrected opA blocking/supersession, +read-generation/consistency assumptions and late receipt/error handling. Independent +human review and baseline usefulness remain open; M1 is not complete. + +Next bounded work: T02 pin an actual client/SDK/server pairing and exercise lost +response/delayed echo recovery; retain existing offline crash/ancestry/accessibility +gaps. T03 prepare a blinded matched comparison using unseen variants and independent +review. See research/reviews/FrontendRecoveryImplementations.md and +research/reviews/RecoveryWalkthroughReview.md. T02/T03 remain progress.