Port layer only (zero src/ edits), per docs/dev/RUMBLE-PLAN.md:
- port/src/input.c: inputRumbleSupported/inputRumble -> SDL_GameControllerRumble;
detection via SDL_GameControllerHasRumble (SDL >= 2.0.18) else
SDL_JoystickIsHaptic + known-type Windows fallback; zeroed on pad close.
Single global gRumbleScale (dflt 0.5) registered as Input.RumbleScale.
- port/src/libultra.c: the two M-87 blockers resolved - g_contStatus[i].status
now sets CONT_CARD_ON for connected rumble-capable pads (so
joyRumblePakInit arms) and osPfsInit returns PFS_ERR_DEVICE for them (so
osMotorInit is attempted); osMotorInit/Start/Stop drive the haptics API.
- port/src/optionsoverlay.c: one global 'Rumble strength' ROW_SLIDER
(Input.RumbleScale, 0.05 detents, %.2f) in the INPUT section +
kResetDefaults entry. The four per-player Input.PlayerN.RumbleScale keys
were dropped (user decision 2026-09-28); stale keys in an existing ini
log four 'unknown key' LOG_NOTE lines and self-clean on next configSave.
- Real-pad haptics confirmed working by the user (2026-09-28).
Build env: build-pc.sh self-heal guard revision - re-exec now writes a
self-contained .ps1 (msys->native argv conversion mangles $-bearing
-Command strings; file write is conversion-free), builds PATH explicitly,
picks TMP from writable candidates (GetTempPath honours the broken
inherited TMP), self-logs to build-pc/ge007-native-reexec-*.log, and
treats a null LASTEXITCODE as 'did not execute' (PS 5.1 piped native
commands error non-terminating). OPEN: the guard still fails inside
build-pc.sh while the identical standalone .ps1 invocation works - AGENTS.md
documents the workaround. docs: RUMBLE-PLAN.md (new, tracked), findings.md
D401 entry + index rows, QOL-INVENTORY D224 -> DONE (D401),
findings-index.csv regenerated.