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:
@@ -0,0 +1,448 @@
|
||||
# ytLlive — Windows Store & code-signing certification research (authoritative)
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md) · memory map: [`schema.md`](../schema.md) · distribution plan: [`Distribution.md`](../Distribution.md)
|
||||
>
|
||||
> **Researched 2026-09-27** against **Microsoft Store Policies version 7.20** (published
|
||||
> 2026-09-15, effective 2026-10-22) and the MSIX packaging docs. Policy version moves —
|
||||
> re-check the version before acting on any line here.
|
||||
>
|
||||
> **This file is the "why".** The executable checklist lives in
|
||||
> [`task-48-distribution-msix.md`](task-48-distribution-msix.md). No code changed as a
|
||||
> result of this research; it only decides what task-48 will eventually do.
|
||||
|
||||
---
|
||||
|
||||
## 1. Bottom line
|
||||
|
||||
**MSIX packaging is viable.** One real blocker, and it is a code change we should want
|
||||
anyway (§4). Three technical blockers that normally kill a Store submission — drivers,
|
||||
per-user services, elevation — we **do not trip** (§7).
|
||||
|
||||
**The decision is NOT made.** The route is open; this file records the options and their
|
||||
costs so the decision can be made from a clear page. `Distribution.md` holds the older
|
||||
plan and contains **one factually dead claim** — see §2.
|
||||
|
||||
---
|
||||
|
||||
## 2. ⚠️ The one line in `Distribution.md` that is now wrong
|
||||
|
||||
`Distribution.md:318` currently says:
|
||||
|
||||
> Buy an EV (Extended Validation) code-signing certificate from DigiCert or Sectigo
|
||||
> ($200-400/year). EV certificates get instant SmartScreen reputation; DV/OV certs
|
||||
> trigger SmartScreen warnings for months.
|
||||
|
||||
**The EV half of that is false.** Microsoft removed the SmartScreen instant-bypass for EV
|
||||
certificates in **March 2024**. An EV-signed file now accumulates reputation exactly the
|
||||
way an OV-signed file does. Paying $400+/yr buys precisely what paying $150 buys.
|
||||
|
||||
`schema.md` rule 4: stale facts get FIXED, not appended. Corrected in `Distribution.md`
|
||||
(2026-09-27).
|
||||
|
||||
Also worth knowing before budgeting:
|
||||
|
||||
- **Cert validity is capped at 460 days** (CA/B Forum CSC-31, effective 2026-03-01). This
|
||||
is a recurring annual line item, not a one-time purchase.
|
||||
- **Private keys must live on an HSM or hardware token** (CA/B rule since 2023-05). Budget
|
||||
for the token or a cloud HSM.
|
||||
- **Signing does not clear the warning on day one.** A valid cert stops the *malware*
|
||||
warning immediately; the "unrecognized publisher" warning clears as SmartScreen accrues
|
||||
reputation from real download volume. Expect a ramp on every route.
|
||||
- **Third-party AV vendors layer their own reputation blocking on top of SmartScreen**, so
|
||||
signed-but-new can still warn on consumer machines. The Store route is the only one that
|
||||
is warning-free, because Microsoft holds the reputation.
|
||||
|
||||
---
|
||||
|
||||
## 3. Signing economics
|
||||
|
||||
| Route | Cert cost | SmartScreen | Install UX | Notes |
|
||||
|---|---|---|---|---|
|
||||
| **Microsoft Store, MSIX package** | **$0** — Microsoft re-signs | No warning | Normal | Store review, public listing, updates handled by Store |
|
||||
| **Microsoft Store, EXE/MSI (10.2.9)** | **$150–300/yr — your own cert** | Warning ramp | **Silent install only** | Store does NOT re-sign; you maintain a versioned URL |
|
||||
| **Direct + OV cert** | $150–300/yr | Warning ramp | Yours | Worldwide availability |
|
||||
| **Direct + Azure Artifact Signing** | ~$9.99/mo ≈ $120/yr | Warning ramp | Yours | **Individuals: USA/Canada only.** Identity validation required |
|
||||
| **Direct + EV cert** | $400+/yr | Same as OV | Yours | **Do not buy.** No benefit since March 2024 |
|
||||
| **Unsigned direct** | $0 | Strong block | Yours | Unusable for public download |
|
||||
|
||||
### Four real combinations
|
||||
|
||||
| # | Distribute | Verify payment | Cert | Revenue cut |
|
||||
|---|---|---|---|---|
|
||||
| **A** | Store | Store IAP | $0 | yes |
|
||||
| **B** | Store | **Polar** | $0 | no |
|
||||
| **C** | Polar file hosting | Polar | $150–300/yr | no |
|
||||
| **D** | Store EXE (10.2.9) | Polar | $150–300/yr | no |
|
||||
|
||||
**A** is the only one where Polar becomes unnecessary — the Store handles payment,
|
||||
entitlement, and refunds, and you would delete `PolarLicenseService` and the
|
||||
customer-portal plumbing. That is a *distribution* choice that happens to subsume
|
||||
licensing.
|
||||
|
||||
**B** is the compromise worth serious consideration: the Store solves the SmartScreen
|
||||
problem and the annual cert bill while Polar stays the licensing system and we keep 100%
|
||||
of revenue. Cost is two systems to maintain.
|
||||
|
||||
**C** is the status quo already sketched in `Distribution.md:14` / `:296` — Polar hosts the
|
||||
signed exe (10GB, signed personal download URLs, SHA-256 included). **The Store is not
|
||||
needed for delivery at all.** The Store's only unique value is *free Microsoft signing with
|
||||
no SmartScreen warning*, and its cost is MSIX packaging work, Store review, and a public
|
||||
listing.
|
||||
|
||||
**D is dominated** — strictly worse than both A and C: cert required anyway, silent install
|
||||
required, and we maintain the versioned download URL. Documented in one line so it is
|
||||
never re-litigated.
|
||||
|
||||
---
|
||||
|
||||
## 4. ⛔ The one real blocker: 10.2.2 (dynamic code inclusion)
|
||||
|
||||
**Policy 10.2.2:**
|
||||
|
||||
> Your product must not attempt to fundamentally change or extend its described
|
||||
> functionality or introduce features or functionality that is in violation of Store
|
||||
> Policies **through any form of dynamic inclusion of code**. Your product should not, for
|
||||
> example, **download a remote script and subsequently execute that script** in a manner
|
||||
> that is not consistent with the described functionality.
|
||||
|
||||
**What we do today:** `Services/Encoder/FfmpegLocator.cs:37-38` pins a GitHub release URL,
|
||||
and `LocateAsync` downloads the zip (line 69), extracts it (line 73), and the encoder then
|
||||
executes that binary. On a cold cache the app **downloads an unsigned executable from the
|
||||
internet and runs it.**
|
||||
|
||||
That is the pattern 10.2.2 names. The word is "script," so a narrow reviewer might quibble
|
||||
about a PE binary — but 10.2.3 reinforces it, and 10.2.9 separately requires all PE files
|
||||
to chain to the Microsoft Trusted Root Program, which a downloaded BtbN build does not.
|
||||
|
||||
**The fix:** bundle `ffmpeg.exe` + `ffprobe.exe` + the `libav*.dll` family **inside the
|
||||
package** instead of downloading. No dynamic code inclusion, so 10.2.2 is satisfied.
|
||||
|
||||
**This is a fix we want regardless of route.** `FfmpegLocator.cs:30-35` records that the
|
||||
previous daily pin aged out of GitHub retention and **404'd on the first real recording
|
||||
attempt (2026-09-01)**. Bundling kills that entire class of cold-start failure permanently,
|
||||
and it also removes the startup network dependency.
|
||||
|
||||
The LGPL-shared licensing reasoning in `FfmpegLocator` is unaffected — dynamic linking was
|
||||
the deliberate choice for LGPL §6 compliance, not for download avoidance. Confirm
|
||||
`THIRD-PARTY-NOTICES.txt` (already shipped) covers the bundled build.
|
||||
|
||||
**What I got wrong initially:** I believed MSIX might forbid *launching* a bundled
|
||||
executable. It does not — see §5.
|
||||
|
||||
---
|
||||
|
||||
## 5. MSIX technical facts (full trust vs AppContainer)
|
||||
|
||||
MSIX packages run at one of two trust levels, chosen by the manifest:
|
||||
|
||||
| Trust level | Behavior |
|
||||
|---|---|
|
||||
| **`mediumIL` / full trust** | **Same permissions as a standard desktop app.** Package identity + some file/registry virtualization. **Can spawn child processes.** ← this is what a WPF broadcast tool wants |
|
||||
| `appContainer` | Strictly isolated. Process and children see only explicitly granted resources. File/registry virtualized. |
|
||||
|
||||
**A packaged WPF app declaring `runFullTrust` runs at medium integrity — it is not an
|
||||
AppContainer.** Bundling and launching ffmpeg from inside the package is therefore fine.
|
||||
This is the "Desktop Bridge" / `packagedClassicApp` model.
|
||||
|
||||
**Critical file-write consequence:** "Writes to user profile locations (such as AppData) are
|
||||
redirected to per-package locations for AppContainer apps, or **pass through for full-trust
|
||||
apps**." The package install folder itself is read-only.
|
||||
|
||||
**Manifest this app needs:**
|
||||
|
||||
- `rescap:Capability Name="runFullTrust"` — medium integrity
|
||||
- `webcam` and `microphone` capabilities
|
||||
- `uap10:TrustLevel="mediumIL"`
|
||||
- `uap10:RuntimeBehavior="packagedClassicApp"`
|
||||
|
||||
### The full-trust recording invariant (durable architectural fact)
|
||||
|
||||
`ViewModels/MainViewModel.Recording.cs` writes recordings to
|
||||
`%USERPROFILE%\Downloads` or `SpecialFolder.MyVideos` (`DefaultRecordFolder()`, line
|
||||
173–179), with `Microsoft.Win32.OpenFolderDialog` for overrides (`ChooseRecordFolder()`,
|
||||
line 151). The whole temp-write-then-move lifecycle stays inside one directory
|
||||
(line 131–132).
|
||||
|
||||
**This works only because we are full trust.** At `mediumIL` those writes pass through
|
||||
unvirtualized and `OpenFolderDialog` is an ordinary Win32 folder browser with no capability
|
||||
token involved. **No `broadFileSystemAccess` is needed.**
|
||||
|
||||
⚠️ **If anyone ever flips the manifest to `appContainer`, recording silently breaks** —
|
||||
`Directory.CreateDirectory` and `File.Move` start resolving to a per-package virtualized
|
||||
location. A code comment belongs at `DefaultRecordFolder()` **when the manifest lands**, not
|
||||
before (a comment describing a manifest that does not exist is worse than no comment).
|
||||
|
||||
---
|
||||
|
||||
## 6. Store policy verdicts — what binds, what doesn't
|
||||
|
||||
Policy 7.20. "Binds" = must be satisfied to submit.
|
||||
|
||||
### ⛔ Binds — blockers or real work
|
||||
|
||||
| Policy | Requirement | Our status |
|
||||
|---|---|---|
|
||||
| **10.2.2** | No dynamic code inclusion (download-and-execute) | ❌ **VIOLATED** — see §4. Fix: bundle ffmpeg |
|
||||
| **10.3.1** | Login required → supply a **working demo account** in certification notes | ☐ TODO — we require YouTube sign-in |
|
||||
| **10.5.1** | **Privacy policy mandatory**; URL in Partner Center. Desktop Bridge + Win32 **always** need one. Must state what PI is accessed/collected/transmitted, how used/stored/secured, types of parties disclosed to, controls the user has, compliance with law, and be kept current | ☐ TODO — `llamachile.shop` can host it |
|
||||
| **10.5.4** | Collect/store/transmit PI securely with modern cryptography | ✅ DPAPI for tokens, HTTPS to YouTube |
|
||||
| **10.5.5** | No highly sensitive PI (health/**financial**) unless tied to functionality + express consent | ⚠️ **SuperChat/reward path touches financial data** — keep display-text-only processing, never log payloads |
|
||||
| **10.6** | Declared capabilities must relate to the product's functions; **must not circumvent OS checks** | ✅ camera/mic for a broadcast tool is self-evident; must use standard MF/DShow/WASAPI paths |
|
||||
| **10.7** | Localize for every declared language; declare **English only** | ☐ Keep the manifest to one language |
|
||||
| **10.1.1** | Title must be unique, **no marketing or descriptive text, no extraneous keywords** | Store name is exactly `LlamaCasty` |
|
||||
| **10.1.3** | Search terms: max 7, no pricing terms, **no other product titles** unless you published them | ☐ Cannot list `OBS` or `StreamYard` as search terms |
|
||||
| **10.1.4** | Distinct informative metadata + **active Store presence** | ☐ Listing must not be a stub |
|
||||
| **10.2.7** | Must enable clean uninstall | ☐ MSIX gives this free |
|
||||
| **10.4.2** | Start promptly, stay responsive, shut down gracefully, survive native API exceptions | ✅ `AppLog` + dispatcher handlers exist |
|
||||
| **11.11.1** | **IARC age-rating questionnaire** required | ☐ General-audience streaming tool, 12+ territory |
|
||||
| **11.11.2** | Keep the rating accurate as features change | ☐ Re-visit if audience-facing features shift |
|
||||
| **11.12** | **User Generated Content** — see §9 | ⚠️ Judgment call, documented not built |
|
||||
| **10.8.1** | Non-game PC products **may** use a secure third-party purchase API **or** Store IAP | ✅ **Polar explicitly permitted.** Must tick the third-party purchase box in Partner Center |
|
||||
| **10.8.2** | Third-party purchase: identify provider, authenticate user, obtain confirmation, PCI DSS, note in Partner Center | ☐ Covered by Polar; tick the box |
|
||||
| **10.8.3** | **Individual** accounts cannot require financial info for primary functionality; requiring it forces a **Company** account | ⚠️ **Open question** — see §11 |
|
||||
| **10.14** | Individual accounts usually fine for a solo dev; Company required if the product needs financial info for primary functionality, or a consumer would read the name as a business | ⚠️ Same question as 10.8.3 |
|
||||
| **10.8.7** | Pricing must follow the FTC Guides Against Deceptive Pricing and must not be irrationally high vs. features | ☐ A pricing decision, not a code task |
|
||||
| **10.5.8** | Must **follow** applicable safety/privacy laws re children | ☐ Follow-the-law obligation — see §8 |
|
||||
| **10.1.5** | May enable acquisition of your other Store products or add-ons | N/A |
|
||||
|
||||
### ✅ Does NOT bind — recorded so it is never re-raised
|
||||
|
||||
| Policy | Why it doesn't apply |
|
||||
|---|---|
|
||||
| **10.10** (Advertising) | **Ads are injected server-side by YouTube after the RTMP handoff.** LlamaCasty displays no ads, renders no ad SDK, and controls no ad decision. Every 10.10 clause is conditioned on ads *your product displays*. Not applicable. |
|
||||
| **10.2.5** (Store-only install) | 7.20 applies "installed and updated only through the Store" to **game products and Xbox console products**. A non-game PC app is not locked to MSIX. *(The 2018 v7.7 wording said "all of your apps" — that language has been narrowed.)* |
|
||||
| **10.2.3** (secondary software) | ffmpeg **enhances** the product's functionality, and once bundled it is not "offered to install" as separate software |
|
||||
| **10.2.8** (Windows settings) | `RegisterHotKey` and standard DShow/MF paths are supported APIs. No accessibility-API or undocumented-API tricks |
|
||||
| **10.10.1 / 10.10.2** | Follows from 10.10 — no ads displayed |
|
||||
| **11.13** (Storefront) | Not a storefront |
|
||||
| **11.14** (Gambling) | Not applicable |
|
||||
| **11.15** (Child Safety) | Prohibits products enabling exploitation/grooming/sexualization/sextortion/trafficking, and adult-themed products targeting children. A broadcast tool is not in this class. Nothing LlamaCasty does creates, uploads, or distributes child-exploiting content |
|
||||
| **10.5.2** | We do not publish a customer's PI to an outside service beyond the stream they themselves broadcast |
|
||||
| **10.5.7** (location) | No device location access |
|
||||
| **10.2.9** | Only if we chose the Store EXE route. It would bind — see §3, route D is dominated |
|
||||
|
||||
### Certification mechanics
|
||||
|
||||
- Technical compliance is tested by the **Windows App Certification Kit** before submission.
|
||||
- Certification takes **up to 3 business days**; the listing appears ~15 min after publish.
|
||||
- MSIX package requirements: SHA2-256 block map, `StoreManifest`, 25 GB max.
|
||||
- Partner Center account: individual vs company — see §11.
|
||||
|
||||
---
|
||||
|
||||
## 7. MSIX disqualifiers we do NOT trip
|
||||
|
||||
Verified by grep across the codebase 2026-09-27. The MSIX prep docs list four hard
|
||||
disqualifiers; **all four are clear**:
|
||||
|
||||
| Disqualifier | Our status |
|
||||
|---|---|
|
||||
| "Your application requires a Windows driver. MSIX doesn't support Windows drivers." | ✅ We **consume** DShow filters, we don't install a driver. (A creator's third-party Virtual Capture Device is their hardware, not something we ship.) |
|
||||
| "Your application requires a user Windows service. MSIX doesn't support per-user Windows services." | ✅ No service installation anywhere |
|
||||
| Apps requiring **elevation** for any functionality are not accepted | ✅ No `requireAdministrator` / `highestAvailable` / UAC manifest |
|
||||
| "Your app's modules are loaded in-process to processes that are not in your Windows app package" (shell extensions, etc.) | ✅ No shell extensions, no in-process module loading, no jump lists |
|
||||
|
||||
Also verified: there is **no `.manifest` file in the repo at all** today, so packaging is
|
||||
purely additive — a new `Package.appxmanifest` plus a packaging project. The existing
|
||||
unpackaged exe keeps working.
|
||||
|
||||
### Other store rules worth knowing while listing
|
||||
|
||||
- **10.1.4** requires an active Store presence — the listing cannot be a placeholder.
|
||||
- **10.7** — declare English only, or localize the description into every declared language.
|
||||
- **10.9** — the app must stay functional when notifications are disabled. Our toast stack
|
||||
must not be load-bearing.
|
||||
|
||||
---
|
||||
|
||||
## 8. Minors, COPPA, and the age question
|
||||
|
||||
### The operator is 13+ by construction
|
||||
|
||||
YouTube Terms of Service:
|
||||
|
||||
- **"You must be at least 13 years old to use the Service"**
|
||||
- 13–17 permitted **with parent/guardian permission**
|
||||
- **Under 13 cannot create an account** — exceptions are YouTube Kids and supervised
|
||||
accounts via Family Link or Google Workspace for Education
|
||||
- Google Accounts: 13 is the minimum to self-manage
|
||||
- **The floor varies by region** — at least one YouTube ToS variant states 14, tracking EU
|
||||
digital-consent ages. Treat it as 13–14, not a fixed 13.
|
||||
|
||||
**Why this does real work:** LlamaCasty *requires* a YouTube account to operate, because
|
||||
streaming requires one. So the person running the broadcast is 13+ by construction. A
|
||||
COPPA theory premised on "a service collecting personal information from children under 13"
|
||||
has no purchase against the operator — and that is true **by construction, not by promise**.
|
||||
That is the cleanest sentence available for a certification note.
|
||||
|
||||
### The residual exposure
|
||||
|
||||
The **viewers** may still be under 13 on supervised/family-linked accounts, so the chat
|
||||
ingestion point does not fully disappear. It weakens substantially, because:
|
||||
|
||||
- Live chat is restricted/disabled on supervised YouTube kid accounts
|
||||
- YouTube moderates the messages before we ever see them (§9)
|
||||
- Our mitigation: **retain nothing** — parse, display, discard (see `task-49`)
|
||||
|
||||
### COPPA is very unlikely to bind
|
||||
|
||||
COPPA applies to child-directed services and to operators collecting PI from children under
|
||||
13. The three-factor test (subject matter, audience, evidence of child focus) is nowhere
|
||||
near met by a broadcast tool aimed at a gaming audience. **10.5.8 is a follow-the-law
|
||||
obligation, not a be-child-safe obligation** — it says "follow all applicable laws," it does
|
||||
not impose COPPA duties on us directly.
|
||||
|
||||
**But note the enforcement trend** (FTC, September 2025 Apitor settlement): operators are
|
||||
held responsible for **what third-party components collect on their behalf**, and the FTC
|
||||
expects a real inquiry into third-party collection practices. That case was about an SDK;
|
||||
the principle is what matters for a chat pipe. This is a documentation obligation, and the
|
||||
answer is "we integrate no third-party analytics or ad SDKs, and we persist no chat or
|
||||
reward payloads."
|
||||
|
||||
---
|
||||
|
||||
## 9. 11.12 User Generated Content — the judgment call
|
||||
|
||||
11.12 triggers on "content that users contribute to a product and which can be viewed or
|
||||
accessed by other users **in an online state**." **Chat is literally that.** If a reviewer
|
||||
classifies the chat surface as UGC, the requirements are:
|
||||
|
||||
1. Published **terms of service, code of conduct, and/or content guidelines** for UGC,
|
||||
accessible **in-product and on your website**
|
||||
2. A **means for users to report** inappropriate/illegal/harmful UGC to the developer for
|
||||
review, and/or proactive detection
|
||||
3. Respect **user safety, parental, and content privilege settings**, and handle restricted
|
||||
access gracefully
|
||||
4. **Remove or disable UGC when requested by Microsoft**
|
||||
5. Disclose that content is **not created by the developer/publisher** where appropriate
|
||||
|
||||
### The argument: YouTube discharges the moderation obligation upstream
|
||||
|
||||
| 11.12 asks for | How YouTube already covers it |
|
||||
|---|---|
|
||||
| Published ToS / CoC / content guidelines | Community Guidelines, linkable from our listing |
|
||||
| A reporting mechanism | Creator-side chat reporting; YouTube enforces |
|
||||
| Respect parental / privilege settings | YouTube's restricted + supervised accounts |
|
||||
| Remove/disable on request | YouTube removes; we never hosted the original |
|
||||
| Disclose third-party UGC origin | Visibly YouTube chat; YouTube is platform of record |
|
||||
|
||||
**And the enforcement is demonstrably real.** YouTube's transparency report for
|
||||
**Jan–Mar 2026**: approximately **1.6 billion comments removed in a single quarter**, with
|
||||
**child safety the #2 removal reason at 124,624,293** (hateful/abusive 15,977,127;
|
||||
harassment/cyberbullying 71,326,861; spam/scams 1.31 B).
|
||||
|
||||
**The certification-note sentence:**
|
||||
|
||||
> UGC is mirrored from YouTube, which moderates it at industrial scale upstream. We render
|
||||
> transiently, persist nothing, and provide no user-to-user communication surface.
|
||||
|
||||
**The "persist nothing" half is ours to keep** — and it is the same property
|
||||
`task-49` (profanity filter) needs. Convenient, not coincidental.
|
||||
|
||||
**Our read:** 11.12 targets products hosting a UGC *community*. A chat *mirror* rendered
|
||||
from YouTube — where YouTube is the platform of record and already supplies reporting,
|
||||
age-gating, and parental controls — is arguably not "our" UGC. **This is a judgment call,
|
||||
and we resolve it by documenting the position rather than building features on a guess.**
|
||||
State the reasoning in the certification notes; Microsoft reads them.
|
||||
|
||||
### The documentation we owe regardless
|
||||
|
||||
| Artifact | Requirement |
|
||||
|---|---|
|
||||
| **Privacy policy** on `llamachile.shop` | 10.5.1. Must state: camera/mic access is user-directed and OS-gated; **no retention** of chat or reward payloads; no viewer data collected; **ffmpeg is bundled, nothing is fetched at runtime** |
|
||||
| **Code of conduct + content guidelines** | 11.12 / 11.15. General audience; explicitly not directed at under-13s |
|
||||
| **IARC age-rating questionnaire** | 10.11.1 |
|
||||
| **Certification notes** | the 11.12 reading, the YouTube age-gate argument, the Polar third-party purchase box, the demo account |
|
||||
|
||||
---
|
||||
|
||||
## 10. Camera, microphone, and "only when the user says so"
|
||||
|
||||
**We do not write that certification. Windows does it — and the Store forbids us from
|
||||
bypassing it.** Three layers:
|
||||
|
||||
1. **Policy 10.6** — "You must not circumvent operating system checks for capability
|
||||
usage." Route through the standard OS consent path; do not roll our own.
|
||||
2. **Windows privacy settings** — Settings → Privacy & security → Camera / Microphone.
|
||||
Since **Windows 10 1903**, *"Let desktop apps access your camera/microphone"* is the
|
||||
toggle that governs a Win32 broadcast app. Turn it off and the app loses access. **That
|
||||
is the "explicit user direction" mechanism, enforced by the OS, not by our EULA.**
|
||||
3. **Hardware/OS indicators** — camera light (or a notification when there is no light) and
|
||||
a microphone icon in the taskbar tray. Automatic. The OS is the disclosure mechanism, so
|
||||
we get neither credit nor blame from it.
|
||||
|
||||
### ⚠️ The open question — measure, don't assume
|
||||
|
||||
Microsoft's own support page carries this caveat:
|
||||
|
||||
> Desktop apps may not always appear in the list of apps available to the Camera and
|
||||
> Microphone settings pages or might still be able to access your camera or microphone even
|
||||
> when these settings are turned off.
|
||||
|
||||
**Untested: does the Win11 desktop-app camera toggle reliably gate a DShow webcam and a
|
||||
capture card?**
|
||||
|
||||
- If it **does** gate them, we can make privacy-forward claims after verifying.
|
||||
- If it **does not**, that is **not** a Store certification failure — we declared `webcam`
|
||||
honestly and use supported APIs — but it is a real user-trust issue, and we must not
|
||||
write privacy-forward marketing copy on the assumption that it works.
|
||||
|
||||
**Tracked as an open item in `TASKS.md`. A guard note in `MARCOM.md` blocks privacy-forward
|
||||
copy until it passes.**
|
||||
|
||||
---
|
||||
|
||||
## 11. Open questions
|
||||
|
||||
1. **Individual or Company Partner Center account?** (10.8.3 / 10.14.) Individual accounts
|
||||
are "usually appropriate for a single developer working on their own," and a Company
|
||||
account is required if the product requires financial account information **for primary
|
||||
functionality**. Polar collects payment externally and we never ask the user for card
|
||||
details, so we look like a clean individual case — but it is a question for Partner
|
||||
Center, and getting it wrong means re-enrolling.
|
||||
2. **Does the desktop-app camera toggle gate DShow?** (§10) — gates the `MARCOM.md`
|
||||
privacy claim.
|
||||
3. **MSIX write behavior under a real package identity** — full trust passes writes through
|
||||
per the docs, but worth confirming on a real packaged build before trusting it with
|
||||
recordings.
|
||||
4. **Store revenue-share terms** — do not plan on any specific percentage. The terms have
|
||||
moved more than once and small indie apps sometimes qualify for better rates. Verify
|
||||
current terms and conditions before pricing against them.
|
||||
5. **`liveBroadcasts.insert` requires `status.selfDeclaredMadeForKids`** (COPPA) — already
|
||||
known, see [`research-youtube-api.md`](research-youtube-api.md) item 1. Confirm the
|
||||
dialog wording is right for a tool that is never child-directed.
|
||||
|
||||
---
|
||||
|
||||
## 12. Profanity filter — design constraints (feeds `task-49`)
|
||||
|
||||
YouTube's Community Guidelines carry a specific **Vulgar language policy** under
|
||||
"Sensitive content," alongside nudity/sexual content, child safety, and self-harm. So
|
||||
profanity is a named policy surface, not an edge case.
|
||||
|
||||
Three external reasons it earns a slot, plus the real one:
|
||||
|
||||
1. YouTube treats it as policy-relevant, so 11.12's "proactive detection" language has
|
||||
something to attach to
|
||||
2. Competitive parity — overlay tools in this lane generally offer it
|
||||
3. It is a reasonable reading of 11.12's proactive-detection language
|
||||
4. **The real reason: we control what gets projected on screen.** That is the creator's
|
||||
call, not YouTube's.
|
||||
|
||||
**Four constraints, because they protect the privacy story rather than complicate it:**
|
||||
|
||||
1. **Local and on-device only.** No server, no telemetry of message content, nothing leaves
|
||||
the machine.
|
||||
2. **Non-persistent.** Filter at ingest, discard the raw text, keep only the display
|
||||
string. Same property that makes the 11.12 answer in §9 strong.
|
||||
3. **User-supplied word list**, opt-in, stored locally. **Not a hardcoded slur list baked
|
||||
into the binary** — that is an unpleasant artifact, generates false positives across
|
||||
dialects and languages, and becomes our problem the moment someone extracts it. A
|
||||
user-curated list is also simply more useful: streamers know their community's
|
||||
euphemisms and we do not.
|
||||
4. **Match display text only.** Never the SuperChat amount or any reward-event field —
|
||||
those are financial data under 10.5.5, and matching on them would be a real mistake.
|
||||
|
||||
The existing alert box already has a ticker and three display methods
|
||||
(`Controls/OverlayHost.xaml`, `ViewModels/MainViewModel.Chat.cs`), so there is probably a
|
||||
**single insertion point** rather than scattered call sites. Verify before building.
|
||||
Reference in New Issue
Block a user