Skip to content

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

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
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