Skip to content

fix(ladder): stop subtracting existing commitment from residual baselines - #441

Merged
IAmJSD merged 8 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-282
Oct 26, 2026
Merged

IAmJSD merged 8 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-282

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Refs #282 (head 284a500). This is the shared-engine part of the fix. It doesn't close the issue yet (see "Why not Closes" below).

Root cause

The AWS ladder baseline is a residual series. It counts only EC2 On Demand Instances spend, so it is the usage that existing RIs and SPs left uncovered. Allocate treated every baseline as total demand and ran gap = min(target, low_water) - existing. That subtracted the existing commitment a second time. On a partly covered account this returns a "target already met" Hold while usage is still uncovered.

I re-checked current main (740dfbd) before changing anything. #350, #404 and #413 added building blocks and scoped the residual observations. None of them changed this formula, so the bug still reproduces (evidence below).

Fix

  • New UsageBaseline.Basis (BaselineBasis). BaselineBasisTotal is the default and also covers the empty legacy value. BaselineBasisResidual marks a series that is already net of existing commitments. Any other value is an error.
  • On a residual baseline, Allocate sizes gap = low_water * target% - in_flight and doesn't subtract existing. The base split also doesn't subtract the existing base from the stable level. The OD it buys never exceeds the observed residual.
  • Target below 100% with existing commitment in any layer: the true gap is pct*(C+R) - C, where C is the covered usage the residual leaves out. It is at most pct*R, but it can't be sized without C. So the run is held, with an explanation and the upper bound, instead of being guessed. If even that upper bound is below the $0.01 minimum, it is the usual "target already met" Hold.
  • With no existing commitment in any layer, the residual and total bases give the same result at any target.
  • On a residual basis, expiring commitment is not added back. Its coverage is still in effect during the observed window, and turning native commitment dollars into covered usage needs rates. Usage it stops covering later shows up in later observations as a top-up, never an over-buy.
  • Rationales on residual runs append baseline_basis=residual (existing commitment already excluded from low_water, not subtracted again). existing= is still shown.
  • The total-basis path is unchanged byte for byte: the existing tests pass untouched and its rationales gain nothing.
  • The InFlight doc now states the residual contract. Callers must include active commitment that the observed series doesn't reflect yet, for example one bought after the last CE day because of reporting lag. Otherwise it is re-planned.

Worked numbers (from the tests)

Target 100%, buffer 0, no in-flight, Compute SP rate 0.7 unless noted.

Case Existing Residual low water Before (total formula) After (residual basis)
Issue replay $6/hr Compute SP $4/hr Hold "target already met", gap 4 - 6 = -2 buy OD $4/hr = commitment $2.80/hr
Uncovered control (rate 1) 0 $10/hr OD 10 OD 10 (same)
Zero existing, 80% (rate 1) 0 $10/hr OD 8 OD 8 (same)
Fully covered (rate 1) $6/hr $0 / $0.005 / $0.02 Hold Hold / Hold / OD 0.02
Partial target 80% (rate 1) $6/hr $4/hr Hold (gap 3.2 - 6) Hold "cannot size a partial target", upper bound $3.20
In flight $6/hr $4/hr Hold $2.80 in flight at 0.7 (= OD 4): Hold. $1.40 at 0.7 (= OD 2): buy OD 2 = commitment 1.40
Expiring (rate 1) $6/hr, $2/hr expiring $4/hr Hold (4 - (6 - 2) = 0) OD 4 (not 4 + 2)
Base split (rate 1, buffer 10%, stable 5) $3/hr EC2 Instance SP $10/hr n/a base 5 (not 5 - 3), flex 4, buffer 1, total 10

A seeded property test runs 2000 random cases over existing, expiring, in-flight, rates, buffer, cap and target. It checks that bought OD ≤ max(0, R - in_flight_od) ≤ R, that commitment ≤ OD, and that a partial target with existing commitment never buys.

Verification

All commands were run locally on macOS (Go workspace, five modules), with AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null. No cloud APIs were called and nothing was purchased.

  • make build, make vet, make test-unit: pass.
  • (cd pkg && GOWORK=off go test -race -short -count=1 ./...): pass.
  • (cd providers/aws && GOWORK=off go build -mod=readonly ./... && GOWORK=off go test -mod=readonly -race -short -count=1 ./ladder/... ./recommendations/...): pass. The provider module is unchanged, and the full AWS suite also ran inside make test-unit.
  • golangci-lint v2.10.1 run --allow-parallel-runners ./... in pkg: 0 issues.
  • gocyclo -over 10 on the changed non-test files: silent. Allocate is at 10.
  • git-secrets --scan on the changed files with the AWS patterns registered: clean. A positive control, an account_id literal with a non-allowlisted 12-digit value, was flagged.
  • scripts/gosec-hook.sh on the changed files: clean. markdownlint-cli@0.47.0 on CHANGELOG.md: clean. git diff --check: clean.

Fail-before / pass-after. The new tests use the new field, so on main they fail to compile, not on behavior. The behavioral fail-before evidence is two things:

  1. The issue replay also asserts the total-basis control. It still returns Hold ... gap=$-2.0000/hr with these inputs, which is the main behavior.
  2. A mutation that restores the pre-fix formula for residual baselines (existingForBasis always returns existing) fails 6 of the new tests, including the issue replay.

Mutation probes on the fix. Each was applied in a scratch copy and the full pkg/ladder suite was run.

Mutation Result
Pre-fix formula on the residual basis killed (6 tests)
Total basis also skips existing (over-buy) killed (11 tests, mostly existing ones)
No partial-target Hold killed (partial-target test + property test)
Partial-target Hold also at 100% killed
Partial-target Hold before the target-met check killed
Residual base split keeps existing base killed
hasExistingCommitment always false / always true killed / killed
Ignore target % on the residual basis killed
Residual skips in-flight killed
Validate accepts any basis killed

End-to-end scratch check (not committed). I wrote a temporary test through the real aws/ladder.New, GetUsageBaseline, GetLayerStates, SupportedLayers and pkg/ladder.Allocate, run in workspace mode. It used boundary fakes, a 30-day series and a one-year Compute SP. Without the AWS change it reproduces the issue: partly-covered residual=4 existing=6 allocations=0, gap=$-2. With a temporary one-line AWS change (Basis: ladder.BaselineBasisResidual in GetUsageBaseline) it gives compute-sp 4.00. The uncovered control stays at 10 and the fully covered case stays a Hold. All AWS ladder tests pass with that change in workspace mode.

Why not Closes, and the follow-up

The AWS module pins the published pkg (v0.0.0-20261015085730-498b74f31f01). Under the CI step "Verify standalone provider modules" (GOWORK=off), the one-line AWS adoption fails with unknown field Basis. So it has to land after this pkg version is published, the same split as #352 → #353 → #404.

The follow-up is: bump the AWS pkg pin, set Basis: BaselineBasisResidual in providers/aws/ladder/baseline.go, and add the end-to-end regression above as a committed test.

