We Recovered a Silent February Fest Demo After January Git LFS Pointer Drift - 2026 Case Study

This is a synthesized case study—a field pattern seen across January–February 2027 fest demos when Git LFS pointer files drift after holiday hotfix merges. The game boots, Wednesday smoke cold launch passes, and Discord reports “no music / silent menu.” It is not a named studio turnaround. There are no invented revenue figures, no fake player quotes, and no made-up download counts.
What follows is the failure signature, the isolation order that worked, git_lfs_pointer_drift_receipt_v1.json, and how the pattern maps if your February RC build looks fine in CI but ships pointer stubs instead of FMOD banks.
Pair 5-night FMOD menu snapshot spot, 7-day February RC smoke challenge, January unfreeze audit, Guide #33 Blender mirror cousin forward, and Help forward #37 FMOD spot fix.
Non-repetition note: FMOD challenge owns RTPC spot discipline (P1–P6). Blender glTF mirror evening owns mesh hash mirror. Mismatched save slots case study owns persistence key drift. This URL owns LFS pointer / binary stub recovery—not another menu RTPC ladder.
Why this matters now (January 2027 hotfix week)
- Defer merges resume — December defer authorized SHIP exceptions; audio banks ride in LFS.
.gitattributesconflicts — Contractor rebases re-track extensions; pointers update withoutgit lfs pull.- Silent failures — Boot path works; first FMOD load fails or loads empty—smoke S4 may skip audio if golden path is movement-only.
- February RC pressure — 7-day RC challenge Day 5 hotfix merges touch
Content/andAudio/trees. - CI without LFS — Build agents compile; bank bytes never fetched—artifact looks GREEN.
Direct answer: Recovery required pointer OID audit, git lfs fsck, on-disk bank hash proof, extended smoke S-AUDIO, and git_lfs_pointer_drift_receipt_v1.json with gates LF1–LF6 before next fest-demo-2027-02-rc* promote.
Beginner quick start — what recovered means here
Recovered in this pattern means:
- Reproduced silent or missing menu music on installed Steam build—not editor with local banks.
- Identified at least one LFS-tracked bank file that was a pointer stub (≈130 bytes) in the export tree.
- Restored real bank bytes; rebuilt; re-smoked with audio in golden path.
- Filed receipt JSON; set BUILD_RECEIPT
git_lfs_pointer_drift_ok: true. - Reduced new “no audio” reports for seven days on the same
build_label(qualitative—not a fabricated %).
Success check: Title screen plays menu loop within 5 seconds on clean install; Player.log shows FMOD bank load success, not ERR_FILE_NOTFOUND.
The player-facing failure (typical signals)
| Channel | Typical wording |
|---|---|
| Steam discussion | “No music since Tuesday patch” |
| Playtest form | “Game is silent” |
| Stream clip | Menu visible; zero audio |
| Internal QA | “Works on my machine” (local LFS cache populated) |
Internal language before fix: “FMOD integration broken” — when root cause was export tree held pointers, not studio project corruption.
Starting state (what was wrong)
| Layer | Symptom |
|---|---|
| Git | .gitattributes merge changed *.bank tracking |
| Workspace | git lfs pull not run post-merge on build machine |
| Export | Desktop/fest/Audio/*.bank files ~130 bytes |
| Runtime | FMOD silent or fallback; no crash |
| Smoke | S4 movement-only golden path—S-AUDIO not in checklist |
| BUILD_RECEIPT | demo_smoke_ok: true; no lfs_bank_hash_ok column |
Gameplay ran. Audio truth did not ship.
Root cause pattern (synthesized)
Three recurring mechanics—often combined:
| Mechanic | What drifted |
|---|---|
| Pointer OID mismatch | Merge left pointer referencing deleted LFS object |
| Untracked extension | New .bank committed without LFS filter—CI has stub |
| Stale build agent | Agent cache from pre-merge; fresh clone would fail |
| Submodule / vendor tree | Third-party audio pack LFS not pulled in export job |
None require malice—only missing LFS discipline on January hotfix week.
Timeline (five working days — pattern timing)
| Day | Focus | Output |
|---|---|---|
| D1 | Repro on installed Steam | Recording + Player.log |
| D2 | Pointer vs byte audit | lfs_bank_inventory_v1.json |
| D3 | git lfs fetch + rebuild |
Fixed export hashes |
| D4 | Extended smoke S-AUDIO | demo_smoke_receipt_v1.json |
| D5 | Receipt + BUILD_RECEIPT | git_lfs_pointer_drift_receipt_v1.json |
Teams with January unfreeze rg orphan scan caught stub sizes in D2; teams without took full five days.
Hour-by-hour D1 (reproduction discipline)
| Step | Action |
|---|---|
| 1 | Clean install fest-demo-2027-02-rc1 from Steam library |
| 2 | Note build_label on credits/footer |
| 3 | Launch; wait 10 s on title—record audio pass/fail |
| 4 | Capture Player.log / %LOCALAPPDATA% FMOD lines |
| 5 | Compare to engineer machine with local LFS cache |
| 6 | Confirm smoke receipt lacked S-AUDIO row |
If engineer hears audio and players do not—suspect export byte drift, not mix levels.
Player.log signals (working dev)
| Log fragment | Likely class | Next step |
|---|---|---|
FMOD::File not found |
LF1 stub / missing bank | Size audit |
Failed to load bank + path |
LF3 pull not run | git lfs pull |
| Bank loads; zero bus level | FMOD spot | RTPC ladder |
| No FMOD lines at all | Integration init | WebGL boot cousin |
rg -i "fmod|bank|audio" Player.log | tail -40
Save excerpt to release-evidence/audio/lfs-drift/player-log-fmod-excerpt.txt for receipt evidence.
Producer note: If playtest CSV rows lack an audio pass/fail column, add one before February fest—otherwise qualitative "silent" reports never join BUILD_RECEIPT row review.
Engine-specific export paths (working dev)
| Engine | Typical bank location in export | LFS pitfall |
|---|---|---|
| Unity | Assets/StreamingAssets/FMOD/ or Addressables audio group |
Addressables cache hides stub until player build |
| Unreal | Content/FMOD/Desktop/ staged banks |
Cook step copies pointer from synced tree |
| Godot | addons/FMOD/banks/ or custom res:// pack |
Export filter excludes .bank from PCK |
| Custom C++ | Content/Audio/Desktop/*.bank beside exe |
CI archives repo without LFS |
Rule: Audit the same folder your Steam depot packages—not the FMOD Studio source tree on the audio lead's laptop.
D2 — pointer vs byte audit (LF1–LF2)
Inventory expected banks from FMOD project export manifest:
{
"schema": "lfs_bank_inventory_v1",
"build_label": "fest-demo-2027-02-rc1",
"banks": [
{ "path": "Content/Audio/Desktop/Master.bank", "min_bytes": 1048576, "sha256": "..." },
{ "path": "Content/Audio/Desktop/Master.strings.bank", "min_bytes": 4096, "sha256": "..." }
]
}
On build machine:
find Content/Audio -name '*.bank' -exec wc -c {} \;
git lfs ls-files -s | rg '\.bank'
LF1 pass: No .bank file under 512 bytes unless documented stub exception.
LF2 pass: git lfs ls-files OID matches git lfs fsck clean.
PowerShell size spot:
Get-ChildItem -Recurse -Filter *.bank Content\Audio |
Where-Object { $_.Length -lt 512 } |
Select-Object FullName, Length
D3 — restore bytes and rebuild (LF3–LF4)
| Step | Action | Pass |
|---|---|---|
| 1 | git lfs pull on clean clone matching tag |
LF3 |
| 2 | Re-export FMOD banks to pinned paths | LF3 |
| 3 | sha256sum banks vs inventory |
LF4 |
| 4 | Bump build_label to fest-demo-2027-02-rc2 |
label receipt |
| 5 | CI job: fail if any .bank < min_bytes |
LF4 |
Add CI guard (cousin to January jq gates):
jq -e '.banks[] | select(.actual_bytes < .min_bytes) | length == 0' lfs_bank_audit.json
Pair February RC label evening when bumping to rc2.
CI guard sketch (GitHub Actions)
lfs-bank-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: true
- run: git lfs pull
- run: |
find Content/Audio -name '*.bank' -size -512c -print | tee stub_banks.txt
test ! -s stub_banks.txt
Fail the job when stub_banks.txt is non-empty—cousin culture to 3-day false-green CI and 12 concurrency patterns.
.gitattributes merge review (producer)
When defer PR touches .gitattributes, require audio lead sign-off:
| Extension | Must be LFS? | Review question |
|---|---|---|
*.bank |
Yes | Did export job pull LFS? |
*.wav source |
Often yes | Still in repo or LFS only? |
*.fsb legacy |
Team policy | Migrated to .bank? |
Document decision in PR body—link to git_lfs_pointer_drift_receipt_v1.json when recovery happens.
D4 — extended Wednesday smoke S-AUDIO (LF5)
Extend Wednesday smoke golden path:
| Smoke row | Check | Pass when |
|---|---|---|
| S-AUDIO | Menu loop audible within 5 s of title | No FMOD ERR_FILE_NOTFOUND in log |
| S-AUDIO-2 | One combat or explore cue if in demo scope | Bus levels non-zero in FMOD spot cousin row |
LF5 pass: S-AUDIO GREEN on installed build; attach audio_smoke.log excerpt.
Beginner mistake: Testing audio in editor while banks live outside export folder—always smoke Steam install.
git_lfs_pointer_drift_receipt_v1.json (D5 schema)
{
"schema": "git_lfs_pointer_drift_receipt_v1",
"iso_week": "2027-W05",
"build_label_before": "fest-demo-2027-02-rc1",
"build_label_after": "fest-demo-2027-02-rc2",
"gates": {
"LF1": "GREEN",
"LF2": "GREEN",
"LF3": "GREEN",
"LF4": "GREEN",
"LF5": "GREEN",
"LF6": "GREEN"
},
"evidence": {
"lfs_bank_inventory": "release-evidence/audio/lfs-drift/lfs_bank_inventory_v1.json",
"pointer_audit_log": "release-evidence/audio/lfs-drift/git-lfs-ls-files.log",
"fsck_log": "release-evidence/audio/lfs-drift/git-lfs-fsck.log",
"sha256_manifest": "release-evidence/audio/lfs-drift/bank_sha256_manifest.txt",
"audio_smoke_log": "release-evidence/audio/lfs-drift/audio_smoke.log",
"demo_smoke_receipt": "release-evidence/february-rc/challenge-2027-W05/day6-demo_smoke_receipt_v1.json"
},
"git_lfs_pointer_drift_ok": true,
"root_cause": "gitattributes_merge_without_lfs_pull_on_build_agent",
"notes": "rc1 silent; rc2 restored Master.bank bytes"
}
BUILD_RECEIPT root rows
{
"build_label": "fest-demo-2027-02-rc2",
"demo_smoke_ok": true,
"git_lfs_pointer_drift_ok": true,
"git_lfs_pointer_drift_receipt": "release-evidence/audio/lfs-drift/git_lfs_pointer_drift_receipt_v1.json",
"menu_snapshot_spot_ok": true,
"february_rc_challenge_ok": true
}
Gates LF1–LF6 summary
| Gate | Name | Pass criteria |
|---|---|---|
| LF1 | Stub scan | No .bank under min_bytes in export tree |
| LF2 | LFS integrity | git lfs fsck clean on release tag |
| LF3 | Bytes restored | git lfs pull + re-export complete |
| LF4 | Hash manifest | sha256 matches inventory |
| LF5 | S-AUDIO smoke | Menu audio on installed build |
| LF6 | Receipt filed | git_lfs_pointer_drift_ok: true on BUILD_RECEIPT |
LF1–LF5 block promotion when RED.
Partner and player communication (D5)
After rc2 promote, post template:
Audio fix shipped on fest-demo-2027-02-rc2
Root cause: Git LFS pointer stubs in rc1 export (not mix regression)
Action: clean install or verify build_label in credits shows rc2
Evidence: git_lfs_pointer_drift_receipt_v1.json on file
Avoid blaming players for "wrong settings" when banks were missing—visible build label lets them prove which binary they run.
Comparison — silent demo failure classes
| Failure class | Boot? | Movement? | Audio? | Owner doc |
|---|---|---|---|---|
| LFS pointer drift | Yes | Yes | No | This case study |
| FMOD RTPC spot drift | Yes | Yes | Wrong buses | 5-night FMOD challenge |
| WebGL integration order | Varies | Varies | No on itch | WebGL snapshot playbook |
| Addressables false green | Yes | Crash on load | N/A | 3-day CI challenge |
| Missing codec / DLL | Often no | No | No | Platform redist checklist |
Route support threads using this table before opening a week-long "audio rewrite."
Proof table
| Evidence | Proves | Fail signal |
|---|---|---|
| wc -c / size audit | LF1 stub detection | 130-byte “banks” |
| git lfs fsck | LF2 OID integrity | Missing LFS objects |
| sha256 manifest | LF4 byte truth | Hash mismatch vs inventory |
| audio_smoke.log | LF5 player experience | Silent title |
| Pointer receipt | LF6 team latch | Verbal “banks fine” |
| Player.log FMOD lines | Root cause class | FILE_NOTFOUND vs RTPC |
Scenarios A–G
| ID | Situation | Move |
|---|---|---|
| A | Standard January hotfix merge | Full D1–D5 timeline |
| B | CI never had LFS | Add git lfs pull step; LF3 |
| C | Only WebGL bank missing | Separate inventory row per platform |
| D | Submodule audio pack | LF2 on submodule pointer |
| E | Smoke passed without audio | Add S-AUDIO permanently |
| F | rc2 during 7-day RC challenge Day 5 | Re-run Day 6 smoke |
| G | RTPC loud but banks present | Route to FMOD menu spot—not LFS |
Prevention checklist (post-recovery)
[ ] CI: git lfs pull before export
[ ] CI: fail build if *.bank < min_bytes
[ ] Wednesday smoke: S-AUDIO in golden path
[ ] January unfreeze: rg scan for pointer paths in export log
[ ] .gitattributes changes require audio lead sign-off
[ ] BUILD_RECEIPT column git_lfs_pointer_drift_ok on RC bumps
Wire into 7-day RC challenge Day 5 hotfix checklist.
Add to January unfreeze audit optional Tool 15 row: find … -size -512c on *.bank before defer merges resume.
Micro-studio time budget (recovery)
| Phase | Solo dev | Audio + engineer |
|---|---|---|
| D1 repro | 45 min | 20 min |
| D2 audit | 60 min | 30 min |
| D3 rebuild | 2–4 h | 1 h |
| D4 smoke | 20 min | 10 min |
| D5 receipt | 30 min | 15 min |
Cheaper than shipping silent rc1 through a February fest weekend—especially when refund correlation tags spike on gameplay without root-cause receipts.
Counterarguments (honest limits)
"Git LFS is dev infrastructure—not fest ops."
Fest demos ship bytes built from LFS-tracked trees; pointer drift is player-facing.
"FMOD project unchanged so audio unchanged."
Export path can hold stubs while Studio project is fine—on-disk export is truth.
"Same as FMOD WebGL silent boot."
WebGL snapshot playbook owns integration order; this case study owns missing bank files on desktop.
Outbound references
- Git LFS documentation — pointer files and
git lfs pull - FMOD Studio banks — expected bank packaging
Related GamineAI reads
- 7-day February RC smoke challenge
- 5-night FMOD menu snapshot spot
- January unfreeze audit tools
- February RC label receipt
- Wednesday demo smoke
- December defer playbook
- Mismatched save slots case study
- Visible build label opinion
- BUILD_RECEIPT beginner pipeline
- Guide #33 forward — Blender mirror hash cousin discipline
Key takeaways
- Silent fest demo can be LFS pointer stubs—not FMOD project corruption.
- Boot + movement smoke does not prove audio banks shipped.
- Gates LF1–LF6 sequence stub scan → fsck → restore → hash → S-AUDIO → receipt.
git_lfs_pointer_drift_receipt_v1.jsondocuments root cause class for partners.git_lfs_pointer_drift_okon BUILD_RECEIPT blocks repeat silent promote.- Pair FMOD menu spot when banks exist but buses wrong.
- 7-day RC challenge Day 5 hotfix should trigger LFS audit.
- CI must
git lfs pullbefore export—compile GREEN is insufficient. - Synthesized pattern—no invented studio metrics.
- Help forward #37 owns fix lane; this case study owns recovery narrative.
- Guide #33 mirror hash cousin for non-audio LFS assets.
- Forward #6 February signup trend playbook after audio truth restored—G3 defer crosswalk before Participate.
FAQ
Is this the same as FMOD menu snapshot spot?
No. Menu spot checks RTPC levels when banks load. This case study checks bank files exist as bytes.
Can pointers fail without Git LFS?
Yes if large binaries were committed as stubs manually—audit uses file size, not only git lfs ls-files.
Should S-AUDIO join standard Wednesday smoke?
Yes for any demo with music or VO in scope—add permanently after recovery.
How does this relate to January unfreeze audit?
Add bank stub scan to U1 tool pass—find + size threshold alongside jq.
Does recovery require rc2 label bump?
Recommended—players need distinguishable build_label from silent rc1.
Can Addressables hide this failure?
Yes—Unity teams may see banks in Editor Addressables preview while player build packages stubs. Always audit the depot folder CI uploads, not the Unity Project view alone.
Should we drop LFS entirely?
Rarely the right January fix—discipline (pull, size audit, S-AUDIO) beats re-committing multi-gig banks to plain Git and blowing clone times before February fest.
Closing
January hotfix week trades silent demos for speed when LFS discipline slips. The game boots, smoke passes, and Discord says “no audio” until someone opens a .bank file and finds a hundred bytes instead of a hundred megabytes.
Audit pointers before promote. Extend smoke with S-AUDIO. File the receipt so rc2 means bytes, not hope.
Next: February signup trend playbook — G1–G6 before Participate; backlog #7 capsule safe-zone pass forward.