Skip to content

fix(ladder): on-demand baseline dollars are bought 1:1 as commitment dollars (over-buys by 1/(1-discount)) once the executor ships #349

Open

Description

@cristim

Found by the go#282 planner (plan: ~/.claude/projects/cloud-commitments-go/plans/go-282-ladder-residual-baseline.md).

The ladder sizes commitments from an on-demand-priced baseline series (uncovered on-demand EC2 dollars per hour). Allocate buys that many commitment dollars 1:1. A Savings Plan or RI hourly commitment is stated in discounted dollars, so covering X on-demand dollars per hour needs about X * (1 - discount) commitment dollars per hour. Buying X commitment dollars over-buys by roughly 1 / (1 - discount) (for a 30% discount, about 43% too much commitment).

Today the executor is disabled so no money has moved (platform#118 / #70 track the executor). This must be fixed before any executor ships: convert on-demand baseline to commitment dollars using the offering/commitment rate (per layer: Compute SP, EC2 Instance SP, Convertible RI), fail loud when the rate is unknown, never default to 1:1.

Related: go#282 (residual baseline subtracts existing commitment again; under-buy side), platform#118, platform#70.

Activity

  1. cristim commented on Oct 15, 2026

    @cristim
    MemberAuthor

    PR #404 adds the provider boundary for measured regional EC2 Instance SP rates, reusing the calculation from #352 and the allocation contract from #353. The purchase precision change is already merged in #403.

    This leaves #349 open. Compute sizing still needs a supported workload-matching policy; neither an account blend nor an EC2 proxy is selected implicitly. The remaining integration also needs the residual-baseline and existing-exposure normalization work in #282, followed by a coherent platform pin update with immutable NUMERIC tranche rates, stored-rate in-flight netting and consistent OD/commitment displays.

    The automatic execution continuation is tracked in LeanerCloud/cloud-commitments-platform#118 and LeanerCloud/cloud-commitments-platform#70. It still needs the due-tranche callback and task wiring, reusing the claim locks, grants, retry protection, execution rechecks and visibility components that have already landed. Enablement stays a separate owner decision after the full chain is verified.

  2. cristim commented on Oct 15, 2026

    @cristim
    MemberAuthor

    The scoped EC2 rate-capability leaf is merged through #404 and its separate packaging correction #405. Main commit: 9511dcfbdcb1aa9eac8081b54b6a648434580496.

    Verification on the merged revision:

    • Both postmerge workflows passed: build/test 38703740925 and pre-commit 38703740924.
    • Fresh published-main consumer proof passed. Starting with only AWS v0.0.0-20261015081001-9511dcfbdcb1, normal dependency resolution selects the shared optional interface. Build and fresh race tests passed without replacements or workspace overrides, exercising SDK request/response fixtures, filtering, pagination, missing and malformed data, Compute Holds, commitment sizing and stored-rate replay.
    • Independent exact-revision reviews and the dependency finding's fail-before/pass-after evidence are recorded on both PRs. Final CodeRabbit review was rate limited; its existing finding was fixed and verified. Both merges used the repository's documented independent-review waiver and normal server protections.

    These are constructed local SDK transport responses, not live AWS billing acceptance. No purchase, deployment or execution enablement occurred.

    #349 remains open. The next prerequisite is #282's total OD baseline and existing-exposure normalization using actual scoped observations. The remaining program also includes the matching-workload/Compute policy decision, compatible platform module adoption, immutable tranche-rate persistence and c/r netting, and due-tranche executor/task continuation. Missing rates still Hold; that does not complete automatic ladder execution. Flags and schedulers stay off. Retrospective CodeRabbit review for #404/#405 remains tracked here when review quota becomes available.

  3. 2 remaining items

  4. cristim commented on Oct 17, 2026

    @cristim
    MemberAuthor

    Decision needed (one line): which workload-matching policy sizes Compute SP commitment rates: a per-family proxy, an account blend, or fail loud until a rate is supplied? Merged so far: #403, #404, #405, #413; #282 is in flight as #441. Safe default: fail loud when no rate is known, never 1:1. Marking status/needs-info.

  5. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Owner question (2026-11-05): Does the Cost Explorer Savings Plans purchase recommendation, which reports an hourly commitment in commitment dollars, already give the figure we need? Could it be used directly as the commitment source instead of converting on-demand dollars to commitment dollars? Next: assess using the Cost Explorer recommendation's commitment figure as the source, failing loudly (no 1:1 conversion) when no recommendation exists.

  6. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Proposal: use Cost Explorer's commitment figure for Compute SP sizing, and fail loud without it

    Where things stand (go main / pinned 6111142):

    • The CE call already exists: GetSavingsPlansPurchaseRecommendation returns, per detail, HourlyCommitmentToPurchase (SDK costexplorer/types SavingsPlansPurchaseRecommendationDetail.HourlyCommitmentToPurchase *string: "the recommended hourly commitment level ... based on the usage during the lookback period"). It's in commitment dollars, not on-demand dollars.
    • providers/aws/recommendations/sp_commitment_rate.go derives the ladder's conversion rate from that same response:
      • per detail, covered_od = EstimatedSPCost + EstimatedSavingsAmount and r = (EstimatedAverageUtilization/100) * EstimatedSPCost / covered_od, summed as a ratio of sums;
      • an absent field or no match gives ErrNoSPCommitmentRate, never 1:1.
    • parser_sp.go:183, :255 already parse HourlyCommitmentToPurchase for the ordinary recommendation records.
    • The platform asks for rates once per run (internal/server/handler_ladder.go:339, GetCommitmentRates), and the engine converts its on-demand gap with them (pkg/ladder/allocate_units.go:96-113). Today only the EC2 Instance SP rate is returned (providers/aws/ladder/commitment_rates.go:18-45). Platform fix(aws): expiry adjustment divides an org-wide count by a per-rec share of demand #70 adds Compute SP (slice G0-A) and the Convertible RI rate (G0-C).

    Why not use HourlyCommitmentToPurchase as the buy amount directly. It's CE's own total for CE's own coverage target over its lookback. The ladder buys a share of its own gap: its target coverage minus existing coverage, split into ramp tranches. Using CE's total as the amount would replace the ladder's target and ramp with CE's, and would ignore the commitment the account already holds. That's the double-count problem #282 tracks.

    Proposal:

    1. Sizing: keep converting the ladder's on-demand gap with r from the same CE recommendation. That already uses CE's commitment and cost figures, not a 1:1 assumption.
    2. Use the CE figure where it fits, as a per-layer ceiling: extend the rate result with the matched details' summed HourlyCommitmentToPurchase (scope: plan type, linked account, term, payment). The engine then never plans more commitment for a layer in one run than that figure. If the ladder's gap would buy more than CE recommends, it buys CE's amount. The mixed-unit gap is gone, because both sides are commitment dollars.
    3. Fail loud:
      • No matching recommendation, or an absent HourlyCommitmentToPurchase, or an absent field in the rate formula: the layer is held (ErrNoSPCommitmentRate) and nothing is bought. Never 1:1, never 0.
      • A present but unparseable or non-finite value is an error.
    4. Tests: the ceiling binds when the gap exceeds CE's figure; no detail means hold; a missing figure with a present rate means hold; a malformed figure means error.

    This fits platform #70's plan without changing its slices: G0-A adds the Compute SP rate, and the ceiling would be a small addition there. It should land before #70's sweep can buy anything (#70 S14).

  7. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    go#31 (the EC2 Instance SP base layer) resumes when this lands.

  8. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Claimed by claude-cc-platform-2. This starts after the platform's cloud-commitments-go pin bump (waiting on go#684).

    The implementation follows the proposal above. The Compute SP rate comes from the same GetSavingsPlansPurchaseRecommendation response the EC2 Instance SP rate uses. On top of that, the summed HourlyCommitmentToPurchase of the matching details caps each layer's commitment per run, in commitment dollars on both sides. If the recommendation, or a field the rate or ceiling needs, is absent, the layer holds and buys nothing. It is never 1:1 and never 0. A fail-before test comes first. If the owner prefers using HourlyCommitmentToPurchase as the buy amount itself rather than as a ceiling, say so here before the PR opens.

  9. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Revised after review: no separate ceiling; one bias needs an explicit ack

    A cold review of the implementation plan changed two things.

    1. The HourlyCommitmentToPurchase ceiling is dropped. As a per-layer ceiling it would not bound spend:

    • It ignores commitments already in flight, so repeated runs can each plan up to it.
    • The Compute figure is account-wide, so every regional ladder would get the full amount.
    • The EC2 Instance SP and Compute SP recommendations each assume they cover the same usage, so per-layer ceilings would add up to about twice the need.

    Spend is already bounded by the per-run cap (MaxHourlyCommitPerRun, pkg/ladder/allocate.go:546) and by the required per-sweep cap planned in platform #70. So the answer to the owner's question is: the CE Savings Plans recommendation already is the source of the conversion rate. Using its commitment figure directly, as an amount or a cap, adds risk without a working bound.

    2. One known bias needs an explicit ack before the code lands.

    • The Compute SP rate from CE is an account-wide blend over EC2, Lambda and Fargate in all regions (sp_commitment_rate.go:148-150).
    • The ladder's gap is regional EC2 on-demand dollars only (providers/aws/ladder/baseline.go:47-49). Until the stable-usage estimator lands, the whole gap goes to Compute SP (baseline.go:51-58).
    • Lambda and Fargate get smaller Compute SP discounts, so the blended rate is higher than EC2's alone, and the ladder buys r_blend / r_EC2 times what an EC2-only rate would.
    • Example: a 20% Lambda share at r=0.83 with EC2 at r=0.5 gives about 13% more commitment than needed. Low recommendation utilization pushes the other way.
    • It is bounded by the per-run and per-sweep caps.

    Options:

    The slice itself is small. Compute SP gets its own rate, fetched independently of EC2. A missing rate for either layer holds only that layer, and any other error fails loud. It is never 1:1 and never 0.

  10. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Correction to option B above. Its wording suggested Compute would resume later. Under B, Compute never buys. Concretely:

    • Until the stable-usage estimator lands: the whole steady gap is assigned to Compute, which holds and is not moved to another layer. So nothing is bought except, later, the Convertible RI buffer share.
    • After the estimator: only the stable base goes to EC2 Instance SP. The rest of the gap stays unbought for good.
    • Accounts that already hold Compute SPs: with no Compute rate, every run for those accounts holds entirely, EC2 Instance SP included, until the platform converts existing coverage with the observed rate (platform fix(aws): expiry adjustment divides an org-wide count by a per-rec share of demand #70, slice S7f).

    So the real choice is: A, buy Compute with the blended rate, bounded by the caps, with the over-buy bias stated above; or B, no Compute buying, with most of the gap left uncovered.

  11. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Owner decision (2026-11-05, decision doc 05c Q1): option A. Compute SP gets the Cost Explorer blended rate. It's an account-wide EC2 + Lambda + Fargate blend, so the over-buy bias described above (r_blend / r_EC2) is accepted, bounded by the per-run cap and the platform's per-sweep cap. A missing rate holds that layer, other errors fail loud, and nothing ever falls back to 1:1 or 0.

    Next: add the Compute SP entry to the per-layer list that #691 introduced in providers/aws/ladder/commitment_rates.go (account-wide, no region filter), with tests for Compute present, Compute missing, and a hard Compute error after an EC2 success. That's after the current quota window.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions