[P1-09] Add end-to-end idempotency and duplicate suppression across HTTP, Rabbit, persistence, targets, and leases #47

Open
opened 2026-07-22 00:19:58 +00:00 by lost-rob0t · 0 comments
lost-rob0t commented 2026-07-22 00:19:58 +00:00 (Migrated from github.com)

ARDR reconciliation — 2026-08-29

Canonical research/design now own this issue:

  • Research: lost-rob0t/starintel-auto-research/roam/research/star-server/STAR-RESEARCH-053-end-to-end-idempotency-duplicate-suppression.org — READY_FOR_DESIGN.
  • Design/adversarial review: lost-rob0t/starintel-auto-research/roam/design/star-server/STAR-SERVER-052-end-to-end-idempotency-duplicate-suppression.org — DESIGN_READY_FOR_OPERATOR_REVIEW.
  • Implementation authorization: PENDING / AWAITING_OPERATOR_IMPLEMENTATION_APPROVAL.

Research/design readiness, issue priority/state, green validation, or machine recommendation do not authorize RAGE implementation.

Current-source correction

This is not a blank-slate dedupe feature. Current server already has useful idempotency islands:

  • /api/v1/targets requires an idempotency key, derives principal-scoped request identity, and fingerprints semantic target request fields;
  • target dispatch separately fingerprints schedule/revision/dispatch-affecting semantics;
  • the lease stack already has request/digest replay semantics coupled to monotonic fencing.

The missing invariant is a shared transport-neutral application idempotency contract across HTTP, Rabbit redelivery, persistence/outbox, target occurrences, and lease composition. Preserve stronger existing subsystem identities; do not replace them with a generic seen? cache.

Design decision

Add one runtime-owned IdempotencyRepository port plus a pure application coordinator. Each mutating operation binds a scoped logical operation identity to one deterministic request fingerprint. The repository atomically returns first execute-authority, replay-known-success, replay-known-terminal-failure, in-progress, reconciliation-required/outcome-unknown, conflict, or repository-unavailable.

Only execute-authority may run first execution. Same key/scope with a changed fingerprint conflicts before authoritative mutation. Outcome-unknown never becomes fresh work merely because a process restarted or a timeout elapsed.

Identity boundaries

  • logical operation ID != HTTP request/correlation ID;
  • logical operation ID != Rabbit delivery tag;
  • target schedule ID != scheduled occurrence ID != retry attempt ID;
  • outbox event ID remains the logical publication identity;
  • generic idempotency does not replace lease request/digest or fencing generation.

Replay is not authorization: current disclosure/resource authorization still applies before protected result material is returned.

Proposed implementation slices — ALL PENDING OPERATOR APPROVAL

Slice 1 — pure state machine + fake repository

No network, actor, CouchDB, Rabbit or Valkey effects.

Mandatory RED-first target:

operation = (principal=p1, kind=fixture.mutate.v1, key=k1)
fingerprint = F(request-A)
first claim -> execute-authority
record success R
second claim, same operation/fingerprint -> replay-known-success R
mutation callback count == 1

Untouched current server must fail because no shared IdempotencyRepository/coordinator exists. Existing target-specific helpers do not count as GREEN.

Sibling REDs: changed fingerprint conflicts with zero mutation calls; concurrent first claims yield exactly one execute authority; duplicate-in-progress cannot execute; outcome-unknown invokes reconciliation only; stale claim tokens cannot overwrite known state; repository unavailable fails closed; principal/operation/version/resource scoping prevents collisions.

Slice 2 — migrate current target-create vertical

Preserve current wire/request identity and conflict behavior while moving it behind the shared coordinator. Lost response after committed target creation must retry to the original result with one logical target/schedule.

Slice 3 — durable CouchDB adapter + reconciliation

Implement the protocol behind #40/#41 using atomic revision/CAS semantics. Crash-point tests cover claim, mutation, and outcome recording. Ambiguous writes reconcile using deterministic effect identity rather than retrying as fresh work.

Slice 4 — canonical ingest/outbox

