Skip to content

refactor(gcp): remove unread stored ctx fields - #575

Merged
cristim merged 4 commits into
mainfrom
refactor/6-remove-stored-ctx
Oct 20, 2026
Merged

cristim merged 4 commits into
mainfrom
refactor/6-remove-stored-ctx

Conversation

@cristim

@cristim cristim commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Part of #6 (M-6).

Removes stored context.Context fields that no code reads, so contexts flow per call:

  • providers/gcp/recommendations.go: RecommendationsClientAdapter.ctx (also dropped from the literal in provider.go).
  • providers/gcp/services/computeengine/client.go: Client.ctx and the ctx parameter of computeengine.NewClient, which only fed it. Callers and tests updated.

Kept: computeengine.realBillingService.ctx (read at client.go ListSKUs) and Provider.ctx (separate struct, out of scope).

Skipped: cloudsql, cloudstorage, memorystore. Open PR #471 by @IAmJSD edits their client.go files, so they are left for a follow-up after it merges.

Deletion probe: after the change, the only remaining .ctx / ctx: hits in providers/gcp outside those three services are:

providers/gcp/provider.go:142:		ctx:        ctx,
providers/gcp/provider.go:164:		ctx:        ctx,
providers/gcp/provider_test.go:274:	assert.Equal(t, ctx, provider.ctx)
providers/gcp/provider_test.go:361:	assert.Equal(t, ctx, provider.ctx)
providers/gcp/services/computeengine/client.go:350:	skus, err := skulist.All(r.ctx, r.service.Services.Skus.List(serviceID).PageSize(skuPageSize), skulist.DefaultMaxPages)
providers/gcp/services/computeengine/client.go:1004:	return &realBillingService{ctx: ctx, service: service}, nil
providers/gcp/services/computeengine/paging_test.go:52:	return &realBillingService{ctx: context.Background(), service: api}

Verification (providers/gcp, with and without GOWORK=off): build, vet, go test -timeout 300s -count=1 ./... all pass; golangci-lint 0 issues; scripts/test-git-secrets-allowlist.sh 44 PASS, 0 FAIL.

🤖 Generated with Claude Code

Update (review round): realBillingService.ctx removed, BillingService.ListSKUs now takes ctx first (breaking for custom implementations; no sibling repo references it). Provider.ctx removed (was only written, never read). computeengine.NewClient callers outside this repo: mcp tools/gcp_computeengine_cud_safeguards_test.go:76,125, tools/search_dedupe_test.go:344, cmd/cudly-mcp/gcp_purchase_protocol_test.go:102; platform internal/purchase/gcp_history_cost_test.go:48. CHANGELOG entry added. Re-verified at 2958440 with and without GOWORK=off: build, vet, test, test -race, golangci-lint 0 issues.

Drop RecommendationsClientAdapter.ctx and computeengine.Client.ctx, plus the
NewClient ctx parameter that only fed it. cloudsql, cloudstorage and memorystore
are skipped while PR #471 is open.

Part of #6 (M-6)

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

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 13 billable files and costs up to $3.25.

  • 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 87 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-go/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: bf060913-0f7c-4d3d-bb95-5c79be188cc3
📥 Commits

Reviewing files that changed from the base of the PR and between 8c1022b and ece5c58.

📒 Files selected for processing: 13
  • CHANGELOG.md
  • providers/gcp/provider.go
  • providers/gcp/provider_test.go
  • providers/gcp/recommendations.go
  • providers/gcp/recommendations_test.go
  • providers/gcp/services/computeengine/client.go
  • providers/gcp/services/computeengine/client_test.go
  • providers/gcp/services/computeengine/dedupe_test.go
  • providers/gcp/services/computeengine/paging_test.go
  • providers/gcp/services/computeengine/plan_test.go
  • providers/gcp/services/computeengine/pricing.go
  • providers/gcp/services/computeengine/pricing_test.go
  • providers/gcp/services/computeengine/savings_window_test.go
  • 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 20, 2026 12:26
BillingService.ListSKUs takes ctx first so realBillingService stops storing
one; Provider.ctx was written but never read.

Part of #6 (M-6)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #6 (M-6)

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

cristim commented Oct 20, 2026

Copy link
Copy Markdown
Member Author

Merge gate verdict (claude-cc-libs)

Every gate holds at head ece5c58:

  • Two independent reviews approve the reviewed head 2958440. The branch was then updated from main, and the PR diff is byte-identical to the reviewed diff (compared mechanically).
  • CI is green on ece5c58, which is the reviewed change on top of current main.
  • 0 unresolved threads; MERGEABLE/CLEAN.

CodeRabbit is waived as a merge gate under the 2026-10-19 decision. Squash-merging.

@cristim
cristim merged commit 1ce87bd into main Oct 20, 2026
15 checks passed
@cristim
cristim deleted the refactor/6-remove-stored-ctx branch October 20, 2026 10:46
cristim added a commit to LeanerCloud/cloud-commitments-mcp that referenced this pull request Oct 20, 2026
* chore(deps): bump cloud-commitments-go to 1ce87bd

Bump pkg, providers/aws, providers/azure and providers/gcp. The only
breakage is computeengine.NewClient losing its ctx parameter
(LeanerCloud/cloud-commitments-go#575); fix the four test call sites and
drop the ctx that became unused in search_dedupe_test.go. The bump also
brings (*ec2.Client).GetOfferingDetailsForClass (go#574), used by the next
commit.

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

* fix(purchase): price standard EC2 RIs at the standard offering

committedUSD priced every purchase through GetOfferingDetails, which
always resolves the convertible offering. An EC2 purchase with
offering_class=standard was therefore capped by
CUDLY_MCP_MAX_COMMITMENT_USD and counted against CUDLY_MCP_BUDGET_USD at
the convertible price, not the price actually committed.

For EC2 with offering_class=standard, price through
GetOfferingDetailsForClass (LeanerCloud/cloud-commitments-go#574). A
client that lacks the method is refused before any purchase (fail
closed); there is no fallback to convertible pricing. Convertible, empty
and non-EC2 paths are unchanged. Existing EC2 handler tests that buy a
standard RI now use a fake that implements the method.

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

* fix(purchase): refuse Redshift until the first-attempt time is tracked

The bump brings cloud-commitments-go#515: a tokenized Redshift purchase
is refused unless PurchaseOptions.RequestedAt (the first-dispatch time of
the idempotency key) is set, because reserved nodes are found by start
time. The MCP always sets a token, never RequestedAt, and keeps no
durable per-key state to supply it; the call time would let a later
retry miss the first purchase and double-buy. Refuse Redshift up front,
before the budget is reserved, rather than failing in the library after.

The audit of PurchaseOptions fields in 9dae64b..1ce87bd found no other
newly required option. Also pin classPricer to *ec2.Client at compile
time and name the pulled-in behavior changes in the CHANGELOG.

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

* feat(purchase): track the first-attempt time of each idempotency key

Replace the Redshift refusal with the real fix for cloud-commitments-go#515.
The library finds an earlier Redshift purchase by start time relative to
PurchaseOptions.RequestedAt, so a retry must reuse the first attempt time,
not its own call time. Record the first-dispatch time of the token before
the provider call and pass it as RequestedAt for every provider.

With CUDLY_MCP_BUDGET_STATE set the time is kept in <state>.attempts, using
the budget file lock and atomic write (extracted as writeStateAtomically),
with 30-day retention (the MCP has no idempotency horizon constant). A
corrupt or unwritable store refuses the purchase and releases the budget
reservation. Without a state file the time is per process; Redshift, whose
dedupe must survive a restart, is refused in that mode.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant