fix(chat): stop painting what YouTube removed, and retire the local word filter
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.
This commit is contained in:
@@ -4,7 +4,30 @@
|
||||
> **Research: [`TASKS/research-store-certification.md`](research-store-certification.md) §12.**
|
||||
> Carved out 2026-09-27; shares a scope lock with nothing else.
|
||||
|
||||
**Status:** ☐ Queued — not blocked (does not depend on the route decision)
|
||||
**Status:** ❌ **Retired 2026-11-05** — YouTube owns chat moderation (creator ruling). What replaced it:
|
||||
`Services/YouTubeChatService.cs` no longer turns YouTube's own moderation markers into chat rows
|
||||
(`tombstone`, `hasDisplayContent:false`, chat-mode events), with tests in
|
||||
`ytLive.Tests/ChatModerationParseTests.cs`. The reasoning and citations are below and in
|
||||
`docs/ai/decisions.md`; the body of this file is kept so the option is not re-derived from scratch.
|
||||
|
||||
### Why retired
|
||||
|
||||
- YouTube's **blocked words** filter ("block live chat messages that contain or closely match certain
|
||||
words") and **hold for review** both run upstream of the API: blocked/held messages are not returned
|
||||
by `liveChatMessages.list` (community evidence: held messages never appear —
|
||||
<https://stackoverflow.com/questions/74511524/>). Ours would be a second list, a second set of false
|
||||
positives and a second support surface for a switch the creator already owns.
|
||||
- Deleted messages arrive as a `tombstone` — "signifies that a message used to exist … it has since
|
||||
been deleted … only liveChatId, type and publishedAt are present"
|
||||
(<https://developers.google.com/youtube/data/live/reference/rest/v3/liveChatMessages>). The parser had
|
||||
no filter, so a deletion rendered as a **blank chat row**. That is the actual defect, and it is fixed.
|
||||
- Deletion events (`messageDeletedEvent`/`messageRetractedEvent`/`userBannedEvent`) are documented in
|
||||
the resource but have not been delivered to clients for years
|
||||
(<https://stackoverflow.com/questions/44346893/>), so no client-side moderation machinery can be built
|
||||
on them. The parser skips them if they ever do arrive.
|
||||
|
||||
The constraints below are therefore **moot for us and binding on YouTube** — except constraint 4, which is
|
||||
why the Super Chat parse path still asserts that reward fields are never reinterpreted.
|
||||
|
||||
**Goal:** let the creator decide what reaches the projected chat box, without the app ever
|
||||
becoming a moderator that stores what people said.
|
||||
|
||||
Reference in New Issue
Block a user