← back to Tk10630 Sku Suffix Canary
revert-backfill.mjs
35 lines
// Revert the 70 mis-backfilled products (bare Momentum number -> leak) back to their
// prior DWHD codes. Restores variant SKUs to plan.varChanges.from + dw_sku metafields to
// the DWHD base. Corrective write for the Option-C-was-wrong ('always pl momentum') error.
import { readFileSync } from 'node:fs';
import { gql } from './shopify.mjs';
const plan = JSON.parse(readFileSync('generator-backfill-plan.json', 'utf8'));
const doneHandles = new Set(readFileSync('done-backfill.jsonl', 'utf8').split('\n').filter(Boolean).map(l => JSON.parse(l).handle));
const work = plan.filter(p => doneHandles.has(p.handle) && !p.COLLISION);
const APPLY = process.argv.includes('--apply');
console.log(`[revert] mode=${APPLY ? 'LIVE' : 'DRY'} to-revert=${work.length}`);
const sleep = ms => new Promise(r => setTimeout(r, ms));
async function q(query, v) { for (let a = 0; ; a++) { try { return (await gql(query, v)).data; } catch (e) { if (/THROTTLED|<html/i.test(e.message) && a < 8) { await sleep(1500 * (a + 1)); continue; } throw e; } } }
const INV = `mutation($id:ID!,$sku:String!){ inventoryItemUpdate(id:$id, input:{sku:$sku}){ userErrors{message} } }`;
const MFS = `mutation($m:[MetafieldsSetInput!]!){ metafieldsSet(metafields:$m){ userErrors{message} } }`;
let ok = 0, err = 0;
for (const p of work) {
// DWHD base from the original variant sku (.from), e.g. DWHD-503061-Sample -> DWHD-503061
const base = (p.varChanges[0]?.from || '').replace(/-(sample|yard|roll)$/i, '');
if (!/^DWH/i.test(base)) { console.log('skip (no DWHD from):', p.handle); continue; }
try {
const d = await q(`query{ productByHandle(handle:"${p.handle}"){ id variants(first:6){ nodes{ sku inventoryItem{ id } } } } }`);
const prod = d.productByHandle; if (!prod) { err++; continue; }
const errs = [];
for (const c of p.varChanges) {
const v = prod.variants.nodes.find(x => x.sku === c.to); // current = the bare-number target
if (!v) continue;
if (APPLY) { const r = await q(INV, { id: v.inventoryItem.id, sku: c.from }); if (r.inventoryItemUpdate.userErrors.length) errs.push(JSON.stringify(r.inventoryItemUpdate.userErrors)); }
}
const m = ['global', 'dwc', 'custom'].map(ns => ({ ownerId: prod.id, namespace: ns, key: 'dw_sku', type: 'single_line_text_field', value: base }));
if (APPLY) { const r = await q(MFS, { m }); if (r.metafieldsSet.userErrors.length) errs.push(JSON.stringify(r.metafieldsSet.userErrors)); }
if (errs.length) { err++; console.log('✗', p.handle, errs.join(';')); } else ok++;
} catch (e) { err++; console.log('✗', p.handle, e.message.slice(0, 80)); }
}
console.log(`[revert] DONE ok=${ok} err=${err} ${APPLY ? '(written back to DWHD)' : '(dry)'}`);