docs: bank the Windows Store + signing research, and fix the dead EV-certificate line
The distribution answer existed only in conversation, so every session re-derived it. It is now in the map, and the route decision is explicitly parked as the creator's. new TASKS/research-store-certification.md — Store Policies 7.20 + MSIX packaging: which policies bind, which don't (and why), cert economics, camera/mic gating layers, YouTube age + COPPA, the 11.12 UGC judgment call. Two real defects surfaced, neither fixed (docs-only unit): - FfmpegLocator downloads an unsigned exe from GitHub and runs it. That is policy 10.2.2 (dynamic code inclusion) verbatim, and it is the root cause of the 2026-09-01 404 — the pin aged out of BtbN's 14-day retention on the creator's first real recording attempt. -> TASK 48 item 1, not Store-conditional. - Distribution.md:318 recommended a $400+/yr EV cert for a SmartScreen bypass Microsoft removed in March 2024. Fixed; had it shipped it would have cost $400+/yr to buy what $150 buys. Also new: TASKS/task-48 (checklist, carved out of TASK 36 item 6) and TASKS/task-49 (chat profanity filter, not blocked). ai.md gains the durable invariants — full trust or recording breaks silently, chat is rendered never stored — plus a correction to the FFmpeg locator section. MyMistakes.md records the lesson: a policy citation is a claim about scope, not just text. MARCOM.md got the privacy-copy guard but is gitignored by design, so that edit stays local and did not travel here.
This commit is contained in:
@@ -634,6 +634,22 @@ const). Constructor-injected search dirs / tools dir / downloader (`Func<string,
|
||||
Task<byte[]>>`) keep it hermetic: tests fake the network with a real in-memory zip. Constructed in the
|
||||
encoder step (not yet — this PR ships the seam + impl + tests only).
|
||||
|
||||
**⛔ The pinned-download design is now formally a defect, not a cold-start edge case (2026-09-27).**
|
||||
It **failed in production on 2026-09-01** — 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. Two facts make
|
||||
the "pin is a const, just bump it" assumption wrong:
|
||||
- **Microsoft Store policy 10.2.2 forbids dynamic code inclusion.** Downloading an executable
|
||||
from the internet and running it is the exact pattern the policy names. An MSIX submission
|
||||
is rejected over it.
|
||||
- Bumping the pin is whack-a-mole against a retention window we do not control.
|
||||
|
||||
**Fix (TASK 48 item 1, recommended on EVERY route — it is not Store-conditional):** bundle
|
||||
`ffmpeg.exe` + `ffprobe.exe` + the `libav*.dll` family **inside the package**; `FfmpegLocator`
|
||||
resolves PATH → package-local → cache and never downloads. This also deletes the startup
|
||||
network dependency entirely. The LGPL-**shared** build choice is **unaffected** — dynamic
|
||||
linking was chosen for LGPL §6 compliance ("license text + source offer"), not to enable
|
||||
downloading. Analysis: `TASKS/research-store-certification.md` §4.
|
||||
|
||||
### Live encoder + RTMP push (TASK 4 ship step 3 — shipped 2026-08-12, plan in TASKS.md)
|
||||
|
||||
The encoder is a **thin orchestrator over `ffmpeg.exe`** — no H.264/AAC code in the app. It spawns the
|
||||
@@ -1775,3 +1791,95 @@ published decisions (recorded in `TASKS/task-43-native-alerts.md`):
|
||||
dedicated 8s stereo-48k ring (`AlertBufferSeconds`), drained in `FillAndMix` before the
|
||||
limiter and added at **unity — never ducked** (creator ruling: "don't lower my game
|
||||
audio for a tip"); `StartLive` clears it. Per-alert loudness = the Volume slider.
|
||||
|
||||
---
|
||||
|
||||
## Windows packaging & distribution (2026-09-27 — research settled, route NOT decided)
|
||||
|
||||
Full analysis: `TASKS/research-store-certification.md` (Store Policies **7.20**, effective
|
||||
2026-10-22 — re-check the version before acting). Executable checklist:
|
||||
`TASKS/task-48-distribution-msix.md`. **The route is the creator's decision** (Store MSIX +
|
||||
Store IAP / Store MSIX + Polar / Polar-hosted + own cert / dominated Store-EXE). Do not build
|
||||
packaging work before that call, and do not re-derive the options — they are tabulated in the
|
||||
research file §3.
|
||||
|
||||
### ⛔ Durable invariant: full trust, or recording silently breaks
|
||||
|
||||
MSIX packages run at one of two trust levels. A packaged WPF app declaring
|
||||
`rescap:Capability Name="runFullTrust"` runs at **mediumIL — the same permissions as a
|
||||
standard desktop app, NOT AppContainer** — and may spawn child processes, which is why
|
||||
bundling ffmpeg is legal. Writes to user-profile locations (AppData, Downloads, MyVideos)
|
||||
**pass through unvirtualized at mediumIL**; the package install folder is read-only.
|
||||
|
||||
**`ViewModels/MainViewModel.Recording.cs` writes recordings to
|
||||
`%USERPROFILE%\Downloads` / `SpecialFolder.MyVideos` (`DefaultRecordFolder()`,
|
||||
`ChooseRecordFolder()` via `Microsoft.Win32.OpenFolderDialog`), and the whole
|
||||
temp-write-then-move lifecycle stays in one directory.** That works *only* because we are full
|
||||
trust. No `broadFileSystemAccess` capability is needed, and none should be added.
|
||||
|
||||
⚠️ **If anyone flips the manifest to `appContainer`, `Directory.CreateDirectory` and
|
||||
`File.Move` start resolving to a per-package virtualized location and output vanishes with no
|
||||
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
|
||||
|
||||
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 **Store MSIX route
|
||||
needs no certificate at all** — Microsoft re-signs. `Distribution.md` §4.3 was corrected
|
||||
2026-09-27; it previously recommended EV.
|
||||
|
||||
### Distribution and licensing are independent
|
||||
|
||||
A **Store-distributed** app may still verify licenses with **Polar** (policy 10.8.1
|
||||
explicitly permits a secure third-party purchase API for non-game PC products; the box is
|
||||
ticked in Partner Center). So "should we use the Store?" does **not** imply "should we drop
|
||||
Polar?" — the only combination that removes Polar is Store + Store IAP, and that is a
|
||||
*licensing* choice which happens to ride on a *distribution* decision. (The monetisation
|
||||
posture itself is unchanged and lives in the Monetization section above: free gets
|
||||
everything; the branding flash is the only paid delta.)
|
||||
|
||||
### ⛔ "Only when the user says so" is enforced by Windows, not by us
|
||||
|
||||
Camera/mic consent is layered: Store policy **10.6** forbids circumventing OS checks; the
|
||||
**Windows desktop-app camera/microphone toggle** (Settings → Privacy & security, since Win10
|
||||
1903) is the gate; hardware lights and tray indicators are the OS's disclosure mechanism. So
|
||||
**route everything through the standard MF/DShow/WASAPI paths and we never write that
|
||||
certification ourselves** — the OS does it and gets neither our credit nor our blame.
|
||||
|
||||
⚠️ **Untested:** whether that toggle reliably gates a **DShow webcam and a capture card**.
|
||||
Microsoft's own support page admits desktop apps "might still be able to access your camera
|
||||
or microphone even when these settings are turned off." This is **not** a certification
|
||||
failure (we declare `webcam` honestly and use supported APIs) but it is a real user-trust
|
||||
issue — so **no privacy-forward marketing copy until it is measured.** Guard note added to
|
||||
`MARCOM.md`.
|
||||
|
||||
### ⛔ Durable invariant: chat is rendered, never stored
|
||||
|
||||
`TASK 49`'s profanity filter is **local, on-device, opt-in, non-persistent**, with a
|
||||
**user-supplied word list — never a hardcoded slur list baked into the binary** (unpleasant
|
||||
artifact, false positives across dialects, extractable). It must **never match the SuperChat
|
||||
amount or any reward field** — those are financial data under policy 10.5.5.
|
||||
|
||||
The non-persistence half is not just hygiene: it is the load-bearing half of the **11.12 UGC
|
||||
certification answer** (mirrored YouTube chat is moderated at industrial scale upstream; ~1.6B
|
||||
comments removed in Q1 2026 alone, child safety the #2 reason at 124.6M). **No future feature
|
||||
— chat history, moderation logs, analytics, crash payloads — may quietly break that
|
||||
assumption.** If one is ever proposed, the 11.12 position must be re-argued first.
|
||||
|
||||
### Minors
|
||||
|
||||
The **operator is 13+ by construction**, not by promise: LlamaCasty requires a YouTube
|
||||
account to stream, and YouTube's ToS sets the account floor at **13** (regional variants reach
|
||||
14; 13–17 need parent/guardian permission; under-13s are on supervised/YouTube Kids accounts).
|
||||
So a COPPA theory premised on collecting PI from under-13s has no purchase against the
|
||||
operator. The residual is **viewers** — still possible on supervised family accounts — and it
|
||||
is weak: live chat is restricted there, YouTube moderates before we see it, and we persist
|
||||
nothing. COPPA is very unlikely to bind (not child-directed), but note the enforcement trend
|
||||
(FTC Sept 2025 *Apitor*: operators are responsible for what third-party components collect) —
|
||||
so the answer is a documented inquiry, and ours is "no third-party analytics or ad SDKs, no
|
||||
persisted chat or reward payloads."
|
||||
|
||||
Reference in New Issue
Block a user