12 Free GitHub Actions Concurrency Group Patterns That Won't Corrupt Unity Addressables Builds - 2026
Tuesday: Addressables group move merges. Wednesday: two pushes in twenty minutes. GitHub Actions shows green. Thursday playtest: InvalidKeyException in the installed build. You open logs—the cancelled job stopped mid-catalog write, and the next job restored a poisoned Library/ from cache.
November 2026 Unity 6.x teams add concurrency: cancel-in-progress to stop duplicate CI—then lint and Addressables player builds share one group. Compile passes; player smoke fails. 3-day no-false-green challenge owns cache-key ladder F1–F6; evening cache-bust tutorial owns ContentState hash in actions/cache—this Listicles & Resource Roundups post owns twelve concurrency patterns + ci_cancel_safe_receipt_v1.json before fest promotion.
Non-repetition note: Concurrency cancel preflight (Guide) owns ninety-second X1–X6; Lesson 268 owns BUILD_RECEIPT milestone; Lesson 261 owns cache key column; Resource #28 forward owns bookmark refresh. This URL is the printable pattern catalog + YAML cookbook.
Why this matters now (November 2026)
cancel-in-progressis default advice — Fast feedback onmainwithout understanding Addressables mid-write risk.- Shared
Library/cache — Cancel + restore amplifies partial catalog writes (Library cache preflight). - Fest week push storms — Hotfixes stack while Addressables strip PRs merge.
- False green culture — Green badge ≠ installed player truth (Wednesday smoke).
- Receipt chain —
library_cache_bust_ok→addressables_build_exclusive_ok→demo_smokemust be ordered.
Direct answer: Never share one concurrency.group between fast jobs and Addressables catalog jobs; disable cancel-in-progress on exclusive Addressables work; add rm -rf Library with if: always() after cancel weeks; file ci_cancel_safe_receipt_v1.json; jq-gate merge on addressables_build_exclusive_ok.
Who this listicle is for
| Audience | You will use these patterns to… |
|---|---|
| Beginner | Pick one of four safe templates (cheat sheet below) |
| Solo dev | Split workflows without reading GitHub docs for an hour |
| Tech lead | Pin group naming in #unity-ci |
| Working dev | Copy YAML + wire receipt JSON |
Time: ~25 minutes to adopt patterns 1–4; ~90 minutes for full twelve-pattern audit + receipt.
Beginner cheat sheet — four safe patterns
| Pattern | Group name sketch | cancel-in-progress |
Safe for Addressables? |
|---|---|---|---|
| A — Fast lint | unity-fast-${{ github.ref }} |
Yes | N/A (no catalog writes) |
| B — Addressables exclusive | unity-addressables-exclusive-${{ github.ref }} |
No | Yes |
| C — Post-cancel cleanup | Same workflow, cleanup job |
N/A | Yes (rm -rf Library) |
| D — Deploy / Steam | unity-deploy-${{ github.ref }} |
Yes | Yes (no Library/ coupling) |
Rule: Patterns A and B must use different group strings. Pattern C runs after B even when B is cancelled.
Developer path — receipt + CI tail
- Audit workflow YAML for shared
concurrency.groupstrings. - Apply patterns 1–12 below; log group names in
ci_cancel_safe_receipt_v1.json. - Reproduce one forced cancel week (pattern 4 in 3-day challenge scenario F).
- Add BUILD_RECEIPT column
addressables_build_exclusive_ok. jq -e '.addressables_build_exclusive_ok == true'before merge to fest branch.
The twelve concurrency patterns
Pattern 1 — Split fast lint from Addressables (foundational)
Problem: One group: unity-ci-${{ github.ref }} lets lint cancel Addressables mid-catalog.
# .github/workflows/unity-fast.yml
concurrency:
group: unity-fast-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-and-compile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: echo "compile smoke only"
# .github/workflows/unity-addressables-player.yml
concurrency:
group: unity-addressables-exclusive-${{ github.ref }}
cancel-in-progress: false
Pass when: Group names differ in receipt concurrency_groups—Lesson 268 gate X1.
Beginner note: You do not need three workflow files on day one—Pattern 2 achieves the same split inside one YAML file. The receipt must still log two distinct group strings, not two job names.
Pattern 2 — Disable cancel on Addressables-exclusive job only
Single-file teams: job-level concurrency on the slow job only.
jobs:
addressables-build:
concurrency:
group: unity-addressables-exclusive-${{ github.ref }}
cancel-in-progress: false
runs-on: ubuntu-latest
Fast jobs elsewhere may still use cancel-in-progress: true—X2 pass.
Pattern 3 — Post-cancel Library/ cleanup (if: always())
cleanup-after-addressables:
needs: addressables-build
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rm -rf Library Temp
Fail when: Cleanup runs only on success—cancelled Addressables leaves poison for the next job (X3).
Pattern 4 — Serial player packaging after catalog
player-build:
needs: addressables-build
concurrency:
group: unity-addressables-exclusive-${{ github.ref }}
cancel-in-progress: false
Player job inherits exclusive group—no parallel packaging during catalog writes.
Pattern 5 — Separate deploy / setlive / Steam upload group
# .github/workflows/unity-deploy.yml
concurrency:
group: unity-deploy-${{ github.ref }}
cancel-in-progress: true
SteamPipe upload does not read Library/—safe to cancel independently of Pattern B.
Pattern 6 — Per-ref groups, not repo-global unity-main
| Anti-pattern | Fix |
|---|---|
group: unity-main for all branches |
unity-fast-${{ github.ref }} |
Same group for main and fest_public |
Add branch suffix or workflow filter |
Prevents fest hotfix cancel from killing unrelated main Addressables job on wrong ref.
Pattern 7 — workflow_dispatch long jobs without cancel
on:
workflow_dispatch:
concurrency:
group: unity-addressables-manual-${{ github.run_id }}
cancel-in-progress: false
Manual strip-week builds use run_id group—second dispatch does not cancel first mid-catalog.
Pattern 8 — PR vs push group suffix
concurrency:
group: unity-addressables-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
Optional: allow cancel on PR lint only; set false for push to fest_public via if expression in job-level concurrency.
Pattern 9 — Fork PR isolation
concurrency:
group: unity-fast-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
Fork PRs do not share groups with main Addressables—prevents external PR spam cancelling studio catalog builds.
Pattern 10 — Matrix shard per matrix key
strategy:
matrix:
platform: [StandaloneWindows64, StandaloneLinux64]
concurrency:
group: unity-player-${{ matrix.platform }}-${{ github.ref }}
cancel-in-progress: false
Each platform packages serially within shard—avoid one matrix leg cancelling another mid-Addressables on shared runner cache without Pattern 3.
Pattern 11 — Cache key includes ContentState after cancel week
Pair evening cache-bust—after any cancel week, verify actions/cache key includes AddressablesContentState hash (Lesson 261). Cancel poison mimics stale cache false green.
Pattern 12 — Fail-closed jq on ci_cancel_safe_receipt_v1.json
jq -e '.addressables_build_exclusive_ok == true' release-evidence/unity/ci-cancel/CI_CANCEL_SAFE_RECEIPT.json
Block merge when receipt missing after busy CI week—X5 / X6 in Guide preflight.
Full workflow sketch (patterns 1–3–4–12)
Copy into .github/workflows/unity-addressables-player.yml as a starting point—replace Unity build steps with your licensed runner commands:
name: unity-addressables-player
on:
push:
branches: [main, fest_public]
workflow_dispatch:
concurrency:
group: unity-addressables-exclusive-${{ github.ref }}
cancel-in-progress: false
jobs:
addressables-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Unity Addressables content build
run: |
# Replace with game-ci, unity-builder, or self-hosted invoke
echo "AddressablesPlayerBuildProcessor runs here"
- name: Hash ContentState for cousin 261 receipt
run: |
test -f Library/com.unity.addressables/AddressablesContentState.bin
sha256sum Library/com.unity.addressables/AddressablesContentState.bin
player-build:
needs: addressables-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Package player artifact
run: echo "Standalone player build for Wednesday smoke"
cleanup-after-addressables:
needs: addressables-build
if: always()
runs-on: ubuntu-latest
steps:
- run: rm -rf Library Temp
receipt-gate:
needs: [player-build, cleanup-after-addressables]
runs-on: ubuntu-latest
steps:
- name: Pattern 12 jq gate
run: jq -e '.addressables_build_exclusive_ok == true' release-evidence/unity/ci-cancel/CI_CANCEL_SAFE_RECEIPT.json
Pair evening cache-bust for actions/cache steps on addressables-build—Pattern 11 is not optional when cache restores Library/ across jobs.
Sample BUILD_RECEIPT row (after Pattern 12)
{
"build_label": "november-closeout-2026-rc2",
"library_cache_bust_ok": true,
"addressables_build_exclusive_ok": true,
"ci_cancel_safe_receipt_path": "release-evidence/unity/ci-cancel/CI_CANCEL_SAFE_RECEIPT.json",
"demo_smoke": "pending_wednesday",
"concurrency_patterns_applied": [1, 2, 3, 4, 5, 11, 12]
}
Thursday row review — diff addressables_build_exclusive_ok beside library_cache_bust_ok and demo_smoke in one pass.
Weekly ritual map (November fest month)
| Day | CI action | Patterns |
|---|---|---|
| Monday | Audit YAML for shared groups | 1, 6 |
| Tuesday | Strip / group move merges | 11 + 3-day F |
| Wednesday | Installed smoke on CI artifact | — (smoke ritual) |
| Thursday | Row review + cancel repro if busy week | 4, 12 |
| Friday | Hotfix pushes | 2, 3 |
Document in #unity-ci topic: busy push day triggers Pattern 3 cleanup even when no human remembers to rerun Addressables manually.
ci_cancel_safe_receipt_v1.json (pattern index)
{
"schema": "ci_cancel_safe_receipt_v1",
"build_label": "november-closeout-2026-rc2",
"patterns_applied": [1, 2, 3, 4, 5, 12],
"workflow_paths": {
"fast": ".github/workflows/unity-fast.yml",
"addressables_exclusive": ".github/workflows/unity-addressables-player.yml",
"deploy": ".github/workflows/unity-deploy.yml"
},
"concurrency_groups": {
"fast": "unity-fast-${{ github.ref }}",
"addressables_exclusive": "unity-addressables-exclusive-${{ github.ref }}",
"deploy": "unity-deploy-${{ github.ref }}"
},
"cousin_receipts": {
"library_cache": "release-evidence/unity/ci-cache/UNITY_CI_LIBRARY_CACHE_RECEIPT.json",
"addressables_ci_cache_ladder": "release-evidence/unity/ci-cache-ladder/ADDRESSABLES_CI_CACHE_RECEIPT.json"
},
"gates": {
"X1_split_groups": "pass",
"X2_no_cancel_on_addressables": "pass",
"X3_post_cancel_cleanup": "pass",
"X4_cancel_repro": "pass",
"X5_fail_closed": "pass",
"X6_receipt": "pass"
},
"addressables_build_exclusive_ok": true
}
Pin under release-evidence/unity/ci-cancel/CI_CANCEL_SAFE_RECEIPT.json.
Printable audit checklist
# Unity Addressables concurrency audit — 12 patterns
Date: __________ build_label: __________ Ref: __________
[ ] 1. Fast lint uses separate group from Addressables
[ ] 2. Addressables job has cancel-in-progress: false
[ ] 3. cleanup-after-addressables runs if: always()
[ ] 4. Player build needs addressables-build
[ ] 5. Deploy/Steam uses unity-deploy-* group
[ ] 6. No repo-global unity-main group
[ ] 7. workflow_dispatch uses run_id or exclusive group
[ ] 8. PR vs push suffix documented
[ ] 9. Fork PRs isolated from main Addressables
[ ] 10. Matrix legs documented per platform group
[ ] 11. Cache key includes ContentState after cancel week
[ ] 12. ci_cancel_safe_receipt filed — jq gate wired
Approver: __________ UTC: __________
Minimum six-pattern stack (fest month)
When time-boxed, run 1 + 2 + 3 + 5 + 11 + 12 before November promotion—cousin to 12 setlive checks minimum-six stack for Steam.
| Layer | Pattern | Cousin gate |
|---|---|---|
| Split groups | 1 | X1 |
| No cancel on catalog | 2 | X2 |
| Cleanup | 3 | X3 |
| Deploy isolation | 5 | — |
| Cache truth | 11 | C2 / F4 |
| Receipt jq | 12 | X5–X6 |
Proof table
| Row | Evidence | Pass |
|---|---|---|
| Group split | YAML diff | Lint ≠ Addressables names |
| Cancel policy | Workflow log | No cancel mid-Addressables |
| Cleanup | Cancelled job + next job | Library/ removed |
| Player truth | Installed smoke | No InvalidKey |
| Receipt | CI_CANCEL_SAFE_RECEIPT.json |
addressables_build_exclusive_ok: true |
Scenarios A–H
| ID | Situation | Patterns |
|---|---|---|
| A | First cancel-in-progress add |
1–3 minimum |
| B | Busy Tuesday push storm | 3 + 12 |
| C | Strip week group move | 11 + 3-day F |
| D | Fork PR spam | 9 |
| E | Manual Addressables dispatch | 7 |
| F | Multi-platform matrix | 10 + 3 |
| G | Steam upload same hour | 5 separate from B |
| H | Promote without receipt | Block—12 |
Common mistakes
- One group for everything — Pattern 1 fail.
- Cancel on Addressables — Pattern 2 fail.
- Skip cleanup on cancelled — Pattern 3 fail.
- Blame cache only — Run 11 + 3 together.
- Green compile, broken player — Wednesday smoke still required.
- Merge schemas —
ci_cancel_safe_receipt≠unity_ci_library_cache_receipt.
Troubleshooting
| Symptom | Lane |
|---|---|
| Random InvalidKey after busy CI | 1 + 3 |
| Only fails after second push | 2 |
| Cache key correct, still stale | 11 + 261 |
| Intermittent after cancel | Guide X1–X3 |
| Help #30 fix applied, recurs | 1 group still shared |
Facilitator / contractor SOW snippet
Pin in contractor README for CI-touching roles:
| Rule | Pattern |
|---|---|
No cancel-in-progress: true on Addressables jobs |
2 |
File CI_CANCEL_SAFE_RECEIPT.json before fest merge |
12 |
| Attach cancel repro log after busy push day | 4 |
Do not share unity-main concurrency group |
6 |
Pair multi-channel facilitator contract for who may merge to fest_public.
Cancel vs cache decision tree (developer)
Player InvalidKey after CI green?
├─ Busy push day with cancel? → Patterns 1–3 + Lesson 268 receipt
├─ Addressables group move this week? → Evening cache-bust + 3-day F
├─ No cancel, no group move? → jq inventory preflight + Invalid Key help
└─ Only Editor smoke failed? → Wednesday installed smoke (S4–S6)
Do not skip Pattern 3 because Lesson 261 cache key looks correct—cancel poison and stale cache present identically at compile time.
Pattern pairing matrix (non-repetition)
| Sibling content | Owns | This listicle owns |
|---|---|---|
| Evening cache-bust | C1–C6 cache YAML | Patterns 1–5, 12 |
| 3-day challenge | F1–F6 ladder | Pattern 11 + scenario F hook |
| Guide X1–X6 | Ninety-second gate | Twelve-pattern catalog + printable audit |
| Lesson 268 | BUILD_RECEIPT promotion | YAML cookbook + weekly ritual map |
Grep before editing: do not duplicate the evening tutorial's ContentState hash block here—link Pattern 11 instead.
Tools and sibling reads
- 15-free GitHub Actions CI recipes
- Invalid Key runtime help
- Addressables jq preflight
- Thursday BUILD_RECEIPT review
- Official: GitHub Actions concurrency
Key takeaways
- Twelve patterns—four-pattern cheat sheet for beginners, full audit for leads.
cancel-in-progresson Addressables mid-catalog is the root poison class.rm -rf Librarywithif: always()is non-optional on fest months.ci_cancel_safe_receipt_v1.jsonindexes which patterns you adopted.- Pattern 11 pairs cache bust—cancel mimics stale
Library/restore. - 3-day challenge scenario F validates cancel + clean.
- Lesson 268 promotes receipt to BUILD_RECEIPT.
- Guide preflight is ninety-second X1–X6 recap.
- Resource #28 forward bookmark list—grep repo when published.
- Blender diligence evening is parallel Q4 lane—different drift class.
FAQ
Can Godot teams use these patterns?
Group-split spirit applies; Godot has no Library/—use engine-specific cache cleanup cousin.
Same as 3-day challenge?
Challenge owns F1–F6 cache ladder; this list owns concurrency group cookbook.
Same as evening cache-bust tutorial?
Tutorial owns C1–C6 cache key YAML; patterns 11–12 reference it after cancel weeks.
One workflow file or three?
Patterns 1–2 work in one file with job-level concurrency on Addressables job only.
Does this replace Wednesday smoke?
No—installed binary smoke is separate gate.
Help #30 when it ships?
Fix lane after poison; this list prevents promotion without patterns 1–3–12.
How does this relate to Godot VDF LF evening tutorial?
Godot VDF LF is Steam Linux parse cousin—Unity concurrency is separate engine column on BUILD_RECEIPT.
Should we remove cancel-in-progress entirely?
No—Pattern A keeps fast feedback; isolate cancel from Addressables (1–2).
Conclusion
November CI lies when cancel-in-progress interrupts Addressables catalog writes. Adopt patterns 1–3 minimum, audit all twelve before strip week, file ci_cancel_safe_receipt_v1.json, jq-gate addressables_build_exclusive_ok—then merge.
Next reads: Concurrency cancel preflight (Guide), Lesson 268, 3-day no-false-green challenge, evening cache-bust tutorial, Wednesday smoke.
Print the twelve-pattern audit into release-evidence/unity/ci-cancel/ before your next Tuesday push storm—not after Thursday's InvalidKey thread.