docs: the always-Private lock is a decision, and it unlocks at v1

Asked twice about a decision that has been settled since 2026-09-01, so this
is a documentation failure rather than a question worth answering a third
time.

The note was already there and it was accurate. It still didn't work, which is
the whole lesson: every sentence in it was descriptive. It said why the lock
exists and where the unlock lives, and not one sentence told the reader what to
DO when it looks like a defect. I read it, recognised it, and asked anyway —
because recognition is not instruction. It also pointed at TASK 36 for the
unlock while the creator's actual answer is v1, so it was confidently wrong on
top of being non-directive, which is worse than saying nothing.

Rewritten as a prohibition carrying its own trigger: verdict in imperative
voice, then the observations that make it look broken (privacy=private in the
diag line, the PRIVATE badge, recordFromStart/DVR on, no delete call in the
codebase) so recognition fires the instruction instead of prompting a question,
then the retired delete question with its verified answer.

Also: it belongs to v1, not TASK 36, and UpdateBroadcastMetadataAsync:112 is a
retrofit path, not the product change.

MyMistakes.md gets the transferable part, because the fix is not "write it
down" — it is "write decisions as prohibitions, not rationale, and treat a
repeated correction as a broken note rather than an impatient user".
TASKS.md gets it under 1.0 gates so it is a tracked deliverable, not prose.
This commit is contained in:
2026-10-04 14:52:33 -07:00
parent 5ad0106502
commit 74da99c988
3 changed files with 69 additions and 0 deletions
+37
View File
@@ -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.
+10
View File
@@ -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:
+22
View File
@@ -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`),