← 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 →