762 Commits

Author SHA1 Message Date
gamer147
e982300c6d feat(battlenode): inject SessionBattleEngine into BattleSession in pure shadow (Phase 2 N1 exit)
The engine is constructed per session, seated once from the master seed + both
shuffled decks (F-N-5), and fed each frame via ShadowIngest — all inside a
try/catch in ComputeFrames so a shadow failure can never break live dispatch
(ND1/ND6). Routes still come from the existing handlers: wire output is
byte-for-byte unchanged. FrameDispatchContext gains the Engine ref for N2+.

csproj: PrivateAssets=compile on the engine ref so its global-namespace type
surface (MessagePackSerializer, UserConfig, UserCard, ChallengeConfig, ...) does
not leak transitively into SVSim.EmulatedEntrypoint (which references BattleNode)
and collide with that project's own types; the runtime DLL still flows.

All 238 BattleNode unit tests pass; EmulatedEntrypoint builds clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:35:35 -04:00
gamer147
fa86739ac2 test(battlenode): N1 shadow replay tracks captured battle state (Phase 2 N1)
Full single-client capture replay (cl1 send=player seat, receive=opponent seat,
ts-ordered) ingests end-to-end: 33 frames, 0 rejects, 0 invariant violations at
turn boundaries (leader life/PP/board/hand).

Headless gaps filled per playbook (no Engine/ drift):
- IsRecovery=true after construction: the engine's own headless replay mode gates
  the live view/UI layer off (BattleUIContainer, turn-control UI, VFX waits) while
  keeping the live NetworkBattleReceiver (ND4) and authoritative state.
- Seed ToolboxGame.RealTimeNetworkAgent, BattleUIContainer, _backGround, and
  per-player NullPlayerEmotion no-ops the receive/turn cycle dereferences.
- _IfaceImpl.g.cs (shim, not Engine/): BattleCardView.BattleCardIconAnimations
  returns a lazy non-null no-op so the opponent card-reveal icon-init (deferred
  VFX) doesn't NRE.
- HeadlessCardMaster.Load made cumulative: it replaced the global CardMaster each
  call, so a Load(deck) evicted the oracle card set and broke tests run after.

