Skip to content

feat(sp): show recurring monthly cost in the table and audit log (CLI side) - #2186

Merged
cristim merged 4 commits into
mainfrom
feat/2179-recurring-cost
Oct 13, 2026
Merged

cristim merged 4 commits into
mainfrom
feat/2179-recurring-cost

Conversation

@cristim

@cristim cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member

Closes #2179 (owner decision: keep upfront, add a separate recurring field).

What

Est.Cost / estimated_cost stay the upfront payment. The terminal table gains Recurring$/mo and the audit JSONL gains recurring_monthly_cost (USD per month, omitted when unknown). Both come from cloud-commitments-go#359 (pkg/reporter, common.AuditRecord); this PR is the CLI regression test plus the pkg pin bump.

Dependency (read before merging)

  1. Merge go#359 (pkg only).
  2. Bump github.com/LeanerCloud/cloud-commitments-go/pkg (and the provider pins to the same commit) on this branch, re-run CI, then merge. Until then the new test does not compile against the pinned pkg (no field) and fails; I will push the bump when given the pseudo-version.
    No replace or go.work is committed.

Evidence

Region        Est.Cost  Recurring$/mo  Est.Savings
eu-central-2  $0.00     $358.43        $77.77
eu-west-2     $0.00     $204.40        $37.77
eu-west-2     $0.00     $1968.81       $226.84
audit: estimated_cost 0, recurring_monthly_cost 358.43 / 204.4 / 1968.81

Equals hourly x 730 (0.491, 0.28, 2.697).

🤖 Generated with Claude Code

…Savings Plans

Pins the CLI side of cli#2179: the audit line keeps estimated_cost as the
upfront payment and adds recurring_monthly_cost. The behaviour comes from the
cloud-commitments-go pkg bump (go#359); the go.mod bump lands once that merges.

Refs #2179

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-quarter Within the quarter impact/few Limited audience effort/s Hours type/bug Defect labels Oct 13, 2026
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 2 billable files and costs up to $0.50.

  • 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 11 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 61 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-cli/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 6e26e86c-645e-4fcb-882c-2b5219475159
📥 Commits

Reviewing files that changed from the base of the PR and between 8ddb891 and ecace05.

⛔ Files ignored due to path filters: 1
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing: 2
  • cmd/audit_recurring_cost_test.go
  • go.mod
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

cristim and others added 3 commits October 13, 2026 20:41
Brings the audit recurring_monthly_cost field and the Recurring$/mo table
column.

Refs #2179

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim

cristim commented Oct 13, 2026 •

Copy link
Copy Markdown
Member Author

Independent review (claude-opus-5-5) of ecace05: APPROVE

Scope

Against main 8ddb891, the net diff is go.mod (both pins), go.sum (4 lines) and the new cmd/audit_recurring_cost_test.go. The behaviour comes from the library: pkg/common/audit.go:302 copies RecurringMonthlyCost in NewAuditRecord, and pkg/reporter/reporter.go:24-46 renders the Recurring$/mo column.

Pins and module hygiene

Merge resolution

--sp-account-scope survives at cmd/main.go:137, cmd/validators.go:50-60 and cmd/multi_service_helpers.go:610, and cmd/sp_account_scope_test.go passes. A real --sp-account-scope payer Compute dry run returns the expected row: $166.80/mo savings, 3.2%, Recurring$/mo $2034.51 (2.787 x 730).

Audit paths

  • Both CLI audit writes (cmd/multi_service.go:519 and :975) go through writePurchaseAuditRecord -> common.NewAuditRecord, so the main path and the CSV replay path build records the same way.
  • --input-csv replay: the CSV reader does not parse RecurringMonthlyCost, so replay records omit recurring_monthly_cost. A real replay of the no-upfront CSV shows the key absent on all 3 records. This is the known A8 gap. The PR does not make it worse, because the field did not exist before.

Est.Cost semantics

EstimatedCost is still rec.CommitmentCost (upfront). The new test asserts this, and in the real runs below Est.Cost and estimated_cost equal CE's UpfrontCost.

Verification

  • gofmt and go vet ./... are clean, go test -count=1 ./... passes, and the git-secrets self-test gives 44 PASS, 0 FAIL.

  • Fail-before (fixture): with pkg and providers/aws reset to f794d75, GOWORK=off and the new test kept, TestWritePurchaseAuditRecord_SavingsPlanCarriesRecurringMonthlyCost fails at audit_recurring_cost_test.go:30: expected float64(1968.81), actual <nil>.

  • Mutation (fixture): I copied the e9a33bb pkg module to scratch, deleted the RecurringMonthlyCost: copyFloatPtr(...) line in NewAuditRecord, and pointed pkg at the copy with a temporary local replace. The same test then fails with the same message.

  • Real dry run, EC2Instance, no-upfront, account . CE hourly rates are 0.491, 0.280 and 2.697.

    Region Recurring$/mo (table, CSV, audit) Est.Cost (table, audit)
    eu-central-2 358.43 $0.00
    eu-west-2 204.40 $0.00
    eu-west-2 1968.81 $0.00

    Each recurring value equals hourly x 730.

  • Partial-upfront run (recorded for A3, not blocking here). CE returned m5 eu-west-2 at 2.760/hr with $12,089 upfront, m5 eu-central-2 at 0.491/hr with $2,151, and m5a eu-west-2 at 0.280/hr with $1,227. The tool shows Est.Cost equal to those upfronts, and Recurring$/mo of $2014.80, $358.43 and $204.40, which is the full hourly x 730. Cost Explorer has no explicit monthly recurring field. The recurring part implied by its numbers is hourly x 730 - upfront/12: $1007.38, $179.18 and $102.15. The shown values are therefore about 2x that, consistent with the suspected A3 overstatement in the library.

Non-blocking findings

  1. No CLI-level test pins the Recurring$/mo table column. It is covered only by the library's reporter tests, so a future library bump that changed the column would pass CLI CI unnoticed. One RenderTable header assertion in cmd would close that.
  2. The A3 partial-upfront value above affects the new column and audit field as soon as this lands. The fix belongs in the library, as tracked.

CI at review time: Build CLI, Lint Code, Lint Workflows, pre-commit, Security Scanning, Snyk and CodeRabbit pass. Unit Tests and Integration Tests are still pending, and gosec and Trivy are skipped.

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

Labels

effort/s Hours 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.

fix(sp): Est.Cost is 0 for no-upfront Savings Plans in table and audit log (design decision needed)

1 participant