Skip to content

fix(revoke): retry wording and lock time after an uncertain Azure Return #1584

Closed

Description

@IAmJSD

Since #1579, an ambiguous Azure Return failure keeps the in-flight flag, and the 2h sweep releases it. Two user-facing gaps remain:

  1. Retry wording. A retry while the outcome is uncertain gets the existing 207 RECONCILE_PENDING "Refund already issued ... Do not retry". The refund may not have happened, so the message should say the outcome is uncertain and to check the Azure portal.
  2. Lock time and the single-send refusal. The flag can lock the purchase for up to 2h, which can run past the 7-day free-cancel window. After the release, a new revoke can get Azure's "already returned" 4xx on a single send. That clears the flag and leaves a refunded purchase showing as active, as on main before fix(revoke): keep the in-flight flag on an ambiguous Azure Return failure and refuse a late Lambda claim #1579. Consider mapping Azure's "already returned" error code to revoked rather than to a definite refusal.

Found by both independent reviews of #1579.

Activity

  1. cristim commented on Nov 5, 2026

    @cristim
    Member

    Triaged: p2. After an ambiguous Azure Return, the retry message wrongly says a refund was issued, and the 2h lock can run past the free-cancel window. Azure deploys are paused, so impact is few for now. Both fixes are small.

  2. cristim commented on Nov 9, 2026

    @cristim
    Member

    Claimed by claude-darling: planning now (highest-priority unclaimed platform issue: p2, this-quarter, effort/s, money-path wording). One PR with self-merge on green when done.

  3. cristim commented on Nov 9, 2026

    @cristim
    Member

    Checked against main (82fe693 era, #1522/#1529/#1579 in place) before planning:

    1. The premise of gap 1 is partly stale. A retry while the Return outcome is uncertain no longer gets the RECONCILE_PENDING "Refund already issued ... Do not retry" answer: revocationInFlightResult (handler_purchases_revoke.go:922-933) returns it only when the return_posted_at stamp proves Azure accepted the Return, and an uncertain failure answers REVOCATION_PENDING_CONFIRMATION (handler_purchases_revoke_uncertain.go:137-143). What is left of gap 1: that answer's text, "A refund for this purchase is being processed. Check back in a few minutes; don't start another revoke.", also serves the uncertain case, where the flag can last up to 2h and the refund may never have happened, and it does not point to the Azure portal.
    2. That text is owner-approved copy (frontend/src/history.ts:42 says so, feat(revoke): answer a revoke that loses the race with an in-progress response, not "refund already issued" #1522), duplicated in the Go constant, the frontend constant and three tests. Changing it is a product-copy decision, so I am asking the owner (decision doc), not editing it unilaterally.
    3. Gap 2 (map Azure's "already returned" 4xx to revoked) would mark a purchase revoked on the basis of an error code. The code is not in the repo or the issue and I cannot verify it offline; it needs a live capture or Azure's documented code first. Proposed split: a follow-up issue for that, kept out of the wording change.

    I am releasing my claim on this issue for now (taking #1645 meanwhile) and will pick the copy change up when the owner answers.

  4. cristim commented on Nov 12, 2026

    @cristim
    Member

    Owner go (2026-11-12, decide-now list): claude-platform-2 is implementing this item now per the recorded decision; if another lane holds an uncommitted claim on it, please hand over via the bus instead of duplicating.

  5. cristim commented on Nov 12, 2026

    @cristim
    Member

    Decided (owner go 2026-11-12) by claude-platform-2 and landed aa6060b on main (two adversarial review passes plus a comment fix; local verify: go test ./internal/api ./internal/purchase, frontend revoke test + tsc + eslint, golangci-lint 0 issues (v2.11.4; v2.10.1 not installed), integration-tagged revoke probes, pre-commit; CI green on the commit). Premise: gap 1 was only partly live (an uncertain Return already answered REVOCATION_PENDING_CONFIRMATION; the 'Refund already issued ... Do not retry' text only appears when return_posted_at proves the Return). Decisions: (1) WORDING: the uncertain answer now reads 'We could not confirm whether the refund for this purchase went through. Check the reservation in the Azure portal before trying again: if it still shows as active after about 90 minutes, you can revoke again.' (Go constant and frontend copy byte-equal). (2) LOCK TIME: the flag is released by an HOURLY sweep once older than staleRevocationInFlightAfter; it was 2h (real lock 2 to 3 hours, past the free-cancel window for revokes started in the last hours, because the endpoint stops accepting a revoke 1h before the window closes); now 30m (about 8x the 3m30s in-flight bound), so the real lock is 30 to 90 minutes; a test pins the value. (3) ALREADY RETURNED: a single-send definite-refusal 4xx carrying Azure's 'already returned' error code now marks the purchase revoked with no refund amount instead of clearing the flag and leaving a refunded purchase showing active; any other 4xx, a 5xx, or a retry keeps the old handling; matching by error code only. REMAINING (issue stays open): the code string ReservationAlreadyReturned is UNVERIFIED (only a test fixture name; a never-matching code is a no-op): tracked in #1953 and known_issues/43; confirm it from a live or recorded Azure response when Azure deploys resume.

  6. cristim commented on Nov 14, 2026

    @cristim
    Member

    Verified on origin/main: aa6060b is an ancestor and covers all three points (uncertain-Return wording, in-flight lock cut from 2h to 30m, already-returned 4xx mapped to revoked). The only open item, confirming Azure's real 'already returned' error code, cannot be done offline (Azure deploys are paused) and is tracked separately in #1953 and known_issues/43. Closing; nothing else remains here. Claim file claim-claude-platform-2-ccp1584 was 2 days old and is superseded.

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