← back to Tk10630 Sku Suffix Canary
verify-mfr-exact.mjs
55 lines
// AIRTIGHT mfr verification: dedup by product ID (Map) so flaky/duplicate pages
// can't inflate or miss. Terminates on hasNextPage=false OR dedup-stall (N pages
// with no new unique IDs). Exact unique active count. READ-ONLY.
import { gql } from './shopify.mjs';
import { FABRICATED } from './lib.mjs';
import { writeFileSync } from 'node:fs';
const PAGE = `query($c:String){
products(first:50, query:"vendor:\\"Hollywood Wallcoverings\\"", after:$c){
pageInfo{ hasNextPage endCursor }
nodes{ id status
g:metafield(namespace:"global",key:"dw_sku"){value}
d:metafield(namespace:"dwc",key:"dw_sku"){value}
c:metafield(namespace:"custom",key:"dw_sku"){value}
mfr:metafield(namespace:"custom",key:"manufacturer_sku"){value}
dmfr:metafield(namespace:"dwc",key:"manufacturer_sku"){value}
handle title
variants(first:6){ nodes{ sku } }
}
}
}`;
const sleep = ms => new Promise(r => setTimeout(r, ms));
const realCode = s => !!s && /^[A-Z]{2,6}-?\d/i.test(s) && !FABRICATED.test(s);
const realMfr = s => { if (!s) return false; const t = s.trim(); if (t.split(/\s+/).length >= 3) return false; return /\d/.test(t) && !FABRICATED.test(t); };
const seen = new Map(); // id -> product (dedup)
let cursor = null, stall = 0, pages = 0;
while (true) {
let res;
for (let a = 0; ; a++) { try { res = await gql(PAGE, { cursor }); break; } catch (e) { if (/THROTTLED/i.test(e.message) && a < 8) { await sleep(2000 * (a + 1)); continue; } throw e; } }
const before = seen.size;
for (const p of res.data.products.nodes) if (!seen.has(p.id)) seen.set(p.id, p);
pages++;
const added = seen.size - before;
if (added === 0) { if (++stall >= 5) { process.stderr.write(`dedup-stall after ${pages} pages\n`); break; } }
else stall = 0;
if (pages % 10 === 0) process.stderr.write(` page ${pages}: ${seen.size} unique products\n`);
if (!res.data.products.pageInfo.hasNextPage) break;
cursor = res.data.products.pageInfo.endCursor;
if (pages > 400) break; // hard cap
}
let active = 0, ok = 0;
const missing = [];
for (const p of seen.values()) {
if (p.status !== 'ACTIVE') continue;
active++;
const codes = [p.g?.value, p.d?.value, p.c?.value, ...p.variants.nodes.map(v => (v.sku || '').replace(/-(sample|yard|roll)$/i, ''))];
if (codes.some(realCode) || realMfr(p.mfr?.value) || realMfr(p.dmfr?.value)) ok++;
else missing.push({ handle: p.handle, title: p.title, mfr: p.mfr?.value || p.dmfr?.value });
}
writeFileSync('mfr-missing-exact.json', JSON.stringify(missing, null, 2));
console.log(JSON.stringify({ unique_products_total: seen.size, unique_active: active, active_with_real_mfr: ok, active_NO_real_mfr: missing.length }, null, 2));
if (missing.length) console.log('missing:', missing.slice(0, 10).map(m => `${m.handle}[${m.mfr}]`).join(' '));