Duplicate mutation request produces one logical document mutation and one logical outbox event. Crash after persistence but before response reconciles to the original mutation/event identity.

Slice 5 — Rabbit redelivery

First delivery commits then loses connection before ACK; redelivery resolves/replays the same logical operation, produces no second mutation/event, then settles from known terminal state. in-progress alone is not enough to ACK.

Slice 6 — target occurrence/attempt identity + fencing

Retries of occurrence O1 dedupe; later recurrence O2 remains distinct. Compose with #32/#33 so stale attempts cannot commit even if an old idempotency receipt exists.

Slice 7 — lease composition

Reuse existing lease request/digest replay and fencing. A replayed historical acquire result must never be treated as evidence that its lease/fence is currently authoritative.

Slice 8 — retention/diagnostics/vertical expansion

Bound receipt retention per operation class, prove safe compaction against durable effect IDs/fencing, add #46 observability, then migrate remaining mutations vertically.

Acceptance criteria

  • one shared application idempotency contract across migrated transports;
  • same scoped operation + same fingerprint executes first mutation at most once;
  • same scoped operation + different fingerprint fails before mutation;
  • concurrent duplicates cannot both execute;
  • ambiguous mutation outcomes reconcile rather than blindly repeat;
  • schedule/occurrence/attempt identities remain distinct;
  • Rabbit redelivery uses logical message identity and does not ACK unfinished work merely because a claim exists;
  • one logical mutation produces one logical outbox event;
  • lease request/digest/fencing semantics remain authoritative;
  • replay cannot bypass current authorization/disclosure;
  • required idempotency repository outage fails closed;
  • bounded receipt retention cannot make stale work authoritative after eviction;
  • no second actor runtime, lease authority, workflow engine, or external dedupe service.

Dependencies

Slice 1 is pure/fake-backed and can be realized independently after operator approval. Production adapter/application slices reuse #40/#41. Target/lease stale-writer integration composes with #32/#33. Observability follows #46.

Implementation authorization

PENDING / AWAITING_OPERATOR_IMPLEMENTATION_APPROVAL

Do not expose this issue to executable RAGE until explicit operator implementation approval is recorded in the canonical approval workflow.

