Multi-instancing migration (Step 3): convert the dominant per-battle singleton seam — the static `main` backing field and the `GetIns()` accessor — to read through BattleAmbient.Current first, falling back to a renamed `_mainFallback` static when no scope is active. The legacy field is kept (renamed) so unwrapped callers (SingleBattleMgr today, in-process tests that don't yet wrap in BattleAmbient.Enter) keep working with zero behavioral change; scoped callers get per-AsyncLocal isolation so sibling battles in the same process don't clobber each other's "current manager" (design 2026-06-07-engine-multi-instancing, Task 3). GetIns() is the canonical accessor used by ~hundreds of engine call sites; routing it through ambient is what makes the rest of the migration value-adding. Direct cross-file reads of `BattleManagerBase.main` were already absent (the field was private; only an in-comment reference in Shim/BattleAmbientContext.cs exists), so no external callers needed updating. In-file references (4 total) handled as follows: - line 413 declaration → renamed to `_mainFallback` - line 725 GetIns body → ambient-first via Current?.Mgr ?? _mainFallback - line 730 ctor `main = this` → `_mainFallback = this` - line 1491 dispose `main=null` → `_mainFallback = null` --- Engine/BattleManagerBase.cs (~line 413) - private static BattleManagerBase main; + private static BattleManagerBase _mainFallback; --- Engine/BattleManagerBase.cs (~line 725) public static BattleManagerBase GetIns() { - return main; + return SVSim.BattleEngine.Ambient.BattleAmbient.Current?.Mgr ?? _mainFallback; } --- Engine/BattleManagerBase.cs (~line 730) protected BattleManagerBase(IBattleMgrContentsCreator contentsCreator) { - main = this; + _mainFallback = this; --- Engine/BattleManagerBase.cs (~line 1491) - main = null; + _mainFallback = null; }