ISTQB CT-GaMe study materials
ISTQB CT-GaMe study resources

Tidewalker Cross-Save: Modelling the Conflict With State Transitions

ISTQB CT-GaMe · Put your knowledge to work in context.

All case studies

Tidewalker Cross-Save: Modelling the Conflict With State Transitions

Hollow Pine Studio ships Tidewalker, an adventure game with cross-save across PC, PlayStation 5 and Switch. Each player has three manual save slots plus one autosave; saves are written locally and synced to a third-party cloud service. The game is fully playable offline. Support has 47 reports of lost progress in the last month, all from players who played offline for more than two hours and then reconnected; QA reproduced it 3 times in 1,200 scripted sessions. The next patch introduces save schema v4, which adds a 'discovered regions' array and a migration from v3. Saves can be up to 8 MB and the Switch write cap is 2 MB/s. You have 10 working days, three devices per platform, and one engineer who can build automation. The product owner wants the 47 reports 'closed' before the patch.

1. Model the save/sync behaviour as a state machine and derive transition coverage. Explain why state transition testing is the right technique here rather than equivalence partitioning.

Read the worked answer

States: LocalClean, LocalDirty (unsynced changes), Syncing, CloudAhead (cloud newer than local), Conflict, Migrating, and Failed/Retry. Events: play, save, go offline, go online, sync start, sync success, sync failure, schema migration.

The bug lives in a path, not in a value class: LocalDirty -> (reconnect) -> Syncing -> CloudAhead -> conflict resolution. Equivalence partitioning would treat 'offline play' and 'online play' as classes and completely miss the ordering that causes the overwrite. State transition testing makes the ordering the test basis.

Coverage: first achieve 0-switch (every valid transition once), because that already includes LocalDirty -> Syncing. Then add 1-switch (every adjacent pair), with priority on sequences containing CloudAhead and Conflict, since those are where the field reports cluster. Also test invalid transitions explicitly - a sync start while Migrating must be rejected - because undefined behaviour there is how corruption happens.

From the model I would derive concrete cases: offline 2h+ then reconnect with cloud ahead; offline then reconnect where local is ahead; two devices saving within the same minute; app killed during Syncing; migration triggered while LocalDirty; Switch write interrupted at 2 MB/s with an 8 MB save.

2. Define a test oracle for 'no progress lost' and describe how you would automate the check across three slots and three platforms.

Read the worked answer

'No progress lost' needs to be decomposed into checkable invariants, because a single 'looks right' comparison is not an oracle:

  • Monotonicity: playtime, discovered regions and currency never decrease across a sync.
  • Slot isolation: writing slot 2 never alters slot 1 or 3 beyond their timestamps.
  • Convergence: after both devices are online and idle, PC, PS5 and Switch report identical save content for the same slot.
  • Provenance: each save records which device and schema version wrote it, so a wrong overwrite is attributable.
  • Migration safety: a v3 save upgraded to v4 then read back preserves all pre-existing fields, and re-running migration is idempotent.

Automation: a debug build with a save-state hash API that dumps a canonical, ordered JSON of player state. The harness scripts play actions per platform, forces offline/online via network shaping, and compares hashes against golden state after each transition. For conflict cases it asserts the expected winner by rule, not by timestamp guessing. Run it nightly across the three platforms, and keep the 1,200-session reproducer as a regression suite because 3-in-1,200 is too rare for manual retesting.

3. Given a field rate of roughly 1 in 400 affected sessions, how would you reproduce and instrument the bug inside 10 days?

Read the worked answer

A 1-in-400 rate is not reproducible by hand; it needs either a targeted model or production instrumentation, and probably both.

First, use the state model to argue for the most likely trigger rather than brute-forcing sessions: all reports involve more than two hours offline, which suggests a sync token or timestamp comparison that only breaks after a threshold, or an autosave cadence that fires before the dirty flag is set. I would build a time-warp harness that fakes the device clock and the cloud timestamps instead of actually waiting two hours, which turns a 1-in-400 into a deterministic case if the hypothesis is right.

Second, add logging in the next build: sync decisions with the chosen winner, local and cloud revision counters, dirty flags at the moment of sync, and schema version. Log at the conflict-resolution function, not at the UI. Ship this to the beta cohort with consent, and set an alert on 'cloud overwrote local with older revision'.

Third, keep expectations honest in the plan: if no deterministic reproduction exists by day 6, the patch ships with the migration guarded behind a backup-on-migrate step, so a lost save becomes recoverable, and the reports are answered with a workaround rather than falsely closed.