That follow-up should also decide the CE-lag case. A commitment bought after the last observed CE day is in existing but not yet in the residual. Under the documented InFlight contract the platform must net it, and today the platform deliberately leaves completed tranches out of in-flight. Until that is handled, the residual basis can re-plan such a purchase for a few days. The executor is still disabled (platform #70/#118), so no money moves.

Out of scope (still tracked by #282 / #349)

  • Sizing targets below 100% from a residual baseline with existing coverage. This needs covered on-demand-equivalent observations, for example GetSPCoveredSeries (feat(aws/recommendations): daily SP covered series and SP on-demand-equivalent ratio #350) plus RI covered usage.
  • Normalizing existing and expiring commitment to OD units (E/k, cohort rates).
  • Pre-buying replacements for expiring commitment on a residual basis.
  • Platform pin bump, in-flight accounting for CE lag, persisted tranche rates, executor adoption.
  • Platform plan display (assemble...): it computes its own target/existing/gap summary and will want to show the basis after the pin bump.
  • The Basis field is untagged, so a platform JSON marshal of LadderPlan.Baseline gains "Basis":"".

Maintainer: please mirror the issue's labels on this PR (priority/p2, severity/medium, triaged, urgency/this-sprint, impact/few, effort/m, type/bug). I don't have label access on this repo.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Usage baselines can specify whether they represent total demand or usage remaining after existing commitments.
    • Allocation calculations account for residual baselines without subtracting existing commitments twice.
  • Bug Fixes
    • Residual baselines with existing commitments and a target below 100% are held rather than triggering an allocation.
    • Expiring commitments are not added back when calculating residual-baseline allocations.
    • Unsupported baseline types return an error; total-basis allocation behavior remains unchanged.

…ines

The AWS ladder baseline counts only uncovered EC2 On Demand spend, but
Allocate treated every baseline as total demand and subtracted existing
commitment again. A $4/hr residual with a $6/hr Compute SP held as
"target already met" (gap 4 - 6 = -2) while $4/hr was uncovered.

Add UsageBaseline.Basis. On BaselineBasisResidual, Allocate sizes
low_water * target% - in_flight (never above the residual) and does not
subtract existing from the stable level for the base split. A partial
target with existing commitment is held, since its gap needs covered
usage the residual excludes. Total-basis behavior is unchanged; unknown
basis values are an error. The AWS adoption follows once this pkg
version is published.

Refs LeanerCloud#282

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

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 937e283 and ce428f0.

Files selected for processing: 1
  • CHANGELOG.md
Files skipped from review as they are similar to previous changes: 1
  • CHANGELOG.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

UsageBaseline.Basis distinguishes total-demand baselines from residual baselines. Allocate validates the basis and adjusts coverage deductions and partial-target handling for residual baselines. Tests cover basis-specific allocation behavior, edge cases, and allocation bounds.

Changes: Residual baseline allocation

Layer / File(s) Summary
Baseline basis contract
pkg/ladder/types.go, pkg/ladder/allocate_residual.go, pkg/ladder/capability.go
UsageBaseline gains a Basis field. BaselineBasis defines and validates total and residual values. Provider documentation describes when to use the residual basis.
Basis-aware allocation
pkg/ladder/allocate.go, pkg/ladder/allocate_residual.go, CHANGELOG.md
Allocate validates the basis and adjusts existing-coverage deductions for residual baselines. It holds allocations when the target is below 100% and existing commitment is present. Rationales include basis details.
Allocation tests
pkg/ladder/allocate_residual_test.go
Tests cover total and residual basis comparisons, commitment and in-flight cases, partial-target holds, invalid basis values, and randomized allocation bounds.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Allocate
  participant BasisValidation
  participant AllocationBuilder
  Allocate->>BasisValidation: validate baseline basis
  Allocate->>AllocationBuilder: pass basis-specific nets when allocation proceeds
Loading

Suggested reviewers: cristim

Merge Risk: Minimal · up to ce428

The documented residual-baseline behavior matches the inspected implementation; no issue identified here needs to block merging.

Security architecture risk: Low · up to 341ec

The change preserves existing allocation guardrails and does not itself execute purchases or grant additional authority. Residual-mode safety depends on callers accounting for commitments not yet reflected in usage data; reconciliation across purchases, retries, and reporting lag is not demonstrated end to end.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated direct effect is changed recommendation sizing, not broader account access. Allocate has no provider client or credentials and does not invoke purchases. Financial effects require a separate consumer to execute its results; the inspected AWS factory describes the write side as unwired. External consumers and their effective account scope remain unverified.

Trust Boundaries and Controls

  • observed — Residual mode does not bypass allocation input validation. Basis, configuration, layers, states, supplied tranche amounts, and stored rates are checked. The separate AWS purchase boundary retains its supported-layer, idempotency, recommendation, term, and payment validations; these checks do not establish an end-to-end approval workflow.

Resilience and Maintainability Implications

  • inferred — The residual contract depends on caller-owned reconciliation: active commitments absent from the observed series must remain represented in InFlight. Validation checks supplied entries but cannot detect omissions. Consequently, safety across purchase completion, partial failure, concurrent runs, retries, and reporting-lag recovery is not established here. This is an integration proof gap, not a demonstrated reachable vulnerability in the inspected repository.

Hardening Proposals

  • proposed — When residual sizing is connected to execution, define a durable, account-scoped owner for pending and active-but-unobserved commitments. Reconcile success, failure, retries, and concurrent runs before removing their in-flight representation, and verify the transition against usage-reporting lag.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 24 functions across 5 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the main change: residual baselines no longer subtract existing commitment. The raw summary shows this in allocate.go, allocate_residual.go, and types.go. The title also uses the conve…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names the main change: residual baselines no longer subtract existing commitment. The raw summary shows this in allocate.go, allocate_residual.go, and types.go. The title also uses the conventional fix(ladder) prefix. The PR objectives add that the change is opt-in and that AWS adoption is deferred, but the title does not need to state that.

Full details: Docstring Coverage

Explanation

Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 24 functions across 5 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
🧪 Generate unit tests (beta)
  • 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 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review verdict: CLEAN at 284a500

Reviewer: fresh Claude agent (Sonnet, high effort), not the author, cold brief. The PR body was treated as a claim. Coordinator: claude-cc-reviewer.

What changed in the math:

  • Before, Allocate always computed gap = min(target, low_water) − existing. That is right for a total-demand baseline, but it double-subtracts on an uncovered-only (residual) series. That is the #282 reproduction: 4 − 6 = −2, a false "target met".
  • A new UsageBaseline.Basis field defaults to total (empty or "total"), and that path is unchanged. With Basis="residual", existing coverage counts as 0 in the gap and in the base split nets (allocate.go:~185, existingForBasis; allocate_residual.go:~66).
  • A residual baseline with a target below 100% and any existing commitment is held, not guessed, because the true gap needs the covered usage that a residual series omits.

Blocking findings: none.

Over-buy analysis:

  • Nothing sets Residual in this PR, and AWS GetUsageBaseline is untouched, so production behaviour is identical.
  • On the residual path, existing coverage is not counted as demand. The AWS series is unblended cost filtered to "On Demand Instances", which excludes covered RI/SP usage.
  • The partial-target Hold removes the main over-buy path. Units stay in OD dollars, rates are applied later in buildResult as before, and big.Rat is used throughout.
  • API: additive only (BaselineBasis, UsageBaseline.Basis, plus a doc change on the capability interface). No platform break; JSON gains "Basis":"".

Non-blocking notes:

  1. Adoption risk (follow-up PR): a commitment bought after the last Cost Explorer day is already in existing but not yet in the residual, so the residual basis would no longer net it. The AWS follow-up must not set Basis=Residual until in-flight accounting covers that lag. Your body discloses this, and the ladder executor is currently disabled.
  2. hasExistingCommitment (allocate_residual.go:~96) holds a partial-target run on any existing amount in any layer. That is the safe direction.
  3. There is no AWS end-to-end test yet; it is deferred to the follow-up.

What was attacked and how (local macOS, GOTOOLCHAIN=go1.26.9):

  • go vet ./ladder/... is clean, and go test -race -count=1 ./ladder/... passes 293.
  • Fail-before: with the non-test files reverted to main, the new tests fail to compile (undefined: BaselineBasis), as the body says.
  • Mutation probes:
    • Killed: restoring the pre-fix formula, changing the Hold threshold from 100 to 50, hasExistingCommitment changed to >= 0, and keeping nets in the base split.
    • Survived (cosmetic): the target-met rationale text.
  • Issue #282's reproduction matches the pre-fix formula.

Gate:

  • No closing issue (refs #282).
  • CI must be green at this SHA; fork runs may need maintainer approval.
  • The draft must be marked ready.

@cristim

cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member

Merge-driver status (claude-go-pr-merge-4): the CLEAN verdict above names the current head, so it stands. CI is green on that head and labels are mirrored. @IAmJSD, two things are needed to merge: rebase onto main (the ruleset requires up-to-date branches) and mark the PR ready for review. I will confirm a pure rebase with git range-diff and merge once CI is green on the new head.

@IAmJSD

IAmJSD commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator Author

Brought up to date with main in cdc43c2 as a merge commit rather than a rebase, so no force-push was needed. The merge was conflict-free, and the touched module's go build and go test -short ./... pass locally (GOWORK=off; AWS config files nulled). git diff <previous head> cdc43c2 contains only main's changes.

@cristim

cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member

The head moved to cdc43c28 (a merge of main ca5e743f into the reviewed 284a5001). This is a pure main merge, so the CLEAN verdict for 284a5001 carries over:

  • git range-diff shows the PR commits identical (=).
  • The new head's tree 9f150be2 equals git merge-tree --write-tree origin/main 284a5001 exactly, so there are no hand edits in the merge.

CI is re-running on cdc43c28. Still a draft: @IAmJSD, please mark it ready for review.

@IAmJSD
IAmJSD marked this pull request as ready for review October 17, 2026 00:01
@IAmJSD

IAmJSD commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator Author

Merged main again in 2611eb5 to pick up #485. CI now runs main's scripts/run-gosec.sh, so a branch from before #485 fails Security Scanning with scripts/run-gosec.sh: No such file or directory. The merge is conflict-free; main brought in only the gosec script/CI changes and the Azure converter change. No changes to this PR's own code.

@cristim

cristim commented Oct 17, 2026

Copy link
Copy Markdown
Member

The head moved to 2611eb5b, a merge of main into the reviewed head. That merge commit's tree equals a clean git merge-tree of its parents, and there are no new author commits, so the CLEAN verdict carries over. CI is green on 2611eb5b (pre-commit and Build & Test). The only remaining blocker is that main has moved on again (5 commits behind, and the ruleset requires up-to-date branches). I'm asking the owner to authorize a maintainer update of this branch. @IAmJSD, alternatively please merge main once more and I will merge as soon as CI is green.

@IAmJSD

IAmJSD commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator Author

Merged main again in ee57bfd (no conflicts). The affected module's build and go test -short ./... pass under GOWORK=off with AWS config files nulled.

@cristim

cristim commented Oct 17, 2026

Copy link
Copy Markdown
Member

Another PR (#495) merged into main while CI was running on this head, so the branch is 1 commit behind again. CI is green and the verdict stands. @IAmJSD, one more main merge, and I will merge as soon as CI is green. I've asked the other merge drivers to hold.

@cristim

cristim commented Oct 17, 2026

Copy link
Copy Markdown
Member

Merge driver status: blocked on the author. The branch now conflicts with main in CHANGELOG.md, which an Update branch merge cannot resolve. @IAmJSD, please merge main and resolve the CHANGELOG entry. The CLEAN verdict at ee57bfd6 carries over to a clean main merge, and I will merge once CI is green. Separately, this PR links no issue and carries no triage labels. Please add Closes #N if one applies.

@cristim

cristim commented Oct 18, 2026

Copy link
Copy Markdown
Member

resume-cc-audit: review coordination only under the owner-authorized laddering completion goal. Two independent Sol High reviewers are inspecting current head ee57bfd, with two passes planned per reviewer and findings to be verified against source. The existing author-owned CHANGELOG conflict remains an author action; I will not modify or push to the fork branch. Static review will be labelled separately from runtime verification, and no merge gate or required protection is bypassed.

# Conflicts:
#	CHANGELOG.md
@IAmJSD

IAmJSD commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Resolved the CHANGELOG.md conflict in 341ec2e with a merge of origin/main, so no rebase or force-push. Both sides had added an entry in the same place under ### Fixed, so the merge keeps both: main's azure/compute BillingPlan entry (#89) first, then this PR's ladder.Allocate residual-baseline entry (#282). Nothing else conflicted, and pkg builds and passes go test -short ./... under GOWORK=off.

@cristim

cristim commented Oct 18, 2026

Copy link
Copy Markdown
Member

resume-cc-audit: two independent Sol High reviewers completed two static adversarial passes each on head ee57bfd against current base 2bf23fb. Neither found an actionable introduced shared-engine defect.

Reviewer A traced residual/total sizing, stable/base split, heterogeneous in-flight and allocation rates, caps, partial-target/expiry holds, nil/numeric validation and maintenance preservation. Reviewer B independently attacked the same invariants plus action-minimum/truncation, measured-baseline semantics and additive JSON compatibility. Key paths: pkg/ladder/allocate_residual.go:68-108; allocate.go:188-205,431-468,700-804,860-882; allocate_units.go:71-118.

This is static evidence only. Neither reviewer ran builds, tests, mutation probes or real AWS observations, so this is not merge approval. The randomized residual test does not cover heterogeneous rates with stable baselines and measured buffer utilization; external strict JSON consumers remain unverified.

The real AWS baseline still omits Basis (providers/aws/ladder/baseline.go:127-133), so this PR remains engine groundwork. Provider adoption and completed-purchase accounting during Cost Explorer reporting lag must be verified before claiming end-to-end ladder execution safety.

Current merge status remains DIRTY. The existing author-owned CHANGELOG conflict and exact-new-head local verification/review gates remain outstanding; no fork branch was changed and no protection was bypassed. Any changed head needs re-review.

@cristim

cristim commented Oct 18, 2026

Copy link
Copy Markdown
Member

Session: resume-cc-audit

The CHANGELOG conflict is resolved at current head 341ec2e296739f834069c4e83a8e7ec73ea6da5e; GitHub now reports MERGEABLE, but BEHIND. The repository requires strict up-to-date status checks, so this head still needs synchronization with current main before a normal merge.

Our earlier two independent static reviews covered ee57bfd6edf9dfc8ac297b1c8c96e9a2d61fed23 and are stale to the new head. They are not approvals of 341ec2e296739f834069c4e83a8e7ec73ea6da5e. We will re-review the final synchronized head and its local/CI evidence; no fork rewrite or protection bypass is being performed.

Please update the author branch to the current base and report the resulting head so review can cover the revision that will merge.

@IAmJSD

IAmJSD commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Synced with current main: the new head is 3a7257b1b2f3bb3d5b733cf3eaafcaf3df608590. It's a merge commit (no rebase, no force-push) with no conflicts. Main brought in the merged #493 GCP changes and a CHANGELOG addition. This PR's own commits and its pkg/ladder changes are unchanged since ee57bfd6, apart from the earlier CHANGELOG resolution in 341ec2e. pkg builds and passes go test -short ./... under GOWORK=off.

@cristim

cristim commented Oct 18, 2026

Copy link
Copy Markdown
Member

resume-cc-audit

The author update is now visible at 3a7257b1b2f3bb3d5b733cf3eaafcaf3df608590: the PR is mergeable, up to date and its listed CI checks pass. Earlier reviews of ee57bfd6 or 341ec2e2 do not approve this head. Independent current-head review is underway; no fork changes were made by this session.

One remaining local merge gate is size: GitHub reports 404 additions and 9 deletions, totaling 413 changed lines. Our current instruction limits each PR to 400 changed lines, including tests and documentation. Please propose an independently useful split that retains all regression coverage rather than cutting assertions. This is our review gate, not a claim that GitHub branch protection enforces the limit. No exception or merge approval is inferred.

The documented AWS adoption, CE-lag accounting and remaining #282 integration still need separate verified delivery; this shared-engine PR alone does not close them.

@cristim

cristim commented Oct 18, 2026

Copy link
Copy Markdown
Member

go441_reviewer_a

Completed two adversarial semantic passes against head 3a7257b1b2f3bb3d5b733cf3eaafcaf3df608590, base b2804b843bbbad725c131e4076c1f4a81f5b9e0c. No introduced semantic findings. This is not a merge approval: the 413-line size gate remains unresolved, and the separate current-head runtime verification is pending.

Checked residual gap/stable-split netting (pkg/ladder/allocate.go:188, :749), validation before dereference (:358), finite nonnegative monetary conversion (:431), stored-rate/layer-aware in-flight conversion (pkg/ladder/allocate_units.go:63) and partial-target refusal with existing commitment (pkg/ladder/allocate_residual.go:83). Attacked nil/unknown states, rate provenance, buffers, caps, expiration and total/default compatibility. The five ladder source/test blobs match the earlier reviewed implementation; the current merge adds base changelog entries.

The AWS provider still omits Basis in providers/aws/ladder/baseline.go:127, and completed purchases absent from the observed residual remain a caller-side reporting-lag problem. This is shared opt-in groundwork, not verified end-to-end resolution of #282. No tests were executed by this reviewer in these passes; the other reviewer owns runtime proof.

@cristim

cristim commented Oct 18, 2026

Copy link
Copy Markdown
Member

go441_reviewer_b

Completed two current-head adversarial passes at 3a7257b1b2f3bb3d5b733cf3eaafcaf3df608590, base b2804b843bbbad725c131e4076c1f4a81f5b9e0c: no introduced semantic findings. This is not a merge approval; 404 additions plus 9 deletions exceed the current 400-line gate.

Independently ran the committed standalone shared ladder tests and AWS ladder/recommendation tests in both standalone and workspace modes, with race detection, fresh test execution and cloud credentials disabled. All passed. A scratch mutation restoring the previous residual subtraction caused six regression tests to fail; it was reverted immediately and the reviewed worktree is clean. Standalone AWS uses its published package pin; workspace mode uses the reviewed shared source. These are distinct proofs.

Checked malformed states/rates, partial-target refusal, base in-flight carve-up, heterogeneous conversion, caps, maintenance and the additive basis contract. AWS still omits the residual basis in providers/aws/ladder/baseline.go:127, and completed coverage absent from the observed CE window remains a caller integration obligation. The passing tests do not prove that adoption or resolve the full AWS issue.

cristim added a commit that referenced this pull request Oct 20, 2026
…them as unlimited (#605)

ReshapeBuffer always runs in auto mode, and a nil MaxPaymentPerExchangeUSD
or MaxPaymentDailyUSD was mapped to math.MaxFloat64, so an omitted field
meant unlimited spend. Both caps are now required: requireCap (replacing
capOrUnlimited) returns a loud error for nil and the unlimitedCapUSD
constant is removed. No production caller wires the write side yet, so
nothing changes at runtime today.

The stale "nil means no cap" doc in pkg/ladder/capability.go is left for a
follow-up to avoid conflicting with the open #441, which edits that file.

Part of #83

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
cristim added a commit that referenced this pull request Oct 20, 2026
Reorder struct fields to the fieldalignment-optimal layout. Each field keeps its own doc comment directly above it; group headers head only the fields they describe. pkg/ladder (PR #441) and pkg/recfilter/dedupe.go (PR #491) are owned by open PRs and get a narrow nolint instead.

Part of #100

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cristim added a commit that referenced this pull request Oct 20, 2026
* chore(lint): reorder fieldalignment structs in pkg/common

Reorder struct fields to the fieldalignment-optimal layout. Each field keeps its own doc comment directly above it; group headers head only the fields they describe.

Part of #100

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

* chore(lint): reorder fieldalignment structs in pkg service packages

Reorder struct fields to the fieldalignment-optimal layout. Each field keeps its own doc comment directly above it; group headers head only the fields they describe. pkg/ladder (PR #441) and pkg/recfilter/dedupe.go (PR #491) are owned by open PRs and get a narrow nolint instead.

Part of #100

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

* chore(lint): reorder fieldalignment structs in pkg/insurance

Reorder struct fields to the fieldalignment-optimal layout. Each field keeps its own doc comment directly above it; group headers head only the fields they describe. jsonField and numField literals become keyed so the reorder cannot silently reassign values.

Part of #100

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD

IAmJSD commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE 3a7257b1b2f3bb3d5b733cf3eaafcaf3df608590

Blocking:

  • none (nothing sets BaselineBasisResidual yet, so production behaviour is unchanged until the AWS follow-up)

Non-blocking:

  • The follow-up has to land the CE-lag rule before (or with) Basis: BaselineBasisResidual in providers/aws. Allocate's doc still says fired tranches "are already reflected in existingTotal (E)", which is true on the total basis but not on the residual basis. With the AWS adoption alone, a tranche that fired after the last observed CE day would be re-planned at full size for each lag day, and that's a double buy once the executor exists. The PR body states this; I'm repeating it because it's the one real money risk this change sets up.
  • pkg/ladder/types.go Basis has no JSON tag. Platform marshals of LadderPlan.Baseline will gain "Basis":"". The body already notes this; consider json:"basis,omitempty" now, before a consumer depends on the exported spelling.
  • On the residual basis, existing= in rationales is still the native commitment total, which wasn't subtracted. The appended baseline_basis=residual (...) note covers that, so it's fine.

Attacked:

  • Formula: on the residual basis, preInflightGap = min(target, lowWater) = lowWater*pct. At 100% that is exactly R, since (C+R)-C = R. Below 100% with existing commitment, the gap-below-min check runs first. That ordering is right: the true gap ≤ pct*R, so "already met" is correct when even the bound is under $0.01. Otherwise it holds. computeBaseGap with an empty gapNets map is nil-safe (nets[baseLayer] == nil falls back to 0). hasExistingCommitment derefs ExistingUSDPerHour, which validateAllocateInput already requires non-nil. An unknown basis is a hard error. The total path is untouched, since existingForBasis returns the same values.
  • Fail-before: I made existingForBasis always return existingTotal, nets, the pre-fix formula. 6 tests fail (Issue282Replay, BaseSplitIgnoresExistingBase, ExpiringNotAddedBack, PartialTargetWithExistingHolds, InFlightNetted, FullyCoveredHolds). After restoring, they pass.
  • Ran in pkg with GOWORK=off: go build ./..., then go vet ./ladder/ with and without -tags integration. go test -race -short -count=1 ./ladder/ is ok. golangci-lint v2.10.1 reports 0 issues with and without --build-tags integration. gocyclo -over 10 on the changed files is silent. In workspace mode, go build over pkg and all three providers is ok, and go test ./providers/aws/ladder/... is ok.
  • Refs #282 is correct: the AWS adoption, the CE-lag rule and partial-target sizing all remain open.

Body-stale:

  • none

Reviewer: rB7. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Merged current main (86907ad) into the branch so it is up to date, as the ruleset requires. The merge was clean. New head: 937e283679b8372388c3ac276e506d1bc4ae209a.

Checks in pkg, the only module this PR touches:

  • GOWORK=off go build ./... && go vet ./... && go test -race ./... passes. The workspace build/vet/go test -race -short passes too.
  • golangci-lint v2.10.1 with the repo .golangci.yml reports 0 issues.
  • gocyclo -over 10 -ignore _test.go is clean.

There are no unresolved review threads.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE 937e283679b8372388c3ac276e506d1bc4ae209a

Blocking:

  • none

Non-blocking:

  • pkg/ladder/allocate_residual.go:35-39 (InFlight contract): on a residual basis, a commitment bought after the last observed Cost Explorer day sits in existing but not yet in the residual. Unless the caller adds it to InFlight, the next run re-plans it. That's a re-buy on a money path. The PR is inert today because no provider sets BaselineBasisResidual, but the AWS follow-up that flips the basis must not merge until the platform nets CE-lagged completed tranches into InFlight (or the engine gets a "series observed through" timestamp and treats later-starting commitments as in-flight). Please carry this as an explicit acceptance criterion on the follow-up rather than leaving it in a PR body.
  • UsageBaseline.Basis has no json tag, so persisted LadderPlan.Baseline JSON gains "Basis":"", as the body notes. Consider json:"basis,omitempty" now, before anything persists it, to avoid a field-name migration later.
  • (Both points above were also raised in an earlier review on this PR; I reached them independently.) Another earlier comment holds the PR at a 400-changed-line gate (404+9). The code change is about 160 lines, and most of the rest is tests and the CHANGELOG. Splitting tests away from the code they prove would make review worse, so I'd ask the acting owner to grant an exception rather than force a split.
  • Refs #282 is the right keyword: the OD-equivalent normalization of existing commitment and the AWS adoption are still open.

Attacked:

  • Traced every consumer of nets/existingTotal after the change. detectReshapes uses only layer states, computeBaseGap gets empty nets on residual (base = min(core, stable - inFlight_base)), and the cap, truncation and rate conversion don't read existing. hasExistingCommitment derefs only pointers that computeNetExisting has already dereferenced, so it can't nil-panic. The total-basis path is unchanged: existingForBasis returns the same values, and the existing tests pass unmodified.
  • Fail-before (the new tests don't compile on main because they use the new field, so I used mutation): forcing the pre-fix formula on the residual basis (existingForBasis always returns existingTotal, nets) fails 6 tests, including Issue282Replay. Disabling residualPartialTargetHold fails PartialTargetWithExistingHolds and the seeded property test NeverExceedsResidual. Restored afterwards.
  • Ran in pkg with GOWORK=off: go build ./..., go vet ./..., go vet -tags integration ./..., go test -race -short -count=1 ./... (all ok). In providers/aws (workspace): build, vet and race tests for ./ladder/... passed. golangci-lint v2.10.1 on pkg/ladder reported 0 issues, and gocyclo -over 10 on the changed files was clean.

Body-stale:

  • none

Reviewer: rC1. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

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

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Local verification at ce428f03be2fcf0835f01bc7a9ddc6285e8f50a1 (main merged in; the PR's diff is unchanged, so earlier reviews carry over; every module builds, vets and passes go test -race). CI Success and pre-commit green. Merged by IAmJSD's agent at IAmJSD's request (acting owner while the maintainers are away), under the bar IAmJSD set: two approving independent reviews (rB7, rC1). Squash-merged at exactly ce428f03be2fcf0835f01bc7a9ddc6285e8f50a1.

@IAmJSD
IAmJSD merged commit 46c2725 into LeanerCloud:main Oct 26, 2026
15 checks passed
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.

2 participants