The engine's receive CONDUCTOR fuses each authoritative mutation behind a view
call: the play mutation is an InstantVfx registered to VfxMgr, and the deal hand
is seated by MulliganPhaseBase.StartDeal wired to OperateReceive.OnReceiveDeal.
Headless, the shared VfxMgr no-op'd registration (correct for the direct
ActionProcessor path the M2-M12 oracles use) and OnReceiveDeal was never wired,
so the receive path resolved nothing.
Untangle (Candidate B, zero Engine logic edits):
- InstantVfx.Run() opt-in executor (authored shim).
- HeadlessConductorVfxMgr : VfxMgr runs registered InstantVfx; wired only via the
node's SessionContentsCreator.CreateVfxMgr (verified the receive mgr's VfxMgr
comes from there — BattleManagerBase.cs:768). M2-M12 use HeadlessContentsCreator,
so they're isolated by construction.
- WireMulliganPhase: construct NetworkMulliganPhase + MulliganEventSetting() to
install OnReceiveDeal -> StartDeal (the node never pumps the phase machine).
View no-op surface (the 7 from the probe, minus 1 not hit; +1 emergent):
- Deal wiring (NetworkMulliganPhase) [node seed]
- MulliganInfoControl._partsPlayer/_partsOpponent._exchangeMark/_keepZone/_abandonZone [node seed: prefab + SeedMulliganInfoControl]
- Data.BattleRecoveryInfo (IsMulliganEnd=false) [EngineGlobalInit seed]
- IBattlePlayerView.PlayQueueView -> HeadlessPlayQueueViewStub [_IfaceImpl.g.cs, both getters]
- DetailMgr.DetailPanelControl/SubDetailPanelControl [node seed]
- BattleCardIconAnimations.collection (emergent: UpdateInPlayBattleCardIconLabel) -> HeadlessIconAnimations empty SkillCollectionBase [_IfaceImpl.g.cs]
- BattleMenuBtn (probe item 7): NOT hit on the vanilla path; not seeded.
Oracle (HeadlessConductorTests): node Deal seats 3-card hand; a vanilla
hand-card Play leaves hand (-1), adds board (+1), drops PP by cost.
Regression: 24/24 BattleEngine.Tests oracles (M2-M12) green; 241/241
SVSim.UnitTests BattleNode green. The 2 SessionEngine capture-replay shadow
tests are marked Ignore (superseded): they passed VACUOUSLY when the receive
path resolved nothing; with resolution live they hit the documented
capture-replay draw-misalignment artifact. Node-native battles are the oracle.
Drift: no drift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- VFX: SequentialVfxPlayer.GetAllVfxAsList, ParallelVfxPlayer.GetVfxList,
VfxMgr.CheckAndAddEffectVfxList; point our own ShowBattleUIImmediatelyVfx stub at
NullVfx.GetInstance() (it called a non-existent NullVfx.Create).
- Static factories: SkillTargetSelectTouchProcessor.Create (10-arg),
DialogReportToManagement.Create(long).
- Re-add StartSkillSelectVfx.OnStart event (m1_stub_gen drops `event` decls — the
recurring session-6 gap; generator event-capture fix still pending).
- Stop the BattleCardView/GameObjMgr ctor cascade: parameterless ctors on the no-op
BattleCardView and GameObjMgr hand shims so non-chaining subclass/field stubs satisfy
their implicit base() call.
- Copy Cute/ListExtensions.cs (FisherYatesShuffle extension) verbatim into Engine.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- VfxWith<T> ctor params were swapped ((T,VfxBase) vs decomp (VfxBase,T)) -> ~38
CS1503 across SkillCollectionBase/BattleCardBase skill-processing (ProcessInfo
<-> VfxBase). These are on the resolution path. Fixed to match decomp.
- UnityEngine primitives: implicit Vector3/Vector2<->Vector4 + Color->Color32
conversions; Transform.Translate/Rotate(Vector3,Space) overloads (iTween).
- ITouchProcessor was dropped from touch-processor stubs by base-clause recovery;
re-attach via Shim/View/TouchProcessorIfaces.cs (interface-only for generated
full-surface stubs, interface+no-op members for the empty hand stubs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hand-shim VFX containers only had no-arg Create(); the engine calls them with
collection/params/loading-main args (510 CS1501). Add the real decomp Create overloads
to SequentialVfxPlayer/ParallelVfxPlayer/VfxWithLoading/VfxWithLoadingSequential.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>