The two parallel maps (`cachedLoudnessGainByTrackId`,
`stableLoudnessGainByTrackId`) plus their helpers
(`isReplayGainActive`, `loudnessCacheStateKeysForTrackId`,
`clearLoudnessCacheStateForTrackId`, `loudnessGainDbForEngineBind`)
move into `src/store/loudnessGainCache.ts`. The new module exposes a
thin API:
- `getCachedLoudnessGain` / `setCachedLoudnessGain`
- `hasStableLoudness` / `markLoudnessStable` (atomic set + stable)
- `forgetLoudnessGain` (single-key delete) vs
`clearLoudnessCacheStateForTrackId` (two-form delete)
- existing names kept for `isReplayGainActive`,
`loudnessGainDbForEngineBind`, `loudnessCacheStateKeysForTrackId`
playerStore's seven direct-access sites (delete pairs, set-pair, stable
flag check, cached read, neighbour-cache write) become API calls — the
mutables are no longer reachable from outside the module.
All helpers were file-private; no caller-side changes outside
playerStore's own imports. 22 focused tests pin the API surface including
the partial-vs-stable visibility split and the two delete-shape variants.
playerStore 3415 → 3389 LOC.