{
  "contract": "replay-scope",
  "version": 2,
  "summary": "This contract covers racing ghosts, daily seeds, observer replays, solution shares, and other recorded reruns. It decides what the record contains, whether the game can still play the record after an update, what must match, and what happens at the first difference. This contract does not cover input encoding, random-number methods, storage, cameras, or networking.",
  "questions": {
    "replay-record": {
      "asks": "What does this replay need to run again?",
      "rationale": "A daily seed recreates a challenge. A racing ghost also needs the driver's recorded inputs.",
      "options": {
        "seed-only": {
          "meaning": "The replay needs only the seed. A roguelike daily run rebuilds the day's dungeon before new play begins.",
          "semantics": "The record carries the seed but no input log; each claim's comparison reference is carried or recomputed from the record. Playback consumes the seed, accepts live inputs, and applies each claim's live-input answer."
        },
        "seed-and-input-log": {
          "meaning": "The replay needs the seed and the recorded inputs. A racing ghost follows the recorded steering on the same generated track.",
          "semantics": "The record carries the seed and one ordered input log; each claim's comparison reference is carried or recomputed from the record. Playback consumes the seed and log from the declared starting point; changing either creates a different record instance."
        },
        "input-log-from-fixed-start": {
          "meaning": "The replay needs recorded inputs and one fixed start. A puzzle solution begins from the shared board and repeats the saved moves.",
          "semantics": "The record carries one fixed-start identity and one ordered input log; each claim's comparison reference is carried or recomputed from the record. Seed identity is not a separate requirement."
        }
      }
    },
    "after-an-update": {
      "asks": "What happens to a recorded replay after the game updates?",
      "rationale": "A patch can change rules, content, or timing. The replay needs a clear version promise before playback starts.",
      "options": {
        "same-version-only": {
          "meaning": "The replay works only in the version that recorded it. A patched racing game labels an older ghost as incompatible.",
          "semantics": "When the recorded and running version ids differ, refuse the replay before consuming its seed, start, or inputs. Equal version ids do not override failed content, mod, or settings checks."
        },
        "migrate-then-replay": {
          "meaning": "The game converts the replay before playing it. A puzzle update maps an old move list onto the revised board rules.",
          "semantics": "When the version ids differ, a cited migration rule derives a new record for the running version while preserving the source record. Playback consumes only a successful migrated record and identifies both versions and the migration used."
        },
        "best-effort-with-declared-divergence": {
          "meaning": "The game tries the old replay and states what may differ. An RTS update names changed unit balance before the observer replay starts.",
          "semantics": "When the version ids differ, the running version consumes the original record after presenting the cited known changes between the versions. Actual differences still follow the divergence-response answer."
        }
      }
    },
    "divergence-response": {
      "asks": "What happens at the first difference between the replay and the record?",
      "rationale": "A replay can stop, continue with a warning, or continue without showing the difference.",
      "options": {
        "stop-and-report": {
          "meaning": "Stop the replay and report the first difference. A puzzle solution stops on the first move that produces the wrong board.",
          "semantics": "Do not consume the next recorded input. Report the failed claim, comparison point, expected result, observed result, versions, and platforms, then end playback as diverged."
        },
        "continue-and-flag": {
          "meaning": "Keep playing and mark the replay as diverged. An RTS observer can watch the rest after a unit first appears in the wrong place.",
          "semantics": "Report the first difference, mark playback as diverged, and continue from playback's own state. Later comparisons are informational; they do not replace the first report or resynchronize playback to the reference."
        },
        "continue-silently": {
          "meaning": "Keep playing without showing the difference. A racing ghost can finish the lap after its position differs from the record by more than the allowed gap.",
          "semantics": "Mark the difference inside the replay controller, send no report to the player, to the ordinary log, or to telemetry, and continue from playback's own state. Later comparisons are informational and playback remains diverged."
        }
      }
    }
  },
  "declares": {
    "values": {
      "allowed-position-gap": {
        "description": "The greatest allowed distance between recorded and replayed positions, in the position unit named by every position claim in this adoption.",
        "range": [
          0,
          1000000
        ],
        "forms": [
          "number",
          "citation"
        ],
        "when": {
          "row-has": {
            "reproduction-claims": {
              "matching-standard": [
                "allowed-position-gap"
              ]
            }
          }
        }
      }
    },
    "rows": {
      "replay-record": {
        "description": "Give the rules that record and play back this kind of replay. One adoption has exactly one row.",
        "when-empty": "An empty replay-record list is never a behavior choice: this adoption requires exactly one row, and a reviewer rejects a file without it.",
        "record": {
          "id": {
            "type": "string",
            "required": true,
            "pattern": "kebab-case",
            "unique": true,
            "description": "A short name for this kind of replay in your game's words, such as ghost-lap or observer-match. Each finished record of this kind has its own identity. The rules for recording define that identity."
          },
          "recording-declared-in": {
            "type": "citation",
            "required": true,
            "description": "Where your game's rules name the start and the end of recording. The same rules set the recording version, the platform, the content-set identity, the settings, the mod identity, and the record's own identity. They name the seed or the fixed start, and the input log when one is used. They say whether each claim's comparison reference is captured at recording or recomputed from the record at playback."
          },
          "input-clock-declared-in": {
            "type": "citation",
            "when": {
              "flag": {
                "replay-record": [
                  "seed-and-input-log",
                  "input-log-from-fixed-start"
                ]
              }
            },
            "description": "Where your game's rules say how recorded inputs are ordered, and which clock, step, or turn is used to play them back."
          },
          "fixed-start-declared-in": {
            "type": "citation",
            "when": {
              "flag": {
                "replay-record": [
                  "input-log-from-fixed-start"
                ]
              }
            },
            "description": "Where your game's rules say how the game identifies the fixed starting state and verifies it before the first input."
          },
          "migration-declared-in": {
            "type": "citation",
            "when": {
              "flag": {
                "after-an-update": [
                  "migrate-then-replay"
                ]
              }
            },
            "description": "Where your game's rules state the deterministic rule that derives the record for the running version. The source record stays unchanged."
          },
          "cross-version-divergence-declared-in": {
            "type": "citation",
            "when": {
              "flag": {
                "after-an-update": [
                  "best-effort-with-declared-divergence"
                ]
              }
            },
            "description": "Where your game's rules state the known changes that may alter this replay in the running version. The game shows this statement to the player."
          },
          "difference-report-declared-in": {
            "type": "citation",
            "required": true,
            "description": "Where your game's rules describe the incompatibility or difference report. Before playback, the report presents a refusal because of the version, the content, the mods, the settings, the start, or the migration. When the selected response is visible, the report presents the first failed claim and the comparison details."
          }
        }
      },
      "reproduction-claims": {
        "description": "List one row for each result this replay promises to compare. Rows may share one conditions section when the same conditions apply. A shared section must cover every row that points to it.",
        "when-empty": "This adoption makes no replay promise without at least one result to compare, and a reviewer rejects the empty list.",
        "record": {
          "id": {
            "type": "string",
            "required": true,
            "pattern": "kebab-case",
            "unique": true,
            "description": "A short name for this comparison claim in your game's words, such as car-path or match-state."
          },
          "artifact": {
            "type": "string",
            "required": true,
            "description": "The game's plain name for the result that playback compares."
          },
          "platform-reach": {
            "type": "string",
            "required": true,
            "options": [
              "recorded-platform-only",
              "every-supported-platform"
            ],
            "description": "Whether this claim is compared only on the recording platform or on every supported platform."
          },
          "shifts-with-live-input": {
            "type": "string",
            "when": {
              "flag": {
                "replay-record": [
                  "seed-only"
                ]
              }
            },
            "options": [
              "seed-fixes-this-claim",
              "live-input-may-shift-this-claim"
            ],
            "description": "Can the player's input during playback change a result that this replay promises? Say whether the seed alone decides this result, or whether live input may change it."
          },
          "live-input-dependence-declared-in": {
            "type": "citation",
            "when": {
              "row": {
                "shifts-with-live-input": [
                  "live-input-may-shift-this-claim"
                ]
              }
            },
            "description": "Where your game's rules name every fact about the player's earlier live input that may change this result. Live input that the rules do not list does not change the result."
          },
          "matching-standard": {
            "type": "string",
            "required": true,
            "options": [
              "bit-exact-state",
              "outcome-equivalent",
              "allowed-position-gap"
            ],
            "description": "What this claim compares: every named state byte, every named outcome field, or position in the named space using the adoption's allowed gap."
          },
          "reproduces": {
            "type": "citation",
            "required": true,
            "description": "Where your game's rules name every state byte, outcome field, or position that must match."
          },
          "excludes": {
            "type": "citation",
            "required": true,
            "description": "Where your game's rules name what this claim excludes from what it promises to match. This section is separate from the section that names what must match. When nothing is excluded, the section says so."
          },
          "conditions": {
            "type": "citation",
            "required": true,
            "description": "Where your game's rules say when the promise holds. The conditions include the content-set identity, the settings, the mods, and every other condition for compatibility or comparison. Content identity is a condition, not a version."
          },
          "comparison-points": {
            "type": "citation",
            "required": true,
            "description": "Where your game's rules say when a reference is captured or recomputed and when playback compares it, such as at every simulation checkpoint, at the finish line, or at the solved board."
          }
        }
      }
    }
  },
  "rules": {
    "best-effort-must-be-visible": {
      "forbid": {
        "flag": {
          "after-an-update": [
            "best-effort-with-declared-divergence"
          ],
          "divergence-response": [
            "continue-silently"
          ]
        }
      },
      "message": "A replay that the game tries after an update must show its first difference. Choose stop-and-report or continue-and-flag, or choose same-version-only."
    }
  },
  "origin": "https://opengdd.org/contracts/replay-scope-2",
  "mechanism": [
    "This text decides the order of the steps for what is recorded, when capture or recomputation happens, what playback consumes, and how differences are detected and handled. The questions and rows supply choices and cited game rules. They do not change the order.",
    "A `replay-record` row names a replay kind. Each immutable replay record of that kind carries its own stable instance identity under `recording-declared-in`. It also carries the recording version, platform, content-set identity, settings and mod identity; the chosen seed or fixed start; the ordered input log when selected; and every claim's comparison reference. A reference is either captured at recording or deterministically recomputed from the sealed record at lifecycle step 11. A migrated record is a derived record with its own identity and a link to the unchanged source.",
    "A **comparison point** is a cited checkpoint at which playback reads a result and obtains the corresponding captured or recomputed reference. A **difference** is the first eligible comparison that fails that claim's matching standard. The terminal playback result is `diverged`, `rejected`, or `complete`; before a terminal result, playback is in progress. When the game refuses a record or a replay, the result is `rejected`.",
    "### Record",
    "1. Read the one `replay-record` row and every reproduction claim. From `recording-declared-in`, set the recording version, platform, content-set identity, settings, and mod identity before the record begins. They do not change during the recording.",
    "2. Establish the start. A seed-only or seed-and-input record captures the seed before any claimed seeded result is generated. A fixed-start record captures an identity that the cited state rule can verify before playback.",
    "3. Begin input capture at the cited start. A seed-only record captures no inputs. Either input-log record captures each mapped game action with its complete order and cited clock, step, or turn.",
    "4. At every claim's comparison point, either capture the reference required by that claim's matching standard or capture all sealed source data that the cited rule requires to recompute the reference at step 11.",
    "5. End capture at the cited boundary. Seal the record's own instance identity and contents. A later edit creates a different record instance of the same replay kind.",
    "### Select a playable version and claims",
    "6. Before consuming the seed, start, or inputs, read the version, platform, content-set identity, settings, and mod identity carried under `recording-declared-in`, then read every cited compatibility condition. If a record-wide identity — content, settings, mods, or the fixed start — no longer holds, refuse the record and use the incompatibility report. A failed condition cited by one claim alone exempts only that claim, per steps 7 and 12. Content identity is a condition, not a version; a level-content patch can therefore invalidate a record even when the version id is unchanged.",
    "7. Determine platform reach claim by claim. A claim limited to the recording platform is not compared on another running platform. A claim covering every supported platform is not compared on an unsupported running platform. A claim that is excluded in one of these two ways does not diverge. The other claims continue.",
    "8. Only when the recorded version differs from the running version, apply the selected update policy. `same-version-only` refuses the record with the incompatibility report. `migrate-then-replay` runs the cited migration once; success creates a derived record naming source version, target version, and migration rule, and when the migration fails, the game refuses the record. `best-effort-with-declared-divergence` presents the cited known changes and keeps the source record unchanged. Migration must map the recorded input clock to an existing running-version clock; playback under `best-effort-with-declared-divergence` refuses the record if the cited clock no longer exists.",
    "### Replay and compare",
    "9. Recreate the start. Supply the recorded seed when present. Verify or restore the fixed starting state when present. Refuse the replay if either required item cannot be established.",
    "10. For an input-log record, consume inputs in their recorded order at their cited clock, step, or turn. For a seed-only record, accept live inputs. A `seed-fixes-this-claim` result cannot change when those inputs vary. A `live-input-may-shift-this-claim` result may read only the live-input facts named by its `live-input-dependence-declared-in` citation.",
    "11. Obtain each claim's comparison reference. Read a reference captured in the record, or deterministically recompute it from the sealed record using the method cited by `recording-declared-in` and that claim's `comparison-points`. This is the recomputation step used by a puzzle share whose solved-board reference is derived from its fixed board and move log.",
    "12. At each comparison point, first read the claim's cited conditions. If they are not met, do not compare that claim and do not mark a divergence. The `live-input-dependence-declared-in` citation of a `live-input-may-shift-this-claim` result works the same way: a result that differs only as that citation permits is not compared against the recorded reference and does not diverge; where the citation's method recomputes a reference for the actual inputs, step 11's recomputation applies. Otherwise compare with the reference using the row's matching standard. Bit-exact state compares every declared byte. Outcome matching compares every declared outcome field. Position matching measures distance in the cited space and passes when it is no greater than `allowed-position-gap`. `excludes` subtracts from `reproduces`; excluded state is never compared.",
    "This contract makes no promise about changes outside the cited conditions. Such a change does not fail this contract.",
    "### Handle the first difference",
    "13. On the first failed eligible comparison, set the playback result to `diverged` and retain the claim id, comparison point, expected result, observed result, versions, platforms, and last consumed input when present.",
    "14. Under `stop-and-report`, present the difference, consume no later input, and end playback. Under `continue-and-flag`, present the difference, keep a visible diverged mark, and continue. Under `continue-silently`, emit no outward report and continue. Either continuing route advances from playback's own state. Later comparisons are informational and never resynchronize playback to the recorded reference.",
    "15. If no eligible comparison fails and the record reaches its cited end, set the result to `complete`. Completion means every comparison actually made matched. It makes no promise about excluded claims, unmet conditions, or excluded state.",
    "Every event offered at the same replay moment enters this lifecycle in the total order supplied by **Event resolution**. This contract preserves that order but does not choose it."
  ],
  "pack": "sha256:bf1143945366c1a44f1715fbfb5ca22c389ccc27b091ac8bc7bbfac64be3593c",
  "answers": {
    "replay-record": "seed-and-input-log",
    "after-an-update": "same-version-only",
    "divergence-response": "continue-and-flag"
  },
  "values": {
    "allowed-position-gap": 0.05
  },
  "rows": {
    "replay-record": [
      {
        "id": "ghost-lap",
        "recording-declared-in": "racing.ghost-recording",
        "input-clock-declared-in": "racing.physics-steps",
        "difference-report-declared-in": "racing.ghost-status"
      }
    ],
    "reproduction-claims": [
      {
        "id": "car-path",
        "artifact": "ghost car path",
        "platform-reach": "recorded-platform-only",
        "matching-standard": "allowed-position-gap",
        "reproduces": "racing.ghost-car-position",
        "excludes": "racing.ghost-path-exclusions",
        "conditions": "racing.ghost-lap-conditions",
        "comparison-points": "racing.ghost-sample-points"
      }
    ]
  }
}
