Add repeatable verification and establish fresh save checkpoint
Consolidate current readiness and existing rule decisions, preserve selective subagents and automatic verified Git pushes, and record the efficiency pilot. Add source-bound compact checks, private saved-game snapshots/online backups, and bounded HTTP seat-restoration checks with 15 meaningful regressions. At the user's explicit request, archive and clear 3,644 old local rooms and related records while retaining schema/migrations; preserve future games from a fresh empty baseline. Private backups and credentials are outside Git. Validation: npm run check passes types, lint and all 4,177 offline tests. Full report: 20260913-efficiency-check-3, 130.147 seconds; source fingerprint 344ce1d44475b0cd4ff10a915f28331cb4e2fcacbc7595636fbaa645c0568f64. Two earlier broad attempts stopped at new type/lint errors before tests; both were fixed. Independent review found cancellation falsely passing; SIGINT/SIGTERM regressions and review confirm the fix. Documentation links, example test selection, private backup integrity and empty baseline verified. No app/build/dependency/HTTP implementation changed; no production build, HTTP suite, browser acceptance or AI calibration claimed for this checkpoint. The full game goal and existing release gates remain unfinished.
This commit is contained in:
1 parent
06d0a66fc5
commit
6e26ba5daa
17 files changed
+1242
-2
No files matched your search
@@ -0,0 +1,102 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import * as sqlite from 'node:sqlite';
|
||||
import { mkdtempSync, mkdirSync, rmSync, existsSync, statSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
import {
|
||||
captureSavedGames,
|
||||
compareSavedGames,
|
||||
loadSavedGameSnapshot,
|
||||
readSavedGames,
|
||||
} from '../tools/saved-game-verification';
|
||||
|
||||
function fixture(t: test.TestContext) {
|
||||
const area = mkdtempSync(join(tmpdir(), 'dune-preservation-'));
|
||||
const root = join(area, 'repo');
|
||||
mkdirSync(root);
|
||||
const path = join(root, 'games.sqlite'),
|
||||
db = new sqlite.DatabaseSync(path);
|
||||
db.exec(
|
||||
"PRAGMA journal_mode=WAL; CREATE TABLE rooms(code TEXT PRIMARY KEY, version INTEGER, state TEXT); INSERT INTO rooms VALUES('ABCDEFGH', 2, '{\"privateHand\":[1]}')",
|
||||
);
|
||||
t.after(() => {
|
||||
db.close();
|
||||
rmSync(area, { recursive: true, force: true });
|
||||
});
|
||||
return { area, root, path, db };
|
||||
}
|
||||
|
||||
void test('preservation allows new rooms but detects changed state, versions and missing originals', (t) => {
|
||||
const { path, db } = fixture(t),
|
||||
baseline = readSavedGames(path);
|
||||
db.exec("INSERT INTO rooms VALUES('BCDEFGHJ', 0, '{}')");
|
||||
const added = compareSavedGames(baseline, readSavedGames(path));
|
||||
assert.equal(added.preserved, true);
|
||||
assert.equal(added.added, 1);
|
||||
db.exec("UPDATE rooms SET version=3 WHERE code='ABCDEFGH'");
|
||||
assert.equal(
|
||||
compareSavedGames(baseline, readSavedGames(path)).preserved,
|
||||
false,
|
||||
);
|
||||
db.exec("UPDATE rooms SET version=2, state='{}' WHERE code='ABCDEFGH'");
|
||||
assert.deepEqual(compareSavedGames(baseline, readSavedGames(path)).changed, [
|
||||
'ABCDEFGH',
|
||||
]);
|
||||
db.exec("DELETE FROM rooms WHERE code='ABCDEFGH'");
|
||||
assert.deepEqual(compareSavedGames(baseline, readSavedGames(path)).missing, [
|
||||
'ABCDEFGH',
|
||||
]);
|
||||
});
|
||||
|
||||
void test('private snapshot stores hashes and cannot overwrite an earlier baseline', async (t) => {
|
||||
const { area, root, path } = fixture(t),
|
||||
out = join(area, 'snapshot');
|
||||
const result = await captureSavedGames(root, path, out);
|
||||
assert.deepEqual(loadSavedGameSnapshot(join(out, 'snapshot.json')), result);
|
||||
assert.equal(JSON.stringify(result).includes('privateHand'), false);
|
||||
assert.equal(statSync(join(out, 'snapshot.json')).mode & 0o777, 0o600);
|
||||
await assert.rejects(captureSavedGames(root, path, out));
|
||||
assert.deepEqual(loadSavedGameSnapshot(join(out, 'snapshot.json')), result);
|
||||
assert.throws(
|
||||
() =>
|
||||
compareSavedGames(
|
||||
{ ...result, rooms: [...result.rooms, ...result.rooms] },
|
||||
result,
|
||||
),
|
||||
/Invalid/,
|
||||
);
|
||||
});
|
||||
|
||||
void test('missing source never creates a database or output', async (t) => {
|
||||
const { area, root } = fixture(t),
|
||||
missing = join(area, 'missing.sqlite'),
|
||||
out = join(area, 'out');
|
||||
await assert.rejects(captureSavedGames(root, missing, out));
|
||||
assert.equal(existsSync(missing), false);
|
||||
assert.equal(existsSync(out), false);
|
||||
});
|
||||
|
||||
void test(
|
||||
'online backup includes WAL state and leaves the live database untouched',
|
||||
{ skip: typeof sqlite.backup !== 'function' },
|
||||
async (t) => {
|
||||
const { area, root, path, db } = fixture(t),
|
||||
out = join(area, 'backup');
|
||||
db.exec("INSERT INTO rooms VALUES('CDEFGHJK', 4, '{\"pending\":true}')");
|
||||
const before = readSavedGames(path),
|
||||
snapshot = await captureSavedGames(root, path, out, true);
|
||||
assert.equal(compareSavedGames(before, snapshot).preserved, true);
|
||||
assert.equal(snapshot.rooms.length, 2);
|
||||
assert.equal(
|
||||
compareSavedGames(snapshot, readSavedGames(join(out, 'games.sqlite')))
|
||||
.preserved,
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
compareSavedGames(before, readSavedGames(path)).preserved,
|
||||
true,
|
||||
);
|
||||
assert.equal(statSync(join(out, 'games.sqlite')).mode & 0o777, 0o600);
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user