| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- #!/usr/bin/env node
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const {
- buildClosureSummary,
- renderReport,
- bestHistoryAudit,
- bestCustomerEffectSummary,
- bestOvernightAggregate,
- isClosableOvernightAggregate
- } = require('./proof-gap-closure-audit');
- function main() {
- const historyAuditPath = path.join('outputs', 'history-audit-latest', 'historical-dataset-audit.json');
- const staleHistoryAuditPath = path.join('outputs', 'stale-history-audit', 'historical-dataset-audit.json');
- const sourceFiles = { history: historyAuditPath };
- const passingHistory = passingHistoryAudit();
- const open = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: false, historyReady: false, videoReady: false, reviewMetricsReady: false, customerEffectReady: false }, failureCount: 9 },
- history: null,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: false }, counts: { realReferenceRows: 1, realCandidateRows: 0 }, failureCount: 1 },
- videoAb: { acceptance: { passed: false }, delta: { strong: 1, evidenceCards: 2 } },
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: false, failedGateCount: 1 }, failureCount: 0 },
- customerEffect: { acceptance: { overallPass: false }, customerSelectedRate: 0.2 }
- });
- assert(!open.complete, 'open summary should not be complete');
- assert(open.openCount === 5, `openCount should be 5, got ${open.openCount}`);
- assert(open.businessOpenCount === 5, `businessOpenCount should be 5, got ${open.businessOpenCount}`);
- assert(open.openCount === open.businessOpenCount, 'openCount should remain a business-open alias for compatibility');
- assert(open.businessClosedCount === 0, `businessClosedCount should be 0, got ${open.businessClosedCount}`);
- assert(open.businessGapCount === 5, `businessGapCount should be 5, got ${open.businessGapCount}`);
- assert(open.precheckRowCount === 1, `precheckRowCount should be 1, got ${open.precheckRowCount}`);
- assert(open.precheckOpenCount === 1, `precheckOpenCount should be 1, got ${open.precheckOpenCount}`);
- assert(open.totalRows === 6, `totalRows should include intake precheck row, got ${open.totalRows}`);
- assert(open.countSemantics?.openCount === 'business_gap_open_count_excludes_precheck_rows', 'summary should document openCount count semantics');
- assert(open.intakeReady === false, 'open summary should record intake readiness as false');
- assert(open.rows.every(row => row.status === 'open'), 'all open fixture rows should be open');
- assert(open.rows.some(row => row.id === 'intake-readiness'), 'summary should include intake readiness row');
- assert(open.rows.every(row => row.command && row.expectedArtifact), 'all rows should include command and expected artifact');
- assert(open.rows.every(row => Array.isArray(row.missingProofRequirements) && row.missingProofRequirements.length >= 1), 'all open fixture rows should explain missing proof requirements');
- assert(open.rows.find(row => row.id === 'intake-readiness').missingProofRequirements.includes('acceptance.overallReady=true'), 'intake row should explain missing overall readiness');
- assert(open.rows.find(row => row.id === 'historical-dataset').missingProofRequirements.includes('missing historical-dataset-audit.json'), 'history row should explain missing history audit');
- assert(open.rows.find(row => row.id === 'video-real-candidate').missingProofRequirements.includes('counts.realCandidateRows>=1'), 'video resource row should explain missing real candidate rows');
- assert(open.rows.find(row => row.id === 'live-provider-overnight-proof').missingProofRequirements.includes('acceptance.overallPass=true'), 'overnight row should explain missing overall pass');
- assert(open.rows.find(row => row.id === 'manual-review-and-customer-effect').missingProofRequirements.includes('acceptance.overallPass=true'), 'customer effect row should explain missing customer effect pass');
- const closed = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: {
- acceptance: { passed: true },
- proofContext: {
- mode: 'live',
- collectionMode: 'live',
- generatedBy: 'acceptance:video-ab',
- requiresRuntimeCredential: true,
- requiresVocSocialProvider: true,
- requiresVideoAnalysisProvider: true
- },
- enhanced: { provider: { evidence: { providerStatus: 'ok' } } },
- delta: { strong: 1, evidenceCards: 3 }
- },
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- assert(closed.complete, 'closed summary should be complete');
- assert(closed.closedCount === 5, `closedCount should be 5, got ${closed.closedCount}`);
- assert(closed.businessClosedCount === 5, `businessClosedCount should be 5, got ${closed.businessClosedCount}`);
- assert(closed.closedCount === closed.businessClosedCount, 'closedCount should remain a business-closed alias for compatibility');
- assert(closed.businessOpenCount === 0, `businessOpenCount should be 0, got ${closed.businessOpenCount}`);
- assert(closed.precheckOpenCount === 0, `precheckOpenCount should be 0, got ${closed.precheckOpenCount}`);
- assert(closed.precheckClosedCount === 1, `precheckClosedCount should be 1, got ${closed.precheckClosedCount}`);
- assert(closed.intakeReady === true, 'closed summary should record intake readiness as true');
- assert(closed.rows.every(row => Array.isArray(row.missingProofRequirements) && row.missingProofRequirements.length === 0), 'closed rows should not keep stale missing proof requirements');
- const report = renderReport(closed);
- assert(report.includes('是否全部关闭:是'), 'report should render completion');
- assert(report.includes('Intake 预审是否就绪:是'), 'report should render intake readiness');
- assert(report.includes('业务证明缺口未关闭:0'), 'report should render business open proof gap count');
- assert(report.includes('预审未就绪行:0'), 'report should render precheck open row count separately');
- assert(report.includes('缺失证明'), 'report should render missing proof column');
- assert(report.includes('验证命令'), 'report should render command column');
- assert(report.includes('期望产物'), 'report should render expected artifact column');
- assert(!/sk-[A-Za-z0-9_-]{8,}/.test(report), 'report should not include secret-like values');
- const thinIntake = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: false, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: passingVideoReadiness(),
- videoAb: passingVideoAb(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- const thinIntakeRow = thinIntake.rows.find(row => row.id === 'intake-readiness');
- assert(thinIntakeRow.status === 'open', 'intake with top-level overallReady but missing child readiness should remain open');
- assert(thinIntakeRow.missingProofRequirements.includes('acceptance.historyReady=true'), 'thin intake should require history readiness');
- const thinHistory = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: { briefCount: 3, acceptance: { readyForCustomerEffectProof: true } },
- videoReadiness: passingVideoReadiness(),
- videoAb: passingVideoAb(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- const thinHistoryRow = thinHistory.rows.find(row => row.id === 'historical-dataset');
- assert(thinHistoryRow.status === 'open', 'history audit with fewer than 5 briefs should remain open');
- assert(thinHistoryRow.missingProofRequirements.includes('briefCount>=5'), 'thin history should require at least 5 briefs');
- const thinTopLevelHistory = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: { briefCount: 5, acceptance: { readyForCustomerEffectProof: true } },
- videoReadiness: passingVideoReadiness(),
- videoAb: passingVideoAb(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- const thinTopLevelHistoryRow = thinTopLevelHistory.rows.find(row => row.id === 'historical-dataset');
- assert(thinTopLevelHistoryRow.status === 'open', 'history audit with only top-level ready flag should remain open');
- assert(thinTopLevelHistoryRow.missingProofRequirements.includes('acceptance.allHaveManualFinalList=true'), 'thin history should require manual final-list coverage');
- assert(thinTopLevelHistoryRow.missingProofRequirements.includes('items.length>=5'), 'thin history should include auditable item details');
- const thinVideoResource = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1 }, failureCount: 0 },
- videoAb: passingVideoAb(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- const thinVideoResourceRow = thinVideoResource.rows.find(row => row.id === 'video-real-candidate');
- assert(thinVideoResourceRow.status === 'open', 'video readiness without video URL rows should remain open');
- assert(thinVideoResourceRow.missingProofRequirements.includes('counts.videoUrlRows>=1'), 'thin video readiness should require video URL rows');
- const thinCustomerEffect = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: passingVideoAb(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: { acceptance: { overallPass: true }, customerSelectedRate: 0.42, manualSupplementReductionRate: 0.5, historyAuditPath },
- sourceFiles
- });
- const thinCustomerEffectRow = thinCustomerEffect.rows.find(row => row.id === 'manual-review-and-customer-effect');
- assert(thinCustomerEffectRow.status === 'open', 'thin customer-effect summary should not close customer proof');
- assert(thinCustomerEffectRow.missingProofRequirements.includes('acceptance.reviewMetricsOverallUsable=true'), 'thin customer-effect summary should require review metrics usability');
- assert(thinCustomerEffectRow.missingProofRequirements.includes('referenceCustomerSelectedRate=number'), 'thin customer-effect summary should require reference customer selected rate');
- const mismatchedCustomerEffect = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: passingVideoAb(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(staleHistoryAuditPath),
- sourceFiles
- });
- const mismatchedCustomerEffectRow = mismatchedCustomerEffect.rows.find(row => row.id === 'manual-review-and-customer-effect');
- assert(mismatchedCustomerEffectRow.status === 'open', 'customer-effect summary bound to stale history audit should stay open');
- assert(mismatchedCustomerEffectRow.missingProofRequirements.includes('historyAuditPath=current-history-audit'), 'customer-effect summary should bind to current history audit path');
- const fakeVideo = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: { acceptance: { passed: true }, delta: { strong: 1, evidenceCards: 3 } },
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- assert(!fakeVideo.complete, 'passed video A/B without live proofContext should not close all proof gaps');
- const fakeVideoRow = fakeVideo.rows.find(row => row.id === 'video-ab-live-proof');
- assert(fakeVideoRow.status === 'open', 'video A/B without live proofContext should remain open');
- assert(fakeVideoRow.missingProofRequirements.includes('proofContext.mode=live'), 'video A/B row should explain missing live mode');
- assert(fakeVideoRow.missingProofRequirements.includes('proofContext.generatedBy=acceptance:video-ab'), 'video A/B row should explain missing generatedBy');
- const preflightVideo = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: { acceptance: { passed: true }, enhanced: { provider: { evidence: { providerStatus: 'ok' } } }, delta: { strong: 1, evidenceCards: 3 } },
- videoAbPreflight: failedVideoAbPreflight(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- assert(!preflightVideo.complete, 'video A/B preflight failure context should not close live proof');
- assert(preflightVideo.videoAbPreflightReadyForVideoAb === false, 'summary should expose video A/B preflight readiness');
- assert(preflightVideo.videoAbPreflightFailureCount === 4, 'summary should expose video A/B preflight failure count');
- const preflightVideoRow = preflightVideo.rows.find(row => row.id === 'video-ab-live-proof');
- assert(preflightVideoRow.status === 'open', 'video A/B row should remain open when only preflight failed');
- assert(preflightVideoRow.evidence.includes('preflight.readyForVideoAb=false'), 'video A/B evidence should include preflight readiness');
- assert(preflightVideoRow.evidence.includes('runtimeCredentialPresent=false'), 'video A/B evidence should include runtime credential presence only');
- assert(preflightVideoRow.missingProofRequirements.includes('videoAbPreflight.readyForVideoAb=true'), 'video A/B row should require preflight readiness before live proof can run');
- assert(preflightVideoRow.missingProofRequirements.includes('videoAbPreflight.company resolved for live run'), 'video A/B row should include preflight missing company context');
- const liveVideoWithStalePreflight = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: passingVideoAb(),
- videoAbPreflight: failedVideoAbPreflight(),
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0 }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- assert(liveVideoWithStalePreflight.complete, 'passing live video A/B proof should not be blocked by an older preflight failure');
- const liveVideoRow = liveVideoWithStalePreflight.rows.find(row => row.id === 'video-ab-live-proof');
- assert(liveVideoRow.status === 'closed', 'passing live video A/B row should close');
- assert(!liveVideoRow.evidence.includes('preflight.readyForVideoAb=false'), 'closed live video proof should not foreground stale preflight failure context');
- const tokenLeak = buildClosureSummary({
- root: process.cwd(),
- intakeReadiness: { acceptance: { overallReady: true, historyReady: true, videoReady: true, reviewMetricsReady: true, customerEffectReady: true }, failureCount: 0 },
- history: passingHistory,
- videoReadiness: { acceptance: { readyForVideoAbPreflight: true }, counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 }, failureCount: 0 },
- videoAb: {
- acceptance: { passed: true },
- proofContext: {
- mode: 'live',
- collectionMode: 'live',
- generatedBy: 'acceptance:video-ab',
- requiresRuntimeCredential: true,
- requiresVocSocialProvider: true,
- requiresVideoAnalysisProvider: true
- },
- enhanced: { provider: { evidence: { providerStatus: 'ok' } } },
- delta: { strong: 1, evidenceCards: 3 }
- },
- overnight: { manifest: { liveEnabled: true }, acceptance: { overallPass: true, failedGateCount: 0, tokenLeak: true }, failureCount: 0 },
- customerEffect: passingCustomerEffect(historyAuditPath),
- sourceFiles
- });
- const tokenLeakRow = tokenLeak.rows.find(row => row.id === 'live-provider-overnight-proof');
- assert(tokenLeakRow.status === 'open', 'overnight aggregate with token leak should remain open');
- assert(tokenLeakRow.missingProofRequirements.includes('acceptance.tokenLeak=false'), 'overnight token leak should be listed as a missing requirement');
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-proof-gap-'));
- try {
- const closableDir = path.join(tmp, 'older-closable');
- const badDir = path.join(tmp, 'newer-bad');
- fs.mkdirSync(closableDir, { recursive: true });
- fs.mkdirSync(badDir, { recursive: true });
- const closableFile = path.join(closableDir, 'aggregate-summary.json');
- const badFile = path.join(badDir, 'aggregate-summary.json');
- fs.writeFileSync(closableFile, JSON.stringify({
- manifest: { liveEnabled: true },
- acceptance: { overallPass: true, failedGateCount: 0, tokenLeak: false },
- failureCount: 0
- }), 'utf8');
- fs.writeFileSync(badFile, JSON.stringify({
- manifest: { liveEnabled: false },
- acceptance: { overallPass: false, failedGateCount: 1, tokenLeak: false },
- failureCount: 0
- }), 'utf8');
- fs.utimesSync(closableFile, new Date(Date.now() - 10000), new Date(Date.now() - 10000));
- fs.utimesSync(badFile, new Date(), new Date());
- const best = bestOvernightAggregate(tmp);
- assert(path.resolve(best) === path.resolve(closableFile), 'best overnight aggregate should prefer an older closable aggregate over a newer bad aggregate');
- assert(isClosableOvernightAggregate(JSON.parse(fs.readFileSync(best, 'utf8'))), 'selected overnight aggregate should be closable');
- } finally {
- fs.rmSync(tmp, { recursive: true, force: true });
- }
- const proofTmp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-proof-discovery-'));
- try {
- const realHistoryDir = path.join(proofTmp, 'pipeline-run', 'history-audit');
- const smokeHistoryDir = path.join(proofTmp, 'pipeline-smoke-run', 'history-audit');
- const newerFailingHistoryDir = path.join(proofTmp, 'latest-real-run', 'history-audit');
- fs.mkdirSync(realHistoryDir, { recursive: true });
- fs.mkdirSync(smokeHistoryDir, { recursive: true });
- fs.mkdirSync(newerFailingHistoryDir, { recursive: true });
- const passingHistoryFile = path.join(realHistoryDir, 'historical-dataset-audit.json');
- const smokeHistoryFile = path.join(smokeHistoryDir, 'historical-dataset-audit.json');
- const failingHistoryFile = path.join(newerFailingHistoryDir, 'historical-dataset-audit.json');
- fs.writeFileSync(passingHistoryFile, JSON.stringify(passingHistoryAudit(), null, 2), 'utf8');
- fs.writeFileSync(smokeHistoryFile, JSON.stringify(passingHistoryAudit(), null, 2), 'utf8');
- fs.writeFileSync(failingHistoryFile, JSON.stringify({ briefCount: 1, acceptance: { readyForCustomerEffectProof: false }, items: [] }, null, 2), 'utf8');
- fs.utimesSync(passingHistoryFile, new Date(Date.now() - 20000), new Date(Date.now() - 20000));
- fs.utimesSync(smokeHistoryFile, new Date(), new Date());
- fs.utimesSync(failingHistoryFile, new Date(Date.now() - 10000), new Date(Date.now() - 10000));
- const discoveredHistory = bestHistoryAudit(proofTmp);
- assert(path.resolve(discoveredHistory) === path.resolve(passingHistoryFile), 'history discovery should recurse and prefer a claimable non-smoke audit');
- const currentCustomerDir = path.join(proofTmp, 'latest-real-run', 'customer-effect-audit');
- const staleCustomerDir = path.join(proofTmp, 'other-real-run', 'customer-effect-audit');
- fs.mkdirSync(currentCustomerDir, { recursive: true });
- fs.mkdirSync(staleCustomerDir, { recursive: true });
- const currentCustomerFile = path.join(currentCustomerDir, 'customer-effect-summary.json');
- const staleCustomerFile = path.join(staleCustomerDir, 'customer-effect-summary.json');
- fs.writeFileSync(currentCustomerFile, JSON.stringify({
- ...passingCustomerEffect(failingHistoryFile),
- acceptance: { overallPass: false, historyReadyForCustomerEffectProof: false },
- customerSelectedRate: 0
- }, null, 2), 'utf8');
- fs.writeFileSync(staleCustomerFile, JSON.stringify(passingCustomerEffect(path.join('outputs', 'stale-history-audit', 'historical-dataset-audit.json')), null, 2), 'utf8');
- fs.utimesSync(currentCustomerFile, new Date(Date.now() - 10000), new Date(Date.now() - 10000));
- fs.utimesSync(staleCustomerFile, new Date(), new Date());
- const discoveredCustomerEffect = bestCustomerEffectSummary(proofTmp, failingHistoryFile, process.cwd());
- assert(path.resolve(discoveredCustomerEffect) === path.resolve(currentCustomerFile), 'customer-effect discovery should prefer summaries bound to the selected history audit');
- } finally {
- fs.rmSync(proofTmp, { recursive: true, force: true });
- }
- console.log(JSON.stringify({ ok: true, openCount: open.openCount, closedCount: closed.closedCount }, null, 2));
- }
- function assert(condition, message) {
- if (!condition) throw new Error(message);
- }
- function passingVideoAb() {
- return {
- acceptance: { passed: true },
- proofContext: {
- mode: 'live',
- collectionMode: 'live',
- generatedBy: 'acceptance:video-ab',
- requiresRuntimeCredential: true,
- requiresVocSocialProvider: true,
- requiresVideoAnalysisProvider: true
- },
- enhanced: { provider: { evidence: { providerStatus: 'ok' } } },
- delta: { strong: 1, evidenceCards: 3 }
- };
- }
- function passingVideoReadiness() {
- return {
- acceptance: { readyForVideoAbPreflight: true },
- counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 },
- failureCount: 0
- };
- }
- function failedVideoAbPreflight() {
- return {
- materialType: 'video_ab_runtime_preflight',
- directCustomerProof: false,
- proofLevel: 'not_business_proof',
- canCloseProofGap: false,
- readyForVideoAb: false,
- failureCount: 4,
- proofContext: {
- mode: 'not_run',
- collectionMode: 'not_run',
- generatedBy: 'acceptance:video-ab-preflight',
- requiresRuntimeCredential: true,
- requiresVocSocialProvider: true,
- requiresVideoAnalysisProvider: true
- },
- runtime: {
- runtimeCredentialPresent: false,
- companyResolved: false,
- vocSocialProviderTokenPresent: false,
- videoAnalysisTokenPresent: false
- },
- missingProofRequirements: [
- 'proofContext.requiresRuntimeCredential=true',
- 'company resolved for live run',
- 'proofContext.requiresVocSocialProvider=true',
- 'proofContext.requiresVideoAnalysisProvider=true'
- ]
- };
- }
- function passingCustomerEffect(historyAuditPath) {
- return {
- reviewPath: path.join('outputs', 'review-metrics-latest', 'reviewed.csv'),
- historyAuditPath,
- customerSelectedRate: 0.5,
- referenceCustomerSelectedRate: 0.5,
- manualSupplementBaseline: { available: true, source: 'history-audit', total: 10, byBrief: [{ briefId: 'brief-a', count: 10 }] },
- currentManualSupplement: { available: true, source: 'cli-arg', total: 5, byBrief: [] },
- manualSupplementReductionRate: 0.5,
- acceptance: {
- overallPass: true,
- reviewMetricsOverallUsable: true,
- customerSelectedRateMeasured: true,
- customerSelectedRate30Pass: true,
- referenceCustomerSelectedRateMeasured: true,
- referenceCustomerSelectedRate40Pass: true,
- historyReadyForCustomerEffectProof: true,
- manualSupplementBaselineAvailable: true,
- currentManualSupplementAvailable: true,
- manualSupplementReduction50Pass: true
- },
- missingEvidence: []
- };
- }
- function passingHistoryAudit() {
- return {
- generatedAt: '2026-06-11T02:48:48.000Z',
- minBriefs: 5,
- briefCount: 5,
- categoryCount: 3,
- categories: ['skincare', 'mom-baby', 'home'],
- withReference: 5,
- withManualFinalList: 5,
- withCustomerDecision: 5,
- withRejectionReason: 2,
- withManualSupplementBaseline: 5,
- missingCriticalCount: 0,
- acceptance: {
- parseOk: true,
- minBriefsMet: true,
- allHaveBriefText: true,
- allHaveManualFinalList: true,
- allHaveCustomerDecision: true,
- allHaveFeedbackReason: true,
- allHaveManualSupplementBaseline: true,
- categoryCoverageMet: true,
- referenceCoverageMeasured: true,
- readyForLongRun: true,
- readyForCustomerEffectProof: true
- },
- items: Array.from({ length: 5 }, (_, index) => ({
- id: `brief-${index + 1}`,
- parseOk: true,
- hasBriefText: true,
- hasManualFinalList: true,
- hasCustomerDecision: true,
- hasRejectionReason: index < 2,
- hasManualSupplementBaseline: true,
- manualSupplementBaseline: 2,
- missingCritical: []
- }))
- };
- }
- main();
|