[h1-request] 同期v2: 合議(伝票の競合解決)と訂正提案 #55

Open
opened 2026-10-09 19:56:39 +00:00 by joe · 1 comment
Owner

背景

v1 は競合を LWW で自動決着し、修正はフィールド単位で確定伝票を上書きする。伝票の競合は人が判断する(合議)、確定(発行ロック)済み伝票の訂正は赤黒のみ、と決定した。

依頼内容(ADR-0002 §7・§5 の行き違い規則)

  • SyncConflict(tenant, entity_type, uuid, base_rev, candidates[], status)
  • POST /api/sync/v2/conflicts/{id}/resolve(take_local|take_remote|edited+バンドル)。先に解決した側が有効、後着は already_resolved
  • pull に conflict_opened / conflict_resolved(採用版+新 rev)
  • o2 Web UI: 競合一覧・ヘッダ/明細の差分表示・解決操作(弥生風 UI 基盤に従う)
  • 合議中の伝票は発行ロック不可
  • ロック vs 編集の行き違い: h1 のロック版が古い base_rev で届いたらロック版を accepted とし、ロック前に入っていた o2 側の編集を correction_proposal として h1 へ配信(h1 は承認時に赤黒伝票を発行。フィールド上書きはしない)

受け入れ条件

  • 競合の開始→h1 側解決/o2 側解決/同時解決(後着 already_resolved)のテストと fixture
  • 行き違い時に訂正提案が生成されるテスト
  • UI から解決でき、結果が pull で配信される

契約の正本: ADR-0002(ブランチ docs/adr-0002-offline-first-sync-v2。未マージなら先に main へマージしてから着手)
https://git.cyberius.biz/joe/o2/src/branch/docs/adr-0002-offline-first-sync-v2/docs/adr/0002-offline-first-sync-v2.md

h1 側の内部設計(参考): https://git.cyberius.biz/joe/h1-c2/src/branch/main/docs/superpowers/specs/2026-10-09-offline-first-sync-design.md

前提: h1 は本体単体で完全稼働し、o2 接続時のみ同期する。v1(/api/sync/push|pull・/api/sync/corrections*)は h1 の移行完了まで並行稼働を維持すること(v1 を壊さない)。
検証データ: 入出力例を tests/fixtures/sync_v2/*.json に追加する。h1 は同じ fixture を Dart テストで検証する(sales_calculation fixture と同じ運用)。

## 背景 v1 は競合を LWW で自動決着し、修正はフィールド単位で確定伝票を上書きする。伝票の競合は人が判断する(合議)、確定(発行ロック)済み伝票の訂正は赤黒のみ、と決定した。 ## 依頼内容(ADR-0002 §7・§5 の行き違い規則) - `SyncConflict(tenant, entity_type, uuid, base_rev, candidates[], status)` - `POST /api/sync/v2/conflicts/{id}/resolve`(`take_local|take_remote|edited`+バンドル)。**先に解決した側が有効**、後着は `already_resolved` - pull に `conflict_opened` / `conflict_resolved`(採用版+新 rev) - o2 Web UI: 競合一覧・ヘッダ/明細の差分表示・解決操作(弥生風 UI 基盤に従う) - 合議中の伝票は発行ロック不可 - ロック vs 編集の行き違い: h1 のロック版が古い base_rev で届いたらロック版を accepted とし、ロック前に入っていた o2 側の編集を `correction_proposal` として h1 へ配信(h1 は承認時に赤黒伝票を発行。フィールド上書きはしない) ## 受け入れ条件 - [ ] 競合の開始→h1 側解決/o2 側解決/同時解決(後着 `already_resolved`)のテストと fixture - [ ] 行き違い時に訂正提案が生成されるテスト - [ ] UI から解決でき、結果が pull で配信される --- **契約の正本**: ADR-0002(ブランチ `docs/adr-0002-offline-first-sync-v2`。未マージなら先に main へマージしてから着手) https://git.cyberius.biz/joe/o2/src/branch/docs/adr-0002-offline-first-sync-v2/docs/adr/0002-offline-first-sync-v2.md **h1 側の内部設計**(参考): https://git.cyberius.biz/joe/h1-c2/src/branch/main/docs/superpowers/specs/2026-10-09-offline-first-sync-design.md **前提**: h1 は本体単体で完全稼働し、o2 接続時のみ同期する。v1(`/api/sync/push|pull`・`/api/sync/corrections*`)は h1 の移行完了まで**並行稼働を維持**すること(v1 を壊さない)。 **検証データ**: 入出力例を `tests/fixtures/sync_v2/*.json` に追加する。h1 は同じ fixture を Dart テストで検証する(`sales_calculation` fixture と同じ運用)。
Author
Owner

実装完了(o2側)— 合議(伝票の競合解決)と訂正提案

実装

  • SyncConflict に解決列(resolution/resolved_rev/resolved_by_device_id)
  • POST /api/sync/v2/conflicts/{id}/resolve(take_local/take_remote/edited、先着有効・既解決は already_resolved)。採用版を新 rev で確定
  • 競合開始で conflict_opened、解決で conflict_resolved を SyncV2Event に積み pull 配信
  • 合議中(open 競合)は発行ロック(false→true)を拒否
  • ロック vs 編集の訂正提案: h1 のロック版が古い base_rev で届いたらロック版を accepted とし、ロック前の o2 編集を correction_proposal として h1 へ配信(フィールド上書きしない/赤黒前提)
  • Web UI /sync-conflicts(競合一覧・差分表示・解決)
  • migration f7a8b9c0d1e2、fixtures(conflict_resolve / correction_proposal)

インフラ注意: 現在リモートへの git push が SSH タイムアウト(www.cyberius.biz:18)で失敗中。実装はローカル main にマージ済み・o2.db 適用済みで、push は回復後に実施します。回帰確認: 全 6422 passed, 1 skipped。

## 実装完了(o2側)— 合議(伝票の競合解決)と訂正提案 ### 実装 - `SyncConflict` に解決列(`resolution`/`resolved_rev`/`resolved_by_device_id`) - `POST /api/sync/v2/conflicts/{id}/resolve`(`take_local`/`take_remote`/`edited`、**先着有効**・既解決は `already_resolved`)。採用版を新 rev で確定 - 競合開始で `conflict_opened`、解決で `conflict_resolved` を `SyncV2Event` に積み pull 配信 - **合議中(open 競合)は発行ロック(`false→true`)を拒否** - **ロック vs 編集の訂正提案**: h1 のロック版が古い `base_rev` で届いたらロック版を accepted とし、ロック前の o2 編集を `correction_proposal` として h1 へ配信(フィールド上書きしない/赤黒前提) - Web UI `/sync-conflicts`(競合一覧・差分表示・解決) - migration `f7a8b9c0d1e2`、fixtures(conflict_resolve / correction_proposal) --- **インフラ注意**: 現在リモートへの git push が SSH タイムアウト(`www.cyberius.biz:18`)で失敗中。実装はローカル main にマージ済み・`o2.db` 適用済みで、push は回復後に実施します。回帰確認: 全 **6422 passed, 1 skipped**。
Sign in to join this conversation.
No labels
h1-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
joe/o2#55
No description provided.