diff --git a/MyMistakes.md b/MyMistakes.md index c0f7bd4..3c32435 100644 --- a/MyMistakes.md +++ b/MyMistakes.md @@ -1362,3 +1362,40 @@ even when the compiler accepts it. `fileName` + `memberName` looks fine and is w shape puts the variable part last and the required context first. This is the same family as the prose-matching lesson — **the aim is to make the wrong thing hard to write, not to detect it afterward** — and I got it wrong in the very commit written to apply that idea. + +## Asked twice about a deliberate, already-documented decision (2026-10-04) + +**What happened:** the creator asked whether the test streams still upload private, and added "I +don't think you're able to delete them". I answered, researched `videos.delete`, and then — in the +very next exchange — *offered to build a cleanup tool*, which re-litigated a decision that has been +settled since 2026-09-01. Then got asked about it again. The creator's response: "I keep telling +you; maybe you should write it down." It **was** written down. The note existed, was accurate, and +named the decision correctly. It still did not work. + +**Why the note failed — this is the actual lesson.** The old text read: + +> **Visibility picker — DELIBERATE TEST-PHASE LOCK, not drift.** The "always Private" enforcement +> stays while the creator runs multi-month real-world testing… The unlock is a deliberate final-pass +> item in **TASK 36**, wired with the dialog selection — never opportunistic. + +Every sentence is **descriptive**. It explains *why* the lock exists and *where* the unlock lives. +Not one sentence instructs the reader. So it told me what the truth was but never told me what to +*do* when the truth looked like a defect — and `privacy=private` in a log line, a PRIVATE badge, and +the absence of any delete call all *look* like defects. I read it, recognised it, and still asked, +because recognition is not instruction. Worse, "never opportunistic" and "TASK 36" pointed at a +*different* answer than the one the creator actually gave me (v1, not TASK 36), so the note was +partly stale on top of being non-directive. + +**The generalisation:** a decision note must be written as a **prohibition addressed to the future +reader, carrying its own trigger** — not as rationale. Three parts, all required: +1. **The verdict, in imperative voice:** "do not change it", not "it stays because". +2. **The trigger condition:** *what you will observe* that makes it look wrong — `privacy=private` + in a log, the PRIVATE badge, no delete call — so recognition fires the instruction automatically. +3. **The correction, verbatim, where it differs from the note.** The creator's answer (v1) was not + what the note said (TASK 36). A note that is confidently wrong is worse than no note: it makes me + confidently re-ask. + +Corollary, and the part I keep skipping: **a repeated user correction is a documentation failure, +not a user annoyance.** The second time the same question gets asked, the correct response is not a +better answer — it is to go find why the written answer did not land, and fix *that*. Answering +well the first time was never the problem; the map was not carrying the instruction. diff --git a/TASKS.md b/TASKS.md index 6393539..21e38d9 100644 --- a/TASKS.md +++ b/TASKS.md @@ -303,6 +303,16 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw ## 1.0 gates (do these before the first shipped build) +- **⛔ Replace the always-Private broadcast lock with a real visibility option (creator ruling, + restated 2026-10-04).** `privacyStatus = "private"` hardcoded in + `YouTubeStreamService.CreateBroadcast` is deliberate and correct for the whole pre-v1 test + phase — it is the reason test VODs of a still-breaking product stay off the channel. At v1 it + becomes a user-selectable visibility option in the Go-Live dialog, wired to the same + `UpdateBroadcastMetadataAsync` path. **Before v1, do not touch it and do not raise it as a + question, observation or suggestion — it has been asked and answered repeatedly.** Full rationale + and the retired "can we delete the test VODs?" question: `ai.md` → YouTube Live API design + constraints. + - **Kill the dev multi-instance affordance.** `Helpers/InstanceProfile.cs` is already entirely `#if DEBUG`, so a Release build ships as `DataRoot => DefaultRoot` / `WebViewDataFolder => null`. Nothing to do but *keep it that way* — and re-prove it: diff --git a/ai.md b/ai.md index 741332d..19b5d99 100644 --- a/ai.md +++ b/ai.md @@ -1717,6 +1717,28 @@ These are the hard facts behind every decision. Full list in `TASKS.md`. to subscribers and serve as post-mortem review tapes; bulk-delete pre-GA. The unlock is a deliberate final-pass item in **TASK 36 (gold pass)**, wired with the dialog selection — never opportunistic. The PRIVATE badge keeps showing when the stream is actually private. +- **⛔⛔ STOP. The always-Private lock is a DECISION, not a bug, not drift, not an open question. + (Creator ruling, restated 2026-10-04 after being asked about it AGAIN.)** + `privacyStatus = "private"` hardcoded in `YouTubeStreamService.CreateBroadcast` is + **exactly right as written. Do not change it, do not "unlock" it, and — this is the part I keep + getting wrong — do not raise it as a question, an observation, a suggestion, or a + "heads-up".** The creator has now answered this more than once. + - **What it becomes:** the hardcoded lock is replaced by a real, user-selectable + visibility option in the Go-Live dialog — **at v1, not before.** Not at 1.0-candidate, not + at GA prep, not opportunistically during any other unit. + - **Why it exists:** pre-v1 test streams would otherwise publish VODs of a product still + breaking, in public, to subscribers. Private keeps those tapes usable for post-mortem review + while staying invisible to the channel's audience. + - **Do not let these look like symptoms of the one they resemble.** All are working as designed: + `privacy=private` in the broadcast diag line; the PRIVATE badge; `recordFromStart`/DVR ON; + and the absence of any delete call in the codebase (there is no delete feature, by design at + this stage — "can we delete the test VODs" is a *retired* question, answered 2026-10-04: + `videos.delete` accepts `youtube.force-ssl` which we already hold, private is a visibility + setting not a deletion lock, and anyway a broadcast that never reaches `live` never becomes a + VOD at all). + - **`CreateBroadcast:112` is not the unlock** — `UpdateBroadcastMetadataAsync` can already set + visibility post-hoc, but that is the retrofit path, not the product change. The product change + is the dialog option at v1. - **Full broadcast form (TASK 9 item 7) — RESCOPED 2026-09-01** — the core editable fields ship (since 2026-08-24) as the always-visible **Text drawer**: title, description, tags, visibility, made-for-kids, live-editable; scheduling ships as **TASK 34** (drawer ☑ Scheduled + adoption at Start). The old **Advanced tab is permanently out of product** (the 10% margin — see TASKS.md → "Out of product"): latency locked `low`, DVR/record-from-start locked on, embed/projection/CC/region fixed at sane defaults, invisible — every exposed field is a support ticket. `categoryId` is removed from `CreateBroadcast` (not a `liveBroadcast` field, silently ignored). Monetization enablement (if ever needed) rides the reward-events chain via `liveBroadcasts.update`, not a form field. Go-live order (TASK 9, shipped 2026-08-16): `BeginGoLive` → `PrepareAndStartLiveAsync` — ensure the reusable stream (`GetOrCreateReusableStreamAsync`, cache it), create the broadcast bound to it (`CreateBroadcast(..., stream.Id)` → `boundStreamId`),