docs: purge the dead $29/$49 + Polar model from every tracked file, add the Y1 forecast

The pricing ruling landed twice (2026-09-21 one-time, then 2026-09-27 Store IAP
$10/mo + $400 lifetime) and the map never caught up. Six tracked files still told
a future session that billing was Polar and the price was $29/$49. A stale memory
map is worse than a stale comment: it is the file every session trusts, and this
one was actively steering work toward a deleted provider.

MONETIZATION.md (gitignored, so not in this commit) was rebuilt first:
- "Revenue projections" now carries a modelled Year 1 forecast —
  pessimistic $4.0K / base $15.4K / optimistic $53.3K net, ~$22K weighted.
  Funnel is installs -> 35-45% activate -> 1.5-3% of active users pay.
- Three findings recorded: Year 1 is ~97% lifetime transactions (subs net $392
  of $15.4K, so MRR is not a Year-1 planning input); conversion dominates price
  (~1pp of conversion = ~$7K net, and ADA 6(h) locks $10 anyway); subscriber
  churn moves Year 1 by under $200 and is a Year-2 problem.
- Break-even restated for $400: $25K net = 74 lifetime buyers, not 862.
  The price cut the volume requirement ~10x and raised the skill requirement
  to match.
- Market sizing willingness-to-pay row rewritten. The 100K-400K TAM was
  price-bound to $29-49 and is wrong at $400; revised ~20K-60K, flagged as an
  estimate rather than a sourced number.
- Flagged a real contradiction: $500K ARR needs ~4,900 concurrent subscribers,
  so the Exit section's ARR multiples do not describe what Years 1-3 produce.
  The defensible asset there is lifetime cash flow, not ARR.

Tracked files corrected to match:
- ai.md: paid-delta, pricing and billing bullets rewritten; Polar product id,
  org id, LCYT- key prefix and LLAMAFOUNDER/LLAMA50 marked as deleted;
  15% share + net-after-tax recorded with the ADA 6(b)(i) citation.
- TASKS.md: catalog row retitled as a teardown; the "still to verify — the
  price is not decided" note closed (it contradicted the ruling 20 lines
  below it); the OverlayHost "Polar unlocks alerts" open question marked
  resolved; Polar file-hosting deliverable removed from the release build.
- task-10: reframed as a teardown. Steps 4-5 marked as surviving, 1-2-3-6-7 as
  deleting, 8 as a compliance action (Velopack downloads AND executes, which
  Store policy 10.2.2 does not permit).
- task-36 item 5 (license-expiry reminders) struck — no key, no expiry, no
  lapse under Store IAP, so there is nothing to remind anyone about.
- Distribution.md 4.2 / 4.4 / 4.5 marked obsolete; 4.5's "already implemented"
  corrected, since PolarLicenseService is being deleted rather than shipped.
- README: "one-time license" -> "paid tier".

Historical Polar sections are retained deliberately — the reasoning is reusable
(merchant-of-record, fee comparison), only the conclusions are dead. Each is now
labelled so it cannot be mistaken for the plan.

