[object Object]

← back to Designerwallcoverings

fix remove-194-collisions: metafieldDelete->REST delete by id (2024-10 has no metafieldDelete mutation); remove ALL matching namespaces (custom+global), not just first

b0f1d98adbb484cceceefd3d9034c2e3beb05d4e · 2026-09-03 10:04:06 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ddgxmase3XCnLRxVyaE1LD

Files touched

Diff

commit b0f1d98adbb484cceceefd3d9034c2e3beb05d4e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 3 10:04:06 2026 -0700

    fix remove-194-collisions: metafieldDelete->REST delete by id (2024-10 has no metafieldDelete mutation); remove ALL matching namespaces (custom+global), not just first
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ddgxmase3XCnLRxVyaE1LD
---
 scripts/pj-mfr-backfill/remove-194-collisions.mjs | 30 ++++++++++++++---------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/scripts/pj-mfr-backfill/remove-194-collisions.mjs b/scripts/pj-mfr-backfill/remove-194-collisions.mjs
index ff3a22e..3cdd600 100644
--- a/scripts/pj-mfr-backfill/remove-194-collisions.mjs
+++ b/scripts/pj-mfr-backfill/remove-194-collisions.mjs
@@ -51,13 +51,19 @@ async function gql(q, v) {
   });
   const j = await r.json(); if (j.errors) throw new Error(JSON.stringify(j.errors)); return j.data;
 }
-async function liveMfr(pid) {
+async function liveMfrs(pid) {
   const r = await fetch(`https://${STORE}/admin/api/${API}/products/${pid}/metafields.json`, { headers: { 'X-Shopify-Access-Token': TOKEN } });
   const d = await r.json();
-  const m = (d.metafields || []).find(x => x.key && x.key.toLowerCase() === 'manufacturer_sku' && (x.value || '').trim());
-  return m ? { id: m.id, namespace: m.namespace, value: m.value } : null;
+  return (d.metafields || [])
+    .filter(x => x.key && x.key.toLowerCase() === 'manufacturer_sku' && (x.value || '').trim())
+    .map(m => ({ id: m.id, namespace: m.namespace, value: String(m.value) }));
+}
+// Shopify 2024-10 has no `metafieldDelete` mutation; delete by metafield id via REST.
+async function delMeta(pid, id) {
+  const r = await fetch(`https://${STORE}/admin/api/${API}/products/${pid}/metafields/${id}.json`,
+    { method: 'DELETE', headers: { 'X-Shopify-Access-Token': TOKEN } });
+  if (!r.ok) throw new Error(`DELETE metafield ${id} -> HTTP ${r.status} ${await r.text()}`);
 }
-const DEL = `mutation($id:ID!){ metafieldDelete(input:{id:$id}){ deletedId userErrors{message} } }`;
 
 async function main() {
   const recs = parseCsv(fs.readFileSync(CSV, 'utf8'));
@@ -67,13 +73,15 @@ async function main() {
     for (const r of recs.slice(b, b + BATCH)) {
       i++;
       const pid = r.product_numeric_id, expect = String(r.new_manufacturer_sku).trim();
-      const cur = await liveMfr(pid);
-      if (!cur) { skip_absent++; continue; }
-      if (cur.value.trim() !== expect) { skip_mismatch++; console.log(`  SKIP ${r.dw_sku}: live='${cur.value}' != expected '${expect}' (not ours)`); continue; }
-      if (!APPLY) { if (i <= 5) console.log(`  DRY delete ${r.dw_sku} (${pid}) ${cur.namespace}.manufacturer_sku='${cur.value}'`); removed++; continue; }
-      const d = await gql(DEL, { id: cur.id });
-      if (d.metafieldDelete.userErrors.length) throw new Error(JSON.stringify(d.metafieldDelete.userErrors));
-      fs.appendFileSync(LEDGER, JSON.stringify({ ts: new Date().toISOString(), product_id: pid, dw_sku: r.dw_sku, removed_value: cur.value, namespace: cur.namespace }) + '\n');
+      const all = await liveMfrs(pid);
+      const ours = all.filter(m => m.value.trim() === expect);   // only the value WE wrote — any namespace (custom AND global)
+      if (all.length === 0) { skip_absent++; continue; }
+      if (ours.length === 0) { skip_mismatch++; console.log(`  SKIP ${r.dw_sku}: live=[${all.map(m => m.namespace + '=' + m.value).join(',')}] != '${expect}' (not ours)`); continue; }
+      if (!APPLY) { if (i <= 5) console.log(`  DRY delete ${r.dw_sku} (${pid}) ${ours.map(m => m.namespace + '.manufacturer_sku=' + m.value).join(', ')}`); removed++; continue; }
+      for (const m of ours) {
+        await delMeta(pid, m.id);
+        fs.appendFileSync(LEDGER, JSON.stringify({ ts: new Date().toISOString(), product_id: pid, dw_sku: r.dw_sku, removed_value: m.value, namespace: m.namespace, metafield_id: m.id }) + '\n');
+      }
       removed++;
     }
     console.log(`  batch ${b / BATCH + 1}: removed=${removed} skip_mismatch=${skip_mismatch} skip_absent=${skip_absent}`);

← 18eb4cc TK-11131: PJ mfr# — 706/194 collision split + delete-194 cor  ·  back to Designerwallcoverings  ·  auto-data-snapshot: 2026-09-03T10:32:28 (16 data files) — sc 1fa3961 →