← 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
M backfill-specs.mjsA fix-real-vendor.mjsM hollywood-create.mjs
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 →