← back to Dw Unbuyable Recovery Pilot
tk11041-innovations-reconcile/reconcile.mjs
161 lines
#!/usr/bin/env node
// TK-11041 — feed-first / local SKU reconciliation for the missing Innovations cohort.
//
// READ-ONLY. No Shopify writes. No dw_unified writes. No catalog activation.
// Produces a DETERMINISTIC, dry-run recovery map for the 51 ACTIVE, sample-only
// Phillipe-Romano-private-label Innovations products, proving whether any LOCAL
// (feed-first) recovery path exists before falling back to the gated vendor line-sheet.
//
// Cohort definition (deterministic):
// vendor='Phillipe Romano' AND status='ACTIVE'
// AND NOT has_product_variant (unbuyable: only the $4.25 memo Sample)
// AND supplier_name ~* 'innov'
//
// Recovery-source join keys tested (per the pilot README's proven join model):
// sp.sku = innovations_catalog.dw_sku (numeric DW-SKU form)
// sp.dw_sku = innovations_catalog.dw_sku
// sp.mfr_sku= innovations_catalog.mfr_sku
// + feed-first pattern-token word match against innovations_catalog.pattern_name
//
// Every candidate source is additionally run through lib/provenance.classifyCatalogSource
// so a "match" made of fabricated (no-URL / truncated) catalog data is never counted
// as a real recovery.
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { queryRows } from '../lib/db.mjs';
import { classifyCatalogSource } from './lib/provenance.mjs';
const HERE = path.dirname(fileURLToPath(import.meta.url));
const DATA = path.join(HERE, 'data');
fs.mkdirSync(DATA, { recursive: true });
// ---------------------------------------------------------------------------
// 1) The 51 cohort, with the identity fields + a derived pattern token.
// ---------------------------------------------------------------------------
const cohort = queryRows(`
select
sp.sku,
coalesce(sp.dw_sku,'') as dw_sku,
coalesce(sp.mfr_sku,'') as mfr_sku,
split_part(coalesce(sp.mfr_sku,''),'-',1) as collection,
trim(regexp_replace(
regexp_replace(split_part(sp.title,' | ',1),'( Type ?2| Natural| Vinyl| Memo Sample).*$','','i'),
'^La ','')) as base,
sp.title
from shopify_products sp
where sp.vendor='Phillipe Romano' and sp.status='ACTIVE'
and not coalesce(sp.has_product_variant,false)
and sp.supplier_name ~* 'innov'
order by sp.mfr_sku
`);
const patToken = base => (base || '').split(' ').filter(Boolean)[0] || '';
// ---------------------------------------------------------------------------
// 2) Per-item local-recovery test (all read-only lookups against the catalog).
// ---------------------------------------------------------------------------
const map = cohort.map(r => {
const tok = patToken(r.base);
const bySku = r.sku ? queryRows(
`select mfr_sku, product_url, pattern_name, price_trade from innovations_catalog
where upper(dw_sku)=upper($$${r.sku}$$)`) : [];
const byDwSku = r.dw_sku ? queryRows(
`select mfr_sku, product_url, pattern_name, price_trade from innovations_catalog
where upper(dw_sku)=upper($$${r.dw_sku}$$)`) : [];
const byMfr = r.mfr_sku ? queryRows(
`select mfr_sku, product_url, pattern_name, price_trade from innovations_catalog
where upper(mfr_sku)=upper($$${r.mfr_sku}$$)`) : [];
const byPattern = tok.length >= 4 ? queryRows(
`select mfr_sku, product_url, pattern_name, price_trade from innovations_catalog
where pattern_name ~* ('\\m'||$$${tok}$$||'\\M')`) : [];
const candidates = [...bySku, ...byDwSku, ...byMfr, ...byPattern];
// A candidate only counts as a REAL recovery if it is a trustworthy source
// (has provenance + a non-fabricated code) AND carries a usable net price.
const trustworthy = candidates.filter(c =>
classifyCatalogSource(c).trustworthy && Number(c.price_trade) > 0);
const recoverable = trustworthy.length > 0;
return {
sku: r.sku,
internal_code: r.mfr_sku,
collection: r.collection,
pattern_token: tok,
title: r.title,
join_sku_hits: bySku.length,
join_dwsku_hits: byDwSku.length,
join_mfr_hits: byMfr.length,
pattern_match_hits: byPattern.length,
trustworthy_priced_sources: trustworthy.length,
status: recoverable ? 'RECOVERABLE_LOCAL' : 'BLOCKED_ON_VENDOR_LINESHEET',
recovery_action: recoverable
? 'stage add-yard variant (net_trade/0.65/0.85 per YARD) via proven stage-innov-reprice — GATED (Shopify write)'
: 'no trustworthy local source; match returned Innovations line-sheet on pattern+colorway, then stage add-yard — email send GATED to Steve',
};
});
// ---------------------------------------------------------------------------
// 3) Catalog provenance snapshot (grounds the "no local source" conclusion).
// ---------------------------------------------------------------------------
const catalog = queryRows(`select mfr_sku, product_url, pattern_name from innovations_catalog`);
let noUrl = 0, corrupted = 0, trustworthy = 0;
for (const row of catalog) {
const c = classifyCatalogSource(row);
if (c.reasons.includes('no_provenance_url')) noUrl++;
if (c.reasons.includes('corrupted_lowercase_tail') || c.reasons.includes('code_is_pattern_tail')) corrupted++;
if (c.trustworthy) trustworthy++;
}
// links: which vendor does innovations_catalog actually describe?
const linkage = queryRows(`
select sp.vendor, count(*) n from innovations_catalog ic
join shopify_products sp on sp.shopify_id like '%'||ic.shopify_product_id
where coalesce(ic.shopify_product_id,'')<>'' group by 1 order by 2 desc`);
const summary = {
task: 'TK-11041',
generated_at: new Date().toISOString(),
cohort_size: map.length,
recoverable_local: map.filter(m => m.status === 'RECOVERABLE_LOCAL').length,
blocked_on_vendor: map.filter(m => m.status === 'BLOCKED_ON_VENDOR_LINESHEET').length,
collections: [...new Set(map.map(m => m.collection))].sort(),
join_coverage: {
by_sku: map.reduce((a, m) => a + m.join_sku_hits, 0),
by_dwsku: map.reduce((a, m) => a + m.join_dwsku_hits, 0),
by_mfr: map.reduce((a, m) => a + m.join_mfr_hits, 0),
by_pattern_token: map.reduce((a, m) => a + m.pattern_match_hits, 0),
},
catalog_provenance: {
total_rows: catalog.length,
no_provenance_url: noUrl,
fabricated_code_rows: corrupted,
trustworthy_source_rows: trustworthy,
describes_vendor: linkage,
},
conclusion: 'BLOCKED_ON_VENDOR_LINESHEET — 0 trustworthy local recovery sources for the cohort; '
+ 'innovations_catalog describes the Innovations USA (DWIN-) line, not the PR private-label. '
+ 'Local backfill would fabricate identity/price. Recovery requires the gated vendor line-sheet.',
};
// ---------------------------------------------------------------------------
// 4) Emit artifacts.
// ---------------------------------------------------------------------------
fs.writeFileSync(path.join(DATA, 'innovations-recovery-map.json'),
JSON.stringify({ summary, map }, null, 2));
fs.writeFileSync(path.join(DATA, 'reconcile-summary.json'),
JSON.stringify(summary, null, 2));
const csvCols = ['sku', 'internal_code', 'collection', 'pattern_token',
'join_sku_hits', 'join_dwsku_hits', 'join_mfr_hits', 'pattern_match_hits',
'trustworthy_priced_sources', 'status'];
const csv = [csvCols.join(',')]
.concat(map.map(m => csvCols.map(k => JSON.stringify(m[k] ?? '')).join(',')))
.join('\n');
fs.writeFileSync(path.join(DATA, 'innovations-recovery-map.csv'), csv + '\n');
console.log(JSON.stringify(summary, null, 2));
console.log(`\nWrote:\n data/innovations-recovery-map.json (${map.length} items)\n data/innovations-recovery-map.csv\n data/reconcile-summary.json`);