← back to Mfr Review Viewer Corruption
scripts/build-queue.mjs
170 lines
#!/usr/bin/env node
// build-queue.mjs — READ-ONLY loader for the broken "DW# == Mfr SKU" corruption.
// Runs the corruption-signature query against dw_unified.shopify_products,
// classifies each row, prefers the other agent's richer output when present,
// and writes data/queue.jsonl. NEVER writes to dw_unified / FileMaker / Shopify.
import { execFileSync } from 'node:child_process';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');
const DATA_DIR = join(ROOT, 'data');
const OUT = join(DATA_DIR, 'queue.jsonl');
const PSQL = '/opt/homebrew/opt/postgresql@14/bin/psql';
const DB = 'dw_unified';
// The other agent's richer output — consumed as source-of-truth when present.
const PEER_FILE = process.env.PEER_FILE ||
'/Users/macstudio3/Projects/filemaker-mcp/data/mfr-review-queue.jsonl';
if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
// Does shopify_products have a usable created/updated timestamp column?
function detectDateCol() {
const cols = execFileSync(PSQL, [DB, '-Atc',
`SELECT column_name FROM information_schema.columns
WHERE table_name='shopify_products'
AND column_name IN ('created_at','created_at_shopify','updated_at','updated_at_shopify','synced_at')`
], { encoding: 'utf8' }).trim().split('\n').filter(Boolean);
// Prefer a real creation timestamp, then updated, then synced.
for (const c of ['created_at','created_at_shopify','updated_at','updated_at_shopify','synced_at']) {
if (cols.includes(c)) return c;
}
return null;
}
const dateCol = detectDateCol();
console.log(`[build-queue] date column: ${dateCol || 'none'}`);
// Corruption signature: mfr_sku <> '' AND mfr_sku = numeric tail of dw_sku.
// We pull the raw fields + the derived pattern token so classification runs in JS.
//
// SCOPE (Steve 2026-08-27, "only look at active patterns"): DEFAULT to status='ACTIVE'
// only — the ~18k DELETED_FROM_SHOPIFY/ARCHIVED ghosts (and ALL Schumacher rows, which
// are already all deleted/archived) are noise for review. ACTIVE-only = ~2,432 rows.
// Set STATUS_FILTER=all to see every status again.
const STATUS_FILTER = (process.env.STATUS_FILTER || 'ACTIVE').trim().toUpperCase();
const STATUS_CLAUSE = STATUS_FILTER === 'ALL' ? '' : `status='${STATUS_FILTER.replace(/'/g, "''")}'\n AND `;
console.log(`[build-queue] status filter: ${STATUS_FILTER}`);
const SIG = `${STATUS_CLAUSE}mfr_sku IS NOT NULL AND mfr_sku <> ''
AND mfr_sku = (regexp_match(dw_sku,'(\\d+)(-SAMPLE)?$','i'))[1]`;
const selDate = dateCol ? `to_char(${dateCol} AT TIME ZONE 'UTC','YYYY-MM-DD"T"HH24:MI:SS"Z"')` : `NULL`;
// Use a control char (\t) delimiter; fields are simple text so this is safe.
const SQL = `
COPY (
SELECT
dw_sku,
mfr_sku,
COALESCE(vendor,''),
COALESCE(pattern_name,''),
${selDate},
COALESCE((regexp_match(dw_sku, '^[A-Za-z0-9]+?-(.+)$'))[1], '')
FROM shopify_products
WHERE ${SIG}
ORDER BY vendor, dw_sku
) TO STDOUT WITH (FORMAT text, DELIMITER E'\\t', NULL '');
`;
console.log('[build-queue] querying dw_unified (read-only)...');
const raw = execFileSync(PSQL, [DB, '-v', 'ON_ERROR_STOP=1', '-Atc', SQL], {
encoding: 'utf8', maxBuffer: 1024 * 1024 * 256,
});
// Load peer (other agent) output keyed by dw_sku, if it exists.
const peer = new Map();
if (existsSync(PEER_FILE)) {
try {
for (const line of readFileSync(PEER_FILE, 'utf8').split('\n')) {
if (!line.trim()) continue;
const o = JSON.parse(line);
const k = o.dw_sku || o.dwSku || o.sku;
if (k) peer.set(k, o);
}
console.log(`[build-queue] loaded ${peer.size} peer rows from ${PEER_FILE}`);
} catch (e) {
console.warn(`[build-queue] peer file unreadable, ignoring: ${e.message}`);
}
} else {
console.log(`[build-queue] no peer file at ${PEER_FILE} (using computed guesses)`);
}
function classify(dw_sku, bad_mfr, vendor, patternToken) {
const token = (patternToken || '').replace(/-SAMPLE$/i, '');
// LIKELY-LEGIT: Schumacher family — DW# IS their real mfr.
if (/schumacher/i.test(vendor)) {
return { best_guess_real_mfr: bad_mfr, source: 'likely-legit-numeric',
confidence: 'exclude', tier: 'LIKELY-LEGIT' };
}
// TIER-4: corrupt SKU — no proper alpha series prefix, or a huge bare number.
const noAlphaPrefix = !/^[A-Za-z]{2,}-/.test(dw_sku);
const hugeNumber = /^[0-9]{13,}$/.test(dw_sku);
const leadingDash = /^-/.test(dw_sku);
if (leadingDash || hugeNumber || noAlphaPrefix) {
return { best_guess_real_mfr: '', source: 'bad-sku',
confidence: 'n/a', tier: 'TIER-4' };
}
// TIER-2: alpha-prefix recovery. Token is ALPHA+digits, and stripping the
// leading alpha equals bad_mfr → the token IS the real mfr code.
if (/^[A-Za-z]+[0-9]+$/.test(token)) {
const digitTail = token.replace(/^[A-Za-z]+/, '');
if (digitTail === bad_mfr) {
return { best_guess_real_mfr: token, source: 'dwsku-alpha-prefix',
confidence: 'high', tier: 'TIER-2' };
}
}
// TIER-3: real mfr not recoverable from dw_unified — needs review queue.
return { best_guess_real_mfr: '', source: 'none',
confidence: 'needs-review', tier: 'TIER-3' };
}
const lines = raw.split('\n').filter((l) => l.length);
const out = [];
let peerUsed = 0;
for (const line of lines) {
const [dw_sku, bad_mfr, vendor, pattern_name, created_at, patternToken] =
line.split('\t');
const c = classify(dw_sku, bad_mfr, vendor, patternToken);
const rec = {
dw_sku,
bad_mfr,
vendor: vendor || '',
pattern_name: pattern_name || '',
created_at: created_at || null,
best_guess_real_mfr: c.best_guess_real_mfr,
source: c.source,
confidence: c.confidence,
tier: c.tier,
};
// Prefer the peer's richer best_guess/source when it covers this dw_sku.
const p = peer.get(dw_sku);
if (p && (p.best_guess_real_mfr || p.best_guess || p.real_mfr)) {
rec.best_guess_real_mfr = p.best_guess_real_mfr || p.best_guess || p.real_mfr;
rec.source = p.source || rec.source;
if (p.confidence) rec.confidence = p.confidence;
if (p.tier) rec.tier = p.tier;
rec.peer = true;
peerUsed++;
}
out.push(JSON.stringify(rec));
}
writeFileSync(OUT, out.join('\n') + (out.length ? '\n' : ''));
// Per-tier tally for the report.
const tally = {};
for (const l of out) { const t = JSON.parse(l).tier; tally[t] = (tally[t]||0)+1; }
console.log(`[build-queue] wrote ${out.length} rows -> ${OUT}`);
console.log(`[build-queue] peer overrides applied: ${peerUsed}`);
console.log(`[build-queue] tiers:`, JSON.stringify(tally));