diff --git a/services/wolf.sh b/services/wolf.sh
index 7e77269..49cbb8e 100644
--- a/services/wolf.sh
+++ b/services/wolf.sh
@@ -1604,13 +1604,28 @@ GOW_ESDE_SETTINGS_TEMPLATE = """
"""
-if 'ROMDirectory' not in content:
+if not content.strip():
content = GOW_ESDE_SETTINGS_TEMPLATE
else:
content = re.sub(r'[ \t]*[ \t]*\n?', '', content)
line = '\n'
content = content.rstrip('\n') + '\n' + line
+ # CONFIRMED LIVE: a file can already contain a ROMDirectory *key* while
+ # its value is blank (e.g. ES-DE's own first-run "select ROM directory"
+ # step got skipped/cancelled in a headless Moonlight session and ES-DE
+ # saved that empty value back over GOW's own template) — checking only
+ # whether the key exists, as an earlier version of this fix did, treated
+ # that as "already populated" and left the blank path in place, so ES-DE
+ # kept finding zero games even though the fix had technically "run".
+ # Force it to /ROMs (the one true value in this container — see the
+ # 'roms:/ROMs' mount on every app that reads ROMs) whenever it's missing
+ # or empty, independent of whether RunInBackground needed touching.
+ m = re.search(r'[ \t]*\n?', '', content)
+ content = content.rstrip('\n') + '\n' + '\n'
+
with open(path, 'w') as f:
f.write(content)
ESDESETTINGSPY
@@ -4790,21 +4805,26 @@ default behavior here.
It writes \`esde-settings/es_settings.xml\` directly from GOW's own real
template (100+ settings, fetched from GOW's own repo, byte-for-byte
identical except \`RunInBackground\` flipped to off) whenever that file is
-either missing or still the old broken placeholder — detected by checking
-for \`ROMDirectory\`, a key only GOW's own bootstrap or ES-DE itself ever
-writes. If the file already has a real, fully-populated value (because
-EmulationStation has already launched at least once and GOW wrote its own
-copy), only the one \`RunInBackground\` line is patched, leaving every
-other setting (theme, scraper prefs, etc.) untouched. Either way, one
+missing or empty. If the file already has real content, only the one
+\`RunInBackground\` line is patched, leaving every other setting (theme,
+scraper prefs, etc.) untouched — **except \`ROMDirectory\`, which is always
+independently forced to \`/ROMs\` whenever its value is blank**, regardless
+of whether the rest of the file looks populated. Either way, one
\`sudo ./setup.sh wolf\` run is enough — no need to connect via Moonlight
-first. **Confirmed live, the hard way, twice:** earlier versions of this
-fix either pre-created a minimal stub that made GOW skip writing its own
-template (breaking ROM discovery on every system, since the ROM path fell
-back to something other than \`/ROMs\`), or only patched an already-existing
-file and left a genuinely missing/broken one alone, requiring exactly the
-manual Moonlight-connect step this version removes. Setting it by hand
-still works too, any time: **Main Menu → Other Settings → Run in
-background (while game is launched) → off**.
+first. **Confirmed live, the hard way, three times:** earlier versions of
+this fix (1) pre-created a minimal stub that made GOW skip writing its own
+template, breaking ROM discovery on every system since the ROM path fell
+back to something other than \`/ROMs\`; (2) only patched an already-existing
+file and left a genuinely missing/broken one alone, requiring a manual
+Moonlight-connect step; and (3) treated the mere *presence* of the
+\`ROMDirectory\` key as proof the file was already correctly populated —
+but ES-DE can write that key with a **blank value** (its own first-run
+"select ROM directory" step going unanswered in a headless Moonlight
+session saves an empty path back over GOW's template), which the presence
+check alone couldn't tell apart from a real one. Setting it by hand still
+works too, any time: **Main Menu → Other Settings → Run in background
+(while game is launched) → off**, and the ROM directory under **Main Menu
+→ Other Settings → ROM directory → \`/ROMs\`** if it's ever blank again.
**Why this needed its own mount, not just a one-time write:** \`~/ES-DE\`
(settings, gamelists, scraped artwork, logs) had no bind mount onto the