| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- #!/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, '..');
- const DOC = path.join(ROOT, 'docs', 'tihao-handoff-index.md');
- const REQUIRED_PATHS = [
- 'docs/tihao-experience-optimization-plan.md',
- 'docs/business-proof-action-order.zh-CN.md',
- 'outputs/latest-form-index-latest/latest-form-index.md',
- 'outputs/real-proof-intake-bundle-latest/real-proof-intake-bundle.md',
- 'outputs/real-proof-closure-work-order-latest/real-proof-closure-work-order.md',
- 'outputs/local-seed-material-index-latest/local-seed-material-index.md',
- 'outputs/local-seed-to-intake-worklist-latest/local-seed-to-intake-worklist.md',
- 'outputs/experience-transcript-index-latest/experience-transcript-index.md',
- 'outputs/real-gap-material-audit-latest/real-gap-material-audit.md',
- 'outputs/proof-gap-request-latest/proof-gap-request-report.md',
- 'outputs/proof-gap-operator-pack-latest/proof-gap-operator-pack.md',
- 'outputs/business-execution-index-latest/business-execution-index.md',
- 'outputs/business-proof-progress-latest/business-proof-progress-report.md',
- 'outputs/plan-execution-status-latest/plan-execution-status.md',
- 'outputs/optimization-completion-latest/optimization-completion-report.md',
- 'outputs/long-run-readiness-latest/long-run-readiness-report.md',
- 'outputs/optimization-handoff-latest/optimization-handoff-report.md'
- ];
- const REQUIRED_PHRASES = [
- 'proof-gap-closure.openCount=3',
- '@vocmarket/tihao-sop@1.0.2',
- 'dist-tags.latest=1.0.2',
- 'real-gap-material-audit',
- 'realGapMaterialAudit',
- 'materialFoundCount=3',
- 'optimization-handoff.complete=false',
- 'optimization-status.counts.passed=31',
- 'optimization-handoff.externalBlockers=1',
- 'pipeline-scoped customer-effect',
- 'pipelineBlocked',
- 'proofGapClosure.complete=true/openCount=0',
- 'live-provider-overnight-proof` 不再出现在 `externalBlockers`',
- 'readyNotProven=video-ab-proof,historical-dataset',
- 'externalBlockers=customer-effect-proof',
- 'optimization-completion.readyForClaim=false',
- 'longrun:readiness.ready=false',
- '商务执行总表已把',
- 'businessExecutionIndex.longRunReadiness',
- '长跑前置门禁报告',
- 'status=blocked',
- 'actionCount=',
- '不能宣称提号率提升',
- '不能宣称客户效果达标',
- '不能宣称人工补号量下降',
- '不是业务证明',
- 'gapIds=historical-dataset',
- 'fillFileCount=3',
- 'recheckCommandCount=9',
- 'ownerGroupCount=2',
- 'ownerArtifactCount=2',
- 'evidenceRowCount=5',
- 'nextActionCount=5',
- 'operatorPackEvidenceRowCount=5',
- 'operatorPackNextActionCount=5',
- 'operatorPackOwnerArtifactCount=2',
- 'real-proof-closure-work-order',
- 'workOrderCount=13',
- 'realProofClosureWorkOrder.ownerArtifactCount=2',
- 'realProofClosureWorkOrder.canCloseProofGap=false',
- '商务执行总表已透传',
- 'operatorPackOwnerArtifactCount=2',
- '业务证明进度表已透传',
- 'businessProofProgress.operatorPackOwnerArtifactCount=2',
- 'businessProofNextActions.actionCount=3',
- '本地种子材料索引',
- 'local-seed-material-index',
- '本地种子转 intake 补表 worklist',
- 'local-seed-to-intake-worklist',
- 'historyDraftRows=1',
- 'candidateSeedRows=12',
- 'videoCandidateNeedsResourceRows=3',
- '经验逐字稿索引',
- 'experience-transcript-index',
- 'transcriptCount=2',
- 'coveredRuleCount=8',
- 'canCloseProofGap=false',
- '长期计划执行状态面板已透传',
- 'planExecutionStatus.operatorPackOwnerArtifactCount=2',
- 'businessExecutionOperatorPackOwnerArtifactRowCount=2',
- '操作包负责人附件',
- '真实历史 Brief 数据集',
- '真实候选视频资源',
- '真实视频 A/B live proof',
- 'proofContext.generatedBy=acceptance:video-ab',
- 'proofContext.mode=unknown',
- 'TIHAO_SESSION_TOKEN',
- '真实 live/provider 长跑证明',
- '商务复核和客户效果证明',
- '## 最近一次复验结果',
- 'overallReady=false',
- 'failureCount=6',
- 'readyForVideoAbPreflight=true',
- 'realCandidateRows=1',
- 'closedCount=2',
- 'readyForClaim=false',
- 'videoAbPreflightReadyForVideoAb=false',
- 'videoAbPreflightFailureCount=4',
- 'optimizationCompletion.videoAbPreflightFailureCount',
- 'video A/B preflight 失败上下文进入 closure/completion',
- 'proofGapOpenCount=3',
- 'failCount=',
- '不能用 `0` 或示例值代替',
- '## 接手角色分工',
- '## 完成判定矩阵',
- '## 可说与不可说',
- 'readyForCustomerEffectProof=true',
- 'readyForVideoAbPreflight=true',
- 'longrun:readiness',
- 'ready=true',
- 'liveEnabled=true',
- 'overallPass=true',
- 'openCount=0',
- 'complete=true',
- 'readyForClaim=true',
- '29 步全部 `pass`',
- 'round-deposition.passCount=142',
- 'provider mock、fallback、dry-run',
- 'npm run longrun:readiness -- --mode full-matrix',
- 'npm run optimization:completion -- --output outputs\\optimization-completion-latest',
- 'npm run round:refresh -- --output-root outputs --strict'
- ];
- function main() {
- assert(fs.existsSync(DOC), 'task handoff index doc should exist');
- const text = fs.readFileSync(DOC, 'utf8').replace(/^\uFEFF/, '');
- for (const requiredPath of REQUIRED_PATHS) {
- assert(text.includes(requiredPath), `task handoff index should link ${requiredPath}`);
- }
- for (const phrase of REQUIRED_PHRASES) {
- assert(text.includes(phrase), `task handoff index should include ${phrase}`);
- }
- assert(!/sk-[A-Za-z0-9_-]{10,}/.test(text), 'task handoff index should not contain model token patterns');
- assert(!/r:[A-Za-z0-9]{20,}/.test(text), 'task handoff index should not contain Parse sessionToken patterns');
- assert(!/Authorization\s*[:=]\s*Bearer/i.test(text), 'task handoff index should not expose authorization bearer values');
- const closure = readJson(path.join(ROOT, 'outputs', 'proof-gap-closure-latest', 'proof-gap-closure-summary.json'));
- const proofGapOperatorPack = readJson(path.join(ROOT, 'outputs', 'proof-gap-operator-pack-latest', 'proof-gap-operator-pack-summary.json'));
- const realProofIntakeBundle = readJson(path.join(ROOT, 'outputs', 'real-proof-intake-bundle-latest', 'real-proof-intake-bundle-summary.json'));
- const realProofClosureWorkOrder = readJson(path.join(ROOT, 'outputs', 'real-proof-closure-work-order-latest', 'real-proof-closure-work-order-summary.json'));
- const completion = readJson(path.join(ROOT, 'outputs', 'optimization-completion-latest', 'optimization-completion-summary.json'));
- const longRunReadiness = readJson(path.join(ROOT, 'outputs', 'long-run-readiness-latest', 'long-run-readiness-summary.json'));
- const latestForm = readJson(path.join(ROOT, 'outputs', 'latest-form-index-latest', 'latest-form-index-summary.json'));
- const handoff = readJson(path.join(ROOT, 'outputs', 'optimization-handoff-latest', 'optimization-handoff-summary.json'));
- const businessExecutionIndex = readJson(path.join(ROOT, 'outputs', 'business-execution-index-latest', 'business-execution-index-summary.json'));
- const businessProofProgress = readJson(path.join(ROOT, 'outputs', 'business-proof-progress-latest', 'business-proof-progress-summary.json'));
- const businessProofNextActions = readJson(path.join(ROOT, 'outputs', 'business-proof-next-actions-latest', 'business-proof-next-actions-summary.json'));
- const planExecutionStatus = readJson(path.join(ROOT, 'outputs', 'plan-execution-status-latest', 'plan-execution-status-summary.json'));
- const localSeed = readJson(path.join(ROOT, 'outputs', 'local-seed-material-index-latest', 'local-seed-material-index-summary.json'));
- const seedWorklist = readJson(path.join(ROOT, 'outputs', 'local-seed-to-intake-worklist-latest', 'local-seed-to-intake-worklist-summary.json'));
- const experienceTranscript = readJson(path.join(ROOT, 'outputs', 'experience-transcript-index-latest', 'experience-transcript-index-summary.json'));
- assert(closure?.complete === false && Number(closure.openCount || 0) === 3, 'current proof gap closure should still have three open gaps');
- assertProofGapOperatorPack(proofGapOperatorPack, 'current proof-gap operator pack');
- assertRealProofIntakeBundle(realProofIntakeBundle, 'current real proof intake bundle');
- assertRealProofClosureWorkOrder(realProofClosureWorkOrder, 'current real proof closure work order');
- assert(completion?.complete === false && completion?.readyForClaim === false && Number(completion.proofGapOpenCount || 0) === Number(closure.openCount || 0), 'current optimization completion audit should not be ready for claim');
- assert(completion?.canClaim?.tihaoRateImproved === false && completion?.canClaim?.customerEffectAchieved === false && completion?.canClaim?.manualSupplementReduced === false, 'completion audit should forbid all business-effect claims while incomplete');
- assertOptimizationCompletionPreflightContext(completion, 'current optimization completion');
- assert(longRunReadiness?.ready === false && Number(longRunReadiness.counts?.fail || 0) > 0, 'current long-run readiness should remain blocked with failing checks');
- assertBusinessExecutionLongRunReadiness(businessExecutionIndex, Number(longRunReadiness.counts?.fail || 0), 'current business execution index');
- assertBusinessExecutionOptimizationCompletionPreflight(businessExecutionIndex, completion, 'current business execution index');
- assertBusinessExecutionOperatorOwnerArtifacts(businessExecutionIndex, 'current business execution index');
- assertBusinessProofProgress(businessProofProgress, proofGapOperatorPack, businessExecutionIndex, 'current business proof progress');
- assertBusinessProofNextActions(businessProofNextActions, 'current business proof next actions');
- assert(localSeed?.proofLevel === 'not_business_proof' && localSeed?.directCustomerProof === false && localSeed?.canCloseProofGap === false, 'current local seed material index should not be business proof or close proof gaps');
- assert(Number(localSeed?.existingMaterialCount || 0) >= 1, 'current local seed material index should expose available seed materials');
- assertSeedToIntakeWorklist(seedWorklist, 'current local seed to intake worklist');
- assertExperienceTranscriptIndex(experienceTranscript, 'current experience transcript index');
- assertPlanExecutionStatus(planExecutionStatus, proofGapOperatorPack, businessExecutionIndex, 'current plan execution status');
- assert(latestForm?.passed === true && latestForm?.supportDocs?.some(item => item.path?.includes('tihao-handoff-index.md')), 'latest form index should expose task handoff doc');
- assert(latestForm?.longRunReadiness?.report?.includes('long-run-readiness-report.md') && latestForm.longRunReadiness.ready === false, 'latest form index should expose long-run readiness entry');
- assertOptimizationCompletionPreflightContext(latestForm?.optimizationCompletion, 'latest form index optimization completion');
- assertLatestFormNextActionsEntry(latestForm?.nextActions, businessProofNextActions, 'latest form index');
- assertPlanExecutionStatusEntry(latestForm?.planExecutionStatus, planExecutionStatus, 'latest form index');
- assertProofGapOperatorPackEntry(latestForm?.proofGapOperatorPack, proofGapOperatorPack, 'latest form index');
- assertRealProofIntakeBundleEntry(latestForm?.realProofIntakeBundle, realProofIntakeBundle, 'latest form index');
- assertRealProofClosureWorkOrderEntry(latestForm?.realProofClosureWorkOrder, realProofClosureWorkOrder, 'latest form index');
- assert(handoff?.complete === false && handoff?.supportDocs?.some(item => item.doc?.includes('tihao-handoff-index.md')), 'handoff summary should expose task handoff doc');
- assertHandoffProofBlockers(handoff, 'handoff summary');
- assert(handoff?.longRunReadiness?.report?.includes('long-run-readiness-report.md') && handoff.longRunReadiness.ready === false, 'handoff summary should expose top-level long-run readiness entry');
- assert(handoff?.latestFormIndex?.longRunReadiness?.report?.includes('long-run-readiness-report.md') && handoff.latestFormIndex.longRunReadiness.ready === false, 'handoff latest form index should expose long-run readiness entry');
- assertOptimizationCompletionPreflightContext(handoff?.optimizationCompletion, 'handoff optimization completion');
- assertOptimizationCompletionPreflightContext(handoff?.latestFormIndex?.optimizationCompletion, 'handoff latest form optimization completion');
- assertBusinessProofProgressEntry(handoff?.businessProofProgress, businessProofProgress, 'handoff summary');
- assertBusinessProofNextActionsEntry(handoff?.businessProofNextActions, businessProofNextActions, 'handoff summary');
- assertHandoffLatestFormNextActionsEntry(handoff?.latestFormIndex, latestForm?.nextActions, 'handoff latest form index');
- assertPlanExecutionStatusEntry(handoff?.planExecutionStatus, planExecutionStatus, 'handoff summary');
- assertPlanExecutionStatusEntry(handoff?.latestFormIndex?.planExecutionStatus, planExecutionStatus, 'handoff latest form index');
- assertProofGapOperatorPackEntry(handoff?.proofGapOperatorPack, proofGapOperatorPack, 'handoff summary');
- assertProofGapOperatorPackEntry(handoff?.latestFormIndex?.proofGapOperatorPack, proofGapOperatorPack, 'handoff latest form index');
- assertRealProofIntakeBundleEntry(handoff?.realProofIntakeBundle, realProofIntakeBundle, 'handoff summary');
- assertRealProofIntakeBundleEntry(handoff?.latestFormIndex?.realProofIntakeBundle, realProofIntakeBundle, 'handoff latest form index');
- assertRealProofClosureWorkOrderEntry(handoff?.realProofClosureWorkOrder, realProofClosureWorkOrder, 'handoff summary');
- assertRealProofClosureWorkOrderEntry(handoff?.latestFormIndex?.realProofClosureWorkOrder, realProofClosureWorkOrder, 'handoff latest form index');
- assertHandoffBusinessExecutionLongRunReadiness(handoff, Number(longRunReadiness.counts?.fail || 0), 'current handoff summary');
- assertHandoffBusinessExecutionOptimizationCompletionPreflight(handoff, completion, 'current handoff summary');
- assertHandoffBusinessExecutionOperatorOwnerArtifacts(handoff, 'current handoff summary');
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-task-handoff-index-'));
- const latestOutput = path.join(temp, 'latest-form-index');
- const handoffOutput = path.join(temp, 'optimization-handoff');
- const businessExecutionOutput = path.join(temp, 'business-execution-index');
- runNode(['scripts/latest-form-index.js', '--output', latestOutput, '--strict']);
- runNode(['scripts/generate-optimization-handoff.js', '--output', handoffOutput]);
- runNode(['scripts/business-execution-index.js', '--output', businessExecutionOutput, '--strict']);
- const generatedLatest = readJson(path.join(latestOutput, 'latest-form-index-summary.json'));
- const generatedHandoff = readJson(path.join(handoffOutput, 'optimization-handoff-summary.json'));
- const generatedBusinessExecutionIndex = readJson(path.join(businessExecutionOutput, 'business-execution-index-summary.json'));
- assert(generatedLatest?.supportDocs?.some(item => item.path?.includes('tihao-handoff-index.md')), 'generated latest form index should expose task handoff doc');
- assert(generatedLatest?.longRunReadiness?.report?.includes('long-run-readiness-report.md'), 'generated latest form index should expose long-run readiness entry');
- assertOptimizationCompletionPreflightContext(generatedLatest?.optimizationCompletion, 'generated latest form optimization completion');
- assertLatestFormNextActionsEntry(generatedLatest?.nextActions, businessProofNextActions, 'generated latest form index');
- assertPlanExecutionStatusEntry(generatedLatest?.planExecutionStatus, planExecutionStatus, 'generated latest form index');
- assertProofGapOperatorPackEntry(generatedLatest?.proofGapOperatorPack, proofGapOperatorPack, 'generated latest form index');
- assertRealProofIntakeBundleEntry(generatedLatest?.realProofIntakeBundle, realProofIntakeBundle, 'generated latest form index');
- assertRealProofClosureWorkOrderEntry(generatedLatest?.realProofClosureWorkOrder, realProofClosureWorkOrder, 'generated latest form index');
- assert(generatedHandoff?.supportDocs?.some(item => item.doc?.includes('tihao-handoff-index.md')), 'generated handoff summary should expose task handoff doc');
- assertHandoffProofBlockers(generatedHandoff, 'generated handoff summary');
- assert(generatedHandoff?.longRunReadiness?.report?.includes('long-run-readiness-report.md'), 'generated handoff should expose top-level long-run readiness entry');
- assertOptimizationCompletionPreflightContext(generatedHandoff?.optimizationCompletion, 'generated handoff optimization completion');
- assertOptimizationCompletionPreflightContext(generatedHandoff?.latestFormIndex?.optimizationCompletion, 'generated handoff latest form optimization completion');
- assertBusinessProofProgressEntry(generatedHandoff?.businessProofProgress, businessProofProgress, 'generated handoff summary');
- assertBusinessProofNextActionsEntry(generatedHandoff?.businessProofNextActions, businessProofNextActions, 'generated handoff summary');
- assertHandoffLatestFormNextActionsEntry(generatedHandoff?.latestFormIndex, latestForm?.nextActions, 'generated handoff latest form index');
- assertPlanExecutionStatusEntry(generatedHandoff?.planExecutionStatus, planExecutionStatus, 'generated handoff summary');
- assertProofGapOperatorPackEntry(generatedHandoff?.proofGapOperatorPack, proofGapOperatorPack, 'generated handoff summary');
- assertRealProofIntakeBundleEntry(generatedHandoff?.realProofIntakeBundle, realProofIntakeBundle, 'generated handoff summary');
- assertRealProofClosureWorkOrderEntry(generatedHandoff?.realProofClosureWorkOrder, realProofClosureWorkOrder, 'generated handoff summary');
- assertRealProofClosureWorkOrderEntry(generatedHandoff?.latestFormIndex?.realProofClosureWorkOrder, realProofClosureWorkOrder, 'generated handoff latest form index');
- assertHandoffBusinessExecutionLongRunReadiness(generatedHandoff, Number(longRunReadiness.counts?.fail || 0), 'generated handoff summary');
- assertHandoffBusinessExecutionOptimizationCompletionPreflight(generatedHandoff, completion, 'generated handoff summary');
- assertBusinessExecutionLongRunReadiness(generatedBusinessExecutionIndex, Number(longRunReadiness.counts?.fail || 0), 'generated business execution index');
- assertBusinessExecutionOptimizationCompletionPreflight(generatedBusinessExecutionIndex, completion, 'generated business execution index');
- assertBusinessExecutionOperatorOwnerArtifacts(generatedBusinessExecutionIndex, 'generated business execution index');
- const readme = fs.readFileSync(path.join(ROOT, 'README.md'), 'utf8');
- assert(readme.includes('docs/tihao-handoff-index.md'), 'README should link task handoff index');
- const packageJson = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
- assert(packageJson.scripts['task:handoff-index:smoke'] === 'node scripts/task-handoff-index-smoke.js', 'package should expose task handoff smoke script');
- assert(packageJson.scripts['optimization:completion'] === 'node scripts/optimization-completion-audit.js', 'package should expose optimization completion audit script');
- assert(packageJson.scripts['optimization:completion:smoke'] === 'node scripts/optimization-completion-smoke.js', 'package should expose optimization completion smoke script');
- const acceptance = fs.readFileSync(path.join(ROOT, 'scripts', 'acceptance.js'), 'utf8');
- assert(acceptance.includes("task:handoff-index:smoke"), 'acceptance should run task handoff smoke');
- assert(acceptance.includes("optimization:completion:smoke"), 'acceptance should run optimization completion smoke');
- console.log(JSON.stringify({
- ok: true,
- doc: path.relative(ROOT, DOC).replace(/\\/g, '/'),
- openCount: closure.openCount,
- operatorPackRecheckCommandCount: proofGapOperatorPack.recheckCommandCount,
- businessExecutionOperatorPackOwnerArtifactCount: businessExecutionIndex.operatorPackOwnerArtifactCount,
- businessProofProgressOperatorPackOwnerArtifactCount: businessProofProgress.operatorPackOwnerArtifactCount,
- businessProofNextActionCount: businessProofNextActions.actions.length,
- handoffBusinessProofNextActionCount: handoff.businessProofNextActions.actionCount,
- latestFormIndexNextActionTopCount: latestForm.nextActions.topActions.length,
- handoffLatestFormIndexNextActionTopCount: handoff.latestFormIndex.topActions.length,
- planExecutionStatusOperatorPackOwnerArtifactCount: planExecutionStatus.operatorPackOwnerArtifactCount,
- planExecutionStatusBusinessExecutionOperatorPackOwnerArtifactRowCount: planExecutionStatus.businessExecutionOperatorPackOwnerArtifactRowCount,
- seedToIntakeHistoryDraftRows: seedWorklist.counts?.historyDraftRows,
- seedToIntakeCandidateSeedRows: seedWorklist.counts?.candidateSeedRows,
- seedToIntakeVideoCandidateNeedsResourceRows: seedWorklist.counts?.videoCandidateNeedsResourceRows,
- experienceTranscriptCount: experienceTranscript.transcriptCount,
- experienceTranscriptCoveredRuleCount: experienceTranscript.coveredRuleCount,
- realProofBundleOperatorPackEvidenceRowCount: realProofIntakeBundle.operatorPackEvidenceRowCount,
- realProofBundleOperatorPackNextActionCount: realProofIntakeBundle.operatorPackNextActionCount,
- realProofClosureWorkOrderCount: realProofClosureWorkOrder.workOrderCount,
- realProofClosureWorkOrderOwnerArtifactCount: realProofClosureWorkOrder.ownerArtifacts.length,
- readyForClaim: completion.readyForClaim,
- businessExecutionLongRunStatus: findBusinessExecutionLongRunRow(businessExecutionIndex)?.status,
- latestSupportDocCount: latestForm.supportDocs.length,
- handoffSupportDocCount: handoff.supportDocs.length
- }, null, 2));
- }
- function assertRealProofIntakeBundle(bundle, label) {
- assert(bundle?.passed === true, `${label} should pass`);
- assert(bundle?.complete === false, `${label} should remain incomplete while proof gaps are open`);
- assert(bundle?.directCustomerProof === false, `${label} should preserve non-business-proof boundary`);
- assert(bundle?.proofLevel === 'not_business_proof', `${label} should keep not_business_proof level`);
- assert(Number(bundle?.proofOpenCount || 0) >= 1, `${label} should keep open proof gaps`);
- assert(Number(bundle?.proofGapRowCount || 0) === 5, `${label} should expose five proof gap rows`);
- assert(Number(bundle?.operatorPackEvidenceRowCount || 0) === 5, `${label} should expose operator evidence row count`);
- assert(Number(bundle?.operatorPackNextActionCount || 0) === 5, `${label} should expose operator next action count`);
- assert(Number(bundle?.operatorPackMissingProofRequirementCount || 0) >= 1, `${label} should expose operator missing proof requirement count`);
- assert(Number(bundle?.operatorPackOwnerArtifactCount || 0) >= 1, `${label} should expose operator owner artifact count`);
- assert(Array.isArray(bundle?.operatorPackOwnerArtifacts) && bundle.operatorPackOwnerArtifacts.length === Number(bundle.operatorPackOwnerArtifactCount || 0), `${label} should expose operator owner artifacts`);
- assert(bundle.operatorPackOwnerArtifacts.some(item => item.owner === '商务' && item.markdown?.includes('by-owner/business.md') && item.csv?.includes('by-owner/business.csv')), `${label} should expose business owner operator files`);
- if (Array.isArray(bundle?.proofGapRows)) {
- assert(bundle.proofGapRows.every(row => row.evidence && row.nextAction), `${label} proof gap rows should carry evidence and next action`);
- }
- }
- function assertHandoffProofBlockers(handoff, label) {
- const externalIds = new Set((handoff?.externalBlockers || []).map(item => item.id));
- const readyNotProvenIds = new Set((handoff?.readyNotProven || []).map(item => item.id));
- assert(externalIds.size === 1, `${label} should expose exactly one external proof blocker in the current state`);
- assert(externalIds.has('customer-effect-proof'), `${label} should keep customer-effect-proof as the only external proof blocker`);
- assert(!externalIds.has('live-provider-overnight-proof'), `${label} should not list closed live-provider proof as an external blocker`);
- assert(readyNotProvenIds.has('video-ab-proof'), `${label} should keep video A/B proof as ready-not-proven`);
- assert(readyNotProvenIds.has('historical-dataset'), `${label} should keep historical dataset as ready-not-proven`);
- }
- function assertRealProofIntakeBundleEntry(entry, bundle, label) {
- assert(entry?.markdown?.includes('real-proof-intake-bundle.md'), `${label} should link real proof intake bundle report`);
- assert(entry?.csv?.includes('real-proof-intake-bundle.csv'), `${label} should link real proof intake bundle csv`);
- assert(entry?.summary?.includes('real-proof-intake-bundle-summary.json'), `${label} should link real proof intake bundle summary`);
- assert(entry?.directCustomerProof === false, `${label} should preserve real proof bundle proof boundary`);
- assert(entry?.proofLevel === 'not_business_proof', `${label} should preserve real proof bundle proof level`);
- assert(Number(entry?.proofOpenCount || 0) === Number(bundle?.proofOpenCount || 0), `${label} should mirror real proof bundle open proof count`);
- assert(Number(entry?.proofGapRowCount || 0) === Number(bundle?.proofGapRowCount || 0), `${label} should mirror real proof bundle proof gap row count`);
- assert(Number(entry?.operatorPackEvidenceRowCount || 0) === Number(bundle?.operatorPackEvidenceRowCount || 0), `${label} should mirror real proof bundle operator evidence row count`);
- assert(Number(entry?.operatorPackNextActionCount || 0) === Number(bundle?.operatorPackNextActionCount || 0), `${label} should mirror real proof bundle operator next action count`);
- assert(Number(entry?.operatorPackMissingProofRequirementCount || 0) === Number(bundle?.operatorPackMissingProofRequirementCount || 0), `${label} should mirror real proof bundle operator missing proof requirement count`);
- assert(Number(entry?.operatorPackOwnerArtifactCount || 0) === Number(bundle?.operatorPackOwnerArtifactCount || 0), `${label} should mirror real proof bundle operator owner artifact count`);
- if (bundle?.operatorPackOwnerArtifacts?.some(item => item.owner === '商务/投放')) {
- assert(entry?.operatorPackOwnerArtifacts?.some(item => item.csv?.includes('by-owner/business-media.csv')), `${label} should mirror real proof bundle business/media owner csv when present`);
- }
- }
- function assertRealProofClosureWorkOrder(workOrder, label) {
- assert(workOrder?.passed === true, `${label} should pass`);
- assert(workOrder?.complete === false, `${label} should remain incomplete while proof gaps are open`);
- assert(workOrder?.directCustomerProof === false, `${label} should preserve non-business-proof boundary`);
- assert(workOrder?.canCloseProofGap === false, `${label} should not close proof gaps`);
- assert(workOrder?.proofLevel === 'not_business_proof', `${label} should keep not_business_proof level`);
- assert(workOrder?.materialType === 'real_proof_closure_work_order', `${label} should classify material type`);
- assert(workOrder?.requiresHumanRealMaterial === true, `${label} should require human real material`);
- assert(Number(workOrder?.workOrderCount || 0) >= 5, `${label} should expose work orders`);
- assert(Number(workOrder?.ownerGroupCount || 0) >= 1, `${label} should expose owner groups`);
- assert(Array.isArray(workOrder?.ownerArtifacts) && workOrder.ownerArtifacts.length === Number(workOrder.ownerGroupCount || 0), `${label} should expose owner artifacts`);
- assert(workOrder.ownerArtifacts.some(item => item.markdown?.includes('by-owner/business.md') && item.csv?.includes('by-owner/business.csv')), `${label} should expose business owner files`);
- assert(workOrder.ownerArtifacts.some(item => item.markdown?.includes('by-owner/tech-ai.md') && item.csv?.includes('by-owner/tech-ai.csv')), `${label} should expose tech/AI owner files`);
- if (workOrder.ownerArtifacts.some(item => item.owner === '商务/投放')) {
- assert(workOrder.ownerArtifacts.some(item => item.markdown?.includes('by-owner/business-media.md') && item.csv?.includes('by-owner/business-media.csv')), `${label} should expose business/media owner files when present`);
- }
- assert(Number(workOrder?.sourceState?.proofGapOpenCount || 0) >= 1, `${label} should expose open proof gaps`);
- assert(Number(workOrder?.sourceState?.intakeFailureCount || 0) >= 1, `${label} should expose intake failure count`);
- assert(Number(workOrder?.sourceState?.realCandidateRows || 0) >= 0, `${label} should expose real candidate rows`);
- }
- function assertRealProofClosureWorkOrderEntry(entry, workOrder, label) {
- assert(entry?.markdown?.includes('real-proof-closure-work-order.md'), `${label} should link real proof closure work order report`);
- assert(entry?.csv?.includes('real-proof-closure-work-order.csv'), `${label} should link real proof closure work order csv`);
- assert(entry?.summary?.includes('real-proof-closure-work-order-summary.json'), `${label} should link real proof closure work order summary`);
- assert(entry?.directCustomerProof === false, `${label} should preserve real proof closure work order proof boundary`);
- assert(entry?.canCloseProofGap === false, `${label} should preserve real proof closure work order non-closure boundary`);
- assert(entry?.proofLevel === 'not_business_proof', `${label} should preserve real proof closure work order proof level`);
- assert(entry?.materialType === 'real_proof_closure_work_order', `${label} should preserve real proof closure work order material type`);
- assert(entry?.complete === false, `${label} should keep real proof closure work order incomplete state`);
- assert(Number(entry?.workOrderCount || 0) === Number(workOrder?.workOrderCount || 0), `${label} should mirror real proof closure work order count`);
- assert(Number(entry?.ownerGroupCount || 0) === Number(workOrder?.ownerGroupCount || 0), `${label} should mirror real proof closure owner group count`);
- assert(Number(entry?.ownerArtifacts?.length || 0) === Number(workOrder?.ownerArtifacts?.length || 0), `${label} should mirror real proof closure owner artifact count`);
- assert(Number(entry?.proofGapOpenCount || 0) === Number(workOrder?.sourceState?.proofGapOpenCount || 0), `${label} should mirror real proof closure open proof gaps`);
- assert(Number(entry?.intakeFailureCount || 0) === Number(workOrder?.sourceState?.intakeFailureCount || 0), `${label} should mirror real proof closure intake failures`);
- assert(Number(entry?.realCandidateRows || 0) === Number(workOrder?.sourceState?.realCandidateRows || 0), `${label} should mirror real proof closure real candidate rows`);
- if (workOrder?.ownerArtifacts?.some(item => item.owner === '商务/投放')) {
- assert(entry?.ownerArtifacts?.some(item => item.csv?.includes('by-owner/business-media.csv')), `${label} should mirror real proof closure business/media owner csv when present`);
- }
- assert(entry?.ownerArtifacts?.some(item => item.markdown?.includes('by-owner/tech-ai.md')), `${label} should mirror real proof closure tech owner markdown`);
- }
- function assertExperienceTranscriptIndex(index, label) {
- assert(index?.proofLevel === 'not_business_proof', `${label} should keep not_business_proof level`);
- assert(index?.materialType === 'experience_seed', `${label} should classify transcripts as experience seed`);
- assert(index?.directCustomerProof === false, `${label} should not be direct customer proof`);
- assert(index?.canCloseProofGap === false, `${label} should not close proof gaps`);
- assert(index?.complete === false, `${label} should not claim completion`);
- assert(Number(index?.transcriptCount || 0) === 4, `${label} should index four transcripts`);
- assert(Number(index?.coveredRuleCount || 0) === 13, `${label} should cover thirteen experience rules`);
- assert(Array.isArray(index?.ruleCoverage) && index.ruleCoverage.every(item => item.proofLevel === 'not_business_proof' && item.canCloseProofGap === false), `${label} rules should preserve proof boundary`);
- }
- function assertSeedToIntakeWorklist(worklist, label) {
- assert(worklist?.proofLevel === 'not_business_proof', `${label} should keep not_business_proof level`);
- assert(worklist?.materialType === 'seed_to_intake_worklist', `${label} should classify material type`);
- assert(worklist?.directCustomerProof === false, `${label} should not be direct customer proof`);
- assert(worklist?.canCloseProofGap === false, `${label} should not close proof gaps`);
- assert(worklist?.complete === false, `${label} should not claim completion`);
- assert(Number(worklist?.counts?.historyDraftRows || 0) >= 1, `${label} should expose history draft rows`);
- assert(Number(worklist?.counts?.candidateSeedRows || 0) >= 1, `${label} should expose candidate seed rows`);
- assert(Number(worklist?.counts?.videoWorklistRows || 0) >= 1, `${label} should expose video worklist rows`);
- assert(Number(worklist?.counts?.videoCandidateNeedsResourceRows || 0) >= 1, `${label} should expose candidate videos needing resources`);
- assert(Array.isArray(worklist?.targetFiles) && worklist.targetFiles.some(file => file.includes('history-data-template.csv')), `${label} should point to history intake template`);
- assert(Array.isArray(worklist?.targetFiles) && worklist.targetFiles.some(file => file.includes('video-resource-template.csv')), `${label} should point to video resource template`);
- assert(Array.isArray(worklist?.missingProofRequirements) && worklist.missingProofRequirements.length >= 1, `${label} should expose missing proof requirements`);
- }
- function assertProofGapOperatorPack(pack, label) {
- const gapIds = gapIdsOf(pack);
- for (const requiredId of ['historical-dataset', 'video-real-candidate', 'video-ab-live-proof', 'live-provider-overnight-proof', 'manual-review-and-customer-effect']) {
- assert(gapIds.includes(requiredId), `${label} should expose ${requiredId}`);
- }
- assert(pack?.passed === true, `${label} should pass`);
- assert(pack?.complete === false, `${label} should remain incomplete while proof gaps are open`);
- assert(pack?.directCustomerProof === false, `${label} should preserve non-business-proof boundary`);
- assert(pack?.proofLevel === 'not_business_proof', `${label} should keep not_business_proof level`);
- assert(Number(pack?.openCount || 0) >= 1, `${label} should keep open gaps`);
- assert(Number(pack?.rowCount || 0) === 5, `${label} should expose five rows`);
- assert(Number(pack?.fillFileCount || 0) === 3, `${label} should expose fill file count`);
- assert(Number(pack?.recheckCommandCount || 0) === 9, `${label} should expose recheck command count`);
- assert(Number(pack?.ownerGroupCount || 0) === Number(pack?.ownerArtifactCount || pack?.ownerGroups?.length || 0), `${label} should expose owner group count`);
- assert(Number(pack?.evidenceRowCount || 0) === 5, `${label} should expose evidence row count`);
- assert(Number(pack?.nextActionCount || 0) === 5, `${label} should expose next action count`);
- assert(Number(pack?.missingProofRequirementCount || 0) >= 1, `${label} should expose missing proof requirement count`);
- }
- function assertProofGapOperatorPackEntry(entry, pack, label) {
- assert(entry?.markdown?.includes('proof-gap-operator-pack.md'), `${label} should link proof-gap operator pack report`);
- assert(entry?.csv?.includes('proof-gap-operator-pack.csv'), `${label} should link proof-gap operator pack csv`);
- assert(entry?.summary?.includes('proof-gap-operator-pack-summary.json'), `${label} should link proof-gap operator pack summary`);
- assert(entry?.directCustomerProof === false, `${label} should preserve proof-gap operator pack proof boundary`);
- assert(entry?.proofLevel === 'not_business_proof', `${label} should preserve proof-gap operator pack proof level`);
- assert(Number(entry?.openCount || 0) === Number(pack?.openCount || 0), `${label} should mirror proof-gap operator pack open count`);
- assert(Number(entry?.rowCount || 0) === Number(pack?.rowCount || 0), `${label} should mirror proof-gap operator pack row count`);
- assert(Number(entry?.fillFileCount || 0) === Number(pack?.fillFileCount || 0), `${label} should mirror proof-gap operator pack fill file count`);
- assert(Number(entry?.recheckCommandCount || 0) === Number(pack?.recheckCommandCount || 0), `${label} should mirror proof-gap operator pack recheck command count`);
- assert(Number(entry?.ownerGroupCount || 0) === Number(pack?.ownerGroupCount || 0), `${label} should mirror proof-gap operator pack owner group count`);
- assert(Number(entry?.evidenceRowCount || 0) === Number(pack?.evidenceRowCount || 0), `${label} should mirror proof-gap operator pack evidence row count`);
- assert(Number(entry?.nextActionCount || 0) === Number(pack?.nextActionCount || 0), `${label} should mirror proof-gap operator pack next action count`);
- for (const gapId of gapIdsOf(pack)) {
- assert(gapIdsOf(entry).includes(gapId), `${label} should mirror proof-gap operator pack gap ID ${gapId}`);
- }
- }
- function gapIdsOf(item) {
- if (Array.isArray(item?.gapIds)) return item.gapIds.map(value => String(value || ''));
- if (Array.isArray(item?.rows)) return item.rows.map(row => String(row.gapId || '')).filter(Boolean);
- return [];
- }
- function assertBusinessProofProgress(progress, pack, businessExecutionIndex, label) {
- assert(progress?.complete === false, `${label} should remain incomplete while proof gaps are open`);
- assert(Number(progress?.operatorPackOwnerArtifactCount || 0) === Number(pack?.ownerArtifactCount || 0), `${label} should mirror proof-gap operator owner artifact count`);
- assert(Number(progress?.operatorPackOwnerArtifactCount || 0) === Number((pack?.ownerArtifacts || []).length), `${label} should expose current operator owner artifacts`);
- assert(Number(progress?.observed?.businessExecutionOperatorPackOwnerArtifactRowCount || 0) === Number(businessExecutionIndex?.operatorPackOwnerArtifactRowCount || 0), `${label} should mirror business execution operator owner artifact row count`);
- assert(Number(progress?.counts?.blocked_by_external_data || 0) >= 1, `${label} should expose external data blockers`);
- assertOperatorOwnerArtifactsMatch(progress?.operatorPackOwnerArtifacts, pack?.ownerArtifacts, label);
- }
- function assertBusinessProofProgressEntry(entry, progress, label) {
- assert(entry?.summary?.includes('business-proof-progress-summary.json'), `${label} should link business proof progress summary`);
- assert(entry?.report?.includes('business-proof-progress-report.md'), `${label} should link business proof progress report`);
- assert(entry?.complete === false, `${label} should keep business proof progress incomplete state`);
- assert(Number(entry?.operatorPackOwnerArtifactCount || 0) === Number(progress?.operatorPackOwnerArtifactCount || 0), `${label} should mirror business proof progress operator owner artifact count`);
- assert(Number(entry?.businessExecutionOperatorPackOwnerArtifactRowCount || 0) === Number(progress?.observed?.businessExecutionOperatorPackOwnerArtifactRowCount || 0), `${label} should mirror business proof progress business execution artifact row count`);
- assert(Number(entry?.counts?.blocked_by_external_data || 0) === Number(progress?.counts?.blocked_by_external_data || 0), `${label} should mirror business proof progress blocker count`);
- assertOperatorOwnerArtifactsMatch(entry?.operatorPackOwnerArtifacts, progress?.operatorPackOwnerArtifacts, label);
- }
- function assertBusinessProofNextActions(nextActions, label) {
- assert(nextActions?.complete === false, `${label} should remain incomplete while proof gaps are open`);
- const actions = Array.isArray(nextActions?.actions) ? nextActions.actions : [];
- assert(actions.length === Number(nextActions?.actionCount || actions.length), `${label} should mirror deduped next action count`);
- assert(Number(nextActions?.sourceState?.proofGapOpenCount || 0) >= 1, `${label} should keep open proof gaps`);
- if (nextActions?.sourceState?.pipelineStale === true) {
- assert(Number(nextActions.sourceState.pipelineNextActionCount || 0) === 0, `${label} should suppress current pipeline next actions when pipeline is stale`);
- assert(Number(nextActions.sourceState.pipelineSuppressedNextActionCount || 0) >= 1, `${label} should expose suppressed stale pipeline action count`);
- assert(actions.every(action => !String(action.source || '').includes('optimization-pipeline')), `${label} should not dispatch stale optimization-pipeline actions`);
- }
- assert(nextActions.actions.some(action => action.id === 'step-03' && String(action.command || '').includes('history-data-template.csv')), `${label} should expose historical data fill action`);
- assert(nextActions.actions.some(action => action.id === 'gap-video-ab-live-proof' && String(action.command || '').includes('acceptance:video-ab')), `${label} should expose video A/B live proof action`);
- }
- function assertBusinessProofNextActionsEntry(entry, nextActions, label) {
- assert(entry?.summary?.includes('business-proof-next-actions-summary.json'), `${label} should link business proof next actions summary`);
- assert(entry?.report?.includes('business-proof-next-actions-report.md'), `${label} should link business proof next actions report`);
- assert(entry?.csv?.includes('business-proof-next-actions.csv'), `${label} should link business proof next actions csv`);
- assert(entry?.complete === false, `${label} should keep next action queue incomplete state`);
- assert(Number(entry?.actionCount || 0) === Number(nextActions?.actions?.length || 0), `${label} should mirror next action count`);
- assert(Number(entry?.sourceState?.proofGapOpenCount || 0) === Number(nextActions?.sourceState?.proofGapOpenCount || 0), `${label} should mirror next action proof gap open count`);
- assert(Boolean(entry?.sourceState?.pipelineStale) === Boolean(nextActions?.sourceState?.pipelineStale), `${label} should mirror next action pipeline stale state`);
- assert(Number(entry?.sourceState?.pipelineSuppressedNextActionCount || 0) === Number(nextActions?.sourceState?.pipelineSuppressedNextActionCount || 0), `${label} should mirror suppressed stale pipeline action count`);
- assert(Array.isArray(entry?.topActions) && entry.topActions.length >= Math.min(5, nextActions.actions.length), `${label} should expose top next actions`);
- assert(entry.topActions.some(action => action.id === 'step-03' && String(action.command || '').includes('history-data-template.csv')), `${label} should expose top historical data action`);
- assert(entry.topActions.some(action => action.id === 'gap-video-ab-live-proof' && String(action.command || '').includes('acceptance:video-ab')), `${label} should expose top video A/B action`);
- }
- function assertLatestFormNextActionsEntry(entry, nextActions, label) {
- assert(entry?.complete === false, `${label} should keep latest form next action queue incomplete state`);
- assert(Number(entry?.actionCount || 0) === Number(nextActions?.actions?.length || 0), `${label} should mirror latest form next action count`);
- assert(Number(entry?.proofOpenCount || 0) === Number(nextActions?.sourceState?.proofGapOpenCount || 0), `${label} should mirror latest form proof gap open count`);
- assert(Number(entry?.sourceState?.proofGapOpenCount || 0) === Number(nextActions?.sourceState?.proofGapOpenCount || 0), `${label} should mirror latest form next action source proof gap open count`);
- assert(Boolean(entry?.sourceState?.pipelineStale) === Boolean(nextActions?.sourceState?.pipelineStale), `${label} should mirror latest form next action pipeline stale state`);
- assert(Number(entry?.sourceState?.pipelineSuppressedNextActionCount || 0) === Number(nextActions?.sourceState?.pipelineSuppressedNextActionCount || 0), `${label} should mirror latest form suppressed stale pipeline count`);
- assert(Number(entry?.ownerGroupCount || 0) === Number(nextActions?.ownerGroupCount || entry?.ownerGroups?.length || 0), `${label} should mirror latest form next action owner group count`);
- assert(Number(entry?.ownerArtifactCount || 0) === Number(nextActions?.ownerArtifactCount || entry?.ownerArtifacts?.length || 0), `${label} should mirror latest form next action owner artifact count`);
- assert(Array.isArray(entry?.topActions) && entry.topActions.length >= Math.min(5, nextActions.actions.length), `${label} should expose latest form top next actions`);
- assert(entry.topActions.some(action => action.id === 'step-03' && String(action.command || '').includes('history-data-template.csv')), `${label} should expose latest form top historical data action`);
- assert(entry.topActions.some(action => action.id === 'gap-video-ab-live-proof' && String(action.command || '').includes('acceptance:video-ab')), `${label} should expose latest form top video A/B action`);
- }
- function assertHandoffLatestFormNextActionsEntry(entry, latestNextActions, label) {
- assert(entry?.complete === false, `${label} should keep handoff latest form next action queue incomplete state`);
- assert(Number(entry?.actionCount || 0) === Number(latestNextActions?.actionCount || 0), `${label} should mirror handoff latest form next action count`);
- assert(Number(entry?.proofOpenCount || 0) === Number(latestNextActions?.proofOpenCount || 0), `${label} should mirror handoff latest form proof gap open count`);
- assert(Number(entry?.sourceState?.proofGapOpenCount || 0) === Number(latestNextActions?.sourceState?.proofGapOpenCount || 0), `${label} should mirror handoff latest form source proof gap open count`);
- assert(Boolean(entry?.sourceState?.pipelineStale) === Boolean(latestNextActions?.sourceState?.pipelineStale), `${label} should mirror handoff latest form pipeline stale state`);
- assert(Number(entry?.sourceState?.pipelineSuppressedNextActionCount || 0) === Number(latestNextActions?.sourceState?.pipelineSuppressedNextActionCount || 0), `${label} should mirror handoff latest form suppressed stale pipeline count`);
- assert(Number(entry?.ownerGroupCount || 0) === Number(latestNextActions?.ownerGroupCount || 0), `${label} should mirror handoff latest form owner group count`);
- assert(Number(entry?.ownerArtifactCount || 0) === Number(latestNextActions?.ownerArtifactCount || 0), `${label} should mirror handoff latest form owner artifact count`);
- assert(Array.isArray(entry?.topActions) && entry.topActions.length >= Math.min(5, latestNextActions?.topActions?.length || 0), `${label} should expose handoff latest form top next actions`);
- assert(entry.topActions.some(action => action.id === 'step-03' && String(action.command || '').includes('history-data-template.csv')), `${label} should expose handoff latest form top historical data action`);
- assert(entry.topActions.some(action => action.id === 'gap-video-ab-live-proof' && String(action.command || '').includes('acceptance:video-ab')), `${label} should expose handoff latest form top video A/B action`);
- }
- function assertPlanExecutionStatus(status, pack, businessExecutionIndex, label) {
- assert(status?.complete === false, `${label} should remain incomplete while proof gaps are open`);
- assert(status?.directCustomerProof !== true, `${label} should preserve non-business-proof boundary`);
- assert(Number(status?.rowCount || 0) === 8, `${label} should expose eight plan sections`);
- assert(Number(status?.proofOpenCount || 0) === Number(pack?.openCount || 0), `${label} should mirror open proof gaps`);
- assert(Number(status?.operatorPackOwnerArtifactCount || 0) === Number(pack?.ownerArtifactCount || 0), `${label} should mirror proof-gap operator owner artifact count`);
- assert(Number(status?.businessExecutionOperatorPackOwnerArtifactRowCount || 0) === Number(businessExecutionIndex?.operatorPackOwnerArtifactRowCount || 0), `${label} should mirror business execution owner artifact rows`);
- assertOperatorOwnerArtifactsMatch(status?.operatorPackOwnerArtifacts, pack?.ownerArtifacts, label);
- }
- function assertPlanExecutionStatusEntry(entry, status, label) {
- assert(entry?.markdown?.includes('plan-execution-status.md'), `${label} should link plan execution status report`);
- assert(entry?.csv?.includes('plan-execution-status.csv'), `${label} should link plan execution status csv`);
- assert(entry?.summary?.includes('plan-execution-status-summary.json'), `${label} should link plan execution status summary`);
- assert(entry?.directCustomerProof === false, `${label} should preserve plan execution proof boundary`);
- assert(entry?.complete === false, `${label} should keep plan execution incomplete state`);
- assert(Number(entry?.rowCount || 0) === Number(status?.rowCount || 0), `${label} should mirror plan execution row count`);
- assert(Number(entry?.proofOpenCount || 0) === Number(status?.proofOpenCount || 0), `${label} should mirror plan execution proof open count`);
- assert(Number(entry?.operatorPackOwnerArtifactCount || 0) === Number(status?.operatorPackOwnerArtifactCount || 0), `${label} should mirror plan execution operator owner artifact count`);
- assert(Number(entry?.businessExecutionOperatorPackOwnerArtifactRowCount || 0) === Number(status?.businessExecutionOperatorPackOwnerArtifactRowCount || 0), `${label} should mirror plan execution business execution artifact rows`);
- assertOperatorOwnerArtifactsMatch(entry?.operatorPackOwnerArtifacts, status?.operatorPackOwnerArtifacts, label);
- }
- function assertBusinessExecutionLongRunReadiness(index, failCount, label) {
- const row = findBusinessExecutionLongRunRow(index);
- assert(index?.sourceFiles?.longRunReadiness?.includes('long-run-readiness-summary.json'), `${label} should expose long-run readiness source`);
- assert(row, `${label} should expose long-run readiness key file row`);
- assert(row.mainFile?.includes('long-run-readiness-report.md'), `${label} should link long-run readiness report`);
- assert(row.expectedArtifact?.includes('long-run-readiness-summary.json'), `${label} should link long-run readiness summary`);
- assert(row.status === 'blocked', `${label} should keep long-run readiness blocked while ready=false`);
- assert(Number(row.actionCount || 0) === failCount, `${label} should mirror long-run readiness fail count`);
- assert(String(row.boundary || '').includes('不能启动') && String(row.boundary || '').includes('不证明客户效果'), `${label} should preserve non-business-proof boundary`);
- }
- function assertBusinessExecutionOperatorOwnerArtifacts(index, label) {
- assert(Number(index?.operatorPackOwnerArtifactCount || 0) === Number(index?.operatorPackOwnerArtifacts?.length || 0), `${label} should expose current operator owner artifacts`);
- assert(Number(index?.operatorPackOwnerArtifactRowCount || 0) === Number(index?.operatorPackOwnerArtifacts?.length || 0), `${label} should expose current operator owner artifact rows`);
- assert(index?.sourceFiles?.proofGapOperatorPack?.includes('proof-gap-operator-pack-summary.json'), `${label} should expose proof-gap operator pack source`);
- assertOperatorOwnerArtifactsMatch(index?.operatorPackOwnerArtifacts, index?.operatorPackOwnerArtifacts, label);
- }
- function assertHandoffBusinessExecutionOperatorOwnerArtifacts(handoff, label) {
- const item = handoff?.businessExecutionIndex;
- assert(Number(item?.operatorPackOwnerArtifactCount || 0) === Number(item?.operatorPackOwnerArtifacts?.length || 0), `${label} should expose business execution operator owner artifact count`);
- assert(Number(item?.operatorPackOwnerArtifactRowCount || 0) === Number(item?.operatorPackOwnerArtifacts?.length || 0), `${label} should expose business execution operator owner artifact row count`);
- assertOperatorOwnerArtifactsMatch(item?.operatorPackOwnerArtifacts, item?.operatorPackOwnerArtifacts, label);
- }
- function assertOperatorOwnerArtifactsMatch(actualArtifacts, expectedArtifacts, label) {
- const actual = Array.isArray(actualArtifacts) ? actualArtifacts : [];
- const expected = Array.isArray(expectedArtifacts) ? expectedArtifacts.filter(item => item.owner) : [];
- assert(actual.length === expected.length, `${label} should mirror current operator owner artifact count`);
- for (const expectedItem of expected) {
- const item = actual.find(entry => entry.owner === expectedItem.owner);
- assert(item, `${label} should expose ${expectedItem.owner} operator artifact`);
- const markdown = normalizeOwnerArtifactPath(expectedItem.markdown);
- const csv = normalizeOwnerArtifactPath(expectedItem.csv);
- if (markdown) assert(normalizeOwnerArtifactPath(item.markdown).includes(markdown), `${label} should expose ${expectedItem.owner} operator markdown`);
- if (csv) assert(normalizeOwnerArtifactPath(item.csv).includes(csv), `${label} should expose ${expectedItem.owner} operator csv`);
- assert(Number(item?.actionCount || 0) === Number(expectedItem.actionCount || item?.actionCount || 0), `${label} should mirror ${expectedItem.owner} operator action count`);
- assert(Number(item?.evidenceRowCount || 0) === Number(expectedItem.evidenceRowCount || item?.evidenceRowCount || 0), `${label} should mirror ${expectedItem.owner} operator evidence rows`);
- assert(Number(item?.nextActionCount || 0) === Number(expectedItem.nextActionCount || item?.nextActionCount || 0), `${label} should mirror ${expectedItem.owner} operator next actions`);
- }
- }
- function normalizeOwnerArtifactPath(value) {
- const normalized = String(value || '').replace(/\\/g, '/');
- const index = normalized.lastIndexOf('by-owner/');
- return index >= 0 ? normalized.slice(index) : normalized;
- }
- function assertOperatorOwnerArtifact(ownerArtifacts, owner, slug, label) {
- const item = (Array.isArray(ownerArtifacts) ? ownerArtifacts : []).find(entry => entry.owner === owner);
- assert(item?.markdown?.includes(`by-owner/${slug}.md`), `${label} should expose ${owner} operator markdown`);
- assert(item?.csv?.includes(`by-owner/${slug}.csv`), `${label} should expose ${owner} operator csv`);
- assert(Number(item?.actionCount || 0) >= 1, `${label} should expose ${owner} operator action count`);
- assert(Number(item?.evidenceRowCount || 0) >= 1, `${label} should expose ${owner} operator evidence rows`);
- assert(Number(item?.nextActionCount || 0) >= 1, `${label} should expose ${owner} operator next actions`);
- }
- function findBusinessExecutionLongRunRow(index) {
- return (Array.isArray(index?.rows) ? index.rows : []).find(row => row.title === '长跑前置门禁报告');
- }
- function assertHandoffBusinessExecutionLongRunReadiness(handoff, failCount, label) {
- const item = handoff?.businessExecutionIndex?.longRunReadiness;
- assert(item?.report?.includes('long-run-readiness-report.md'), `${label} should expose business execution long-run readiness report row`);
- assert(item?.summary?.includes('long-run-readiness-summary.json'), `${label} should expose business execution long-run readiness summary`);
- assert(item.status === 'blocked', `${label} should keep business execution long-run readiness blocked while ready=false`);
- assert(item.ready === false, `${label} should expose business execution long-run ready=false`);
- assert(Number(item.failCount || 0) === failCount, `${label} should mirror business execution long-run fail count`);
- assert(item.directCustomerProof === false, `${label} should keep business execution long-run proof boundary`);
- }
- function assertOptimizationCompletionPreflightContext(item, label) {
- assert(item, `${label} should exist`);
- assert(item.readyForClaim === false, `${label} should remain not ready for claim`);
- assert(item.videoAbPreflightReadyForVideoAb === false, `${label} should expose video A/B preflight readiness`);
- assert(Number(item.videoAbPreflightFailureCount || 0) >= 1, `${label} should expose video A/B preflight failure count`);
- assert(item.directCustomerProof === false, `${label} should preserve non-customer-proof boundary`);
- }
- function assertBusinessExecutionOptimizationCompletionPreflight(index, completion, label) {
- const row = findBusinessExecutionOptimizationCompletionRow(index);
- assert(row?.mainFile?.includes('optimization-completion-report.md'), `${label} should expose optimization completion report row`);
- assert(row?.expectedArtifact?.includes('optimization-completion-summary.json'), `${label} should expose optimization completion summary artifact`);
- assert(row.status === 'blocked', `${label} should keep optimization completion blocked`);
- assert(String(row.acceptance || '').includes('readyForClaim=false'), `${label} should expose readyForClaim=false`);
- assert(String(row.acceptance || '').includes('videoAbPreflightReadyForVideoAb=false'), `${label} should expose video A/B preflight readiness`);
- assert(String(row.acceptance || '').includes(`videoAbPreflightFailureCount=${Number(completion?.videoAbPreflightFailureCount || 0)}`), `${label} should mirror video A/B preflight failure count`);
- assert(String(row.boundary || '').includes('不得宣称提号率提升'), `${label} should preserve forbidden-claim boundary`);
- }
- function assertHandoffBusinessExecutionOptimizationCompletionPreflight(handoff, completion, label) {
- const item = handoff?.businessExecutionIndex?.optimizationCompletion;
- assert(item?.report?.includes('optimization-completion-report.md'), `${label} should expose business execution optimization completion report row`);
- assert(item?.summary?.includes('optimization-completion-summary.json'), `${label} should expose business execution optimization completion summary`);
- assert(item.status === 'blocked', `${label} should keep business execution optimization completion blocked`);
- assert(item.readyForClaim === false, `${label} should expose business execution optimization readyForClaim=false`);
- assert(item.videoAbPreflightReadyForVideoAb === false, `${label} should expose business execution video A/B preflight readiness`);
- assert(Number(item.videoAbPreflightFailureCount || 0) === Number(completion?.videoAbPreflightFailureCount || 0), `${label} should mirror business execution video A/B preflight failure count`);
- assert(item.directCustomerProof === false, `${label} should keep business execution optimization proof boundary`);
- }
- function findBusinessExecutionOptimizationCompletionRow(index) {
- return (Array.isArray(index?.rows) ? index.rows : []).find(row => row.title === '优化完成度审计报告');
- }
- function runNode(args) {
- const result = spawnSync(process.execPath, args, {
- 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, `${args.join(' ')} should pass`);
- }
- function readJson(file) {
- if (!fs.existsSync(file)) return null;
- return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, ''));
- }
- function assert(condition, message) {
- if (!condition) throw new Error(message);
- }
- if (require.main === module) main();
|