Adds board-state accessors (LeaderLife/Pp/HandCount/BoardCount) and CaptureReplay
ts ordering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:28:08 -04:00
gamer147
6740313446 feat(battlenode): Receive ingests a captured PlayActions headless (Phase 2 N0)
Receive feeds the decoded frame into the mgr's own NetworkBattleReceiver
(isHaveSequence:true, checkBreakData:false — mirroring the engine's
RecoveryDataHandler frame replay), reboxing object?->object for nested data.
No engine gaps surfaced; the only fix was a test-harness one (load all deck ids
in a single HeadlessCardMaster.Load — per-id calls each replace the master).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:05:36 -04:00
gamer147
eaa7b4d85c test(battlenode): capture-replay helper + battle_test fixtures (Phase 2 N1)
CaptureReplay normalizes the capture's send/receive envelope asymmetry (send
frames carry uri at top level + bare payload body; receive frames carry a full
envelope body) and extracts selfDeck + master seed from Matched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 14:59:48 -04:00
gamer147
c9841c012b feat(battlenode): Setup builds two-seat network battle headless (Phase 2 N0)
Mirrors HeadlessFixture.NewNetworkEmitBattle wiring (opponent seating, leader
life, card templates, deck seeding) minus the emit-only RealTimeNetworkAgent
scaffolding (shadow only receives). Probe passed first run — M13 already filled
the network-mgr construction gaps. No Engine/ edits; drift clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 14:51:51 -04:00
gamer147
f6cbde723b feat(battlenode): SessionBattleEngine skeleton + types (Phase 2 N0)
SessionContentsCreator mirrors the test HeadlessContentsCreator fully (all
IBattleMgrContentsCreator members) so it compiles; Setup/Receive throw pending
the Task 3/4 probes. New files use the 'engine' extern alias.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 14:49:18 -04:00
gamer147
83f82efe1b feat(battlenode): reference SVSim.BattleEngine (Phase 2 N0 wire-up)
Aliased (extern alias 'engine') to confine the decompiled engine's large
global-namespace type surface, which would otherwise collide with node types
(BattlePlayer, MessagePackSerializer). Also expose internals to
SVSim.BattleEngine.Tests for the upcoming N0/N1 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 14:46:37 -04:00
gamer147
e6a561b30f test(battle-engine M13): shared NetworkEmitFixtureBase teardown — close IsForecast/agent global leak
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 13:03:07 -04:00
gamer147
bfd99c4829 docs(battle-engine M13): note _notEmit precondition on TryReadStockedEmitData (review polish)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:42:45 -04:00
gamer147
feb47f6437 test(battle-engine M13): best-effort emit-payload presence (Inconclusive => deferred to structural validation)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:37:24 -04:00
gamer147
73286ba78b chore(battle-engine M13): align OnEmit line-cite + HEADLESS marker spelling (review polish)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:34:53 -04:00
gamer147
ac0886389a feat(battle-engine M13): M3 spell emits PlayActions headless via OperateMgr -> NetworkBattleSender (O1 read = GO)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:23:51 -04:00
gamer147
25e9ae9573 test(battle-engine M13): NewNetworkEmitBattle harness + OnEmit capture seam
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:00:04 -04:00
gamer147
6b2c825eb8 chore(battle-engine M13): drop unused using + complete shim comment (review polish)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 11:56:23 -04:00
gamer147
2f6bc5b6c0 test(battle-engine M13): HeadlessNetworkBattleMgr constructs headless (construction probe)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 11:48:52 -04:00
gamer147
0fe45517da test(rng-seam): reset IsRandomDraw in RandomDrawOracleTests teardown (avoid cross-fixture leak) 2026-06-06 10:57:39 -04:00
gamer147
ffc0fcaa43 test(rng-seam): M12 oracle — scripted RNG draws a known deck card (genuine multi-outcome roll) 2026-06-06 10:46:35 -04:00
gamer147
2fd0aac5b6 test(rng-seam): M12 constants + NewAuthoritativeBattle harness factory 2026-06-06 10:40:59 -04:00
gamer147
f6e3b67be1 docs(rng-seam): note stableRandomCount divergence in HeadlessBattleMgr 2026-06-06 10:38:58 -04:00
gamer147
c47f8d9fa7 feat(rng-seam): HeadlessBattleMgr override + decoupling/parity tests (F2 resolved)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:33:59 -04:00
gamer147
201158db5d patch(rng-seam): make StableRandomDouble/StableRandomOnlySelf virtual (DP5, zero logic change)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:25:35 -04:00
gamer147
1a108fa393 feat(rng-seam): ScriptedRandomSource (throw-on-overrun deterministic source) 2026-06-06 10:21:44 -04:00
gamer147
2fd42c10cf feat(rng-seam): SeededRandomSource mirrors the engine's two System.Random streams 2026-06-06 10:18:19 -04:00
gamer147
c77d789558 feat(rng-seam): IRandomSource interface + RandomSourceBridge arithmetic
Adds the RNG seam skeleton (Task 1 of M12): IRandomSource (NextUnit/NextSelf)
and RandomSourceBridge.Range mirroring BattleManagerBase.StableRandom exactly
(`(int)Math.Floor(val * unit)`). RngSeamTests pins the floor arithmetic (1 test, passing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 10:14:50 -04:00
gamer147
7370a35e9c test(battle-engine-port): M11 — gated conditional resolves headless (the GATE is the oracle)
Card 103111050 (ELF cost-1 self-buff follower) carries skill_condition
`character=me&target=self&play_count>2`. New GatedConditionalOracleTests asserts
BOTH branches of the SAME card in one fixture, varying only the seeded per-turn
play count via the public AddCurrentTrunPlayCount seam (M4/M10):

  * gate TRUE  (seed 5 > 2)  -> when_play powerup fires -> 1/1 -> 2/2
  * gate FALSE (seed 0 <= 2) -> powerup is a NO-OP (stays 1/1), BUT the card
    still pays its cost and still moves hand -> board.

This proves the engine SUPPRESSES an effect when a skill_condition is false (the
dual of "effect fires" — no prior milestone proved this), and that the gate
suppresses the EFFECT, not the PLAY. Jointly satisfiable only by a correctly-
gating engine: an always-buffs engine fails FALSE, a never-buffs engine fails
TRUE. Reuses the M4-proven buff dimension so the only new thing under test is the
conditional itself.

11/11 green; engine 0 errors; check_drift clean; ZERO new Engine copies / ZERO
shim / ZERO manifest changes — a clean milestone like M4/M6/M8/M10 (condition
evaluation is pure logic on copied engine code).

Load-bearing proof (M4/M6/M8/M10 discipline; the test passed on its first run,
which proves nothing alone): swapped the two seeds -> exactly the 4 stat
assertions failed for the right reason (formerly-TRUE branch seeded 0 took no
buff [1/1, expected 2/2]; formerly-FALSE branch seeded 5 buffed [2/2, expected
1/1]), while the cost-paid + hand->board assertions stayed green in both branches
— confirming the gate drives ONLY the effect and the card resolves regardless.
Reverted -> 11/11.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:10:45 -04:00
gamer147
c3590e9c9b test(battle-engine-port): M10 — first dynamic {}-value card resolves headless
DynamicValueSpellOracleTests proves the engine COMPUTES an effect magnitude
from live game state (the value the wire can't carry). Card 112134010's
`when_play damage={me.play_count}-1` resolves via the proven IsForecast/
IsRecovery + ActionProcessor.PlayCard (DP4) path; the oracle asserts the
damage equals the engine's own live GetCurrentTurnPlayCount() - 1, not a
literal. Seeds play_count via M4's AddCurrentTrunPlayCount seam; lone
surviving enemy 13/13 gives a clean life-delta; selectedCards: null
(auto-target AoE). 10/10 green; zero Engine/shim/manifest changes; drift
clean. First-unknown resolved by the first RED: the per-play +1 lives in
OnBeforePlayCard (wired only via OperateMgr/Prediction), so the direct-
ActionProcessor harness reads exactly the seeded count (damage == seeded-1);
load-bearing proven by varying the seed 4->7 and watching damage track 3->6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:02:59 -04:00
gamer147
eee8450144 feat(battle-engine-port): M9 COMPLETE — when_play draw resolves headless (hand/deck-delta oracle)
Proves the deck->hand transfer dimension (design §5 draw oracle) — the last
deterministic, non-RNG card-effect class no prior milestone touched (M3/M4/M6/M8
moved stats, M2/M5/M7 the board, M3 the leader).

Card 800114010 (clan-1 ELF cost-1 when_play draw 1 from own deck, ungated, no
evo/preprocess). The resume-guide's skill_target=none/no-RNG shape does not exist
in cards.json — EVERY draw selects from the deck via a random_count filter
(skill_option is always literally 'none'). RNG neutralized structurally: seed the
deck with EXACTLY ONE known card so random_count=1 is deterministic regardless of
seed. New primitive HeadlessEngineEnv.SeedDeck (create via the null-view seam +
engine AddToDeck). Oracle DrawSpellOracleTests asserts: seeded card moves deck->hand
(by id + by reference), deck -1, drawn card IsInHand, spell pays cost + leaves hand
+ resolves to cemetery, board/opponent untouched. Load-bearing confirmed the M7 way
(seed a different id -> the by-id assertion fails).

Shim gap fixed (the predicted M9 cost): Skill_draw's BattleLog tail
(UpdateFusionedCardSkillDrewCard, unguarded; + the IsBattleLog AddLogSkillDrawCard
calls) dereferences BattleLogManager.GetInstance(), an M1 'default!' null singleton
-> NRE after the draw already committed. One-line HEADLESS-FIX (M9) in
BattleLogManager.g.cs returns the existing _instance singleton (all its methods are
no-ops), per the M2/M7 Null*-singleton playbook. No Engine/ edit (drift clean).

9/9 green; check_drift.py clean; engine still 0 Error(s).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 08:47:04 -04:00
gamer147
4f76fb21f0 feat(battle-engine-port): M8 COMPLETE — lethal damage proves follower death via combat math
A when_play damage=5 spell (the M6 card 800134020) played at a select_count=1
enemy follower with life <= 5 kills it as a consequence of damage -> life <= 0 ->
the dead-check + the same RemoveInplayCard/cemetery path M7 lit up (the dominant
real-card removal mechanic), reached through combat math rather than `destroy`.

Oracle LethalDamageSpellOracleTests: selected follower (1/2) removed (board -1 +
cemetery +1, the M7 dimension); un-selected control (6/7, life > 5) untouched and
still on board (M6 routing; select_count=1 hits only the selected target). 8/8
green; engine 0 errors; check_drift clean; ZERO new Engine/shim/manifest work —
the death path inherited M7's death-voice fix; the predicted damage-VFX shadow
never materialized.

Load-bearing (M4/M6 discipline): swapping the selection to the 6/7 -> it survives
at 2 and nobody dies, proving removal is gated on the SELECTED follower's life
reaching <= 0, not on selection (M7's destroy) or a blanket wipe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 08:35:02 -04:00
gamer147
9fc97abee7 feat(battle-engine-port): M7 COMPLETE — targeted destroy resolves headless (follower death / board-removal)
First proof that follower DEATH / board-removal commits in the authoritative
part of PlayCard headless (not the cosmetic post-Process tail). Card 800144120
(cost-0 when_play destroy of a select_count=1 enemy follower) resolves via the
M6 selectedCards path: selected enemy follower removed (board -1 + cemetery +1),
un-selected untouched (routing confirmed load-bearing by swapping the selection).

Shim gap fixed (the predicted M7 cost): SkillProcessor.SelectCardToHaveDestroyVoicePlay's
cosmetic death-voice tail NRE'd on three M1 default!/Null* shadows
(IBattleCardView.VoiceInfo, CardVoiceInfoCache.GetCardVoiceInfoForBattle,
ReadOnlyVoiceInfo.GetDestroyVoice — the last unusable as the interface since
m1_stub_gen dropped its : IReadOnlyVoiceInfo base). Fix = one hand shim
HeadlessVoiceInfo : IReadOnlyVoiceInfo returning the engine's own
VoiceAndWaitTime._nullVoice sentinel, wired into the two generated seams with
// HEADLESS-FIX markers. No Engine/ edit (drift clean).

dotnet test SVSim.BattleEngine.Tests -> 7/7 green; check_drift.py clean; engine 0 Error(s).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 08:23:53 -04:00
gamer147
c8314bd3c0 test(battle-engine-port): M6 COMPLETE — targeted when_play damage spell resolves headless (selection-routing oracle)
First card to exercise the selectedCards path of ActionProcessor.PlayCard
(dormant through M2-M5, all of which played selectedCards: null). Spell
800134020 (clan-1 cost-1, when_play damage=5 to a select_count=1 enemy
follower) resolves headless: with two vanilla followers on the enemy board
and one passed as selectedCards, the damage hits ONLY the selected follower
(13->8) and the un-selected one is untouched (7).

New oracle dimension: SELECTION ROUTING via a differential life-delta on two
surviving targets (selected -5, un-selected 0) — reads the authoritative
damage path M3 proved, with no dependence on follower death/board-removal
timing. Load-bearing confirmed (M4 discipline): swapping which follower is
selected makes the damage follow the selection (assertions fail for the right
reason), then reverted to green.

Like M4, a clean milestone: NO new engine/shim work — the selectedCards path
resolved on the existing shim surface. The only authoring was test-side: the
M6 card constants, a shared HeadlessEngineEnv.PutFollowerInPlay primitive
(create via the null-view seam + drive HandCardToField), and the oracle.

Engine still 0 errors; check_drift clean; dotnet test -> 6/6 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 08:08:01 -04:00
gamer147
62a28fe2d4 feat(battle-engine-port): M5 COMPLETE — summon_token spell resolves headless (board-count delta oracle)
Card 800134010 (clan-1 cost-1 ungated spell, summon_token=100011020): a when_play
summon places one new neutral 2/2 follower token on the caster board. New oracle
dimension = board-count + token-identity delta from a SKILL-CREATED card. 5/5 green;
engine 0 errors; check_drift clean; zero new Engine copies.

This is the first headless run of the PUBLIC prefab card-creation path
(CardCreatorBase.CreateCard, createNullView:false) — engine-internal card creation
(summon/draw/token) has no null-view path in solo mode, unlike the M2-M4 hand-card
seam. Built that path headless:
- Self-consistent no-op Unity object graph (UnityShim.cs): Component.gameObject/
  transform, GameObject.transform, Transform.parent/Find now lazily non-null +
  cached; GetComponent routed through the GameObject component model.
- Targeted NGUI material backing-field wiring (UIFont.mMat / UILabel.mMaterial) so
  the copied material getters return non-null via their simple branch (blanket/deep
  wiring would make them delegate down a re-nulling chain).
- getUIBase_CardManager() default! -> field-wired no-op via new ShimView.Create<T>().
- Test-side seeds: SBattleLoad card templates + 3D scene GameObjects (InitCardTemplates).

Load-bearing proof: swapping to the M3 non-summoning spell fails the board-count
(Expected 2, was 1) + token-not-found assertions; reverted to green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 03:19:47 -04:00
gamer147
b13cfa0fad test(battle-engine-port): M4 COMPLETE — when_play self-buff follower resolves headless (4/4 green)
Fold SetupCardEvent into a shared HeadlessEngineEnv.CreateHeadlessHandCard primitive
(consolidating the duplicated M2/M3 helpers), then add the M4 oracle: card 103111050
(ELF cost-1 1/1, when_play powerup add_offense=1&add_life=1 to target=self). New oracle
dimension = the played card's OWN stat delta (1/1 -> 2/2). Gate play_count>2 seeded via
the public AddCurrentTrunPlayCount; proven load-bearing (without the seed the fanfare
gates out and Atk stays 1). No new shim/data gaps were needed — only harness seeding.
Engine still 0 errors; check_drift clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 02:36:02 -04:00
gamer147
c47ae93027 feat(battle-engine-port): M3 COMPLETE — fixed-damage spell resolves headless (leader-life-delta oracle passes)
Card 900124030 (ELF cost-3, when_play damage=3 to enemy leader) resolves to
correct authoritative state headless via the IsForecast/IsRecovery +
ActionProcessor.PlayCard path. New oracle dimension (opponent leader-life delta)
passes; 3/3 tests green; engine still 0 errors; check_drift clean.

Four headless gaps, each mechanical (no logic/Unity wall):
- Data seam: InitLeaderLife (SetupInitialGameState->InitializeClassLife subset);
  leader BaseMaxLife was 0 => game-over => play silently rejected. M2 missed it
  (only asserted leader life unchanged: 0==0).
- Runtime cast: re-attach IClassBattleCardView on the generated
  NullClassBattleCardView stub (members already present; base-clause recovery
  stripped the decl). Compiled fine -> M1 loop never surfaced it.
- M1 mis-cut: copy NullVfxWithLoading verbatim (its GetInstance() lazy singleton
  was stubbed to default!/null). Same pattern as M2 NullCardVfxCreator.
- Card events: CreateHeadlessHandCard now calls SetupCardEvent so a spell's
  OnPlay->RemoveSpellCardFromHand / OnFinishWhenPlaySkill->AddSpellCardToCemetery
  fire (the bare CreateCardWithoutResources seam skips them).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 02:19:54 -04:00
gamer147
171f07ec74 feat(battle-engine-port): M2 COMPLETE — vanilla follower resolves headless (go/no-go = GO)
First green: a zero-skill vanilla follower (100011010, neutral 1/2) resolves to
correct authoritative state HEADLESS via IsForecast/IsRecovery + ActionProcessor.
PlayCard (DP4), no Unity runtime. §5 oracle passes (PP-cost; hand->in-play;
atk/health == CardCSVData base; opponent unchanged; no exception). VERDICT: the
port approach is validated through the resolution path, not just M1's compile path.

VanillaFollowerOracleTests.Vanilla_follower_resolves_to_correct_state — GREEN.
HeadlessCardMaster now loads the follower's real id from cards.json.

Resolution-path shim/engine gaps closed (all mechanical no-op fills or data seams,
never a Unity/logic wall):
- M1 mis-cut copies (DP1/DP3 — pure no-op logic wrongly stubbed to null):
  Engine/Wizard.Battle.View.Vfx/NullCardVfxCreator.cs (its GetInstance() singleton
  was nulled) + its dep NotEmptyNullVfx.cs. Deleted the generated NullCardVfxCreator
  stub + its _IfaceImpl block; both manifested, check_drift clean.
- _IfaceImpl explicit-impl shadow: interface-typed view/mgr calls dispatch to the
  explicit impls (which returned default!), shadowing public stubs. Fixed
  IBattlePlayerView.GetSideLogControl (SkillProcessor side-log tail) to return a
  non-null no-op. KEY M3+ learning: fix _IfaceImpl.g.cs for interface-typed NREs.

(GameMgr/component-model/Resources/IClassBattleCardView shim fills + CardIconControl
copy + the SVSim.BattleEngine.Tests project landed in the prior commit 2b50657.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 01:57:15 -04:00
gamer147
2b506574e7 feat(battle-engine-port): M2 step 1 — SingleBattleMgr constructs headless
First green of the M2 go/no-go probe: `new SingleBattleMgr(StandardBattleMgr-
ContentsCreator)` now builds the two-player pair fully headless against the shim,
no Unity runtime. Verdict: headless construction is feasible; every blocker was a
mechanical no-op shim fill or data seam, not a Unity/logic wall.

Shim fills (authored):
- GameMgr: lazy non-null DataMgr/PrefabMgr/InputMgr/SoundMgr/BattleControl.
- GameObject: lazy cached component model so GetComponent<T>/AddComponent<T> return
  non-null no-op instances for Component-derived T (F1: unguarded view touches).
- Resources.Load(string): cached non-null GameObject so the prefab->Instantiate->
  GetComponent chain (UnityEventAgent) yields a real object.
- ClassBattleCardViewBase: re-attach dropped IClassBattleCardView (no-op members);
  ClassBattleCardBase.Setup casts the created view to it.

Engine copy (DP1/DP3 mis-cut fix):
- CardIconControl.cs copied verbatim (manifested) + generated null-stub deleted.
  SplitAndCompleteIconStr is pure string logic on the resolution path that M1 had
  wrongly stubbed as "View" -> null deref in SkillCreator.CreateBuildInfo.

Test harness (SVSim.BattleEngine.Tests, authored fixture):
- HeadlessContentsCreator/HeadlessPhaseCreator: deterministic replica of the solo
  practice init (StandardBattleMgrContentsCreator + SingleBattlePhaseCreator) with
  no-op recovery/replay managers.
- HeadlessCardMaster: reflects the loader cards.json dump into CardMaster.
- HeadlessMasterData: minimal Data.Master (class-character list, empty collections)
  + Data.Load + player/enemy chara ids.
- ConstructionProbeTests.SingleBattleMgr_constructs_headless — GREEN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 01:36:22 -04:00
gamer147
1078b1ef50 port(m1): wave 7k — M1 COMPLETE: 0 compile errors, headless engine builds (12->0)
Final three clusters:
- RoomParamKey: copy Wizard.RoomMatch/RoomParamKey.cs verbatim (UriNames/WatchUriNames
  static dicts keyed by PlayerController.ROOM_URI + PlayerControllerForWatching.
  SEND_PARAMETER — both now real enums).
- CardChooseTask: copy the TwoPick/CardChooseTask.cs (TaskManager `using`s .Arena.TwoPick,
  not .Competition — copy_loop had only landed the Competition twin).
- SetCardNumLabel CS1739: decompiler param-name artifact — the local fn's 3rd param was
  recovered as `flag` but call sites pass it named `isRed:`. First DP5 tracked patch:
  Engine/UICardList.cs edited (flag->isRed, zero logic change), recorded in
  Patches/ + manifest patched=1 (drift-clean).

M1 exit criteria met: `dotnet build SVSim.BattleEngine` = 0 errors, no Unity ref in csproj,
check_drift clean. Session 7: 198 -> 0 across waves 7a-7k.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 01:03:58 -04:00
gamer147
f63d1cc2e2 port(m1): wave 7j — Material/Plane/Socket overloads + IDictionary extension (24->12)
- Material.SetVector(int nameID, Vector4); Plane(Vector3, float d) ctor; Socket.On
  (SocketIOEventTypes, callback) overload.
- Global GetValueOrDefault(this IDictionary<,>) extension — the BCL form only binds to
  IReadOnlyDictionary, so the IDictionary call mis-resolved to JsonDataExtension.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 01:00:12 -04:00
gamer147
ad58994b8e port(m1): wave 7i — RoomMatch/Story/Effect app members + ROOM_URI enum (40->24)
- PlayerController.ROOM_URI nested enum (verbatim-generated).
- RoomRoot.CreateChangeSceneDialog, StoryRecoveryData.ToJsonData,
  BattlePlayerViewBase.IsSelecting, StorySelectionWorldScene.RedirectSectionId,
  EffectMgr.LoadAndInstantiate2dEffectCoroutine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:57:51 -04:00
gamer147
59cb089c97 port(m1): wave 7h — Unity overloads + SDK return types + RoomRoot:UIBase (56->40)
- Resources.LoadAsync(string) non-generic, LayerMask implicit-from-int, Animation
  string indexer.
- SDK return-type fixes: RedShellSDK.MarkConversion/LogEvent return IEnumerator
  (StartCoroutine arg), Packsize.Test() returns bool (!Test()).
- RoomRoot : UIBase (decomp base) so TopBar/Footer's (RoomRoot) casts succeed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:54:47 -04:00
gamer147
3a88b27752 port(m1): wave 7g — Unity coroutine/overload + app-member tail (88->56)
- MonoBehaviour.StopCoroutine(string) (iTween/NGUI StopCoroutine("name")),
  Object.DestroyImmediate(o, bool), GetComponentInParent<T>(bool includeInactive).
- App members: TitlePanelBase (:MonoBehaviour + IsFinishInit), PlayerController.Target,
  DialogManager.CreateDialogBaseOpenCardDetail, BattleLogWindow.HideCardListPanel,
  DetailPanelTouchProcessor.StopAttackTarget, StoryRecoveryData.ChapterCharaId +
  (SelectedStoryInfo) ctor overload.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:52:18 -04:00
gamer147
5c5a58af3c port(m1): wave 7f — VFX containers / Create factories / dropped event / ctor cascade (112->88)
- 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>
2026-06-06 00:49:07 -04:00
gamer147
981f903504 port(m1): wave 7e — Unity/NGUI/Spine member tail (142->112)
- isActiveAndEnabled onto Behaviour (real Unity location) — clears it on all 5
  MonoBehaviour-derived NGUI types (MyPageCardPanel/WizardUIButton/UITweenAlpha/
  UIScrollView/UICardList) in one edit.
- Touch.tapCount, Rigidbody2D.isKinematic, AnimatorStateInfo.fullPathHash,
  AnimationClip.frameRate.
- Spine: SkeletonData.Skins (List<Skin>) + Skin.Name, for SpineObject's
  Data.Skins.Any(s => s.Name == ...).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:44:04 -04:00
gamer147
7d3d92981e port(m1): wave 7d — LoginBonus/Story data ctors + nested BuildInfo/FileNamePair (158->142)
- Add the (JsonData) ctor to the LoginBonus data hand stubs (Continuous/Normal/
  Special/FreeCardPackBox) and StoryRecoveryData (LitJson.JsonData is copied).
- Full-surface the two nested View types that only the parent's empty stub covered:
  BattleCardView.BuildInfo (14-arg ctor) and DestroyVfx.FileNamePair (ctors +
  ObjectFileName/SeFileName); add BattleCardView(BuildInfo) to the hand shim.
- Regenerate Field/Spell/UnitBattleCardView: stale stubs whose ctors had dropped the
  decomp `: base(buildInfo)` chain, exposed (CS7036) once BattleCardView lost its
  implicit default ctor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:42:03 -04:00
gamer147
57f1f0c25e port(m1): wave 7c — SelectionProcessing Parameter + Touch-processor ctors (174->158)
- Generate both SelectionProcessing Parameter classes namespace-aware (full-surface
  captures the 8-arg Main / 6-arg BattleResult ctors); drop the empty hand stubs.
- Add the missing decomp ctors to the 5 empty Touch-processor hand stubs
  (SetCard/EvolutionSimple/Emotion/ClassBuff/DetailPanel) — compile-only ballast,
  empty bodies.
- Regenerate FusionWaitProcessor.g.cs: it was a stale stub whose ctor had dropped
  its decomp `: base(...)` initializer; harmless while SetCardProcessor had an
  implicit default ctor, exposed (CS7036) once the parameterized ctor landed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:38:58 -04:00
gamer147
38ab33a765 port(m1): wave 7b — Main-namespace dialog dupes + IReplayRecordManager (190->174)
Generate the Main-namespace versions of the four colliding SelectionProcessing
dialog classes (ChapterCharaDecider/DownloadInfoGetter/DeckSelectionDialogDisplay/
DeckSelectionConfirmDialogDisplay) via the new --ns path — AreaSelectUI uses the
Main module and constructs them into an IProcessing[]. baseclauses binds each to
Main.ProcessingBase; iface_reattach (regenerated full) attaches Main.IProcessing.

Also fill IReplayRecordManager with its 3 real members (SetupRecording/
SetupBattleInfoFilter/SetupOperateMgrEvents); both implementors already had them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:34:12 -04:00
gamer147
fc54dac081 port(m1): wave 7a — namespace-aware ProcessingBase collapses Story SelectionProcessing cluster (198->190)
The Story chapter-selection processing subsystem is duplicated across two
namespaces (…SelectionProcessing.Main and .BattleResult), each with its own
ProcessingBase : IProcessing + Parameter. m1_genstub keyed output by bare type
name, so only ONE ProcessingBase.g.cs was emitted (BattleResult), and
m1_baseclauses cross-qualified the Main leaves to BattleResult.ProcessingBase —
making it impossible to give IProcessing its real members (Execute(Main.Parameter)
≠ inherited Execute(BattleResult.Parameter) → CS0535).

Now both ProcessingBase variants are generated via the namespace-aware tooling
(<Type>__<Namespace>.g.cs), baseclauses resolves each leaf to its same-namespace
ProcessingBase, and both IProcessing interfaces carry NextProcessing + Execute.
8 IProcessing CS1061 cleared, no CS0535 introduced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:31:29 -04:00
gamer147
6e9c5c059f port(m1): wave 6i — Networking/Facebook/BestHTTP CS0103 statics (210->198)
- UnityEngine.Networking: UnityWebRequestTexture, DownloadHandlerTexture, DownloadHandlerAssetBundle.
- Facebook.Unity.AccessToken (CurrentAccessToken/TokenString/UserId).
- BestHTTP.Decompression.Zlib.GZipStream.UncompressBuffer; global DllCheck.Test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:20:22 -04:00
gamer147
8bb392dcd6 port(m1): wave 6h — CS0246 app types + Unity members/enums (236->210)
- Generated app types: ChapterCharaDecider, DownloadInfoGetter, DeckSelection(Confirm)DialogDisplay,
  SubChapterStorySectionBtn, EvolutionHideMessageVfx; nested OpeningShowCharacterPanelVfx on OpeningVfx.
- EffectMgr.MoveType: full 47-value decomp enum (was 4).
- MonoBehaviour.print, Debug.isDebugBuild, LayerMask.LayerToName,
  SystemLanguage.Chinese, RuntimePlatform.XBOX360/BlackBerryPlayer/+console values.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:15:46 -04:00
gamer147
d4364ae4b1 port(m1): wave 6g — CS1061 member cluster (304->236)
- Friend.PlayerData full-surface generated (18 members) + hand stub -> partial.
- Wizard.RoomMatch.Player: 7 friend-info props (ViewerId/Name/Rank/Emblem/Degree/Country/IsFriend).
- GameMgr: HasAuthAdmin, ChangeAspectRatio(float), Update().
- Cute.SceneManager: ChangeScene overloads + SceneChangeParameter (+SceneChangeParameter stub).
- UnityEngine.SceneManagement.SceneManager + Scene; RedShellSDK.RedShellSDK statics.
- Packet.Attachments; Vector2.Dot/Angle/Normalize.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:11:43 -04:00
gamer147
e5e05deadb port(m1): wave 6f — Unity primitive operators (362->304)
CS0019 operator gaps on value-type shims:
- Vector2: ==/!=, Vector2*Vector2, Equals/GetHashCode.
- Vector4: *float, +/-, ==/!=, Equals/GetHashCode.
- Color: ==/!= (Color==Color32 via existing implicit conv), Equals/GetHashCode.
- Rect: ==/!=; Matrix4x4: *, GetColumn/GetRow/indexer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 00:08:11 -04:00