Skip to content

[P1][Storage][UX] stale revisionを拒否するmutation receiptとoptimistic concurrencyを実装する #122

Description

@tuzuminami

背景

#117 のatomic commitで「失敗時にphantom stateを出さない」契約を整える一方、同じ旧画面から送られた複数の編集・import・deleteは現在last-writer-winsになる。StoreSnapshot.generationは内部にあるだけで、APIのread response・mutation request・success responseへ出ていない。

これは非エンジニアが画面を複数開いた場合、または応答喪失後にretryした場合に、意図しない上書き・重複auditを起こす。#120 のundo/redoとは別に、write時点でstale stateを拒否する必要がある。

目的

全てのstate mutationにrevision/operation receiptを導入し、古いrevisionを明示的な409として拒否する。正常retryは同じoperation receiptを返し、event・import history・audit logを重複させない。

対象

  • EventStoreのmonotonic revisionとsuccess receipt
  • read payload(snapshot、event page、settings、import history、diagnostics)へのrevision露出
  • label/review/edit/exclude/split/merge/settings/clear/import/recording finalization/deleteのexpected_revision
  • FastAPI、handwritten local API、desktop WebUIの409 stale_revision 表示と再読込導線
  • request/operation idempotency keyとSQLite上のdurable operation ledger
  • retry、同時writer、response-loss、restart後retryのtest matrix

非対象

Claude Code実装契約

  1. StoreSnapshot.generationを永続revisionとして扱う。process restart後に0へ戻らないようSQLite transaction内で更新する。
  2. mutation requestはexpected_revisionとclient generated operation_idを必須にする。recording agentの内部retryはsession/sequenceから安定したoperation idを作る。
  3. EventStoreはlock内でexpected revisionを照合する。異なる場合はDB/memoryを一切変更せず、stable stale_revision errorを返す。
  4. operation ledgerはmutation payload fingerprint・revision・success receiptを同じSQLite transactionで保存する。同じoperation idかつ同一payloadのretryは保存済みreceiptを返し、異なるpayloadならstable conflictにする。
  5. success responseにはrevisionoperation_id、必要なresource idを含める。409/503ではraw exception、absolute path、PIIを返さない。
  6. WebUIは409時に「他の変更を検出した。最新状態を読み直してからやり直す」と表示し、入力を勝手に再送しない。
  7. compatibilityを壊す変更はAPI/schema versionとdocsへ明記し、FastAPI/handwritten serverで同一contractを保つ。

受け入れ条件

  • 同じold revisionから送られた2編集は先行1件だけ成功し、後続は409 stale_revision。DB、memory、再起動後stateが一致する。
  • import/clear/delete/recording finalizationを含む全mutationで、operation retryはevent/import history/auditを重複させず同じreceiptを返す。
  • response-loss後、process restart後、concurrent writer、WAL reader下のproperty testがpassする。
  • FastAPI、handwritten local API、desktop WebUIのエラー契約と翻訳が一致する。
  • ./scripts/test.sh./scripts/lint.sh./scripts/check_licenses.sh./scripts/check_no_external_network.sh がpassする。

依存関係

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:qualityTests, CI, performance, and release gatesarea:storagePersistence, migration, backup, and recoveryarea:uxNon-engineer user experiencepriority:P1Required for v1.0 qualityrelease:v1.0Targeted for OpsMineFlow v1.0.0

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions