Skip to content

feat(040): H2 forecast presets + Claude billing cadence toggle#120

Merged
studert merged 4 commits into
mainfrom
040-h2-forecast-presets
Jun 12, 2026
Merged

feat(040): H2 forecast presets + Claude billing cadence toggle#120
studert merged 4 commits into
mainfrom
040-h2-forecast-presets

Conversation

@studert

@studert studert commented Jun 12, 2026

Copy link
Copy Markdown
Member

Summary

Evolves the Budget / Cost Forecast Simulation (spec 036) to model the org's actual H2 2026 plan, replacing the three generic presets, and adds a Monthly / Yearly billing toggle for the Claude seats line.

Presets (replace Conservative / Expected / Aggressive)

Lever H2 Gradual H2 Plan (default) H2 Accelerated
Claude Console API (metered) compound −25%/period compound −35%/period compound −50%/period
Claude seats +10/period @ 35% Premium +15/period @ 40% Premium +20/period @ 40% Premium
GitHub Copilot flat −1 seat/period −2 seats/period
Cursor / MS Copilot flat flat flat

Compound decline encodes "fade out very fast, down to almost zero — a few applications and a few users remain": from today's 42 active keys over the ~7 remaining FY2026 periods, the central plan lands at ≈2 keys. Rationale is documented in the engine's preset doc comment and the spec folder.

