Stop Shipping Post-Fest Hotfix Patches Without a Numbered Post-Fest Patch Exception List - 2026 Opinion

November D+4 after October Next Fest: crash recovery #4 shipped 2026.11.05-trunk02 with POSTFEST-PATCH-001 documented. Retention challenge #3 latched post_fest_retention_ok. Monday stand-up: "refunds still yellow—ship trunk03 tonight." Engineering opens Steamworks. Producer asks "do we need another receipt?" Someone replies "it's just a small fix." Nobody increments POSTFEST-PATCH-002. jq weekly #7 fails J5 next week because build_id changed without a row—and contractor burn-down #8 B-HOTFIX blocks the invoice.
November 2026 is when compassionate post-fest hotfixes destroy the evidence trail you built after fest live. HOTFIX exception disciplined live-week D1–D7 binary bumps. PATCH exception disciplined Addressables catalog ships. SETLIVE exception disciplined upload-week default promotions. Post-fest weeks need a cousin list with different stakes: every demo binary change after fest_live_allowed and branch unset must appear as the next integer in post_fest_patch_exception_list_receipt_v1.json—not "one more fix," not "players are complaining," not verbal producer approval in #post-fest-ops.
This Opinion & Hot Takes piece makes a narrow claim: during November 2026 first weeks after October fest, no trunk build_id promotion that players can download ships unless the change is POSTFEST-PATCH-00N with smoke proof, retention/jq lineage update, and producer sign-off—refuse uploads that skip the next number even when refund charts stay yellow.
Non-repetition note: HOTFIX owns fest live D1–D7. PATCH owns remote catalog Addressables. MERGE owns trunk integration merges. Crash recovery #4 owns C1–C6 narrative when R3 stays RED. This URL owns numbered POSTFEST-PATCH list + P1–P6 when post-fest demo binary churn peaks.
Pair crash recovery #4, contractor burn-down #8, jq weekly #7, PATCH cousin, HOTFIX cousin; forward #10 Wednesday post-fest smoke / #12 capstone; Help #51 forward.
Why this matters now (November 2026 post-October fest)
- "One more fix" culture — Refunds yellow becomes permission for unlimited trunk uploads after fest ended.
- Receipt theater —
post_fest_retention_okGREEN whilebuild_iddrifts without rows. - jq weekly silent changes — Retention jq #7 J5 fails when patches skip POSTFEST-PATCH.
- Contractor hours chase unnumbered patches — Burn-down B-HOTFIX blocks invoices without exception IDs.
- Capstone expects patch latch — Forward #12
child_receipts[]indexespost_fest_patch_exception_list_ok.
Direct answer: Maintain postfest-patch-exception-list-2026-november.md with monotonic POSTFEST-PATCH-001…N, file post_fest_patch_exception_list_receipt_v1.json, set BUILD_RECEIPT post_fest_patch_exception_list_ok: true, run installed smoke same calendar day any exception changes player-downloadable bytes—refuse depot uploads that skip the next number.
The opinion in one paragraph
Post-fest week is not a forgiveness window for silent binaries. If you promote trunk03 because refunds are yellow without incrementing POSTFEST-PATCH-002, you did not help players—you created a second demo timeline: crash recovery receipt for trunk02, Slack lore about trunk03, jq hashes that disagree, and partners reading GREEN flags that hide churn. Micro-studios cannot afford three build_id stories in one November sprint. Numbered POSTFEST-PATCH lists are the minimum authorization layer between smoke logs, retention receipts, contractor burn-down, and the capstone you hope indexes cleanly. Verbal "small fix" is how teams ship demo churn with a green BUILD_RECEIPT toast.
Who this opinion is for
| Audience | Why read |
|---|---|
| Solo founder after fest | Copy-paste "next POSTFEST-PATCH number or no upload" |
| Producer on post-fest support | Block promote until list matches smoke + build_id |
| Engineer | Wire verify_post_fest_patch_exception_list.sh before depot |
| Finance / contractor lead | Map invoice hours to POSTFEST-PATCH IDs |
HOTFIX vs PATCH vs POSTFEST-PATCH — format ladder
| List | Window | Schema | Primary gate |
|---|---|---|---|
| HOTFIX exception | Fest live D1–D7 | hotfix_exception_list_receipt_v1 |
H1–H6 |
| PATCH exception | Content-update season | patch_exception_list_receipt_v1 |
P1–P6 (catalog) |
| POSTFEST-PATCH exception | Nov post-fest weeks | post_fest_patch_exception_list_receipt_v1 |
P1–P6 (demo binary) |
| SETLIVE exception | Oct upload window | setlive_exception_list_receipt_v1 |
S1–S6 |
| Crash recovery #4 | After R3 RED | post_fest_crash_recovery_receipt_v1 |
C1–C6 |
Rule: HOTFIX rows do not substitute for POSTFEST-PATCH after fest ends—HOTFIX window closes when fest live ends. PATCH rows do not substitute when the ship changes demo binary on default trunk—catalog-only bumps stay on PATCH cousin. Prefer zero POSTFEST-PATCH exceptions: forward fix once with smoke, then stop.
Beginner path — when post-fest patch is OK vs never OK
Never OK (post-fest weeks)
- "Refunds are yellow—ship tonight."
- "It's the same fix we discussed in Discord."
- "Crash recovery already GREEN—this is tiny."
- "We'll add the receipt tomorrow."
- "Store capsule tweak needs a new build" (use badge-strip #6—not POSTFEST-PATCH unless binary changes).
OK only with POSTFEST-PATCH-00N
- Menu crash repro fixed on trunk with crash recovery evidence path.
- Refund spike tied to reproducible crash with log folder—not scope rewrite alone.
- Config toggle disable documented in C5 forward fix receipt.
- Partner-mandated hotfix with ticket ID in exception row.
- jq weekly J5 requires documented
build_idchange with note.
Prefer instead of another patch
- Complete uninstall curve #5 scope REWRITE if copy—not binary—drives signal.
- Run retention challenge nightly card before new upload.
- Wait for jq weekly Monday diff before second patch same week.
- If hours are the pressure, use contractor burn-down B-HOTFIX—do not skip the list.
Numbered list in 25 minutes
Copy into release-evidence/post-fest/postfest-patch-exception-list-2026-november.md:
# Numbered POSTFEST-PATCH exception list (November 2026 post-October fest)
post_fest_window: 2026-11-first-weeks
list_owner: producer
next_seq: 2
binary_policy: demo_trunk_only
| Seq | Date | Summary | build_id_before | build_id_after | Smoke path | Owner | Ticket |
|-----|------|---------|-----------------|----------------|------------|-------|--------|
| POSTFEST-PATCH-001 | 2026-11-05 | Menu crash forward fix | 2026-11-01-trunk01 | 2026-11-05-trunk02 | crash-recovery/C6 | eng@studio | internal |
| POSTFEST-PATCH-002 | (reserved) | — | — | — | — | — | — |
Beginner rules:
- Next trunk upload must be
next_seq—no POSTFEST-PATCH-003 before 002 exists. - Installed smoke required same day—two clean installs per crash recovery C6 or forward smoke #10.
build_id_aftermust update BUILD_RECEIPT and jq weekly jsonl.- Store-only edits ⇒ not POSTFEST-PATCH—art/copy receipts own those surfaces.
Developer path — gates P1–P6 (post-fest patch schema)
These P gates belong to post_fest_patch_exception_list_receipt_v1—not PATCH catalog P1–P6. Same letter prefix, different columns.
| Gate | Check | Fail action |
|---|---|---|
| P1 | exceptions[] seq integers 1..N contiguous |
Fix gaps before upload |
| P2 | next_seq == N+1 in markdown matches JSON |
Sync list + receipt |
| P3 | Each row has build_id_before / build_id_after + smoke path |
Block upload |
| P4 | Last build_id_after matches BUILD_RECEIPT + jq weekly tail |
Fix lineage |
| P5 | scope is demo_binary only—no catalog/store-only rows |
Reject out-of-scope |
| P6 | post_fest_patch_exception_list_ok: true + producer sign-off |
Fail capstone bundle |
post_fest_patch_exception_list_receipt_v1.json (template)
{
"schema": "post_fest_patch_exception_list_receipt_v1",
"post_fest_window": "2026-11-first-weeks",
"generated_at": "2026-11-05T18:00:00Z",
"next_seq": 2,
"scope_policy": "demo_binary_trunk_only",
"exceptions": [
{
"seq": 1,
"id": "POSTFEST-PATCH-001",
"date_utc": "2026-11-05",
"summary": "Menu crash forward fix after fest",
"scope": "demo_binary",
"build_id_before": "2026-11-01-trunk01",
"build_id_after": "2026-11-05-trunk02",
"crash_recovery_receipt_path": "release-evidence/post-fest/crash-recovery-2026/receipts/post_fest_crash_recovery_receipt_v1.json",
"smoke_evidence_path": "release-evidence/post-fest/crash-recovery-2026/smoke/C6_two_clean_installs/",
"producer_signoff_path": "release-evidence/post-fest/patches/POSTFEST_PATCH_001_SIGNOFF.json",
"owner": "eng@studio",
"rollback_avoided": true
}
],
"pointers": {
"retention_challenge": "release-evidence/post-fest/retention-challenge-2026/receipts/post_fest_retention_challenge_receipt_v1.json",
"retention_weekly_jq": "release-evidence/post-fest/post_october_fest_retention_weekly_log.jsonl",
"contractor_burn_down": "release-evidence/ops/post_fest_contractor_burn_down_receipt_v1.json",
"branch_unset": "release-evidence/post-fest/branch-unset/post_fest_branch_unset_receipt_v1.json"
},
"gates": {
"P1": "pass",
"P2": "pass",
"P3": "pass",
"P4": "pass",
"P5": "pass",
"P6": "pass"
},
"post_fest_patch_exception_list_ok": true
}
BUILD_RECEIPT root rows
{
"post_fest_patch_exception_list_ok": true,
"post_fest_patch_exception_count": 1,
"post_fest_patch_exception_list_receipt_path": "release-evidence/post-fest/patches/post_fest_patch_exception_list_receipt_v1.json",
"build_id": "2026-11-05-trunk02",
"crash_recovery_ok": true,
"post_fest_retention_ok": true
}
Fail-closed: If post_fest_patch_exception_count ≠ exceptions[].length or last build_id_after ≠ build_id, upload gate fails.
verify_post_fest_patch_exception_list.sh
#!/usr/bin/env bash
set -euo pipefail
LIST="${1:-release-evidence/post-fest/patches/post_fest_patch_exception_list_receipt_v1.json}"
BR="${2:-BUILD_RECEIPT.json}"
jq -e '.schema == "post_fest_patch_exception_list_receipt_v1"' "$LIST" || exit 1
COUNT=$(jq '.exceptions | length' "$LIST")
for i in $(seq 1 "$COUNT"); do
ACT=$(jq -r --argjson n "$i" '.exceptions[] | select(.seq == $n) | .seq' "$LIST")
[[ "$ACT" == "$i" ]] || { echo "P1 fail: missing seq $i"; exit 2; }
done
jq -e '
[.exceptions[] | select(.scope == "demo_binary")
| .smoke_evidence_path] | all(. != null and . != "")
' "$LIST" || { echo "P3 fail: missing smoke path"; exit 3; }
LAST=$(jq -r '.exceptions[-1].build_id_after' "$LIST")
BID=$(jq -r '.build_id' "$BR")
[[ "$LAST" == "$BID" ]] || { echo "P4 fail: build_id mismatch"; exit 4; }
jq -e '.post_fest_patch_exception_list_ok == true' "$LIST" || exit 6
echo "post_fest_patch_exception_list verify: OK"
Producer approval script
POSTFEST-PATCH request:
Seq / next_seq match:
build_id_before → after:
Receipt field (crash_recovery / retention / jq):
Smoke evidence path:
Contractor hours (B-HOTFIX):
Approve Y/N:
Integration with November cluster
| Cousin | Relationship |
|---|---|
| Crash recovery #4 | POSTFEST-PATCH-001 often first row after C5 |
| Contractor burn-down #8 | B-HOTFIX requires exception ID on invoice |
| jq weekly #7 | P4 lineage on build_id |
| Retention #3 | Upstream before first patch |
| Forward #10 smoke | Same-day smoke cousin for non-crash patches |
| Forward #12 capstone | Indexes post_fest_patch_exception_list_ok |
Scenarios A–G
A — Second patch same week without POSTFEST-PATCH-002
P1/P2 fail—block upload; complete jq Monday diff first.
B — Crash recovery without exception row
Violates C5 + this opinion—add POSTFEST-PATCH-001 retroactively only with smoke re-run documented.
C — Catalog-only Addressables bump
Route to PATCH cousin—not POSTFEST-PATCH.
D — Fest live week patch attempt
Route to HOTFIX cousin—window closed post-fest.
E — Scope REWRITE only
Uninstall curve #5—no binary POSTFEST-PATCH.
F — Partner diligence zip
Attach exception list JSON + smoke paths—redact player IDs.
G — Zero patches preferred
Empty list with next_seq: 1 and post_fest_patch_exception_list_ok: true when policy is no post-fest binary changes—document explicitly.
RED / YELLOW / GREEN routing
| Color | Condition | Action |
|---|---|---|
| RED | Upload without next_seq | Block depot promote |
| RED | P4 build_id mismatch | Fix BUILD_RECEIPT + jq |
| YELLOW | One patch week—wait for jq Monday | Hold second patch |
| GREEN | P1–P6 pass | Proceed smoke #10, capstone #12 |
Common mistakes
- Using HOTFIX numbers after fest ended.
- Shipping trunk without smoke path in P3.
- Mixing store art into POSTFEST-PATCH list.
- Skipping contractor B-HOTFIX exception ID on invoice.
- Assuming crash recovery GREEN allows unlimited patches.
- Empty list without explicit zero-patch policy note.
Enterprise notes
- Change control: POSTFEST-PATCH ID in ticket system required.
- Audit: Append-only exception list—no editing prior seq rows.
- Partner comms: "Forward fix POSTFEST-PATCH-00N" language—not "hotfix."
- Security: Smoke logs may contain player paths—redact before partner zip.
- Governance: Producer + engineering dual sign-off on P6—no single-person override after fest.
Monday post-fest patch triage (30 minutes)
Use this sequence before anyone opens SteamPipe for trunk:
- Read jq weekly tail — Retention jq #7
build_idmust match BUILD_RECEIPT. - Classify signal — crash repro (POSTFEST-PATCH candidate) vs copy/scope (uninstall curve #5).
- Check exception list —
next_seqin markdown equals JSON; no gaps in P1. - Reserve hours — Contractor burn-down #8 B-HOTFIX row with POSTFEST-PATCH id placeholder.
- Smoke plan — two clean installs documented before upload completes.
- Run verify script —
verify_post_fest_patch_exception_list.shexit 0 before depot promote. - Append jq jsonl — note POSTFEST-PATCH id in weekly line
notesfield. - Capstone pointer — ensure
post_fest_patch_exception_list_receipt_pathon BUILD_RECEIPT for forward #12.
If step 2 classifies as scope-only, stop—do not burn a POSTFEST-PATCH integer on a store copy tweak.
CI sketch (GitHub Actions)
name: post-fest-patch-gate
on:
workflow_dispatch:
inputs:
exception_list:
default: release-evidence/post-fest/patches/post_fest_patch_exception_list_receipt_v1.json
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: P1-P6 verify
run: ./scripts/verify_post_fest_patch_exception_list.sh "${{ inputs.exception_list }}" BUILD_RECEIPT.json
- name: jq weekly lineage
run: |
LAST=$(jq -r '.exceptions[-1].build_id_after' "${{ inputs.exception_list }}")
TAIL=$(tail -n1 release-evidence/post-fest/post_october_fest_retention_weekly_log.jsonl | jq -r '.build_id')
test "$LAST" = "$TAIL" || { echo "P4 jq tail mismatch"; exit 4; }
Wire this job as a required check before any workflow that uploads demo depots post-fest.
Key takeaways
- Post-fest patches need POSTFEST-PATCH-001…N—not Slack urgency.
- Gates P1–P6 on
post_fest_patch_exception_list_receipt_v1.json(demo binary schema). post_fest_patch_exception_list_okfeeds forward #12 capstone.- Pair crash recovery #4 for first-row narrative.
- Pair contractor burn-down #8 for B-HOTFIX invoice mapping.
- HOTFIX is fest live only.
- PATCH is catalog only.
- Installed smoke same day is P3 hard requirement.
verify_post_fest_patch_exception_list.shfail-closes silent churn.- Prefer zero patches after first forward fix—document policy.
FAQ
Is this the same as HOTFIX during fest?
No—HOTFIX is D1–D7 live week. POSTFEST-PATCH starts after fest ends and branch unset.
Can one patch cover multiple fixes?
One POSTFEST-PATCH row per player-downloadable build_id promotion—bundle fixes in one build, one row.
What if we need a third patch?
POSTFEST-PATCH-003 with new smoke—justify in summary; consider if curve class is stability_issue.
Does store capsule edit need POSTFEST-PATCH?
No—badge-strip #6 owns art surfaces unless binary changes.
Help #51 forward?
Help fix owns runtime unblocker steps; this URL owns numbered authorization policy.
Related reads
- We Recovered Steam Demo Crash Rate Spike After October Fest
- Post-October Fest Contractor Burn-Down Cap Worksheet
- jq Gate Sketch for post_october_fest_retention Weekly Demo Row Diff
- Stop Hotfixing Fest Demos During Live Week
- Stop Shipping Content Updates Without Numbered PATCH Exception List
- 5-Night Post-October Fest Demo Retention Response Challenge
- Wednesday Post-Fest Smoke BUILD_RECEIPT Row Review — forward #10
- Friday Post-October Fest First-Week Capstone — forward #12
- Your First SteamFest Branch Unset Receipt
Closing
Post-fest week tempts teams to treat every yellow metric as permission for another trunk upload. Numbered POSTFEST-PATCH rows are how you ship forward fixes without demo churn theater—smoke proof, build_id lineage, contractor hours, and capstone crosswalk all grep the same integer. When someone says "just one more fix," the answer is the next sequence number—or an explicit zero-patch policy—not vibes.