## ARDR reconciliation — 2026-08-29 Canonical research/design now own this issue: - Research: `lost-rob0t/starintel-auto-research/roam/research/star-server/STAR-RESEARCH-053-end-to-end-idempotency-duplicate-suppression.org` — `READY_FOR_DESIGN`. - Design/adversarial review: `lost-rob0t/starintel-auto-research/roam/design/star-server/STAR-SERVER-052-end-to-end-idempotency-duplicate-suppression.org` — `DESIGN_READY_FOR_OPERATOR_REVIEW`. - **Implementation authorization: PENDING / AWAITING_OPERATOR_IMPLEMENTATION_APPROVAL.** Research/design readiness, issue priority/state, green validation, or machine recommendation do not authorize RAGE implementation. ## Current-source correction This is not a blank-slate dedupe feature. Current server already has useful idempotency islands: - `/api/v1/targets` requires an idempotency key, derives principal-scoped request identity, and fingerprints semantic target request fields; - target dispatch separately fingerprints schedule/revision/dispatch-affecting semantics; - the lease stack already has request/digest replay semantics coupled to monotonic fencing. The missing invariant is a **shared transport-neutral application idempotency contract** across HTTP, Rabbit redelivery, persistence/outbox, target occurrences, and lease composition. Preserve stronger existing subsystem identities; do not replace them with a generic `seen?` cache. ## Design decision Add one runtime-owned `IdempotencyRepository` port plus a pure application coordinator. Each mutating operation binds a scoped logical operation identity to one deterministic request fingerprint. The repository atomically returns first `execute-authority`, replay-known-success, replay-known-terminal-failure, in-progress, reconciliation-required/outcome-unknown, conflict, or repository-unavailable. Only `execute-authority` may run first execution. Same key/scope with a changed fingerprint conflicts before authoritative mutation. Outcome-unknown never becomes fresh work merely because a process restarted or a timeout elapsed. ## Identity boundaries - logical operation ID != HTTP request/correlation ID; - logical operation ID != Rabbit delivery tag; - target schedule ID != scheduled occurrence ID != retry attempt ID; - outbox event ID remains the logical publication identity; - generic idempotency does not replace lease request/digest or fencing generation. Replay is not authorization: current disclosure/resource authorization still applies before protected result material is returned. ## Proposed implementation slices — ALL PENDING OPERATOR APPROVAL ### Slice 1 — pure state machine + fake repository No network, actor, CouchDB, Rabbit or Valkey effects. **Mandatory RED-first target:** ```text operation = (principal=p1, kind=fixture.mutate.v1, key=k1) fingerprint = F(request-A) first claim -> execute-authority record success R second claim, same operation/fingerprint -> replay-known-success R mutation callback count == 1 ``` Untouched current server must fail because no shared `IdempotencyRepository`/coordinator exists. Existing target-specific helpers do not count as GREEN. Sibling REDs: changed fingerprint conflicts with zero mutation calls; concurrent first claims yield exactly one execute authority; duplicate-in-progress cannot execute; outcome-unknown invokes reconciliation only; stale claim tokens cannot overwrite known state; repository unavailable fails closed; principal/operation/version/resource scoping prevents collisions. ### Slice 2 — migrate current target-create vertical Preserve current wire/request identity and conflict behavior while moving it behind the shared coordinator. Lost response after committed target creation must retry to the original result with one logical target/schedule. ### Slice 3 — durable CouchDB adapter + reconciliation Implement the protocol behind #40/#41 using atomic revision/CAS semantics. Crash-point tests cover claim, mutation, and outcome recording. Ambiguous writes reconcile using deterministic effect identity rather than retrying as fresh work. ### Slice 4 — canonical ingest/outbox Duplicate mutation request produces one logical document mutation and one logical outbox event. Crash after persistence but before response reconciles to the original mutation/event identity. ### Slice 5 — Rabbit redelivery First delivery commits then loses connection before ACK; redelivery resolves/replays the same logical operation, produces no second mutation/event, then settles from known terminal state. `in-progress` alone is not enough to ACK. ### Slice 6 — target occurrence/attempt identity + fencing Retries of occurrence O1 dedupe; later recurrence O2 remains distinct. Compose with #32/#33 so stale attempts cannot commit even if an old idempotency receipt exists. ### Slice 7 — lease composition Reuse existing lease request/digest replay and fencing. A replayed historical acquire result must never be treated as evidence that its lease/fence is currently authoritative. ### Slice 8 — retention/diagnostics/vertical expansion Bound receipt retention per operation class, prove safe compaction against durable effect IDs/fencing, add #46 observability, then migrate remaining mutations vertically. ## Acceptance criteria - one shared application idempotency contract across migrated transports; - same scoped operation + same fingerprint executes first mutation at most once; - same scoped operation + different fingerprint fails before mutation; - concurrent duplicates cannot both execute; - ambiguous mutation outcomes reconcile rather than blindly repeat; - schedule/occurrence/attempt identities remain distinct; - Rabbit redelivery uses logical message identity and does not ACK unfinished work merely because a claim exists; - one logical mutation produces one logical outbox event; - lease request/digest/fencing semantics remain authoritative; - replay cannot bypass current authorization/disclosure; - required idempotency repository outage fails closed; - bounded receipt retention cannot make stale work authoritative after eviction; - no second actor runtime, lease authority, workflow engine, or external dedupe service. ## Dependencies Slice 1 is pure/fake-backed and can be realized independently **after operator approval**. Production adapter/application slices reuse #40/#41. Target/lease stale-writer integration composes with #32/#33. Observability follows #46. ## Implementation authorization `PENDING / AWAITING_OPERATOR_IMPLEMENTATION_APPROVAL` Do not expose this issue to executable RAGE until explicit operator implementation approval is recorded in the canonical approval workflow.
Sign in to join this conversation.
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
nsaspy/starintel-server#47
No description provided.