Skip to content
This repository was archived by the owner on Sep 20, 2026. It is now read-only.
This repository was archived by the owner on Sep 20, 2026. It is now read-only.

fix(ghost-battle): gate combat start on complete native board setup #302

Description

@pengx17

Background

Ghost Battle playback has been fixed repeatedly, but the same failure still occurs intermittently: combat begins while cards are only partially present on the board. Another speculative delay or one more local readiness check is not acceptable without stage-level evidence.

Current problem

Verified from the user-provided screenshot on 2026-08-25:

  • Game build: 1.0.11980-prod-macos-arm64-d75a8ee9
  • Mod build: BPP 5.2.1.prod
  • Saved Ghost Battle playback is already at 0:22.00 and resolving combat effects.
  • The local board is visibly incomplete: most card bodies are absent while several cooldown labels remain over empty board regions.
  • This is therefore a start-gate/readiness failure, not merely a loading screen that lingers before combat.

Still unverified:

  • Whether the missing objects were never instantiated, were instantiated but not activated/render-ready, or were invalidated by a stale playback session.
  • Which owner actually authorizes combat start in the failing run.

Candidate cause mechanisms

Treat these as alternatives to falsify, not conclusions:

  1. Readiness is too shallow: the gate observes a populated DTO/controller/list before each native card's asynchronous SetUp and visual activation have completed.
  2. Expected-count mismatch: readiness compares against a filtered or transient count, so missing cards are accepted as a complete board.
  3. Lost ordering: an auto-start callback is armed before board construction finishes and is not cancelled/revalidated when asynchronous setup is still pending.
  4. Cross-session completion: a task/callback from a previous replay generation releases or bypasses the current replay's gate.
  5. Timeout fail-open: a bounded wait expires and intentionally starts combat without recording exactly what remained incomplete.
  6. Non-transactional application: payload/state application and native board construction publish partial state that combat consumes before the final reconciliation pass.

Verification method

Before changing behavior, add a temporary probe on the real Ghost Battle playback path. Every event must carry one playback/session generation and monotonic elapsed time.

Capture:

  • payload accepted: expected hero, item, skill, and board-slot counts for both sides;
  • native construction requested/completed per stable card id and slot;
  • asynchronous card SetUp requested/completed/failed and final activeInHierarchy/visibility state;
  • every readiness evaluation with expected vs completed vs visible counts;
  • every start authorization with owner, reason (ready, timeout, or other bypass), session generation, and unresolved ids/slots;
  • cancellation/disposal and any callback rejected as stale.

Reproduce at least once from a cold asset/cache state and once on a warm repeat of the same Ghost Battle. The hypothesis is considered proven only when one start-authorization event precedes the missing cards' terminal setup state (or shows an incorrect expected set/session generation).

Fix acceptance

  • Combat cannot enter its running state until all payload-required native board entities for the active playback generation have reached a terminal setup outcome.
  • A setup failure has an explicit user-visible/logged terminal policy; it cannot silently look ready.
  • Timeout, if retained, does not silently start a partial battle.
  • Stale callbacks cannot mutate or release a newer playback generation.
  • Pure tests pin the discovered ordering invariant and the failure/timeout policy.
  • Runtime probe/log evidence from cold and warm playback shows start authorization only after the final required setup completion.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions