Skip to content

feat(purchase): allow Retry of proven-NoSubmission rows for EC2, Redshift and Azure savings plans #1803

Open

Description

@cristim

Problem

RedriveRefusalReason (internal/purchase/manager.go) refuses Retry for EC2, Redshift and Azure savings-plan purchases whatever the row's NoSubmission says. That is right when a request may have reached the provider. But some failed rows prove nothing was submitted, for example the per-account skip rows from #1798 (#1672) and pre-execution refusals. For those providers, the user has to start a new purchase instead of retrying.

Proposal

Let Retry (checkRetryEligibilityGates) and the execution-time re-drive check accept a failed row with NoSubmission set for those providers.

This is a money path, so it needs its own double-buy review:

  • prove every writer of NoSubmission=true runs strictly before any provider call;
  • prove a Retry of such a row cannot race an in-flight attempt of the same lineage;
  • test that a NoSubmission EC2 row is retryable and a submitted one stays refused.

When this lands, the skip row's wording in skippedAccountNote can drop its "start a new purchase" branch.

Activity

  1. cristim commented on Nov 7, 2026

    @cristim
    MemberAuthor

    Claimed by claude-ui-fix-1 (coordinator-assigned). This is a money path, so I'm planning first: map every writer of NoSubmission=true and its ordering relative to provider calls, and the lineage race with in-flight attempts, before any code.

  2. cristim commented on Nov 7, 2026

    @cristim
    MemberAuthor

    Scope note from planning (no code yet). The proposal as written is unsafe in one case, so the plan narrows it:

    • NoSubmission proves one row, not a lineage. Retry successors reuse the lineage's idempotency key. A successor can fail with NoSubmission set (for example when a plan step is failed before it runs), but that says nothing about attempt 0, which may have bought. EC2 has no provider-side dedupe. So the rule is "failed, NoSubmission, and first attempt" (the existing NeverSubmitted), not "failed and NoSubmission".
    • The execution-time check runs on the successor, whose own NoSubmission is always false. It will read the predecessor instead and require it to be failed, NoSubmission and attempt 0. A lookup error or a missing predecessor refuses.
    • Under the Retry transaction's row lock, the same condition is re-checked before linking the successor.
    • RedriveRefusalReason stays unchanged for the reaper. A Retry-only predicate lifts just the EC2, Redshift and Azure savings-plan reasons. Unknown providers keep refusing.

    Defaults taken, to be overridden here if wanted:

    • first attempt only, no chain walk;
    • fan-out root rows with NoSubmission at attempt 0 are eligible;
    • no new idempotency-key index.

    Sequencing: this branches after #1832, which removes the Redshift refusal on its own, so this change covers EC2 and Azure savings plans. Existing retries for RDS, plain savings plans and GCP, and every first purchase, keep today's path unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions