mail: conditional mutations with three outcomes (Applied/Conflict/Unknown) #391

Open
opened 2026-08-10 19:28:12 +00:00 by KofTwentyTwo · 0 comments
KofTwentyTwo commented 2026-08-10 19:28:12 +00:00 (Migrated from github.com)

Closes the "reported completed, did nothing" hole on the mutations that already exist.

apply_mutation returns Result<()> and Ok(()) is recorded as completed with no check that anything happened. A UID command against a UID another client already moved returns OK having done nothing (RFC 3501 §6.4.8), so a lost race is indistinguishable from success.

MutationOutcome = Applied { token: Option<Token> } | Conflict { observed } | Unknown

Conflict requires positive evidence — [MODIFIED …] in the tagged response, or HTTP 412. Anything ambiguous is Unknown and triggers re-enumeration rather than a verdict. The obvious proofs are all unreliable:

  • COPYUID is only SHOULD for MOVE (RFC 6851 §4.3), is advised untagged, has no empty form (RFC 4315 §3 ABNF), and is legitimately omitted for UIDNOTSTICKY destinations. Present ⇒ applied; absent ⇒ unknown.
  • Under QRESYNC, UID EXPUNGE returns VANISHED, not EXPUNGE (RFC 6851 §4.4) — counting EXPUNGE reports failure on every successful delete.
  • +FLAGS.SILENT suppresses the untagged FETCH (RFC 3501 §6.4.6) and is the normal form for conditional stores.
  • MODIFIED means "changed by someone else", not "gone".

Flags use per-flag last-writer-wins with benign merge — RFC 7162 §3.1.3 only SHOULDs avoiding spurious MODIFIED, so a blanket hard-conflict policy makes routine concurrent flag activity a conflict stream.

Also here

  • Disposition gains Conflict; status vocabulary and list_pending_mutations follow.
  • Wire the dead calculate_backoff_ms — it has no callers, so a 25-second blip currently fails every queued mutation permanently across the fleet.
  • Sequence the outbox account_id column against docs/superpowers/plans/2026-08-07-nuncio-monitor.md Task 1, whose backfill joins messages.account_id.

Depends on #388. Testable against #384.

Design: ADR 0002 · review evidence (PR #385)

**Closes the "reported completed, did nothing" hole on the mutations that already exist.** `apply_mutation` returns `Result<()>` and `Ok(())` is recorded as `completed` with no check that anything happened. A UID command against a UID another client already moved returns `OK` having done nothing (RFC 3501 §6.4.8), so a lost race is indistinguishable from success. ``` MutationOutcome = Applied { token: Option<Token> } | Conflict { observed } | Unknown ``` **`Conflict` requires positive evidence** — `[MODIFIED …]` in the tagged response, or HTTP 412. Anything ambiguous is `Unknown` and triggers re-enumeration rather than a verdict. The obvious proofs are all unreliable: - `COPYUID` is only *SHOULD* for MOVE (RFC 6851 §4.3), is advised **untagged**, has no empty form (RFC 4315 §3 ABNF), and is legitimately omitted for UIDNOTSTICKY destinations. Present ⇒ applied; absent ⇒ **unknown**. - Under QRESYNC, `UID EXPUNGE` returns `VANISHED`, not `EXPUNGE` (RFC 6851 §4.4) — counting `EXPUNGE` reports failure on every successful delete. - `+FLAGS.SILENT` suppresses the untagged FETCH (RFC 3501 §6.4.6) and is the normal form for conditional stores. - `MODIFIED` means "changed by someone else", **not** "gone". Flags use per-flag last-writer-wins with benign merge — RFC 7162 §3.1.3 only *SHOULD*s avoiding spurious `MODIFIED`, so a blanket hard-conflict policy makes routine concurrent flag activity a conflict stream. ### Also here - `Disposition` gains `Conflict`; status vocabulary and `list_pending_mutations` follow. - **Wire the dead `calculate_backoff_ms`** — it has no callers, so a 25-second blip currently fails every queued mutation permanently across the fleet. - Sequence the outbox `account_id` column against `docs/superpowers/plans/2026-08-07-nuncio-monitor.md` Task 1, whose backfill joins `messages.account_id`. Depends on #388. Testable against #384. Design: [ADR 0002](https://github.com/KofTwentyTwo/nuncio/blob/dev/docs/adr/0002-multi-engine-sync-model.md) · [review evidence](https://github.com/KofTwentyTwo/nuncio/blob/dev/docs/reviews/2026-08-10-multi-engine-design-review.md) (PR #385)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: KofTwentyTwo/nuncio#391