From f3fed0a2a8104135ef942a0ac6a00b50f09aae37 Mon Sep 17 00:00:00 2001 From: gramps Date: Fri, 2 Oct 2026 20:56:37 -0700 Subject: [PATCH] docs: purge the dead $29/$49 + Polar model from every tracked file, add the Y1 forecast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Distribution.md | 47 +++++++++++++++---- README.md | 2 +- TASKS.md | 22 +++++---- TASKS/task-10-monetization.md | 80 ++++++++++++++++++++++---------- TASKS/task-18-local-recording.md | 2 +- TASKS/task-36-gold-pass.md | 9 ++-- ai.md | 53 ++++++++++++--------- 7 files changed, 145 insertions(+), 70 deletions(-) diff --git a/Distribution.md b/Distribution.md index 31b9483..62d0738 100644 --- a/Distribution.md +++ b/Distribution.md @@ -318,9 +318,17 @@ Single-file means everything is inside the `.exe`. No DLLs, no runtime dependenc **Caveat:** Self-contained single-file means ~80-120MB due to bundled .NET runtime. For smaller size, use framework-dependent publishing (requires .NET 8 runtime on user machines) — drops to ~5-10MB. -### 4.2 Distribution via Polar +### 4.2 Distribution via Polar — ⛔ OBSOLETE (2026-09-27) -**Product setup on Polar:** +> **Superseded by Microsoft Store MSIX + Store IAP** (ruling in +> `TASKS/task-48-distribution-msix.md` item 0). The Store re-signs, hosts, updates, and takes +> payment — so file hosting, license keys, checkout, the customer portal, device deactivation and +> key rotation are **all** handled by Microsoft and none of it needs building. Retained below as a +> record of the model that was designed and abandoned. ⚠️ **The `$29`/`$49` one-time prices in this +> section are dead** — the settled pricing is **`$10/mo` or `$400` lifetime**, net of a verified +> 15% Store share. + +**Product setup on Polar (as designed, never shipped):** 1. Create a product: "LlamaCasty" — **one-time purchase** (perpetual license; $29 founder / $49 list). 2. Add two benefits: @@ -345,6 +353,11 @@ Single-file means everything is inside the `.exe`. No DLLs, no runtime dependenc - If a key is compromised, customer or merchant can rotate it via Polar. - Previous key stops validating immediately. Status, usage, limits, expiry preserved. +**What the Store does instead:** the customer installs from the Store listing, pays through Store +checkout, and the app reads the entitlement the OS already holds. There is no key to enter, no +activation call, no portal to visit, and no offline-grace period to maintain — which also retires +the whole "network flaky → app thinks I'm expired" bug class in §4.5. + ### 4.3 Code Signing > ⚠️ **The cert choice below is a live decision, and the old plan's EV recommendation is @@ -393,7 +406,13 @@ Set-AuthenticodeSignature -FilePath "LlamaCasty.exe" ` **Storage:** Certificate `.pfx` file stored in GitHub Secrets (or Azure DevOps secure files). Never committed to the repo. -### 4.4 Update Mechanism +### 4.4 Update Mechanism — ⛔ OBSOLETE (2026-09-27) + +> **Superseded by Store updates.** Microsoft delivers and updates the app from the listing, so +> there is nothing to check and no manifest to host. The Velopack updater currently in +> `App.xaml.cs` **downloads *and executes***, which Store policy **10.2.2** does not permit — its +> removal is a **compliance action**, not optional cleanup (TASK 48 item 3). The Polar-native design +> below is retained as a record of the approach that was rejected; it is not an option. **Polar-native approach (no custom infrastructure):** @@ -428,10 +447,18 @@ public class UpdateCheckService - Download link points to Polar's customer portal (not direct download). - This adds one external dependency (GitHub) but keeps Polar as the source of truth. -### 4.5 Licensing Logic (already implemented) +### 4.5 Licensing Logic — ⛔ BEING DELETED (2026-09-27) + +> ⚠️ **"Already implemented" was true as of 2026-09-21 and is no longer.** `PolarLicenseService` +> and `Helpers/PolarLicense.cs` are being **removed** as part of the TASK 10 teardown (TASK 48 item 0). +> Store IAP replaces the whole validation hop: `IsPremium` is derived from the **OS-supplied Store +> entitlement**, so there is no network call, no key, and — importantly — **no 14-day offline-grace +> machine to protect**, which retires the entire "network flaky → app thinks I'm expired" bug class. +> What survives is only `IsPremium` → `BrandFlashEnabled = !value`. Retained below as the record of +> what shipped and why it no longer applies. ```csharp -// Services/PolarLicenseService.cs — already ships +// Services/PolarLicenseService.cs — shipped under Polar; being deleted // Calls Polar's customer-portal validation endpoint (no auth required) // Survives obfuscation — property names excluded via [Obfuscation(Exclude = true)] [Obfuscation(Exclude = true)] @@ -444,11 +471,11 @@ public class LicenseValidationResult } ``` -**What's already done:** -- `PolarLicenseService` validates keys against Polar API. -- `OrganizationId` is hardcoded (safe — it's public knowledge, tied to our Polar account). -- License state persists in `LayoutStore.Settings` (SQLite) with offline grace period. -- `PremiumUrl` points to Polar checkout. +**What shipped under Polar (now being deleted):** +- `PolarLicenseService` validated keys against the Polar API. +- `OrganizationId` was hardcoded. +- License state persisted in `LayoutStore.Settings` (SQLite) with an offline grace period. +- `PremiumUrl` pointed to Polar checkout. **What survives obfuscation:** The validation logic in `Services.dll` is obfuscated. An attacker who decompiles the exe sees only the UI calling an interface — the actual Polar API call is in the obfuscated DLL. diff --git a/README.md b/README.md index 3b8cd38..7e2942c 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ text sources, chat on-stream, the social bar, mic/desktop audio with auto-duck a recording, variable quality tiers with auto step-down, one-click go-live + scheduling, stream resilience (auto-reconnect inside YouTube's grace, one-click back on air), built-in monetization awareness (reward capture, session reports, YPP journey tracker), Alerts — all free and ungated; -the one-time license only removes the branding flash. +the paid tier only removes the branding flash. ## Structure diff --git a/TASKS.md b/TASKS.md index f756420..6393539 100644 --- a/TASKS.md +++ b/TASKS.md @@ -29,7 +29,7 @@ | 07 | Meter scaling amplification | ✅ Done | [`TASKS/task-07-meter-scaling.md`](TASKS/task-07-meter-scaling.md) | | 08 | Audio milestone | ✅ SHIPPED 2026-08-14 | [`TASKS/task-08-audio-milestone.md`](TASKS/task-08-audio-milestone.md) | | 09 | YouTube Live Stream Management | ⏳ In progress — items 1–3, 4 shipped; item 5 open; item 6 locked (TASK 36) | [`TASKS/task-09-live-stream-management.md`](TASKS/task-09-live-stream-management.md) | -| 10 | Monetization: watermark-only one-time license + Polar billing | 🔶 In progress — steps 1–7 shipped; **now a TEARDOWN: Polar is deleted in favour of Store IAP (2026-09-27)** | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) | +| 10 | Monetization: watermark-only paid delta (branding flash) | 🔶 **TEARDOWN, not a build** — Polar deleted in favour of Store IAP (2026-09-27); `$10/mo` + `$400` lifetime, no annual | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) | | 11 | Post-pause polish batch (creator's 8 review issues) | ✅ SHIPPED 2026-08-15 | [`TASKS/task-11-polish-batch.md`](TASKS/task-11-polish-batch.md) | | 12 | Master limiter on the live mix | ☐ Queued | [`TASKS/task-12-master-limiter.md`](TASKS/task-12-master-limiter.md) | | 13 | Social media launch kit | 🔶 Scoped — queued after v1 | [`TASKS/task-13-social-launch-kit.md`](TASKS/task-13-social-launch-kit.md) | @@ -120,8 +120,9 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw - **Shipping / release build (creator-queued 2026-09-26)** — no publish config exists yet: the csproj has only `OutputType=WinExe` + `TargetFramework`, so a plain `dotnet publish` is **framework-dependent** (customer needs the .NET 8 Desktop Runtime preinstalled). - `Distribution.md` targets a self-contained ~80–120MB `LlamaCasty.exe` uploaded to Polar - as a File Download benefit. Two deliverables: + `Distribution.md` targets a self-contained ~80–120MB `LlamaCasty.exe`. ⛔ **The Polar + File-Download benefit is dead** — the Store hosts and updates the app, so there is no upload + step (TASK 48). Two deliverables: 1. **`scripts/publish.sh`** wrapping `dotnet publish ytLive.csproj -c Release -r win-x64 --self-contained true -o ./publish/win-x64`, and **asserting the output contains no test/xunit artifacts**. (The compile side needs @@ -235,9 +236,12 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw - **Unchanged:** the watermarks posture. Free gets everything; the branding flash stays the ONLY paid delta (TASK 36 item 2). Store IAP changes how the bit is *obtained*, never what it *gates*. - - **Still to verify (does not block packaging):** current Store revenue-share terms — ⚠️ do - not assume any percentage, verify before setting a price; and the one-time vs - subscription shape of the IAP tier (the storefront is decided, the price is not). + - **Both formerly-open questions are now CLOSED (2026-09-27).** Store revenue share is + **verified at 15%, subscriptions included** (ADA v8.10 §6(b)(i) — read from the PDF, not a + search excerpt), and the IAP tier shape is **decided: `$10/mo` subscription + `$400` + lifetime, no annual**, declared in Partner Center as two products. Full detail in + `TASKS/task-48-distribution-msix.md` item 0. ⚠️ Do **not** re-open the fee question without + re-reading the ADA, and do not *assume* 15% if the terms ever move. - **✅ item 1 SHIPPED 2026-09-28 — bundle ffmpeg instead of downloading it.** The app no longer fetches an executable at runtime (Store policy 10.2.2, and the pin 404'd on the creator's first real recording on 2026-09-01). `scripts/fetch-ffmpeg.sh` populates a @@ -310,8 +314,10 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw - Still queued from earlier: `scripts/publish.sh` (self-contained win-x64, no test artifacts, Debug-only `InternalsVisibleTo`, no WPF trimming), and the `LlamaCasty.exe` assembly rename (three pack URIs incl. `MainWindow.xaml:14` — do not rename `%APPDATA%\ytLlive`). -- Decide the open business question: `OverlayHost.xaml` copy says Polar unlocks *alerts* too, but - alerts are not gated by `IsPremium`. Either fix the copy or gate the alerts — do not leave it. +- ✅ **RESOLVED — do not re-open.** The `OverlayHost.xaml` copy claimed Polar unlocked *alerts*; + alerts were never gated by `IsPremium`. The file is **deleted outright** by the TASK 10 teardown + (TASK 48 item 0), so the copy is gone with it. The "or gate the alerts" option is **permanently + closed** — there is no feature gating, ever. --- diff --git a/TASKS/task-10-monetization.md b/TASKS/task-10-monetization.md index dcbacac..04700a5 100644 --- a/TASKS/task-10-monetization.md +++ b/TASKS/task-10-monetization.md @@ -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. \ No newline at end of file diff --git a/TASKS/task-18-local-recording.md b/TASKS/task-18-local-recording.md index 4ada254..04e9cb2 100644 --- a/TASKS/task-18-local-recording.md +++ b/TASKS/task-18-local-recording.md @@ -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. diff --git a/TASKS/task-36-gold-pass.md b/TASKS/task-36-gold-pass.md index a15fc72..6cb35c8 100644 --- a/TASKS/task-36-gold-pass.md +++ b/TASKS/task-36-gold-pass.md @@ -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 — 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). diff --git a/ai.md b/ai.md index aaf48fe..4b7c84c 100644 --- a/ai.md +++ b/ai.md @@ -1506,7 +1506,8 @@ Apply this to every UI decision: ## Monetization (design decision — the branding flash is the sword) -Full pricing, discount codes, and Polar product details in `MONETIZATION.md` (gitignored). +Full pricing and the Year 1 revenue forecast in `MONETIZATION.md` (gitignored). ⚠️ **No Polar +product, discount code, or license key exists any more** — billing is Microsoft Store IAP. Brand palette and assets in `MARCOM.md` (gitignored). This section covers the in-app model. Free forever: **all features unlocked for everyone** — no feature lock between free and paid. @@ -1554,30 +1555,40 @@ crooked. credit — `Advance` both *opens* the presentation and *ages* it by the same delta, so a single 5.1s step blows clean through the 2s window. Always step in 1/30s increments like the real timer (the `Step` helpers in `BrandFlashOutputTests`). -- **Paid (one-time perpetual license):** branding flash removed. `BrandFlashEnabled` is now a - **derived, non-assignable** `!IsPremium` and the presenter's own `Enabled` gate is re-checked on - every frame, so a key entered (or revoked) mid-credit cuts the advertisement on the next tick - rather than letting it finish. That's it. No feature gating. Alerts, social bar slots, voice - filters, TRAX, recording — everything is free. -- **Pricing (2026-09-21 — switched from subscription to one-time "own it"):** **$29 lifetime** founder's - price (launch → 90 days) → **$49 lifetime** list at GA. The key is **perpetual** (`IsPremium` never - lapses; the old renewal/lapse path is dead). Rationale: a local app with no per-user server cost and a - renewal-averse, free-surrounded audience — minimize commitment size, don't charge rent. Accessibility is - the driver: the free tier is the *full* app (only the watermark differs), so a broke new streamer pays $0; - the low one-time price is the "no recurring bill" entry. Full reasoning, and the dropped $49.99/yr → - $99/yr subscription model, in `MONETIZATION.md`. -- **Billing:** **Polar (polar.sh)** — open-source MoR (Apache 2.0), handles payments, **one-time orders**, - license keys, and global tax compliance. Startup Program gives Scale plan free for 12 months. - Product: `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` (⚠️ currently a $99/yr *subscription* product — must be - re-created as a one-time product for the new model). Checkout: `llamacasty.com` → Polar hosted page. - Org ID: `c05fb364-b967-4f6c-adf2-8a144e46d085` (org-scoped OAT — `organization_id` omitted from API calls). - Key prefix: `LCYT-`. Discounts: `LLAMAFOUNDER` (100% off, 50 uses), `LLAMA50` (50% off, 12 months). Details in `MONETIZATION.md`. +- **Paid:** branding flash removed. `BrandFlashEnabled` is now a **derived, non-assignable** + `!IsPremium` and the presenter's own `Enabled` gate is re-checked on every frame, so the + entitlement changing mid-credit cuts the advertisement on the next tick rather than letting it + finish. That's it. No feature gating. Alerts, social bar slots, voice filters, TRAX, recording — + everything is free. **How `IsPremium` is obtained is a billing concern and has changed twice; + what it gates has not.** +- **Pricing (✅ DECIDED 2026-09-27 — supersedes the 2026-09-21 one-time "own it" model):** + **`$10/mo` subscription, or `$400` lifetime. No annual. No `.99` prices.** ⛔ The old `$29` + founder → `$49` list lifetime ruling is **dead — do not cite it.** Two tiers, one delta: they + break even at **month 40**, so they barely compete, which is why lifetime is safe to offer at + launch instead of saving it for later. The free tier is the *full* app (only the watermark + differs), so accessibility is preserved without pricing down. ⛔ No annual tier: Microsoft does + not pro-rate and **the developer cannot refund** the forfeited remainder — verbatim the + grievance that drove the ruling. **ADA §6(h): raising the price disables auto-renew, so `$10` is + effectively locked for the product's life.** Full reasoning in `MONETIZATION.md` → Pricing. +- **Billing: ⛔ Polar is DELETED — Microsoft Store IAP, Microsoft as merchant of record** (ruling + 2026-09-27; teardown in `TASKS/task-48-distribution-msix.md` item 0). **Revenue share 15%, + subscriptions included** — verified from the ADA v8.10 PDF, §6(b)(i); the agreement's own v8.0 + changelog says *"85/15 revenue share for non-Game subscriptions"*. ⇒ net **~$8.50/mo**, + **~$340** lifetime. Microsoft handles VAT/GST/sales tax, refunds, chargebacks, the customer + portal, and device deactivation — the strongest argument for the switch. Net receipts are after + tax, so commission is not paid on pass-through tax. Payouts monthly, $50 threshold. + ⚠️ **No Polar product, org ID, key prefix, or discount code exists any more** — `d105dfa1-…`, + `c05fb364-…`, `LCYT-`, `LLAMAFOUNDER`/`LLAMA50`, the customer-portal validate endpoint, and the + 14-day offline-grace machine are all being deleted. Products are declared in **Partner Center** + instead: one auto-renewing monthly subscription + one non-expiring lifetime IAP. + ⛔ A discounted subscriber→lifetime upgrade SKU is **not** approved. - **Support (creator's model, corrected 2026-09-01):** support = email + GitHub issues — the once-planned in-app bug-reporter is **out of product** (TASKS.md → closed list). Most queries are how-tos / feature requests / manual-skimmers. Maintenance cadence = "when I get around to it" with emergency patches; not a 24/7 service promise. The only license chatter is the paid-user **expiry - reminder — now moot** (perpetual keys never expire, one-time model 2026-09-21); paid users see zero - license UI. TASK 36 item 5 (expiry reminder) is superseded. + reminder — now moot** (superseded twice: keys are moot because the lifetime entitlement never + expires, and the entire license-key system is moot because Store IAP has no keys); paid users see + zero license UI. TASK 36 item 5 (expiry reminder) is struck. **Monetization awareness (built-in, ungated, free — 2026-09-01; v1 SCOPE per the complete-v1 ruling — build order: capture → report → journey → Alerts):** the app is monetization-aware by