← back to Dw Unbuyable Recovery Pilot

pilot.mjs

106 lines

#!/usr/bin/env node
// TK-10875 — BOUNDED RECOVERY PILOT (DRY-RUN ONLY), Wolf Gordon cohort.
//
// EMPIRICALLY-CORRECTED (verified against LIVE Shopify, 2026-08-30):
// The 224 cost-joined WG "unbuyable" products are NOT sample-only, and NOT
// already-sellable. Each has a SINGLE variant with option1='Sample' priced at
// the ROLL RETAIL (e.g. $54.75, $343.80) — not the $4.25 memo price. This is the
// "RR-defect" class already repaired for Ronald Redding + Cole & Son under
// TK-10875-130: a lone Sample-labeled variant mispriced at roll retail, with no
// real $4.25 sample and no clean "Sold Per Roll" variant.
//
// The dw_unified MIRROR cannot detect this: it carries no `option1`, and its
// price is stale (dead sync job — one product read $180.90 in the mirror vs
// $343.80 live). So this plan is ADVISORY: a real executor MUST read each
// product live and recompute retail from STAGING trade cost (not the mirror).
//
// Recovery action (GATED — NOT executed here): for each product,
//   - relabel the lone variant option1 'Sample' -> 'Sold Per Roll',
//     price = trade_cost/0.65/0.85 (DW markup), SKU = numeric DW-SKU (no mint);
//   - add a real Sample variant at $4.25 (SKU <dwsku>-Sample).
// This is the exact reversible, rollback-mapped, ledgered pattern from
// TK-10875-130 (dw-add-sellable-variant / dw-data-repair rollback-all.mjs).

import { writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { queryRows } from './lib/db.mjs';

const HERE = dirname(fileURLToPath(import.meta.url));
const COHORT = 'Wolf Gordon';
const SAMPLE_PRICE = 4.25;

const rows = queryRows(`
  SELECT
    wg.shopify_id,                          -- REAL Shopify product id (gid://…)
    wg.id                                   AS mirror_row_id,
    wg.sku                                  AS dw_numeric_sku,
    wg.mfr_sku,
    wg.title,
    wg.variant_count,
    wg.min_variant_price                    AS mirror_price_STALE,
    c.pattern_name,
    c.price_trade                           AS trade_cost,
    round(c.price_trade/0.65/0.85, 2)       AS computed_roll_retail
  FROM shopify_products wg
  JOIN wolf_gordon_catalog c ON c.dw_sku = wg.sku
  WHERE wg.vendor='${COHORT}'
    AND lower(wg.status)='active'
    AND (wg.has_product_variant IS DISTINCT FROM true)
    AND c.price_trade > 0
  ORDER BY wg.title`);

const plan = rows.map(r => ({
  shopify_id: r.shopify_id,
  title: r.title,
  pattern: r.pattern_name,
  mfr_sku: r.mfr_sku,
  proposed_roll_sku: r.dw_numeric_sku,               // reuse existing numeric DW-SKU (no mint)
  proposed_roll_retail: Number(r.computed_roll_retail), // from STAGING trade cost, not the stale mirror
  proposed_sample_sku: `${r.dw_numeric_sku}-Sample`,
  proposed_sample_price: SAMPLE_PRICE,
  mirror_price_stale: Number(r.mirror_price_STALE ?? 0),
  existing_variant_count: Number(r.variant_count ?? 0),
  action: 'RESTRUCTURE_LONE_SAMPLE_VARIANT', // GATED — customer-facing Shopify write
  live_confirm_required: true,               // executor must GET the live variant first
}));

const singleVariant = plan.filter(p => p.existing_variant_count === 1);

const report = {
  ticket: 'TK-10875',
  cohort: COHORT,
  mode: 'DRY-RUN — no Shopify or dw_unified writes performed',
  generated_at: new Date().toISOString(),
  empirical_verification: 'Live Shopify GET on 4 WG products (price range $54.75–$343.80) — ALL show a single option1=Sample variant priced at roll retail (RR-defect). Mirror lacks option1 and is price-stale (13 days).',
  retail_formula: 'trade_cost / 0.65 / 0.85 (recompute from staging at execution; do NOT trust mirror price)',
  recovery_pattern: 'TK-10875-130 variant-restructure (relabel lone Sample->Sold Per Roll + add $4.25 Sample); reversible via rollback-all.mjs, ledgered',
  gating: 'GATED — customer-facing Shopify variant write. Route to vp-dw-commerce. Draft only; NOT executed here.',
  counts: {
    recoverable_via_restructure: plan.length,
    single_variant_confirmed: singleVariant.length,
  },
  plan,
};

const jsonOut = join(HERE, 'data', 'wolf-gordon-dryrun.json');
const csvOut  = join(HERE, 'data', 'wolf-gordon-dryrun.csv');
writeFileSync(jsonOut, JSON.stringify(report, null, 2));

const cols = ['shopify_id','proposed_roll_sku','mfr_sku','title','pattern','trade_cost','proposed_roll_retail','proposed_sample_price','mirror_price_stale','existing_variant_count','action','live_confirm_required'];
// re-derive trade_cost onto plan rows for the CSV
plan.forEach((p,i)=>{ p.trade_cost = Number(rows[i].trade_cost); });
const esc = v => `"${String(v ?? '').replace(/"/g,'""')}"`;
writeFileSync(csvOut, [cols.join(','), ...plan.map(p => cols.map(c => esc(p[c])).join(','))].join('\n') + '\n');

console.log(`\n================ DRY-RUN — NO WRITES PERFORMED ================`);
console.log(`Cohort: ${COHORT}`);
console.log(`Recoverable via RR-restructure: ${plan.length}  (all single-variant: ${singleVariant.length})`);
console.log(`Verified: live Shopify shows lone option1=Sample @ roll retail (RR-defect).`);
console.log(`Plan written: ${jsonOut}`);
console.log(`             ${csvOut}`);
console.log(`\nGATED next step (drafted, NOT executed): route the ${plan.length}-row plan to`);
console.log(`vp-dw-commerce for a tested, reversible, ledgered variant restructure — executor`);
console.log(`MUST read each product live + recompute retail from staging (mirror price is stale).`);
console.log(`==============================================================\n`);