Skip to content

test: golden valuation fixture shared with recoupable/api#44

Open
sweetmantech wants to merge 1 commit into
mainfrom
test/valuation-golden-fixture
Open

test: golden valuation fixture shared with recoupable/api#44
sweetmantech wants to merge 1 commit into
mainfrom
test/valuation-golden-fixture

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Part of recoupable/chat#1850 (video/experience parity, item 2 — valuation derivation guard).

Why

The catalog valuation model is intentionally implemented twice: lib/valuation/computeCatalogValuation.ts here (the /valuation card computes its band client-side for the progressive in-card state) and lib/catalog/computeValuationBand.ts in recoupable/api. The constants are mirrored by comment-discipline only — nothing fails if one side drifts. This PR adds the guard.

What

  • lib/valuation/__tests__/fixtures/valuation-golden.json — canonical inputs → expected band cases derived independently from the published formula ($0.0035/stream, gross-ups 1.25/1.4/1.6, NLS = gross x 0.85 x 0.75, multiples 10/13/16, age = round(ms/365.25d) clamped >= 1, default 5y). Cases: the real verified 16.3B-stream catalog (age fallback), zero streams, a 10y catalog aged from its release date, and the 1y age clamp. The fixture's mid key maps to this repo's central.
  • lib/valuation/__tests__/valuationGoldenFixture.test.ts — runs computeCatalogValuation against every case, asserting to within one cent. GREEN on first run against the existing implementation (zero divergence today).

Lockstep rule: this fixture's twin lives at api/lib/catalog/__tests__/fixtures/valuation-golden.json (recoupable/api#765) and the two files must stay byte-identical (SHA-1 a2c9737f167a25e3589b5d53fa4bf832d4f1e0bd). Any model change must update the fixture in BOTH repos in the same coordinated change, or one repo's CI goes red — which is the point.

Follow-up (out of scope): extract a true shared package so the formula exists once; until then this fixture is the divergence tripwire.

Verification

  • pnpm test — 21 files / 71 tests pass (4 new)
  • pnpm build — passes (route table generated). Two local-env notes, both pre-existing on clean origin/main and unrelated to this diff: (1) local pnpm 9 rejects the committed pnpm-10-style pnpm-workspace.yaml ("packages field missing or empty"), worked around with --ignore-workspace; (2) the build requires NEXT_PUBLIC_PRIVY_APP_ID (deliberate fail-closed gate in contexts/PrivyAuthProvider.tsx) — set to the public value inlined in the live site's client bundle.

Siblings

🤖 Generated with Claude Code


Summary by cubic

Add a shared golden fixture and test to guard the catalog valuation model from drifting between marketing and API. CI now verifies computeCatalogValuation matches expected bands to the cent using the same JSON used in recoupable/api.

  • New Features
    • Added lib/valuation/__tests__/fixtures/valuation-golden.json with canonical cases (5y age fallback, zero streams, 10y from release date, 1y age clamp). Must stay byte-identical to api/lib/catalog/__tests__/fixtures/valuation-golden.json.
    • Added lib/valuation/__tests__/valuationGoldenFixture.test.ts to assert low/central/high within $0.01 for each case; fixture mid maps to central.
    • Supports recoupable/chat#1850 (valuation derivation guard).

Written for commit ea158ec. Summary will update on new commits.

Review in cubic

Guards the twin implementations of the catalog valuation model
(computeCatalogValuation here, computeValuationBand in api) against
silent divergence: a byte-identical fixture JSON is committed in both
repos and each repo's CI asserts its implementation reproduces every
case to the cent (recoupable/chat#1850).

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

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
marketing Ready Ready Preview Jul 7, 2026 11:31pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@sweetmantech, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ce097aaa-7e64-4714-b8bd-adf3ead1697f

📥 Commits

Reviewing files that changed from the base of the PR and between f9862ee and ea158ec.

📒 Files selected for processing (2)
  • lib/valuation/__tests__/fixtures/valuation-golden.json
  • lib/valuation/__tests__/valuationGoldenFixture.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/valuation-golden-fixture

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/valuation/__tests__/fixtures/valuation-golden.json">

<violation number="1" location="lib/valuation/__tests__/fixtures/valuation-golden.json:2">
P3: The formula description's `msSince(earliestReleaseDate) / 365.25d` notation skips the ms‑to‑days conversion factor (86400000). Since this fixture is the canonical reference shared verbatim across two repos, a reader re‑implementing from the description alone could mis‑compute the age. Suggest `msSince(earliestReleaseDate) / (365.25 * 86400000)` (or `daysSince(…) / 365.25`) to make the unit conversion explicit.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@@ -0,0 +1,61 @@
{
"description": "Golden valuation-band cases shared verbatim between recoupable/api (lib/catalog/computeValuationBand.ts) and recoupable/marketing (lib/valuation/computeCatalogValuation.ts). The two copies of this file must stay byte-identical, and each repo has a test asserting its implementation reproduces every case to the cent. If a test fails, the implementations have diverged: fix the code or update this fixture in BOTH repos in the same change. Formula: annualGross = (totalStreams / catalogAgeYears) * 0.0035; band = annualGross * grossUp{1.25,1.4,1.6} * (1 - 0.15) * (1 - 0.25) * multiple{10,13,16}; catalogAgeYears = round(msSince(earliestReleaseDate) / 365.25d) clamped to >= 1, defaulting to 5 when earliestReleaseDate is null. Band keys here are low/mid/high; marketing names the middle value 'central'.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The formula description's msSince(earliestReleaseDate) / 365.25d notation skips the ms‑to‑days conversion factor (86400000). Since this fixture is the canonical reference shared verbatim across two repos, a reader re‑implementing from the description alone could mis‑compute the age. Suggest msSince(earliestReleaseDate) / (365.25 * 86400000) (or daysSince(…) / 365.25) to make the unit conversion explicit.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/valuation/__tests__/fixtures/valuation-golden.json, line 2:

<comment>The formula description's `msSince(earliestReleaseDate) / 365.25d` notation skips the ms‑to‑days conversion factor (86400000). Since this fixture is the canonical reference shared verbatim across two repos, a reader re‑implementing from the description alone could mis‑compute the age. Suggest `msSince(earliestReleaseDate) / (365.25 * 86400000)` (or `daysSince(…) / 365.25`) to make the unit conversion explicit.</comment>

<file context>
@@ -0,0 +1,61 @@
+{
+  "description": "Golden valuation-band cases shared verbatim between recoupable/api (lib/catalog/computeValuationBand.ts) and recoupable/marketing (lib/valuation/computeCatalogValuation.ts). The two copies of this file must stay byte-identical, and each repo has a test asserting its implementation reproduces every case to the cent. If a test fails, the implementations have diverged: fix the code or update this fixture in BOTH repos in the same change. Formula: annualGross = (totalStreams / catalogAgeYears) * 0.0035; band = annualGross * grossUp{1.25,1.4,1.6} * (1 - 0.15) * (1 - 0.25) * multiple{10,13,16}; catalogAgeYears = round(msSince(earliestReleaseDate) / 365.25d) clamped to >= 1, defaulting to 5 when earliestReleaseDate is null. Band keys here are low/mid/high; marketing names the middle value 'central'.",
+  "cases": [
+    {
</file context>

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