Stop Merging Post-Fest Branches Without a Numbered MERGE Exception List - 2026 Opinion

March 5: engineering says "we'll just merge fest-demo-2027-02-postfest into main—it's faster than cherry-pick." March 6: jq March weekly shows build_label bump without a receipt row. March 8: October RC label evening pins fest-demo-2026-10-rc1 while Steamworks still points at February fest depot—because someone merged post-fest without updating steamworks_map or filing an exception.
March 2027 is when compassionate branch merges destroy the post-fest evidence trail you built in February. HOTFIX exception opinion disciplined D1–D7 binary promotion. SHIP exception opinion disciplined holiday freeze → re-entry. Post-fest needs a cousin list with different stakes: every merge from fest branch into trunk during March sprint must appear as the next integer in merge_exception_list_receipt_v1.json—not "quick merge," not "we'll document after October prep," not verbal producer approval in #post-fest-sprint.
This Opinion & Hot Takes piece makes a narrow claim: during March 2027 post-fest sprint, no merge from fest-demo-* or nextfest-* branches into main/trunk/develop happens unless the change is MERGE-00N with same-week Wednesday smoke, build_label lineage update, and producer sign-off—refuse merges that skip the next number even when contractors bill overtime.
Non-repetition note: SHIP exception owns holiday freeze O1–O6. HOTFIX exception owns live-week D1–D7 H1–H6. Setlive case study owns recovery after mismatch. This URL owns numbered MERGE exception list + M1–M6 gates when post-fest branch integration collides with October prep.
Pair jq March weekly sprint, March engineering runway, Sunday February closeout, Friday March capstone (#11 published).
Why this matters now (March 2027 post-fest sprint)
- "Quick merge" culture — Teams treat fest branches as disposable after debrief; merges hide depot and label drift until October promotion.
- jq weekly
build_labelbumps — March sprint weekly ER3 routes bumps to MERGE opinion—this URL supplies MERGE-00N format. - October RC collision — July signup and RC label evening need clean trunk—fest merges without receipts poison L2 branch screenshots.
- Contractor overtime cash — March engineering runway ER3 ties merge work to exception list—unnumbered merges burn cap without audit trail.
- Friday capstone — Forward #11 expects
merge_exception_counton BUILD_RECEIPT before April content update authorization.
Direct answer: Maintain merge-exception-list-2027-postfest.md with monotonic MERGE-001…N, file merge_exception_list_receipt_v1.json, set BUILD_RECEIPT merge_exception_list_ok: true, run Wednesday smoke same ISO week any exception touches player-visible or depot-promoted binaries—refuse trunk merges that skip the next number.
The opinion in one paragraph
Post-fest is not "cleanup week" where git hygiene optional. If you merge a fest branch without incrementing a numbered MERGE exception, you did not integrate fixes—you created a second product timeline inside trunk: February depot assumptions, March feature scope, October labels on BUILD_RECEIPT that jq cannot reconcile, and partners reading setlive recovery folklore again. Micro-studios cannot afford two depot stories before summer freeze. Numbered MERGE lists are the minimum correlation layer between branch names, build_label, steamworks_map, and the smoke ritual you already claim to respect. Verbal "we merged post-fest" is how teams ship October prep on February fest depots while telling stand-up trunk is clean.
Who this opinion is for
| Audience | Why read |
|---|---|
| Solo founder post-debrief | Copy-paste "next MERGE number or no trunk merge" |
| Producer on March sprint | Block merge until list matches smoke + label |
| Engineer | Wire verify_merge_exception_list.sh before PR merge |
| Tech lead planning October RC | Refuse trunk drift before L1–L6 evening |
SHIP vs HOTFIX vs MERGE — format ladder
| List | Window | Schema | Primary gate |
|---|---|---|---|
| SHIP exception | Dec freeze → Jan re-entry | ship_exception_list_receipt_v1 |
O1–O6 |
| HOTFIX exception | Feb live D1–D7 | hotfix_exception_list_receipt_v1 |
H1–H6 |
| MERGE exception | Mar post-fest W10–W13 | merge_exception_list_receipt_v1 |
M1–M6 |
| jq March weekly | Weekly ISO | march_post_fest_sprint_receipt_v1 |
J1–J6 |
Rule: HOTFIX rows do not substitute for MERGE rows after live week ends—archive HOTFIX list at Sunday closeout; start MERGE list at MERGE-001 on first post-fest trunk merge touching fest lineage.
Beginner path — numbered list in 25 minutes
Copy into release-evidence/post-fest/merge-exception-list-2027-postfest.md:
# Numbered MERGE exception list (March 2027 post-fest sprint)
sprint_window: 2027-03-post-fest-sprint
list_owner: producer
next_seq: 2
source_branch_policy: fest-demo-* | nextfest-* only
| Seq | ISO week | Summary | source_branch | target_branch | Touches depot? | build_label_after | Smoke same week? | Owner |
|-----|----------|---------|---------------|---------------|----------------|-------------------|------------------|-------|
| MERGE-001 | W10 | Integrate pager crash fix from postfest-1 | fest-demo-2027-02-postfest-1 | main | yes | fest-demo-2027-02-rc3-postfest-1 | yes | engineering |
| MERGE-002 | (reserved) | — | — | — | — | — | — | — |
Beginner rules:
- Next trunk merge must be
next_seq—no MERGE-003 before MERGE-002 exists. - Depot touch ⇒ smoke same ISO week—cousin Wednesday smoke.
build_label_aftermust update on BUILD_RECEIPT when merge affects player-visible or promoted bits.- Feature scope ⇒ defer—post-fest MERGE list is integration of fest fixes, not new October hero scope.
Success check: Producer can answer "how many post-fest merges hit trunk?" by reading highest Seq integer.
Developer path — gates M1–M6
| Gate | Check | Fail action |
|---|---|---|
| M1 | exceptions[] seq integers 1..N contiguous |
Fix gaps before merge |
| M2 | next_seq == N+1 in markdown matches JSON |
Sync list + receipt |
| M3 | touches_depot: true ⇒ smoke_receipt_path same ISO week |
Block merge PR |
| M4 | Last build_label_after matches BUILD_RECEIPT build_label |
Fix label lineage |
| M5 | source_branch matches fest pattern documented in policy |
Reject non-fest merges here |
| M6 | merge_exception_list_ok: true + producer sign-off path |
Fail jq weekly bundle |
merge_exception_list_receipt_v1.json (template)
{
"schema": "merge_exception_list_receipt_v1",
"sprint_window": "2027-03-post-fest-sprint",
"generated_at": "2027-03-05T18:00:00Z",
"next_seq": 2,
"source_branch_policy": "fest-demo-*|nextfest-*",
"exceptions": [
{
"seq": 1,
"id": "MERGE-001",
"iso_week": "2027-W10",
"summary": "Integrate pager crash fix from postfest branch",
"source_branch": "fest-demo-2027-02-postfest-1",
"target_branch": "main",
"touches_depot": true,
"touches_binary": true,
"build_label_before": "fest-demo-2027-02-rc3",
"build_label_after": "fest-demo-2027-02-rc3-postfest-1",
"smoke_required": true,
"smoke_receipt_path": "release-evidence/smoke/MERGE_001_SMOKE.json",
"steamworks_map_updated": true,
"steamworks_map_path": "release-evidence/steam/postfest/steamworks_map_v2.json",
"producer_signoff_path": "release-evidence/post-fest/MERGE_001_SIGNOFF.json",
"owner": "engineering",
"march_sprint_weekly_receipt": "release-evidence/post-fest/MARCH_SPRINT_RECEIPT_W10.json",
"engineering_runway_week_cap_usd": 2800
}
],
"pointers": {
"february_closeout": "release-evidence/february-live/FEBRUARY_FEST_CLOSEOUT_RECEIPT.json",
"march_engineering_runway": "release-evidence/ops/march_engineering_runway_receipt_v1.json"
},
"gates": {
"M1": "pass",
"M2": "pass",
"M3": "pass",
"M4": "pass",
"M5": "pass",
"M6": "pass"
},
"merge_exception_list_ok": true
}
Store canonical copy at release-evidence/post-fest/MERGE_EXCEPTION_LIST_RECEIPT.json.
BUILD_RECEIPT row
{
"merge_exception_list_ok": true,
"merge_exception_count": 1,
"merge_exception_list_receipt": "release-evidence/post-fest/MERGE_EXCEPTION_LIST_RECEIPT.json",
"build_label": "fest-demo-2027-02-rc3-postfest-1",
"engineering_runway_ok": true,
"march_post_fest_sprint_weekly_ok": true
}
Fail-closed: If merge_exception_count ≠ exceptions[].length or last build_label_after ≠ build_label, merge gate fails.
verify_merge_exception_list.sh
#!/usr/bin/env bash
set -euo pipefail
LIST="${1:-release-evidence/post-fest/MERGE_EXCEPTION_LIST_RECEIPT.json}"
BR="${2:-BUILD_RECEIPT.json}"
jq -e '.schema == "merge_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 "M1 fail: missing seq $i"; exit 2; }
done
jq -e '
[.exceptions[] | select(.touches_depot == true)
| .smoke_receipt_path] | all(. != null and . != "")
' "$LIST" || { echo "M3 fail: depot touch without smoke"; exit 3; }
LAST=$(jq -r '.exceptions[-1].build_label_after' "$LIST")
BL=$(jq -r '.build_label' "$BR")
[[ "$LAST" == "$BL" ]] || { echo "M4 fail: label mismatch"; exit 4; }
jq -e '.merge_exception_list_ok == true' "$LIST" || exit 6
echo "merge_exception_list verify: OK"
Exit codes: 1 schema, 2 M1 gaps, 3 M3 smoke, 4 M4 label, 5 M5 branch policy, 6 M6 latch.
Merge theater vs honest MERGE exception
| Merge theater | Honest MERGE exception |
|---|---|
| "Cherry-pick later" | MERGE-00N filed before trunk merge |
| "Main is always truth" | build_label_after on BUILD_RECEIPT |
| "October will fix depot" | steamworks_map_updated row when depot touch |
| "Quick merge Friday" | Same-week smoke + jq weekly GREEN |
| Verbal producer OK | producer_signoff_path on disk |
jq weekly integration (ER3 cousin)
When March sprint weekly row_diff shows build_label bump:
jq -r '.exceptions[-1].id' release-evidence/post-fest/MERGE_EXCEPTION_LIST_RECEIPT.json
Must equal latest MERGE id referenced in weekly receipt notes—or weekly diff is RED until MERGE row filed.
Worked example — synthesized MERGE-001
| Step | Action | Result |
|---|---|---|
| W10 Mon | Debrief complete; postfest branch exists | Branch fest-demo-2027-02-postfest-1 |
| W10 Tue | Engineer proposes trunk merge | Producer requests MERGE-001 |
| W10 Tue | File exception row + smoke | M3 GREEN |
| W10 Wed | Merge PR; update BUILD_RECEIPT label | M4 GREEN |
| W10 Wed | jq weekly verify | engineering_runway_ok + merge count aligned |
| W10 Thu | October RC quote arrives | ER4 on runway—merge list proves trunk clean |
Producer rule: No merge contractor week billed without MERGE id on invoice notes field.
Proof table
| Evidence | Proves | Fail signal |
|---|---|---|
| MERGE-001…N markdown | M2 monotonic seq | Gap at MERGE-003 |
| smoke_receipt_path | M3 depot discipline | Merge without smoke |
| BUILD_RECEIPT label | M4 lineage | Trunk label stale |
| steamworks_map_path | Depot truth | October RC on wrong branch |
| verify exit 0 | M6 latch | Verbal "merged" |
| jq weekly crosswalk | ER3 wiring | Bump without MERGE id |
Scenarios A–G
| ID | Situation | Move |
|---|---|---|
| A | Standard post-fest integration | Full M1–M6 before merge |
| B | Zero merges needed | merge_exception_count: 0; merge_exception_list_ok: true with empty exceptions[] |
| C | Cherry-pick only, no trunk merge | Document cherry_pick_only in notes—not MERGE list |
| D | Solo dev, one branch | Same rules—seq still monotonic |
| E | Depot touch without steamworks update | M3 fail until map filed |
| F | jq weekly RED | Pause merges per ER2 cousin |
| G | October RC starting same week | MERGE list must be GREEN before L2 branch screenshot |
Engine / VCS notes
| Tool | Merge discipline |
|---|---|
| Git | PR title includes MERGE-00N; squash merge updates build_label in commit message |
| Perforce | Integrate record links to exception id |
| Plastic | Merge changeset comment cites MERGE id |
| Git LFS | MERGE row notes if pointers drift—pair LFS case study |
Printable producer card
# Post-fest merge gate (before trunk merge)
[ ] Next seq = MERGE-00N in markdown + JSON
[ ] Wednesday smoke same ISO week if depot/binary touch
[ ] BUILD_RECEIPT build_label matches build_label_after
[ ] verify_merge_exception_list.sh exit 0
[ ] jq March weekly GREEN
[ ] Engineering runway column has cap room (ER3)
Signed: __________
Counterarguments (honest limits)
"Cherry-pick is safer than merge."
Cherry-pick still changes trunk—file MERGE row or document cherry_pick_only waiver with smoke.
"We're done with February fest."
Receipt culture continues through March sprint—closeout annex is not trunk hygiene.
"Same as HOTFIX list."
Different window, schema, and gates—cousin discipline, not copy-paste JSON.
"Valve does not require MERGE lists."
Correct—this is team ops before October prep and partner diligence.
Outbound references
- Git merge documentation — branch integration mechanics
- Steamworks branches — depot assignment after trunk changes
Related GamineAI reads
- HOTFIX exception opinion
- SHIP exception opinion
- jq March weekly sprint
- March engineering runway
- Setlive mismatch case study
- October RC label evening
- Wednesday demo smoke
- Sunday February closeout
- PATCH exception opinion — April–June Addressables content-update cousin (catalog hash, not trunk merge)
- Stop Claiming Demo Progress Cloud-Syncs Without Numbered MIGRATE Exceptions — demo→full save migration (≠ MERGE trunk)
Key takeaways
- March 2027 post-fest merges need MERGE-001…N—not verbal "quick merge."
merge_exception_list_receipt_v1.jsongates M1–M6 with depot smoke + label lineage.merge_exception_list_okon BUILD_RECEIPT latches merge discipline.- HOTFIX + SHIP + PATCH cousins—different windows.
- jq March weekly ER3 routes
build_labelbumps here. - March engineering runway ER3 ties merge contractor spend to MERGE id.
steamworks_map_updatedwhen depot touch—October RC L2 depends on truth.- Forward #11 Friday March capstone (published) expects stable
merge_exception_count. - Empty
exceptions[]allowed when zero trunk merges—still file receipt. verify_merge_exception_list.shgives CI one exit code before merge PR.- Cherry-pick without trunk merge: document waiver—not MERGE theater.
- Prevention beats setlive recovery repeat before October.
- No invented merge metrics—numbered list is the audit artifact.
FAQ
Is this the same as HOTFIX exception list?
No—HOTFIX is live-week binary promotion; MERGE is post-fest branch into trunk during March sprint.
Can we merge without touching depot?
If merge is docs-only, set touches_depot: false and touches_binary: false—M3 smoke waived with producer note.
How does jq weekly diff relate?
build_label bump in weekly diff should reference latest MERGE id in notes.
What if we need zero merges?
File receipt with exceptions: [], merge_exception_count: 0, merge_exception_list_ok: true.
Does this block October RC label evening?
No—MERGE discipline enables clean L2 branch screenshot by proving trunk lineage.
When does Friday capstone (#11) consume this?
End of March—merge_exception_count must match annex before April content update.
Monday stand-up script (producer, 90 seconds)
Read aloud before any "quick merge" discussion:
1. Highest MERGE seq on disk? (markdown + JSON must match)
2. Does this PR touch depot or player binaries? → smoke this ISO week
3. Does BUILD_RECEIPT build_label match last build_label_after?
4. jq March weekly GREEN? engineering_runway_ok if contractor week?
5. If any NO → defer merge; file MERGE-00N first
Beginner tip: Stand-up ends when producer can cite one integer—not "we merged post-fest yesterday."
Contractor invoice crosswalk (ER3 cousin)
When March engineering runway bills merge work:
| Invoice field | Required value |
|---|---|
notes |
MERGE-00N + source_branch |
week_iso |
Same as exception iso_week |
cap_bucket |
Engineering (not marketing) |
stop_rule |
ER3 if build_label bump without list |
Developer check: jq weekly row_diff showing build_label bump must include merge_exception_id in weekly receipt notes—or ER3 fires and contractor week pauses until MERGE row exists.
March cluster integration (cousin URLs)
| Backlog | URL | MERGE touchpoint |
|---|---|---|
| #1 Monday debrief | Facilitator card | Debrief annex cites merge_exception_count |
| #8 jq weekly | March sprint diff | build_label bump → MERGE id in notes |
| #9 Cash runway | Engineering worksheet | ER3 blocks merge contractor week |
| #10 MERGE opinion | This URL | M1–M6 + merge_exception_list_ok |
| #11 Friday capstone | March capstone (published) | Consumes full MERGE list at month end |
Working dev path: Wire verify_merge_exception_list.sh in the same CI job as jq weekly verify—one failed gate blocks trunk merge PR and weekly jsonl append.
Archive HOTFIX at Sunday closeout (handoff rule)
After Sunday February closeout annexes hotfix_exception_count, do not append HOTFIX rows during March sprint. First trunk merge from fest lineage starts MERGE-001—even if engineers still say "hotfix" in stand-up. Language drift is how HOTFIX-007 becomes an unlogged trunk merge in W11.
RED / YELLOW / GREEN routing (M gates)
| Signal | Route |
|---|---|
| M1 RED | Fix seq gaps before merge |
| M3 RED | Run Wednesday smoke; update steamworks_map |
| M4 RED | Align BUILD_RECEIPT build_label |
| M6 RED | No trunk merge until verify GREEN |
| jq weekly RED | Pause merges (ER2 cousin) |
| All GREEN | Merge PR + append jq weekly row |
Closing
Post-fest branch merges are not free cleanup—they are depot and label promotions wearing git merge cosplay. File merge_exception_list_receipt_v1.json, increment MERGE-00N before trunk integration, and wire Wednesday smoke when binaries or depots move. Beginners use the markdown template; producers block PRs without seq; working devs run verify before merge. Forward #11 Friday capstone and October RC label expect trunk truth—not February fest ghosts in summer branches.