Billing toggle

  • Monthly = the live tier prices ($25 Standard / $125 Premium); yearly = $20 / $100 effective per month, implemented as CLAUDE_YEARLY_FACTOR = 0.8 on the loader-supplied prices (exact against the live tiers, and it keeps tracking them if they're edited).
  • The cadence is a procurement assumption, not a scenario lever: it persists across preset switches and is threaded into preset scoring, so tiles, ghost lines, and comparison rows stay like-for-like. Reset restores monthly. Yearly is modelled as a smoothed effective per-period rate, not a January lump sum.
  • Deliberate asymmetry on tile click: the edited ceiling still resets to the live one (unchanged 036 behavior), billing does not — switching scenarios shouldn't silently flip how seats are paid.

Scope

Engine + client + unit tests only — no schema or loader changes, feature stays read-only. Spec folder: specs/040-h2-forecast-presets/ (implementation plan — adversarially challenged before coding — and running implementation notes incl. design decisions / tradeoffs / open questions).

Verification

  • Unit: 623/623 — new hand-computed regression anchors on the frozen fixture (714 544 / 888 871 / 1 028 750 monthly; 770 311 h2Plan yearly), billing-factor coverage incl. a round-placement pin, stamping rules
  • Lint zero warnings · typecheck clean
  • Browser (Playwright vs live data): 24/24 — default H2 Plan, yearly toggle flips captions $25/$125 → $20/$100 and drops year-end $109,281 → $98,088, cadence persists across preset switches, reset restores Monthly + H2 Plan
  • Post-implementation simplify pass (4 parallel reviewers) applied: currentMonthlyCost delegates to toolCostAt(·, ·, 0) for claudeSeats, centralized claudeBillingFactor(), prop/memos tightened

🤖 Generated with Claude Code

studert and others added 2 commits June 12, 2026 13:03
Replace the Budget / Cost Forecast presets (Conservative / Expected /
Aggressive) with three H2 2026 migration scenarios — H2 Gradual / H2 Plan
(default) / H2 Accelerated — encoding the Console API fade-out, the Claude
seat ramp (+10/+15/+20 per period at 35-40% Premium), a very slow Copilot
fade, and flat Cursor / MS Copilot.

Add a Monthly / Yearly billing toggle to the Claude seats line: yearly
commitment prices seats at $20 std / $100 prem effective per month
(CLAUDE_YEARLY_FACTOR = 0.8 on the live tier prices, applied inside the
rounding). The cadence is a procurement assumption, not a scenario lever:
it persists across preset switches and is threaded into preset scoring so
tiles, ghost lines, and comparison rows stay like-for-like; reset restores
monthly.

Engine + client + unit tests only — no schema or loader changes. New
hand-computed regression anchors on the frozen fixture; billing-factor
coverage incl. a round-placement pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- currentMonthlyCost claudeSeats branch delegates to toolCostAt(tool, p, 0)
  instead of duplicating the blend + billing-factor math
- centralize the cadence->factor mapping as exported claudeBillingFactor()
- claudeBilling: useMemo -> plain derived const (primitive value)
- BillingToggle takes the tool whole instead of three projected props
- drop redundant Math.round before formatUSD0; footnote computes the
  discount % from CLAUDE_YEARLY_FACTOR instead of hardcoding 20%

623 unit tests, lint, typecheck, and the 24-check browser run all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 12, 2026 11:12
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ai-developer-hub Ready Ready Preview, Comment Jun 12, 2026 12:26pm

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the Budget / Cost Forecast Simulation (spec 036) to reflect the org’s H2 2026 plan by replacing the legacy Conservative/Expected/Aggressive presets with three H2 migration presets, and adds a Monthly/Yearly billing cadence toggle that discounts only the Claude seats line (via a 0.8 factor) while persisting across preset switches.

Changes:

  • Replace forecast presets with h2Gradual, h2Plan (default), and h2Accelerated, including updated unit-test anchors.
  • Add Claude seats billing cadence (monthly/yearly) to the engine and thread it through preset application/scoring and the client UI.
  • Add spec documentation (implementation plan/notes) and update CLAUDE.md “Recent Changes”.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit/scenarios/budget-forecast.test.ts Updates preset expectations and adds billing-factor coverage + regression anchors.
src/lib/scenarios/budget-forecast.ts Introduces H2 preset keys/values and Claude seats billing factor support in projection math and preset input stamping.
src/app/scenarios/budget-forecast/budget-forecast-client.tsx Re-keys UI to new presets and adds a Claude billing toggle that persists across preset switches and affects scoring.
specs/040-h2-forecast-presets/implementation-plan.html Adds the written implementation plan/spec for the change set.
specs/040-h2-forecast-presets/implementation-notes.html Adds running notes/tradeoffs/verification record for the implementation.
CLAUDE.md Documents spec 040 in the repository “Recent Changes” section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1219 to +1223
<BillingToggle
tool={tool}
billing={params.billing ?? "monthly"}
onChange={(billing) => onChange({ billing })}
/>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in c3fff2b — the control call site now normalizes monthly back to undefined (billing: billing === "yearly" ? "yearly" : undefined), preserving the "undefined ≡ monthly" rule, and the toggle guards no-op clicks so the already-active option no longer mutates state. Same normalization pattern as the burn-cap slider's "No cap" → undefined.

Comment on lines +1263 to +1266
<ToggleButton
active={billing === "monthly"}
onClick={() => onChange("monthly")}
>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in c3fff2bonClick now guards on a cadence change (billing !== "monthly" && onChange(...)), so clicking the active Monthly is a no-op and the plan stays on its preset. Added a browser regression check for exactly this (no-op Monthly click keeps the H2 Plan tile active).

Comment thread src/app/scenarios/budget-forecast/budget-forecast-client.tsx
Comment on lines +1276 to +1279
<p className="mt-1.5 font-mono text-[10px] uppercase tracking-wide text-faint">
{formatUSD0((tool.stdPrice ?? 0) * factor)} std ·{" "}
{formatUSD0((tool.premPrice ?? 0) * factor)} prem / seat / mo
</p>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in c3fff2b — restored Math.round at the display boundary with a comment noting formatUSD0's integer-cents contract. Agreed that relying on Intl's float rounding would be fragile if a discounted tier price ever lands on fractional cents.

- guard no-op billing-toggle clicks so clicking the active cadence
  doesn't mutate state / mark the plan Custom
- normalize monthly back to undefined at the control call site
  (undefined === monthly, keeps params deep-equal to pristine presets)
- round discounted tier prices to integer cents before formatUSD0
  (its documented contract) instead of relying on Intl float rounding

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…5 keys

User review of the open questions: ~5 remaining Console keys at FY-end is
the realistic 'a few applications and a few users' target (not ~2), and
the monthly billing default stays.

- h2Gradual api: compound -25% -> -15%/period (~13-14 keys from 42 over 7)
- h2Plan     api: compound -35% -> -25%/period (~5-6 keys)
- h2Accelerated unchanged at -50% (~0.3 keys)

Unit anchors recomputed by hand: 719066 / 892744 / 1028750 monthly,
774184 h2Plan yearly; strict ascending ordering preserved. Spec plan and
notes updated; open questions marked resolved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@studert

studert commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Post-review tuning per the author's answers to the two open questions in the implementation notes (e2e2b7f):

  1. API fade rates: the central plan should leave ~5 Console keys at year-end, not ~2 — re-tuned the ladder to −15 / −25 / −50 %/period (≈ 13–14 / ≈ 5–6 / ≈ 0.3 keys from today's 42 over the 7 remaining periods). Unit anchors recomputed by hand; strict ascending ordering preserved.
  2. Billing default: stays monthly — confirmed, no change.

All checks re-run green (623 unit tests, lint, typecheck).

@studert studert merged commit a091864 into main Jun 12, 2026
7 checks passed
@studert studert deleted the 040-h2-forecast-presets branch June 12, 2026 12:31
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