docs: decisions log, queue trim, HANDOFF rewrite — the map stops being a treadmill
TASKS.md 467 → 66 lines: one line per live item, detail stays in TASKS/ task-*.md. The old catalogue (63 rows of paragraph status prose plus the historical narration) is preserved verbatim as TASKS/archive.md — a 2026-10-29 snapshot, not the live queue. The "out of product" list and every retired decision moved to docs/ai/decisions.md with cause of death. HANDOFF.md 440 → 40 lines, and it is now OVERWRITTEN, not appended: branch, what's in flight, next action, live landmines, pending creator checks. History belongs to git log; the previous handoff is reachable at ee3c592:HANDOFF.md. docs/ai/decisions.md (new) collects what no longer governs: the paid tier and its pricing, Polar, Store IAP, the Store route and why it died, the deleted Velopack updater, signing economics, the retired monetization ideas, and the permanent out-of-product list. Facts that lived in the old ai.md "Current limitations" section were re-homed rather than dropped with the router rewrite: OAuth/DPAPI/session behaviour → docs/ai/youtube-api.md; paths, persistence and the Google project number → docs/ai/environment.md. verify.sh caps now cover all four always-read files (AGENTS 210, ai 100, HANDOFF 40, TASKS 120). Docs-only unit: scope-check run, no build.
This commit is contained in:
@@ -253,3 +253,25 @@ These are the hard facts behind every decision. Full list in `TASKS.md`.
|
||||
already cover insert. **Real stinger/TTS alert widgets are DONE (TASK 43, shipped
|
||||
2026-09-24) as the native alert box** — see the next section; Text source (TASK 3 item 16)
|
||||
and the RewardEvent persistence (item 20) remain open.
|
||||
|
||||
## Auth & session (YouTube OAuth)
|
||||
|
||||
- `Helpers/OAuthCredentials.cs` holds the real ClientId/ClientSecret. Auth is complete and the
|
||||
session **persists via Windows DPAPI** (`Helpers/TokenStore.cs` → `%APPDATA%\ytLlive\ytLlive.auth`,
|
||||
CurrentUser scope), reloaded best-effort at startup with a proactive refresh of a near-expiry
|
||||
access token.
|
||||
- Sign-in / Change Account lives **inside the Start Stream dialog** — a two-state flow, no separate
|
||||
Connect button. Sign-out is **explicit only**: `StopStream()` does NOT clear the session
|
||||
("stopping a recording leaves the creator signed in", 2026-08-29).
|
||||
- `YouTubeAuthService` takes an optional `HttpClient` + `sessionChanged` + `openBrowser` callback
|
||||
(test seams + save hook; services are constructed in `MainViewModel`).
|
||||
- **Change Account must never sign out first** (fixed 2026-09-27): `SignOutYouTubeAsync` →
|
||||
`TokenStore.Clear()` **deletes** `ytLlive.auth`, so cancelling in the Google chooser left the
|
||||
creator logged out of a working account. It is now just `await SignInAsync()` — success overwrites
|
||||
the token through the `sessionChanged` hook; cancel/failure leaves the session untouched.
|
||||
- **The OAuth flow releases its loopback port on retry:** an abandoned browser attempt holds
|
||||
`localhost:8765` for its 5-minute timeout, so `AuthenticateAsync` cancels and awaits the abandoned
|
||||
attempt before binding, serialised by a `SemaphoreSlim` (`_authGate`) — without the gate, two
|
||||
overlapping calls both see a free port and race to bind it.
|
||||
- Test seam: `YouTubeAuthService.SetSession()` is public — inject a channel with a future
|
||||
`TokenExpiry` so `EnsureToken()` passes offline, paired with `HttpClient(new StubHandler())`.
|
||||
|
||||
Reference in New Issue
Block a user