site_audit: createWorld needs a site now — feed verifyPosts the shipped JSON

A's gate-1 merge made createWorld REQUIRE a site (throws without one), which
crashed this tool's post cross-check: it called createWorld(scene, {wind}) with
no site. Fixed by reading the shipped data/sites/backyard_01.json and passing it
(loadSite fetch()es, so it can't run in node — read the file directly). The
cross-check is now BETTER: it verifies the dressed-snapshot posts against the
actual shipped site data, raked in createWorld, rather than against code.

Built-in audit green again; dress-source refusal (exit 2) and resolved-export
(exit 0) paths unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-17 15:59:58 +10:00
parent bb1106efec
commit 3c313f593f

View File

@ -91,6 +91,12 @@ const VERIFIABLE = new Set(['p1', 'p2', 'p3', 'p4']);
/**
* Re-derive the posts from live world.js and fail loudly if the dump drifted.
* The one guard-rail a hand-typed yard can actually have.
*
* SPRINT10: world.js stopped being code createWorld now REQUIRES a site and
* throws without one. It reads the site from data/sites/backyard_01.json, which
* is exactly the extraction A shipped, so this cross-check now compares the dump
* against the DATA's posts (raked in createWorld, no dress needed). loadSite()
* itself fetch()es and can't run in node, so read the JSON and hand it over raw.
*/
async function verifyPosts(site) {
const THREE = await import('../../web/world/vendor/three.module.js');
@ -100,7 +106,8 @@ async function verifyPosts(site) {
speedAt: () => 4, rainAt: () => 0, rainMmPerHour: () => 0,
gustTelegraph: () => null, setSheltersFromTrees() {}, eventsBetween: () => [],
};
const world = createWorld(new THREE.Scene(), { wind: stub }); // graybox: fine, posts are graybox
const siteData = JSON.parse(await readFile(new URL('../../web/world/data/sites/backyard_01.json', import.meta.url), 'utf8'));
const world = createWorld(new THREE.Scene(), { wind: stub, site: siteData }); // graybox: fine, posts are raked in createWorld
const live = new Map(world.anchors.map((a) => [a.id, a.pos]));
const drift = [];
for (const a of site.anchors) {