RGreview-game-corethe engine behind concept-first review games

Feature detail

Content-identity restore seam

Session snapshots carry an optional content identity (questionId, contentId, contentVersion) so a restored turn can be compared honestly against current authored content before it is resumed.

workflow/sessionworkflow/persistence

Worked example

Persisted vs current content identity

The session stamps a content identity on persist; on restore the consumer can ask the core whether authored content drifted.

Input

{
  "persisted": {
    "questionId": "q-1",
    "contentId": "factoring.q-1",
    "contentVersion": 3
  },
  "currentVariants": {
    "matches": {
      "questionId": "q-1",
      "contentId": "factoring.q-1",
      "contentVersion": 3
    },
    "drifted": {
      "questionId": "q-1",
      "contentId": "factoring.q-1",
      "contentVersion": 4
    }
  }
}

Output

{
  "matchesCurrent": {
    "matches": true,
    "mismatchFields": [],
    "unknownFields": [],
    "persisted": {
      "questionId": "q-1",
      "contentId": "factoring.q-1",
      "contentVersion": 3
    },
    "current": {
      "questionId": "q-1",
      "contentId": "factoring.q-1",
      "contentVersion": 3
    }
  },
  "driftedCurrent": {
    "matches": false,
    "mismatchFields": [
      "contentVersion"
    ],
    "unknownFields": [],
    "persisted": {
      "questionId": "q-1",
      "contentId": "factoring.q-1",
      "contentVersion": 3
    },
    "current": {
      "questionId": "q-1",
      "contentId": "factoring.q-1",
      "contentVersion": 4
    }
  }
}

Real source excerpt

Content identity types and comparison contract

src/workflow/session.ts
export type SessionContentVersion = string | number;

export interface SessionContentIdentity {
  questionId?: string | null;
  contentId?: string | null;
  contentVersion?: SessionContentVersion | null;
}

export interface ResolvedSessionContentIdentity {
  questionId: string | null;
  contentId: string | null;
  contentVersion: SessionContentVersion | null;
}

export type SessionContentIdentityField = keyof ResolvedSessionContentIdentity;

export interface SessionContentIdentityComparison {
  matches: boolean;
  mismatchFields: SessionContentIdentityField[];
  unknownFields: SessionContentIdentityField[];
  persisted: ResolvedSessionContentIdentity;
  current: ResolvedSessionContentIdentity;
}