Skip to content

fix(frontend/history): Retry button still offered on Azure savings-plans rows the backend now refuses #161

Closed

Description

@cristim

Follow-up to LeanerCloud/cloud-commitments-cli#1668 / LeanerCloud/cloud-commitments-cli#1713, which closed the money hole: the retry endpoint now returns a 409 with ops_hint + redrive_unsafe: true when an execution's recommendations are not safe to re-drive (Azure savings-plans, or an unrecognized provider).

The History UI still renders the Retry button on those rows. It hides the button only when the row carries a server-computed ops_hint (frontend/src/history.ts:603), and handler_history.go computes that field from the failure-reason map alone, which knows nothing about provider re-drive safety. So the operator clicks Retry, the backend refuses, and they get an error toast instead of never being offered the action.

Purely cosmetic now that the backend fails closed, but the button promises something that can never succeed.

Suggested shape: have the History row projection surface the same purchase.RedriveRefusalReason result (as ops_hint plus a redrive_unsafe flag so the badge can word itself as permanent rather than operator-fixable), and let the existing if (p.ops_hint) return false in canRetry do the rest. Touches internal/api/handler_history.go, internal/config/types.go (the OpsHint projection struct), frontend/src/types.ts and frontend/src/history.ts.

Activity

  1. cristim commented on Aug 3, 2026

    @cristim
    MemberAuthor

    Raised p3 -> p2, severity/low -> medium, urgency/eventually -> this-sprint.

    A control that is always offered and always fails is worse than "eventually". Once LeanerCloud/cloud-commitments-cli#1713 lands, every Azure savings-plans row in History keeps a Retry button that returns a permanent 409, and the user has no way to tell that from a transient failure they should retry later. The likely outcomes are repeated clicking and a support contact asking to have it unblocked, which is the behaviour the p0 exists to discourage even though the money risk is now closed server-side.

    CodeRabbit independently flagged the same thing on PR LeanerCloud/cloud-commitments-cli#1713 (internal/api/handler_purchases.go:1751): the frontend ignores the redrive_unsafe detail and renders the permanent refusal as an operator-fixable ops_hint. So the response already carries the signal needed to fix this; the frontend just does not read it.

    Correcting my own reasoning on the record: I initially pushed for this to be fixed inside LeanerCloud/cloud-commitments-cli#1713 and told the implementer it outranked the other finding. That was wrong. I had assumed a user could still reach a double-purchase through the UI, and the backend gate makes that impossible, so the remaining defect is presentational. The implementer's judgement to split it out was better than my instruction, and holding a p0 for it would have been the wrong trade. p2 with the signal already present in the API response is the right shape.

    Scope when someone picks this up: handler_history.go derives ops_hint from the failure-reason map, and the frontend hides the Retry button only on that. It needs to also treat redrive_unsafe as terminal. Keep it to that.

  2. added 3 commits that reference this issue on Aug 3, 2026
  3. cristim commented on Oct 16, 2026

    @cristim
    MemberAuthor

    Claiming: working on this [claude-cc-impl]

  4. self-assigned this
    on Oct 16, 2026
  5. added 5 commits that reference this issue on Oct 16, 2026
    6f7e213
    c60588f
    35dec45
    48e6adb
    21daf1c
  6. added a commit that references this issue on Oct 17, 2026
    579421e
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