TASK 49 is retired (creator ruling): YouTube owns chat moderation. Its blocked-words filter and hold-for-review run upstream of `liveChatMessages.list` — held messages are never returned (https://stackoverflow.com/questions/74511524/) — so a second local list would duplicate a switch the creator already owns, with a second set of false positives and a second support surface. What we actually owed the platform, and had wrong: - The parser added every item to the overlay. A deleted message arrives as a `tombstone` carrying no text at all ("it has since been deleted … only liveChatId, type and publishedAt are present" — https://developers.google.com/youtube/data/live/reference/rest/v3/liveChatMessages), so every deletion rendered as a BLANK chat row. `hasDisplayContent:false` messages and chat-mode events did the same. - Deletion events (`messageDeletedEvent`/`messageRetractedEvent`/`userBannedEvent`) are documented but have not been delivered to clients for years (https://stackoverflow.com/questions/44346893/), so nothing is built on them; they are skipped if they ever arrive. - Found while testing: Super Chat read `displayString`, but YouTube's field is `amountDisplayString` — every amount silently fell back to a recomposed string, which mangles non-dollar locales. The model's own comment said this was the reason the field exists. Test: `ChatModerationParseTests` — tombstone, no-display-content, chat-mode events all produce no row; a real Super Chat still parses its pre-rendered amount (constraint 4: reward fields are never reinterpreted). Docs: TASK 49 marked retired with the citations, the rule recorded in decisions.md, HANDOFF updated. verify.sh: 550 passed, 0 failed, 0 warnings.
108 lines
12 KiB
Markdown
108 lines
12 KiB
Markdown
# 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)
|
||
|
||
**Day 4 remainder:** TASK 49 (chat profanity filter) then TASK 34 (scheduled streams — its two research
|
||
flags must be cited first). Day 3's resilience row (TASK 32/33) is still outstanding and is a launch
|
||
blocker; the smallest slice is 32·4 (fragmented MP4 on the record block).
|
||
|
||
## 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 | ☐ | RewardEvent persistence: canonical `RewardEvents` table + `superChatEvents.list` 30-day backfill (the session report and journey read it) | [`task-03`](TASKS/task-03-capture-pipeline.md) |
|
||
| 32 | ☐ | Stream resilience: blip retry → measured grace + amber "RECONNECTING" → one-click Back on air → fragmented MP4 → ingest pre-flight | [`task-32`](TASKS/task-32-stream-resilience.md) |
|
||
| 33 | ☐ | Bandwidth auto step-down: pure policy over dropped-frame rate, one-way within a broadcast | [`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: Analytics scopes, watch-hours/Shorts velocity + ETA | [`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; free Steam Demo and paid app use one codebase; paid app ID and Steam Demo setup still pending | [`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)
|