Files
jason.woltje 21aa1cab0b darkwing: re-pin window rows 177-185 packet, STATE.md (sha256 b586f11c9b6f1329), W.txt (edd4622c5c45ef3f), S1/S2/S2b/B snapshots, matrices, W10 browser check and P3 rehearsals (#1683; P19 386)
NEW 490e2771d live for mosaic-stack, activation 20261020T075800Z-490e2771d3d0, store 3i. W0-W10 pass;
stops at W9 (assistant idle stop, mos-0948) and S2b/B (old chief end rows in the backup, mos-0950).
2026-10-20 03:27:30 -05:00

41 lines
2.4 KiB
JavaScript

// Window rows 177-185, mos-0949 B check: B (the W5 backup) has one more events row and one more
// role_claims row than S1. This hashes the backup's rows at or below S1's maxSeq exactly as
// snapshot.mjs read() hashes a table (columns in name order, rows in seq order, JSON lines, bigints as
// strings), so each prefix sha256 compares with S1's table sha256. It also prints the rows above S1's
// maxSeq: events by seq, at, kind, actor_role and actor_run only (no body or subject); role_claims by
// seq, at, role, op, holder_run, by and reason.
// Opens only the backup, immutable=1 and readOnly, and refuses when -wal or -shm is present.
// usage: node bprefix.mjs /abs/backup/bus.sqlite /abs/S1.json
import { DatabaseSync } from 'node:sqlite';
import { createHash } from 'node:crypto';
import { existsSync, readFileSync } from 'node:fs';
import { pathToFileURL } from 'node:url';
const [path, s1Path] = process.argv.slice(2);
for (const f of [path + '-wal', path + '-shm']) if (existsSync(f)) { console.error(`${f} is present`); process.exit(1); }
const s1 = JSON.parse(readFileSync(s1Path, 'utf8')).tables;
const db = new DatabaseSync(pathToFileURL(path).href + '?immutable=1', { readOnly: true });
const q = (name) => `"${name.replaceAll('"', '""')}"`;
const value = (v) => (typeof v === 'bigint' ? String(v) : v instanceof Uint8Array ? { hex: Buffer.from(v).toString('hex') } : v);
const SHOW = { events: ['seq', 'at', 'kind', 'actor_role', 'actor_run'], role_claims: ['seq', 'at', 'role', 'op', 'holder_run', 'by', 'reason'] };
let ok = true;
for (const table of Object.keys(SHOW)) {
const cols = db.prepare('SELECT name FROM pragma_table_info(?)').all(table).map((c) => c.name).sort();
const limit = BigInt(s1[table].maxSeq);
const stmt = db.prepare(`SELECT ${cols.map(q).join(',')} FROM ${q(table)} ORDER BY seq`);
stmt.setReadBigInts(true);
const h = createHash('sha256');
let n = 0;
const above = [];
for (const row of stmt.iterate()) {
if (row.seq <= limit) { h.update(JSON.stringify(cols.map((c) => value(row[c]))) + '\n'); n++; }
else above.push(Object.fromEntries(SHOW[table].map((c) => [c, value(row[c])])));
}
const sha = h.digest('hex');
const same = sha === s1[table].sha256 && n === s1[table].rows;
if (!same) ok = false;
console.log(JSON.stringify({ table, s1MaxSeq: String(limit), prefixRows: n, prefixSha256: sha, s1Sha256: s1[table].sha256, same, above }));
}
db.close();
process.exit(ok ? 0 : 2);