Compare commits
6
Commits
fe80e8c994
...
f8dd1079f3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8dd1079f3 | ||
|
|
ed47480116 | ||
|
|
058bef4312 | ||
|
|
29ef5d5f85 | ||
|
|
d8febbd0d8 | ||
|
|
9fb628b473 |
@@ -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
|
||||
|
||||
@@ -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) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user