056c47581f
Ships the second dashboard surface — a Pattern Library + Preview Theatre — that presents the 4-section PDP pilot batch back to Umar, compliance, and the board in an editorial format. Adds the full data layer that drives it: 5 source-backed per-SKU drafts at QA 100/100, 15 competitor PDP semantic extracts, PubMed evidence packs, EFSA claims library extension, JV brand voice guide, hand-curated product FAQs, and the Matrixify-ready CSV exports for Lewis. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
41 lines
2.1 KiB
TypeScript
41 lines
2.1 KiB
TypeScript
#!/usr/bin/env bun
|
|
import { intelPath, listProducts, loadCompetitorConfig, readJson, readPilotDoc, sourcePath, sourceStatus, writeJson, now, slug } from './lib/intel-utils'
|
|
|
|
const competitors = loadCompetitorConfig()
|
|
for (const product of listProducts()) {
|
|
const sku = product.sku
|
|
const { aspects, sw } = readPilotDoc(sku)
|
|
const seededBenefits = product.metafields?.pdpProductBenefits || []
|
|
const rows = competitors.map((c: any, index: number) => {
|
|
const doc = readJson(sourcePath('competitor-pdps', `${slug(c.brand)}.json`), null)
|
|
const okPages = (doc?.pages || []).filter((p: any) => p.ok)
|
|
return {
|
|
rank: index + 1,
|
|
brand: c.brand,
|
|
domain: c.domain,
|
|
sourceCoverage: okPages.length ? `${okPages.length}/${(doc?.pages || []).length} URLs fetched` : 'pending crawl/import',
|
|
priceSignal: '',
|
|
format: '',
|
|
dose: '',
|
|
claims: '',
|
|
whitespace: okPages.length ? 'Homepage/PDP probe captured. Needs product-specific extraction before final comparison.' : 'Pending competitor PDP/Amazon/Trustpilot evidence. Do not use for final copy yet.',
|
|
status: okPages.length ? 'source_probe_available' : 'needs_ingestion'
|
|
}
|
|
})
|
|
const jvSignals = (sw.items || []).length
|
|
? sw.items.slice(0, 5).map((item: any) => ({ rank: item.rank, signal: item.insight, source: 'Feefo strengths/weaknesses' }))
|
|
: seededBenefits.slice(0, 5).map((benefit: string, index: number) => ({ rank: index + 1, signal: benefit, source: 'product content benefits seed; needs competitor validation' }))
|
|
writeJson(intelPath(sku, 'competitor-comparison.json'), {
|
|
sku,
|
|
name: aspects.name || product.name || sku,
|
|
generatedAt: now(),
|
|
generatedBy: 'build-competitor-comparison.ts',
|
|
n: rows.length,
|
|
sourceStatus: { competitorPdp: sourceStatus('competitor-pdps'), amazon: sourceStatus('amazon'), trustpilot: sourceStatus('trustpilot') },
|
|
coverage: (sw.items || []).length ? 'pilot_feefo_plus_competitor_probes' : 'catalogue_queue_seeded_from_product_content_and_competitor_probes',
|
|
competitors: rows,
|
|
jvSignals
|
|
})
|
|
console.log(`${sku}: wrote competitor comparison for ${rows.length} brands`)
|
|
}
|