← 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('  '));