Skip to content

feat: interpolate the survival ramp instead of stepping it (#74 knee step 1) - #245

Merged
pshenok merged 1 commit into
mainfrom
feat/knee-step1-ramp-interpolation
Aug 8, 2026
Merged

feat: interpolate the survival ramp instead of stepping it (#74 knee step 1)#245
pshenok merged 1 commit into
mainfrom
feat/knee-step1-ramp-interpolation

Conversation

@pshenok

@pshenok pshenok commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Step 1 of the failure-knee work, on top of the step 0 baseline.

The problem

rpsAcceleration.milestones were a step function. At t=180 the multiplier jumped 1.6 → 2.0 and target RPS went 12.0 → 15.0 in a single frame. Step 0 measured the reference board's readable band at ~20 % wide in arrival rate, so a 25 % step vaults clean over it — at exactly the three-minute mark #74 complains about.

The change

The multiplier is interpolated linearly between milestones. Endpoints are unchanged — every milestone time still yields exactly its milestone multiplier, so the difficulty envelope is the same curve without the cliffs between its sample points.

Interpolating from 1.0 at t=0, rather than holding 1.0 until the first milestone, is deliberate: leaving that edge would keep one 30 % discontinuity, and the point is continuity everywhere.

Surge warnings still fire at the original milestone times — the "a surge just landed" beat is unchanged, only the arrival is spread out.

Measured — including where it fell short of the design's hope

stepped interpolated
worst single-frame jump in target RPS (700 s run) ~25 % 0.20 %
time with target RPS inside the readable band [5, 7] 26.9 s 29.0 s

The band effect is +8 %, not the 5× the design hoped for, and the numbers show why: the early milestones (t=60, t=120) land while target RPS is still ~2–4, well below the band, so smoothing them changes little. Reporting it rather than quietly moving the goalpost.

This step's real value is therefore narrower than pitched: it removes a discontinuity that would otherwise skip whatever band steps 2 and 4 build, and turns the ramp into a continuous, testable function. The band widening itself has to come from the knee (step 4) and the smoothed axis (step 2).

Verification

Interpolation hits every milestone exactly, is monotonic, holds past the last, survives 1-milestone / 0-milestone / zero-width-span configs, never moves target RPS >1 % per frame, crosses the old t=180 cliff smoothly, and still fires all six surge warnings at their original times. Mutation-verified: restoring the step function reddens three of these tests. 835/835 ×3, eslint clean.

…step 1)

The acceleration milestones were a step function: at t=180 the
multiplier jumped 1.6 -> 2.0 and target RPS went 12.0 -> 15.0 in a
SINGLE frame, which the smoother then chased down in under two seconds.
Step 0 measured the reference board's readable band at roughly 20% wide
in arrival rate, so a 25% step vaults over it — at exactly the
three-minute mark #74 complains about.

The multiplier is now interpolated linearly between milestones.
Endpoints are unchanged: every milestone time still yields exactly its
milestone multiplier, so the difficulty envelope is the same curve
without the cliffs between its sample points. Interpolating from 1.0 at
t=0, rather than holding 1.0 until the first milestone, is deliberate —
leaving that edge in place would keep one 30% discontinuity, and the
point is that the ramp is continuous everywhere.

The surge WARNINGS still fire at the original milestone times. The
player's "a surge just landed" beat is unchanged; only the arrival is
spread out, and announcing the threshold still tells them a new tier of
pressure is in effect.

Measured, and reported honestly: the worst single-frame jump in target
RPS across a 700-second run falls from ~25% to 0.20%, and every
milestone's multiplier is hit exactly. But the effect on the readable
band is SMALL — time with target RPS inside the band goes 26.9s ->
29.0s, +8%, not the 5x the design hoped for. The reason is visible in
the numbers: the early milestones (t=60, t=120) land while target RPS
is still ~2-4, well below the band, so smoothing them changes little.
The band widening has to come from the knee itself (step 4) and the
smoothed axis (step 2); this step's real value is removing a
discontinuity that would otherwise skip whatever band those steps build,
and making the ramp a continuous, testable function.

Tests: interpolation hits every milestone exactly, is monotonic, holds
past the last, survives a 1- or 0-milestone config and a zero-width
span, never moves target RPS more than 1% in a frame, crosses the old
t=180 cliff smoothly, and still fires all six surge warnings at their
original times. Mutation-verified: restoring the step function reddens
three of them. 835/835 x3, eslint clean.
@pshenok
pshenok merged commit 58d88e2 into main Aug 8, 2026
1 check passed
@pshenok
pshenok deleted the feat/knee-step1-ramp-interpolation branch August 8, 2026 21:02
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