Skip to content

fix(api): refuse marketplace pricing for an RI with no purchase timestamp - #448

Merged
cristim merged 2 commits into
mainfrom
fix/98-marketplace-zero-timestamp
Sep 28, 2026
Merged

cristim merged 2 commits into
mainfrom
fix/98-marketplace-zero-timestamp

Conversation

@cristim

@cristim cristim commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Summary

Marketplace listing no longer prices an RI whose purchase_history row has no timestamp. It returns an explicit error instead.

Root cause

computeRemainingMonths returned 1 for a zero purchaseTime, so the default schedule became upfront * 1/termMonths * 0.95 (a $36k 3-year RI listed at about $950). The supplied-schedule floor used the same value, so it could not catch it.

Fix

computeRemainingMonths now returns (int, error) and errors on a zero timestamp or non-positive term. marketplaceList returns that error. The separate Term <= 0 check folds into the helper (keeps marketplaceList under the gocyclo 10 budget; the error still contains "invalid term"). No other code computes remaining term from timestamps (grepped internal/).

Regression test

TestMarketplaceList_ZeroTimestampReturnsError asserts an error and zero CreateMarketplaceListing calls. Against the pre-fix handler (fix stashed) it fails: --- FAIL: TestMarketplaceList_ZeroTimestampReturnsError. TestComputeRemainingMonths updated for the new contract.

Verification

  • GOTOOLCHAIN=go1.26.6 go test -race -short ./internal/api/: ok
  • gofmt, go vet, go mod tidy, gocyclo, gosec pre-commit hooks: passed
  • golangci-lint not run locally (session pausing); relying on CI.

Closes #98

Summary by CodeRabbit

  • Bug Fixes
    • Marketplace listings now return an error when purchase information is missing or has a non-positive term, instead of calculating a default remaining term. Valid purchases continue to use the existing remaining-month calculation.

…tamp

computeRemainingMonths returned 1 for a zero timestamp, so a row without a timestamp was listed at 1/termMonths of its upfront cost. It now returns an error for a zero timestamp or non-positive term; the separate Term <= 0 check in marketplaceList folds into it.
@cristim cristim added triaged Item has been triaged priority/p1 Next up; this sprint severity/high Significant harm urgency/this-quarter Within the quarter impact/few Limited audience effort/s Hours type/bug Defect labels Sep 28, 2026
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: LeanerCloud/cloud-commitments-platform/.coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: b45ad42f-9028-4fa9-8be3-c16e621e9095

📥 Commits

Reviewing files that changed from the base of the PR and between dfad8fc and 3936b03.

📒 Files selected for processing (2)
  • internal/api/handler_marketplace.go
  • internal/api/handler_marketplace_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

Marketplace listing now returns an error for a purchase with a zero timestamp or non-positive term. Valid remaining-month calculations retain the one-month minimum.

Changes

Marketplace listing validation

Layer / File(s) Summary
Remaining-month input validation
internal/api/handler_marketplace.go, internal/api/handler_marketplace_test.go
computeRemainingMonths now returns an error for a zero timestamp or non-positive term. Tests check invalid inputs, valid calculations, and the one-month floor.
Marketplace listing error propagation
internal/api/handler_marketplace.go, internal/api/handler_marketplace_test.go
marketplaceList returns an error from the remaining-month calculation. A test verifies that a zero-timestamp purchase does not trigger EC2 listing creation.

Priority: ⬆️ High

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

Change: Bug fix · Severity of issue fixed: High

Merge Risk: ⚪ Minimal · up to e4018

No actionable issue remains before merge under normal checks.

🚥 Pre-merge checks | ✅ 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: marketplace pricing now refuses an RI that has no purchase timestamp.
Linked Issues check ✅ Passed Issue #98 requires marketplace listing to fail when purchase timestamp is missing. The PR changes computeRemainingMonths to return an error for purchaseTime.IsZero() and for non-positive terms. `m…
Out of Scope Changes check ✅ Passed The changes are limited to the issue #98 pricing guard, its propagation through marketplaceList, and focused automated tests. The non-positive-term validation is moved into the same helper and remai…
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 4 functions across 2 files.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

@cristim

cristim commented Sep 28, 2026

Copy link
Copy Markdown
Member Author

Independent adversarial review (Opus 5.5) at 3936b03: MERGE. computeRemainingMonths now errors on a zero purchase timestamp or non-positive term instead of returning 1, which had listed the RI at 1/termMonths of its upfront cost. It fails closed before the price schedule, the EC2 client and reserveAndCreateListing, so no listing row and no marketplace call happen. The valid-timestamp math is unchanged. Pre-fix: TestMarketplaceList_ZeroTimestampReturnsError reaches listing reservation on main (panic) and passes here. go test -race -short ./internal/api 2369 pass, golangci-lint v2.10.1 clean; CI 25/25. Follow-up filed (reject expired RIs, 4xx instead of 500). (branch updated with main; reviewed changes unchanged)

@cristim
cristim merged commit 0959adc into main Sep 28, 2026
25 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/p1 Next up; this sprint severity/high Significant 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(api): marketplace listing prices a zero-timestamp RI at 1 month of residual value

1 participant