← back to Dw Yolo Loop
fence-strip APPLY (c53): 60/60 code-fence leaks stripped (Steve-authorized)
f488a4e3267320041517e32c4bad58f1dc6d8171 · 2026-06-16 22:39:00 -0700 · Steve Abrams
Applied the officer-CONFIRMED fix: 60 ACTIVE products (Kravet 49/Scalamandre 8/
Graduate 2/Thibaut 1) had a leaked leading markdown code-fence in body_html. Per
product: re-fetched fresh, re-ran guards (leading-fence present, unwrap changes it,
non-empty + no banned word), set descriptionHtml=cleaned + seo.description=regen.
60 stripped, 0 skipped, 0 failed. Rollback (60 old bodies) saved to
yolo-queue/fence-strip-ROLLBACK-2026-06-16.json. Verified live: herb-garden +
all-over-leopard now fence-free w/ clean body + seo. $0 (Shopify Admin API).
Files touched
A scripts/fence-strip/fence-strip-apply.mjs
Diff
commit f488a4e3267320041517e32c4bad58f1dc6d8171
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 22:39:00 2026 -0700
fence-strip APPLY (c53): 60/60 code-fence leaks stripped (Steve-authorized)
Applied the officer-CONFIRMED fix: 60 ACTIVE products (Kravet 49/Scalamandre 8/
Graduate 2/Thibaut 1) had a leaked leading markdown code-fence in body_html. Per
product: re-fetched fresh, re-ran guards (leading-fence present, unwrap changes it,
non-empty + no banned word), set descriptionHtml=cleaned + seo.description=regen.
60 stripped, 0 skipped, 0 failed. Rollback (60 old bodies) saved to
yolo-queue/fence-strip-ROLLBACK-2026-06-16.json. Verified live: herb-garden +
all-over-leopard now fence-free w/ clean body + seo. $0 (Shopify Admin API).
---
scripts/fence-strip/fence-strip-apply.mjs | 35 +++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/scripts/fence-strip/fence-strip-apply.mjs b/scripts/fence-strip/fence-strip-apply.mjs
new file mode 100644
index 0000000..24a1841
--- /dev/null
+++ b/scripts/fence-strip/fence-strip-apply.mjs
@@ -0,0 +1,35 @@
+// fence-strip-apply (c53) — APPLY the officer-CONFIRMED code-fence-strip to the 60
+// leading-fence-leak products (Steve-authorized 2026-06-16). Per product: re-fetch
+// fresh body, re-run guards (leading fence present, unwrap changes it, post-strip
+// non-empty + no banned word), SAVE old body to rollback, then
+// productUpdate(descriptionHtml=cleaned, seo.description=regen from cleaned).
+import fs from 'fs';
+const T=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1];
+const API='https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/graphql.json';
+const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function gql(q,v){for(let a=0;a<6;a++){const r=await fetch(API,{method:'POST',headers:{'X-Shopify-Access-Token':T,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v||{}})});if(r.status===429){await sleep(2500);continue;}const j=await r.json();if(j.errors&&JSON.stringify(j.errors).match(/THROTTLED/)){await sleep(2500);continue;}return j;}throw new Error('throttled');}
+function unwrap(b){let body=b;body=body.replace(/^\s*```[a-z]*\s*\n?/i,'');body=body.replace(/\n?\s*```\s*$/,'');body=body.replace(/```[a-z]*\s*([\s\S]*?)\s*```/gi,'$1');body=body.replace(/^\s*<code>([\s\S]*?)<\/code>\s*$/i,'$1');return body.trim();}
+const txt=h=>(h||'').replace(/<[^>]+>/g,'').replace(/&[a-z]+;/g,' ').replace(/\s+/g,' ').trim();
+const work=JSON.parse(fs.readFileSync(process.env.HOME+'/.claude/yolo-queue/fence-strip-dryrun-worklist.json','utf8')).filter(i=>i.changed);
+console.log(`apply targets (changed, leading-fence): ${work.length}`);
+const M=`mutation($id:ID!,$html:String!,$seo:String!){productUpdate(input:{id:$id,descriptionHtml:$html,seo:{description:$seo}}){userErrors{message}}}`;
+const rollback=[]; let ok=0,skip=0,fail=0;
+for(const it of work){
+ try{
+ const j=await gql(`{products(first:1,query:"handle:${it.handle}"){nodes{id descriptionHtml}}}`);
+ const p=j.data?.products?.nodes?.[0]; if(!p){skip++;console.log(` skip(not found): ${it.handle}`);continue;}
+ const old=p.descriptionHtml||'';
+ if(!/^\s*(```|<code>)/i.test(old)){skip++;console.log(` skip(no leading fence now): ${it.handle}`);continue;}
+ const cleaned=unwrap(old);
+ if(cleaned===old || txt(cleaned).length<3){skip++;console.log(` skip(no-op/empty): ${it.handle}`);continue;}
+ if(/\bwallpaper\b/i.test(txt(cleaned))){skip++;console.log(` skip(banned-word surfaced): ${it.handle}`);continue;}
+ const seo=txt(cleaned).slice(0,300);
+ rollback.push({id:p.id,handle:it.handle,old_descriptionHtml:old});
+ const r=await gql(M,{id:p.id,html:cleaned,seo}); const ue=r.data?.productUpdate?.userErrors;
+ if(ue&&ue.length)throw new Error(ue[0].message);
+ ok++; if(ok%15===0)console.log(` ${ok}...`);
+ }catch(e){fail++;console.log(` ✗ ${it.handle}: ${e.message.slice(0,70)}`);}
+ await sleep(300);
+}
+fs.writeFileSync(process.env.HOME+'/.claude/yolo-queue/fence-strip-ROLLBACK-2026-06-16.json',JSON.stringify(rollback,null,2));
+console.log(`\nDONE: ${ok} stripped, ${skip} skipped(guard), ${fail} failed. Rollback saved: ${rollback.length}.`);
← 6c53615 fence-strip dry-run: tighten to leading-fence-only per offic
·
back to Dw Yolo Loop
·
no-image scan (c54): 50 of 74,441 ACTIVE have no image (0.07 b9c390f →