Files
houseplan-card/scripts/coordinate-write-barrier-guard.mjs
T
2026-09-05 09:25:08 +03:00

106 lines
4.7 KiB
JavaScript

#!/usr/bin/env node
/** Executable inventory of every persisted config/layout coordinate writer (#291). */
import { readFileSync, readdirSync } from 'node:fs';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const defaultRoot = fileURLToPath(new URL('..', import.meta.url));
const occurrences = (source, needle) => {
const out = [];
let from = 0;
while (true) {
const index = source.indexOf(needle, from);
if (index < 0) return out;
out.push(index);
from = index + needle.length;
}
};
const requireWindow = (errors, source, index, pattern, label, before = 650) => {
const window = source.slice(Math.max(0, index - before), index + 260);
if (!pattern.test(window)) errors.push(`${label} bypasses the canonical boundary`);
};
export function checkCoordinateWriteBarriers(root = defaultRoot) {
const errors = [];
// The editor implementation is a lazy chunk, but the persisted-coordinate
// inventory remains one logical frontend. Normalize the typed host port so
// the existing boundary windows keep describing the production call sites.
const card = readFileSync(resolve(root, 'src/houseplan-card.ts'), 'utf8');
const editor = readFileSync(resolve(root, 'src/houseplan-editor-runtime.ts'), 'utf8')
.replaceAll('this.host.', 'this.');
const optimize = readFileSync(resolve(root, 'src/plan-optimize-write.ts'), 'utf8')
.replaceAll('host.', 'this.');
const frontend = `${card}\n${editor}\n${optimize}`;
const configWrites = occurrences(frontend, "type: 'houseplan/config/set'");
if (configWrites.length !== 1) errors.push(`frontend config writer inventory: ${configWrites.length}`);
for (const index of configWrites) requireWindow(
errors, frontend, index,
/const canonicalCandidate = canonicalizeConfigGeometry\(candidate\);[\s\S]*config: canonicalCandidate,[\s\S]*expected_rev: this\._cfgRev/,
'frontend config/set', 600,
);
if (occurrences(frontend, '._sendConfigCandidate(candidate)').length !== 2) {
errors.push('frontend canonical config transport callers changed');
}
const positionWrites = occurrences(frontend, "type: 'houseplan/layout/update'");
if (positionWrites.length !== 3) errors.push(`frontend position writer inventory: ${positionWrites.length}`);
for (const [ordinal, index] of positionWrites.entries()) requireWindow(
errors, frontend, index,
/const pos = canonicalizePosition\([^)]+\);[\s\S]*pos(?:[,\s}])/,
`frontend layout/update #${ordinal + 1}`,
);
const localWrites = occurrences(frontend, 'localStorage.setItem(LS_KEY');
if (localWrites.length !== 1) errors.push(`frontend local layout writer inventory: ${localWrites.length}`);
for (const index of localWrites) requireWindow(
errors, frontend, index,
/this\._layout = canonicalizeLayoutGeometry\(this\._layout\);/,
'frontend localStorage layout', 350,
);
const optimizeWrites = occurrences(frontend, "type: 'houseplan/plan/optimize'");
if (optimizeWrites.length !== 1) errors.push(`frontend Optimize writer inventory: ${optimizeWrites.length}`);
for (const index of optimizeWrites) requireWindow(
errors, frontend, index,
/config,[\s\S]*layout,[\s\S]*expected_config_rev: this\._cfgRev/,
'frontend Optimize transaction', 300,
);
const componentRoot = resolve(root, 'custom_components/houseplan');
const pythonFiles = readdirSync(componentRoot)
.filter((name) => name.endsWith('.py'));
for (const name of pythonFiles) {
const source = readFileSync(resolve(componentRoot, name), 'utf8');
if (name === 'store.py') continue;
if (name === 'trails.py') continue; // operational breadcrumb Store, not plan geometry
if (/\b(?:runtime|rt)\.(?:config_store|store)\.async_save\s*\(/.test(source)) {
errors.push(`backend direct plan Store writer: custom_components/houseplan/${name}`);
}
}
const store = readFileSync(resolve(componentRoot, 'store.py'), 'utf8');
if (!/out\["layout"\] = canonicalize_layout_geometry\(layout\)/.test(store)) {
errors.push('backend layout_store_payload bypasses lattice canonicalization');
}
if (!/canonical_config = canonicalize_config_geometry\(config\)/.test(store)) {
errors.push('backend async_save_config_state bypasses lattice canonicalization');
}
if (occurrences(store, 'runtime.store.async_save(').length !== 1
|| occurrences(store, 'runtime.config_store.async_save(').length !== 1) {
errors.push('backend central Store writer inventory changed');
}
return errors;
}
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
const errors = checkCoordinateWriteBarriers();
if (errors.length) {
for (const error of errors) console.error(`coordinate write barrier: ${error}`);
process.exitCode = 1;
} else {
console.log('coordinate write barrier: OK');
}
}