Skip to content

Provider duplicate-purchase proof matrix: Azure Savings Plans has no server-side dedupe #838

Closed

Description

@cristim

Provider duplicate-purchase proof matrix (platform#631 B4)

Platform side: every recommendation of an execution receives DeriveIdempotencyToken(lineage, index) and a re-drive reuses it (TestRedriveReusesDerivedTokensForEveryProvider). Where the pinned cloud-commitments-go module (go.mod, ad67030387e4) uses that token, and where it is tested there:

Provider / service Token use Proof in the module
AWS Savings Plans CreateSavingsPlanInput.ClientToken (services/savingsplans/client.go:247) services/savingsplans/client_test.go
AWS RDS, ElastiCache, MemoryDB, OpenSearch deterministic reservation ID + idempotencyGuard / recoverAlreadyExists services/rds/client_test.go PurchaseCommitment_Idempotent_* (others share the helper)
AWS EC2, Redshift tag lookup by token before buying (ec2/client.go:139, redshift/client.go:177) ec2/client_test.go, redshift/client_test.go Idempotent_ScanBoundaries; the platform still REFUSES re-drive (recRedriveRefusalReason)
Azure compute, cache, cosmosdb, database, managedredis, search, synapse DoIdempotentPurchaseTwoStep with the token tag and reservation-order lookup services/internal/reservations/purchase_test.go
GCP Compute Engine RequestId from IdempotencyGUID(token) plus deterministic name (computeengine/client.go:931) computeengine/client_test.go:775-806

No proof / no guard (double-buy risk if re-driven):

  • Azure Savings Plans: alias name from time.Now().UnixNano() (services/savingsplans/client.go:373), no server-side dedupe. Platform refuses re-drive (recRedriveRefusalReason, TestRedriveRefusedWhereNoProviderGuardExists), so the risk is only a first attempt whose response is lost.
  • AWS EC2 / Redshift: the module now looks up by tag, but the lookup is a scan with documented boundaries; the platform conservatively refuses re-drive. Not a risk; an opportunity to relax once the scan is trusted.
  • GCP Cloud SQL, Cloud Storage, Memorystore: PurchaseCommitment returns an error (no purchase API), so nothing can be bought or doubled.
  • Any other provider name: refused on re-drive.

Ask: decide whether to (a) keep refusing Azure Savings Plans re-drive permanently, or (b) add a server-side dedupe upstream; and whether to relax the EC2/Redshift refusal.

Refs #631

Activity

  1. IAmJSD commented on Oct 23, 2026

    @IAmJSD
    Collaborator

    Claiming: working on this

  2. self-assigned this
    on Oct 23, 2026
  3. IAmJSD commented on Oct 26, 2026

    @IAmJSD
    Collaborator

    Owner decision (IAmJSD, acting owner, 2026-10-26, D18): keep refusing automatic re-drive for Azure Savings Plans, and keep the EC2 and Redshift re-drive refusals as they are. The safe path is to look up the existing order alias before buying; that's tracked in LeanerCloud/cloud-commitments-go#624, to be built after the Azure deploy pause. #1305 (merged) pins the alias to the re-drive token.

  4. IAmJSD commented on Oct 26, 2026

    @IAmJSD
    Collaborator

    Closing as done. The owner decided (D18 in the acting-owner report) to accept the Azure Savings Plans gap in the duplicate-purchase proof matrix as documented, and #1305 added the test that pins the matrix. The library-side follow-up is LeanerCloud/cloud-commitments-go#624.

    Checked against main at 3bfc2fe5. Closed by IAmJSD's agent at IAmJSD's request (acting owner) as part of a sweep of stale assigned issues; reopen if anything is missing.

  5. IAmJSD commented on Oct 26, 2026

    @IAmJSD
    Collaborator

    Correction to the closing note above: D18 was to keep refusing automatic re-drive for Azure Savings Plans (and keep the EC2 and Redshift refusals), not to accept a gap. #1305 (merged) pins the order alias to the re-drive token. The safe re-drive path, looking up the existing order alias before buying, is tracked in LeanerCloud/cloud-commitments-go#624.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions