[object Object]

← back to Hollywood Import

real_vendor = Momentum not the Hollywood brand — fixed creator + backfill + corrective pass over 366 live DWHD products

ddd2da08407a83811d1f7f641449935f1120e817 · 2026-07-15 14:37:24 -0700 · Steve Abrams

Files touched

Diff

commit ddd2da08407a83811d1f7f641449935f1120e817
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 15 14:37:24 2026 -0700

    real_vendor = Momentum not the Hollywood brand — fixed creator + backfill + corrective pass over 366 live DWHD products
---
 backfill-specs.mjs   |  8 ++++++--
 fix-real-vendor.mjs  | 44 ++++++++++++++++++++++++++++++++++++++++++++
 hollywood-create.mjs |  5 ++++-
 3 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/backfill-specs.mjs b/backfill-specs.mjs
index 2c628b3..60836d8 100644
--- a/backfill-specs.mjs
+++ b/backfill-specs.mjs
@@ -56,7 +56,10 @@ function buildMetafields(it) {
   add('custom', 'supplier_name', 'Hollywood Wallcoverings');
   add('custom', 'manufacturer_sku', it.momentum_sku);
   add('custom', 'material', it.content, ml);
-  add('dwc', 'real_vendor', 'Hollywood Wallcoverings');
+  // real_vendor = the TRUE upstream vendor (internal purchasing field, never theme-rendered).
+  // Hollywood Wallcoverings is the BRAND, not the vendor — Steve 2026-07-15. Pushed directly
+  // because scrub() would erase "Momentum".
+  mf.push({ namespace: 'dwc', key: 'real_vendor', type: sl, value: 'Momentum' });
   add('dwc', 'manufacturer_sku', it.momentum_sku);
   return mf;
 }
@@ -110,7 +113,8 @@ for (const it of todo) {
   const pid = pidOf(it);
   const mf = buildMetafields(it);
   const body = buildBody(it);
-  const leak = LEAK.test(mf.map(m => m.value).join(' ') + ' ' + body);
+  // dwc.real_vendor legitimately holds the upstream vendor name — exempt from the leak gate
+  const leak = LEAK.test(mf.filter(m => !(m.namespace === 'dwc' && m.key === 'real_vendor')).map(m => m.value).join(' ') + ' ' + body);
   if (!APPLY) {
     console.log(`\n${it.base_sku}  ${it.handle}  ${leak ? '⚠LEAK' : 'clean'}  mf=${mf.length}`);
     for (const m of mf) console.log(`  ${m.namespace}.${m.key} = ${m.value.slice(0, 70)}`);
diff --git a/fix-real-vendor.mjs b/fix-real-vendor.mjs
new file mode 100644
index 0000000..bd14347
--- /dev/null
+++ b/fix-real-vendor.mjs
@@ -0,0 +1,44 @@
+// fix-real-vendor.mjs — corrective pass over the 366 DWHD products written by
+// backfill-specs.mjs on 2026-07-15: dwc.real_vendor was set to the BRAND
+// ("Hollywood Wallcoverings"); the field's contract is the TRUE upstream vendor,
+// which for the DWHD/momentum_colorways line is Momentum (Steve 2026-07-15).
+// Scope is ONLY the backfill-targets.json pids — legacy X**-prefix Hollywood
+// products have mixed/unknown upstream sources and are untouched.
+// Batched 25 owners per metafieldsSet call. $0 — Admin API only.
+import fs from 'node:fs';
+
+const env = fs.readFileSync('/Users/macstudio3/Projects/secrets-manager/.env', 'utf8');
+const STORE = (env.match(/^SHOPIFY_STORE=(.+)$/m) || [])[1].trim();
+const TOKEN = (env.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m) || [])[1].trim();
+const GQL = `https://${STORE}/admin/api/2024-10/graphql.json`;
+const H = { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' };
+const APPLY = process.argv.includes('--apply');
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+const M_SET = `mutation($mf:[MetafieldsSetInput!]!){metafieldsSet(metafields:$mf){userErrors{field message}}}`;
+const items = JSON.parse(fs.readFileSync(new URL('backfill-targets.json', import.meta.url).pathname, 'utf8'));
+const pids = [...new Set(items.map(it => Number(String(it.shopify_id).match(/\d+$/)[0])))];
+console.log(`fix-real-vendor: ${pids.length} products → dwc.real_vendor = "Momentum" · ${APPLY ? 'APPLY' : 'DRY-RUN'}`);
+if (!APPLY) { console.log('sample pids:', pids.slice(0, 5).join(', ')); process.exit(0); }
+
+let done = 0, err = 0;
+for (let i = 0; i < pids.length; i += 25) {
+  const batch = pids.slice(i, i + 25).map(pid => ({
+    ownerId: `gid://shopify/Product/${pid}`,
+    namespace: 'dwc', key: 'real_vendor',
+    type: 'single_line_text_field', value: 'Momentum',
+  }));
+  try {
+    const r = await fetch(GQL, { method: 'POST', headers: H, body: JSON.stringify({ query: M_SET, variables: { mf: batch } }) });
+    const j = await r.json();
+    if (j.errors) throw new Error(JSON.stringify(j.errors).slice(0, 200));
+    const ue = j.data.metafieldsSet.userErrors;
+    if (ue.length) { console.error(`  batch@${i} userErrors: ${JSON.stringify(ue).slice(0, 200)}`); err += ue.length; }
+    done += batch.length - ue.length;
+    console.log(`  … ${Math.min(i + 25, pids.length)}/${pids.length}`);
+    await sleep(800);
+  } catch (e) {
+    console.error(`  batch@${i} ERR: ${e.message.slice(0, 160)}`); err += batch.length; await sleep(1500);
+  }
+}
+console.log(`DONE: set=${done} err=${err}`);
diff --git a/hollywood-create.mjs b/hollywood-create.mjs
index 715f54b..94943e2 100644
--- a/hollywood-create.mjs
+++ b/hollywood-create.mjs
@@ -59,7 +59,10 @@ function payload(it) {
   mf('custom', 'supplier_name', 'Hollywood Wallcoverings');
   mf('custom', 'manufacturer_sku', it.mfr_sku);
   mf('custom', 'material', it.content, ml);
-  mf('dwc', 'real_vendor', 'Hollywood Wallcoverings');
+  // real_vendor = the TRUE upstream vendor (internal purchasing field, never theme-rendered).
+  // Hollywood Wallcoverings is the BRAND, not the vendor — Steve 2026-07-15. Pushed directly
+  // because scrub() would erase "Momentum".
+  metafields.push({ namespace: 'dwc', key: 'real_vendor', type: sl, value: 'Momentum' });
   mf('dwc', 'manufacturer_sku', it.mfr_sku);
   return { product: {
     title, vendor: 'Hollywood Wallcoverings', product_type: it.product_type || 'Wallcovering', status: 'draft',

← 771ade4 backfill: newline-flatten single-line metafield values; 366/  ·  back to Hollywood Import  ·  legacy real_vendor mapping proposal: 4,256 products mapped p b929935 →