Skip to content

fix(purchase): map session approve and direct execute failures by cause - #644

Merged
cristim merged 1 commit into
mainfrom
fix/execute-error-mapping-532
Oct 6, 2026
Merged

cristim merged 1 commit into
mainfrom
fix/execute-error-mapping-532

Conversation

@cristim

@cristim cristim commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Refs #532. Slice 1 of 4 (plan: #532 (comment)).

What changed

  • ApproveAndExecute returns the row (like RunPlannedPurchaseNow), so handlers can tell a lost claim from a failure after the claim.
  • New Manager.DirectExecute: same funnel, stamps executed_at/executed_by_user_id/pre_approval_skip_reason only once the CAS is won. The handler no longer saves them before the claim.
  • runNowError is now executeFailureError(executionID, action, final, err), shared by run-now, session approve and direct execute.
  • openapi.yaml: 502 added to approve (session mode) and execute (direct mode); approve 409 text no longer lists execution failure.

Mapping (same as run-now)

error status
four-eyes denial 403 (was 409 on approve and direct execute)
lost claim, row gone (no row returned) 409
other error before the claim 500 (was 409)
audit loss after the claim 500
any other failure after the claim, including partially_completed 502 with execution_id and the row's status (was 409)

Decisions for the owner

Proof

Before: handler_purchases.go:851 and :3179 returned 409 for every error, and :3158 stamped ExecutedAt before the claim. The new tests fail when executeFailureError is mutated to answer 409 for the post-claim case (verified), and the DirectExecute stamp test fails when the skip reason is removed (verified). The existing 4-eyes direct-execute tests (real manager) were asserting the old 409 and now assert 403 and that no save carries ExecutedAt.

  • go test -race -short ./..., go vet ./..., go vet -tags integration ./internal/...: pass. OpenAPI tests pass. errcheck -blank, shadow, unparam, gocritic, misspell: nothing new in changed lines.
  • Not run locally: testcontainers tests (Docker hangs on this host); CI covers them.

Session approve and direct execute answered 409 for every error, including
failures after the claim where money may have moved, and direct execute
stamped executed_at before the claim, so a refused run kept it.

ApproveAndExecute now returns the row, and a new DirectExecute stamps the
executed_* audit fields only after the claim is won. Both handlers map
errors through executeFailureError (renamed from runNowError): 403 for a
four-eyes denial, 409 for a lost claim, 500 before the claim, 502 with the
row's status after it.

Refs #532
@cristim cristim added priority/p2 Backlog-worthy severity/medium Moderate harm effort/l Weeks triaged Item has been triaged urgency/this-quarter Within the quarter impact/few Limited audience type/bug Defect labels Oct 6, 2026
@coderabbitai

coderabbitai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 15 billable files and costs up to $3.75.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 6 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 69 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 6db14457-75cc-4546-856e-7911d1e9e1ff
📥 Commits

Reviewing files that changed from the base of the PR and between e96f5ae and 5780b34.

📒 Files selected for processing (15)
  • internal/api/executed_notification_flow_test.go
  • internal/api/execution_scope_test.go
  • internal/api/handler_purchases.go
  • internal/api/handler_purchases_test.go
  • internal/api/middleware_test.go
  • internal/api/mocks_test.go
  • internal/api/openapi.yaml
  • internal/api/purchase_pricing_test.go
  • internal/api/session_denial_final_test.go
  • internal/api/types.go
  • internal/purchase/approvals.go
  • internal/purchase/approvals_test.go
  • internal/purchase/armed_redrive_test.go
  • internal/server/interfaces.go
  • internal/testutil/mocks.go
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

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

Labels

effort/l Weeks impact/few Limited audience priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant