docs(queue): six veggies, then the new work; scheduling and publishing retired
Creator ruling 2026-11-09: finish the queue before the new features, gold pass always last. **Retired (platform's surface, not ours):** - 34 scheduled streams — YouTube owns scheduling *and* the reminder that makes it worth anything. - 50 publish recording — Studio owns upload (resumable, quota-aware, explains rejections), and an in-app uploader would widen the OAuth consent to whole-channel video management for one convenience. The app adds "Show in folder" instead. **New tasks:** 65 replay clips (the creator-side buffer YouTube does not give you), 66 timed ticker messages, 67 per-event alert videos, 68 edit-while-live + first-run On-Air. **TASK 65 spec** is the interesting one: 15 s is a clip (10/15/20, default 15); the ring holds encrypted *encoded* fragments in RAM — raw 1080p frames would be ~7.4 GB for 15 s — so there is no steady disk write and no crash debris; F10 saves; the replay layer plays once then hides in Live and loops the last 1–3 elsewhere; silent by default; three kept; the layer is excluded from its own clip (hall of mirrors). **TASK 14 gains Branch 3:** mic input gain ahead of the gate (table boom mics fall under it), webcam blank hotkey, opacity/geometry parity with a collapsed Geometry disclosure, Show-in-folder. **Decisions recorded:** the replay-buffer reversal (it was retired in 2022-era reasoning as "different product"; the case for it won), the platform-surface rule, and voice triggering deferred — always- listening in a streaming app hears the game, so the content is its own false-positive source. Queue refactored to 56 lines by archiving completed rows and the superseded surge plan; HANDOFF at 40.
This commit is contained in:
+6
-6
@@ -1,12 +1,11 @@
|
||||
# HANDOFF — 2026-11-09 (TASK 33 policy; vertical checks passed)
|
||||
# HANDOFF — 2026-11-09 (TASK 33 done; queue re-ordered for 1.0)
|
||||
|
||||
## State
|
||||
|
||||
- `main`. TASK 21 (video layer + soundtrack), TASK 64 (green/blue screen) and TASK 32·4 (fragmented MP4)
|
||||
are complete; TASK 49 is retired (YouTube owns chat moderation — we just don't paint tombstones).
|
||||
- **Starting art**: `Assets/starting-background.jpg` is the corrected onboarding screen (earlier
|
||||
images in `Assets/archive/`). Bundled art is hash-keyed into the layout DB, so
|
||||
`StampDefaultBackgroundAsset` compares bytes and re-stamps on a mismatch — no version bump.
|
||||
- **Starting art**: `Assets/starting-background.jpg` is the corrected onboarding screen; bundled art is
|
||||
hash-keyed into the layout DB, so `StampDefaultBackgroundAsset` compares bytes and re-stamps.
|
||||
- Left panel alert stack shipped: Steam licence indicator pinned at row 1, event rows LIFO, click →
|
||||
About or Logs with the event's lines painted. Detail: `docs/ai/ui-surface.md`.
|
||||
- Site: demo video (silent loop) is the hero; Starting screen is in the scenes section.
|
||||
@@ -17,8 +16,9 @@
|
||||
|
||||
## Next action
|
||||
|
||||
- **App queue starts at 34** (scheduled streams; cite its research flags first), then 35/37/40/50/55,
|
||||
Move transitions, 9·5.
|
||||
- **Queue re-ordered (creator ruling):** 35 → 37 → 40 → 55 → Move → 9·5 → 14 slices → 65 (clips) →
|
||||
66 → 67 → 68 → 36. TASK 34 (scheduling) and 50 (publishing) are **retired** — platform's surface.
|
||||
- **New:** 65 replay clips, 66 timed ticker, 67 per-event alert videos, 68 edit-while-live.
|
||||
- Site repo commits are local (`llgit.llamachile.tube`); deploy is `./deploy.sh`, not a push.
|
||||
- Do not push the app absent a checkpoint request.
|
||||
- **Steam is a wait, not a task:** identity verification pending, tax review in Valve's queue (up to 30
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ kept locally, and what is never collected.
|
||||
| Your layout: scenes, sources, assets, settings | `%APPDATA%\ytLlive\ytLlive.db` | So the app looks the same next time |
|
||||
| YouTube sign-in token | `%APPDATA%\ytLlive\ytLlive.auth`, encrypted with Windows DPAPI (CurrentUser) | So you stay signed in; only your Windows account can decrypt it |
|
||||
| Diagnostic log | `%APPDATA%\ytLlive\startup.log`, capped at 5 MB | To diagnose crashes you report |
|
||||
| Recordings | the folder you choose | Your files; the app never uploads them unless you press Publish |
|
||||
| Recordings | the folder you choose | Your files; the app never uploads them |
|
||||
| Replay clips (if you use them) | `clips\` beside your recordings | Only the three most recent are kept; older ones are deleted automatically. Local only, never uploaded |
|
||||
|
||||
Nothing else is written to disk. There is no analytics service, no crash
|
||||
reporter, no advertising SDK and no telemetry of any kind.
|
||||
|
||||
@@ -1,106 +1,55 @@
|
||||
# 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).
|
||||
> One line per live item; the detail lives in `TASKS/task-*.md`. Done work and the retired surge plan are
|
||||
> in [`TASKS/archive.md`](TASKS/archive.md). 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)
|
||||
## Next up
|
||||
|
||||
**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.
|
||||
**Creator ruling 2026-11-09 — finish the queue before the new features, gold pass always last.**
|
||||
|
||||
**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.
|
||||
`35 → 37 → 40·A/C/D → 55·2–3 → Move → 9·5 → 14 (slices) → 65 → 66 → 67 → 68 → 36`
|
||||
|
||||
| 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.
|
||||
The rule behind the two retirements below: **do not rebuild the platform's own surface.** Scheduling,
|
||||
publishing, moderation and channel management are YouTube's; the app owns capture → scene → sound →
|
||||
output.
|
||||
|
||||
## 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) |
|
||||
| 35 | ☐ | **Scene-linked audio** — the scene remembers the room: BRB mutes the mic, Chat restores it, applied once at the live transition | [`task-35`](TASKS/task-35-scene-linked-audio.md) |
|
||||
| 37 | ☐ | **Defaults vs current layout split** — separate branded defaults from the live workspace; enables one-click revert | [`task-37`](TASKS/task-37-defaults-current-split.md) |
|
||||
| 40·A/C/D | ☐ | **Settings round** — active-camera picker; persist output resolution + surface transition defaults + confirm-before-End; accent consolidation | [`task-40`](TASKS/task-40-app-settings-round.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) |
|
||||
| — | ☐ | **Move transition** — per-layer carry-across-scenes flag, per-scene placement, fixed z band | [`ui-surface`](docs/ai/ui-surface.md) |
|
||||
| 9·5 | ☐ | **Webcam identity key reconciliation** — one stable identity per camera across re-plugs | [`task-09`](TASKS/task-09-live-stream-management.md) |
|
||||
| 14 | 🔶 | **Creator feedback batch** — Branch 2 shipped; Branch 3 = mic input gain, webcam blank/standby, opacity+geometry consistency, Show-in-folder on stop | [`task-14`](TASKS/task-14-creator-feedback-batch.md) |
|
||||
| 65 | ☐ | **Replay clips** — 10/15/20 s (default 15), RAM ring of fragmented MP4, F10 to save; replay layer plays once then hides in Live and loops the last 1–3 elsewhere; silent by default; three kept | [`task-65`](TASKS/task-65-replay-clips.md) |
|
||||
| 66 | ☐ | **Timed ticker messages** — "every N minutes show this", from a creator-written list | [`task-66`](TASKS/task-66-timed-ticker.md) |
|
||||
| 67 | ☐ | **Per-event alert videos** — a clip per monetization event, falling back to the default | [`task-67`](TASKS/task-67-per-event-alert-videos.md) |
|
||||
| 68 | ☐ | **Editing while live** + first-run On-Air state matching the 1-2-3 screen | [`task-68`](TASKS/task-68-edit-while-live.md) |
|
||||
| 36 | ☐ | **Gold pass** — the v1 gate: screens/layers audit (every control does something), native-Windows verification, branding-flash decision. Always the last unit | [`task-36`](TASKS/task-36-gold-pass.md) |
|
||||
| 34 | ❌ | **Scheduled streams — retired 2026-11-09.** YouTube owns scheduling *and* the reminder that makes it useful; the app neither creates nor displays scheduled broadcasts, and there is no value in a copy that can fall out of sync | [`decisions`](docs/ai/decisions.md) |
|
||||
| 50 | ❌ | **Publish recording — retired 2026-11-09.** YouTube Studio owns upload (resumable, quota-aware, and it explains rejections). In-app publishing would also widen the OAuth consent to whole-channel video management. The recording lands in the creator's folder; the app adds "Show in folder" instead | [`decisions`](docs/ai/decisions.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 | [`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.
|
||||
| — | ☐ | **Steam packaging** — `publish` output + `steam_api64.dll`, paid app and Demo, depots, `steamcmd` upload, store pages + capsule assets, measured system requirements | [`Distribution.md`](Distribution.md) |
|
||||
| 48 | ⏸ | Distribution & packaging (winget/portable) — parked behind the entitlement seam | [`task-48`](TASKS/task-48-distribution-msix.md) |
|
||||
| — | ☐ | **Training-video series** — 32 subjects listed in `youTubeTrainingVideos.md`; each is documentation, channel content and support deflection at once | `youTubeTrainingVideos.md` |
|
||||
|
||||
## 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.
|
||||
- **Release visibility flow** — default to Private; let the creator choose Private/Unlisted/Public at
|
||||
creation and change it live through `UpdateBroadcast`; keep development/test runs forced Private.
|
||||
- **Kill the dev multi-instance affordance** — `Helpers/InstanceProfile.cs` is `#if DEBUG`; re-prove on a
|
||||
Release build.
|
||||
- **Single-instance guard** — Release has none: two launches share one layout DB (read-whole/write-whole)
|
||||
and one audio pipe. A named mutex that activates the first window.
|
||||
- **Gold pass** (TASK 36).
|
||||
- Release engineering: `publish.sh` **done**, exe rename **done**, full licence texts beside
|
||||
`THIRD-PARTY-NOTICES.txt` needed; Debug-only `InternalsVisibleTo` outstanding.
|
||||
|
||||
## Research
|
||||
|
||||
|
||||
@@ -474,3 +474,55 @@ These were explicitly ruled out:
|
||||
default. Tests: `BrandLogoTests`. On-screen check pending.
|
||||
- ☐ **Cube** — GPU path gated on capability; CPU path only if it holds 60fps.
|
||||
- Gear: right-click opens App Settings (built, on-screen check pending). Left-click menu stays for now.
|
||||
|
||||
---
|
||||
|
||||
# 2026-11-09 trim — completed rows and the retired surge plan
|
||||
|
||||
Moved out of `TASKS.md` when the queue was refactored (creator ruling: finish the queue, then the new
|
||||
features). Nothing here is active; the reasons for the two `❌` rows live in `docs/ai/decisions.md`.
|
||||
|
||||
## Completed
|
||||
|
||||
| Task | Scope |
|
||||
|---|---|
|
||||
| 53 | Output-format contract — six size/FPS modes, vertical YouTube playback, recordings visually accepted |
|
||||
| 3·17 | Text layer — content, font, colour, alignment, drag/resize, persisted (2026-11-04) |
|
||||
| 21 | Media source — video file decodes, composites, plays audio, loops, stops with last reference (2026-11-05) |
|
||||
| 64 | Green/Blue Screen — detect + key from the decode pipe, opt-in auto-apply, alert clips included (2026-11-05) |
|
||||
| 3·20 | Session report — derived from `superChatEvents.list` on demand, never persisted (2026-11-05) |
|
||||
| 39·2 | YPP slice 2 — three eligibility bars, dated thresholds, "x of 3 criteria met" (2026-11-05) |
|
||||
| 32 | Stream resilience — fragmented MP4, blip retry, poll-driven RECONNECTING, ingest pre-flight, one-click Back on air |
|
||||
| 33 | Auto step-down — cause-classified (machine → shed, fps, resolution; upload → bitrate), one-way, floors |
|
||||
| — | Preview undo (Ctrl+Z / Ctrl+Shift+Z) |
|
||||
| — | OutputProfile gate + Demo conversion UI |
|
||||
| — | System-message strip replaced by the Logs tab |
|
||||
|
||||
## Retired rows
|
||||
|
||||
| Task | Why |
|
||||
|---|---|
|
||||
| 49 | Chat profanity filter — YouTube owns moderation (2026-11-05) |
|
||||
| 10 | Polar subscription path — superseded by the one-price model (2026-11-01) |
|
||||
| — | `StreamConfig` defaults — no production call sites |
|
||||
| 34 | Scheduled streams — retired 2026-11-09, platform's surface |
|
||||
| 50 | Publish recording — retired 2026-11-09, platform's surface |
|
||||
|
||||
## The surge plan (2026-11-02 → 11-07) — superseded
|
||||
|
||||
Six days of assigned work, written before the queue was re-ordered. Kept for the record only; the live
|
||||
order is in `TASKS.md`:
|
||||
|
||||
| Day | Units |
|
||||
|---|---|
|
||||
| 1 | Licensing: ownership check, greyed tiers, About conversion, Logs tab |
|
||||
| 2 | Release blockers: visibility flow, 30/60-fps gate, vertical resolution, webcam identity, Move |
|
||||
| 3 | Resilience: TASK 32 + 33 |
|
||||
| 4 | Content & media: text layer, media wiring, profanity filter (retired), scheduled streams (retired) |
|
||||
| 5 | Data & settings: reward persistence, YPP slice 2, defaults split, scene audio, settings round, disk hygiene |
|
||||
| 6 | Finish: publish recording (retired), undo, feedback batch, gold pass, sweep |
|
||||
|
||||
## Creator hands — cleared 2026-11-09
|
||||
|
||||
- Vertical-tier camera check: 1–6 pass (Live tile inside the band, Chat rect-only, 16:9 restored exactly).
|
||||
- Webcam cadence, vertical geometry: 29.8 distinct images/s — the 25.6/s failure does not reproduce.
|
||||
|
||||
@@ -22,3 +22,15 @@
|
||||
13. ✅ Web source URI hidden for webcam — URI section was showing for webcam due to WPF binding path `SelectedElement.Type` not resolving on `WebcamSceneConfig`; replaced with `IsWebSource` virtual property on `SceneElement` (mirrors existing `IsWebcam` pattern), overridden in `Source` to return `Type == SourceType.WebSource`, bound via `BoolToVis`
|
||||
14. ✅ Check/revert consistent order + accept — all three element sections (webcam border, countdown timer, web URI) now use consistent [✕][✓] button order; green check buttons enabled with click handlers that save current values as snapshot baseline (so revert undoes to last accepted state, not initial selection)
|
||||
|
||||
|
||||
### Branch 3 — queued 2026-11-09 (creator testing notes)
|
||||
|
||||
| # | Slice | Why |
|
||||
|---|---|---|
|
||||
| 15 | ☐ **Mic input gain** — a dB stage *ahead of* the gate, meter reads post-gain | A headset mic sits close enough to clear the gate; a table-mounted boom is quieter and the gate eats it. Not AGC — automatic gain pumps on breath and silence. Clipping is already the limiter's job |
|
||||
| 16 | ☐ **Webcam blank / standby** — a visibility hotkey for the webcam layer (tenth registration), optional standby media while hidden | "My webcam has to go away *now*." The privacy blur covers the screen case; this covers the camera in one keystroke |
|
||||
| 17 | ☐ **Opacity + geometry consistency** — every layer type exposes the same opacity control and the same position/size affordances | Parity across layer types. Geometry fields stay, but collapse behind a "Geometry" disclosure: keyboard-only and screen-reader users cannot drag a layer, and precise alignment between two monitors is otherwise guesswork |
|
||||
| 18 | ☐ **Show in folder** — on the stop notification, reveal the finished recording | Publishing is retired to YouTube (TASK 50); the app's remaining job is "where did my file go?" |
|
||||
|
||||
One Good Dog test per slice. If any of them turns out to be a redesign rather than a fix, it gets its own
|
||||
task number instead of hiding in this batch.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# TASK 65 — Replay clips: buffer the last 15 seconds, show it, save it
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
|
||||
> Spec settled with the creator 2026-11-09. **Not a Twitch-clip clone:** the platform owns viewer
|
||||
> clips; this is the creator-side replay buffer YouTube does not give you.
|
||||
|
||||
## The rule
|
||||
|
||||
**15 seconds is a clip.** Options 10 / 15 / 20, default **15**, no slider, no 30. A clip is a moment,
|
||||
not a segment — 3-minute Shorts are the platform's problem, not ours.
|
||||
|
||||
## Why the ring holds encoded bytes, not frames
|
||||
|
||||
A 1080p BGRA composite frame is 8.3 MB; fifteen seconds at 60 fps is **~7.4 GB** of raw frames. The
|
||||
15 MB figure is *after* compression. So the ring keeps **fragmented MP4** (`frag_keyframe+empty_moov`)
|
||||
that ffmpeg writes to a pipe, in a **byte ring in RAM** — never on disk, never raw.
|
||||
|
||||
- Fragments are **1 s** (not 2): the ring can only hand back whole fragments, so a longer fragment
|
||||
means the save can miss the punchline.
|
||||
- The buffer is capped **by bytes**, not seconds — bitrate moves. When 15 s would exceed the cap, the
|
||||
clip is simply shorter.
|
||||
- The ring is a member of the process: it dies with the app, so a crash leaves no debris and needs no
|
||||
sweep. **Nothing touches the disk until F10.**
|
||||
|
||||
## Trigger
|
||||
|
||||
**F10** saves the clip (F1–F9 are taken; F11 is the fallback if a game steals F10). No focus switch, no
|
||||
mouse. Deferred deliberately: **voice triggering** (always-listening in a streaming app is a privacy
|
||||
liability, and the game's own audio produces false positives) and **`!clip`** (only for viewers/mods,
|
||||
never the creator, who cannot reach a keyboard mid-moment).
|
||||
|
||||
## The replay layer
|
||||
|
||||
One layer type, added by the creator to the scenes they want; behaviour comes from the scene:
|
||||
|
||||
| Scene | Behaviour |
|
||||
|---|---|
|
||||
| **Live** | plays the new clip **once**, then **hides** — you're there to see it or you're not |
|
||||
| Every other scene | loops the last **1–3** saved clips **in order** (highlight reel), configurable |
|
||||
|
||||
- **Audio off by default**, toggleable per layer. The show's sound design is the creator's; a replay
|
||||
should not re-mix it uninvited.
|
||||
- **The replay layer is excluded from the clip's own composition.** Otherwise saving while a clip plays
|
||||
records a video of a video (hall of mirrors). Viewers still see it live; the clip simply doesn't.
|
||||
|
||||
## Storage and retention
|
||||
|
||||
- Saved to `clips\` beside recordings, as a normal `.mp4`.
|
||||
- **The three most recent are kept**; the fourth deletes the oldest.
|
||||
- **Auto-clip on monetization events** (off by default): a Super Chat / membership / raid saves the
|
||||
preceding 15 s hands-free. Same retention, so it cannot accumulate.
|
||||
- **Disk discipline:** no steady writes while live (the ring is RAM); the free-space guard that already
|
||||
protects REC also disables the ring when space is low — **the recording always wins**.
|
||||
|
||||
## Privacy
|
||||
|
||||
Named in `PRIVACY.md`: clips are local only, the three most recent are kept, older ones are deleted
|
||||
automatically, and nothing is uploaded. The first save says the same in one line, so the policy is not
|
||||
only a document.
|
||||
|
||||
## Tests
|
||||
|
||||
- Ring: fragment boundaries respected, byte cap enforced, save emits a playable MP4, oldest pruned.
|
||||
- Layer: once-then-hide in Live, in-order loop elsewhere, silent by default, layer excluded from the clip.
|
||||
- Failure: save with an empty ring (just started) says so instead of writing a 0-byte file.
|
||||
@@ -0,0 +1,17 @@
|
||||
# TASK 66 — Timed ticker messages (the ticker's real job)
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md). Creator idea 2026-11-09.
|
||||
|
||||
**Problem.** The ticker today is wired to YouTube events that a new streamer will rarely see — no
|
||||
memberships, no Super Chats, nothing to tick. A feature that fires twice a year is furniture.
|
||||
|
||||
**Idea.** Give the ticker its own clock: a list of creator-written messages plus an interval.
|
||||
|
||||
- Config: interval (minutes) and a list of lines; rotate in order, newest config wins on restart.
|
||||
- Example the creator gave: *every 20 minutes, promote the merch channel*.
|
||||
- Yields to an alert: an event's own ticker beats a scheduled one, and the clock resumes after.
|
||||
- Off by default, one message to start, no randomisation and no scheduling-per-day until asked.
|
||||
|
||||
**Where:** the ticker section of the alert box properties.
|
||||
|
||||
**Tests:** interval firing, rotation order, alert pre-emption, persistence across restart.
|
||||
@@ -0,0 +1,16 @@
|
||||
# TASK 67 — Per-event alert videos
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md). Creator idea 2026-11-09.
|
||||
|
||||
**Problem.** The app plays one alert clip for every event. That single clip was always a placeholder.
|
||||
|
||||
**Idea.** A clip per event kind — Super Chat, Super Sticker, membership, subscription, gift, raid —
|
||||
falling back to the default when a kind has none assigned.
|
||||
|
||||
- Each slot accepts a local file; the existing picker and the decode/keying pipe are reused unchanged
|
||||
(TASK 21 / 64), including green/blue screen — a clip is a clip.
|
||||
- Missing slot → default clip → nothing, in that order, and never an error for the creator who only
|
||||
filled one.
|
||||
- The alert box's display method, sound byte and ticker stay per-event as they already are.
|
||||
|
||||
**Tests:** slot selection per event kind, fallback chain, a keyed per-event clip composites correctly.
|
||||
@@ -0,0 +1,28 @@
|
||||
# TASK 68 — Editing while live, and the first-run On-Air state
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md). Creator rulings 2026-11-09.
|
||||
|
||||
## Part 1 — edit while live
|
||||
|
||||
Creators need to change a layout mid-show: hide a layer, nudge a camera, swap a video. Today editing is
|
||||
gated to "not live", so the only way is to stop the show.
|
||||
|
||||
- Allow the layer panel and geometry edits while streaming/recording.
|
||||
- An edit becomes program immediately — one canvas, no preview/program split — so an accidental drag is
|
||||
visible to viewers. Undo (Ctrl+Z) must therefore be live too, and the UI must say when editing is live.
|
||||
- Preview-mode gestures stay as they are: left = zoom while live, right = menu; **no chord while live**.
|
||||
Editing live is an explicit mode the creator turns on, not something a stray click does.
|
||||
- Never allow: removing the Background, deleting a scene that is on air, changing the output tier's
|
||||
composition mid-frame.
|
||||
|
||||
## Part 2 — first-run state
|
||||
|
||||
The app should open in **On-Air mode** to match the 1-2-3 screen, so the first thing the creator sees
|
||||
is the state they will stream from.
|
||||
|
||||
Risk to settle before building: an armed ON-AIR pill changes what Start does. The 1-2-3 screen must
|
||||
*explain* the state rather than let the app default into the riskier action silently — a creator who
|
||||
expects a recording must not go live by pressing Start.
|
||||
|
||||
**Tests:** edit during a session changes the composite; undo restores; a blocked edit action reports and
|
||||
does nothing; first-run state matches the guide's copy.
|
||||
+17
-3
@@ -219,6 +219,20 @@ Do not build these; each was explicitly ruled out.
|
||||
(<https://stackoverflow.com/questions/44346893/>), so no client-side moderation machinery is built on them.
|
||||
- Virtual camera output — a different product and a device-driver swamp; our output is one
|
||||
YouTube stream.
|
||||
- Replay buffer, stream clipping, multi-destination restreaming, an in-app bug reporter, and an
|
||||
advanced broadcast-form tab (latency/DVR/embed/projection/CC/region are fixed at sane defaults;
|
||||
every exposed field is a support ticket).
|
||||
- Multi-destination restreaming, an in-app bug reporter, and an advanced broadcast-form tab
|
||||
(latency/DVR/embed/projection/CC/region are fixed at sane defaults; every exposed field is a support
|
||||
ticket).
|
||||
- **Replay buffer — REVERSED 2026-11-09 (TASK 65).** It was out on "different product" grounds; the
|
||||
creator's case won: YouTube gives viewers clips but gives the creator no last-15-seconds buffer, so
|
||||
this is the app's surface, not the platform's. Scoped tightly: 10/15/20 s, RAM ring of encoded
|
||||
fragments (raw frames would be ~7.4 GB), three kept, silent by default.
|
||||
- **Do not rebuild the platform's own surface (2026-11-09).** Scheduling and publishing are retired for
|
||||
this reason: YouTube owns scheduled broadcasts *and* the reminder that gives them value, and Studio
|
||||
owns upload (resumable, quota-aware, explains rejections) — reimplementing either would be a worse
|
||||
copy that can fall out of sync. The app's edges are capture → scene → sound → output; everything past
|
||||
the file belongs to YouTube. Publishing would also widen the OAuth consent to whole-channel video
|
||||
management for one convenience.
|
||||
- **Voice triggering — deferred 2026-11-09.** Not a recognition-quality problem: an always-listening
|
||||
trigger in a streaming app hears the *game*, so the content is the false-positive source, and the
|
||||
consent cost is worse than the upload scope we refused. Windows Voice Access or a Stream Deck can
|
||||
send the keystroke; the app keeps F10.
|
||||
|
||||
@@ -66,6 +66,9 @@ launch set already in `MARCOM.md`.
|
||||
| Layout autosave | "close the app, come back, it is where you left it" |
|
||||
| Record with no account, no sign-in | "you do not need YouTube to press record" |
|
||||
| Test stream (private, simulated chat) | "practice without an audience" |
|
||||
| **Replay clips** — F10 saves the last 15 s; a layer replays it (once in Live, a looping reel elsewhere) | "clip that" — the moment nobody had to leave the keyboard for |
|
||||
| **Timed ticker messages** — every N minutes, your own line | "promote something without remembering to" |
|
||||
| **Per-event alert videos** — a different clip per event kind | "your Super Chat gets its own moment" |
|
||||
| **Resilience**: ingest pre-flight (dead network never creates a ghost broadcast), reconnect without ending the stream, one-click **Back on air**, crash-safe fragmented MP4 | "the network dropped and the stream came back" — proof beats a feature list |
|
||||
| Chat overlay (fonts, colours, fade, never stored) | privacy + looks |
|
||||
| Alerts: built-in clip, custom video, sound byte, ticker | "your Super Chat moment" |
|
||||
|
||||
Reference in New Issue
Block a user