Monotonic settlement for optional publication retries
Locked reservation-bound settlement for retried durable operations: monotonic success only when fingerprint and authorization binding match the reserved generation.
Monotonic settlement for optional publication retries
Trigger
Use when an optional background path can publish a remote side effect, the primary task must complete independently, and worker crashes, deadlines, or lost acknowledgements can trigger retries.
Failure it prevents
Prevents: declaring a possibly committed publication denied; duplicating publication with a fresh retry; allowing a late timeout to erase confirmed completion; adopting a successful response from the wrong request generation or authorization binding; and turning auxiliary warning floods into a new failure of the primary task.
Reservation tuple
Bind one durable operation identity to a reservation tuple, not to an operation identifier alone:
- operation identifier (shared across retries for one logical publication)
- request fingerprint (hash of the payload and intent being published)
- authorization binding (subject, scope, or policy token authorizing this publication)
- generation (monotonic counter bumped when the caller edits payload or re-authorizes)
Every retry and reconciliation attempt for that logical publication reuses the same reservation tuple. A new edit or re-authorization bumps generation and mints a fresh reservation; stale workers must not settle against it.
Locked settlement
Monotonic promotion to completed is allowed only when incoming terminal evidence matches the full reservation tuple currently held on the durable record.
Settlement decision:
- If incoming rank is lower than aggregate rank, reject (no downgrade).
- If incoming is terminal completed or failed but reservation tuple does not match, quarantine the evidence and leave aggregate unchanged (remain deny, unknown, or prior terminal).
- If incoming is terminal and reservation matches, accept monotonic upgrade.
- If two matching terminals disagree on result payload, enter explicit conflict; do not pick arbitrarily.
Operation identifier match without fingerprint or binding match is insufficient. Treat such success as foreign evidence.
Why success-blind merge is unsafe
Preferring any successful response ignores that success may belong to a different logical request:
- Stale generation replay: Retry B from generation 1 completes after the caller edited the payload and bumped to generation 2. Success-blind merge would publish outdated content as current truth.
- Cross-binding bleed: Success arrives with the same operation slot but an authorization binding issued before scope revocation; adopting it re-grants publication the caller no longer authorized.
- Sibling operation confusion: Two logical publications reuse a pooled identifier due to misconfiguration; a foreign success would mark the wrong work complete and skip legitimate retries.
Monotonic rank alone answers "which observation is stronger?" Locked settlement answers "stronger observation about which reserved work?"
Practical steps
- Locate the commit boundary. Initialize sharing verdict to deny before any remote write. Worker crash or deadline before authenticated completion leaves sharing denied, not ambiguous primary failure.
- Treat post-send silence as unknown. After a possible remote write without durable acknowledgement, record unknown until reconciliation; do not infer rollback.
- Reconcile before writing again. Read durable record and remote idempotency state. If reconciliation unavailable, retain unknown and block new writes rather than minting a fresh operation identity.
- Merge outcomes monotonically with reservation lock. Matching committed terminal outranks pending, in-progress, unknown, and observer-timeout. Late timeout cannot overwrite matching completion. Mismatched terminal success cannot overwrite anything.
- Keep the primary path independent. Persist and return the primary result without waiting for auxiliary publication settlement.
- Bound warnings durably. Enforce one warning record per primary task and warning class (unique constraint or idempotent upsert). Later failures update that record or increment bounded counters; in-memory counters are insufficient across crashes or concurrent workers.
Operational example
A user finalizes an analytics export (primary task). The handler persists the export, returns success immediately, and enqueues optional Slack sharing.
The share worker validates the candidate, then crashes before any remote write. Sharing verdict remains denied because no authenticated worker completion occurred. The primary export success is unaffected.
A reconciliation pass later retries sharing under the same reservation tuple. If the worker times out after a possible send, aggregate moves to unknown, not denied and not completed, until reconciliation confirms remote state.
Warnings use the rule: one durable row per (primarytaskid, warning_class). The first deferred-share event inserts share_publication_deferred; subsequent crashes or deadline retries upsert the same row and bump a bounded retry counter. The user sees one warning card, not one per retry attempt.
Limits
Idempotency prevents duplicate effects only when the remote system participates or the local system owns an atomic visibility gate. A timeout cannot undo a remote commit. Strict proof that sharing stayed denied requires keeping every remote write after a successful pre-publication gate or using a protocol with a definitive abort or commit decision. Locked settlement does not resolve contradictory matching terminals without explicit conflict handling.
Evidence
Reasoned analysis only. No tests executed, no code run, no repository or configuration inspected.