docs: distribution route decided — Microsoft Store MSIX + Store IAP

Creator ruling 2026-09-27. Criteria, verbatim: "zero headaches, minimal
maintenance (for me) while still providing accountability and a reasonably
easy upgrade flow." Route A is the only combination where all four are solved
by handing the work to Microsoft rather than to a certificate vendor: $0/yr,
no certificate, no HSM, no annual renewal, no SmartScreen ramp — plus Store
auto-update, Store-side payments/entitlements/refunds/support, and Microsoft
review as the accountability layer.

The rejected options and their reasons stay in research-store-certification.md
§3 so a later session reads the ruling instead of re-deriving it.

What this deletes:
- The entire licensing backend. PolarLicenseService, PolarLicense,
  MainViewModel.License.cs (PremiumUrl, customer portal, the OfflineGracePeriod
  = 14 days subscription-era artifact, renewal/lapse copy) and the wrong
  "Polar unlocks alerts" string all become dead code. IsPremium is derived from
  the Store entitlement instead of an HTTP call, which also removes the whole
  "network flaky -> app thinks I'm expired" bug class.
- Velopack, the update URL, and the self-hosted droplet — the Store updates.
- Distribution.md's premise: Polar as the distribution backbone, Polar file
  hosting, and code signing as our problem. The IP-protection sections (1, 5,
  6, 7) still stand and the build-posture ceiling is unchanged.

What does NOT change: the entitlement. Free gets everything; the branding
flash stays the only paid delta. Store IAP changes how IsPremium is obtained,
never what it gates.

Still open, deliberately: the price. The Store revenue share is unverified (do
not assume a percentage), and MONETIZATION.md's $29 -> $49 one-time decision is
re-opened against a fresh instinct toward ~$99/yr. No price encoded yet.

The first code unit is unchanged: bundle ffmpeg (TASK 48 item 1). That clears
the one hard certification gate and fixes a real user-facing 404.

