Compare commits

...
6 Commits
5 changed files with 152 additions and 1 deletions
+24
View File
@@ -15,6 +15,30 @@
## 🔬 Recipes registry
### ⛔ NEVER PRINT CREDENTIALS.md — NOT EVEN "FILTERED" (2026-10-09 incident)
**What happened:** to look for an API key, a `sed -n '1,40p' CREDENTIALS.md` piped through a
redaction regex was run. The regex only matched `password: \`…\``; the **"Sudo pattern"
line stores the password inside `echo '…'`**, slipped past the filter, and the full sudo
password was printed into the session output (and so into local session logs and the model
provider's transcript). Owner had to rotate it.
**Rule:** never `cat`/`sed`/`grep`/`read` CREDENTIALS.md (or any secrets file) in a way that
can print values. Redaction regexes are not a safety net — secrets hide in shapes you didn't
anticipate.
- **Need a secret for a command?** Load it into a variable, never echo it:
`PW=$(sed -n 's/.*password:.*\`\(.*\)\`.*/\1/p' CREDENTIALS.md | head -1)` then use `"$PW"`.
- **Need to know what's in the file?** List **keys only**, never values:
`grep -oE '^\s*- \*\*[^*]+\*\*' CREDENTIALS.md` (bold labels) — or ask the owner.
- **Looking for a specific secret?** Test for presence without printing:
`grep -qi 'gitea' CREDENTIALS.md && echo present || echo absent`.
- Secrets in source (e.g. the Google client secret) live in gitignored
`Helpers/OAuthCredentials.cs` — check with `git check-ignore -v`, don't open it.
**Rotation (YunoHost user `gramps`):** YunoHost owns the password (LDAP) — plain `passwd`
may not apply. Owner rotates via web admin → Users → gramps, or
`sudo yunohost user update gramps -p` (prompts). Never route the new password through the AI.
### YOUTUBE STATISTICS ARE JSON STRINGS; TryGetInt64 THROWS ON STRINGS (RECIPE)
YouTube Data API v3 returns `statistics.subscriberCount / viewCount / videoCount` as
+4 -1
View File
@@ -29,7 +29,7 @@
| 07 | Meter scaling amplification | ✅ Done | [`TASKS/task-07-meter-scaling.md`](TASKS/task-07-meter-scaling.md) |
| 08 | Audio milestone | ✅ SHIPPED 2026-08-14 | [`TASKS/task-08-audio-milestone.md`](TASKS/task-08-audio-milestone.md) |
| 09 | YouTube Live Stream Management | ⏳ In progress — items 1–3, 4 shipped; item 5 open; item 6 locked (TASK 36) | [`TASKS/task-09-live-stream-management.md`](TASKS/task-09-live-stream-management.md) |
| 10 | Monetization: watermark-only paid delta (branding flash) | 🔶 **TEARDOWN, not a build** — Polar deleted in favour of Store IAP (2026-09-27); `$10/mo` + `$400` lifetime, no annual | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) |
| 10 | Monetization: watermark-only paid delta (branding flash) | 🔶 **TEARDOWN, not a build** — Polar deleted in favour of Store IAP (2026-09-27); `$10/mo` + `$400` lifetime, no annual. **SUPERSEDED 2026-10-08** — free-forever ruling (watermark-free, gratuity/merch only); see TASK 54 | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) |
| 11 | Post-pause polish batch (creator's 8 review issues) | ✅ SHIPPED 2026-08-15 | [`TASKS/task-11-polish-batch.md`](TASKS/task-11-polish-batch.md) |
| 12 | Master limiter on the live mix | ☐ Queued | [`TASKS/task-12-master-limiter.md`](TASKS/task-12-master-limiter.md) |
| 13 | Social media launch kit | 🔶 Scoped — queued after v1 | [`TASKS/task-13-social-launch-kit.md`](TASKS/task-13-social-launch-kit.md) |
@@ -68,6 +68,9 @@
| 50 | One-button "Publish this video" (resumable upload of the local recording) | ☐ Queued (2026-09-28) | [`TASKS/task-50-publish-recording.md`](TASKS/task-50-publish-recording.md) |
| 51 | **Webcam background effects: Remove + Blur** | ☐ **v1 requirement** — booked 2026-10-08; next up now that the zoom box shipped (TASK 52) | [`TASKS/task-51-webcam-bg-effects.md`](TASKS/task-51-webcam-bg-effects.md) |
| 52 | **Zoom box (anchored 2× magnifier)** | ✅ Done — shipped 2026-10-08 (3 creator corrections during the build: loupe → anchored capture over the full composite, drawn last → never shows the dim shading) | [`TASKS/task-52-zoom-box.md`](TASKS/task-52-zoom-box.md) |
| 53 | **Output-format verification: Shorts/TikTok geometry (9:16)** | ☐ Queued (2026-10-08) — output formats never tested end-to-end; pin + prove the vertical geometry | [`TASKS/task-53-output-formats.md`](TASKS/task-53-output-formats.md) |
| 54 | **Marcom round: free-forever positioning + merch storefront** | 🔶 In progress — llamacasty.com copy live 2026-10-08 (pricing stripped); merch POD + app About links queued | [`TASKS/task-54-marcom-free-merch.md`](TASKS/task-54-marcom-free-merch.md) |
| 55 | **Disk hygiene: log rotation + low-disk guard** | ☐ Queued (2026-10-09) — `startup.log` appears uncapped; also temp alert-clip cleanup + free-space check before recording | [`TASKS/task-55-disk-hygiene.md`](TASKS/task-55-disk-hygiene.md) |
---
+34
View File
@@ -0,0 +1,34 @@
# TASK 53 — Output-format verification: Shorts / TikTok geometry (queued 2026-10-08)
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
**Why:** the output formats have never been tested end-to-end. The site claims "vertical 1080p60
(9:16)" and Shorts-style streams, but nobody has verified that the geometry actually comes out
correct for Shorts and TikTok — safe zones, caption clearance, and the text-safe inset all still
need checking against a real capture.
**Goal:** prove the vertical/short-form path is geometrically correct, or fix the gaps and then
prove it. Make the output formats a tested, locked contract instead of an assumption.
**Slices (one integration test each, in order):**
1. ☐ **What we actually emit** — enumerate the real encoding configurations (widescreen 1080p60/
1080p30/720p60/720p30 + vertical 9:16 1080p60) and pin them in one place (`FfmpegArgs`-adjacent),
each with its own geometry contract test. This turns "formats exist" into "formats are defined".
2. ☐ **9:16 geometry** — vertical render must be true 1080×1920 (or the GUP-negotiated size) with
the composite laid out for a phone: viewer-safe top strip (TikTok/Shorts overlays live top-left
and bottom), caption/text clearance, and the webcam not cropped off-centre. Test: composite a
known layout, decode the output frame, assert dimensions + element placement vs the contract.
3. ☐ **Live-shorts check on a real stream** — private Test Stream at 9:16, then pull the thumbnail/
player quirk list from YouTube (Title visible, overlays); confirm nothing the streamer put on
screen sits under YouTube's own chrome. This is the "never tested" item the creator flagged —
test on a real vertical test stream and cite the observation.
4. ☐ **Recorded .mp4 matches output** — the saved vertical .mp4 must carry the same 9:16 frame the
stream showed, not a squeezed/wider master. Test: record vertical, decode first frames, assert.
**Design decisions:**
- Geometry is a contract with tests, not a hope. Derived ratios (stream vs composite vs canvas)
get a derived-value test so one change can't silently wreck Shorts/TikTok output.
- Keep widescreen untouched — only add what vertical needs (the existing test suite stays green
for 16:9).
+61
View File
@@ -0,0 +1,61 @@
# TASK 54 — Marcom round: free-forever positioning + merch (queued 2026-10-08)
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
**Why:** the monetization decision changed. LlamaCasty launches **watermark-free and free as in beer,
forever** — no paid tiers, no branding flash. The old watermark-paid-delta plan (TASK 10) is
superseded. Money, if any, comes from **gratuity and branded merch**, never from gating the app.
**History of the ruling (creator-led, 2026-10-08):** feature set is locked for v1; there are no new
pricing tiers to build. The compensation decision: ship the app free and watermark-free, put a
coffee jar / merch storefront in front of people, done. Assistant recommendation that was accepted:
**print-on-demand merch** instead of a tip jar for the main channel, because a t-shirt the viewer
wears is free advertising a donation is not.
**Done so far:**
- ✅ llamacasty.com stripped of ALL pricing (2026-10-08): plans ($0/$10/$400), the feature chart,
the "made with LlamaCasty!" flash copy, and the `#pricing` section replaced with a **free-forever
band**: "Free forever. Completely yours." — no watermark, no branding on stream, no subscription,
no account. Nav + footer relinked to `#free`. Deployed + verified live (0 pricing refs).
- ✅ Ruling recorded: no watermark, no branding-flash, app ships as-is.
**Merch plan (accepted, corrected 2026-10-08):**
- **Printful as the producer/fulfillment** (quality + creative control). **Storefront-layer facts
(verified via websearch 2026-10-08 — there is NO free one-site tier that integrates Printful):**
- Printful's built-in storefront ("Quick Stores") = US-seller/US-buyer only, no custom domain.
- **Ecwid:** free Starter plan has **no third-party app integrations** — Printful's own doc states
Printful requires Venture, Business, or Unlimited (Venture ≈ $29/mo annual). Dead on a free tier.
- **PROVIDER DECISION (2026-10-08, after websearch of the POD market):** **Fourthwall**, not
Printful. It eliminates the storefront-layer problem entirely:
- Real free plan ($0/mo, not a trial), **built-in storefront**, connect own domain
(`shop.llamacasty.com`) for free (Pro $19/mo adds .store domain, 0% digital fees).
- Native creator integrations: **YouTube Merch Shelf, Twitch product gifting, TikTok Shop,
Discord** — where the young audience buys.
- Fulfillment incl. **Mexico** (US/UK/EU/CA/MX/AU/JP partners); Merchant of Record (tax/VAT
handled); Fourthwall handles catalog-order customer support.
- **No platform fee on physical products** — base cost + processing (2.9%+30¢ domestic) only;
you keep 100% of markup. Quality-first curated partners (max-ink printing), not supplier lottery.
- vs rivals: Printful/POD = production-only (storefront friction = the whole Square/BigCartel/
Ecwid saga above); Printify = cheapest bases but needs third-party store + own tax/support.
- **GO/NO-GO to verify at signup:** Fourthwall seller payout to a Mexico-based account (MX
*shipping* is confirmed; seller payouts unverified).
- Design assets (llama 816×1645 @300dpi PNG, back-URL text) port as-is; re-confirm the catalog
picks (hoodie, tee, stickers, bottle) in Fourthwall's catalog.
- **Small lineup: 3–5 items** to start (t-shirt, mug, sticker set — the llama logo is the obvious
draw). Assets live in `llamacasty.web/assets/img/` (icon-512.png, logo.webp, gramps-480.webp).
**In-app tasks bundled here (small, App-layer only):**
- ☐ Branding-flash text becomes **"llamacasty.com"** (single small mention) instead of the
"made with LlamaCasty!" overlay — pending the "no branding, completely yours" wording conflict:
a streamer showing zero branding and a streamer showing "llamacasty.com" are different promises;
creator to pick.
- ☐ Add the merch/storefront links to the **About pop-up** so the store is reachable from inside
the app at all times.
**Marcom write-up:** capture this whole decision (positioning, competitor note — Meld Studio runs
free core + paid AI tiers and a merch store; ArtCraft monetizes AI credits — the free-forever
difference) into the dedicated **marcom.md** file once the creator creates it. This task file is the
working copy until then.
+29
View File
@@ -0,0 +1,29 @@
# TASK 55 — Disk hygiene: log rotation + low-disk guard (queued 2026-10-09)
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
**Why (creator ask, 2026-10-09):** "we need some sort of log-rotation so that we don't
inadvertently fill up a user's drive." A free app that quietly eats disk space is a support
ticket and a trust breach.
**What's known (from the 2026-10-09 privacy-policy code research — re-verify before building):**
- `Helpers/AppLog.cs` appends to `%APPDATA%\ytLlive\startup.log`, a timestamped line per entry,
with **no size cap or rotation found** (not specifically searched — confirm first).
- `Services/Encoder/FfmpegEncoder.cs` (~:371) logs **every non-progress ffmpeg stderr line**
(≤400 chars each) — the main growth source over long streams.
- Default alert clip is written to `%TEMP%\ytLive-alert-<id>.mp4`
(`ViewModels/MainViewModel.Chat.cs` ~:106) — confirm whether it's ever deleted.
- Recordings (`.mp4`, default `Downloads`) are user-directed, but nothing checks free space.
**Slices (one integration test each, in order):**
1. ☐ **Size-capped log rotation** — when `startup.log` passes a cap (~5 MB), roll it to
`startup.1.log` (keep 1–2 old files), start fresh. Test: write past the cap, assert the roll
and the bounded total. Standard pattern (NLog/Serilog `fileSizeLimitBytes` +
`retainedFileCountLimit`) — cite in the commit.
2. ☐ **Temp alert clip cleanup** — delete the `%TEMP%` alert clip on app close (and sweep
stale ones at startup). Test: create, close, assert gone.
3. ☐ **Low-disk guard for recordings** — check free space on the record folder's drive before
Record starts, and warn (toast) when it runs low mid-recording. Thresholds TBD with the creator.
**Design decisions:** keep `AppLog`'s call surface unchanged — rotation lives inside it.