docs(commercial): one source of truth for the money — prices, entitlement, channels

The commercial plan was spread over five documents written in five different weeks,
and they contradicted each other: product.md sold the Store, decisions.md called the
Store dead then re-opened, Distribution.md (736 lines) still described Polar as a
download host, MARCOM.md quoted "no subscription" next to a paid tier, and README.md
promised "free forever". An outsider could not tell what ships.

docs/ai/commercial.md is now the only place money is decided: free = whole app at a
921,600 px / 30 fps output profile covering the recording as well as the stream; Pro =
$10/mo or $400 lifetime through Polar, key bound to the buyer's YouTube channel ID via
a claim page, 2 activations, 7–14 day lease with offline grace, fail closed, never
downgrade a running stream; one portable zip + winget primary, Steam and the Store
parked; Azure Trusted Signing (~$9.99/mo), no EV; Founding 200 promo; ~$135/yr costs;
anti-piracy posture and what is permanently rejected.

Everything else now points at it instead of restating it:
- product.md — money sections replaced with pointers; packaging rewritten to
  winget-first, Store parked; signing updated to Trusted Signing.
- decisions.md — graveyard with cause of death for free-forever, the Store ordering,
  the updater, and the 2026-10-30 reversal of the quality-ceiling rejection.
- Distribution.md — rewritten to release mechanics only (artifact, GitHub Releases,
  winget manifest, signing, checklist, takedown): 736 → 120 lines.
- TASKS.md — TASK 54 rewritten, TASK 48's route settled, TASK 10 superseded, five new
  rows (entitlement seam, output-profile gate, licence UI, system messages, packaging).
- README.md — "free forever" replaced with the real split.
- capture.md — obs-backgroundremoval is GPL-3.0 and so licence-INCOMPATIBLE since the
  proprietary EULA; the old "compatible" line was falsified by that change.
- TASKS/task-10, task-48, task-51, task-54 — superseded-banner at the top of each, so
  none of them reads as current policy.
- HANDOFF.md — rewritten: plan settled, next code unit is the entitlement seam.

MARCOM.md and MONETIZATION.md (gitignored) were corrected in place: policy pointer at
the top of each, the flash removed from every live claim, the Polar fee break-even
corrected to ~$900/mo, and the projections flagged as written against a dead model.
This commit is contained in:
2026-10-31 08:32:25 -07:00
parent 90d5140906
commit 7827d239e2
14 changed files with 445 additions and 854 deletions
+26 -30
View File
@@ -1,40 +1,36 @@
# HANDOFF — 2026-10-30 (scoreboard built to the polling policy; two wiring items left)
# HANDOFF — 2026-10-31 (commercial plan settled in docs; next code unit is the entitlement seam)
## State
- Branch `main`. The audio dock is shipped and pushed. **The scoreboard is built** in ten units,
local commits only: tallies (`Models/ScoreboardState`, session-scoped), lifecycle
(`ScoreboardRecorder`: start clears, End freezes), layout (`Models/ScoreboardLayout`: coupled
edges resolved at render time, shrink-then-wrap, never scroll), renderer
(`Services/Compositor/ScoreboardRenderer`: plate + text colour + opacity + 14–24px, cached),
tile selection (`Models/ScoreboardTiles`, opt-in, money per currency), the cached presenter, the
layer itself (`SourceType.Scoreboard`, strip geometry, resolver case), the properties panel
(eight fact switches + colours + plate + size, theme widgets only), the Analytics scope
(`yt-analytics.readonly`, incremental, `HasAnalyticsScope`), and the polling policy
(`Models/ScoreboardCadence`).
- Fixed on the way: the chat feed now reaches the tallies (the recorder had no caller).
- Branch `main`. Pushed through `c72b61b`; **`90d5140` + this commit are local only** (push at a
checkpoint, not per commit).
- **Commercial plan is settled and written down**: freemium (free = whole app at a 921,600 px /
30 fps profile, stream **and** recording), Pro = $10/mo or $400 lifetime through **Polar** (key
bound to the buyer's YouTube channel ID via a claim page, 2 activations, 7–14 day lease), one
portable zip + **winget** as the primary channel, **Steam and the Store parked**, Azure Trusted
Signing, Founding 200 promo. New single source of truth: [`docs/ai/commercial.md`](docs/ai/commercial.md).
- Docs consolidated this unit: `product.md` (money section → pointer), `decisions.md` (banners +
history), `index.md`, `ai.md`, `README.md`, `Distribution.md` (rewritten to release mechanics,
736 → 120 lines), `TASKS.md` (five new rows), `capture.md` (GPL line falsified by the proprietary
EULA), plus gitignored `MARCOM.md` / `MONETIZATION.md`. Site repo: `AGENTS.md`, `README.md`,
`build-this.md`.
- Scoreboard: built, unchanged from the last handoff (HTTP providers + goal inputs still missing).
## Next action
1. **HTTP providers** behind the cadence policy: watch hours (`reports.query`,
`metrics=estimatedMinutesWatched`) and subscriber count (`channels.list?mine=true&part=statistics`),
both behind an interface with a fake for tests, plus the timer that calls
`ScoreboardCadence.Due(...)` and writes the values into `ScoreboardTiles`.
2. **Goal-target inputs** in the properties panel (the tiles read `SubscriberGoal`/`WatchHourGoal`
but nothing sets them yet).
3. **On-screen check** of the strip: one line at 24px, plate/opacity, and the edge swap against the
social bar.
1. **Entitlement seam** — `IEntitlement` over Polar activate/validate/deactivate, channel-ID match,
2 activations, lease + offline grace, `--activate LCYT-…` CLI, fail closed. One Good Dog test.
2. Then the **OutputProfile gate** (one profile consumed by both the stream encoder and the
recorder; greyed tier entries; never downgrade mid-stream), the licence UI, and system messages.
3. Scoreboard HTTP providers + goal inputs whenever the creator queues them.
## Landmines
- **Not every hex is a theme colour.** `BorderColorPalette` and the chat/socials config defaults
are USER DATA — they keep their literals. On-stream graphics now come from `OutputPalette`,
never from a literal or from app resources (the pump thread must not touch them).
- A red settings control is a bug now — red means live/record.
- **Nothing may gate a feature.** The only paid delta is the output profile. `ShowBrandFlash` stays
`false` and entitlement must never enable it.
- **The site publishes the model, never the numbers** — and its CTA ("Coming soon to the Microsoft
Store") stays until the creator says the download exists.
- **No self-updater, by policy**: `winget upgrade` + a version banner. `StorePackagingTests` asserts it.
- Pre-existing: the **full test suite hangs** (WASAPI teardown). Per-class runs are the way.
## Pending
- **Launch and eyeball**: fonts render (pack-URI resolution cannot be proven in the test host),
the blue accent, blue-staged / red-live tiles, and mono telemetry.
- Vertical-tier camera check; webcam-cadence take in the failing geometry.
- Not every hex is a theme colour — `BorderColorPalette`/chat defaults are USER DATA; on-stream
graphics come from `OutputPalette`. A red settings control is still a bug.