No code touched.
This commit is contained in:
2026-10-02 20:56:37 -07:00
parent d95a23c6fb
commit f3fed0a2a8
7 changed files with 145 additions and 70 deletions
+55 -25
View File
@@ -1,12 +1,36 @@
# TASK 10 — Monetization: watermark-only one-time license + Polar billing
# TASK 10 — Monetization: watermark-only paid delta (branding flash)
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
**Goal:** a **paid tier that removes the branding flash and nothing else.** Every feature is free
— Alerts, social bar slots, voice filters, TRAX, recording, analytics. The free tier is the *full*
app. ⛔ **There is no feature gating, ever** — revenue argument, not taste: the free tier's reach
is the funnel, and the flash is an ad running inside other people's content, so a free user with a
flash every 30–60s is already paying in exposure.
**Goal:** a **one-time perpetual license** via Polar.sh that removes the branding watermark. All features
are free — the only difference between free and paid is the watermark. (Model changed 2026-09-21 from
annual subscription to one-time "own it": $29 founder / $49 list lifetime. See `MONETIZATION.md` →
Pricing for the reasoning.)
**⚠️ STATUS: THIS IS A TEARDOWN, NOT A BUILD (2026-09-27).** The billing provider is
**Microsoft Store IAP**, not Polar. Everything below describing Polar is **dead** and is retained
only as history. **Do not resurrect any of it.** The teardown's file-by-file list lives in
[`TASKS/task-48-distribution-msix.md`](task-48-distribution-msix.md) item 0 — **work from there,
not from this file.**
**Pricing — ✅ DECIDED 2026-09-27: `$10/mo` subscription, or `$400` lifetime. No annual.**
| Tier | Price | Net after 15% | Role |
|---|---|---|---|
| Free | $0 | — | Everything, plus the branding flash. The funnel. |
| **Pro monthly** | **$10/mo** | ~$8.50/mo | The default. Low-risk entry. |
| **Pro lifetime** | **$400** | ~$340 | The hedge. Committed / subscription-hostile buyers. |
- **15% Store revenue share, subscriptions included** — verified from the ADA v8.10 PDF, §6(b)(i).
Net receipts are after VAT/GST, so commission is not paid on pass-through tax.
- **Break-even is month 40**, so the two tiers barely compete — which is why lifetime is safe to
offer at launch rather than saving it for later.
- ⛔ **No annual tier** — Microsoft does not pro-rate and the developer cannot refund the
forfeited remainder. ⛔ **No `.99` prices.** ⛔ **No discounted upgrade SKU.**
- **ADA §6(h): raising the price disables auto-renew ⇒ `$10` is effectively locked for life.**
- ⛔ **Superseded pricing, do not cite:** the 2026-09-21 one-time model (`$29` founder → `$49`
list lifetime) and the earlier `$49.99/yr → $99/yr` subscription.
**Related work — monetization awareness (2026-09-01, ungated, free):** this task's billing is the
*payer* side; the *product* also carries built-in, ungated monetization awareness for every creator —
@@ -19,26 +43,32 @@ narrative, not a separate task number — it ships in its own code slices with o
**Scope: v1** (2026-09-01 complete-v1 ruling — there is no v1.x): slice order = reward-event capture →
session report → journey tracker → Alerts (TASK 3 item 20).
**Business details (pricing, Polar product/checkout/discounts) in `MONETIZATION.md` (gitignored).**
**Business details (pricing, Partner Center product declaration) in `MONETIZATION.md` (gitignored).**
**Polar product:** `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` (LlamaCasty, ⚠️ currently configured as
$99/yr **subscription** — must be re-created as a **one-time** product: $29 founder / $49 list lifetime)
**Checkout:** `llamacasty.com` → Polar hosted page (~80% configured)
**Discounts:** `LLAMAFOUNDER` (100% off, 50 uses, `once`), `LLAMA50` (50% off, `once`)
**Org ID:** `c05fb364-b967-4f6c-adf2-8a144e46d085` (org-scoped OAT — `organization_id` can be omitted from API calls)
**Key prefix:** `LCYT-`
**Validate endpoint:** `POST https://api.polar.sh/v1/customer-portal/license-keys/validate` (no auth required for client-side validation)
### Status: 🔶 TEARDOWN — steps 1–7 shipped under Polar, all now to be removed
### Status: 🔶 In progress — steps 1–7 shipped, Velopack update URL pending
1. ✅ **Billing provider** — Polar (polar.sh) chosen and configured. Product, price, license key benefit, discounts, checkout link all created.
2. ✅ **License key entry + verification UI** — About overlay swap panel (same pattern as Licenses panel). Text input + "Activate" button + status message. "Enter License Key" button in the hub.
3. ✅ **Offline entitlement** — `LayoutStore` Settings table: `LicenseKey`, `LicenseValidatedAt`, `IsPremium`. 14-day offline grace period. Startup re-validates online, falls back to cache.
4. ✅ **BrandFlash → watermark toggle** — `IsPremium` property setter flips `BrandFlashEnabled = !value`. Flash stops immediately on premium activation. Flash asset VideoFrame rendering deferred to TASK 4 compositor.
5. ✅ **Remove social slot locks** — all 6 social bar slots open to everyone (no `IsPremium` gating on slots 3-6) — shipped as TASK 10c
6. ✅ **"Unlock Premium" button** — `PremiumUrl` set to Polar checkout; `IsPremiumAvailable` is true; button lights up in the About hub.
7. ✅ **Licensing model** — startup re-validates against Polar API. **Perpetual key (2026-09-21): the
license never expires, `IsPremium` never lapses, and the flash does not return.** The former
renewal/lapse path is dead. Offline grace period (14 days) still applies to the validation call only.
8. 🔶 **Velopack auto-updates** — NuGet packages + bootstrap in `App.xaml.cs`. Update URL self-hosted on DO droplet (pending configuration).
Steps 1–7 below are a **record of what was built**, not a description of what ships. The Polar
licensing path is being deleted because Store IAP supplies the same bit from the OS entitlement.
1. ⛔ **Billing provider** — was Polar (polar.sh). **DELETED.** The product, checkout link, and the
discount codes `LLAMAFOUNDER` / `LLAMA50` no longer exist. Store IAP products are declared in
**Partner Center**, not Polar.
2. ⛔ **License key entry + verification UI** — was the About-overlay swap panel
("Enter License Key"). **DELETING.**
3. ⛔ **Offline entitlement** — was `LayoutStore` Settings (`LicenseKey`, `LicenseValidatedAt`,
`IsPremium`) + a 14-day offline grace period + startup re-validation. **DELETING.** The OS
supplies license state, so the entire offline-grace machine goes with it — along with the whole
"network flaky → app thinks I'm expired" bug class.
4. ✅ **BrandFlash → watermark toggle** — `IsPremium` setter flips `BrandFlashEnabled = !value`, so
the flash stops the moment the entitlement flips. **This survives the teardown.** Under Store IAP
`IsPremium` is derived from the Store entitlement rather than a remote HTTP call. One bit,
locally cached, refreshed by the OS. ⚠️ **This is the whole product surface of the paid tier.**
5. ✅ **Remove social slot locks** — all 6 social bar slots open to everyone. **Survives.**
6. ⛔ **"Unlock Premium" button** — `PremiumUrl` pointed at Polar checkout. **DELETING**; the Store
handles purchase. Paid users see zero license UI.
7. ⛔ **Licensing model / renewal-lapse path** — already dead before the Store ruling (a perpetual
key never expires). Now superseded again: **Store IAP has no keys at all.**
8. 🔶 **Velopack auto-updates** — NuGet packages + bootstrap in `App.xaml.cs`. **TEARDOWN is a
compliance action, not cleanup:** the updater downloads *and executes*, and Store policy 10.2.2
does not permit it. Tracked as [`TASKS/task-48-distribution-msix.md`](task-48-distribution-msix.md)
item 3; the Store updates the app instead.
+1 -1
View File
@@ -39,7 +39,7 @@ The tasks below are ordered by dependency and risk. Each task builds on the prev
1. ✅ **TASK 9.4** — Live chat (right panel) — wire `YouTubeChatService.Start()`, parse messages, render in panel. Foundation for chat box source.
2. ✅ **TASK 3.18** — Chat box source — renders chat ON the stream. Depends on TASK 9.4 (same message parsing).
3. ✅ **TASK 10** — Polar billing — license key entry + watermark toggle + Velopack auto-updates (steps 1-7 shipped; Velopack update URL pending).
3. ✅ **TASK 10** — watermark-only paid delta (brand flash). Steps 1–7 shipped under **Polar**, which is **now deleted in favour of Microsoft Store IAP** (2026-09-27) — TASK 10 is a **teardown**, and the Velopack updater goes with it (Store policy 10.2.2).
4. ✅ **TASK 19/23** — Control Surface UX — director's control room: thumbnails above central monitor, transitions (Cut/Fade/Move), edit mode offline only, left panel two-state (layers/props ↔ chat), right panel eliminated. Verified shipped 2026-08-24.
5. ✅ **TASK 20** — Hotkeys — global keyboard shortcuts. Shipped 2026-08-26: F1-F9 defaults + config UI with modifier chords, persistence, conflict detection, unbinding.
5b. ✅ **Broadcast metadata pull-out + launch geometry** — shipped 2026-08-24 (row 29 above). Live-screen "Text" tab → broadcast form, persistence + remote update; window default/minimums bumped (1920×1040 / 1366×768) with size+position restore.
+5 -4
View File
@@ -17,10 +17,11 @@ may be done opportunistically mid-development — each item has a lock/comment p
real mp4 decode/loop/pacing (TASK 21 picker must have landed), real recording file opens +
plays (fragmented MP4), a real private go-live end-to-end, GUI/RealApp test classes green on
the desktop (they've only ever run against fakes).
5. ☐ **License-expiry reminders** — T-14 / T-7 / T-1 toasts via the existing notification stack
("renews <date> — manage here" → `PremiumUrl`); lapsed: flash returns (the product itself is the
notice) + one Info toast; active paid users see ZERO license UI. Research: does Polar's
validate response carry `expires_at` reliably — cite before building.
5. ⛔ **STRUCK — License-expiry reminders are dead.** This item assumed a Polar license with an
`expires_at` we could warn about. Under **Store IAP** there is no key, no expiry, and no lapse:
the lifetime entitlement never ends and the subscription is renewed by Microsoft. **Nothing to
remind anyone about — do not build.** (The `expires_at` question is moot for the same reason:
`PolarLicenseService` is being deleted.)
6. ☐ **Release engineering** (the `Distribution.md` plan, 644 lines, finally tasked): code signing
(HARD blocker — an unsigned installer is a SmartScreen scarewall), installer + Velopack update URL
(TASK 10 item 8), EULA draft/review, THIRD-PARTY-NOTICES license-texts gate (TASK 4 req 9).