← back to Designer Wallcoverings
Carl Robinson increments: add global.Sold-Per/Minimum to full canonical set + committed value-asserting verifier (67/67 pass)
a109ccd51f4c5e08611693724df8ea784eb8c98f · 2026-07-06 14:25:53 -0700 · Steve
Files touched
M scripts/wallquest-refresh/set-increment-carl-robinson.cjsA scripts/wallquest-refresh/verify-increment-carl-robinson.cjs
Diff
commit a109ccd51f4c5e08611693724df8ea784eb8c98f
Author: Steve <steve@designerwallcoverings.com>
Date: Mon Jul 6 14:25:53 2026 -0700
Carl Robinson increments: add global.Sold-Per/Minimum to full canonical set + committed value-asserting verifier (67/67 pass)
---
.../set-increment-carl-robinson.cjs | 3 ++
.../verify-increment-carl-robinson.cjs | 62 ++++++++++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/scripts/wallquest-refresh/set-increment-carl-robinson.cjs b/scripts/wallquest-refresh/set-increment-carl-robinson.cjs
index 5fd81cf8..3aa2be59 100644
--- a/scripts/wallquest-refresh/set-increment-carl-robinson.cjs
+++ b/scripts/wallquest-refresh/set-increment-carl-robinson.cjs
@@ -14,6 +14,9 @@ const MF = [
{ namespace: 'global', key: 'v_prods_quantity_order_units', value: INC, type: 'single_line_text_field' },
{ namespace: 'dwc', key: 'order_unit', value: INC, type: 'single_line_text_field' },
{ namespace: 'global', key: 'unit_of_measure', value: 'Priced Per Yard', type: 'single_line_text_field' },
+ // full canonical set per wallquest-textile-yard-pricing memory + DW CLAUDE.md global-namespace taxonomy
+ { namespace: 'global', key: 'Sold-Per', value: 'Yard', type: 'single_line_text_field' },
+ { namespace: 'global', key: 'Minimum', value: INC, type: 'single_line_text_field' },
];
function shopify(method, path, body) {
return new Promise((res, rej) => { const data = body ? JSON.stringify(body) : null;
diff --git a/scripts/wallquest-refresh/verify-increment-carl-robinson.cjs b/scripts/wallquest-refresh/verify-increment-carl-robinson.cjs
new file mode 100644
index 00000000..ed2a8ff3
--- /dev/null
+++ b/scripts/wallquest-refresh/verify-increment-carl-robinson.cjs
@@ -0,0 +1,62 @@
+// Re-runnable, committed verifier for the Carl Robinson 8-yard-increment enforcement.
+// Does a FRESH GET of each live product's metafields + tags + variants and ASSERTS
+// VALUES (not just key existence) — the exact thing set-increment's swallow-all catch
+// can't prove. Exits NON-ZERO if any product fails, so it's usable as a gate/canary.
+// Env: SHOPIFY_ADMIN_TOKEN. Optional: LIMIT=N to sample.
+const https = require('https');
+const { execSync } = require('child_process');
+const TOK = process.env.SHOPIFY_ADMIN_TOKEN;
+const DOMAIN = 'designer-laboratory-sandbox.myshopify.com';
+const INC = process.env.INC || '8';
+const LIMIT = parseInt(process.env.LIMIT || '999', 10);
+if (!TOK) { console.error('no SHOPIFY_ADMIN_TOKEN'); process.exit(2); }
+
+// exact expected values (canonical set per wallquest-textile-yard-pricing memory + DW CLAUDE.md)
+const EXPECT_MF = {
+ 'global.v_prods_quantity_order_min': INC,
+ 'global.v_prods_quantity_order_units': INC,
+ 'dwc.order_unit': INC,
+ 'global.unit_of_measure': 'Priced Per Yard',
+ 'global.Sold-Per': 'Yard',
+ 'global.Minimum': INC,
+ 'global.packaged': 'Packaged in 8 yard bolts only',
+};
+function shopify(path) {
+ return new Promise((res, rej) => {
+ const req = https.request({ hostname: DOMAIN, path: `/admin/api/2024-10/${path}`, method: 'GET',
+ headers: { 'X-Shopify-Access-Token': TOK } },
+ r => { let d = ''; r.on('data', c => d += c); r.on('end', () => { try { res(JSON.parse(d)); } catch (e) { rej(e); } }); });
+ req.on('error', rej); req.end();
+ });
+}
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+(async () => {
+ const rows = execSync(`PGPASSWORD=DW2024SecurePass psql -h 127.0.0.1 -U dw_admin -d dw_unified -tAc "SELECT dw_sku||'|'||shopify_product_id FROM carl_robinson_catalog WHERE on_shopify AND shopify_product_id IS NOT NULL ORDER BY dw_sku"`).toString().trim().split('\n').filter(Boolean).slice(0, LIMIT);
+ console.log(`Verifying ${rows.length} Carl Robinson products (asserting metafield VALUES + tag + per-yard + sample)\n`);
+ let pass = 0; const fails = [];
+ for (const row of rows) {
+ const [sku, pid] = row.split('|');
+ try {
+ const mfRes = await shopify(`products/${pid}/metafields.json`);
+ const have = {}; (mfRes.metafields || []).forEach(m => { have[`${m.namespace}.${m.key}`] = String(m.value); });
+ const missing = Object.entries(EXPECT_MF).filter(([k, v]) => have[k] !== String(v)).map(([k, v]) => `${k}!=${v} (got ${have[k] ?? 'MISSING'})`);
+ const prod = (await shopify(`products/${pid}.json?fields=tags,variants`)).product;
+ const tag = (prod.tags || '').split(',').map(s => s.trim()).includes('display_variant');
+ const std = prod.variants.find(v => !/-Sample$/i.test(v.sku));
+ const smp = prod.variants.find(v => /-Sample$/i.test(v.sku));
+ const yard = std && /yard/i.test(std.option1 || '');
+ const samp = smp && parseFloat(smp.price) === 4.25;
+ const issues = [...missing];
+ if (!tag) issues.push('display_variant tag MISSING');
+ if (!yard) issues.push(`variant option not per-yard (${std && std.option1})`);
+ if (!samp) issues.push(`sample not $4.25 (${smp && smp.price})`);
+ if (issues.length) fails.push(`${sku} (${pid}): ${issues.join('; ')}`);
+ else pass++;
+ } catch (e) { fails.push(`${sku} (${pid}): ERROR ${e.message}`); }
+ await sleep(90);
+ }
+ console.log(`PASS ${pass}/${rows.length}`);
+ if (fails.length) { console.error(`\nFAILURES (${fails.length}):`); fails.forEach(f => console.error(' ❌ ' + f)); process.exit(1); }
+ console.log('✅ ALL VERIFIED — every product has the full canonical increment set, tag, per-yard price, and $4.25 sample.');
+})().catch(e => { console.error('FATAL', e.message); process.exit(2); });
← 21c4a09b DWTT double-roll PHASE 2 live: 3105 metafields, 0 errors (ca
·
back to Designer Wallcoverings
·
Kravet-under-PR re-vendor tool (dry-run default; --apply/--a 080ee652 →