| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- #!/usr/bin/env node
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const { buildEvidenceIndex } = require('./evidence-index');
- function main() {
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-evidence-index-root-'));
- const outputs = path.join(root, 'outputs');
- fs.mkdirSync(outputs, { recursive: true });
- writeJson(path.join(outputs, 'overnight-live', 'aggregate-summary.json'), {
- manifest: { liveEnabled: true },
- acceptance: { overallPass: true, failedGateCount: 0 },
- runCount: 12,
- failureCount: 0,
- fixtureCount: 3,
- variantCount: 4
- });
- writeJson(path.join(outputs, 'overnight-live-failed', 'aggregate-summary.json'), {
- manifest: { liveEnabled: true },
- acceptance: { overallPass: false, failedGateCount: 1 },
- runCount: 12,
- failureCount: 0,
- fixtureCount: 3,
- variantCount: 4
- });
- writeJson(path.join(outputs, 'status', 'optimization-status-summary.json'), {
- complete: false,
- counts: { passed: 12, ready_not_proven: 2, blocked_by_external_data: 2 }
- });
- writeJson(path.join(outputs, 'live-preflight-ready', 'live-preflight-summary.json'), {
- readyForLiveAcceptance: true,
- readyForVideoAb: true,
- checks: [
- { name: 'session-token-present', status: 'pass' },
- { name: 'company-resolved', status: 'pass' },
- { name: 'video-model-doubao-seed-2-0-pro', status: 'pass' }
- ]
- });
- writeJson(path.join(outputs, 'live-preflight-missing', 'live-preflight-summary.json'), {
- readyForLiveAcceptance: false,
- readyForVideoAb: false,
- checks: [
- { name: 'session-token-present', status: 'fail' },
- { name: 'company-resolved', status: 'fail' },
- { name: 'homepage-provider-configured', status: 'warn' }
- ]
- });
- writeJson(path.join(outputs, 'review', 'review-metrics-summary.json'), {
- total: 10,
- selectedCount: 4,
- businessUsableRate: 0.7,
- offTargetHardFailRate: 0.1,
- customerSelectedRate: 0.4,
- acceptance: { overallPass: true, customerSelectedRatePass: true }
- });
- writeJson(path.join(outputs, 'history-real', 'historical-dataset-audit.json'), passingHistoryAudit());
- writeJson(path.join(outputs, 'history-thin', 'historical-dataset-audit.json'), {
- briefCount: 5,
- categoryCount: 3,
- withCustomerDecision: 5,
- acceptance: {
- readyForLongRun: true,
- readyForCustomerEffectProof: true
- }
- });
- writeJson(path.join(outputs, 'video', 'video-hit-rate-summary.json'), {
- acceptance: {
- passed: true,
- realReferenceResourceLoaded: true,
- realVideoResourceLoaded: true,
- coverOrFrameOrAsrLoaded: true,
- evidenceCardsNotPending: true,
- evidenceCardsHaveSignals: true,
- strongNotDegraded: true,
- top10EvidenceImproved: true
- },
- delta: { strong: 1, top10EvidenceHitCandidates: 3 }
- });
- writeJson(path.join(outputs, 'video-weak', 'video-hit-rate-summary.json'), {
- acceptance: {
- passed: true,
- realReferenceResourceLoaded: true,
- realVideoResourceLoaded: false,
- coverOrFrameOrAsrLoaded: true,
- evidenceCardsNotPending: true,
- evidenceCardsHaveSignals: true,
- strongNotDegraded: true,
- top10EvidenceImproved: true
- },
- delta: { strong: 1, top10EvidenceHitCandidates: 3 }
- });
- writeJson(path.join(outputs, 'video-ab-preflight-missing', 'video-hit-rate-preflight-summary.json'), {
- materialType: 'video_ab_runtime_preflight',
- directCustomerProof: false,
- proofLevel: 'not_business_proof',
- canCloseProofGap: false,
- readyForVideoAb: false,
- failureCount: 4,
- proofContext: {
- generatedBy: 'acceptance:video-ab-preflight',
- mode: 'not_run',
- collectionMode: 'not_run'
- }
- });
- writeJson(path.join(outputs, 'video-resource-ready', 'video-resource-readiness-summary.json'), {
- acceptance: { readyForVideoAbPreflight: true },
- counts: { realReferenceRows: 1, realCandidateRows: 1, videoUrlRows: 2 },
- failureCount: 0
- });
- writeJson(path.join(outputs, 'video-resource-missing', 'video-resource-readiness-summary.json'), {
- acceptance: { readyForVideoAbPreflight: false },
- counts: { realReferenceRows: 0, realCandidateRows: 0, videoUrlRows: 0 },
- failureCount: 3
- });
- writeJson(path.join(outputs, 'homepage-evidence-ready', 'homepage-evidence-readiness-summary.json'), {
- ready: true,
- directCustomerProof: false,
- proofLevel: 'smoke_or_local',
- counts: { candidates: 2, providerEvidenceCreators: 2, creatorsWithPosts: 2 },
- failureCount: 0
- });
- writeJson(path.join(outputs, 'homepage-evidence-missing', 'homepage-evidence-readiness-summary.json'), {
- ready: false,
- directCustomerProof: false,
- proofLevel: 'not_business_proof',
- counts: { candidates: 1, providerEvidenceCreators: 0, creatorsWithPosts: 0 },
- failureCount: 4
- });
- fs.writeFileSync(
- path.join(outputs, 'homepage-evidence-missing', 'homepage-evidence-repair-actions.csv'),
- 'owner,action,reason\nbusiness-media,补齐最近 10 篇主页内容,缺主页近期内容证据\n',
- 'utf8'
- );
- fs.writeFileSync(
- path.join(outputs, 'video-resource-missing', 'video-resource-repair-actions.csv'),
- 'owner,action,reason\nbusiness-media,补齐真实候选视频 URL,缺候选视频\n',
- 'utf8'
- );
- writeJson(path.join(outputs, 'customer-effect', 'customer-effect-summary.json'), {
- customerSelectedRate: 0.5,
- referenceCustomerSelectedRate: 0.6,
- manualSupplementReductionRate: 0.5,
- acceptance: {
- overallPass: true,
- customerSelectedRateMeasured: true,
- customerSelectedRate30Pass: true,
- referenceCustomerSelectedRateMeasured: true,
- referenceCustomerSelectedRate40Pass: true,
- historyReadyForCustomerEffectProof: true,
- manualSupplementBaselineAvailable: true,
- currentManualSupplementAvailable: true,
- manualSupplementReduction50Pass: true
- }
- });
- writeJson(path.join(outputs, 'customer-effect-missing-current', 'customer-effect-summary.json'), {
- customerSelectedRate: 0.5,
- referenceCustomerSelectedRate: 0.6,
- manualSupplementReductionRate: null,
- acceptance: {
- overallPass: false,
- customerSelectedRateMeasured: true,
- customerSelectedRate30Pass: true,
- referenceCustomerSelectedRateMeasured: true,
- referenceCustomerSelectedRate40Pass: true,
- historyReadyForCustomerEffectProof: true,
- manualSupplementBaselineAvailable: true,
- currentManualSupplementAvailable: false,
- manualSupplementReduction50Pass: null
- }
- });
- writeJson(path.join(outputs, 'pipeline-pass', 'optimization-pipeline-summary.json'), {
- dryRun: false,
- readyForClaim: true,
- proofGapClosure: { complete: true, closedCount: 5, openCount: 0 },
- counts: { pass: 5 },
- results: [
- { id: 'history-audit', status: 'pass' },
- { id: 'review-metrics', status: 'pass' },
- { id: 'customer-effect-audit', status: 'pass' },
- { id: 'proof-gap-closure', status: 'pass' },
- { id: 'evidence-index', status: 'pass' }
- ]
- });
- writeJson(path.join(outputs, 'pipeline-claim-with-open-closure', 'optimization-pipeline-summary.json'), {
- dryRun: false,
- readyForClaim: true,
- proofGapClosure: { complete: false, closedCount: 4, openCount: 1 },
- counts: { pass: 5 },
- results: [
- { id: 'history-audit', status: 'pass' },
- { id: 'review-metrics', status: 'pass' },
- { id: 'customer-effect-audit', status: 'pass' },
- { id: 'proof-gap-closure', status: 'pass' },
- { id: 'evidence-index', status: 'pass' }
- ]
- });
- writeJson(path.join(outputs, 'pipeline-claim-with-open-closure', 'customer-effect-audit', 'customer-effect-summary.json'), {
- customerSelectedRate: 0.5,
- referenceCustomerSelectedRate: 0.6,
- manualSupplementReductionRate: 0.5,
- acceptance: {
- overallPass: true,
- customerSelectedRateMeasured: true,
- customerSelectedRate30Pass: true,
- referenceCustomerSelectedRateMeasured: true,
- referenceCustomerSelectedRate40Pass: true,
- historyReadyForCustomerEffectProof: true,
- manualSupplementBaselineAvailable: true,
- currentManualSupplementAvailable: true,
- manualSupplementReduction50Pass: true
- }
- });
- writeJson(path.join(outputs, 'pipeline-fail', 'optimization-pipeline-summary.json'), {
- dryRun: false,
- readyForClaim: false,
- counts: { pass: 1, fail: 1 },
- results: [
- { id: 'history-audit', status: 'pass' },
- { id: 'customer-effect-audit', status: 'fail' }
- ]
- });
- writeJson(path.join(outputs, 'completion-open', 'optimization-completion-summary.json'), {
- complete: false,
- readyForClaim: false,
- proofGapOpenCount: 5,
- proofGapClosedCount: 0,
- blockingReasons: [
- { id: 'intake-readiness' },
- { id: 'customer-effect-proof' }
- ],
- canClaim: {
- tihaoRateImproved: false,
- customerEffectAchieved: false,
- manualSupplementReduced: false
- }
- });
- writeJson(path.join(outputs, 'handoff', 'optimization-handoff-summary.json'), {
- complete: false,
- readyCapabilities: [{ id: 'software-table' }],
- readyNotProven: [{ id: 'video-ab-proof' }],
- externalBlockers: [{ id: 'customer-effect-proof' }]
- });
- writeJson(path.join(outputs, 'proof-gap', 'proof-gap-request-summary.json'), {
- complete: false,
- unresolvedCount: 4,
- rows: [{ id: 'video-real-candidate' }, { id: 'customer-effect-proof' }]
- });
- writeJson(path.join(outputs, 'proof-gap-closure-open', 'proof-gap-closure-summary.json'), {
- complete: false,
- closedCount: 1,
- openCount: 4,
- rows: [{ id: 'historical-dataset', status: 'open' }]
- });
- writeJson(path.join(outputs, 'proof-gap-closure-closed', 'proof-gap-closure-summary.json'), {
- complete: true,
- closedCount: 5,
- openCount: 0,
- rows: [{ id: 'historical-dataset', status: 'closed' }]
- });
- writeJson(path.join(outputs, 'proof-gap-software-form', 'tihao-proof-gap-software-form-summary.json'), {
- passed: true,
- rowCount: 5,
- duplicateIdCount: 0,
- headerMatches: true,
- rowWidthOk: true
- });
- writeJson(path.join(outputs, 'round-deposition', 'round-deposition-summary.json'), {
- passed: true,
- counts: { pass: 24, warn: 0, fail: 0 }
- });
- writeJson(path.join(outputs, 'business-proof-progress', 'business-proof-progress-summary.json'), {
- complete: false,
- counts: { pass: 4, fail: 2, pending: 2, blocked_by_external_data: 7 }
- });
- writeJson(path.join(outputs, 'business-proof-next-actions', 'business-proof-next-actions-summary.json'), {
- complete: false,
- sourceState: { progressComplete: false, proofGapOpenCount: 4 },
- actions: [{ title: '填真实历史 Brief' }, { title: '填真实视频资源' }]
- });
- writeJson(path.join(outputs, 'business-execution-index', 'business-execution-index-summary.json'), {
- passed: true,
- directCustomerProof: false,
- rowCount: 7,
- actionRowCount: 3,
- repairRowCount: 2,
- proofOpenCount: 5
- });
- writeJson(path.join(outputs, 'local-seed-material-index', 'local-seed-material-index-summary.json'), {
- proofLevel: 'not_business_proof',
- directCustomerProof: false,
- canCloseProofGap: false,
- materialCount: 4,
- existingMaterialCount: 2,
- promisingLiveAggregateCount: 1
- });
- writeJson(path.join(outputs, 'local-seed-to-intake-worklist', 'local-seed-to-intake-worklist-summary.json'), {
- proofLevel: 'not_business_proof',
- directCustomerProof: false,
- canCloseProofGap: false,
- complete: false,
- counts: {
- historyDraftRows: 1,
- referenceSeedRows: 3,
- candidateSeedRows: 5,
- videoWorklistRows: 4
- }
- });
- writeJson(path.join(outputs, 'real-proof-closure-work-order', 'real-proof-closure-work-order-summary.json'), {
- passed: true,
- complete: false,
- proofLevel: 'not_business_proof',
- materialType: 'real_proof_closure_work_order',
- directCustomerProof: false,
- canCloseProofGap: false,
- requiresHumanRealMaterial: true,
- workOrderCount: 19,
- ownerGroupCount: 3,
- ownerArtifacts: [
- {
- owner: 'business',
- markdown: 'outputs/real-proof-closure-work-order-latest/by-owner/business.md',
- csv: 'outputs/real-proof-closure-work-order-latest/by-owner/business.csv'
- },
- {
- owner: 'business-media',
- markdown: 'outputs/real-proof-closure-work-order-latest/by-owner/business-media.md',
- csv: 'outputs/real-proof-closure-work-order-latest/by-owner/business-media.csv'
- },
- {
- owner: 'tech-ai',
- markdown: 'outputs/real-proof-closure-work-order-latest/by-owner/tech-ai.md',
- csv: 'outputs/real-proof-closure-work-order-latest/by-owner/tech-ai.csv'
- }
- ],
- sourceState: {
- proofGapOpenCount: 5,
- intakeFailureCount: 9,
- realCandidateRows: 0
- }
- });
- writeJson(path.join(outputs, 'real-gap-material-audit', 'real-gap-material-audit-summary.json'), {
- proofLevel: 'not_business_proof',
- materialType: 'three_real_gap_material_audit',
- directCustomerProof: false,
- canCloseProofGap: false,
- complete: false,
- gapCount: 3,
- materialFoundCount: 3,
- openGapCount: 3
- });
- writeJson(path.join(outputs, 'experience-transcript-index', 'experience-transcript-index-summary.json'), {
- proofLevel: 'not_business_proof',
- materialType: 'experience_seed',
- directCustomerProof: false,
- canCloseProofGap: false,
- transcriptCount: 2,
- ruleCount: 8,
- coveredRuleCount: 8
- });
- writeJson(path.join(outputs, 'latest-form-index', 'latest-form-index-summary.json'), {
- passed: true,
- primaryForm: { csv: 'outputs/tihao-proof-gap-software-form-latest/tihao-proof-gap-software-form.csv' },
- clientList: { csv: 'outputs/software-client-latest/software-client-list.final.csv' },
- nextActions: { actionCount: 5, proofOpenCount: 5 }
- });
- writeJson(path.join(outputs, 'intake-readiness-ready', 'intake-readiness-summary.json'), {
- failureCount: 0,
- acceptance: {
- overallReady: true,
- historyReady: true,
- videoReady: true,
- reviewMetricsReady: true,
- customerEffectReady: true
- }
- });
- writeJson(path.join(outputs, 'intake-readiness-template', 'intake-readiness-summary.json'), {
- failureCount: 9,
- acceptance: {
- overallReady: false,
- historyReady: false,
- videoReady: false,
- reviewMetricsReady: false,
- customerEffectReady: false
- }
- });
- fs.writeFileSync(
- path.join(outputs, 'intake-readiness-template', 'intake-readiness-repair-actions.csv'),
- 'owner,action,reason\nbusiness,补齐真实历史 Brief,仍是模板占位\nbusiness,补齐客户选择字段,缺客户选择\n',
- 'utf8'
- );
- const intake = path.join(outputs, 'data-intake-pack');
- fs.mkdirSync(intake, { recursive: true });
- fs.writeFileSync(path.join(intake, 'history-data-template.csv'), 'brief编号,客户原始Brief,历史人工补号量基线\n', 'utf8');
- fs.writeFileSync(path.join(intake, 'manual-review-template.csv'), 'brief编号,客户选择,本轮人工补号量\n', 'utf8');
- fs.writeFileSync(path.join(intake, 'README.md'), '# 数据收集包\n', 'utf8');
- const videoIntake = path.join(outputs, 'video-intake-pack');
- fs.mkdirSync(videoIntake, { recursive: true });
- fs.writeFileSync(path.join(videoIntake, 'video-resource-template.csv'), 'brief编号,视频链接,封面链接,字幕或ASR文本,帧图链接,是否真实资源\n', 'utf8');
- fs.writeFileSync(path.join(videoIntake, 'README.md'), '# 视频资源收集包\n', 'utf8');
- const summary = buildEvidenceIndex({ root, outputsDir: outputs });
- assert(summary.total === 44, 'should classify forty-four evidence entries');
- assert(summary.counts.real_evidence === 6, 'passing live, selected review metrics, strict video A/B, customer effect, detailed history, and closed proof-gap closure should be real evidence');
- assert(summary.counts.not_business_proof === 19, 'incomplete status, failed live, thin history, weak video, video A/B runtime preflight failure, incomplete customer effect, pipeline-scoped customer effect with open proof gaps, missing preflight, failed pipeline, missing video resources, missing homepage evidence, open proof-gap closure, template intake readiness, incomplete completion audit, local seed material index, seed-to-intake worklist, real proof closure work order, real gap material audit, and experience transcript index should not be business proof');
- assert(summary.counts.smoke_or_local === 19, 'ready live preflight, passing pipelines, handoff summary, proof gap request, software proof-gap form, latest form index, round deposition, business proof progress, business proof next actions, business execution index, repair actions, data intake pack, video intake pack, video resource readiness, homepage readiness, and ready intake readiness should be smoke/local startup evidence');
- assert(summary.byType['overnight-quality'] === 2, 'should classify overnight quality');
- assert(summary.byType['customer-effect'] === 3, 'should classify customer effect proof');
- assert(summary.byType['live-preflight'] === 2, 'should classify live preflight readiness');
- assert(summary.byType['optimization-pipeline'] === 3, 'should classify optimization pipeline orchestration');
- assert(summary.byType['historical-dataset'] === 2, 'should classify historical dataset audits');
- assert(summary.byType['optimization-completion'] === 1, 'should classify optimization completion audits');
- assert(summary.byType['optimization-handoff'] === 1, 'should classify optimization handoff summary');
- assert(summary.byType['proof-gap-request'] === 1, 'should classify proof gap request summary');
- assert(summary.byType['proof-gap-closure'] === 2, 'should classify proof gap closure summaries');
- assert(summary.byType['proof-gap-software-form'] === 1, 'should classify proof gap software form summaries');
- assert(summary.byType['latest-form-index'] === 1, 'should classify latest form index summaries');
- assert(summary.byType['round-deposition'] === 1, 'should classify round deposition summary');
- assert(summary.byType['business-proof-progress'] === 1, 'should classify business proof progress summary');
- assert(summary.byType['business-proof-next-actions'] === 1, 'should classify business proof next actions summary');
- assert(summary.byType['business-execution-index'] === 1, 'should classify business execution index summary');
- assert(summary.byType['local-seed-material-index'] === 1, 'should classify local seed material index summary');
- assert(summary.byType['local-seed-to-intake-worklist'] === 1, 'should classify seed-to-intake worklist summary');
- assert(summary.byType['real-proof-closure-work-order'] === 1, 'should classify real proof closure work order summary');
- assert(summary.byType['real-gap-material-audit'] === 1, 'should classify real gap material audit summary');
- assert(summary.byType['experience-transcript-index'] === 1, 'should classify experience transcript index summary');
- assert(summary.byType['intake-readiness'] === 2, 'should classify intake readiness audits');
- assert(summary.byType['data-intake-pack'] === 1, 'should classify data intake pack readiness');
- assert(summary.byType['video-intake-pack'] === 1, 'should classify video intake pack readiness');
- assert(summary.byType['video-resource-readiness'] === 2, 'should classify video resource readiness audits');
- assert(summary.byType['video-ab-runtime-preflight'] === 1, 'should classify video A/B runtime preflight failures');
- assert(summary.byType['homepage-evidence-readiness'] === 2, 'should classify homepage evidence readiness audits');
- assert(summary.byType['intake-repair-actions'] === 1, 'should classify intake repair action CSVs');
- assert(summary.byType['video-resource-repair-actions'] === 1, 'should classify video repair action CSVs');
- assert(summary.byType['homepage-evidence-repair-actions'] === 1, 'should classify homepage evidence repair action CSVs');
- const intakeRepair = summary.entries.find(item => item.type === 'intake-repair-actions');
- assert(intakeRepair.status === 'actions_open' && intakeRepair.summary.includes('actions=2'), 'intake repair actions should expose action count');
- const videoRepair = summary.entries.find(item => item.type === 'video-resource-repair-actions');
- assert(videoRepair.status === 'actions_open' && videoRepair.summary.includes('actions=1'), 'video repair actions should expose action count');
- const homepageRepair = summary.entries.find(item => item.type === 'homepage-evidence-repair-actions');
- assert(homepageRepair.status === 'actions_open' && homepageRepair.summary.includes('actions=1'), 'homepage repair actions should expose action count');
- const businessExecution = summary.entries.find(item => item.type === 'business-execution-index');
- assert(businessExecution.status === 'actions_open' && businessExecution.summary.includes('rows=7') && businessExecution.summary.includes('repairs=2'), 'business execution index should expose row and repair counts');
- const localSeed = summary.entries.find(item => item.type === 'local-seed-material-index');
- assert(localSeed.proofLevel === 'not_business_proof' && localSeed.canCloseProofGap === false, 'local seed material index should preserve proof boundary');
- assert(localSeed.summary.includes('canCloseProofGap=false'), 'local seed material index should expose non-closure boundary');
- const seedWorklist = summary.entries.find(item => item.type === 'local-seed-to-intake-worklist');
- assert(seedWorklist.proofLevel === 'not_business_proof' && seedWorklist.canCloseProofGap === false, 'seed-to-intake worklist should preserve proof boundary');
- assert(seedWorklist.summary.includes('historyDraft=1') && seedWorklist.next.includes('不能替代客户选择'), 'seed-to-intake worklist should expose draft counts and proof boundary');
- const realGapAudit = summary.entries.find(item => item.type === 'real-gap-material-audit');
- assert(realGapAudit.proofLevel === 'not_business_proof' && realGapAudit.canCloseProofGap === false, 'real gap material audit should preserve proof boundary');
- assert(realGapAudit.status === 'open_gaps_have_materials', 'real gap material audit should not close proof gaps');
- assert(realGapAudit.summary.includes('materialFound=3') && realGapAudit.summary.includes('open=3'), 'real gap material audit should expose material coverage and open gaps');
- const realProofClosureWorkOrder = summary.entries.find(item => item.type === 'real-proof-closure-work-order');
- assert(realProofClosureWorkOrder.proofLevel === 'not_business_proof' && realProofClosureWorkOrder.canCloseProofGap === false, 'real proof closure work order should preserve proof boundary');
- assert(realProofClosureWorkOrder.directCustomerProof === false && realProofClosureWorkOrder.complete === false, 'real proof closure work order should not be direct proof or complete');
- assert(realProofClosureWorkOrder.status === 'work_orders_open', 'real proof closure work order should expose open work order status');
- assert(realProofClosureWorkOrder.summary.includes('workOrders=19') && realProofClosureWorkOrder.summary.includes('owners=3'), 'real proof closure work order should expose work order counts');
- assert(realProofClosureWorkOrder.next.includes('工单本身不证明客户效果'), 'real proof closure work order should keep customer-effect boundary in next action');
- const experienceTranscript = summary.entries.find(item => item.type === 'experience-transcript-index');
- assert(experienceTranscript.proofLevel === 'not_business_proof' && experienceTranscript.canCloseProofGap === false, 'experience transcript index should preserve proof boundary');
- assert(experienceTranscript.summary.includes('rules=8/8'), 'experience transcript index should expose rule coverage');
- const openClosurePipeline = summary.entries.find(item => item.type === 'optimization-pipeline' && item.dir.includes('pipeline-claim-with-open-closure'));
- assert(openClosurePipeline.summary.includes('readyForClaim=false'), 'pipeline evidence should not expose readyForClaim=true when closure is open');
- assert(openClosurePipeline.summary.includes('closureOpen=1'), 'pipeline evidence should expose closure open count');
- const standaloneCustomerEffect = summary.entries.find(item => item.type === 'customer-effect' && item.dir.endsWith('/customer-effect'));
- assert(standaloneCustomerEffect.proofLevel === 'real_evidence', 'standalone passing customer-effect should remain real evidence');
- const pipelineCustomerEffect = summary.entries.find(item => item.type === 'customer-effect' && item.dir.includes('pipeline-claim-with-open-closure'));
- assert(pipelineCustomerEffect.proofLevel === 'not_business_proof', 'pipeline-scoped customer-effect should not become real evidence while proof gaps are open');
- assert(pipelineCustomerEffect.pipelineScoped === true && pipelineCustomerEffect.pipelineClaimable === false, 'pipeline-scoped customer-effect should expose non-claimable pipeline context');
- assert(pipelineCustomerEffect.summary.includes('pipelineBlocked=') && pipelineCustomerEffect.summary.includes('proofGapClosure.openCount=1'), 'pipeline-scoped customer-effect should expose pipeline blockers');
- const detailedHistory = summary.entries.find(item => item.type === 'historical-dataset' && item.dir.endsWith('/history-real'));
- assert(detailedHistory.proofLevel === 'real_evidence' && detailedHistory.status === 'ready_for_long_run', 'detailed history audit should be real evidence');
- assert(detailedHistory.summary.includes('missing=0'), 'detailed history audit should expose zero missing requirements');
- const thinHistory = summary.entries.find(item => item.type === 'historical-dataset' && item.dir.endsWith('/history-thin'));
- assert(thinHistory.proofLevel === 'not_business_proof', 'thin history audit should not be real evidence');
- assert(thinHistory.status === 'not_ready', 'thin history audit should not be ready for long run');
- assert(thinHistory.missingProofRequirements.includes('acceptance.allHaveManualFinalList=true'), 'thin history audit should require manual final-list coverage');
- assert(thinHistory.missingProofRequirements.includes('items.length>=5'), 'thin history audit should require auditable item details');
- const completion = summary.entries.find(item => item.type === 'optimization-completion');
- assert(completion.proofLevel === 'not_business_proof' && completion.status === 'incomplete', 'incomplete completion audit should not be business proof');
- assert(completion.summary.includes('readyForClaim=false') && completion.next.includes('不能宣称提号率提升'), 'completion evidence should expose claim boundary');
- console.log(JSON.stringify({ ok: true, total: summary.total, counts: summary.counts }, null, 2));
- }
- function writeJson(file, value) {
- fs.mkdirSync(path.dirname(file), { recursive: true });
- fs.writeFileSync(file, JSON.stringify(value, null, 2), 'utf8');
- }
- 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: []
- }))
- };
- }
- function assert(condition, message) {
- if (!condition) throw new Error(message);
- }
- if (require.main === module) main();
|