e7cded6879
Reconcile the pending doc edits with the creator's actual ruling, and close the revenue-share question that was blocking the monthly price. Verified from the App Developer Agreement v8.10 PDF itself (downloaded and text-extracted, not a search excerpt). Section 6(b) has only three tiers: 6(b)(i) 15% for Apps and their In-App Products *not listed in* 6(b)(iii); 6(b)(ii) 12% Games-only; 6(b)(iii) 30% for Xbox console apps/games, Xbox non-subscription IAP, and Windows 8/Phone 8. LlamaCasty is a Windows PC App, so 6(b)(i) governs BOTH tiers -- there is no subscription surcharge. The agreement's own changelog (v8.0, Oct 26 2017) states it outright: "implement the 85/15 revenue share for non-Game subscriptions." => $10/mo nets $8.50 (~$102/yr); $400 lifetime nets $340. Also confirmed: the 15% applies after VAT/GST (Net Receipts definition), payouts are monthly above a $50 threshold, and no better small-indie rate exists in the standard terms. Creator ruling recorded: $10/mo subscription or $400 lifetime, no annual, no .99. This supersedes the 2026-09-21 one-time $29 -> $49 model. Two obligations ADA 6(h) attaches to the recurring tier, recorded because they change its risk profile and are the reason lifetime is the hedge: we must fulfil the subscription for the entire period as marketed (on breach Microsoft may refund the full amount plus taxes in its sole discretion), and raising the price disables auto-renew -- so $10 is effectively locked for the product's life. Stale facts fixed in the same change rather than appended: - research-store-certification.md: IARC was 11.11.1/11.11.2 in one table and 10.11.1 in another; corrected to 10.11.x. - research-store-certification.md: policy 10.8.1/10.8.2 still asserted "Polar explicitly permitted" and "tick the third-party purchase box". Void now that Store IAP is the route and Polar is being torn down. - task-48: the working YouTube demo account (10.3.1) was accidentally dropped from the certification list during the Store-IAP edit. Restored -- a reviewer cannot use the app without one. - MyMistakes.md: the verified-fact-vs-decided-outcome lesson now closes its loop (the creator did rule the way the research pointed), and records the over-correction that followed. Docs-only. No code, no build, no tests.
462 lines
27 KiB
Markdown
462 lines
27 KiB
Markdown
# 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
|
||
|
||
**✅ ROUTE DECIDED 2026-09-27 — the creator chose route A: Microsoft Store, MSIX package,
|
||
Store IAP.** The research below is what the decision was made from, and it stays as the
|
||
audit trail so the choice is never re-litigated. The executable checklist is
|
||
`TASKS/task-48-distribution-msix.md`; the ruling and the criteria behind it are in that
|
||
file's item 0.
|
||
|
||
**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).
|
||
|
||
**Nothing else is open on distribution.** The only number still unverified is the Store
|
||
revenue-share rate (§11 item 4), which is a *pricing* input, not a distribution one.
|
||
|
||
---
|
||
|
||
## 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 was chosen (2026-09-27)** — the creator's criteria were "zero headaches, minimal
|
||
maintenance (for me) while still providing accountability and a reasonably easy upgrade
|
||
flow," and A is the only option where *every* one of those is solved by handing the work to
|
||
Microsoft rather than to a certificate vendor. The rest of this section stays as the record
|
||
of what was rejected and why, so the decision is not reopened by a later session that
|
||
remembers only that "certs cost $150/yr."
|
||
|
||
**A** is the only one where Polar becomes unnecessary — the Store handles payment,
|
||
entitlement, and refunds, and `PolarLicenseService` and the customer-portal plumbing are
|
||
deleted. That is a *distribution* choice that happens to subsume licensing.
|
||
|
||
**B** is the compromise that was **not** taken: the Store would have solved the SmartScreen
|
||
problem and the annual cert bill while Polar stayed the licensing system. Rejected because
|
||
it keeps a licensing backend, a customer portal, activation limits, and an offline-grace
|
||
machine alive — the exact maintenance the ruling was made to eliminate.
|
||
|
||
**C** is the status quo previously 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**; its only unique value is *free Microsoft signing with no
|
||
SmartScreen warning*, and its cost is MSIX packaging work, Store review, and a public
|
||
listing. Note the irony: C is the only option with a recurring cost *and* the only one where
|
||
the creator maintains payment plumbing themselves.
|
||
|
||
**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 |
|
||
| **10.11.1** | **IARC age-rating questionnaire** required | ☐ General-audience streaming tool, 12+ territory |
|
||
| **10.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 | ✅ **Superseded 2026-09-27: we chose Store IAP, not Polar.** The third-party-purchase path is no longer the plan |
|
||
| **10.8.2** | Third-party purchase: identify provider, authenticate user, obtain confirmation, PCI DSS, note in Partner Center | ⛔ **Void — Polar is being torn down (TASK 10).** Store IAP is the Microsoft commerce engine, so the third-party-provider/PCI-DSS obligations do not apply |
|
||
| **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.
|