docs(commercial): the claim page was never needed, signing waits for revenue, and support is a filter
Four things derived this session superseded what the plan said twenty-four hours earlier,
and the docs are corrected where each one died:
**Licensing needs no server.** Polar's customer-portal endpoints authenticate on the key
itself plus the public organization_id; the org access token is only needed to create
products. Channel binding rides in `conditions: {channel_id}`, re-checked on every
validate — so the "claim page" (a hosted OAuth flow that wrote the UC id onto the key)
and the key database it implied are deleted. Device management, key rotation and
subscription auto-revocation are Polar's; four states, one lease, no callback endpoint.
**Signing is deferred until two subscribers.** It never removes the day-one SmartScreen
warning (EV's instant-bypass died in 2024), so buying it before revenue buys only the
publisher line. Renamed to Azure Artifact Signing, $9.99/mo Basic, and it requires a
paid Azure subscription. Year-one fixed cost drops from ~$135 to ~$15.
**The Store account is free.** Microsoft waived the $19 individual fee and removed the
$99 company fee in May 2026, which makes the Store the only zero-cost route to a
Microsoft-signed install — the free answer to SmartScreen, noted beside the paid one.
**Support is a filter, not a promise.** Email, best effort, no SLA, refunds on request
without argument; no training service, no helpdesk. A repeated question becomes a
training video on @llamacasty, which is content and monetization instead of a ticket.
GitHub issues on the releases repo are the deliberate friction.
Also settled: binaries live in a second Gitea repo (`llamacasty-releases`) push-mirrored
to a public GitHub repo — issues and assets public, code private, one publish direction
(a git mirror carries refs, not GitHub Release assets); `@llamacasty` is
standard-verified with intermediate features, so live streaming, >15 min uploads and
custom thumbnails work today and no SIM or ID is needed; and OAuth comes out of Testing
mode by publishing the app (100-user lifetime cap, no 7-day token death).
TASKS.md now opens with the four-day surge slice — artifact shape, output gate,
entitlement seam, real-machine day — because those are what the first public release
waits on. HANDOFF.md rewritten. MyMistakes.md gains the Polar recipe and the
"verify means three different things" entry. MARCOM.md gains the support→content loop
and the surface roles.
This commit is contained in:
+62
-29
@@ -36,14 +36,46 @@ dotnet publish ytLive.csproj -c Release -r win-x64 --self-contained true \
|
||||
settings in `.\data\` instead of `%APPDATA%\ytLlive` (hung off `LayoutPathOverride`). Same binary,
|
||||
USB-stick behaviour, nothing to uninstall.
|
||||
|
||||
## 2. Release
|
||||
## 2. Where releases live — the public handout repo
|
||||
|
||||
**The source repo stays private.** Releases live in a **second Gitea repo,
|
||||
`llamacasty-releases`**, which is push-mirrored to a **public GitHub repo** (`llamacasty/releases`).
|
||||
That public repo holds nothing but a README, an issue template, a known-issues page and the release
|
||||
assets — so the only thing that can ever leak is content authored for publication.
|
||||
|
||||
Why it is shaped that way: GitHub has no "public issues on a private repo" switch, and issue
|
||||
visibility follows repo visibility. An empty public repo gives a public issue tracker, a durable
|
||||
binary URL for winget, and `releases/latest` for the update notice, without the code going anywhere.
|
||||
|
||||
**The mirror carries refs, not release assets.** Git mirrors branches and tags; GitHub Release
|
||||
uploads live outside the object store, so the zip is uploaded separately.
|
||||
|
||||
**Setup, once:**
|
||||
|
||||
1. Gitea → new repo `llamacasty-releases` (private) with `README.md`,
|
||||
`.github/ISSUE_TEMPLATE/bug.yml`, `known-issues.md`.
|
||||
2. Gitea → that repo → **Settings → Mirror Settings → push mirror** →
|
||||
`https://github.com/llamacasty/releases.git` + a GitHub PAT. One-way and force-updating, so the
|
||||
public copy can never drift from what was authored.
|
||||
3. Create the free GitHub **organisation** `llamacasty` so URLs aren't tied to a personal account.
|
||||
4. Point the Steam store page's support URL at
|
||||
`https://github.com/llamacasty/releases/issues/new/choose` — the template chooser, never the
|
||||
open-issue list.
|
||||
|
||||
**Rejected:** a submodule (publishes a pointer, not files), `git subtree split` (three static files
|
||||
don't justify the history surgery, and one stray private file in the prefix leaks forever), and
|
||||
serving zips from the droplet (uses the VPS as a CDN and makes the update notice hand-rolled).
|
||||
|
||||
## 3. Release
|
||||
|
||||
```
|
||||
publish → zip → SHA-256 → GitHub Release → winget manifest PR → update notice
|
||||
publish → zip → SHA-256 → gh release create → winget manifest PR → update notice
|
||||
```
|
||||
|
||||
1. **Tag and publish.** `v<major>.<minor>.<patch>` tag; attach `LlamaCasty-<version>-win-x64.zip`
|
||||
to the **GitHub Release**. Binaries live there, never on the droplet — free CDN, durable URLs,
|
||||
1. **Tag and publish.** `v<major>.<minor>.<patch>` tag; upload
|
||||
`LlamaCasty-<version>-win-x64.zip` with
|
||||
`gh release create v1.0.0 LlamaCasty-1.0.0-win-x64.zip --repo llamacasty/releases
|
||||
--notes-file RELEASE.md`. Binaries live there, never on the droplet — free CDN, durable URLs,
|
||||
release notes in the same place, and `wingetcreate` reads `releases/latest` natively.
|
||||
2. **Record the hash.** `sha256sum` the zip; it goes in the winget manifest and in the release
|
||||
notes. This is the anti-tamper wall: the official channel delivers exactly this artifact or
|
||||
@@ -52,38 +84,38 @@ publish → zip → SHA-256 → GitHub Release → winget manifest PR → update
|
||||
--submit` — it opens the PR against `microsoft/winget-pkgs`. Manifest shape:
|
||||
`InstallerType: portable`, `InstallerSha256`, `NestedInstallerType` where the zip nests the exe.
|
||||
First submission is `wingetcreate new`; the identifier is `LlamaCasty.LlamaCasty`.
|
||||
4. **Update notice.** Write the current version into a small version file on the site (or read
|
||||
`releases/latest` from the GitHub API). The app shows one line — *"v1.4 is out — `winget upgrade
|
||||
LlamaCasty.LlamaCasty`"*. **Nothing downloads or executes**: that is Store policy 10.2.2 and a
|
||||
permanent no (see `product.md`).
|
||||
4. **Update notice.** Commit the current version into the releases repo (so it arrives in the same
|
||||
push or a follow-up commit) or read `releases/latest` from the GitHub API. The app shows one
|
||||
line — *"v1.4 is out — `winget upgrade LlamaCasty.LlamaCasty`"*. **Nothing downloads or
|
||||
executes**: that is Store policy 10.2.2 and a permanent no (see `product.md`).
|
||||
5. **Optional mirrors.** Scoop (a small JSON manifest hosted in a bucket) and Chocolatey (a nupkg
|
||||
with a checksum) — ten minutes each, same audience.
|
||||
6. **MSIX** stays buildable for the parked Store channel: `scripts/package-msix.sh` →
|
||||
`artifacts/LlamaCasty.msix`, submitted nowhere until the Individual account exists.
|
||||
`artifacts/LlamaCasty.msix`, submitted nowhere until the (now free) developer account exists.
|
||||
|
||||
## 3. Signing
|
||||
## 4. Signing — deferred until revenue
|
||||
|
||||
**Azure Trusted Signing, ~$9.99/month** — Microsoft-issued, individuals eligible after identity
|
||||
verification, and it accrues SmartScreen reputation without buying a certificate.
|
||||
**Unsigned is the launch state.** Artifact Signing is bought at **two subscribers**, not before:
|
||||
it never removes the day-one warning (EV's SmartScreen bypass died in March 2024), so the only
|
||||
thing it changes early is the publisher line. Costs and posture:
|
||||
[`docs/ai/commercial.md`](docs/ai/commercial.md).
|
||||
|
||||
```powershell
|
||||
signtool sign /v /fd SHA256 /tr http://timestamp.acs.microsoft.com /td SHA256 `
|
||||
/dlib "Azure.CodeSigning.Dlib.dll" /dmdf "metadata.json" LlamaCasty.exe
|
||||
```
|
||||
|
||||
- **⛔ No EV certificate.** Microsoft removed the EV SmartScreen instant-bypass in March 2024, so
|
||||
EV ($400+/yr) buys exactly what OV (~$150–300/yr) buys — and a bought cert is a 460-day recurring
|
||||
line item whose key must live on an HSM or hardware token.
|
||||
- **No certificate at all** is the interim state: ship unsigned and accept the "unknown publisher"
|
||||
line. winget spares the browser prompt, not the publisher line, so signing is what makes the
|
||||
channel feel legitimate — the reason it is in the year-one budget.
|
||||
- **Signing never clears the warning on day one** — only download volume does. Plan for weeks.
|
||||
- **Azure Artifact Signing** (renamed from "Trusted Signing") — **$9.99/month Basic**, 5,000
|
||||
signatures, **requires a paid Azure subscription**. Individual identity validation is the slow
|
||||
part (days to weeks) and must be renewed; start it when the purchase is decided.
|
||||
- **⛔ No EV certificate, and no certificate with an HSM.** Microsoft removed the EV instant-bypass
|
||||
in March 2024, so EV ($400+/yr) buys exactly what OV (~$150–300/yr) buys.
|
||||
- **The free alternative is the Microsoft Store**: the individual developer fee was waived, and
|
||||
Microsoft signs the MSIX, so a Store install never meets SmartScreen at all.
|
||||
- **Unsigned costs a warning on every release**, because SmartScreen ties reputation to the file
|
||||
hash. Signing accrues reputation to the **publisher** — the only exit from that loop.
|
||||
- **Signing never clears the warning on day one either.** Plan for weeks.
|
||||
- Secrets: the Trusted Signing profile lives in CI secrets; **never commit** a `.pfx` or
|
||||
`metadata.json` with credentials. `MSIX_PFX`/`MSIX_PFX_PASSWORD` are for local test installs only.
|
||||
- Verify every release: `signtool verify /pa /v <file>`, and confirm the hash in the manifest
|
||||
matches the uploaded zip.
|
||||
|
||||
## 4. Release checklist
|
||||
## 5. Release checklist
|
||||
|
||||
- Build clean, 0 warnings (`./scripts/verify.sh`), full test suite green.
|
||||
- `signtool verify /pa` passes on the shipped exe.
|
||||
@@ -95,7 +127,7 @@ signtool sign /v /fd SHA256 /tr http://timestamp.acs.microsoft.com /td SHA256 `
|
||||
- Portable mode: `portable.txt` present → data lands in `.\data\`, deleting the folder deletes the
|
||||
app's footprint.
|
||||
|
||||
## 5. Legal and takedown
|
||||
## 6. Legal and takedown
|
||||
|
||||
- **`LICENSE`** (EULA) forbids redistribution, resale, reverse-engineering and circumvention, and
|
||||
disclaims warranty. It is what makes a mirror site a licence breach rather than a grey area.
|
||||
@@ -109,12 +141,13 @@ signtool sign /v /fd SHA256 /tr http://timestamp.acs.microsoft.com /td SHA256 `
|
||||
hash-pinned delivery, short leases, a free tier good enough that a crack buys nothing, and a
|
||||
licence ID in About. **Not obfuscation, not a native DLL, not hardware locking.**
|
||||
|
||||
## 6. Effort, once
|
||||
## 7. Effort, once
|
||||
|
||||
| Step | Effort |
|
||||
|---|---|
|
||||
| Publish profile + portable mode | 0.5 day |
|
||||
| GitHub Release + hash + version notice | 0.5 day |
|
||||
| Releases repo + Gitea→GitHub push mirror | 0.5 day |
|
||||
| `gh release` + hash + version notice | 0.5 day |
|
||||
| First winget manifest (`wingetcreate new`) | 0.5 day, then ~15 min per release |
|
||||
| Azure Trusted Signing profile + CI step | 0.5 day |
|
||||
| Clean-machine + `winget` smoke test | 0.5 day |
|
||||
| Artifact Signing profile + CI step (deferred) | 0.5 day, at two subscribers |
|
||||
|
||||
Reference in New Issue
Block a user