Found during the ENV-SYNC-01 wave (PR #131 design review, verified against the code).
The EventDraftSnapshotCreated case in applyEventTx (internal/sync/events.go) returns a hard error when tx.ProjectByPath misses ("draft snapshot for unknown project"), and a non-verification error from applyEventTx aborts the entire ApplyEventsWithStats batch and freezes the pull. It survives today only because HLC causality usually sorts project.added first — but the project's origin device being unpinned on the receiver (its project.added sitting in a verification quarantine) makes the ordering gap real, and one stale draft event then wedges the whole sync.
The env apply path (ENV-SYNC-01, PRs #131/#132) already implements the correct shape: a winning tombstone drops the pointer; an absent path without a tombstone quarantines the event as a replayable conflict (env_pending_project kind, cursor advances, batch never aborts) recovered by ReplayPendingEnvProfileConflicts after every pull apply and after devices approve replay. The draft handler should adopt the same tombstone-drop / pending-quarantine / replay pattern (a draft_pending_project kind riding the same replay pass).
Same class, lower severity: a malformed-but-verified env/draft payload that fails upsert validation still hard-errors the batch (payload-schema forward-compat is not covered by the P6-SYNC-02 envelope-version machinery).
Found during the ENV-SYNC-01 wave (PR #131 design review, verified against the code).
The
EventDraftSnapshotCreatedcase inapplyEventTx(internal/sync/events.go) returns a hard error whentx.ProjectByPathmisses ("draft snapshot for unknown project"), and a non-verification error fromapplyEventTxaborts the entireApplyEventsWithStatsbatch and freezes the pull. It survives today only because HLC causality usually sortsproject.addedfirst — but the project's origin device being unpinned on the receiver (itsproject.addedsitting in a verification quarantine) makes the ordering gap real, and one stale draft event then wedges the whole sync.The env apply path (ENV-SYNC-01, PRs #131/#132) already implements the correct shape: a winning tombstone drops the pointer; an absent path without a tombstone quarantines the event as a replayable conflict (
env_pending_projectkind, cursor advances, batch never aborts) recovered byReplayPendingEnvProfileConflictsafter every pull apply and afterdevices approvereplay. The draft handler should adopt the same tombstone-drop / pending-quarantine / replay pattern (adraft_pending_projectkind riding the same replay pass).Same class, lower severity: a malformed-but-verified env/draft payload that fails upsert validation still hard-errors the batch (payload-schema forward-compat is not covered by the P6-SYNC-02 envelope-version machinery).