Files
justvitamin/scripts/generate-executive-decision-brief.ts
Omair Saleh 056c47581f feat: editorial review dashboard + elite-grade pilot batch (5 SKUs)
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>
2026-06-02 18:50:09 +08:00

153 lines
8.7 KiB
TypeScript

#!/usr/bin/env bun
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
const root = process.cwd()
const outRoot = join(root, 'content_population_exports')
mkdirSync(outRoot, { recursive: true })
const generatedAt = new Date().toISOString()
function readJson(path: string, fallback: any = null) {
if (!existsSync(path)) return fallback
return JSON.parse(readFileSync(path, 'utf8').replace(/^\uFEFF/, ''))
}
function csv(rows: any[], headers: string[]) {
const esc = (value: any) => {
if (Array.isArray(value)) value = value.join(' | ')
if (value === undefined || value === null) value = ''
value = String(value)
return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value
}
return [headers.join(','), ...rows.map(row => headers.map(header => esc(row[header])).join(','))].join('\n') + '\n'
}
const handoff = readJson(join(outRoot, 'handoff_manifest.json'), {})
const readiness = readJson(join(outRoot, 'content_population_readiness.json'), {})
const actionPlan = readJson(join(outRoot, 'handoff_action_plan.json'), {})
const claimsMapping = readJson(join(outRoot, 'clinical_claim_mapping_report.json'), {})
const blankDecision = readJson(join(outRoot, 'clinical_blank_decision_template.json'), {})
const approvalDecision = readJson(join(outRoot, 'product_approval_decision_gate.json'), {})
const stagingPacket = readJson(join(outRoot, 'staging_handoff_packet.json'), {})
const stagingEvidence = readJson(join(outRoot, 'staging_evidence_validation.json'), {})
const delivery = readJson(join(outRoot, 'delivery_index.json'), {})
const dataforseoDocs = readJson(join(outRoot, 'dataforseo_reviews_docs_status.json'), {})
const dataforseoPilot = readJson(join(outRoot, 'dataforseo_pilot_manifest.json'), {})
const sourceNext = readJson(join(outRoot, 'source_acquisition_next_actions.json'), {})
const decisions = [
{
Priority: 'D1',
Owner: 'Compliance owner / Umar',
Decision: 'For each SKU with blank clinically_shown_to, either add a source-backed authorised claim or approve the module being blank.',
CurrentState: `${claimsMapping.mappedProducts ?? 0} mapped; ${blankDecision.counts?.pending ?? claimsMapping.unmappedProducts ?? 0} blank decisions pending; ${blankDecision.counts?.validBlankApprovals ?? 0} valid blank approvals.`,
EvidenceFile: 'data/content/compliance/clinical-blank-decisions.json',
Blocks: '185 compliance/export blockers and final handoff readiness.',
SafeDefault: 'Leave clinically_shown_to blank and blocked; do not invent generic clinical claims.'
},
{
Priority: 'D2',
Owner: 'Umar / JV reviewer',
Decision: 'Approve or reject product content, compliance, images, and export readiness per product.',
CurrentState: `${approvalDecision.counts?.validApprovals ?? 0} valid approvals; ${approvalDecision.counts?.pending ?? 190} pending; ${approvalDecision.counts?.applied ?? 0} applied.`,
EvidenceFile: 'data/content/approvals/product-approval-decisions.json',
Blocks: '190 approval blockers and Lewis/Euan import confidence.',
SafeDefault: 'Keep products blocked until explicit approval evidence is recorded.'
},
{
Priority: 'D3',
Owner: 'Lewis/Euan / Kubix',
Decision: 'Only run Matrixify staging import after dashboard handoff blockers are cleared, then return import logs.',
CurrentState: `${stagingPacket.counts?.presentImportFiles ?? 0}/${stagingPacket.counts?.importFiles ?? 0} import/reference files present; readyForLewis=${Boolean(handoff.readyForLewis)}; export blockers=${handoff.counts?.blockers ?? 'unknown'}.`,
EvidenceFile: 'content_population_exports/staging_handoff_packet.md',
Blocks: 'Staging import evidence, PDP checks, and production cutover.',
SafeDefault: 'Do not import as final while export_blockers.csv has rows.'
},
{
Priority: 'D4',
Owner: 'Dashboard owner + Lewis/Euan',
Decision: 'Complete real staging PDP spot checks and cutover approval after import.',
CurrentState: `${stagingEvidence.counts?.passingPdpChecks ?? 0} passing PDP checks; ${stagingEvidence.counts?.importLogs ?? 0} import logs; cutover approval present=${Boolean(stagingEvidence.counts?.cutoverApprovalPresent)}.`,
EvidenceFile: 'data/staging/import-logs/, data/staging/pdp-checks/, data/staging/cutover-approval.json',
Blocks: 'Production cutover.',
SafeDefault: 'Queued PDP templates are not evidence; real staging URLs must be inspected.'
},
{
Priority: 'D5',
Owner: 'Research / project owner',
Decision: 'Use DataForSEO only for the capped review pilot after endpoint/support/spend gates clear; otherwise use the manual capture fallback.',
CurrentState: `${dataforseoPilot.counts?.readyTasks ?? 0} DataForSEO payload rows ready; ${dataforseoPilot.counts?.missingAsins ?? 0} ASINs missing; reviews docs unavailable=${Boolean(dataforseoDocs.endpointTemporarilyUnavailable)}; current instruction: ${sourceNext.currentInstruction || 'not generated'}`,
EvidenceFile: 'content_population_exports/dataforseo_support_escalation.md and source_acquisition_next_actions.md',
Blocks: 'Amazon review-source depth; not current Matrixify handoff if manual/limited source caveat is accepted.',
SafeDefault: 'Do not retry paid Reviews endpoint while official docs/support gate says unavailable.'
}
]
const readinessRows = [
{ Metric: 'Dashboard products', Value: handoff.counts?.productRecords ?? 190 },
{ Metric: 'Matrixify product rows', Value: handoff.counts?.variantRows ?? 350 },
{ Metric: 'Export blockers', Value: handoff.counts?.blockers ?? 0 },
{ Metric: 'Blocked SKUs', Value: handoff.counts?.blockedSkus ?? 0 },
{ Metric: 'Readiness gates', Value: `${readiness.summary?.passing ?? 0}/${readiness.summary?.totalGates ?? 0}` },
{ Metric: 'Delivery packet files', Value: `${delivery.counts?.present ?? 0}/${delivery.counts?.files ?? 0}` },
{ Metric: 'Action plan blocked actions', Value: actionPlan.counts?.blockedActions ?? 0 },
{ Metric: 'Staging import files present', Value: `${stagingPacket.counts?.presentImportFiles ?? 0}/${stagingPacket.counts?.importFiles ?? 0}` }
]
const manifest = {
generatedAt,
ready: Boolean(handoff.readyForLewis) && Boolean(readiness.ready) && Boolean(stagingEvidence.ready),
purpose: 'Executive decision brief for moving JV content population from generated packet to approved Lewis/Euan staging handoff.',
statusLine: Boolean(handoff.readyForLewis)
? 'Handoff packet is clean; proceed to staging evidence capture.'
: `Not handoff-ready: ${handoff.counts?.blockers ?? 'unknown'} export blockers remain, concentrated in compliance decisions and product approvals.`,
counts: {
decisions: decisions.length,
exportBlockers: handoff.counts?.blockers ?? null,
complianceBlockers: handoff.blockerSummary?.compliance ?? null,
approvalBlockers: handoff.blockerSummary?.approval ?? null,
deliveryFiles: delivery.counts?.files ?? null,
deliveryPresent: delivery.counts?.present ?? null
},
decisions,
readinessRows
}
writeFileSync(join(outRoot, 'executive_decision_brief.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'executive_decision_brief_decisions.csv'), csv(decisions, ['Priority', 'Owner', 'Decision', 'CurrentState', 'EvidenceFile', 'Blocks', 'SafeDefault']), 'utf8')
writeFileSync(join(outRoot, 'executive_decision_brief_readiness.csv'), csv(readinessRows, ['Metric', 'Value']), 'utf8')
writeFileSync(join(outRoot, 'executive_decision_brief.md'), [
'# JV executive decision brief',
'',
`Generated: ${generatedAt}`,
'',
`Status: **${manifest.statusLine}**`,
'',
'## Snapshot',
...readinessRows.map(row => `- ${row.Metric}: ${row.Value}`),
'',
'## Decisions required',
...decisions.map(row => [
`### ${row.Priority}${row.Owner}`,
`- Decision: ${row.Decision}`,
`- Current state: ${row.CurrentState}`,
`- Evidence file: \`${row.EvidenceFile}\``,
`- Blocks: ${row.Blocks}`,
`- Safe default: ${row.SafeDefault}`,
''
].join('\n')),
'## Recommended meeting close',
'1. Confirm who owns the 185 clinical blank/source-backed claim decisions.',
'2. Confirm who can enter the 190 product approval decisions.',
'3. Confirm Lewis/Euan should wait for zero export blockers before Matrixify staging import.',
'4. If Amazon Reviews remains blocked at DataForSEO, choose manual capture for the six confirmed ASINs or accept the limited source caveat.',
'',
'## Non-negotiable guardrail',
'Do not mark handoff ready, approve products, or claim staging completion without the explicit evidence files named above.',
''
].join('\n'), 'utf8')
console.log(`Executive decision brief ready: ${manifest.ready}`)
console.log(`Decisions: ${manifest.counts.decisions}`)
console.log(`Export blockers: ${manifest.counts.exportBlockers}`)
if (!manifest.ready) process.exitCode = 1