| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- #!/usr/bin/env node
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const { spawnSync } = require('child_process');
- const ROOT = path.resolve(__dirname, '..');
- function main() {
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-round-refresh-'));
- const outputRoot = path.join(temp, 'outputs');
- seedRequiredOutputs(outputRoot);
- const result = spawnSync(process.execPath, ['scripts/refresh-round-artifacts.js', '--output-root', outputRoot, '--strict'], {
- cwd: ROOT,
- encoding: 'utf8',
- shell: false
- });
- if (result.stdout) process.stdout.write(result.stdout);
- if (result.stderr) process.stderr.write(result.stderr);
- assert(result.status === 0, 'round refresh command should pass');
- const refresh = readJson(path.join(outputRoot, 'round-refresh-summary.json'));
- const form = readJson(path.join(outputRoot, 'tihao-proof-gap-software-form-latest', 'tihao-proof-gap-software-form-summary.json'));
- const proofGap = readJson(path.join(outputRoot, 'proof-gap-request-latest', 'proof-gap-request-summary.json'));
- const closure = readJson(path.join(outputRoot, 'proof-gap-closure-latest', 'proof-gap-closure-summary.json'));
- const feedbackClosure = readJson(path.join(outputRoot, 'feedback-loop-closure-latest', 'feedback-loop-closure-summary.json'));
- const homepageReadiness = readJson(path.join(outputRoot, 'homepage-evidence-readiness-latest', 'homepage-evidence-readiness-summary.json'));
- const intakeReadiness = readJson(path.join(outputRoot, 'intake-readiness-latest', 'intake-readiness-summary.json'));
- const videoReadiness = readJson(path.join(outputRoot, 'video-resource-readiness-latest', 'video-resource-readiness-summary.json'));
- const livePreflight = readJson(path.join(outputRoot, 'live-preflight-latest', 'live-preflight-summary.json'));
- const longRunReadiness = readJson(path.join(outputRoot, 'long-run-readiness-latest', 'long-run-readiness-summary.json'));
- const fieldChecklist = readJson(path.join(outputRoot, 'intake-field-checklist-latest', 'intake-field-checklist-summary.json'));
- const manualReviewLabelGuide = readJson(path.join(outputRoot, 'manual-review-label-guide-latest', 'manual-review-label-guide-summary.json'));
- const progress = readJson(path.join(outputRoot, 'business-proof-progress-latest', 'business-proof-progress-summary.json'));
- const nextActions = readJson(path.join(outputRoot, 'business-proof-next-actions-latest', 'business-proof-next-actions-summary.json'));
- const businessExecution = readJson(path.join(outputRoot, 'business-execution-index-latest', 'business-execution-index-summary.json'));
- const status = readJson(path.join(outputRoot, 'optimization-status-latest', 'optimization-status-summary.json'));
- const evidence = readJson(path.join(outputRoot, 'evidence-index-latest', 'evidence-index-summary.json'));
- const handoff = readJson(path.join(outputRoot, 'optimization-handoff-latest', 'optimization-handoff-summary.json'));
- const completion = readJson(path.join(outputRoot, 'optimization-completion-latest', 'optimization-completion-summary.json'));
- const planExecution = readJson(path.join(outputRoot, 'plan-execution-status-latest', 'plan-execution-status-summary.json'));
- const operatorPack = readJson(path.join(outputRoot, 'proof-gap-operator-pack-latest', 'proof-gap-operator-pack-summary.json'));
- const intakeBundle = readJson(path.join(outputRoot, 'real-proof-intake-bundle-latest', 'real-proof-intake-bundle-summary.json'));
- const softwareRefresh = readJson(path.join(outputRoot, 'software-client-latest', 'software-client-refresh-summary.json'));
- const softwareClient = readJson(path.join(outputRoot, 'software-client-latest', 'software-client-list.final.summary.json'));
- const latestForm = readJson(path.join(outputRoot, 'latest-form-index-latest', 'latest-form-index-summary.json'));
- const localSeed = readJson(path.join(outputRoot, 'local-seed-material-index-latest', 'local-seed-material-index-summary.json'));
- const seedWorklist = readJson(path.join(outputRoot, 'local-seed-to-intake-worklist-latest', 'local-seed-to-intake-worklist-summary.json'));
- const realGapMaterialAudit = readJson(path.join(outputRoot, 'real-gap-material-audit-latest', 'real-gap-material-audit-summary.json'));
- const realProofClosureWorkOrder = readJson(path.join(outputRoot, 'real-proof-closure-work-order-latest', 'real-proof-closure-work-order-summary.json'));
- const experienceTranscript = readJson(path.join(outputRoot, 'experience-transcript-index-latest', 'experience-transcript-index-summary.json'));
- const round = readJson(path.join(outputRoot, 'round-deposition-latest', 'round-deposition-summary.json'));
- const expectedOwnerArtifactCount = Number(operatorPack.ownerArtifactCount || operatorPack.ownerArtifacts?.length || 0);
- const expectedBusinessOwnerArtifactRows = Number(businessExecution.operatorPackOwnerArtifactRowCount || expectedOwnerArtifactCount);
- const expectedWorkOrderCount = Number(realProofClosureWorkOrder.workOrderCount || 0);
- const expectedProofGapOpenCount = Number(closure.openCount || 0);
- const expectedIntakeFailureCount = Number(intakeReadiness.failureCount || 0);
- const expectedRealCandidateRows = Number(videoReadiness.counts?.realCandidateRows || 0);
- assert(refresh.passed === true, 'refresh summary should pass');
- assert(refresh.steps.length === 29, 'refresh should run twenty-nine ordered steps');
- assert(refresh.steps.map(item => item.id).join(',') === 'proof-gap-software-form,proof-gap-request,proof-gap-closure,feedback-loop-closure,homepage-evidence-readiness,intake-readiness,video-resource-readiness,live-preflight,longrun-readiness,intake-field-checklist,manual-review-label-guide,proof-gap-operator-pack,business-proof-progress,business-proof-next-actions,optimization-completion,business-execution-index,optimization-status,plan-execution-status,real-proof-intake-bundle,software-client-list,local-seed-material-index,local-seed-to-intake-worklist,real-gap-material-audit,real-proof-closure-work-order,latest-form-index,optimization-handoff,experience-transcript-index,evidence-index,round-deposition', 'refresh order should be stable');
- assert(form.passed === true && form.rowCount === 5 && form.duplicateIdCount === 0, 'software proof-gap form should pass');
- assert(proofGap.unresolvedCount >= 1, 'proof gap request should refresh unresolved gaps');
- assert(closure.openCount >= 1 && closure.complete === false, 'proof gap closure should refresh open gaps');
- assert(feedbackClosure.complete === false && feedbackClosure.directCustomerProof === false, 'feedback loop closure should keep proof boundary');
- assert(homepageReadiness.directCustomerProof === false, 'homepage readiness should keep proof boundary');
- assert(homepageReadiness.proofLevel === 'not_business_proof' || homepageReadiness.proofLevel === 'smoke_or_local', 'homepage readiness should classify proof level');
- assert(intakeReadiness.acceptance?.overallReady === false && intakeReadiness.failureCount >= 1, 'intake readiness should refresh current incomplete real-material state');
- assertVideoResourceReadiness(videoReadiness);
- assert(typeof livePreflight.readyForLiveAcceptance === 'boolean', 'live preflight should refresh live acceptance readiness');
- assert(typeof livePreflight.readyForVideoAb === 'boolean', 'live preflight should refresh video A/B readiness');
- assert(livePreflight.strict === true && livePreflight.allowFailure === true, 'round refresh live preflight should run strict checks without failing the refresh');
- assert(longRunReadiness.ready === false && Number(longRunReadiness.counts?.fail || 0) >= 1, 'longrun readiness should refresh blocked full-matrix gate');
- assert(refresh.artifacts.intakeReadiness?.includes('intake-readiness-summary.json'), 'refresh artifacts should expose intake readiness summary');
- assert(refresh.artifacts.videoResourceReadiness?.includes('video-resource-readiness-summary.json'), 'refresh artifacts should expose video resource readiness summary');
- assert(refresh.artifacts.livePreflight?.includes('live-preflight-summary.json'), 'refresh artifacts should expose live preflight summary');
- assert(refresh.artifacts.longRunReadiness?.includes('long-run-readiness-summary.json'), 'refresh artifacts should expose longrun readiness summary');
- assert(fieldChecklist.passed === true && fieldChecklist.itemCount >= 1, 'field checklist should refresh field-level intake gaps');
- assert(fieldChecklist.directCustomerProof === false, 'field checklist should keep proof boundary');
- assert(manualReviewLabelGuide.passed === true, 'manual review label guide should refresh');
- assert(manualReviewLabelGuide.directCustomerProof === false, 'manual review label guide should keep proof boundary');
- assert(manualReviewLabelGuide.negativeLabelsRequireAttribution === true, 'manual review label guide should require negative attribution');
- assert(manualReviewLabelGuide.attributionTypeCount >= 8, 'manual review label guide should expose attribution types');
- assert(progress.complete === false && progress.counts.blocked_by_external_data >= 1, 'business proof progress should refresh incomplete proof state');
- assert(progress.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'business proof progress should expose operator owner attachments');
- assert(progress.operatorPackOwnerArtifacts?.some(item => item.csv?.includes('by-owner/business.csv')), 'business proof progress should expose business operator owner csv');
- assert(nextActions.complete === false && nextActions.actions.length >= 1, 'business proof next actions should refresh actionable queue');
- assert(businessExecution.passed === true && businessExecution.rowCount >= 1, 'business execution index should refresh executable business table');
- assert(businessExecution.directCustomerProof === false, 'business execution index should keep proof boundary');
- assert(businessExecution.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'business execution index should expose operator pack owner attachments');
- assert(businessExecution.sourceFiles?.longRunReadiness?.includes('long-run-readiness-summary.json'), 'business execution index should expose longrun readiness source');
- assert(businessExecution.rows?.some(row => row.title?.includes('长跑前置门禁') && row.mainFile?.includes('long-run-readiness-report.md')), 'business execution index should expose longrun readiness report row');
- assert(businessExecution.sourceFiles?.optimizationCompletion?.includes('optimization-completion-summary.json'), 'business execution index should expose optimization completion source');
- assert(businessExecution.rows?.some(row => row.title?.includes('优化完成度审计') && row.mainFile?.includes('optimization-completion-report.md')), 'business execution index should expose optimization completion report row');
- assert(status.complete === false && status.counts.ready_not_proven >= 1, 'status should preserve unfinished boundary');
- assert(completion.complete === false && completion.readyForClaim === false, 'completion audit should preserve unfinished boundary');
- assert(completion.proofGapOpenCount >= 1, 'completion audit should expose open proof gaps');
- assert(completion.canClaim.tihaoRateImproved === false, 'completion audit should forbid tihao-rate claim');
- assert(completion.canClaim.customerEffectAchieved === false, 'completion audit should forbid customer-effect claim');
- assert(completion.canClaim.manualSupplementReduced === false, 'completion audit should forbid manual-supplement claim');
- assert(evidence.byType['proof-gap-software-form'] === 1, 'evidence index should classify latest software form');
- assert(evidence.byType['optimization-completion'] === 1, 'evidence index should classify completion audit');
- assert(evidence.byType['proof-gap-operator-pack'] === 1, 'evidence index should classify proof gap operator pack');
- assert(evidence.byType['real-proof-intake-bundle'] === 1, 'evidence index should classify real proof intake bundle');
- assert(evidence.byType['local-seed-material-index'] === 1, 'evidence index should classify local seed material index');
- assert(evidence.byType['local-seed-to-intake-worklist'] === 1, 'evidence index should classify seed-to-intake worklist');
- assert(evidence.byType['real-gap-material-audit'] === 1, 'evidence index should classify real gap material audit');
- assert(evidence.byType['real-proof-closure-work-order'] === 1, 'evidence index should classify real proof closure work order');
- assert(evidence.byType['experience-transcript-index'] === 1, 'evidence index should classify experience transcript index');
- assert(evidence.byType['feedback-loop-closure'] === 1, 'evidence index should classify feedback loop closure');
- assert(evidence.byType['homepage-evidence-readiness'] === 1, 'evidence index should classify homepage readiness');
- assert(evidence.byType['intake-field-checklist'] === 1, 'evidence index should classify field checklist');
- assert(evidence.counts.smoke_or_local >= 1, 'evidence index should include smoke/local evidence');
- assert(handoff.proofGapSoftwareForm?.passed === true, 'handoff should expose proof-gap software form');
- assert(handoff.feedbackLoopClosure?.directCustomerProof === false, 'handoff should expose feedback loop proof boundary');
- assert(handoff.homepageEvidenceReadiness?.directCustomerProof === false, 'handoff should expose homepage readiness proof boundary');
- assert(handoff.latestFormIndex?.passed === true, 'handoff should expose latest form index');
- assert(handoff.supportDocs?.some(item => item.doc?.includes('tihao-handoff-index.md')), 'handoff should expose task handoff index doc');
- assert(handoff.latestFormIndex?.manualReviewLabelGuide?.markdown?.includes('manual-review-label-guide.md'), 'handoff should expose manual review label guide');
- assert(handoff.latestFormIndex?.planExecutionStatus?.markdown?.includes('plan-execution-status.md'), 'handoff latest form index should expose plan execution status');
- assert(handoff.planExecutionStatus?.markdown?.includes('plan-execution-status.md'), 'handoff should expose top-level plan execution status');
- assert(handoff.planExecutionStatus?.complete === false, 'handoff plan execution status should keep incomplete boundary');
- assert(handoff.planExecutionStatus?.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'handoff plan execution status should expose operator owner attachments');
- assert(handoff.latestFormIndex?.planExecutionStatus?.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'handoff latest form plan execution status should expose operator owner attachments');
- assert(handoff.latestFormIndex?.proofGapRequest?.markdown?.includes('proof-gap-request-report.md'), 'handoff latest form index should expose proof gap request');
- assert(handoff.proofGapRequest?.markdown?.includes('proof-gap-request-report.md'), 'handoff should expose top-level proof gap request');
- assert(handoff.latestFormIndex?.proofGapOperatorPack?.markdown?.includes('proof-gap-operator-pack.md'), 'handoff latest form index should expose proof gap operator pack');
- assert(handoff.proofGapOperatorPack?.markdown?.includes('proof-gap-operator-pack.md'), 'handoff should expose top-level proof gap operator pack');
- assert(handoff.latestFormIndex?.realProofIntakeBundle?.markdown?.includes('real-proof-intake-bundle.md'), 'handoff latest form index should expose real proof intake bundle');
- assert(handoff.realProofIntakeBundle?.markdown?.includes('real-proof-intake-bundle.md'), 'handoff should expose top-level real proof intake bundle');
- assert(latestForm.realProofClosureWorkOrder?.markdown?.includes('real-proof-closure-work-order.md'), 'latest form index should expose real proof closure work order report');
- assert(latestForm.realProofClosureWorkOrder?.csv?.includes('real-proof-closure-work-order.csv'), 'latest form index should expose real proof closure work order csv');
- assert(latestForm.realProofClosureWorkOrder?.summary?.includes('real-proof-closure-work-order-summary.json'), 'latest form index should expose real proof closure work order summary');
- assert(latestForm.realProofClosureWorkOrder?.directCustomerProof === false, 'latest form real proof closure work order should keep proof boundary');
- assert(latestForm.realProofClosureWorkOrder?.proofLevel === 'not_business_proof', 'latest form real proof closure work order should keep proof level');
- assert(latestForm.realProofClosureWorkOrder?.materialType === 'real_proof_closure_work_order', 'latest form real proof closure work order should expose material type');
- assert(latestForm.realProofClosureWorkOrder?.complete === false, 'latest form real proof closure work order should not claim completion');
- assert(latestForm.realProofClosureWorkOrder?.canCloseProofGap === false, 'latest form real proof closure work order should not close proof gaps');
- assert(latestForm.realProofClosureWorkOrder?.workOrderCount === expectedWorkOrderCount, 'latest form real proof closure work order should expose work order count');
- assert(latestForm.realProofClosureWorkOrder?.ownerArtifacts?.length === expectedOwnerArtifactCount, 'latest form real proof closure work order should expose owner artifacts');
- assert(handoff.realProofClosureWorkOrder?.markdown?.includes('real-proof-closure-work-order.md'), 'handoff should expose top-level real proof closure work order');
- assert(handoff.realProofClosureWorkOrder?.workOrderCount === expectedWorkOrderCount, 'handoff real proof closure work order should expose work order count');
- assert(handoff.realProofClosureWorkOrder?.canCloseProofGap === false, 'handoff real proof closure work order should not close proof gaps');
- assert(handoff.realProofClosureWorkOrder?.ownerArtifacts?.some(item => item.csv?.includes('by-owner/business.csv')), 'handoff real proof closure work order should expose business owner csv');
- assert(handoff.latestFormIndex?.realProofClosureWorkOrder?.markdown?.includes('real-proof-closure-work-order.md'), 'handoff latest form index should expose real proof closure work order');
- assert(handoff.latestFormIndex?.realProofClosureWorkOrder?.workOrderCount === expectedWorkOrderCount, 'handoff latest form real proof closure work order should expose work order count');
- assert(handoff.latestFormIndex?.realProofClosureWorkOrder?.ownerArtifacts?.some(item => item.markdown?.includes('by-owner/tech-ai.md')), 'handoff latest form real proof closure work order should expose tech owner markdown');
- assert(latestForm.localSeedToIntakeWorklist?.markdown?.includes('local-seed-to-intake-worklist.md'), 'latest form index should expose seed-to-intake worklist report');
- assert(latestForm.localSeedToIntakeWorklist?.historyDraft?.includes('history-intake-draft.csv'), 'latest form index should expose seed-to-intake history draft');
- assert(latestForm.localSeedToIntakeWorklist?.videoWorklist?.includes('video-resource-worklist.csv'), 'latest form index should expose seed-to-intake video worklist');
- assert(latestForm.localSeedToIntakeWorklist?.candidateWorklist?.includes('candidate-seed-worklist.csv'), 'latest form index should expose seed-to-intake candidate worklist');
- assert(latestForm.localSeedToIntakeWorklist?.directCustomerProof === false, 'latest form seed-to-intake worklist should keep proof boundary');
- assert(latestForm.localSeedToIntakeWorklist?.canCloseProofGap === false, 'latest form seed-to-intake worklist should not close proof gaps');
- assert(Number(latestForm.localSeedToIntakeWorklist?.candidateSeedRows || 0) >= 1, 'latest form seed-to-intake worklist should expose candidate seed rows');
- assert(latestForm.realGapMaterialAudit?.markdown?.includes('real-gap-material-audit.md'), 'latest form index should expose real gap material audit report');
- assert(latestForm.realGapMaterialAudit?.summary?.includes('real-gap-material-audit-summary.json'), 'latest form index should expose real gap material audit summary');
- assert(latestForm.realGapMaterialAudit?.materialType === 'three_real_gap_material_audit', 'latest form real gap material audit should classify material type');
- assert(latestForm.realGapMaterialAudit?.directCustomerProof === false, 'latest form real gap material audit should keep proof boundary');
- assert(latestForm.realGapMaterialAudit?.canCloseProofGap === false, 'latest form real gap material audit should not close proof gaps');
- assert(latestForm.realGapMaterialAudit?.materialFoundCount === realGapMaterialAudit.materialFoundCount, 'latest form real gap material audit should expose material coverage count');
- assert(handoff.localSeedToIntakeWorklist?.markdown?.includes('local-seed-to-intake-worklist.md'), 'handoff should expose top-level seed-to-intake worklist');
- assert(handoff.latestFormIndex?.localSeedToIntakeWorklist?.historyDraft?.includes('history-intake-draft.csv'), 'handoff latest form index should expose seed-to-intake history draft');
- assert(handoff.latestFormIndex?.localSeedToIntakeWorklist?.directCustomerProof === false, 'handoff latest form seed-to-intake worklist should keep proof boundary');
- assert(handoff.realGapMaterialAudit?.markdown?.includes('real-gap-material-audit.md'), 'handoff should expose top-level real gap material audit');
- assert(handoff.realGapMaterialAudit?.materialFoundCount === realGapMaterialAudit.materialFoundCount, 'handoff real gap material audit should expose material coverage count');
- assert(handoff.realGapMaterialAudit?.canCloseProofGap === false, 'handoff real gap material audit should not close proof gaps');
- assert(handoff.latestFormIndex?.realGapMaterialAudit?.summary?.includes('real-gap-material-audit-summary.json'), 'handoff latest form index should expose real gap material audit');
- assert(planExecution.passed === true, 'plan execution status should pass');
- assert(planExecution.complete === false, 'plan execution status should not claim completion');
- assert(planExecution.rowCount === 8, 'plan execution status should map eight plan sections');
- assert(planExecution.proofOpenCount >= 1, 'plan execution status should expose open proof gaps');
- assert(planExecution.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'plan execution status should expose operator owner attachments');
- assert(planExecution.businessExecutionOperatorPackOwnerArtifactRowCount === expectedBusinessOwnerArtifactRows, 'plan execution status should expose business execution operator rows');
- assert(planExecution.rows.some(row => row.section === '关键差距' && row.status === 'open'), 'plan execution status should keep key gaps open');
- assert(planExecution.guardrails.some(item => item.includes('不证明客户效果')), 'plan execution status should keep proof boundary');
- assert(latestForm.primaryForm?.passed === true, 'latest form index should expose passed proof-gap form');
- assert(latestForm.supportDocs?.some(item => item.path?.includes('tihao-handoff-index.md')), 'latest form index should expose task handoff index doc');
- assert(operatorPack.passed === true && operatorPack.rowCount === 5 && operatorPack.openCount >= 1, 'proof gap operator pack should pass and keep open gaps');
- assert(operatorPack.directCustomerProof === false, 'proof gap operator pack should not be direct customer proof');
- assert(intakeBundle.passed === true && intakeBundle.proofOpenCount >= 1 && intakeBundle.fillRowCount >= 3, 'real proof intake bundle should pass and expose fill rows');
- assert(intakeBundle.directCustomerProof === false, 'real proof intake bundle should not be direct customer proof');
- assert(intakeBundle.templateFiles?.some(item => item.path?.includes('long-run-readiness-report.md')), 'real proof intake bundle should expose longrun readiness report');
- assert(intakeBundle.recheckCommands?.some(item => item.command?.includes('longrun:readiness')), 'real proof intake bundle should expose longrun readiness recheck command');
- assert(intakeBundle.sourceState?.longRunReadinessReady === false, 'real proof intake bundle should expose longrun ready=false');
- assert(Number(intakeBundle.sourceState?.longRunReadinessFailCount || 0) >= 1, 'real proof intake bundle should expose longrun fail count');
- assert(softwareRefresh.passed === true && softwareRefresh.skipped === false, 'software client list should refresh from latest manual review sample');
- assert(softwareRefresh.sourceDuplicateRemovedCount >= 0, 'software client refresh should expose source duplicate rows removed');
- assert(softwareRefresh.finalDuplicateGroupCount === 0, 'software client refresh should keep final duplicate groups at zero');
- assert(softwareRefresh.duplicateCountMeaning === 'source_duplicate_removed_count', 'software client refresh should define duplicate count meaning');
- assert(softwareRefresh.rankContinuous === true, 'software client refresh should keep rank continuity');
- assert(softwareClient.finalDuplicateGroupCount === 0, 'software client summary should keep zero final duplicate groups');
- assert(refresh.artifacts.softwareClientList?.includes('software-client-refresh-summary.json'), 'refresh artifacts should expose software client refresh summary');
- assert(latestForm.manualReviewLabelGuide?.markdown?.includes('manual-review-label-guide.md'), 'latest form index should expose manual review label guide');
- assert(latestForm.planExecutionStatus?.markdown?.includes('plan-execution-status.md'), 'latest form index should expose plan execution status');
- assert(latestForm.planExecutionStatus?.rowCount === 8, 'latest form index should expose plan execution row count');
- assert(latestForm.planExecutionStatus?.complete === false, 'latest form index should keep plan execution incomplete boundary');
- assert(latestForm.planExecutionStatus?.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'latest form index should expose plan execution operator owner attachments');
- assert(latestForm.proofGapRequest?.markdown?.includes('proof-gap-request-report.md'), 'latest form index should expose proof gap request');
- assert(latestForm.proofGapRequest?.directCustomerProof === false, 'latest form index should keep proof gap request proof boundary');
- assert(latestForm.proofGapOperatorPack?.markdown?.includes('proof-gap-operator-pack.md'), 'latest form index should expose proof gap operator pack');
- assert(latestForm.proofGapOperatorPack?.directCustomerProof === false, 'latest form index should keep operator pack proof boundary');
- assert(latestForm.businessExecutionIndex?.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'latest form index should expose business execution operator owner attachments');
- assert(latestForm.realProofIntakeBundle?.markdown?.includes('real-proof-intake-bundle.md'), 'latest form index should expose real proof intake bundle');
- assert(latestForm.realProofIntakeBundle?.directCustomerProof === false, 'latest form index should keep real proof intake bundle proof boundary');
- assert(localSeed.directCustomerProof === false, 'local seed material index should keep proof boundary');
- assert(localSeed.canCloseProofGap === false, 'local seed material index should not close proof gaps');
- assert(refresh.artifacts.localSeedMaterialIndex?.includes('local-seed-material-index-summary.json'), 'refresh artifacts should expose local seed material index');
- assert(seedWorklist.directCustomerProof === false, 'seed-to-intake worklist should keep proof boundary');
- assert(seedWorklist.canCloseProofGap === false, 'seed-to-intake worklist should not close proof gaps');
- assert(seedWorklist.materialType === 'seed_to_intake_worklist', 'seed-to-intake worklist should classify material type');
- assert(refresh.artifacts.localSeedToIntakeWorklist?.includes('local-seed-to-intake-worklist-summary.json'), 'refresh artifacts should expose seed-to-intake worklist');
- assert(realGapMaterialAudit.materialType === 'three_real_gap_material_audit', 'real gap material audit should classify material type');
- assert(realGapMaterialAudit.proofLevel === 'not_business_proof', 'real gap material audit should keep proof boundary');
- assert(realGapMaterialAudit.directCustomerProof === false, 'real gap material audit should not be direct customer proof');
- assert(realGapMaterialAudit.canCloseProofGap === false, 'real gap material audit should not close proof gaps');
- assert(realGapMaterialAudit.complete === false, 'real gap material audit should not claim completion');
- assert(realGapMaterialAudit.gapCount === 3 && realGapMaterialAudit.materialFoundCount === 3 && realGapMaterialAudit.openGapCount >= 1, 'real gap material audit should expose three covered but still-open gaps');
- assert(refresh.artifacts.realGapMaterialAudit?.includes('real-gap-material-audit-summary.json'), 'refresh artifacts should expose real gap material audit');
- assert(realProofClosureWorkOrder.passed === true, 'real proof closure work order should pass');
- assert(realProofClosureWorkOrder.complete === false, 'real proof closure work order should not claim completion');
- assert(realProofClosureWorkOrder.proofLevel === 'not_business_proof', 'real proof closure work order should keep not-business-proof level');
- assert(realProofClosureWorkOrder.directCustomerProof === false, 'real proof closure work order should not be direct customer proof');
- assert(realProofClosureWorkOrder.canCloseProofGap === false, 'real proof closure work order should not close proof gaps');
- assert(realProofClosureWorkOrder.materialType === 'real_proof_closure_work_order', 'real proof closure work order should classify material type');
- assert(realProofClosureWorkOrder.workOrderCount === expectedWorkOrderCount, 'real proof closure work order should expose current work orders');
- assert(realProofClosureWorkOrder.ownerArtifacts?.length === expectedOwnerArtifactCount, 'real proof closure work order should expose current owner artifacts');
- assert(realProofClosureWorkOrder.ownerArtifacts.some(item => item.markdown?.includes('by-owner/business.md') && item.csv?.includes('by-owner/business.csv')), 'real proof closure work order should expose business owner files');
- if (realProofClosureWorkOrder.ownerArtifacts.some(item => item.owner === '商务/投放')) {
- assert(realProofClosureWorkOrder.ownerArtifacts.some(item => item.markdown?.includes('by-owner/business-media.md') && item.csv?.includes('by-owner/business-media.csv')), 'real proof closure work order should expose business/media owner files when present');
- }
- assert(realProofClosureWorkOrder.ownerArtifacts.some(item => item.markdown?.includes('by-owner/tech-ai.md') && item.csv?.includes('by-owner/tech-ai.csv')), 'real proof closure work order should expose tech/AI owner files');
- assert(realProofClosureWorkOrder.sourceState?.proofGapOpenCount === expectedProofGapOpenCount, 'real proof closure work order should expose open proof gap count');
- assert(realProofClosureWorkOrder.sourceState?.intakeFailureCount === expectedIntakeFailureCount, 'real proof closure work order should expose intake failures');
- assert(realProofClosureWorkOrder.sourceState?.realCandidateRows === expectedRealCandidateRows, 'real proof closure work order should expose real candidate rows');
- assert(refresh.artifacts.realProofClosureWorkOrder?.includes('real-proof-closure-work-order-summary.json'), 'refresh artifacts should expose real proof closure work order');
- assert(experienceTranscript.directCustomerProof === false, 'experience transcript index should keep proof boundary');
- assert(experienceTranscript.canCloseProofGap === false, 'experience transcript index should not close proof gaps');
- assert(experienceTranscript.materialType === 'experience_seed', 'experience transcript index should classify as experience seed');
- assert(refresh.artifacts.experienceTranscriptIndex?.includes('experience-transcript-index-summary.json'), 'refresh artifacts should expose experience transcript index');
- assert(latestForm.manualReviewLabelGuide?.negativeLabelsRequireAttribution === true, 'latest form index should keep negative attribution rule');
- assert(latestForm.clientList?.csv?.includes('software-client-list.final.csv'), 'latest form index should expose software client list when present');
- assert(latestForm.clientList?.directCustomerProof === false, 'latest form index should keep candidate list proof boundary');
- assert(latestForm.clientList?.finalDuplicateGroupCount === 0, 'latest form index should expose zero final duplicate groups');
- assert(latestForm.clientList?.duplicateCountMeaning === 'source_duplicate_removed_count', 'latest form index should expose duplicate count meaning');
- assert(latestForm.repairActions?.dataIntake?.csv?.includes('intake-readiness-repair-actions.csv'), 'latest form index should expose data intake repair actions');
- assert(latestForm.repairActions?.videoResource?.csv?.includes('video-resource-repair-actions.csv'), 'latest form index should expose video resource repair actions');
- assert(handoff.latestFormIndex?.repairActions?.dataIntake?.csv?.includes('intake-readiness-repair-actions.csv'), 'handoff should expose data intake repair actions');
- assert(handoff.latestFormIndex?.repairActions?.videoResource?.csv?.includes('video-resource-repair-actions.csv'), 'handoff should expose video resource repair actions');
- assert(handoff.businessExecutionIndex?.longRunReadiness?.report?.includes('long-run-readiness-report.md'), 'handoff should expose business execution longrun readiness report row');
- assert(handoff.businessExecutionIndex?.longRunReadiness?.status === 'blocked', 'handoff should expose business execution longrun blocked status');
- assert(handoff.businessExecutionIndex?.operatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'handoff should expose business execution operator owner attachments');
- assert(round.passed === true, 'round deposition should pass');
- assert(round.observed.proofGapSoftwareFormPassed === true, 'round deposition should observe software form');
- assert(round.observed.manualReviewLabelGuidePassed === true, 'round deposition should observe manual review label guide');
- assert(round.observed.latestFormIndexManualReviewLabelGuide?.includes('manual-review-label-guide.md'), 'round deposition should observe indexed manual review label guide');
- assert(round.observed.latestFormIndexPlanExecutionStatus?.includes('plan-execution-status.md'), 'round deposition should observe indexed plan execution status');
- assert(round.observed.planExecutionStatusRowCount === 8, 'round deposition should observe plan execution row count');
- assert(round.observed.planExecutionStatusComplete === false, 'round deposition should observe plan execution incomplete boundary');
- assert(round.observed.planExecutionStatusProofOpenCount >= 1, 'round deposition should observe plan execution proof open count');
- assert(round.observed.latestFormIndexDataRepairCsv?.includes('intake-readiness-repair-actions.csv'), 'round deposition should observe data intake repair csv');
- assert(round.observed.latestFormIndexVideoRepairCsv?.includes('video-resource-repair-actions.csv'), 'round deposition should observe video resource repair csv');
- assert(round.observed.latestFormIndexClientListFinalDuplicateGroupCount === 0, 'round deposition should observe zero final duplicate groups');
- assert(round.observed.latestFormIndexClientListDuplicateCountMeaning === 'source_duplicate_removed_count', 'round deposition should observe duplicate count meaning');
- assert(round.observed.businessExecutionIndexLongRunReadinessReport?.includes('long-run-readiness-report.md'), 'round deposition should observe business execution longrun readiness report');
- assert(round.observed.businessExecutionIndexOperatorPackOwnerArtifactCount === expectedOwnerArtifactCount, 'round deposition should observe business execution operator owner attachment count');
- assert(round.observed.handoffBusinessExecutionIndexLongRunReadinessReport?.includes('long-run-readiness-report.md'), 'round deposition should observe handoff business execution longrun readiness report');
- assert(round.observed.handoffBusinessExecutionIndexLongRunReadinessStatus === 'blocked', 'round deposition should observe handoff business execution longrun blocked status');
- assert(round.observed.realProofIntakeBundleLongRunReadinessReport?.includes('long-run-readiness-report.md'), 'round deposition should observe real proof bundle longrun readiness report');
- assert(round.observed.realProofIntakeBundleLongRunReadinessReady === false, 'round deposition should observe real proof bundle longrun ready=false');
- assert(round.observed.realProofClosureWorkOrderWorkOrderCount === expectedWorkOrderCount, 'round deposition should observe real proof closure work order count');
- assert(round.observed.realProofClosureWorkOrderCanCloseProofGap === false, 'round deposition should observe real proof closure work order boundary');
- assert(round.observed.realProofClosureWorkOrderOwnerArtifactCount === expectedOwnerArtifactCount, 'round deposition should observe real proof closure work order owner artifacts');
- assert(round.observed.latestFormIndexRealProofClosureWorkOrderMarkdown?.includes('real-proof-closure-work-order.md'), 'round deposition should observe latest form real proof closure work order');
- assert(round.observed.handoffRealProofClosureWorkOrderMarkdown?.includes('real-proof-closure-work-order.md'), 'round deposition should observe handoff real proof closure work order');
- assert(round.observed.handoffLatestFormIndexRealProofClosureWorkOrderMarkdown?.includes('real-proof-closure-work-order.md'), 'round deposition should observe handoff latest form real proof closure work order');
- assert(round.observed.realGapMaterialAuditMaterialFoundCount === realGapMaterialAudit.materialFoundCount, 'round deposition should observe real gap material audit coverage');
- assert(round.observed.realGapMaterialAuditCanCloseProofGap === false, 'round deposition should observe real gap material audit non-closure boundary');
- assert(round.observed.latestFormIndexRealGapMaterialAuditMarkdown?.includes('real-gap-material-audit.md'), 'round deposition should observe latest form real gap material audit');
- assert(round.observed.handoffRealGapMaterialAuditMarkdown?.includes('real-gap-material-audit.md'), 'round deposition should observe handoff real gap material audit');
- assert(round.observed.evidenceByType['proof-gap-software-form'] === 1, 'round deposition should read refreshed evidence index');
- assert(round.observed.evidenceByType['optimization-completion'] === 1, 'round deposition should read completion audit evidence index');
- assert(round.observed.evidenceByType['proof-gap-operator-pack'] === 1, 'round deposition should read operator pack evidence index');
- assert(round.observed.evidenceByType['real-proof-intake-bundle'] === 1, 'round deposition should read real proof intake bundle evidence index');
- assert(round.observed.evidenceByType['local-seed-material-index'] === 1, 'round deposition should read local seed material evidence index');
- assert(round.observed.evidenceByType['local-seed-to-intake-worklist'] === 1, 'round deposition should read seed-to-intake worklist evidence index');
- assert(round.observed.evidenceByType['real-gap-material-audit'] === 1, 'round deposition should read real gap material audit evidence index');
- assert(round.observed.evidenceByType['real-proof-closure-work-order'] === 1, 'round deposition should read real proof closure work order evidence index');
- assert(round.observed.evidenceByType['experience-transcript-index'] === 1, 'round deposition should read experience transcript evidence index');
- assert(round.observed.evidenceByType['feedback-loop-closure'] === 1, 'round deposition should read feedback loop evidence index');
- assert(round.observed.evidenceByType['homepage-evidence-readiness'] === 1, 'round deposition should read homepage readiness evidence index');
- console.log(JSON.stringify({
- ok: true,
- outputRoot,
- evidenceTotal: evidence.total,
- roundPassCount: round.counts.pass
- }, null, 2));
- }
- function readJson(file) {
- return JSON.parse(fs.readFileSync(file, 'utf8'));
- }
- function assertVideoResourceReadiness(videoReadiness) {
- const ready = videoReadiness.acceptance?.readyForVideoAbPreflight === true;
- const realCandidateRows = Number(videoReadiness.counts?.realCandidateRows || 0);
- if (ready) {
- assert(Number(videoReadiness.failureCount || 0) === 0, 'ready video resource state should have zero failures');
- assert(realCandidateRows >= 1, 'ready video resource state should expose real candidate rows');
- return;
- }
- assert(Number(videoReadiness.failureCount || 0) >= 1, 'blocked video resource state should expose failures');
- }
- function seedRequiredOutputs(outputRoot) {
- fs.mkdirSync(outputRoot, { recursive: true });
- [
- 'proof-gap-request-latest',
- 'proof-gap-closure-latest',
- 'intake-readiness-latest',
- 'video-resource-readiness-latest',
- 'data-intake-pack-latest',
- 'video-intake-pack-latest',
- 'long-run-readiness-latest',
- 'business-proof-progress-latest',
- 'business-proof-next-actions-latest',
- 'optimization-pipeline-latest',
- 'video-hit-rate-preflight-latest',
- 'software-client-latest'
- ].forEach(name => copyOutputDir(name, outputRoot));
- copySoftwareClientSourceSeed(outputRoot);
- copyRealEvidenceSeed(outputRoot);
- copyVideoAbAuditSeed(outputRoot);
- }
- function copySoftwareClientSourceSeed(outputRoot) {
- const summaryPath = path.join(ROOT, 'outputs', 'software-client-latest', 'software-client-list.final.summary.json');
- if (!fs.existsSync(summaryPath)) return;
- const summary = readJson(summaryPath);
- const inputPath = path.resolve(ROOT, summary.input || '');
- if (!fs.existsSync(inputPath)) return;
- const sourceDir = path.dirname(inputPath);
- const relativeDir = path.relative(path.join(ROOT, 'outputs'), sourceDir);
- if (!relativeDir || relativeDir.startsWith('..') || path.isAbsolute(relativeDir)) return;
- copyDir(sourceDir, path.join(outputRoot, relativeDir));
- }
- function copyOutputDir(name, outputRoot) {
- const source = path.join(ROOT, 'outputs', name);
- if (!fs.existsSync(source)) return;
- copyDir(source, path.join(outputRoot, name));
- }
- function copyRealEvidenceSeed(outputRoot) {
- const outputs = path.join(ROOT, 'outputs');
- if (!fs.existsSync(outputs)) return;
- for (const entry of fs.readdirSync(outputs, { withFileTypes: true })) {
- if (!entry.isDirectory() || !entry.name.startsWith('overnight-quality-')) continue;
- const dir = path.join(outputs, entry.name);
- const aggregatePath = path.join(dir, 'aggregate-summary.json');
- if (!fs.existsSync(aggregatePath)) continue;
- const aggregate = JSON.parse(fs.readFileSync(aggregatePath, 'utf8'));
- const liveProof = Boolean(aggregate.manifest?.liveEnabled) &&
- aggregate.acceptance?.overallPass === true &&
- Number(aggregate.failureCount || 0) === 0 &&
- Number(aggregate.acceptance?.failedGateCount ?? aggregate.failedGateCount ?? 0) === 0;
- if (!liveProof) continue;
- copyDir(dir, path.join(outputRoot, entry.name));
- return;
- }
- }
- function copyVideoAbAuditSeed(outputRoot) {
- const outputs = path.join(ROOT, 'outputs');
- if (!fs.existsSync(outputs)) return;
- for (const entry of fs.readdirSync(outputs, { withFileTypes: true })) {
- if (!entry.isDirectory() || !entry.name.startsWith('video-hit-rate-audit-')) continue;
- const dir = path.join(outputs, entry.name);
- if (!fs.existsSync(path.join(dir, 'video-hit-rate-summary.json'))) continue;
- copyDir(dir, path.join(outputRoot, entry.name));
- return;
- }
- }
- function copyDir(source, target) {
- fs.mkdirSync(target, { recursive: true });
- for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
- const from = path.join(source, entry.name);
- const to = path.join(target, entry.name);
- if (entry.isDirectory()) copyDir(from, to);
- else if (entry.isFile()) fs.copyFileSync(from, to);
- }
- }
- function assert(condition, message) {
- if (!condition) throw new Error(message);
- }
- if (require.main === module) main();
|