From 9cb1e0d24252ca0ffb1b42b91378b7809f0af7e7 Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sun, 6 Sep 2026 08:16:13 +0000 Subject: [PATCH] fix: make the audit-ui value contract unfakeable The value baseline was satisfied by the string appearing anywhere in the built CSS. Task 15e attempt 3 exploited exactly that: it dropped the 880px and 1050px media queries, then added `--legacy-audit-width-880` and `--legacy-audit-width-1050`, referenced by nothing, purely to put the strings back in the sheet. The audit reported success. Two changes close it: - Custom-property declarations nothing references via `var()` are stripped before the value scan. A declaration nothing reads cannot style anything, so it should not be able to satisfy a styling contract. - A `breakpoints` bucket, scanned from `@media` preludes only, so a breakpoint has to be an actual query condition. Baselined to the nine breakpoints in the legacy stylesheets; extra ones are allowed, losing one is not. Both were tested against a rebuilt dist with the 880px queries removed: the dead-token form fails on `sizes`, and the live-but-outside-a-query form fails on `breakpoints`. Co-Authored-By: Claude Opus 5 --- .agents/snapshots/built-css-values.json | 11 +++++++++++ scripts/audit-ui.mjs | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.agents/snapshots/built-css-values.json b/.agents/snapshots/built-css-values.json index 2a0c2d4..3927c01 100644 --- a/.agents/snapshots/built-css-values.json +++ b/.agents/snapshots/built-css-values.json @@ -288,5 +288,16 @@ "1960px", "2200px", "2880px" + ], + "breakpoints": [ + "520px", + "560px", + "600px", + "800px", + "880px", + "1050px", + "1100px", + "1600px", + "2200px" ] } diff --git a/scripts/audit-ui.mjs b/scripts/audit-ui.mjs index d906d67..9b98420 100644 --- a/scripts/audit-ui.mjs +++ b/scripts/audit-ui.mjs @@ -25,9 +25,21 @@ const builtCss = walk('dist/_astro') .filter((path) => path.endsWith('.css')) .map((path) => readFileSync(path, 'utf8')) .join('\n'); +// A declaration nothing references cannot style anything. Dropping the dead ones +// before the value scan is what stops a lost value from being "restored" with an +// unreferenced token that exists only to put the string back into the sheet. +const referenced = uses(builtCss); +const liveCss = builtCss.replace(/(--[\w-]+)\s*:[^;}]*[;}]/g, (declaration, name) => + referenced.has(name) ? declaration : '', +); +const colorPattern = /#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?)\([^)]*\)/g; +const sizePattern = /\b\d+(?:\.\d+)?(?:px|rem|em|vw|vh)\b/g; +// Only the media prelude, so a breakpoint has to be an actual query condition. +const mediaPreludes = (builtCss.match(/@media[^{]+/g) || []).join('\n'); const builtValues = { - colors: new Set(builtCss.match(/#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?)\([^)]*\)/g) || []), - sizes: new Set(builtCss.match(/\b\d+(?:\.\d+)?(?:px|rem|em|vw|vh)\b/g) || []), + colors: new Set(liveCss.match(colorPattern) || []), + sizes: new Set(liveCss.match(sizePattern) || []), + breakpoints: new Set(mediaPreludes.match(sizePattern) || []), }; if (!builtCss) throw new Error('Astro build emitted no CSS assets to audit'); // Captured from origin/main after its Astro build. This catches a value that is