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:
+56
-61
@@ -56,7 +56,9 @@ collaboration, not autonomous code generation.
|
||||
## Licensing — proprietary since 2026-10-30
|
||||
|
||||
**LlamaCasty is closed-source commercial software.** `LICENSE` is the EULA; the paid tier exists
|
||||
because the free tier caps output at **720p30** (creator ruling 2026-10-30, superseding free-forever).
|
||||
because output quality is the paid delta — the free tier is capped at a 720p30 profile (creator
|
||||
ruling 2026-10-30, superseding free-forever). Prices, entitlement and channels:
|
||||
[`commercial.md`](commercial.md).
|
||||
|
||||
- **Every GPL build already published stays GPL for that snapshot.** Attribution/§7 terms
|
||||
(`ADDITIONAL-TERMS.md`) are deleted and were GPL-only; the files are gone.
|
||||
@@ -88,18 +90,21 @@ Apply this to every UI decision:
|
||||
stream, not both; one reusable stream; one webcam; two mixer inputs). If a feature only sings on
|
||||
a high-end chassis, it doesn't ship — the OBS escape hatch is open by design.
|
||||
|
||||
## Monetization — free forever, no watermark
|
||||
## Monetization — free tier + Pro output quality
|
||||
|
||||
**All features are free and ungated** (creator ruling 2026-10-08, TASK 54): no feature lock, no paid
|
||||
tier, no watermark. Money comes from gratuity and merch, not gating. **No licence chatter reaches a
|
||||
user** — no keys, no expiry, no licence UI. Support is email + GitHub issues; an in-app bug reporter
|
||||
is out of product. `IsPremium` gates nothing in v1.
|
||||
**Every feature is free and ungated** (creator ruling 2026-10-08, TASK 54, kept by the 2026-10-30
|
||||
freemium ruling): no feature lock, no watermark, and nothing licence-shaped in the output. The
|
||||
paid delta is **output quality alone** — free is capped at a 720p30 profile, Pro unlocks the
|
||||
higher tiers for **both the stream and the recording**. Prices, entitlement and channels:
|
||||
[`commercial.md`](commercial.md). Support is email + GitHub issues; an in-app bug reporter is out
|
||||
of product.
|
||||
|
||||
**The branding credit is OFF by default.** `MainViewModel.ShowBrandFlash` (internal static, default
|
||||
`false`) is the master switch; `BrandFlashEnabled => ShowBrandFlash && !IsPremium` feeds the
|
||||
presenter. The code is kept, not deleted — creator ruling: *"don't delete it, just make it
|
||||
conditionally displayed."* `BrandFlashOutputTests` opts in by setting the switch before constructing
|
||||
a `MainWindow`; `Credit_IsOffByDefault_EvenOnTheFreeTier` guards the default.
|
||||
**The branding credit is retired as a paid delta and stays off.** `MainViewModel.ShowBrandFlash`
|
||||
(internal static, default `false`) is the master switch; `BrandFlashEnabled => ShowBrandFlash &&
|
||||
!IsPremium` feeds the presenter. The code is kept, not deleted — creator ruling: *"don't delete
|
||||
it, just make it conditionally displayed."* Entitlement must never enable it.
|
||||
`BrandFlashOutputTests` opts in by setting the switch before constructing a `MainWindow`;
|
||||
`Credit_IsOffByDefault_EvenOnTheFreeTier` guards the default.
|
||||
|
||||
If it is ever enabled, the mechanics that matter:
|
||||
|
||||
@@ -117,14 +122,14 @@ If it is ever enabled, the mechanics that matter:
|
||||
- **A mid-credit downgrade** cuts the advertisement on the next tick: the presenter re-checks its own
|
||||
`Enabled` gate every frame rather than letting the credit finish.
|
||||
|
||||
Pricing, billing, the Store IAP plan and the rejected alternatives are history →
|
||||
[`decisions.md`](decisions.md).
|
||||
Live prices, entitlement and channels: [`commercial.md`](commercial.md). Retired pricing, the
|
||||
Store IAP plan and the rejected alternatives: [`decisions.md`](decisions.md).
|
||||
|
||||
|
||||
**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
|
||||
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:
|
||||
design, for **every** creator, free and ungated. It has three layers, all free — the capability no
|
||||
competitor ships (the positioning order across features lives in `MARCOM.md`):
|
||||
|
||||
- **Reward-event capture (the data foundation).** The live-chat poll (`YouTubeChatService.Poll`)
|
||||
receives every reward event over `liveChat/messages` and — since TASK 43 (2026-09-24) —
|
||||
@@ -184,40 +189,32 @@ YouTube channel, they go to YouTube first. This assumption is explicit and must
|
||||
replaced by an in-app account-creation step. Zero state = the Start Stream dialog's "Sign in to
|
||||
YouTube" button; going live is unreachable until an account is connected.
|
||||
|
||||
## Windows packaging & distribution (direct + Steam; Store dropped 2026-10-22)
|
||||
## Windows packaging & distribution (winget primary; Steam + Store parked)
|
||||
|
||||
**The Microsoft Store route is dead** — a brand on the publisher line needs a Company account and
|
||||
a legal entity. Cause of death and the abandoned routes: [`decisions.md`](decisions.md).
|
||||
Live channel policy, the artifact and signing costs: [`commercial.md`](commercial.md). Build
|
||||
mechanics (publish flags, GitHub Releases, the winget manifest): [`Distribution.md`](../../Distribution.md).
|
||||
Retired routes and cause of death: [`decisions.md`](decisions.md).
|
||||
|
||||
**The route now:**
|
||||
|
||||
1. **Direct download from `llamacasty.com`** — the app is **free forever** (TASK 54), so there is
|
||||
nothing to bill in v1.
|
||||
2. **Steam when $100 exists** — Steam Direct is $100 per product (recoupable after $1,000 AGR),
|
||||
accepted categories include *Audio/Video Production* / *Player Tools* (OBS Studio is the
|
||||
precedent), the **developer/publisher name is self-chosen** so the brand needs no entity,
|
||||
5+ screenshots at 1920×1080 + capsule art, a build Valve runs, and a **2-week live page**
|
||||
before release. Valve takes 30%.
|
||||
3. **Polar is dormant, not deleted-in-principle** — chosen checkout/licence provider if a paid
|
||||
tier ever returns; $50 already paid. `Distribution.md` §4.2/§4.5 holds the design.
|
||||
4. **The Microsoft Store: not pursued.** The MSIX package stays as a working artifact and is
|
||||
submitted nowhere. History: `TASKS/research-store-certification.md`,
|
||||
`TASKS/task-48-distribution-msix.md`.
|
||||
**The channels, in order:** direct download from `llamacasty.com` (binaries on GitHub Releases) →
|
||||
**winget**, the primary install path → Steam (parked, $100, lifetime Pro as DLC only) → Microsoft
|
||||
Store (parked, $19 Individual account — the only storefront that bills a subscription natively).
|
||||
|
||||
**Consequences that are architecture, not packaging detail:**
|
||||
|
||||
- **⛔ The updater is now MISSING, not deleted-by-design.** Velopack and its bootstrap were
|
||||
removed on 2026-10-22 (TASK 48 slice 3) because the Store was going to deliver updates — that
|
||||
premise is gone. An update path must come back, and
|
||||
`ytLive.Tests/StorePackagingTests.cs` (which asserts no updater returns) must be rewritten
|
||||
with the chosen updater rather than left to veto one.
|
||||
- **The MSIX package still builds** via `scripts/package-msix.sh` (TASK 48 slice 2) — publish
|
||||
- **⛔ There is no self-updater, by policy as well as by history.** Velopack was removed on
|
||||
2026-10-22 (TASK 48 slice 3) because it downloaded *and executed*, which Store policy 10.2.2
|
||||
forbids — and the same rule would close the Store for good if it came back. Updates arrive
|
||||
through the package manager (`winget upgrade`) plus an in-app "newer version exists" banner read
|
||||
from a version file on GitHub Releases. `ytLive.Tests/StorePackagingTests.cs` must keep asserting
|
||||
that no self-updater returns.
|
||||
- **The MSIX package stays buildable** via `scripts/package-msix.sh` (TASK 48 slice 2) — publish
|
||||
`Release -r win-x64 --self-contained` into `artifacts/msix-stage`, copy
|
||||
`Packaging/Package.appxmanifest` in as `AppxManifest.xml` + `Packaging/Assets/`, then
|
||||
`makeappx pack` → `artifacts/LlamaCasty.msix` (159 MB, gitignored; `MSIX_PFX` signs it for a
|
||||
local install). The manifest is a **full-trust `packagedClassicApp` at `mediumIL`** with
|
||||
`runFullTrust` + webcam + microphone. `Square310x310Logo`/`Wide150x150Logo` traps are in
|
||||
`MyMistakes.md`. Logos come from the app's own artwork via `scripts/make-store-logos.py`.
|
||||
local install). It is the Store channel's artifact, unsubmitted until that account exists. The
|
||||
manifest is a **full-trust `packagedClassicApp` at `mediumIL`** with `runFullTrust` + webcam +
|
||||
microphone. `Square310x310Logo`/`Wide150x150Logo` traps are in `MyMistakes.md`. Logos come from
|
||||
the app's own artwork via `scripts/make-store-logos.py`.
|
||||
- **⛔ Bundle ffmpeg — no runtime downloads** (was Store policy 10.2.2; still right for a direct
|
||||
download, and it fixes the 2026-09-01 404). See [`output.md`](output.md) → "FFmpeg locator".
|
||||
- **⛔ 64-bit Windows only (creator ruling 2026-10-09).** Both csproj files set
|
||||
@@ -226,10 +223,12 @@ a legal entity. Cause of death and the abandoned routes: [`decisions.md`](decisi
|
||||
is the win64 build, ONNX Runtime 1.31 ships no win-x86 native (only win-x64/win-arm64), and a
|
||||
32-bit address space can't hold the 1080p frame buffers. Windows 11 is 64-bit-only anyway.
|
||||
Public copy says "64-bit Windows 10 or 11".
|
||||
- **Portable mode is the distributable's shape:** `portable.txt` beside the exe keeps the layout DB
|
||||
and settings in `.\data\` (hung off `LayoutPathOverride`), so a USB stick carries someone's
|
||||
scenes. The `winget` install and the hand-to-a-friend zip are the same artifact.
|
||||
|
||||
**What does NOT change: the monetization posture.** The app is **free forever with no watermark**
|
||||
(TASK 54, 2026-10-08), so `IsPremium` gates nothing in v1 and the branding flash is OFF by
|
||||
default. `Monetization` above governs.
|
||||
**What does NOT change: no watermark and no feature gating.** The free tier is the whole app at a
|
||||
720p30 profile. `Monetization` above governs.
|
||||
|
||||
### ⛔ Durable invariant: full trust, or recording silently breaks
|
||||
|
||||
@@ -250,28 +249,24 @@ trust. No `broadFileSystemAccess` capability is needed, and none should be added
|
||||
error.** A comment at `DefaultRecordFolder()` is owed **when the manifest lands** (TASK 48
|
||||
item 6) — not before; a comment describing a manifest that doesn't exist is worse than none.
|
||||
|
||||
### Signing — do not buy EV
|
||||
### Signing — Azure Trusted Signing, never EV
|
||||
|
||||
Microsoft **removed the SmartScreen instant-bypass for EV certificates in March 2024**. An
|
||||
EV-signed file now accrues reputation exactly like an OV-signed one, so EV ($400+/yr) buys
|
||||
what OV (~$150–300/yr) buys. Signing is **not** instant regardless — a valid cert stops the
|
||||
*malware* warning immediately, but "unrecognized publisher" clears only as SmartScreen accrues
|
||||
reputation from real download volume. Cert validity is capped at **460 days** (recurring
|
||||
line item) and private keys must live on an **HSM or hardware token**. **The 2026-10-22 ruling
|
||||
is to ship unsigned and accept the "unrecognized publisher" warning** until download reputation
|
||||
accrues — buying a certificate is deferred, not rejected. `Distribution.md` §4.3 was corrected
|
||||
2026-09-27 (it previously recommended EV).
|
||||
Microsoft **removed the SmartScreen instant-bypass for EV certificates in March 2024**, so EV
|
||||
($400+/yr) buys what OV (~$150–300/yr) buys; both need an HSM or hardware token and renew inside
|
||||
**460 days**. The 2026-10-31 ruling is **Azure Trusted Signing (~$9.99/month)**: Microsoft-issued,
|
||||
individuals eligible after identity verification, and it accrues reputation without a certificate
|
||||
purchase. Until the profile exists, builds ship unsigned and the "unknown publisher" line is
|
||||
accepted. Signing never clears the warning on day one either way — only download volume does.
|
||||
Signing steps: [`Distribution.md`](../../Distribution.md).
|
||||
|
||||
### Distribution and licensing are independent — and the channel decision does not decide licensing
|
||||
### Distribution and licensing are independent — the channel never decides billing
|
||||
|
||||
A **Store-distributed** app *may* still verify licences with **Polar** (Store policy 10.8.1
|
||||
explicitly permits a secure third-party purchase API for non-game PC products), so "which
|
||||
channel?" never implied "which billing?" — route B was a real option. The 2026-10-22 reversal
|
||||
proves the point in the other direction: dropping the Store did not by itself restart Polar,
|
||||
because the **2026-10-08 free-forever ruling** (TASK 54) had already removed the paid tier.
|
||||
Polar is therefore *dormant*, ready if a paid tier ever returns, and nothing in v1 depends on it.
|
||||
The lesson worth keeping: the licensing choice rides on a **monetization** decision, not on a
|
||||
distribution decision.
|
||||
channel?" never implies "which billing?". **Polar is the live provider** (2026-10-31) because the
|
||||
2026-10-30 freemium ruling created something to sell; winget has no storefront at all, so the
|
||||
licence path is entirely ours there. The lesson worth keeping: the licensing choice rides on a
|
||||
**monetization** decision, not on a distribution decision.
|
||||
|
||||
### ⛔ "Only when the user says so" is enforced by Windows, not by us
|
||||
|
||||
|
||||
Reference in New Issue
Block a user