[object Object]

← back to Flock Fix Viewer

flock quotes-removal batch tool (idempotent, reversible, ledgered) + confirmed all 41 priced flock buyable

682f69a7a4306758e88902c666e2259259e19295 · 2026-09-02 13:12:37 -0700 · Steve

Files touched

Diff

commit 682f69a7a4306758e88902c666e2259259e19295
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Sep 2 13:12:37 2026 -0700

    flock quotes-removal batch tool (idempotent, reversible, ledgered) + confirmed all 41 priced flock buyable
---
 update-flock.mjs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/update-flock.mjs b/update-flock.mjs
new file mode 100644
index 0000000..14a9081
--- /dev/null
+++ b/update-flock.mjs
@@ -0,0 +1,70 @@
+// Remove the wrong `quotes` tag from ALL priced Phillipe Romano flock products.
+// Reversible (re-add tag) + ledgered. Idempotent. Excludes Maharam / non-PR / sample-only(no roll price).
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
+const SHOP = 'designer-laboratory-sandbox.myshopify.com';
+const TOKEN = fs.readFileSync(new URL('./.token', import.meta.url), 'utf8').trim();
+const LEDGER = path.join(os.homedir(), '.claude/yolo-queue/executed-reversible/ledger.jsonl');
+const DRY = process.argv.includes('--dry');
+
+async function gql(query, variables = {}) {
+  const r = await fetch(`https://${SHOP}/admin/api/2024-10/graphql.json`, {
+    method: 'POST',
+    headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' },
+    body: JSON.stringify({ query, variables })
+  });
+  return r.json();
+}
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+const Q = `query($c:String){
+  products(first:100, query:"vendor:'Phillipe Romano' status:active (tag:'Flock Velvet' OR title:flock OR handle:flock)", after:$c){
+    pageInfo{hasNextPage endCursor}
+    edges{node{ id handle title tags variants(first:8){edges{node{title price}}} }}
+  }
+}`;
+
+const UPD = `mutation($id:ID!,$tags:[String!]!){ productUpdate(input:{id:$id, tags:$tags}){ product{id tags} userErrors{field message} } }`;
+
+function isQuoteTag(t){ return String(t).replace(/["{}]/g,'').trim().toLowerCase() === 'quotes'; }
+
+(async () => {
+  let cur = null, all = [];
+  do {
+    const r = await gql(Q, { c: cur });
+    const p = r?.data?.products; if (!p) { console.error('query err', JSON.stringify(r)); break; }
+    all = all.concat(p.edges);
+    cur = p.pageInfo.hasNextPage ? p.pageInfo.endCursor : null;
+  } while (cur);
+
+  const targets = all.map(e => e.node).filter(n => {
+    const hasQuotes = (n.tags || []).some(isQuoteTag);
+    const roll = (n.variants.edges || []).map(v => v.node).filter(v => !/sample/i.test(v.title || ''));
+    const price = roll.reduce((m, v) => Math.max(m, parseFloat(v.price) || 0), 0);
+    return hasQuotes && price > 10;
+  });
+
+  console.log(`Scanned ${all.length} PR flock products · ${targets.length} need quotes-tag removal (priced + quote-tagged)`);
+  if (DRY) { targets.forEach(n => console.log('  would fix', n.handle)); return; }
+
+  let done = 0, failed = 0;
+  for (const n of targets) {
+    const newTags = (n.tags || []).filter(t => !isQuoteTag(t));
+    const r = await gql(UPD, { id: n.id, tags: newTags });
+    const errs = r?.data?.productUpdate?.userErrors;
+    if (errs && errs.length) { failed++; console.log('  FAIL', n.handle, JSON.stringify(errs)); continue; }
+    done++;
+    const sku = ((n.variants.edges[0]||{}).node||{}).title || n.handle;
+    fs.appendFileSync(LEDGER, JSON.stringify({
+      ts: new Date().toISOString(), agent: 'main:flock-update', ticket: 'flock-quotes',
+      action: `remove quotes tag from ${n.handle}`, blast_radius: 1,
+      undo_cmd: `productUpdate ${n.id} tags += quotes`,
+      verify: `GET /products/${n.handle}.json → tags no longer include quotes; price + add-to-cart visible`
+    }) + '\n');
+    if (done % 5 === 0) console.log(`  …${done}/${targets.length}`);
+    await sleep(350); // gentle on rate limit
+  }
+  console.log(`DONE · removed quotes from ${done} · failed ${failed}`);
+})();

← c01bb17 flock-fix live viewer: per-SKU field status board (live Shop  ·  back to Flock Fix Viewer  ·  auto-data-snapshot: 2026-09-02T13:25:17 (1 data files) — pri 73033e4 →