Files
civitai__civitai/docs/testing
Justin Maier fe67de4633 fix(monetization): put every monetization gate on the creator score, at 10k (#4640)
* fix(monetization): gate on the creator score the account page shows

Monetization and the early-access ladder compared against `User.meta.scores.models`,
the per-category models sub-score, while `/user/account` puts `scores.total` under the
words "Creator Score" and article 34394 tells creators to read the floor there. Both
numbers are called "creator score" in user-facing copy, so a creator could see 53,143
on their own account page and be told by the gate that theirs is 4,883.

Measured on the prod replica: 45,216 accounts clear 10,000 on `total` and not on
`models`, and 21,438 more clear the early-access rung of 40,000 the same way. Three
creators reported it in the comments on article 34394 within eight days; a fourth
report was answered with "that's an odd one" and was this same bug — that account was
124 points short of the rung on `models` behind a displayed score of 678,565.

- `creatorScoreFromMeta` moves to `src/shared/utils/creator-score.ts` and reads
  `scores.total`, so the main app's pricing gate and both early-access ladders read one
  definition. It stays fail-closed on absent or malformed meta.
- Creator Studio's `getModelsScore`/`resolveModelsScore` become
  `getTotalScore`/`resolveTotalScore`, moving the spoke's pricing gate and its
  early-access display with the main app. The moderator simulator cookie keeps its name
  so live simulator state survives. The spoke's separate aggregate `getCreatorScore`
  (sales, Creator Program) is untouched.

Not changed here, and deliberately: 424 accounts pass on `models` and sit under 10,000
on `total`, plus 138 at the early-access rung. Both groups are accounts whose
`reportsAgainst` penalty pulls the total under a models score that already cleared, so
they lose access the day this ships. Whether to grandfather them is Justin's call and
is not folded into this diff.

The two `creatorScoreFromMeta` tests are named for the decision rather than the
behaviour, because a later reader has no way to tell a deliberate switch from a typo.
Reverting the helper to `scores.models` fails nine tests in that file, reading
"expected 4883 to be 53143".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BrgCPUR9TacrvsYNRv9c3

* feat(monetization): open early access and sales at the same 10k creator score

Follows the field alignment in the parent commit with the number. Justin: "we just
need EA access to open at 10k total score and scheduled sale to open at 10k total
as well".

- Early access entry rung 40,000 -> 10,000, in `EARLY_ACCESS_CONFIG` and in the
  Creator Studio mirror of it, for both the day ladder and the concurrent-version
  ladder. The upper rungs are untouched: score still buys longer windows and more
  simultaneous versions, it just no longer decides whether you get early access at all.
- The sale gate reads the creator score (`scores.total`) instead of the spoke's
  aggregate `GREATEST(sum of categories, total)`. A sale is monetization, so it was
  the one monetization gate not reading the number the account page shows.

Measured on the prod replica: early access goes 7,953 -> 60,171 eligible accounts,
the same population as monetization, which is the point — one number to explain
rather than two. 52,306 gain it. 88 lose it and 46 lose the ability to schedule a
sale, all of them accounts whose `reportsAgainst` penalty pulls `total` under a score
that previously cleared. That is the same trade approved for the parent commit.

The ladder tests read their rung values from `EARLY_ACCESS_CONFIG` rather than
hardcoding them, so the entry rung moved without touching an assertion — which is
what that indirection was for, and is why it is worth keeping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BrgCPUR9TacrvsYNRv9c3

* docs(monetization): stop the ladder comment claiming a rule it does not hold

Review findings on the commit beneath this one, plus a doc earned by the CI
trouble on this branch.

The comment I added to EARLY_ACCESS_CONFIG said the entry rung matching the
pricing floor meant "one number to explain rather than two". The number is
shared; the rules behind it are not, and a reader trusts a sentence in
constants.ts more than they trust a PR body. It now says what is true: the
figure is deliberate, the two are separate constants nothing keeps in step, and
clearing this rung is not the same permission as clearing the pricing floor.

Justin reviewed what each floor actually permits and chose to accept it as it
stands, so this is a comment correction rather than a behaviour change.

Also:
- The Studio's score simulator offered 40,000 / 90,000 / 250,000 — every preset
  cleared the old entry rung, so the no-access state, the one case a simulator
  exists to show, had no preset at all. Now 9,999 / 10,000 / 90,000 / 250,000,
  which probes the boundary from both sides.
- Rebuilt a sentence in monetization-rules.md that I had left with two dangling
  "so" clauses, hanging the tier-simulator claim off a premise that does not
  support it. That claim holds because the ladder is score-based, not because
  the floor is high.
- New docs/testing/reading-ci-results.md. Every workflow run on this branch is
  against a commit three pushes back, and `gh pr checks` reports "no checks
  reported" rather than naming the commit it is answering about — a green that
  is real, correctly obtained, still visible, and attached to a diff that no
  longer exists. The doc gives the SHA-scoped commands, the count to compare
  against, and an unconfirmed hypothesis that force-push may not re-trigger
  either CI system here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BrgCPUR9TacrvsYNRv9c3

* docs(testing): replace the CI hypothesis with what the next push measured

Pushing a real commit answered it, and split it in two. Tekton skipped all three
force-pushes and fired on the first normal push; GitHub Actions has not fired
since the branch's first push, including on that normal one. So force-push
explains Tekton and does not explain Actions.

The part worth the doc: after that push `gh pr checks` reported "Passed: 2,
Failed: 0" while 13 check-runs had never run. Nothing in that output is false
and nothing in it looks absent. Earlier the same command on the same PR said
"no checks reported" while four passing runs existed against an older commit.
It answers about what it found, never about what should have been there — so
the rule is to count against a known number, per mechanism, by SHA.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BrgCPUR9TacrvsYNRv9c3

* docs(testing): retract the force-push rule — a later push refuted it

I wrote that force-push does not re-trigger Tekton and that a normal push does.
Three amend-force-pushes producing nothing and a normal push producing Tekton
was a real correlation, and it was not a cause: a rebase plus force-push has
since produced Tekton as well. The shape of the push does not explain it.

What survives is the part that matters and is still measured: GitHub Actions
fired once on this branch's first push and never again across six pushes of
three shapes, which is why `gh pr checks` here can report a pass over jobs that
never ran. What goes is the rule I offered for planning around it.

Leaving the refuted version in place would have been the exact failure this file
exists to warn about — a claim that is real, correctly obtained, and no longer
true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BrgCPUR9TacrvsYNRv9c3

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 19:42:19 -06:00
..