← back to Dw Yolo Loop
Banned-word body-leak scanner: exact cleanup list + strip preview (68 live)
4d885e1482773d3cbeb622eb3f91307322b8116a · 2026-06-16 02:53:54 -0700 · Steve Abrams
Pulled live descriptionHtml for the 68 audit-flagged products: 65 are markdown
code-fence leaks (```html ... ``` wrapping the body), 3 AI preamble. Deterministic
strip transform previewed (remove fences + leading/trailing AI lines) → valid HTML.
Kravet 53 / Scalamandre 8 / Versace 3 / Graduate UK 2 / JS 1 / Thibaut 1. READ-ONLY,
$0. Apply gated via shopify_api_queue {id,body_html}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
A scripts/bannedword-body-leak/bannedword-body-leak.mjs
Diff
commit 4d885e1482773d3cbeb622eb3f91307322b8116a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 02:53:54 2026 -0700
Banned-word body-leak scanner: exact cleanup list + strip preview (68 live)
Pulled live descriptionHtml for the 68 audit-flagged products: 65 are markdown
code-fence leaks (```html ... ``` wrapping the body), 3 AI preamble. Deterministic
strip transform previewed (remove fences + leading/trailing AI lines) → valid HTML.
Kravet 53 / Scalamandre 8 / Versace 3 / Graduate UK 2 / JS 1 / Thibaut 1. READ-ONLY,
$0. Apply gated via shopify_api_queue {id,body_html}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
.../bannedword-body-leak/bannedword-body-leak.mjs | 85 ++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/scripts/bannedword-body-leak/bannedword-body-leak.mjs b/scripts/bannedword-body-leak/bannedword-body-leak.mjs
new file mode 100644
index 0000000..d6f2d26
--- /dev/null
+++ b/scripts/bannedword-body-leak/bannedword-body-leak.mjs
@@ -0,0 +1,85 @@
+// bannedword-body-leak — pull the live body_html for the AI-preamble-leaking
+// products (from the 2026-06-15 banned-word audit), classify the leak, and PREVIEW
+// the strip transform. READ-ONLY (GraphQL GET of descriptionHtml). No writes. $0.
+//
+// Leak classes:
+// md_fence — markdown code fences wrapping the body (```html ... ```)
+// ai_preamble — leading "Sure, here is..." / "Certainly!" / "As an AI..." etc.
+// ai_trailing — trailing "Let me know if...", "I hope this helps"
+// Strip transform (previewed, not applied): drop fences + leading/trailing AI lines.
+import { execFileSync } from 'node:child_process';
+import fs from 'node:fs';
+
+const TOKEN = (fs.readFileSync(`${process.env.HOME}/Projects/secrets-manager/.env`, 'utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m) || [])[1]?.trim();
+const HOST = 'designer-laboratory-sandbox.myshopify.com', API = '2024-10';
+const AUDIT = `${process.env.HOME}/.claude/yolo-queue/banned-word-live-audit-2026-06-15.json`;
+const OUT = `${process.env.HOME}/.claude/yolo-queue/bannedword-body-leak-2026-06-16.json`;
+const MD = `${process.env.HOME}/.claude/yolo-queue/bannedword-body-leak-2026-06-16.md`;
+
+const ids = JSON.parse(fs.readFileSync(AUDIT, 'utf8')).samples.preamble.map(p => `gid://shopify/Product/${p.id}`);
+
+async function gql(query) {
+ const res = await fetch(`https://${HOST}/admin/api/${API}/graphql.json`, {
+ method: 'POST', headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' },
+ body: JSON.stringify({ query }),
+ });
+ return (await res.json()).data;
+}
+
+// strip transform
+const FENCE = /^\s*```(?:html|json|markdown)?\s*$|```/gim;
+const PREAMBLE = /^\s*(?:sure|certainly|absolutely|of course|here(?:'s| is)(?: the| a)?|below is|i'd be happy to|i would be happy to|as an ai|as a language model|i cannot|i can't|i apologize|okay|ok)\b[^.\n]*[.:!]?\s*/i;
+const TRAILING = /\s*(?:let me know if[^.\n]*\.?|i hope this helps[^.\n]*\.?|feel free to[^.\n]*\.?|hope (?:this|that) helps[^.\n]*\.?)\s*$/i;
+
+function classify(body) {
+ const cls = [];
+ if (/```/.test(body)) cls.push('md_fence');
+ if (PREAMBLE.test(body.replace(/<[^>]+>/g, '').trimStart())) cls.push('ai_preamble');
+ if (TRAILING.test(body.replace(/<[^>]+>/g, '').trimEnd())) cls.push('ai_trailing');
+ return cls;
+}
+function strip(body) {
+ let s = body.replace(FENCE, '');
+ // strip leading preamble from the visible text (after any opening tag)
+ s = s.replace(/^(\s*(?:<p>|<div>|<span>)?\s*)/i, (m) => m).replace(PREAMBLE, '');
+ s = s.replace(TRAILING, '');
+ return s.trim();
+}
+
+(async () => {
+ const out = [];
+ for (let i = 0; i < ids.length; i += 40) {
+ const chunk = ids.slice(i, i + 40);
+ const d = await gql(`{ nodes(ids: [${chunk.map(x => `"${x}"`).join(',')}]) { ... on Product { id title vendor descriptionHtml } } }`);
+ for (const n of (d?.nodes || [])) {
+ if (!n) continue;
+ const body = n.descriptionHtml || '';
+ const cls = classify(body);
+ const after = strip(body);
+ out.push({ id: n.id.split('/').pop(), vendor: n.vendor, title: n.title, classes: cls,
+ before_len: body.length, after_len: after.length, removed_chars: body.length - after.length,
+ before_head: body.slice(0, 160), after_head: after.slice(0, 160) });
+ }
+ }
+ const byClass = out.reduce((m, r) => { for (const c of (r.classes.length ? r.classes : ['none'])) m[c] = (m[c]||0)+1; return m; }, {});
+ const byVendor = out.reduce((m, r) => (m[r.vendor] = (m[r.vendor]||0)+1, m), {});
+ const report = { generated_at: new Date().toISOString(), source: 'live Shopify descriptionHtml (READ-ONLY)', total: out.length, by_class: byClass, by_vendor: byVendor, products: out };
+ fs.writeFileSync(OUT, JSON.stringify(report, null, 2));
+
+ let md = `# Banned-word body-leak (AI preamble) — live cleanup list + strip preview\n\n`;
+ md += `**$0, READ-ONLY** (pulled live descriptionHtml for the ${out.length} flagged products). No writes.\n\n`;
+ md += `## Leak classes\n${Object.entries(byClass).map(([k,v])=>`- **${k}**: ${v}`).join('\n')}\n\n`;
+ md += `## By vendor\n${Object.entries(byVendor).sort((a,b)=>b[1]-a[1]).map(([k,v])=>`- ${k}: ${v}`).join('\n')}\n\n`;
+ md += `## Strip transform (previewed, GATED to apply)\n`;
+ md += `1. remove markdown code fences (\\\`\\\`\\\`html … \\\`\\\`\\\`)\n2. strip leading AI preamble ("Sure, here is…", "Certainly!", "As an AI…")\n3. strip trailing AI notes ("Let me know if…", "I hope this helps")\n\n`;
+ md += `## Before → after (sample)\n`;
+ for (const r of out.filter(r => r.classes.length).slice(0, 15)) {
+ md += `\n**${r.vendor} · ${r.title}** (id ${r.id}, classes: ${r.classes.join(',')}, −${r.removed_chars} chars)\n`;
+ md += `- before: \`${r.before_head.replace(/\n/g,' ')}\`\n`;
+ md += `- after: \`${r.after_head.replace(/\n/g,' ')}\`\n`;
+ }
+ md += `\n_Full list + per-product before/after in the JSON. Apply via shopify_api_queue {id, body_html:<stripped>} — GATED, Steve approves._\n`;
+ fs.writeFileSync(MD, md);
+ console.log(`[body-leak] ${out.length} products | classes: ${JSON.stringify(byClass)}`);
+ console.log(`Report: ${MD}`);
+})().catch(e => { console.error('FATAL', e.message); process.exit(1); });
← 75f9a55 Banned-word 'Wallpaper' title rewrite PREVIEW (report-only,
·
back to Dw Yolo Loop
·
Canary board: aggregate all DW canaries into one red/green h a8d1589 →