Report database size and make four genuine suites reproducible
Operations now report the SQLite database size and page count, read through PRAGMA page_count/page_size in the same authority-checked batch as the lifecycle counters with non-numeric values clamped to zero; the page renders both and states that free disk space is still unknown. replaceMoritaniAssassinationTraitors draws the first distinct physical Traitor Card from the reserve instead of the reserve's first entry, because the face-up set-aside card can still sit in that list: re-drawing it produced a receipt whose replacement equalled the revealed card, which the assassination integrity check rejects mid-Mentat. With no distinct card left the step is blocked with an explicit reason instead of committing an invalid receipt. Four tests were made reproducible after measuring their real failure rates, because a suite that fails for random reasons cannot act as a checkpoint gate: the Discovery typed Spice Blow test now removes other cards for the same territory so one blow deposits the printed amount (0/20 after, ~20% before); the Discovery E2 skills deal is pinned with the new shared tests/deterministic-random.ts helper so a Lasgun-shield explosion cannot pre-empt its skill consumer (0/12 after, ~20% before); the Ecaz Occupy Ix/CHOAM policy check accepts any legal continuation and still asserts the phase it reaches (0/30 after, ~10% before); and the mixed-E3 Moritani Cunning test keeps the random storm off red_chasm's single sector (0/25 after, ~20% before). Offline suite 7,801/7,801 with typecheck and lint clean. No game, seat, saved state or deployment changes.
This commit is contained in:
1 parent
8bea4c1a0c
commit
e493bcf58e
12 files changed
+128
-13
No files matched your search
+21
-4
@@ -15,6 +15,8 @@ export type AdminOperations = {
|
||||
backupDownloads: number;
|
||||
stalledRooms: number;
|
||||
oldestStalledChange: number | null;
|
||||
databasePages: number;
|
||||
databaseBytes: number;
|
||||
};
|
||||
|
||||
export type AdminIntegrity = {
|
||||
@@ -56,11 +58,12 @@ const stalledJoins = `FROM rooms r
|
||||
LEFT JOIN room_archives a ON a.room_code=r.code
|
||||
LEFT JOIN room_controls k ON k.room_code=r.code`;
|
||||
|
||||
type Counts = Omit<AdminOperations, 'observedAt'>;
|
||||
type Counts = Omit<AdminOperations, 'observedAt' | 'databasePages' | 'databaseBytes'>;
|
||||
|
||||
/** Aggregate only operational counters, never serialized game or private backup rows. */
|
||||
export async function readAdminOperations(database: D1Database, identity: AdminIdentity, now = Date.now()): Promise<AdminOperations> {
|
||||
const row = await database.prepare(`SELECT
|
||||
const [counters, pages, pageSize] = await database.batch([
|
||||
database.prepare(`SELECT
|
||||
(SELECT COUNT(*) FROM rooms) rooms,
|
||||
(SELECT COUNT(*) FROM rooms r JOIN room_removals m ON m.room_code=r.code WHERE m.removed=1) removedRooms,
|
||||
(SELECT COUNT(*) FROM rooms r JOIN room_archives a ON a.room_code=r.code WHERE a.archived=1) archivedRooms,
|
||||
@@ -75,9 +78,23 @@ export async function readAdminOperations(database: D1Database, identity: AdminI
|
||||
(SELECT COUNT(*) ${stalledJoins} WHERE ${stalledRoom} AND r.updated_at<?) stalledRooms,
|
||||
(SELECT MIN(r.updated_at) ${stalledJoins} WHERE ${stalledRoom} AND r.updated_at<?) oldestStalledChange
|
||||
WHERE EXISTS (${ownerAuthority})`)
|
||||
.bind(now - ADMIN_STALL_MS, now - ADMIN_STALL_MS, identity.sessionHash, identity.id, now).first<Counts>();
|
||||
.bind(now - ADMIN_STALL_MS, now - ADMIN_STALL_MS, identity.sessionHash, identity.id, now),
|
||||
database.prepare('PRAGMA page_count'),
|
||||
database.prepare('PRAGMA page_size'),
|
||||
]);
|
||||
const row = counters.results[0] as Counts | undefined;
|
||||
if (!row) throw new AdminError('Owner sign-in required.', 403);
|
||||
return { observedAt: now, ...row };
|
||||
const count = (result: D1Result, column: string): number => {
|
||||
const value = (result.results[0] as Record<string, unknown> | undefined)?.[column];
|
||||
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : 0;
|
||||
};
|
||||
const databasePages = count(pages, 'page_count');
|
||||
return {
|
||||
observedAt: now,
|
||||
...row,
|
||||
databasePages,
|
||||
databaseBytes: databasePages * count(pageSize, 'page_size'),
|
||||
};
|
||||
}
|
||||
|
||||
/** Bounded, read-only stalled-decision sample for the owner operations page. */
|
||||
|
||||
Reference in new issue
Block a user