Skip to content

fix(audit): record outcome-unknown purchases with a distinct audit status - #54

Merged
cristim merged 2 commits into
mainfrom
fix/49-audit-outcome-unknown
Oct 10, 2026
Merged

cristim merged 2 commits into
mainfrom
fix/49-audit-outcome-unknown

Conversation

@cristim

@cristim cristim commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

  • A purchase that fails with common.ErrOutcomeUnknown (a lost EC2 or Redshift response: the commitment may exist) is now audited as unknown instead of error, on both the returned-error path and the result.Error path. Matched with errors.Is, never by message text.
  • The stderr line for it reads mcp purchase OUTCOME UNKNOWN instead of FAILED.
  • README (Audit log) and CHANGELOG document the new status; consumers of the JSONL that switch on status must handle it.
  • Pins: all four cloud-commitments-go modules bumped to 16b5795 (pkg 30bf383 has the sentinel, providers/aws 16b5795 uses it); tidy only, no source changes needed.

The tool response is unchanged: it still carries the library's error text, which says to reconcile before retrying. No new response field.

Verification (mocks only)

go test -short on ./tools, ./cmd/..., . pass; golangci-lint 0 issues. New test TestExecutePurchaseAuditStatusForOutcomeUnknown reads the audit JSONL back: deep-wrapped sentinel returned as the error gives unknown, sentinel in result.Error gives unknown, a plain error gives error, the sentinel's text without the sentinel gives error, success gives success. Mutations each fail the test: matching on message text, dropping the result path, hard-coding error on the error path.

Closes #49

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Purchase audits now distinguish outcome-unknown failures from ordinary errors. These are recorded as unknown in JSONL, and the diagnostic displays OUTCOME UNKNOWN.
    • Documentation explains that the purchase may have reached the cloud and recommends checking for an existing commitment before retrying.
  • Bug Fixes
    • Failed purchases with an unknown outcome are no longer reported as ordinary failures.

cristim and others added 2 commits October 10, 2026 05:02
…meUnknown

Refs #49

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…atus

A purchase failing with common.ErrOutcomeUnknown (a lost EC2 or Redshift
response) is audited as unknown instead of error, on both the returned-error
and result.Error paths, matched with errors.Is. The stderr line reads
OUTCOME UNKNOWN. README and CHANGELOG document the new status.

Closes #49

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cristim cristim added priority/p3 Polish / idea / may never ship type/bug Defect labels Oct 10, 2026
@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Review in Change Stack →Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-mcp/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: e73d04d2-e97f-49d0-aa48-a2e1336f4d53

📥 Commits

Reviewing files that changed from the base of the PR and between 87ecc84 and 4e23422.


⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum

📒 Files selected for processing (6)
  • CHANGELOG.md
  • README.md
  • go.mod
  • tools/audit.go
  • tools/purchase.go
  • tools/purchase_test.go

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.



📝 Walkthrough

Walkthrough

Purchase errors wrapping common.ErrOutcomeUnknown now receive the unknown audit status and an OUTCOME UNKNOWN diagnostic. Other errors remain error and FAILED. The changelog, README, dependency versions, and tests are updated.

Changes

Purchase outcome auditing

Layer / File(s) Summary
Classify outcome-unknown errors
go.mod, tools/audit.go
The dependency versions are updated. Audit classification uses errors.Is to map errors wrapping common.ErrOutcomeUnknown to unknown; other errors remain error.
Record and report purchase outcomes
tools/purchase.go, tools/purchase_test.go, README.md, CHANGELOG.md
Purchase handling records the classified status and logs OUTCOME UNKNOWN for matching errors. Tests cover wrapped sentinel errors and non-matching errors. The documentation describes the status and reconciliation steps.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix


Merge Risk: ⚪ Minimal · up to 4e234

No actionable merge-blocking risk is established; the change is ready for normal checks.

Pre-merge checks | Passed 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: recording outcome-unknown purchases with a distinct audit status.
Linked Issues check Passed Issue #49 is directly linked and open. The reviewed changes add the unknown audit status and classify common.ErrOutcomeUnknown with errors.Is. They cover both the returned-error path and the `re…
Out of Scope Changes check Passed The reviewed changes stay within issue #49. The test covers the required classification behavior. The README and CHANGELOG document the new audit status. The cloud-commitments-go dependency updates pr…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 3 files. (3 skipped: 3 …

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR


🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@cristim

cristim commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

Gate verdict (independent adversarial review, Opus 5.5, money-path audit semantics): APPROVE at 4e23422.

Local evidence (fresh clone at the exact head, GOTOOLCHAIN=go1.26.9, macOS):

  • GOWORK=off go build -mod=readonly ./... OK; go mod verify all modules verified; go mod tidy leaves go.mod/go.sum unchanged. 815375a touches only go.mod/go.sum; all four cloud-commitments-go modules at v0.0.0-20261010025946-16b57954c6bc. Single go.mod in repo (go.work use .).
  • Library check at 16b5795: common.ErrOutcomeUnknown exported in pkg/common/types.go:29; providers/aws ClassifyPurchaseError (outcome.go:26-38) and the EC2 (client.go:174,190) / Redshift (client.go:201,215) empty-response paths wrap it and return it as err. 16b5795 is reachable from go main (compare: identical).
  • go test -short -count=1 ./...: 528 passed in 3 packages. golangci-lint: no issues.
  • Mutations of the fix, run against TestExecutePurchaseAuditStatusForOutcomeUnknown: match on message text -> FAIL (sentinel-text case, expected "error" actual "unknown"); drop result.Error path -> FAIL (result.Error case, expected "unknown" actual "error"); hardcode auditStatusError on err path -> FAIL (deep-wrapped case); unknown for all errors -> FAIL (plain-error and sentinel-text cases); stderr label hardcoded FAILED -> FAIL (both sentinel cases).
  • Surviving mutation (non-blocking coverage note): adding an errors.Is(err, context.Canceled) -> "error" check before the sentinel check is not caught. The real code has no such branch and the library already wraps context cancellation in the sentinel, so no defect, only a missing test case.
  • Response shape unchanged (PurchaseResponse untouched; error return still %w). No in-repo consumer switches on audit status; dedupe (feat(mcp): suppress search recommendations covered by recent commitments #53) uses provider listings, spend caps (fix(mcp): require operator spend caps before real purchases and price Savings Plan previews #52) run before the provider call, neither reads the audit log. README Audit log + CHANGELOG document the new value.
  • Labels mirror fix(audit): record outcome-unknown purchases with a distinct audit status #49 (priority/p3, type/bug); triaged correctly absent.
  • CI: all checks green at this SHA, mergeStateStatus CLEAN.

@cristim
cristim merged commit b384614 into main Oct 10, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/p3 Polish / idea / may never ship type/bug Defect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(audit): record outcome-unknown purchases with a distinct audit status

1 participant