MARCOM.md and MONETIZATION.md were edited too but are gitignored by design, so
those changes stayed local.
This commit is contained in:
2026-09-27 14:23:51 -07:00
parent e78c58fc28
commit 85fad1ab79
6 changed files with 282 additions and 162 deletions
+78 -79
View File
@@ -1,75 +1,61 @@
# HANDOFF — current state
**Branch:** `main` (pre-1.0, no feature branches — creator ruling 2026-08-24).
**Last pushed:** `938c5b3` (alert ticker). This unit (distribution/certification research) is
**docs-only** — no code touched, no build, no tests run.
**Last pushed:** `e78c58f` (Store certification research). This unit (recording the Store MSIX
+ Store IAP ruling) is **docs-only** — no code touched, no build, no tests run.
## This unit: distribution & Store certification research is WRITTEN DOWN
## ✅ DECIDED 2026-09-27 — distribution is the Microsoft Store: MSIX + Store IAP
The session's open question was "how do we get this in front of users without a SmartScreen
scarewall" and it had been answered **in conversation only** — which meant the next session
would re-derive it. It is now in the map, and the conversation can be dropped.
**Creator's criteria, verbatim: "zero headaches, minimal maintenance (for me) while still
providing accountability and a reasonably easy upgrade flow."** Route A is the only option
where all four are solved by handing the work to Microsoft rather than to a certificate
vendor: **$0/yr, no certificate, no HSM, no annual renewal, no SmartScreen ramp**, plus Store
auto-update, Store-side payments/entitlements/refunds/support, and Microsoft review as the
accountability layer. The rejected options and their reasons are in
`TASKS/research-store-certification.md` §3 — **read that before reopening the question, not
before re-deriving it.**
| File | What it is |
|---|---|
| `TASKS/research-store-certification.md` | **new** — the authoritative research. Store Policies **7.20** (effective 2026-10-22, re-check the version), MSIX full-trust vs AppContainer, cert economics, a ⛔/✅ table of which policies bind and which don't, the camera/mic gating layers, the YouTube age + COPPA analysis, the 11.12 UGC judgment call, and the filter design constraints |
| `TASKS/task-48-distribution-msix.md` | **new** — the executable checklist. Carved out of TASK 36 item 6 (code signing / installer / Velopack URL) so distribution has one owner |
| `TASKS/task-49-chat-profanity-filter.md` | **new** — the chat filter checklist. Not blocked |
| `Distribution.md` §4.3 | **corrected** — the EV recommendation was dead (§ below) |
| `ai.md` | new "Windows packaging & distribution" section (durable invariants) + a correction on the FFmpeg locator |
| `MyMistakes.md` | the policy-applicability lesson |
| `TASKS.md` | rows 48/49, a research index, and the TASK 36 item 6 split |
| `MARCOM.md` | ⛔ **privacy-copy guard — gitignored, so this edit is local-only and did not travel with the push** |
**The big consequence: the whole licensing backend is deleted.** `PolarLicenseService`,
`PolarLicense`, `MainViewModel.License.cs` (`PremiumUrl`, customer portal, the
`OfflineGracePeriod = 14 days` subscription-era artifact, renewal/lapse copy) and the wrong
"Polar unlocks alerts" string all become dead code. `IsPremium` comes from the **Store
entitlement** instead of an HTTP call — which also deletes the entire "network flaky → app
thinks I'm expired" bug class. **Velopack, the update URL and the DO droplet go too.**
### Two real defects the research surfaced (both now recorded, neither fixed — no code this unit)
**What does not change: the entitlement.** Free gets everything; the branding flash stays the
ONLY paid delta. Store IAP changes how `IsPremium` is *obtained*, never what it *gates*.
1. **⛔ `FfmpegLocator` downloads an unsigned exe from GitHub and runs it.** That is Store
policy **10.2.2** (dynamic code inclusion) verbatim, *and* it is the root cause of the
2026-09-01 failure: the previous daily pin aged out of BtbN's 14-day retention and the
download **404'd on the creator's first real recording attempt**. `FfmpegLocator.cs:30-35`
records the incident but still reads like a design choice. → **TASK 48 item 1.** Not
Store-conditional: bundling kills this whole class of cold-start failure and deletes the
startup network dependency. **This is the highest-value unblocked item in the repo.**
2. **⛔ `Distribution.md:318` recommended a $400+/yr EV certificate for a benefit Microsoft
deleted in March 2024.** Fixed. Had it shipped, it would have cost $400+/yr to buy exactly
what $150 buys. Lesson in `MyMistakes.md` — the recurring shape is *citing a policy or a
platform fact from memory instead of re-verifying it in the document itself.*
**⏳ Still open: the price.** The Store revenue share is unverified (⚠️ assume no percentage —
check current terms before setting a price), and `MONETIZATION.md`'s `$29 → $49` one-time
decision is re-opened against a fresh instinct toward a ~$99/yr subscription. **No price is
encoded anywhere until the creator settles it.** Note the storefront changed, so the old
"~$69 floor" and "don't break the launch-price promise" notes now refer to Store tiers.
### ⛔ The decision that is NOT made, and belongs to the creator
### The first code unit: bundle ffmpeg (TASK 48 item 1)
**The distribution route.** Research is done and MSIX is the front-runner (full trust is viable;
we trip **none** of the four MSIX disqualifiers — no driver installed, no per-user service, no
elevation, no shell extension). Four real combinations, costed in
`TASKS/research-store-certification.md` §3:
Two real defects the research surfaced — **neither is fixed yet**, this was a docs unit:
| # | Route | Cert/yr | SmartScreen | Notes |
|---|---|---|---|---|
| A | Store MSIX + Store IAP | **$0** | none | Polar gets deleted; revenue cut; public listing |
| B | Store MSIX + **Polar** | **$0** | none | free signing **and** keep 100% — two systems to maintain |
| C | **Polar file hosting** + own cert | $120–300 | warning ramp | **the status quo already sketched in `Distribution.md:14`/`:296`** |
| D | Store EXE (policy 10.2.9) | $120–300 | warning ramp | **dominated** — cert anyway, silent install, own URL |
1. **⛔ `FfmpegLocator` downloads an unsigned exe from GitHub and runs it.** Store policy
**10.2.2** (dynamic code inclusion) verbatim, *and* the root cause of the 2026-09-01
failure — the pin aged out of BtbN's 14-day retention and the download **404'd on the
creator's first real recording attempt**. `FfmpegLocator.cs:30-35` records the incident but
still reads like a design choice. **Fix: bundle it.** Also deletes the startup network
dependency.
2. **⛔ `Distribution.md:318` recommended a $400+/yr EV certificate for a SmartScreen bypass
Microsoft removed in March 2024.** Fixed last commit — had it shipped, it would have cost
$400+/yr to buy what $150 buys. Now moot anyway (MSIX is signed by Microsoft), but the
lesson in `MyMistakes.md` stands: a policy citation is a claim about **scope**, not just
text.
**Nothing else was allowed to block on this** — the user is right that most of the research is
route-independent and worth banking regardless. So: research banked, dead line fixed, and only
the packaging work is parked.
### ⛔ Two invariants that break silently if touched
**Also still open, deliberately:** pricing (one-time vs one-time+monthly), the license provider,
and therefore all licensing copy. `OverlayHost.xaml` still claims Polar unlocks alerts — wrong,
alerts are not gated. Unresolved, queued, **not** to be papered over.
### The two findings most likely to be forgotten
- **Distribution and licensing are independent.** Policy 10.8.1 lets a **Store-distributed**
app verify licenses with **Polar**. So "should we use the Store?" does not imply "drop Polar?"
Only route A removes Polar, and that is a licensing decision riding on a distribution one.
- **⛴ Two invariants that will break silently if touched:**
- **Full trust, or recording breaks.** `DefaultRecordFolder()` writes to Downloads/MyVideos;
that passes through unvirtualized **only** at `mediumIL`. Flip the manifest to
`appContainer` and output vanishes with no error. A comment is owed there **when the
manifest lands** (TASK 48 item 6) — not before.
- **Chat is rendered, never stored.** That non-persistence half is the load-bearing part of
the 11.12 certification answer. No chat history, moderation log, analytics, or crash payload
may be added without re-arguing 11.12 first.
- **Full trust, or recording breaks.** `DefaultRecordFolder()` writes to Downloads/MyVideos;
that passes through unvirtualized **only** at `mediumIL`. Flip the manifest to
`appContainer` and output vanishes with no error. A comment is owed there **when the
manifest lands** (TASK 48 item 6) — not before.
- **Chat is rendered, never stored.** That non-persistence half is the load-bearing part of
the 11.12 certification answer. No chat history, moderation log, analytics, or crash payload
may be added without re-arguing 11.12 first.
## Landmines
@@ -99,29 +85,42 @@ alerts are not gated. Unresolved, queued, **not** to be papered over.
## Uncommitted / untracked
- `MARCOM.md` — the privacy-copy guard was added but the file is **gitignored by design**
(confidential business file, `.gitignore:11`). It stays local, as intended. Same for
`MONETIZATION.md` and `CREDENTIALS.md` — **never commit those.**
- `MARCOM.md`, `MONETIZATION.md` — both edited (privacy-copy guard; the Polar-obsolete banner
and the re-opened-price note) and both **gitignored by design** (confidential business
files, `.gitignore:10-11`). They stay local, as intended. Same for `CREDENTIALS.md` —
**never commit those.**
## Next
1. **Bundle ffmpeg (TASK 48 item 1)** — unblocked, recommended on every route, and it fixes a
real user-facing failure. *This is the next code unit.*
2. **The route decision** (creator) — A/B/C above, once the ffmpeg fix is out of the way.
3. **Vertical recording verification** — the compositor tier is proven by
1. **Bundle ffmpeg (TASK 48 item 1)** — unblocked, first code unit, fixes a real user-facing
failure and clears the one hard certification gate.
2. **Settle the price** — one-time vs subscription, and the number. Then declare the IAP
products in Partner Center. **Blocks:** the Store listing, and the `OverlayHost.xaml` copy.
3. **The packaging project + `Package.appxmanifest`** (TASK 48 items 2–3) — full trust,
`webcam`/`microphone`, English only; Velopack deleted. Add the `DefaultRecordFolder()`
comment in the same unit.
4. **Polar teardown** (TASK 48 item 0) — `PolarLicenseService`, `PolarLicense`,
`MainViewModel.License.cs`, the `OverlayHost.xaml` string, the `csproj`/`App.xaml.cs`
Velopack sites. `IsPremium` ← Store entitlement. **Do this as one unit** — a half-torn-down
licensing path is worse than either end state.
5. **Verify the Store revenue-share rate** — before step 2, not after.
6. **Vertical recording verification** — the compositor tier is proven by
`Render_VerticalTier_Outputs_1080x1920_From_The_Center_Crop`; the *record* path has never
been run. `FramePump.cs:645` flags off-size tiers as a known follow-up.
4. **Multi-instance** — route `FfmpegLocator._toolsDir` through `InstanceProfile` (same shared
extraction race as #1, and it becomes moot if ffmpeg is bundled). Confirm the launch method:
`$env:YTLIVE_INSTANCE=2` + `dotnet run --no-build` in a second shell is the known-good path.
5. **Post-session efficacy report** — roll up `CurrentHealth` (dropped frames, duration, health
7. **WACK + certification notes + the privacy policy** (TASK 48 items 4–5) — the policy must
state camera/mic is OS-gated, nothing is retained, and nothing is fetched at runtime.
8. **Post-session efficacy report** — roll up `CurrentHealth` (dropped frames, duration, health
message) when a stream or recording ends. `SessionTeardownTests` is the natural home.
6. **`scripts/publish.sh` + Debug-only `InternalsVisibleTo` + the `LlamaCasty.exe` rename** —
still queued from 2026-09-26; do **NOT** add `-p:PublishTrimmed=true` (WPF fails at runtime,
not build time). See `TASKS.md` → "Shipping / release build".
7. **The alert-gating copy** (`OverlayHost.xaml`) — fix the copy or gate the alerts; do not leave
it lying. Blocked behind the pricing ruling.
8. **The camera-privacy measurement** — does the Win11 desktop-app camera toggle actually gate a
DShow webcam and a capture card? Gates all privacy-forward copy (`MARCOM.md` guard).
9. **TASK 36:212 stale "shipped" line** — one-line fix, needs a hand.
10. Ship-checklist items live in `TASKS.md` → "1.0 gates".
9. **Measure whether the Windows camera toggle gates DShow** — gates all privacy-forward copy
(`MARCOM.md` guard). Not a certification risk; a trust risk.
10. **TASK 36:212 stale "shipped" line** — one-line fix, needs a hand.
**Dropped from the list** because the ruling made them moot: multi-instance's ffmpeg tools-dir
race (item 1 makes it disappear), `scripts/publish.sh` + the `LlamaCasty.exe` rename (the Store
packages and delivers — *revisit only if we ever ship outside the Store*), and the alert-gating
copy (the wrong string dies with the Polar teardown in step 4).
**Everything else in the v1 queue:** stream resilience (32), bandwidth step-down (33), scheduled
streams (34), scene-linked audio (35), the master limiter (12), text source (3.16), reward
events (3.20), the media picker (21), webcam identity (9.5), settings units A/C/D (40), and the
defaults split (37). Ship-checklist items live in `TASKS.md` -> "1.0 gates".