/** * Anti-slop linter for generated HTML artifacts. * * Runs grep-style checks against an artifact body and returns a list of * structured findings. P0 findings indicate the artifact is regressing * to AI-slop tropes (purple gradients, emoji feature icons, sans-serif * display, invented metrics, lorem-style filler) and are surfaced back * to the agent as a system message so it can self-correct on the next * turn. P1/P2 findings are advisories. * * The linter is deliberately greppy: cheap, deterministic, and trivial * to extend. It does NOT parse HTML — false positives are tolerable * because each finding includes a snippet so the agent can verify. * * Wired into the artifact save flow (POST /api/artifacts/save) and * exposed standalone at POST /api/artifacts/lint for the chat UI to * surface badges next to each saved artifact. */ /** * @typedef {Object} LintFinding * @property {'P0'|'P1'|'P2'} severity * @property {string} id short stable id (e.g. 'purple-gradient') * @property {string} message one-line explanation * @property {string} fix one-line corrective suggestion (for the agent) * @property {string} [snippet] matched text (≤ 200 chars), if any */ const PURPLE_HEXES = [ '#a855f7', '#9333ea', '#7c3aed', '#6d28d9', '#581c87', '#8b5cf6', '#a78bfa', '#c4b5fd', '#ddd6fe', '#ede9fe', ]; const SLOP_EMOJI = [ '✨', '🚀', '🎯', '⚡', '🔥', '💡', '📈', '🎨', '🛡️', '🌟', '💪', '🎉', '👋', '🙌', '✅', '⭐', '🏆', ]; // Simple sentinel words for invented-metric copy. Catching every claim is // hopeless; we look for the canonical AI-startup phrasings. const INVENTED_METRIC_PATTERNS = [ /\b10×\s+(faster|better|easier)\b/i, /\b100×\s+(faster|better)\b/i, /\b99\.\d+%\s+uptime\b/i, /\bzero[- ]downtime\b/i, /\b3×\s+more\s+(productive|efficient)\b/i, ]; const FILLER_PATTERNS = [ /\bfeature\s+(one|two|three|1|2|3)\b/i, /\blorem\s+ipsum\b/i, /\bdolor\s+sit\s+amet\b/i, /\bplaceholder\s+text\b/i, /\bsample\s+content\b/i, ]; // Display-face check: an h1 / h2 / h3 element whose `font-family` lands on // Inter / Roboto / Arial / -apple-system without an actual serif before it. // We check the `