Discord Fest Live Ops P0 Moderation Webhook Not Firing After Thread Rename - How to Fix
Problem: During February 2027 Steam Next Fest live week, facilitators post P0 keywords (refund, crash, chargeback) in #playtest or a renamed thread, fest_live_moderation_ok on BUILD_RECEIPT is true, but the #fest-ops webhook never delivers. AutoMod may alert; pager sees nothing in the ops channel within the 15-minute community→pager SLA from the moderation listicle.
Who is affected now: Construct and HTML5 teams running the Construct webhook preflight (Guide #39) beside Tuesday CSV jq ingest. Thread rename, archive, or webhook rotation mid-fest breaks routing without updating fest_moderation_webhook_receipt_v1.json. This is live ops webhook routing, not CSV encoding failure or GitHub 422 Whisper bodies.
Fastest safe fix: Confirm DISCORD_FEST_OPS_WEBHOOK_URL env var resolves → run synthetic P0 curl test to #fest-ops → reconcile p0_keyword_map_v1.json AutoMod rule IDs → refresh fest_moderation_webhook_receipt_v1.json → crosswalk facilitator_roster_v1.json discord_oncall for current fest day → set fest_moderation_webhook_ok: true on BUILD_RECEIPT.
Direct answer
Silent webhook after thread rename almost always means the webhook URL or AutoMod rule binding drifted—not that moderators forgot templates. Discord does not auto-update third-party webhook targets when threads move. Re-lock the URL in env/secret (never git), re-map P0 keywords to current AutoMod rule IDs, send one preflight test ping, and file receipt fest_moderation_webhook_ok: true before the next pager handoff.
Why this issue spikes in February 2027 live week
- Thread churn — Facilitators rename
#playtest-feb-d2→#playtestmid-fest; AutoMod rules still point at old channel IDs. - Webhook rotation — Discord invalidates tokens when webhook is deleted/recreated on wrong channel.
- Roster handoffs — D2
discord_oncallchanges but receipt still lists D1 on-call + oldmention_role_id. - Receipt false GREEN — Pre-D1
fest_moderation_webhook_oknever re-tested after rename (M4 skipped). - CSV vs live lane confusion — Tuesday CSV ingest GREEN does not prove webhook GREEN—parallel gates.
Symptoms and search phrases
- P0 player message in thread; no embed in
#fest-opswithin 60 s. curltest returns 401 or 404 against stored webhook URL.- AutoMod does flag keyword; webhook integration does not fire.
fest_moderation_webhook_ok: trueon BUILD_RECEIPT but last ping timestamp before thread rename.- Bot missing
Send Messageson archive or#fest-opsafter permission reset. p0_keyword_map_v1.jsonrule IDs do not match Discord Server Settings → AutoMod.- Facilitator roster shows green;
discord_oncallempty for current fest day.
Root causes (check in order)
- Webhook URL stale — token rotated, channel deleted, or URL copied from wrong server.
- Thread/channel ID drift — AutoMod rule scoped to pre-rename channel.
p0_keyword_map_v1.jsonrule ID mismatch — rule recreated; map not updated.- Env var missing on handoff laptop — pager machine lacks
DISCORD_FEST_OPS_WEBHOOK_URL. - Roster crosswalk stale —
mention_role_idpoints at role with zero members. - Webhook URL in git — rotated for security; CI/local env not updated.
- Wrong cousin receipt — team fixed
fest_live_moderation_receipttemplates but not webhook receipt.
Beginner path (first 15 minutes)
Prerequisites: Discord Manage Webhooks on #fest-ops, moderation listicle M1–M3 done, access to release-evidence/ops/.
- Open
#fest-ops→ confirm webhook integration exists (Integrations → Webhooks). - Copy fresh URL → set
DISCORD_FEST_OPS_WEBHOOK_URLin.env.local(never commit). - Run test ping (Step 2 below)—message must appear in
#fest-ops. - Open AutoMod → verify P0 keywords still match
p0_keyword_map_v1.json. - Update
fest_moderation_webhook_receipt_v1.json→ setfest_moderation_webhook_ok: true→ bump BUILD_RECEIPT.
Common mistake: Renaming the thread only—AutoMod rules are channel-scoped, not thread-title-scoped.
Fastest safe fix path
Step 1 — Verify env lock (M2)
PowerShell:
if (-not $env:DISCORD_FEST_OPS_WEBHOOK_URL) { throw "Webhook env missing — set DISCORD_FEST_OPS_WEBHOOK_URL" }
$env:DISCORD_FEST_OPS_WEBHOOK_URL -match '^https://discord\.com/api/webhooks/\d+/'
Pass: pattern matches. Fail: recreate webhook on #fest-ops → update secret ref in receipt "webhook_secret_ref": "env:DISCORD_FEST_OPS_WEBHOOK_URL".
Step 2 — Synthetic P0 test ping (M4)
curl -sS -o /dev/null -w "%{http_code}" \
-H "Content-Type: application/json" \
-d '{
"username": "Fest-P0-Escalation",
"content": "[RECOVERY] P0 keyword map test after thread rename — build_label=fest-demo-2027-02-rc1",
"allowed_mentions": { "parse": [] }
}' \
"$DISCORD_FEST_OPS_WEBHOOK_URL"
Pass: HTTP 204 or 200; message visible in #fest-ops within 60 s.
Fail 401/404: rotate webhook (Discord → delete old → create on #fest-ops) → update env → retry.
Step 3 — Refresh P0 keyword map (M3)
After thread rename, open Server Settings → AutoMod → Rules and copy current rule IDs into release-evidence/ops/p0_keyword_map_v1.json:
{
"schema": "p0_keyword_map_v1",
"terms": [
{ "keyword": "refund", "automod_rule_id": "NEW_RULE_ID", "severity": "P0" },
{ "keyword": "crash", "automod_rule_id": "NEW_RULE_ID", "severity": "P0" }
],
"case_insensitive": true
}
Verify:
jq -e '.terms | length >= 5' release-evidence/ops/p0_keyword_map_v1.json
Step 4 — Crosswalk facilitator roster (M5)
ROSTER="release-evidence/ops/facilitator_roster_v1.json"
jq -e --arg day "D2" \
'.facilitators[] | select(.fest_day == $day) | .discord_oncall != ""' "$ROSTER"
Update receipt roster_crosswalk.fest_day, discord_oncall, and mention_role_id for current fest day after handoff.
Step 5 — File recovery receipt (M6)
Refresh release-evidence/ops/FEST_MODERATION_WEBHOOK_RECEIPT.json:
{
"schema": "fest_moderation_webhook_receipt_v1",
"fest_window": "2027-02-next-fest-live",
"webhook_secret_ref": "env:DISCORD_FEST_OPS_WEBHOOK_URL",
"webhook_channel": "#fest-ops",
"recovery_reason": "thread_rename_d2",
"test_ping": { "http_status": 204, "sent_utc": "2027-02-23T09:15:00Z" },
"gates": {
"M2_webhook_url_lock": "pass",
"M3_p0_keyword_map": "pass",
"M4_test_ping": "pass",
"M5_roster_crosswalk": "pass",
"M6_receipt": "pass"
},
"fest_moderation_webhook_ok": true
}
BUILD_RECEIPT:
"fest_moderation_webhook_ok": true,
"fest_mod_webhook_last_ping_utc": "2027-02-23T09:15:00Z"
Run verify script from Guide #39 before closing incident.
Verification
| Check | Pass when |
|---|---|
| Env resolves | DISCORD_FEST_OPS_WEBHOOK_URL non-empty |
| Test ping | HTTP 204/200 + visible in #fest-ops |
| Keyword map | ≥5 P0 terms with valid rule IDs |
| Roster | discord_oncall non-empty for today |
| Receipt | fest_moderation_webhook_ok: true |
| SLA | Synthetic P0 → ops channel < 60 s |
Thursday row review — diff fest_mod_webhook_last_ping_utc beside fest_live_moderation_ok.
Alternative fixes (edge cases)
Branch A — AutoMod fires, webhook silent
AutoMod alert action may post to a different channel than your ops webhook. Align AutoMod send alert channel with #fest-ops or add Zapier bridge (listicle Tool 12)—then re-run M4.
Branch B — Thread rename only (forum channel)
For forum threads, AutoMod rules on the parent forum channel still apply—but webhook test must target #fest-ops, not the thread. Do not recreate webhook inside the thread unless that is your documented ops design.
Branch C — Bot permission loss after server boost change
Re-check bot role: View Channel, Send Messages, Embed Links on #fest-ops. Missing Manage Webhooks blocks URL rotation—use admin account for M2.
Branch D — Mid-fest roster swap
Follow listicle mid-fest roster change protocol: update roster JSON → bump fest_mod_webhook_roster_sha256 → re-run M5 only (skip full M1 if listicle cousin still GREEN).
Prevention
- Run Guide #39 preflight before D1 and after any thread rename.
- Pin
fest_mod_webhook_last_ping_utcon BUILD_RECEIPT; nightly pager diff during 5-night challenge. - Document “no rename without ops ping” in facilitator README.
- Keep webhook URL in env/secret only—never Construct export or public repo.
- Separate CSV jq checks from webhook checks on BUILD_RECEIPT—both columns required.
Comparison — three Discord fest lanes
| Symptom | Lane | Fix doc |
|---|---|---|
| Weblate encoding error on CSV | UTF-8 export | Discord CSV UTF-16 help |
| jq empty P0 counts Tuesday | CSV column map | CSV jq Guide #29 |
| Live P0 silent in #fest-ops | Webhook + keyword map | This help |
Related GamineAI reads
- Construct Discord fest webhook preflight (Guide #39) — M1–M6 gates +
fest_moderation_webhook_receipt_v1.json - 14 free February fest live ops moderation tools — full M1–M6 stack + escalation ladder
- Tuesday Discord CSV ingest ritual — pre-live structured export cousin
- February live week timebox — community cap + handoff windows
- 5-night pager challenge — nightly BUILD_RECEIPT diffs
- Lesson 206 — facilitator contract
- Official: Discord webhook docs
FAQ
Is this the same as AutoMod not working?
AutoMod can flag while webhook stays silent—fix URL + map + channel, not templates alone.
Do we rerun the full moderation listicle?
If fest_live_moderation_ok still true, rerun webhook preflight M2–M6 only; if templates/roster broke too, rerun listicle M1–M6.
Can we use the same webhook for Steam pin mirrors?
Yes for Tool 12—but P0 escalation must hit #fest-ops with distinct username Fest-P0-Escalation for searchability.
Thread rename vs new channel?
New channel requires new webhook + AutoMod scope update. Rename usually keeps channel ID—check rule scope anyway.
What ships in Resource #36?
Tool bookmarks for bots/webhooks—this help owns recovery after rename; listicle owns policy.
Bookmark this fix before D2 handoff—silent P0 routing is how refund threads miss pager SLA.