Files
LlamaCasty/TASKS.md
T
gramps 134103c08b feat(33): the step-down acts — one encoder relaunch, one toast, same URL
Slice 3. 589 green, 0 warnings.

- **`FramePump.ChangeEncoderAsync`** is a full pump stop/start, not an encoder swap. A swap leaves an
  in-flight submit pointing at a disposed process, and that faults the loop — which ends the
  broadcast, the one thing a quality step-down must never do. `StopAsync` already awaits the loop and
  flushes, so this reuses the tested path and costs one short freeze, which the ladder accepts.
- **`MainViewModel.StepDown`**: one planner per broadcast, subscribed to `StatsReported`, unsubscribed on
  every stop path. The pump thread only decides; the restart is posted to the dispatcher, because the
  act stops the loop that raised the event.
- **The creator's choice is not rewritten**: `_encoderTierOverride` changes what the encoder emits while
  the dropdown keeps showing what they picked, and the badge adds `· lowered` so the two never disagree
  silently.
- Copy comes from `StepDownPlanner.Describe` (machine cause owns it, upload cause blames the upload);
  the log gets the cause-tagged line for support.

Test: `EncoderRestartTests` runs a real pump with a fake encoder, changes the tier, and asserts a NEW
encoder started at the new fps/bitrate and produced a frame — the regression that would otherwise ship
as "it lowered the badge and the stream died".

Remaining for 33: shed our own capture cost before the fps step, and the session-report line.
2026-11-09 12:50:53 -08:00

108 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASKS — the active queue
> One line per live item; the detail lives in `TASKS/task-*.md`. Done work is in
> [`TASKS/archive.md`](TASKS/archive.md) (2026-10-29 snapshot of the old catalogue). Retired
> decisions are in [`docs/ai/decisions.md`](docs/ai/decisions.md).
> Markers: ☐ queued · 🔶 in progress · ⏳ blocked · ⏸ deferred · ❌ retired.
## The surge — six days, all remaining coding (2026-11-02 → 11-07)
**Every open coding row is assigned below.** No later phase, no "after launch" list. Target is
**6–8 units a day** (above the measured 3–5 baseline — that is the point of a surge). If a day
overruns, the smallest item moves to the next day; a launch blocker never moves.
**Rules, every unit, no exceptions:** one Good Dog test · clean build 0 warnings · per-class tests
green · `./scripts/verify.sh` on the declared scope · commit with the doc fact it falsifies
corrected. No new scope mid-week; anything discovered goes on a list for day 6.
| Day | Units | Done when |
|---|---|---|
| **1 · Mon** — licensing | Paid-app ownership check (`BIsSubscribedApp`) + Debug fake + app-wide `IsAppOwned` · greyed tier entries · About conversion copy + llamacasty.com link · current-launch Logs tab (replaces the separate system-message strip) · Debug-only `InternalsVisibleTo` | A locked tier opens About without changing the selected free tier or leaving the app; the site opens only from its link |
| **2 · Tue** — release blockers | Visibility flow (creator-selected at release; development/test stays Private) · `OutputProfile` entitlement: 30 fps free / 60 fps paid regardless of resolution · ~~`StreamConfig` defaults~~ retired (no production call sites) · TASK 53 (vertical resolution check ✅; remaining output contract open) · 9·5 webcam identity key · Move transitions (per-layer carry-across-scenes) | Visibility is selectable at creation and live-editable; the 30/60-fps gate is tested; remaining Day 2 items stay queued |
| **3 · Wed** — resilience | TASK 32: blip retry → measured grace → amber RECONNECTING → one-click Back on air → fragmented MP4 → ingest pre-flight · 33 bandwidth step-down | Killing the network mid-broadcast recovers without ending it |
| **4 · Thu** — content & media | ~~3·17 Text layer~~ ✅ · ~~21 media acquisition wiring~~ ✅ (picker, loop, lifecycle) · 49 chat profanity filter · 34 scheduled streams | Text layer renders/persists; media file plays, loops; scheduled stream created |
| **5 · Fri** — data & settings | 3·20 RewardEvent persistence + `superChatEvents.list` backfill · 39·2 YPP slice 2 · 37 defaults-vs-current split · 35 scene-linked audio · 40·A/C/D settings round · 55·2–3 disk hygiene | Session report reads persisted events; defaults can be reverted; temp clips cleaned |
| **6 · Sat** — finish & prove | 50 publish recording · preview undo (Ctrl+Z) · 14 creator feedback batch · 36 gold pass · full sweep: clean build, whole per-class suite, `publish.sh` artifact, EULA/privacy/notices in the artifact · commit + push | Gold pass list empty; artifact stages; suite green; pushed |
**Day 6 is the only polish day.** No polish passes before it — a surge dies on cosmetic passes taken
in the middle.
## Next up (after the surge slice)
**Start here:** TASK 33 (bandwidth step-down) — the last unbuilt piece of the resilience row, and the
only launch blocker left in code. Then TASK 34 (scheduled streams; its two research flags must be
cited first), then 35 / 37 / 40·A/C/D / 55·2–3. TASK 32 is complete, Back on air included.
## Queue
> Every open coding row here is assigned to a surge day above. Rows still marked ☐ on
> 2026-11-07 are a failure of the plan, not a scheduling note.
| Task | Status | Scope | Detail |
|---|---|---|---|
| 53 | ✅ | Output-format contract — six size/FPS modes, vertical YouTube playback, and recordings visually accepted | [`task-53`](TASKS/task-53-output-formats.md) |
| — | ✅ | Output entitlement code: free at 30 fps / paid at 60 fps regardless of resolution; Steam App ID is still pending | [`commercial`](docs/ai/commercial.md) |
| 3·17 | ✅ | **Text layer** — content, font family/size/weight/style, colour, alignment, drag/resize, persisted (done 2026-11-04) | [`task-03`](TASKS/task-03-capture-pipeline.md) |
| 21 | ✅ | Media source: video file added from the (+) menu decodes, composites, plays its soundtrack, loops, and stops with its last reference (done 2026-11-05) | [`task-21`](TASKS/task-21-media-source.md) |
| 64 | ✅ | **Green/Blue Screen** — detect + key from the decode pipe, offer on add, Amount/Softness/Fringe, opt-in auto-apply, alert clips included, persisted (done 2026-11-05) | [`task-64`](TASKS/task-64-green-blue-screen.md) |
| — | ☐ | Transitions **Move**: per-layer carry-across-scenes flag, per-scene placement, fixed z band | [`ui-surface`](docs/ai/ui-surface.md) |
| 55·2–3 | ☐ | Disk hygiene: delete `%TEMP%` alert clips on close + sweep at startup; low-disk guard before REC (slice 1 shipped) | [`task-55`](TASKS/task-55-disk-hygiene.md) |
| 40·A/C/D | ☐ | App Settings: active-camera picker; persist output resolution + surface transition defaults + confirm-before-End; accent consolidation | [`task-40`](TASKS/task-40-app-settings-round.md) |
| 3·20 | ✅ | Session report — **derived from `superChatEvents.list` on demand, not persisted** (YouTube is the authority; no ledger). Per-currency totals, money off by default (done 2026-11-05) | [`task-03`](TASKS/task-03-capture-pipeline.md) |
| 32 | ✅ | Stream resilience: fragmented MP4, blip retry, poll-driven RECONNECTING (no countdown — YouTube's cutoff is not a constant), ingest pre-flight, one-click Back on air (`BackOnAirTests`) | [`task-32`](TASKS/task-32-stream-resilience.md) |
| 33 | 🔶 | Auto step-down — **`StepDownPolicy` + 12 unit tests done 2026-11-09** (two ladders, budgets, floors, cooldown, ambiguity, recovery behind a flag); policy, planner, VM watch, encoder relaunch and the toast are in (17 tests); remaining: shed our own capture cost before the fps step, and the session-report line | [`task-33`](TASKS/task-33-bandwidth-step-down.md) |
| 34 | ☐ | Scheduled streams (Text-drawer version) | [`task-34`](TASKS/task-34-scheduled-streams.md) |
| 35 | ☐ | Scene-linked audio | [`task-35`](TASKS/task-35-scene-linked-audio.md) |
| 37 | ☐ | Defaults vs current layout split (build-id); enables one-click revert to defaults | [`task-37`](TASKS/task-37-defaults-current-split.md) |
| — | ✅ | **Preview undo (Ctrl+Z / Ctrl+Shift+Z)** — done 2026-11-01: `Models/PreviewHistory` + `MainViewModel.Preview`, one step per gesture, gated on `EditingActive`, cleared on layout load. Property edits not yet in the stack | [`ui-surface`](docs/ai/ui-surface.md) |
| 39·2 | ✅ | YPP slice 2 — three eligibility bars (subs / watch hours / Shorts views) from Analytics, dated thresholds with a staleness test, "x of 3 criteria met" (done 2026-11-05) | [`task-39`](TASKS/task-39-ypp-journey-tracker.md) |
| 49 | ❌ | Chat profanity filter — **retired 2026-11-05**: YouTube owns moderation (blocked words + hold for review run before the API). Replaced by not rendering YouTube's moderation markers (tombstones / no-display events) | [`task-49`](TASKS/task-49-chat-profanity-filter.md) |
| 50 | ☐ | One-button publish of the local recording (resumable upload) | [`task-50`](TASKS/task-50-publish-recording.md) |
| 54 | 🔶 | Freemium: EULA + privacy shipped; one codebase for free Demo + paid app. **Blocked on Valve**: identity verification pending, tax review up to 30 business days; app IDs, store page and build review all follow | [`task-54`](TASKS/task-54-marcom-free-merch.md) |
| — | 🔶 | **Steam ownership** — `BIsSubscribedApp(paidAppId)` + Debug fake + app-wide `IsAppOwned`; paid app ID awaits Steamworks | [`commercial`](docs/ai/commercial.md) |
| — | ❌ | **Polar subscription path** — retired 2026-11-01 with the one-price model. Design kept in `decisions.md`, not built | [`decisions`](docs/ai/decisions.md) |
| — | ✅ | **OutputProfile gate** — resolver + `EncoderOptions` wiring (`Models/OutputProfile.cs`, one ffmpeg/two outputs, dev override); higher tiers follow `IsAppOwned` | [`commercial`](docs/ai/commercial.md) |
| — | ✅ | **Demo conversion UI** — owned users get higher tiers; non-owners see greyed tiers, and selecting one opens About with conversion copy and an explicit llamacasty.com link. No browser opens until the link is clicked | [`commercial`](docs/ai/commercial.md) |
| — | ✅ | **System-message strip replaced by Logs tab** — current launch's newest 500 raw AppLog entries, newest-first; no prior-launch import or logging-policy changes | [`ui-surface`](docs/ai/ui-surface.md) |
| — | ☐ | **Steam packaging** — `publish` output + `steam_api64.dll`, paid app and associated Demo setup, depot, `steamcmd` upload, store pages + assets | [`Distribution.md`](Distribution.md) |
| — | ☐ | **Training-video series** — capture the first 8–10 recurring questions as videos on `@llamacasty`; each is documentation, channel content and monetization at once | MARCOM → support→content loop |
| 9·5 | ☐ | Webcam identity key reconciliation | [`task-09`](TASKS/task-09-live-stream-management.md) |
| 14 | 🔶 | Creator feedback batch — branch 3+ | [`task-14`](TASKS/task-14-creator-feedback-batch.md) |
| — | ❌ | Retired: `StreamConfig` defaults are unused; encoder output comes from the selected quality tier | [`Models/index.md`](Models/index.md) |
| 36 | ☐ | **Gold pass** — the v1 gate, always the last unit (see 1.0 gates) | [`task-36`](TASKS/task-36-gold-pass.md) |
| 48 | ⏸ | Distribution & packaging — route settled 2026-10-31 (winget/portable first; Steam + Store parked). Build steps: [`Distribution.md`](Distribution.md); starts after the entitlement seam | [`task-48`](TASKS/task-48-distribution-msix.md) |
| 10 | ❌ | Retired 2026-10-08; superseded by the TASK 54 rows above — the Polar design it described is rebuilt as a lease (`commercial.md`), not revived as written | [`task-10`](TASKS/task-10-monetization.md) |
## Pending the creator's hands (not programming)
- ✅ App Settings grouping + right-click gear — reported working 2026-10-29.
- ✅ Transition picker/durations, Wipe, preview + program transitions — reported working 2026-10-29.
- ✅ Brand logo layer — reported working 2026-10-29.
- ⏳ Vertical-tier camera check (Live tile inside the band, Chat rect-only) — outstanding.
- ⏳ **Webcam cadence**: a Release take in the failing geometry (vertical tier first) blocks Units 1–2.
No fix until a reading names the stage.
## Creator-requested follow-ups (park for Day 6)
- Group controls under **This PC** and **YouTube**.
- ON-AIR opens a preflight using the saved visibility default and an explicit **Start Broadcast — [scope]** action.
- Persistent Help icon immediately left of Edit opens the creator-triggered, app-only 1-2-3 first-broadcast guide. Keep copy top-aligned and high-contrast; never composite the guide into broadcast output.
- Add YouTube category selection; send tags through the video API; support thumbnail upload.
- Add tooltips to settings tabs and make Logs wrapping effective.
## 1.0 gates (before the first shipped build)
- **Release visibility flow** — default to Private; let the creator choose Private/Unlisted/Public
in the ON-AIR preflight and change it live through `UpdateBroadcast`; keep development/test runs
forced Private. Hide the separate TEST button as already decided for v1.
- **Kill the dev multi-instance affordance** — `Helpers/InstanceProfile.cs` is already `#if DEBUG`;
re-prove it on a Release build.
- **Release engineering** — `scripts/publish.sh` **done** (self-contained win-x64, `ffmpeg\`
guarded, no test artifacts), `LlamaCasty.exe` assembly rename **done**, full license texts beside
`THIRD-PARTY-NOTICES.txt` (TASK 4 req 9). Outstanding: Debug-only `InternalsVisibleTo`.
- **Gold pass** (TASK 36): the screens/layers audit, native-Windows verification, and the
branding-flash decision.
## Research
[`research-youtube-api.md`](TASKS/research-youtube-api.md) · [`research-store-certification.md`](TASKS/research-store-certification.md)