| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996 |
- #!/usr/bin/env node
- const fs = require('fs');
- const path = require('path');
- function main() {
- const root = path.resolve(__dirname, '..');
- const args = parseArgs(process.argv.slice(2));
- const outputDir = path.resolve(args.output || process.env.TIHAO_STATUS_OUTPUT || path.join(root, 'outputs', `optimization-status-${Date.now()}`));
- const summary = buildStatusSummary(root);
- fs.mkdirSync(outputDir, { recursive: true });
- const jsonPath = path.join(outputDir, 'optimization-status-summary.json');
- const mdPath = path.join(outputDir, 'optimization-status-report.md');
- fs.writeFileSync(jsonPath, JSON.stringify(summary, null, 2), 'utf8');
- fs.writeFileSync(mdPath, withBom(renderReport(summary)), 'utf8');
- console.log(JSON.stringify({
- outputDir,
- json: jsonPath,
- report: mdPath,
- counts: summary.counts,
- complete: summary.complete
- }, null, 2));
- }
- function parseArgs(argv) {
- const result = {};
- for (let index = 0; index < argv.length; index += 1) {
- const arg = argv[index];
- if (!arg.startsWith('--')) continue;
- const key = arg.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase());
- const next = argv[index + 1];
- if (!next || next.startsWith('--')) {
- result[key] = true;
- } else {
- result[key] = next;
- index += 1;
- }
- }
- return result;
- }
- function buildStatusSummary(root) {
- const state = collectState(root);
- const items = buildStatusItems(state);
- return {
- generatedAt: new Date().toISOString(),
- root,
- counts: countStatuses(items),
- complete: items.every(item => item.status === 'passed'),
- items
- };
- }
- function collectState(root) {
- const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
- const scripts = packageJson.scripts || {};
- const files = fileSet(root, [
- 'scripts/live-preflight.js',
- 'scripts/long-run-readiness-audit.js',
- 'scripts/long-run-readiness-smoke.js',
- 'scripts/optimization-pipeline.js',
- 'scripts/optimization-pipeline-smoke.js',
- 'scripts/optimization-completion-audit.js',
- 'scripts/optimization-completion-smoke.js',
- 'scripts/generate-optimization-handoff.js',
- 'scripts/generate-optimization-handoff-smoke.js',
- 'scripts/generate-proof-gap-request.js',
- 'scripts/generate-proof-gap-request-smoke.js',
- 'scripts/proof-gap-closure-audit.js',
- 'scripts/proof-gap-closure-smoke.js',
- 'scripts/business-proof-progress.js',
- 'scripts/business-proof-progress-smoke.js',
- 'scripts/business-proof-next-actions.js',
- 'scripts/business-proof-next-actions-smoke.js',
- 'scripts/latest-form-index.js',
- 'scripts/latest-form-index-smoke.js',
- 'scripts/round-deposition-audit.js',
- 'scripts/round-deposition-smoke.js',
- 'scripts/evidence-index.js',
- 'scripts/evidence-index-smoke.js',
- 'scripts/acceptance.js',
- 'scripts/smoke-package.js',
- 'scripts/plan-consistency-smoke.js',
- 'scripts/hard-rules-smoke.js',
- 'scripts/reference-rules-smoke.js',
- 'scripts/platform-sourcing-strategy-smoke.js',
- 'scripts/overnight-quality-campaign.js',
- 'scripts/overnight-manual-review-smoke.js',
- 'scripts/leak-mojibake-audit.js',
- 'scripts/video-hit-rate-audit.js',
- 'scripts/video-hit-rate-audit-smoke.js',
- 'scripts/review-metrics.js',
- 'scripts/customer-effect-audit.js',
- 'scripts/customer-effect-audit-smoke.js',
- 'scripts/create-data-intake-pack.js',
- 'scripts/create-data-intake-pack-smoke.js',
- 'scripts/intake-readiness-audit.js',
- 'scripts/intake-readiness-smoke.js',
- 'scripts/create-video-intake-pack.js',
- 'scripts/create-video-intake-pack-smoke.js',
- 'scripts/video-resource-readiness-audit.js',
- 'scripts/video-resource-readiness-smoke.js',
- 'scripts/homepage-evidence-readiness-audit.js',
- 'scripts/homepage-evidence-readiness-smoke.js',
- 'scripts/history-dataset-from-csv.js',
- 'scripts/history-dataset-from-csv-smoke.js',
- 'scripts/historical-dataset-audit.js',
- 'scripts/candidate-pool-smoke.js',
- 'scripts/feedback-roundtrip-smoke.js',
- 'scripts/feedback-loop-closure-audit.js',
- 'scripts/feedback-loop-closure-smoke.js',
- 'docs/historical-dataset-guide.md',
- 'docs/ai-overnight-optimization-task.md',
- 'docs/ai-optimization-job-dedup-software-format.md',
- 'docs/overnight-quality-runbook.md',
- 'docs/manual-review-handoff.md',
- 'mcp/src/features/tihao-sourcing/homepage-evidence-provider.js',
- 'mcp/src/features/tihao-sourcing/preference-memory.js',
- 'mcp/src/features/tihao-sourcing/report.js'
- ]);
- const packageText = JSON.stringify(packageJson);
- const overnightText = readOptional(path.join(root, 'scripts/overnight-quality-campaign.js'));
- const overnightReviewSmokeText = readOptional(path.join(root, 'scripts/overnight-manual-review-smoke.js'));
- const reviewMetricsText = readOptional(path.join(root, 'scripts/review-metrics.js'));
- const reviewMetricsSmokeText = readOptional(path.join(root, 'scripts/review-metrics-smoke.js'));
- const customerEffectAuditText = readOptional(path.join(root, 'scripts/customer-effect-audit.js'));
- const customerEffectSmokeText = readOptional(path.join(root, 'scripts/customer-effect-audit-smoke.js'));
- const dataIntakePackText = readOptional(path.join(root, 'scripts/create-data-intake-pack.js'));
- const dataIntakePackSmokeText = readOptional(path.join(root, 'scripts/create-data-intake-pack-smoke.js'));
- const intakeReadinessText = readOptional(path.join(root, 'scripts/intake-readiness-audit.js'));
- const intakeReadinessSmokeText = readOptional(path.join(root, 'scripts/intake-readiness-smoke.js'));
- const videoIntakePackText = readOptional(path.join(root, 'scripts/create-video-intake-pack.js'));
- const videoIntakePackSmokeText = readOptional(path.join(root, 'scripts/create-video-intake-pack-smoke.js'));
- const videoResourceReadinessText = readOptional(path.join(root, 'scripts/video-resource-readiness-audit.js'));
- const videoResourceReadinessSmokeText = readOptional(path.join(root, 'scripts/video-resource-readiness-smoke.js'));
- const historyFromCsvText = readOptional(path.join(root, 'scripts/history-dataset-from-csv.js'));
- const historyFromCsvSmokeText = readOptional(path.join(root, 'scripts/history-dataset-from-csv-smoke.js'));
- const memoryText = readOptional(path.join(root, 'mcp/src/features/tihao-sourcing/preference-memory.js'));
- const reportText = readOptional(path.join(root, 'mcp/src/features/tihao-sourcing/report.js'));
- const smokePackageText = readOptional(path.join(root, 'scripts/smoke-package.js'));
- const planConsistencyText = readOptional(path.join(root, 'scripts/plan-consistency-smoke.js'));
- const candidatePoolSmokeText = readOptional(path.join(root, 'scripts/candidate-pool-smoke.js'));
- const hygieneSmokeText = readOptional(path.join(root, 'scripts/leak-mojibake-audit.js'));
- const hardRulesSmokeText = readOptional(path.join(root, 'scripts/hard-rules-smoke.js'));
- const homepageSmokeText = readOptional(path.join(root, 'scripts/homepage-evidence-provider-smoke.js'));
- const homepageReadinessText = readOptional(path.join(root, 'scripts/homepage-evidence-readiness-audit.js'));
- const homepageReadinessSmokeText = readOptional(path.join(root, 'scripts/homepage-evidence-readiness-smoke.js'));
- const referenceRulesSmokeText = readOptional(path.join(root, 'scripts/reference-rules-smoke.js'));
- const platformStrategySmokeText = readOptional(path.join(root, 'scripts/platform-sourcing-strategy-smoke.js'));
- const feedbackRoundtripSmokeText = readOptional(path.join(root, 'scripts/feedback-roundtrip-smoke.js'));
- const feedbackLoopClosureText = readOptional(path.join(root, 'scripts/feedback-loop-closure-audit.js'));
- const feedbackLoopClosureSmokeText = readOptional(path.join(root, 'scripts/feedback-loop-closure-smoke.js'));
- const providerContractText = readOptional(path.join(root, 'scripts/provider-contract-audit.js'));
- const longRunReadinessText = readOptional(path.join(root, 'scripts/long-run-readiness-audit.js'));
- const longRunReadinessSmokeText = readOptional(path.join(root, 'scripts/long-run-readiness-smoke.js'));
- const optimizationPipelineText = readOptional(path.join(root, 'scripts/optimization-pipeline.js'));
- const optimizationPipelineSmokeText = readOptional(path.join(root, 'scripts/optimization-pipeline-smoke.js'));
- const optimizationCompletionText = readOptional(path.join(root, 'scripts/optimization-completion-audit.js'));
- const optimizationCompletionSmokeText = readOptional(path.join(root, 'scripts/optimization-completion-smoke.js'));
- const handoffText = readOptional(path.join(root, 'scripts/generate-optimization-handoff.js'));
- const handoffSmokeText = readOptional(path.join(root, 'scripts/generate-optimization-handoff-smoke.js'));
- const proofGapText = readOptional(path.join(root, 'scripts/generate-proof-gap-request.js'));
- const proofGapSmokeText = readOptional(path.join(root, 'scripts/generate-proof-gap-request-smoke.js'));
- const proofGapClosureText = readOptional(path.join(root, 'scripts/proof-gap-closure-audit.js'));
- const proofGapClosureSmokeText = readOptional(path.join(root, 'scripts/proof-gap-closure-smoke.js'));
- const businessProofProgressText = readOptional(path.join(root, 'scripts/business-proof-progress.js'));
- const businessProofProgressSmokeText = readOptional(path.join(root, 'scripts/business-proof-progress-smoke.js'));
- const businessProofNextActionsText = readOptional(path.join(root, 'scripts/business-proof-next-actions.js'));
- const businessProofNextActionsSmokeText = readOptional(path.join(root, 'scripts/business-proof-next-actions-smoke.js'));
- const latestFormIndexText = readOptional(path.join(root, 'scripts/latest-form-index.js'));
- const latestFormIndexSmokeText = readOptional(path.join(root, 'scripts/latest-form-index-smoke.js'));
- const roundDepositionText = readOptional(path.join(root, 'scripts/round-deposition-audit.js'));
- const roundDepositionSmokeText = readOptional(path.join(root, 'scripts/round-deposition-smoke.js'));
- const evidenceIndexText = readOptional(path.join(root, 'scripts/evidence-index.js'));
- const evidenceIndexSmokeText = readOptional(path.join(root, 'scripts/evidence-index-smoke.js'));
- const videoHitRateAuditText = readOptional(path.join(root, 'scripts/video-hit-rate-audit.js'));
- const videoHitRateAuditSmokeText = readOptional(path.join(root, 'scripts/video-hit-rate-audit-smoke.js'));
- const historyAuditText = readOptional(path.join(root, 'scripts/historical-dataset-audit.js'));
- const historyAuditSmokeText = readOptional(path.join(root, 'scripts/historical-dataset-audit-smoke.js'));
- const docsText = [
- 'docs/tihao-experience-implementation-log.md',
- 'docs/ai-overnight-optimization-task.md',
- 'docs/overnight-quality-runbook.md',
- 'docs/historical-dataset-guide.md',
- 'docs/manual-review-handoff.md',
- 'docs/capability-map.md',
- 'README.md'
- ].map(file => readOptional(path.join(root, file))).join('\n');
- return {
- root,
- scripts,
- files,
- packageText,
- overnightText,
- overnightReviewSmokeText,
- reviewMetricsText,
- reviewMetricsSmokeText,
- customerEffectAuditText,
- customerEffectSmokeText,
- dataIntakePackText,
- dataIntakePackSmokeText,
- intakeReadinessText,
- intakeReadinessSmokeText,
- videoIntakePackText,
- videoIntakePackSmokeText,
- videoResourceReadinessText,
- videoResourceReadinessSmokeText,
- historyFromCsvText,
- historyFromCsvSmokeText,
- memoryText,
- reportText,
- smokePackageText,
- planConsistencyText,
- candidatePoolSmokeText,
- hygieneSmokeText,
- hardRulesSmokeText,
- homepageSmokeText,
- homepageReadinessText,
- homepageReadinessSmokeText,
- referenceRulesSmokeText,
- platformStrategySmokeText,
- feedbackRoundtripSmokeText,
- feedbackLoopClosureText,
- feedbackLoopClosureSmokeText,
- providerContractText,
- longRunReadinessText,
- longRunReadinessSmokeText,
- optimizationPipelineText,
- optimizationPipelineSmokeText,
- optimizationCompletionText,
- optimizationCompletionSmokeText,
- handoffText,
- handoffSmokeText,
- proofGapText,
- proofGapSmokeText,
- proofGapClosureText,
- proofGapClosureSmokeText,
- businessProofProgressText,
- businessProofProgressSmokeText,
- businessProofNextActionsText,
- businessProofNextActionsSmokeText,
- latestFormIndexText,
- latestFormIndexSmokeText,
- roundDepositionText,
- roundDepositionSmokeText,
- evidenceIndexText,
- evidenceIndexSmokeText,
- videoHitRateAuditText,
- videoHitRateAuditSmokeText,
- historyAuditText,
- historyAuditSmokeText,
- docsText,
- outputs: findOutputEvidence(root)
- };
- }
- function buildStatusItems(state) {
- const liveProof = hasLiveProof(state.outputs);
- const customerEffectProof = hasCustomerEffectProof(state.outputs);
- return [
- item({
- id: 'release-chain',
- requirement: '基础发布链路',
- status: hasScripts(state, ['acceptance', 'smoke:package', 'mcp:smoke', 'acceptance:providers:mock']) &&
- state.files['scripts/acceptance.js'] &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("acceptance:providers:mock") &&
- state.smokePackageText.includes('assertFriendlyAuthState') &&
- state.smokePackageText.includes('should not expose raw 401/403') &&
- state.providerContractText.includes('assertProviderFailurePublicOutputSafe') &&
- state.providerContractText.includes('provider failure public output should not expose raw 401/403')
- ? 'passed'
- : 'missing',
- evidence: 'package.json scripts include acceptance/smoke/mcp/provider mock gates; acceptance.js calls provider mock; smoke-package and provider mock cover friendly auth states',
- next: '继续用 npm run acceptance 做发布前验收。'
- }),
- item({
- id: 'software-table',
- requirement: '软件端表格固定表头、去重和连续排名',
- status: state.reportText.includes('SOFTWARE_TABLE_HEADER') &&
- state.reportText.includes('dedupeCandidates') &&
- state.reportText.includes('getReviewPoolTarget') &&
- state.reportText.includes('1.5 倍候选池') &&
- state.scripts['candidate-pool:smoke'] &&
- state.files['scripts/candidate-pool-smoke.js'] &&
- state.candidatePoolSmokeText.includes('duplicate software row key') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("candidate-pool:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'report.js contains fixed software header, candidate dedupe, 1.5x review-pool target, and candidate-pool smoke is in default acceptance',
- next: '真实交付前用 review:metrics 和 CSV 抽检验证重复键、排名连续和候选池规模。'
- }),
- item({
- id: 'output-hygiene',
- requirement: '输出泄密和中文乱码自动化门禁',
- status: state.scripts['hygiene:smoke'] &&
- state.files['scripts/leak-mojibake-audit.js'] &&
- state.hygieneSmokeText.includes('parse-session-token') &&
- state.hygieneSmokeText.includes('common-mojibake') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("hygiene:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'hygiene:smoke scans docs, README, scripts, mcp/src, skills, and fixtures for token-like secrets and common mojibake patterns; default acceptance runs it',
- next: '每次发布前继续运行 npm run acceptance,确保输出不含 token 和乱码。'
- }),
- item({
- id: 'plan-consistency',
- requirement: '长期计划、AI 任务书和 skill 输出规范口径一致',
- status: state.scripts['plan:consistency:smoke'] &&
- state.files['scripts/plan-consistency-smoke.js'] &&
- state.files['docs/ai-optimization-job-dedup-software-format.md'] &&
- state.planConsistencyText.includes('legacy-dedupe-phrase') &&
- state.planConsistencyText.includes('softwareTableHeader') &&
- state.planConsistencyText.includes('unexpected-task-count') &&
- state.planConsistencyText.includes('全局博主唯一') &&
- state.planConsistencyText.includes('docs/tihao-experience-optimization-plan.md') &&
- state.planConsistencyText.includes('docs/ai-optimization-job-dedup-software-format.md') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("plan:consistency:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'plan:consistency:smoke verifies current plan, software table doc, AI task table, dedup software-format task table, and skill output-format all use global creator dedupe; it also checks fixed 17-column software headers, 9 unique deduped OPT rows, and blocks legacy brief-scoped dedupe phrases',
- next: '后续改 SOP 或输出格式时继续让 acceptance 守住计划口径一致性。'
- }),
- item({
- id: 'hard-rules',
- requirement: '硬性规则和剔除账号本地验收',
- status: state.scripts['hard-rules:smoke'] &&
- state.files['scripts/hard-rules-smoke.js'] &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("hard-rules:smoke") &&
- state.hardRulesSmokeText.includes('male generic account should not be strong recommendation') &&
- state.hardRulesSmokeText.includes('low homepage quality creator should not be strong recommendation') &&
- state.hardRulesSmokeText.includes('主页质感风险') &&
- state.hardRulesSmokeText.includes('excluded competitor should not enter software CSV')
- ? 'passed'
- : 'missing',
- evidence: 'hard-rules smoke verifies hard exclusions, implicit category rules, over-budget downgrade, low homepage quality downgrade, platform filtering, and software CSV exclusion',
- next: '继续把新增品类规则加入 hard-rules smoke。'
- }),
- item({
- id: 'homepage-provider-entry',
- requirement: '主页最近内容 provider 接入入口',
- status: state.files['mcp/src/features/tihao-sourcing/homepage-evidence-provider.js'] &&
- state.scripts['homepage:smoke'] &&
- state.homepageSmokeText.includes('assertMockHomepageContract') &&
- state.homepageSmokeText.includes('recent_posts') &&
- state.homepageSmokeText.includes('assertUnauthorizedFallback') &&
- state.homepageSmokeText.includes('public output should not expose raw 401/403')
- ? 'passed'
- : 'missing',
- evidence: 'homepage evidence provider module and homepage:smoke cover provider request contract, successful evidence attachment, unauthorized fallback, and public-output safety',
- next: '真实 provider 配置后打开 TIHAO_GATE_REQUIRE_HOMEPAGE_PROVIDER。'
- }),
- item({
- id: 'homepage-evidence-readiness',
- requirement: '主页近期内容证据就绪审计',
- status: state.scripts['homepage:readiness'] &&
- state.scripts['homepage:readiness:smoke'] &&
- state.files['scripts/homepage-evidence-readiness-audit.js'] &&
- state.files['scripts/homepage-evidence-readiness-smoke.js'] &&
- state.homepageReadinessText.includes('buildHomepageEvidenceReadiness') &&
- state.homepageReadinessText.includes('recentContentWindow') &&
- state.homepageReadinessText.includes('directCustomerProof') &&
- state.homepageReadinessSmokeText.includes('strict weak evidence should fail readiness gate') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("homepage:readiness:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'homepage readiness audit and smoke verify provider/path evidence, recent 10 posts, cover/title/publish/interactions/risk gates, strict failure, and no customer-proof claim',
- next: '真实 provider 或本地主页证据补齐后运行 npm run homepage:readiness -- --strict。'
- }),
- item({
- id: 'feedback-roundtrip',
- requirement: '反馈导入后二轮闭环',
- status: state.scripts['feedback:roundtrip'] &&
- state.scripts['feedback:closure'] &&
- state.scripts['feedback:closure:smoke'] &&
- state.memoryText.includes('blockedCreators') &&
- state.feedbackRoundtripSmokeText.includes('调性不符') &&
- state.feedbackRoundtripSmokeText.includes('主页质感不符') &&
- state.feedbackRoundtripSmokeText.includes('参考账号不像') &&
- state.feedbackRoundtripSmokeText.includes('teamRuleSuggestions') &&
- state.feedbackRoundtripSmokeText.includes('should not enter client-ready candidates') &&
- state.feedbackLoopClosureText.includes('directCustomerProof') &&
- state.feedbackLoopClosureText.includes('leakedCount') &&
- state.feedbackLoopClosureSmokeText.includes('leakedCount === 0') &&
- state.feedbackLoopClosureSmokeText.includes('directCustomerProof === false')
- ? 'passed'
- : 'missing',
- evidence: 'feedback:roundtrip and feedback:closure cover negative feedback import, blocked creator memory, second-round exclusion, leakedCount audit, proof boundary, blocked style memory, and repeated team-rule suggestions',
- next: '导入真实客户反馈 CSV 后复测二轮负样本率。'
- }),
- item({
- id: 'team-rule-suggestions',
- requirement: '团队规则升级建议',
- status: state.memoryText.includes('teamRuleSuggestions') && state.reportText.includes('反馈记忆与团队规则建议') ? 'passed' : 'missing',
- evidence: 'teamRuleSuggestions and report section exist',
- next: '团队确认后再把建议固化为正式规则。'
- }),
- item({
- id: 'video-ab-proof',
- requirement: '视频 A/B 严格验收',
- status: state.scripts['acceptance:video-ab'] &&
- state.scripts['acceptance:video-ab:smoke'] &&
- state.files['scripts/video-hit-rate-audit.js'] &&
- state.files['scripts/video-hit-rate-audit-smoke.js'] &&
- state.videoHitRateAuditText.includes('computeVideoAcceptance') &&
- state.videoHitRateAuditText.includes('strongNotDegraded') &&
- state.videoHitRateAuditText.includes('top10EvidenceImproved') &&
- state.videoHitRateAuditSmokeText.includes('provider failure should fail') &&
- state.videoHitRateAuditSmokeText.includes('strong count degradation should fail')
- ? 'ready_not_proven'
- : 'missing',
- evidence: 'acceptance:video-ab live script and acceptance:video-ab:smoke cover real video resources, provider ok, evidence cards, top10 non-degradation, and strong-count non-degradation',
- next: '需要真实 token/company/provider 运行 npm run acceptance:video-ab。'
- }),
- item({
- id: 'long-run-readiness',
- requirement: '真实长跑启动前就绪度审计',
- status: state.scripts['longrun:readiness'] &&
- state.scripts['longrun:readiness:smoke'] &&
- state.files['scripts/long-run-readiness-audit.js'] &&
- state.files['scripts/long-run-readiness-smoke.js'] &&
- state.longRunReadinessText.includes('readyForLiveAcceptance') &&
- state.longRunReadinessText.includes('readyForCustomerEffectProof') &&
- state.longRunReadinessText.includes('intake-readiness-overall-ready') &&
- state.longRunReadinessText.includes('doubao-seed-2-0-pro') &&
- state.longRunReadinessText.includes('video-resource-readiness-present') &&
- state.longRunReadinessText.includes('proof-gap-unresolved-zero') &&
- state.longRunReadinessSmokeText.includes('customer effect proof should require history audit') &&
- state.longRunReadinessSmokeText.includes('failing intake readiness should block full matrix readiness') &&
- state.longRunReadinessSmokeText.includes('unresolved proof gaps should block full matrix readiness') &&
- state.longRunReadinessSmokeText.includes('video A/B should require video resource readiness summary') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("longrun:readiness:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'longrun:readiness audits live preflight, intake readiness, history audit, video resource readiness, proof-gap status, video A/B readiness, and customer-effect proof prerequisites before starting controlled or full live matrix runs',
- next: '真实长跑前把 live-preflight-summary.json、historical-dataset-audit.json、video-resource-readiness-summary.json 和 proof-gap-request-summary.json 传给 npm run longrun:readiness。'
- }),
- item({
- id: 'optimization-pipeline',
- requirement: '端到端优化链路编排',
- status: state.scripts['optimization:pipeline'] &&
- state.scripts['optimization:pipeline:smoke'] &&
- state.files['scripts/optimization-pipeline.js'] &&
- state.files['scripts/optimization-pipeline-smoke.js'] &&
- state.optimizationPipelineText.includes('history:from-csv') &&
- state.optimizationPipelineText.includes('customer-effect:audit') &&
- state.optimizationPipelineText.includes('evidence:index') &&
- state.optimizationPipelineSmokeText.includes('pipeline should run customer-effect-audit') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("optimization:pipeline:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'optimization:pipeline can compose history CSV import, history audit, readiness, review metrics, customer effect audit, and evidence index in one local workflow',
- next: '真实数据到位后用 optimization:pipeline 串起审计链路;真实 live 长跑仍需 preflight/readiness 控制。'
- }),
- item({
- id: 'optimization-completion',
- requirement: '长期优化完成度审计',
- status: state.scripts['optimization:completion'] &&
- state.scripts['optimization:completion:smoke'] &&
- state.files['scripts/optimization-completion-audit.js'] &&
- state.files['scripts/optimization-completion-smoke.js'] &&
- state.optimizationCompletionText.includes('readyForClaim') &&
- state.optimizationCompletionText.includes('proofGapOpenCount') &&
- state.optimizationCompletionText.includes('canClaim') &&
- state.optimizationCompletionSmokeText.includes('should not allow tihao-rate claim') &&
- state.optimizationCompletionSmokeText.includes('closed fixture should be ready for claim') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("optimization:completion:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'optimization:completion aggregates intake/video/proof-gap/video A/B/live-provider/customer-effect/pipeline/handoff/progress gates and keeps readyForClaim=false until all real proof gates pass',
- next: '每轮结束后运行 npm run round:refresh -- --output-root outputs --strict;只需单独判断是否可声明完成时再运行 npm run optimization:completion -- --output outputs\\optimization-completion-latest。'
- }),
- item({
- id: 'optimization-handoff',
- requirement: '长期优化交接摘要',
- status: state.scripts['handoff:summary'] &&
- state.scripts['handoff:summary:smoke'] &&
- state.files['scripts/generate-optimization-handoff.js'] &&
- state.files['scripts/generate-optimization-handoff-smoke.js'] &&
- state.handoffText.includes('buildHandoffSummary') &&
- state.handoffText.includes('customer-effect:audit') &&
- state.handoffText.includes('不能把 sample、smoke、dry-run') &&
- state.handoffSmokeText.includes('handoff must not mark long-term goal complete without real proof') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("handoff:summary:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'handoff:summary combines optimization status, evidence index, data intake pack paths, next commands, and proof guardrails; smoke verifies it stays incomplete without real proof',
- next: '常规每轮结束后优先运行 npm run round:refresh -- --output-root outputs --strict;只需单独刷新交接摘要时再运行 npm run handoff:summary。'
- }),
- item({
- id: 'proof-gap-request',
- requirement: '真实证明缺口请求包',
- status: state.scripts['proof-gap:request'] &&
- state.scripts['proof-gap:request:smoke'] &&
- state.files['scripts/generate-proof-gap-request.js'] &&
- state.files['scripts/generate-proof-gap-request-smoke.js'] &&
- state.proofGapText.includes('buildProofGapRequest') &&
- state.proofGapText.includes('video-real-candidate') &&
- state.proofGapText.includes('historical-dataset') &&
- state.proofGapText.includes('manual-review-and-customer-effect') &&
- state.proofGapText.includes('不要在 CSV、报告或聊天中写入 sessionToken') &&
- state.proofGapSmokeText.includes('should request real candidate video resources') &&
- state.evidenceIndexText.includes("type: 'proof-gap-request'") &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("proof-gap:request:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'proof-gap:request generates JSON/Markdown/CSV request material for historical data, real video resources, live/provider proof, manual review, customer choices, and manual supplement baseline; smoke verifies boundary and no secret-like values',
- next: '每轮结束后运行 npm run proof-gap:request -- --output outputs\\proof-gap-request-latest,交给商务补齐真实证明数据。'
- }),
- item({
- id: 'proof-gap-closure',
- requirement: '真实证明缺口关闭审计',
- status: state.scripts['proof-gap:closure'] &&
- state.scripts['proof-gap:closure:smoke'] &&
- state.files['scripts/proof-gap-closure-audit.js'] &&
- state.files['scripts/proof-gap-closure-smoke.js'] &&
- state.proofGapClosureText.includes('proof-gap-closure-summary.json') &&
- state.proofGapClosureText.includes('intake-readiness') &&
- state.proofGapClosureText.includes('intakeReady') &&
- state.proofGapClosureText.includes('historical-dataset') &&
- state.proofGapClosureText.includes('video-ab-live-proof') &&
- state.proofGapClosureText.includes('manual-review-and-customer-effect') &&
- state.proofGapClosureSmokeText.includes('openCount') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("proof-gap:closure:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'proof-gap:closure audits intake readiness plus whether the real historical dataset, video resource readiness, video A/B live proof, live/provider overnight proof, and customer-effect proof are actually closed; acceptance runs its smoke gate',
- next: '真实数据补齐后运行 npm run proof-gap:closure -- --output outputs\\proof-gap-closure-latest,只有 openCount=0 才能进入长期完成判断。'
- }),
- item({
- id: 'round-deposition',
- requirement: '每轮沉淀完整性审计',
- status: state.scripts['round:deposition'] &&
- state.scripts['round:deposition:smoke'] &&
- state.files['scripts/round-deposition-audit.js'] &&
- state.files['scripts/round-deposition-smoke.js'] &&
- state.roundDepositionText.includes('buildRoundDepositionSummary') &&
- state.roundDepositionText.includes('implementation-log') &&
- state.roundDepositionText.includes('failureCount') &&
- state.roundDepositionText.includes('software-table') &&
- state.roundDepositionText.includes('video-ab-proof') &&
- state.roundDepositionText.includes('customer-effect-proof') &&
- state.roundDepositionText.includes('proof-gap-unresolved-recorded') &&
- state.roundDepositionText.includes('proofGapUnresolvedCount') &&
- state.roundDepositionSmokeText.includes('round-deposition-audit should pass') &&
- state.roundDepositionSmokeText.includes('summary should include proof-gap unresolved check') &&
- state.evidenceIndexText.includes('classifyRoundDeposition') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("round:deposition:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'round:deposition audits implementation log, status report, evidence index, handoff summary, proof boundaries, live/video/provider indicators, software duplicate/rank status, and review/customer metrics; acceptance runs its smoke gate',
- next: '常规每轮结束后优先运行 npm run round:refresh -- --output-root outputs --strict,确保状态、证据台账、交接摘要和沉淀审计按顺序刷新。'
- }),
- item({
- id: 'business-proof-progress',
- requirement: '15 步补证进度实时同步',
- status: state.scripts['business-proof:progress'] &&
- state.scripts['business-proof:progress:smoke'] &&
- state.files['scripts/business-proof-progress.js'] &&
- state.files['scripts/business-proof-progress-smoke.js'] &&
- state.businessProofProgressText.includes('buildBusinessProofProgress') &&
- state.businessProofProgressText.includes('business-proof-progress-summary.json') &&
- state.businessProofProgressText.includes('blocked_by_external_data') &&
- state.businessProofProgressText.includes('不能把 sample、smoke') &&
- state.businessProofProgressSmokeText.includes('progress should include 15 steps') &&
- state.roundDepositionText.includes('business-proof-progress-summary') &&
- state.roundDepositionText.includes('businessProofProgressCounts') &&
- state.evidenceIndexText.includes("type: 'business-proof-progress'") &&
- state.handoffText.includes('businessProofProgress') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("business-proof:progress:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'business-proof:progress outputs a 15-step pass/pending/fail/blocked_by_external_data progress board; round:deposition requires it, evidence:index classifies it as smoke_or_local, and handoff:summary links it for the next round',
- next: '每轮结束后运行 npm run business-proof:progress -- --output outputs\\business-proof-progress-latest;它只同步补证进度,不证明客户效果。'
- }),
- item({
- id: 'business-proof-next-actions',
- requirement: '下一步补证行动队列',
- status: state.scripts['business-proof:next-actions'] &&
- state.scripts['business-proof:next-actions:smoke'] &&
- state.files['scripts/business-proof-next-actions.js'] &&
- state.files['scripts/business-proof-next-actions-smoke.js'] &&
- state.businessProofNextActionsText.includes('buildNextActions') &&
- state.businessProofNextActionsText.includes('business-proof-next-actions-summary.json') &&
- state.businessProofNextActionsText.includes('ownerGroups') &&
- state.businessProofNextActionsText.includes('ownerArtifacts') &&
- state.businessProofNextActionsText.includes('writeOwnerArtifacts') &&
- state.businessProofNextActionsText.includes('行动队列只用于安排下一步补证') &&
- state.businessProofNextActionsSmokeText.includes('history blocker should be first') &&
- state.businessProofNextActionsSmokeText.includes('owner groups should include business owner') &&
- state.businessProofNextActionsSmokeText.includes('owner artifact files should exist') &&
- state.roundDepositionText.includes('business-proof-next-actions-summary') &&
- state.handoffText.includes('businessProofNextActions') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("business-proof:next-actions:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'business-proof:next-actions converts progress/proof-gap/intake/video blockers into owner, command, expected artifact, and acceptance rows; handoff links it and round:deposition requires it',
- next: '每轮结束后运行 npm run business-proof:next-actions -- --output outputs\\business-proof-next-actions-latest;它只安排补证任务,不证明客户效果。'
- }),
- item({
- id: 'latest-form-index',
- requirement: '最新提号表单统一入口',
- status: state.scripts['latest-form:index'] &&
- state.scripts['latest-form:index:smoke'] &&
- state.files['scripts/latest-form-index.js'] &&
- state.files['scripts/latest-form-index-smoke.js'] &&
- state.latestFormIndexText.includes('buildLatestFormIndex') &&
- state.latestFormIndexText.includes('directCustomerProof') &&
- state.latestFormIndexText.includes('latest-form-index-summary.json') &&
- state.latestFormIndexText.includes('latest-form-index.md') &&
- state.latestFormIndexSmokeText.includes('client list must still require review/customer proof') &&
- state.roundDepositionText.includes('latest-form-index-summary') &&
- state.handoffText.includes('latestFormIndex') &&
- state.evidenceIndexText.includes("type: 'latest-form-index'") &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("latest-form:index:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'latest-form:index exposes the current proof-gap form, software client list, owner action files, and proof guardrails as one handoff entry; smoke verifies it is not treated as customer-effect proof',
- next: '常规每轮结束后优先运行 npm run round:refresh -- --output-root outputs --strict;只需单独定位最新表单时再运行 npm run latest-form:index。'
- }),
- item({
- id: 'evidence-index',
- requirement: '长跑产物证据台账',
- status: state.scripts['evidence:index'] &&
- state.scripts['evidence:index:smoke'] &&
- state.files['scripts/evidence-index.js'] &&
- state.files['scripts/evidence-index-smoke.js'] &&
- state.evidenceIndexText.includes('real_evidence') &&
- state.evidenceIndexText.includes('not_business_proof') &&
- state.evidenceIndexText.includes('live-preflight-summary.json') &&
- state.evidenceIndexText.includes("type: 'live-preflight'") &&
- state.evidenceIndexText.includes('video-hit-rate-summary.json') &&
- state.evidenceIndexText.includes('customer-effect-summary.json') &&
- state.evidenceIndexText.includes("type: 'customer-effect'") &&
- state.evidenceIndexText.includes('optimization-pipeline-summary.json') &&
- state.evidenceIndexText.includes("type: 'optimization-pipeline'") &&
- state.evidenceIndexText.includes('optimization-completion-summary.json') &&
- state.evidenceIndexText.includes("type: 'optimization-completion'") &&
- state.evidenceIndexText.includes('optimization-handoff-summary.json') &&
- state.evidenceIndexText.includes("type: 'optimization-handoff'") &&
- state.evidenceIndexText.includes('proof-gap-request-summary.json') &&
- state.evidenceIndexText.includes("type: 'proof-gap-request'") &&
- state.evidenceIndexText.includes('proof-gap-closure-summary.json') &&
- state.evidenceIndexText.includes("type: 'proof-gap-closure'") &&
- state.evidenceIndexText.includes('round-deposition-summary.json') &&
- state.evidenceIndexText.includes("type: 'round-deposition'") &&
- state.evidenceIndexText.includes("type: 'data-intake-pack'") &&
- state.evidenceIndexText.includes("type: 'video-intake-pack'") &&
- state.evidenceIndexText.includes('intake-readiness-summary.json') &&
- state.evidenceIndexText.includes("type: 'intake-readiness'") &&
- state.evidenceIndexText.includes('video-resource-readiness-summary.json') &&
- state.evidenceIndexText.includes("type: 'video-resource-readiness'") &&
- state.evidenceIndexSmokeText.includes('closed proof-gap closure should be real evidence') &&
- state.evidenceIndexSmokeText.includes('handoff summary') &&
- state.evidenceIndexSmokeText.includes('optimization pipeline orchestration') &&
- state.evidenceIndexSmokeText.includes('optimization completion audits') &&
- state.evidenceIndexSmokeText.includes('optimization handoff summary') &&
- state.evidenceIndexSmokeText.includes('proof gap request summary') &&
- state.evidenceIndexSmokeText.includes('proof gap closure summaries') &&
- state.evidenceIndexSmokeText.includes('round deposition summary') &&
- state.evidenceIndexSmokeText.includes('intake readiness audits') &&
- state.evidenceIndexSmokeText.includes('data intake pack readiness') &&
- state.evidenceIndexSmokeText.includes('video intake pack readiness') &&
- state.evidenceIndexSmokeText.includes('video resource readiness audits') &&
- state.evidenceIndexSmokeText.includes('incomplete customer effect') &&
- state.evidenceIndexSmokeText.includes('missing preflight') &&
- state.evidenceIndexSmokeText.includes('failed live') &&
- state.evidenceIndexSmokeText.includes('weak video') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("evidence:index:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'evidence:index scans outputs and classifies overnight, status, readiness, live preflight, review metrics, customer effect, historical dataset, video A/B, proof-gap request, and proof-gap closure artifacts into real_evidence, smoke_or_local, and not_business_proof',
- next: '每次长跑或复核后优先运行 npm run round:refresh -- --output-root outputs --strict;只需单独刷新证明等级时再运行 npm run evidence:index。'
- }),
- item({
- id: 'overnight-matrix',
- requirement: 'overnight 完整策略矩阵',
- status: ['reference-account', 'homepage-evidence', 'video-enhanced', 'result-first-broad'].every(term => state.overnightText.includes(term)) ? 'passed' : 'missing',
- evidence: 'overnight script contains baseline/reference/homepage/video/result-first variants',
- next: '真实 live 长跑时使用新版 ai-overnight-optimization-task.md。'
- }),
- item({
- id: 'strict-provider-gates',
- requirement: '严格 provider 门禁',
- status: state.overnightText.includes('TIHAO_GATE_REQUIRE_REFERENCE_PROVIDER') && state.overnightText.includes('TIHAO_GATE_REQUIRE_HOMEPAGE_PROVIDER') ? 'passed' : 'missing',
- evidence: 'overnight strict provider gates exist',
- next: '真实 provider 联调时打开 strict gates。'
- }),
- item({
- id: 'reference-rules',
- requirement: '参考账号冲突和强推荐解释本地验收',
- status: state.scripts['reference-rules:smoke'] &&
- state.scripts['platform:strategy:smoke'] &&
- state.files['scripts/reference-rules-smoke.js'] &&
- state.files['scripts/platform-sourcing-strategy-smoke.js'] &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("reference-rules:smoke") &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("platform:strategy:smoke") &&
- state.referenceRulesSmokeText.includes('reference_conflict') &&
- state.referenceRulesSmokeText.includes('不能强行合并') &&
- state.referenceRulesSmokeText.includes('strong candidate reasons should explain reference/style evidence') &&
- state.referenceRulesSmokeText.includes('strong candidates should have reference style or homepage evidence') &&
- state.referenceRulesSmokeText.includes('strong reference style hit points should not contain placeholder evidence') &&
- state.referenceRulesSmokeText.includes('weak placeholder reference evidence should not be enough for strong recommendation') &&
- state.referenceRulesSmokeText.includes('strong candidate reasons should explain homepage evidence') &&
- state.platformStrategySmokeText.includes('reference_similarity') &&
- state.platformStrategySmokeText.includes('keyword_or_recruitment') &&
- state.platformStrategySmokeText.includes('不作为适配证明')
- ? 'passed'
- : 'missing',
- evidence: 'reference-rules and platform strategy smokes verify conflicting references, strong recommendation brief hits, reference/homepage evidence explanation, xiaohongshu reference-similarity path, and douyin keyword/recruitment fallback',
- next: '真实参考账号数据接入后继续用 review:metrics 验证参考链路通过率。'
- }),
- item({
- id: 'review-metrics',
- requirement: '人工复核/业务指标统计',
- status: state.scripts['review:metrics'] &&
- state.scripts['review:metrics:smoke'] &&
- state.scripts['overnight:review:smoke'] &&
- state.files['scripts/overnight-manual-review-smoke.js'] &&
- state.overnightText.includes('归因类型') &&
- state.overnightText.includes('客户选择') &&
- state.overnightReviewSmokeText.includes('manual review sample should include') &&
- state.reviewMetricsText.includes('compareReferenceAndKeywordStrategies') &&
- state.reviewMetricsText.includes('referencePassRateHigherThanKeyword') &&
- state.reviewMetricsSmokeText.includes('reference strategies should outperform keyword baseline') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("overnight:review:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'review metrics command/smoke exist; overnight manual-review sample includes customer decision, attribution, and feedback fields; review metrics compares reference/homepage/video strategies against keyword baseline; default acceptance runs overnight review smoke',
- next: '商务标注 CSV 后运行 npm run review:metrics,负样本必须填写归因类型。'
- }),
- item({
- id: 'customer-effect-audit-entry',
- requirement: '客户效果证明审计入口',
- status: state.scripts['customer-effect:audit'] &&
- state.scripts['customer-effect:smoke'] &&
- state.files['scripts/customer-effect-audit.js'] &&
- state.files['scripts/customer-effect-audit-smoke.js'] &&
- state.customerEffectAuditText.includes('manualSupplementReduction50Pass') &&
- state.customerEffectAuditText.includes('customerSelectedRate50Pass') &&
- state.customerEffectAuditText.includes('referenceCustomerSelectedRate40Pass') &&
- state.customerEffectSmokeText.includes('missing current manual supplement count should block overall pass') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("customer-effect:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'customer-effect:audit combines review metrics, historical manual supplement baseline, current manual supplement count, customer selected-rate gates, and a smoke that blocks missing proof',
- next: '拿到真实客户选择和人工补号量后运行 customer-effect:audit 生成客户效果证明。'
- }),
- item({
- id: 'history-csv-import',
- requirement: '真实历史数据 CSV 导入',
- status: state.scripts['history:from-csv'] &&
- state.scripts['history:from-csv:smoke'] &&
- state.files['scripts/history-dataset-from-csv.js'] &&
- state.files['scripts/history-dataset-from-csv-smoke.js'] &&
- state.historyFromCsvText.includes('manualFinalList') &&
- state.historyFromCsvText.includes('customerFeedback') &&
- state.historyFromCsvText.includes('manualSupplementBaseline') &&
- state.historyFromCsvSmokeText.includes('converted dataset should be ready for customer effect proof') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("history:from-csv:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'history:from-csv converts business CSV rows into per-brief JSON history records and smoke verifies history:audit readiness',
- next: '商务可先按 CSV 模板整理真实历史数据,再运行 history:from-csv 和 history:audit。'
- }),
- item({
- id: 'data-intake-pack',
- requirement: '真实数据收集包',
- status: state.scripts['data:intake-template'] &&
- state.scripts['data:intake-template:smoke'] &&
- state.files['scripts/create-data-intake-pack.js'] &&
- state.files['scripts/create-data-intake-pack-smoke.js'] &&
- state.dataIntakePackText.includes('history-data-template.csv') &&
- state.dataIntakePackText.includes('manual-review-template.csv') &&
- state.dataIntakePackText.includes('历史人工补号量基线') &&
- state.dataIntakePackText.includes('本轮人工补号量') &&
- state.dataIntakePackSmokeText.includes('history template header should match history:from-csv fields') &&
- state.dataIntakePackSmokeText.includes('review template header should match review/customer-effect fields') &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("data:intake-template:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'data:intake-template generates history and manual-review CSV templates plus a README; smoke verifies headers, proof fields, and no secret-like values',
- next: '把生成的数据收集包交给商务填写真实历史 Brief、客户选择和本轮人工补号量。'
- }),
- item({
- id: 'intake-readiness',
- requirement: '真实材料半成品预审',
- status: state.scripts['intake:readiness'] &&
- state.scripts['intake:readiness:smoke'] &&
- state.files['scripts/intake-readiness-audit.js'] &&
- state.files['scripts/intake-readiness-smoke.js'] &&
- state.intakeReadinessText.includes('overallReady') &&
- state.intakeReadinessText.includes('example.com') &&
- state.intakeReadinessText.includes('readyForCustomerEffectAudit') &&
- state.intakeReadinessText.includes('真实候选视频') &&
- state.intakeReadinessSmokeText.includes('fresh templates should not be treated as real intake data') &&
- state.intakeReadinessSmokeText.includes('complete intake fixtures should pass readiness') &&
- state.evidenceIndexText.includes("type: 'intake-readiness'") &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("intake:readiness:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'intake:readiness audits filled data/video intake packs before formal history/video/review/customer-effect audits; smoke verifies fresh templates fail and complete fixtures pass; evidence:index classifies readiness as startup evidence or not_business_proof',
- next: '商务/投放填完模板后先运行 intake:readiness,确认没有示例占位和半成品,再进入 history:audit、video:resource-readiness、review:metrics 和 customer-effect:audit。'
- }),
- item({
- id: 'video-intake-pack',
- requirement: '真实视频资源收集包',
- status: state.scripts['video:intake-template'] &&
- state.scripts['video:intake-template:smoke'] &&
- state.files['scripts/create-video-intake-pack.js'] &&
- state.files['scripts/create-video-intake-pack-smoke.js'] &&
- state.videoIntakePackText.includes('video-resource-template.csv') &&
- state.videoIntakePackText.includes('视频链接') &&
- state.videoIntakePackText.includes('封面链接') &&
- state.videoIntakePackText.includes('字幕或ASR文本') &&
- state.videoIntakePackText.includes('帧图链接') &&
- state.videoIntakePackText.includes('是否真实资源') &&
- state.videoIntakePackText.includes('不得声明视频分析完成') &&
- state.videoIntakePackSmokeText.includes('video resource header should match expected fields') &&
- state.evidenceIndexText.includes("type: 'video-intake-pack'") &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("video:intake-template:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'video:intake-template generates a CSV/README for real reference and candidate video URLs, covers, ASR/subtitles, frame URLs, real-resource flag, and proof boundaries; evidence:index classifies it as smoke_or_local',
- next: '交给商务补齐真实视频资源后,再运行 npm run acceptance:video-ab;模板本身不证明视频分析提升命中率。'
- }),
- item({
- id: 'video-resource-readiness',
- requirement: '视频 A/B 前置资源就绪审计',
- status: state.scripts['video:resource-readiness'] &&
- state.scripts['video:resource-readiness:smoke'] &&
- state.files['scripts/video-resource-readiness-audit.js'] &&
- state.files['scripts/video-resource-readiness-smoke.js'] &&
- state.videoResourceReadinessText.includes('readyForVideoAbPreflight') &&
- state.videoResourceReadinessText.includes('hasRealReferenceResource') &&
- state.videoResourceReadinessText.includes('hasRealCandidateResource') &&
- state.videoResourceReadinessText.includes('hasRealVideoUrl') &&
- state.videoResourceReadinessText.includes('hasCoverOrAsrOrFrameOrText') &&
- state.videoResourceReadinessText.includes('provider ok、证据卡、Top 10 非退化') &&
- state.videoResourceReadinessSmokeText.includes('complete video resources should pass preflight readiness') &&
- state.videoResourceReadinessSmokeText.includes('missing video resources should fail readiness') &&
- state.evidenceIndexText.includes("type: 'video-resource-readiness'") &&
- readOptional(path.join(state.root, 'scripts', 'acceptance.js')).includes("video:resource-readiness:smoke")
- ? 'passed'
- : 'missing',
- evidence: 'video:resource-readiness audits filled video-resource CSVs for real reference video, real candidate video, real video URL, cover/ASR/frame/text evidence, no fake-real rows, and no secret-like values; evidence:index classifies it as smoke_or_local when ready',
- next: '商务填完 video-resource-template.csv 后先运行 video:resource-readiness;通过后再配置 provider 运行 acceptance:video-ab。'
- }),
- item({
- id: 'historical-dataset',
- requirement: '真实历史数据准备验收',
- status: state.scripts['history:audit'] &&
- state.files['docs/historical-dataset-guide.md'] &&
- state.historyAuditText.includes('readyForCustomerEffectProof') &&
- state.historyAuditText.includes('allHaveManualSupplementBaseline') &&
- state.historyAuditSmokeText.includes('missing manual supplement baseline should block customer effect proof')
- ? 'ready_not_proven'
- : 'missing',
- evidence: 'history:audit, historical dataset guide, customer decision gates, rejection reason gates, and manual supplement baseline gates exist',
- next: '先运行 data:intake-template 生成收集包;真实历史 Brief/人工名单/客户选择/人工补号量基线数据填完后通过 history:audit。'
- }),
- item({
- id: 'live-provider-overnight-proof',
- requirement: '真实 live/provider 长跑效果',
- status: liveProof ? 'passed' : 'blocked_by_external_data',
- evidence: liveProof
- ? 'outputs include closable live/provider aggregate: liveEnabled=true, overallPass=true, failureCount=0, failedGateCount=0, tokenLeak=false'
- : 'no current verified live/provider/customer dataset proof in local outputs',
- next: liveProof
- ? '该单项只证明真实 live/provider overnight 通过;仍不能替代客户效果、历史数据或视频 A/B proof。'
- : '需要有效 sessionToken/company/provider 和真实历史数据运行完整 live 矩阵。'
- }),
- item({
- id: 'customer-effect-proof',
- requirement: '客户选中率 30%/40%/50% 和人工补号量减少 50%',
- status: customerEffectProof ? 'passed' : 'blocked_by_external_data',
- evidence: customerEffectProof ? 'review metrics output includes customer selection evidence' : 'no real customer selection dataset has been audited',
- next: '需要客户最终选择字段和人工补号量基线。'
- })
- ];
- }
- function item(value) {
- return { ...value, title: value.title || value.requirement };
- }
- function hasScripts(state, names) {
- return names.every(name => Boolean(state.scripts[name]));
- }
- function findOutputEvidence(root) {
- const outputs = path.join(root, 'outputs');
- if (!fs.existsSync(outputs)) return [];
- return fs.readdirSync(outputs, { withFileTypes: true })
- .filter(entry => entry.isDirectory())
- .map(entry => path.join(outputs, entry.name))
- .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)
- .map(dir => ({
- dir,
- aggregate: readJsonOptional(path.join(dir, 'aggregate-summary.json')),
- review: readJsonOptional(path.join(dir, 'review-metrics-summary.json')),
- history: readJsonOptional(path.join(dir, 'historical-dataset-audit.json')),
- customerEffect: readJsonOptional(path.join(dir, 'customer-effect-summary.json')) ||
- readJsonOptional(path.join(dir, 'customer-effect-audit', 'customer-effect-summary.json'))
- }));
- }
- function hasLiveProof(outputs) {
- return outputs.some(item => isClosableLiveAggregate(item.aggregate));
- }
- function hasCustomerEffectProof(outputs) {
- return outputs.some(item => item.customerEffect?.acceptance?.overallPass === true);
- }
- function isClosableLiveAggregate(aggregate) {
- return Boolean(
- aggregate?.manifest?.liveEnabled === true &&
- aggregate?.acceptance?.overallPass === true &&
- Number(aggregate?.failureCount || 0) === 0 &&
- Number(aggregate?.acceptance?.failedGateCount ?? aggregate?.failedGateCount ?? 0) === 0 &&
- aggregate?.acceptance?.tokenLeak !== true
- );
- }
- function countStatuses(items) {
- const result = {};
- for (const item of items) result[item.status] = (result[item.status] || 0) + 1;
- return result;
- }
- function renderReport(summary) {
- const lines = [
- '# 提号优化计划状态审计',
- '',
- `- 生成时间:${summary.generatedAt}`,
- `- 是否全部完成:${summary.complete ? '是' : '否'}`,
- '',
- '## 状态汇总',
- '',
- ...Object.entries(summary.counts).map(([key, value]) => `- ${key}: ${value}`),
- '',
- '## 要求明细',
- '',
- '| ID | 状态 | 要求 | 当前证据 | 下一步 |',
- '| --- | --- | --- | --- | --- |',
- ...summary.items.map(item => `| ${escapeCell(item.id)} | ${item.status} | ${escapeCell(item.title || item.requirement)} | ${escapeCell(item.evidence)} | ${escapeCell(item.next)} |`),
- '',
- '## 说明',
- '',
- '- `passed` 表示当前代码、脚本或本地验收已覆盖该能力。',
- '- `ready_not_proven` 表示验收入口已具备,但需要真实 token/provider/数据运行后才能证明业务效果。',
- '- `blocked_by_external_data` 表示当前不能靠代码继续证明,需要真实 live 权限、provider 或客户选择数据。'
- ];
- return lines.join('\n');
- }
- function fileSet(root, files) {
- return Object.fromEntries(files.map(file => [file, fs.existsSync(path.join(root, file))]));
- }
- function readOptional(file) {
- return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
- }
- function readJsonOptional(file) {
- if (!fs.existsSync(file)) return null;
- try {
- return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, ''));
- } catch {
- return null;
- }
- }
- function escapeCell(value) {
- return String(value || '').replace(/\|/g, '/').replace(/\n/g, ' ');
- }
- function withBom(text) {
- return `\uFEFF${text}`;
- }
- if (require.main === module) {
- try {
- main();
- } catch (error) {
- console.error(error && error.stack ? error.stack : String(error));
- process.exit(1);
- }
- }
- module.exports = {
- buildStatusItems,
- buildStatusSummary,
- collectState,
- findOutputEvidence,
- hasLiveProof
- };
|