Skip to content

refactor(config): add RampSchedule.CumulativePercent (631 C0) - #860

Merged
cristim merged 2 commits into
mainfrom
feat/ramp-cumulative-percent
Oct 13, 2026
Merged

cristim merged 2 commits into
mainfrom
feat/ramp-cumulative-percent

Conversation

@cristim

@cristim cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member

Scope

C0 of platform#631 (cumulative ramp sizing). Adds RampSchedule.CumulativePercent(step) (min(100, step*PercentPerStep); 100 for immediate) and makes GetCurrentCoverage call it, so there is one definition of cumulative ramp progress. No behavior change: nothing else calls the new method yet. Refs #631.

Evidence

  • go test ./internal/config: the existing TestRampSchedule_GetCurrentCoverage table stays green (equivalence), plus new tests for CumulativePercent (immediate, step 0, cap at 100, custom 3x40) and a no-drift test.
  • Unit tests only; no integration surface.

🤖 Generated with Claude Code

…mp-progress definition

GetCurrentCoverage now derives from it so later per-step sizing and the
coverage figure cannot drift apart.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cristim cristim added urgency/this-sprint Within the current sprint triaged Item has been triaged priority/p1 Next up; this sprint severity/high Significant harm impact/many Affects most users effort/xl Multi-week / refactor type/feat New capability 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 12 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 62 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-platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: aa3539df-09a0-4b5f-806f-08609dade6ef
📥 Commits

Reviewing files that changed from the base of the PR and between 74c3234 and 6d16bbd.

📒 Files selected for processing: 2
  • internal/config/types.go
  • internal/config/types_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

cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Gate verdict: CHANGES REQUESTED at 31a11ca

Finding (internal/config/types.go:291-292): GetCurrentCoverage is not bit-for-bit unchanged for Type == "immediate". Before, it returned baseCoverage itself. Now it returns baseCoverage * 100 / 100, which rounds:

  • GetCurrentCoverage(0.1694) gives 0.16939999999999997 (before: 0.1694)
  • GetCurrentCoverage(1.512) gives 1.5119999999999998
  • GetCurrentCoverage(1e-300) gives 1.0000000000000002e-300
  • GetCurrentCoverage(math.MaxFloat64) gives +Inf (overflow in x*100)

C0 is specified as a pure refactor whose proof is equivalence, so this is a behavior change on a function that feeds ramp sizing. Impact today is nil: GetCurrentCoverage has no non-test callers on main or at this head. Suggested fix: keep the early return in GetCurrentCoverage:

func (r *RampSchedule) GetCurrentCoverage(baseCoverage float64) float64 {
	if r.Type == "immediate" {
		return baseCoverage
	}
	return baseCoverage * r.CumulativePercent(r.CurrentStep) / 100
}

With that change applied locally, the differential harness reports 0 differences.

Evidence (local, git archive of the head, GOTOOLCHAIN=go1.26.9, macOS):

  • go test ./internal/config/ at the head: 777 passed.
  • Old-vs-new differential harness (throwaway test file, not committed). Grid: 6 types (immediate, weekly, monthly, custom, empty, IMMEDIATE), 23 PercentPerStep values (0, -0, fractional, 25/40/100/150, 1e9, negative, plus/minus Inf, NaN, MaxFloat64), 15 steps (MinInt, negative, 0, 1-5, 9, 52, MaxInt32, MaxInt), about 2,000 base values. Total: 4,185,540 cases. Results: 96,255 bit differences, all with Type == "immediate". Non-immediate types, including step 0, step > TotalSteps, k*pps > 100, custom ramps, zero values and NaN/Inf, showed 0 differences.
  • Callers: GetCurrentCoverage and CumulativePercent have no production callers. Nothing new is wired into production paths.
  • Mutation probes on the helper (14): step+1, step-1, clamp removed, clamp at 99 and at 101, Max in place of Min, immediate returns 0, immediate branch dropped, r.CurrentStep in place of step, GetCurrentCoverage passing CurrentStep+1 or TotalSteps, /100 dropped, TotalSteps in place of pps, immediate changed to weekly. All 14 were killed by the existing tests. The tests did not catch the rounding change above, because every case they cover is exact under float64.
  • Labels match feat(plans): plan steps resolve real recommendations and show real counts and prices (tier B of #609) #631. CI was still pending when this was checked.

Not merged. Re-gate after the fix.

GetCurrentCoverage returned base*100/100 for immediate schedules, which is
not exact in floating point. Return the base unchanged as before.

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

cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Gate verdict: APPROVED at 6d16bbd

The earlier finding is fixed. GetCurrentCoverage returns baseCoverage unchanged for Type == "immediate" again (internal/config/types.go:292-294).

Evidence (local, git archive of each SHA, GOTOOLCHAIN=go1.26.9, macOS):

  • Old-vs-new differential: compared origin/main GetCurrentCoverage against this head across 4,185,540 cases (6 types, 23 PercentPerStep values including 0, -0, negative, ±Inf, NaN and MaxFloat64, 15 steps from MinInt to MaxInt, about 2,000 bases). Result: 0 bit differences. The grid covers step 0, step > TotalSteps, k*pps > 100, custom ramps and zero values.
  • Fails before the fix: I ran the new TestRampSchedule_GetCurrentCoverageImmediateIsExact against the old head 31a11ca. It fails (expected 0.1694, actual 0.16939999999999997; expected MaxFloat64, actual +Inf). It passes at this head.
  • Package tests: go test ./internal/config/ passes at this head.
  • Mutation probes: 14 mutants on the helper, run on the previous head (the helper body has not changed since). The tests killed all 14: off-by-one in both directions, clamp removed, clamp at 99 and at 101, Max in place of Min, immediate branch changed or dropped, wrong step source, /100 dropped, among others. Reverting the new early return is caught by the regression test above.
  • Callers: GetCurrentCoverage and CumulativePercent have no non-test callers, so nothing new reaches production paths.
  • Merge state: CI is green (26/26) and mergeStateStatus is CLEAN at this SHA. The head is up to date with main, and the labels mirror feat(plans): plan steps resolve real recommendations and show real counts and prices (tier B of #609) #631.

Evidence type: unit-level differential and fixture tests. There is no real-account path to exercise, because the change has no production caller.

@cristim
cristim merged commit 48b28a7 into main Oct 13, 2026
26 checks passed
@cristim
cristim deleted the feat/ramp-cumulative-percent branch October 16, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/xl Multi-week / refactor impact/many Affects most users priority/p1 Next up; this sprint severity/high Significant harm triaged Item has been triaged type/feat New capability urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant