From 3c313f593fa675e7f5678ee173e7681237aa8090 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Fri, 17 Jul 2026 15:59:58 +1000 Subject: [PATCH] =?UTF-8?q?site=5Faudit:=20createWorld=20needs=20a=20site?= =?UTF-8?q?=20now=20=E2=80=94=20feed=20verifyPosts=20the=20shipped=20JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- tools/site_audit/audit.mjs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/site_audit/audit.mjs b/tools/site_audit/audit.mjs index de0622c..1400f12 100644 --- a/tools/site_audit/audit.mjs +++ b/tools/site_audit/audit.mjs @@ -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) {