feat(ypp): the three eligibility bars, with dated thresholds (TASK 39·2)
YouTube moves the goalposts, so the app stops modelling them as its own truth and shows progress against a threshold table that carries the date it was read. - `Models/YppProgress.cs` — pure: three metrics, per-criterion met, and `MeetsPublishedRule`, which encodes the real shape of the rule (subscribers AND either view route). The drawer says "x of 3 criteria met — YouTube reviews eligibility" and spells out the either/or, so "2 of 3" can't be misread. - `Services/YouTubeAnalyticsService.cs` — the two numbers only Analytics publishes: long-form watch hours (trailing 12 months, `creatorContentType==video`) and Shorts-feed views (90 days, `==shorts`). No rows means NO DATA, not zero. - **Thresholds are data with a publication date** (`YppThresholds.AsOfUtc`, shown in the drawer) and a test fails once that reading is more than 180 days old. The 2027-02-01 doubling (4,000h → 8,000h, 10M → 20M Shorts views) resolves from the date, not from an edit. - **No Analytics scope → no invented numbers:** the drawer explains the missing consent instead of drawing two empty bars as zero. Money stays behind 3·20's "Show monetary metrics" toggle. - Fan-funding tier (500 subs) demoted to a single muted line, since the three bars are the ad-revenue path. Tests: `YppProgressTests` — either/or eligibility, subscribers alone insufficient, Shorts as a qualifying route, bars clamp at 100%, the doubling date, the staleness guard, Analytics parsing (no rows = no data), and compact value formatting. FAST gate: 567 passed, 0 failed, 0 warnings.
This commit is contained in:
@@ -91,7 +91,22 @@ MyMistakes.
|
||||
- 2FA: `https://myaccount.google.com/signinoptions/two-step-verification`
|
||||
- AdSense: `https://support.google.com/youtube/answer/72851`
|
||||
|
||||
## Slice 2 (outline, queued)
|
||||
## Slice 2 — ✅ SHIPPED 2026-11-05 (the three bars)
|
||||
|
||||
Shipped as designed: `yt-analytics.readonly` behind `IWatchMetricsSource`, three bars (subscribers,
|
||||
long-form watch hours, Shorts views) against `YppThresholds.Tier2Now`, and one line —
|
||||
"x of 3 criteria met — YouTube reviews eligibility." Notes recorded with it:
|
||||
|
||||
- **The view routes are either/or**, so the line is qualified in the drawer ("subscribers plus watch
|
||||
hours, or subscribers plus Shorts views"); `YppProgress.MeetsPublishedRule` encodes that shape.
|
||||
- **Thresholds carry a publication date** (`YppThresholds.AsOfUtc`, shown in the drawer) and a test
|
||||
fails once that reading is older than 180 days — YouTube moves the bar and a stale bar must not look
|
||||
current. The 2027-02-01 doubling is data, not a code change.
|
||||
- **No analytics scope → no invented numbers**: the drawer says what is missing instead of drawing
|
||||
empty bars as zero.
|
||||
- Money stays behind the drawer's "Show monetary metrics" toggle (TASK 3·20).
|
||||
|
||||
## Slice 2 (original outline, for reference)
|
||||
|
||||
`yt-analytics.readonly` (+ re-consent) → `YouTubeAnalyticsService` behind `IChannelStatsProvider`
|
||||
(`ai.md`): long-form `estimatedMinutesWatched` (12-mo), Shorts-feed views (90-d), then velocity /
|
||||
|
||||
Reference in New Issue
Block a user