Remaining slice of #641 after PR #652 (AWS-other) + #653 (Azure). GCP Compute (providers/gcp/services/computeengine/client.go:422) names commitments cud-<unix-second> and never reads opts.IdempotencyToken, so a re-drive creates a second committed-use discount. Use the IdempotencyToken as the commitment name (or the requestId) so GCP rejects/dedupes a repeat. Greenfield (the #641 recovery agent confirmed no partial existed). Add a re-drive regression test: same token does not create a second commitment. Note: this is the LAST piece blocking #639 (auto-re-drive); #641 closes when this lands. Do NOT touch CloudSQL/Storage/Memorystore (those are advisory-only per #640/PR #649).
Remaining slice of #641 after PR #652 (AWS-other) + #653 (Azure). GCP Compute (
providers/gcp/services/computeengine/client.go:422) names commitmentscud-<unix-second>and never readsopts.IdempotencyToken, so a re-drive creates a second committed-use discount. Use the IdempotencyToken as the commitment name (or the requestId) so GCP rejects/dedupes a repeat. Greenfield (the #641 recovery agent confirmed no partial existed). Add a re-drive regression test: same token does not create a second commitment. Note: this is the LAST piece blocking #639 (auto-re-drive); #641 closes when this lands. Do NOT touch CloudSQL/Storage/Memorystore (those are advisory-only per #640/PR #649).