← back to Dw Activation Debug TK11314

lib/readiness-repairs.js

52 lines

'use strict';
function repairType(reason) {
  if (/missing spec.*width/.test(reason)) return 'restore-width-metafield';
  if (/mfr-sku/.test(reason)) return 'verify-manufacturer-code';
  if (/description/.test(reason)) return 'repair-description';
  if (/sample.variant/.test(reason)) return 'restore-sample-variant';
  if (/price|sellable/.test(reason)) return 'verify-sellable-price';
  if (/no product image/.test(reason)) return 'restore-product-image';
  if (/private-label-leak/.test(reason)) return 'correct-private-label';
  if (/banned word/.test(reason)) return 'correct-title';
  return 'review-readiness';
}
function buildRepairReport(decisions, { generatedAt = new Date().toISOString(), complete = true } = {}) {
  const latest = new Map();
  for (const row of decisions) {
    if (!row.shopify_id) continue;
    const previous = latest.get(row.shopify_id);
    if (!previous || String(row.ts) >= String(previous.ts)) latest.set(row.shopify_id, row);
  }
  const items = [];
  const counts = {};
  for (const row of latest.values()) {
    if (!['skip-gate', 'skip-read-error', 'activate-error', 'settlement-hold', 'settlement-block'].includes(row.action)) continue;
    const groups = new Map();
    for (const reason of row.reasons || []) {
      const type = repairType(reason);
      if (!groups.has(type)) groups.set(type, []);
      groups.get(type).push(reason);
    }
    if (row.action === 'settlement-hold') groups.set('retry-image-review', [row.settlement?.reason || 'unknown']);
    if (row.action === 'settlement-block') groups.set('settlement-block-review', [row.settlement?.reason || 'unknown']);
    if (row.action === 'activate-error') groups.set('verify-activation-result', ['Shopify did not confirm ACTIVE']);
    for (const [type, reasons] of groups) {
      counts[type] = (counts[type] || 0) + 1;
      items.push({ id: `${row.shopify_id}:${type}`, shopify_id: row.shopify_id,
        dw_sku: row.dw_sku, vendor: row.vendor, title: row.title,
        observed_at: row.ts, created_at: row.ts, type, reasons: [...new Set(reasons)],
        source: 'rotation-live-check', width_source: row.width_source || null,
        diagnostics: row.settlement?.diagnostics || null,
        requires: type === 'retry-image-review' ? 'provider-recovery-and-fresh-review' : 'verified-source-and-live-recheck',
        apply_authorized: false,
      });
    }
  }
  return { schema_version: 1, generated_at: generatedAt, scan_complete: complete,
    scope: 'Products observed in this activation run; not the entire draft catalog',
    mode: 'review-only', products_observed: latest.size,
    products_needing_attention: new Set(items.map(item => item.shopify_id)).size,
    counts, items };
}
module.exports = { buildRepairReport, repairType };