Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd98f46267 | |||
| c60d465711 | |||
| ce2b29f5df |
@@ -6,6 +6,23 @@ project follows [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.43.3] — 2026-07-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Replays are now self-contained (schema v4).** A replay stores the dealt
|
||||
board itself via the upstream `card_game` session serializers instead of
|
||||
re-dealing from the seed at playback time, so replays survive RNG and
|
||||
upstream upgrades that change the seed→deal mapping — the failure that had
|
||||
silently broken every stored replay. The web player and web game now
|
||||
exchange the full payload through the wasm layer (the old JS path hardcoded
|
||||
`schema_version: 2`, uploaded empty move lists, and corrupted u64 seeds via
|
||||
`Math.round`), and the replay viewer reports unplayable old-format replays
|
||||
in the caption instead of dying silently. Pre-v4 replays are rejected by a
|
||||
version gate; local histories repopulate with new wins. (#170)
|
||||
- **Difficulty-mode wins can upload.** The server's replay `mode` validation
|
||||
now accepts data-carrying `GameMode` variants (previously a 400). (#170)
|
||||
|
||||
## [0.42.0] — 2026-07-06
|
||||
|
||||
### Added
|
||||
|
||||
@@ -69,9 +69,9 @@ test("draw-mode toggle affects replay payload draw_mode", async ({ page }) => {
|
||||
|
||||
const payload = await page.evaluate(() => window.__FERROUS_DEBUG__.replayPayload());
|
||||
expect(payload.draw_mode).toBe("DrawThree");
|
||||
expect(payload.schema_version).toBe(2);
|
||||
expect(Array.isArray(payload.moves)).toBeTruthy();
|
||||
expect(payload.moves.length).toBeGreaterThan(0);
|
||||
expect(payload.schema_version).toBe(4);
|
||||
expect(Array.isArray(payload.recording?.instructions)).toBeTruthy();
|
||||
expect(payload.recording.instructions.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("autonomous play keeps invariants stable across seed batch", async ({ page }) => {
|
||||
|
||||
@@ -47,7 +47,7 @@ test("debug failure report contains replay diagnostics", async ({ page }) => {
|
||||
expect(report.invariants).toBeTruthy();
|
||||
});
|
||||
|
||||
test("replay payload builder exports schema-v2 moves", async ({ page }) => {
|
||||
test("replay payload builder exports a schema-v4 recording", async ({ page }) => {
|
||||
await page.goto("/play-classic?seed=42");
|
||||
await page.waitForFunction(() => typeof window.__FERROUS_DEBUG__ === "object");
|
||||
|
||||
@@ -57,10 +57,14 @@ test("replay payload builder exports schema-v2 moves", async ({ page }) => {
|
||||
.poll(async () => await page.evaluate(() => window.__FERROUS_DEBUG__.replayPayload() !== null))
|
||||
.toBe(true);
|
||||
const payload = await page.evaluate(() => window.__FERROUS_DEBUG__.replayPayload());
|
||||
expect(payload.schema_version).toBe(2);
|
||||
// Schema v4: the wasm layer assembles the whole payload; the deal is
|
||||
// embedded in `recording` and moves live at recording.instructions.
|
||||
expect(payload.schema_version).toBe(4);
|
||||
expect(payload.draw_mode).toMatch(/Draw(One|Three)/);
|
||||
expect(payload.mode).toBe("Classic");
|
||||
expect(Array.isArray(payload.moves)).toBeTruthy();
|
||||
expect(payload.moves.length).toBeGreaterThan(0);
|
||||
expect(payload.win_move_index).toBe(payload.moves.length - 1);
|
||||
expect(payload.recording).toBeTruthy();
|
||||
expect(payload.recording.initial_state).toBeTruthy();
|
||||
expect(Array.isArray(payload.recording.instructions)).toBeTruthy();
|
||||
expect(payload.recording.instructions.length).toBeGreaterThan(0);
|
||||
expect(payload.win_move_index).toBe(payload.recording.instructions.length - 1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user