finishing AIs work because tokens

This commit is contained in:
2026-09-01 07:27:35 -07:00
parent 4a321b19ff
commit 8fa54d2de7
3 changed files with 53 additions and 2 deletions
+32
View File
@@ -130,6 +130,11 @@ GlobalHotkeyTests + HotkeyConfigTests (TASK 20), WebcamMenuGateTests (TASK 26),
`AudioPipelineTests.Mix_HonorsProviderGains…` + `RoundClipInteractionTests.Round_Clip_Corner_Is_Grabbable…`
are NOT regressions; see HANDOFF.md. Run test classes individually — the full-suite vstest run hangs.)**
Reward-event capture (monetization awareness, see the Monetization section) will add its integration
tests here when it ships: one real chat-poll payload containing all seven reward event types →
assert the persisted canonical `RewardEvent` rows (type + amount/currency/tier/memberLevel/participant
ids) round-trip into SQLite.
### Real-MainWindow tests MUST be hermetic (DB pollution bug)
The integration test boots a real `MainWindow` → `MainViewModel` → real `LayoutStore`
@@ -861,6 +866,33 @@ crooked.
how-tos / feature requests / manual-skimmers. Maintenance cadence = "when I get around to it" with
emergency patches; not a 24/7 service promise.
**Monetization awareness (built-in, ungated, free — 2026-09-01):** the app is monetization-aware by
design, for **every** creator, free and ungated (the only subscriber swap remains the branding-flash
removal above). It has three layers, all free — this is the product's differentiator, not a paid tier:
- **Reward-event capture (the data foundation).** The live-chat poll (`YouTubeChatService.Poll`)
already receives every reward event over `liveChatMessages` but today only decodes two
(`superChatEvent`, `newSponsorEvent`); the other five — `superStickerEvent`, `membershipGiftingEvent`,
`giftMembershipReceivedEvent`, `memberMilestoneChatEvent`, `giftEvent` — are silently dropped. The
plan: decode all seven into a canonical `RewardEvent` and persist each to a SQLite table
(`RewardEvents`: broadcastId, type, timestamp, amountMicros, currency, tier, memberLevelName,
gifter/recipient channelIds). `superChatEvents.list` (30-day lookback) backfills prior broadcasts.
This single feed is the foundation that Alerts, the session report, and the journey tracker all read.
- **Session / broadcast report.** A session is created at Go Live; the poll + End roll that session's
reward totals (new members, Super Chat $, stickers $, gifts, milestones). This is the in-app
replacement for the emailed external "stream activity report" — the incumbents (Streamlabs et al.)
email near-useless post-stream summaries; we track the same data natively and maintain it.
- **Journey tracker.** On sign-in/startup, pull current `channels.list?mine=true&part=statistics`
(`subscriberCount`/`viewCount`/`videoCount` — the current OAuth scopes suffice). Compute position
toward each YPP tier threshold and project an ETA curve from the creator's own
per-stream/per-day velocity (subs + watch hours). **YPP thresholds are versioned, date-aware DATA,
never constants** — the Tier-2 bar doubles for new applicants on **2027-02-01** (long-form 4,000 →
8,000 qualified hrs / 365d; Shorts 10M → 20M / 90d), while the Tier-1 fan-funding bar (500 subs /
3,000 hrs / 3M Shorts) is unchanged. Hardcoding the pre-2027 numbers would ship a wrong ETA.
Analytics-API scopes (`yt-analytics.readonly`, additive `yt-analytics-monetary.readonly`) are an
additive capability behind a seam (`IChannelStatsProvider`), not a v1 blocker — current-scope data
is the v1 baseline; the Analytics scopes would require an OAuth re-consent, deferred.
**What was rejected:** always-on watermark (obscurable — replaced by the flash), hard stream-time
cutoffs (the worst dead end — a stream dying mid-broadcast reads as broken, and YouTube streams
routinely run 2-4 hours), soft-limit nagging, freemium feature tiers, and donation-only (relies on