// Checks web/world.ts renders prompts byte-identically to train/world.py. import { execFileSync } from "node:child_process"; import { fileURLToPath } from "node:url"; import * as W from "../web/world.ts"; const here = fileURLToPath(new URL(".", import.meta.url)); const { cases, lists } = JSON.parse(execFileSync("python3", [here + "parity_states.py", "1"], { maxBuffer: 1 << 26 })); let bad = 0; for (const [k, py] of Object.entries(lists)) { const js = W[k] instanceof Set ? [...W[k]].sort() : W[k]; if (JSON.stringify(js) !== JSON.stringify(py)) { bad++; console.log(k, JSON.stringify(js), "!=", JSON.stringify(py)); } } // Every app event line must match exactly one Python pattern (the training // validator), and offers must be recognised as offers. const E = W.events; for (const c of cases) { const wake = ["talk", "touch", "light"].flatMap((k) => Array.from({ length: 6 }, (_, n) => W.wakeChance(c.st.stats.energy, k, n + 1))); if (wake.some((v, i) => Math.abs(v - c.wake[i]) > 1e-12)) { bad++; console.log("wake chance mismatch"); } for (const [k, got] of [["chat", W.header("chat", c.st)], ["diary", W.header("diary", c.st)], ["look", W.look(c.st)], ["clock", W.clock(c.st)], ["recall", W.recall(c.st.memories, c.q)]]) { if (got !== c[k]) { bad++; if (bad < 4) console.log(k, JSON.stringify(got), "!=", JSON.stringify(c[k])); } } const o = c.st.owner, p = c.st.pet; const evs = c.events.map((r) => new RegExp("^" + r + "$")), offers = c.offers.map((r) => new RegExp("^" + r + "$")); const lines = [...W.FOODS.map((f) => [E.offerFood(o, p, f), true]), [E.offerBath(o, p), true], [E.offerMedicine(o, p), true], [E.offerCatch(o, p), true], [E.caught(o, p, 1), false], [E.caught(o, p, 7), false], [E.pat(o, p), false], [E.lights(o, true), false], [E.lights(o, false), false], [E.woke(p), false], [E.pooped(p), false], [E.cleaned(o), false], [E.back(o, "3 hours"), false], [E.back(o, "1 day"), false], ...["kid", "teen", "adult"].map((s) => [E.grew(p, s), false])]; for (const [line, isOffer] of lines) { if (evs.filter((r) => r.test(line)).length !== 1 || offers.some((r) => r.test(line)) !== isOffer) { bad++; if (bad < 8) console.log("event", JSON.stringify(line), isOffer ? "(offer)" : ""); } } } console.log(`${cases.length} states, ${Object.keys(lists).length} word lists, ${bad} mismatches`); process.exit(bad ? 1 : 0);