| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157 |
- #!/usr/bin/env node
- const fs = require('fs');
- const path = require('path');
- const { buildStatusSummary } = require('./optimization-status-audit');
- const { buildEvidenceIndex } = require('./evidence-index');
- const ROOT = path.resolve(__dirname, '..');
- const OUTPUTS = path.join(ROOT, 'outputs');
- function main() {
- const args = parseArgs(process.argv.slice(2));
- const outputDir = path.resolve(args.output || process.env.TIHAO_HANDOFF_OUTPUT || path.join(OUTPUTS, `optimization-handoff-${Date.now()}`));
- const summary = buildHandoffSummary({
- root: ROOT,
- outputsDir: path.resolve(args.outputs || OUTPUTS)
- });
- fs.mkdirSync(outputDir, { recursive: true });
- const jsonPath = path.join(outputDir, 'optimization-handoff-summary.json');
- const reportPath = path.join(outputDir, 'optimization-handoff-report.md');
- fs.writeFileSync(jsonPath, JSON.stringify(summary, null, 2), 'utf8');
- fs.writeFileSync(reportPath, withBom(renderReport(summary)), 'utf8');
- console.log(JSON.stringify({
- outputDir,
- json: jsonPath,
- report: reportPath,
- complete: summary.complete,
- readyCapabilities: summary.readyCapabilities.length,
- externalBlockers: summary.externalBlockers.length
- }, null, 2));
- }
- function buildHandoffSummary({ root, outputsDir }) {
- const status = buildStatusSummary(root);
- const evidence = buildEvidenceIndex({ root, outputsDir });
- const latestDataIntakePack = latestEvidenceDir(evidence, 'data-intake-pack');
- const latestBusinessProofProgress = latestEvidenceDir(evidence, 'business-proof-progress');
- const businessProofProgressSummary = latestBusinessProofProgress
- ? readJsonSummary(root, latestBusinessProofProgress, 'business-proof-progress-summary.json')
- : null;
- const latestBusinessProofNextActions = latestOutputDir(outputsDir, /^business-proof-next-actions-/);
- const businessProofNextActionsSummary = latestBusinessProofNextActions
- ? readBusinessProofNextActionsSummary(root, latestBusinessProofNextActions)
- : null;
- const latestBusinessExecutionIndex = latestOutputDir(outputsDir, /^business-execution-index-/);
- const businessExecutionIndexSummary = latestBusinessExecutionIndex
- ? readJsonSummary(root, latestBusinessExecutionIndex, 'business-execution-index-summary.json')
- : null;
- const latestProofGapSoftwareForm = latestOutputDir(outputsDir, /^tihao-proof-gap-software-form-/);
- const proofGapSoftwareFormSummary = latestProofGapSoftwareForm
- ? readJsonSummary(root, latestProofGapSoftwareForm, 'tihao-proof-gap-software-form-summary.json')
- : null;
- const latestProofGapRequest = latestOutputDir(outputsDir, /^proof-gap-request-/);
- const proofGapRequestSummary = latestProofGapRequest
- ? readJsonSummary(root, latestProofGapRequest, 'proof-gap-request-summary.json')
- : null;
- const latestProofGapClosure = latestOutputDir(outputsDir, /^proof-gap-closure-/);
- const proofGapClosureSummary = latestProofGapClosure
- ? readJsonSummary(root, latestProofGapClosure, 'proof-gap-closure-summary.json')
- : null;
- const latestFeedbackLoopClosure = latestOutputDir(outputsDir, /^feedback-loop-closure-/);
- const feedbackLoopClosureSummary = latestFeedbackLoopClosure
- ? readJsonSummary(root, latestFeedbackLoopClosure, 'feedback-loop-closure-summary.json')
- : null;
- const latestHomepageEvidenceReadiness = latestOutputDir(outputsDir, /^homepage-evidence-readiness-/);
- const homepageEvidenceReadinessSummary = latestHomepageEvidenceReadiness
- ? readJsonSummary(root, latestHomepageEvidenceReadiness, 'homepage-evidence-readiness-summary.json')
- : null;
- const latestLongRunReadiness = latestOutputDir(outputsDir, /^long-run-readiness-/);
- const longRunReadinessSummary = latestLongRunReadiness
- ? readJsonSummary(root, latestLongRunReadiness, 'long-run-readiness-summary.json')
- : null;
- const latestIntakeFieldChecklist = latestOutputDir(outputsDir, /^intake-field-checklist-/);
- const intakeFieldChecklistSummary = latestIntakeFieldChecklist
- ? readJsonSummary(root, latestIntakeFieldChecklist, 'intake-field-checklist-summary.json')
- : null;
- const latestFormIndex = latestOutputDir(outputsDir, /^latest-form-index-/);
- const latestFormIndexSummary = latestFormIndex
- ? readJsonSummary(root, latestFormIndex, 'latest-form-index-summary.json')
- : null;
- const latestLocalSeedToIntakeWorklist = latestOutputDir(outputsDir, /^local-seed-to-intake-worklist-/);
- const localSeedToIntakeWorklistSummary = latestLocalSeedToIntakeWorklist
- ? readJsonSummary(root, latestLocalSeedToIntakeWorklist, 'local-seed-to-intake-worklist-summary.json')
- : latestFormIndexSummary?.localSeedToIntakeWorklist || null;
- const latestRealGapMaterialAudit = latestOutputDir(outputsDir, /^real-gap-material-audit-/);
- const realGapMaterialAuditSummary = latestRealGapMaterialAudit
- ? readJsonSummary(root, latestRealGapMaterialAudit, 'real-gap-material-audit-summary.json')
- : latestFormIndexSummary?.realGapMaterialAudit || null;
- const latestPlanExecutionStatus = latestOutputDir(outputsDir, /^plan-execution-status-/);
- const planExecutionStatusSummary = latestPlanExecutionStatus
- ? readJsonSummary(root, latestPlanExecutionStatus, 'plan-execution-status-summary.json')
- : latestFormIndexSummary?.planExecutionStatus || null;
- const latestProofGapOperatorPack = latestOutputDir(outputsDir, /^proof-gap-operator-pack-/);
- const proofGapOperatorPackSummary = latestProofGapOperatorPack
- ? readJsonSummary(root, latestProofGapOperatorPack, 'proof-gap-operator-pack-summary.json')
- : latestFormIndexSummary?.proofGapOperatorPack || null;
- const latestRealProofIntakeBundle = latestOutputDir(outputsDir, /^real-proof-intake-bundle-/);
- const realProofIntakeBundleSummary = latestRealProofIntakeBundle
- ? readJsonSummary(root, latestRealProofIntakeBundle, 'real-proof-intake-bundle-summary.json')
- : latestFormIndexSummary?.realProofIntakeBundle || null;
- const latestRealProofClosureWorkOrder = latestOutputDir(outputsDir, /^real-proof-closure-work-order-/);
- const realProofClosureWorkOrderSummary = latestRealProofClosureWorkOrder
- ? readJsonSummary(root, latestRealProofClosureWorkOrder, 'real-proof-closure-work-order-summary.json')
- : latestFormIndexSummary?.realProofClosureWorkOrder || null;
- const latestRepairActions = latestFormIndexSummary?.repairActions || buildRepairActionsSummary(root);
- const latestOptimizationPipeline = latestOutputDir(outputsDir, /^optimization-pipeline-/);
- const optimizationPipelineSummary = latestOptimizationPipeline
- ? readOptimizationPipelineSummary(root, latestOptimizationPipeline)
- : null;
- const latestOptimizationCompletion = latestOutputDir(outputsDir, /^optimization-completion-/);
- const optimizationCompletionSummary = latestOptimizationCompletion
- ? readJsonSummary(root, latestOptimizationCompletion, 'optimization-completion-summary.json')
- : latestFormIndexSummary?.optimizationCompletion || null;
- const latestEvidenceIndex = latestOutputDir(outputsDir, /^evidence-index-/) || latestEvidenceDir(evidence, 'optimization-status');
- const proofActionOrderPath = firstExistingPath(root, [
- path.join('docs', 'business-proof-action-order.zh-CN.md'),
- path.join('docs', 'business-proof-action-order.md')
- ]);
- const supportDocs = [
- {
- title: '长期优化计划主文件',
- path: path.join(root, 'docs', 'tihao-experience-optimization-plan.md'),
- purpose: '当前目标文件;用于执行长期优化计划、同步每轮进度、确认验收标准和完成边界。'
- },
- {
- title: '长期优化计划中文执行版',
- path: path.join(root, 'docs', 'tihao-experience-optimization-plan.zh-CN.md'),
- purpose: '用于下一轮 AI 或项目负责人理解长期目标、策略矩阵、验收标准和完成边界。'
- },
- {
- title: '补证操作顺序中文执行版',
- path: path.join(root, 'docs', 'business-proof-action-order.zh-CN.md'),
- purpose: '用于商务、投放、技术/AI 按 15 步顺序补齐真实材料和验收证据。'
- }
- ,
- {
- title: '提号任务交接入口',
- path: path.join(root, 'docs', 'tihao-handoff-index.md'),
- purpose: '下一轮 AI、商务或投放接手时优先打开;按顺序定位主计划、补证顺序、最新表单索引、真实材料总包、proof-gap 请求包、商务执行总表和交接摘要。'
- }
- ]
- .filter(item => fs.existsSync(item.path))
- .map(item => ({
- title: item.title,
- doc: rel(root, item.path),
- purpose: item.purpose
- }));
- const readyCapabilities = status.items
- .filter(item => item.status === 'passed')
- .map(publicStatusItem);
- const readyNotProven = status.items
- .filter(item => item.status === 'ready_not_proven')
- .map(publicStatusItem);
- const externalBlockers = status.items
- .filter(item => item.status === 'blocked_by_external_data')
- .map(publicStatusItem);
- const businessProofNextActionSourceState = normalizeBusinessProofNextActionSourceState(businessProofNextActionsSummary?.sourceState);
- const latestFormNextActionSourceState = normalizeBusinessProofNextActionSourceState(latestFormIndexSummary?.nextActions?.sourceState);
- const pipelineStaleSummary = buildPipelineStaleSummary(businessProofNextActionSourceState, latestFormNextActionSourceState);
- const proofGapClosureCounts = normalizeProofGapClosureCounts(proofGapClosureSummary);
- return {
- generatedAt: new Date().toISOString(),
- root,
- outputsDir,
- complete: status.complete,
- statusCounts: status.counts,
- evidenceCounts: evidence.counts,
- evidenceByType: evidence.byType,
- readyCapabilities,
- readyNotProven,
- externalBlockers,
- pipelineStaleSummary,
- dataIntakePack: latestDataIntakePack ? {
- dir: latestDataIntakePack,
- historyTemplate: artifactRef(root, artifactPath(root, latestDataIntakePack, 'history-data-template.csv')),
- manualReviewTemplate: artifactRef(root, artifactPath(root, latestDataIntakePack, 'manual-review-template.csv')),
- readme: artifactRef(root, artifactPath(root, latestDataIntakePack, 'README.md'))
- } : null,
- localSeedToIntakeWorklist: latestLocalSeedToIntakeWorklist || latestFormIndexSummary?.localSeedToIntakeWorklist ? normalizeLocalSeedToIntakeWorklist({
- ...(latestFormIndexSummary?.localSeedToIntakeWorklist || {}),
- ...(localSeedToIntakeWorklistSummary || {}),
- markdown: latestFormIndexSummary?.localSeedToIntakeWorklist?.markdown || (latestLocalSeedToIntakeWorklist ? artifactRef(root, artifactPath(root, latestLocalSeedToIntakeWorklist, 'local-seed-to-intake-worklist.md')) : ''),
- csv: latestFormIndexSummary?.localSeedToIntakeWorklist?.csv || (latestLocalSeedToIntakeWorklist ? artifactRef(root, artifactPath(root, latestLocalSeedToIntakeWorklist, 'local-seed-to-intake-worklist.csv')) : ''),
- summary: latestFormIndexSummary?.localSeedToIntakeWorklist?.summary || (latestLocalSeedToIntakeWorklist ? artifactRef(root, artifactPath(root, latestLocalSeedToIntakeWorklist, 'local-seed-to-intake-worklist-summary.json')) : ''),
- historyDraft: latestFormIndexSummary?.localSeedToIntakeWorklist?.historyDraft || (latestLocalSeedToIntakeWorklist ? artifactRef(root, artifactPath(root, latestLocalSeedToIntakeWorklist, 'history-intake-draft.csv')) : ''),
- videoWorklist: latestFormIndexSummary?.localSeedToIntakeWorklist?.videoWorklist || (latestLocalSeedToIntakeWorklist ? artifactRef(root, artifactPath(root, latestLocalSeedToIntakeWorklist, 'video-resource-worklist.csv')) : ''),
- candidateWorklist: latestFormIndexSummary?.localSeedToIntakeWorklist?.candidateWorklist || (latestLocalSeedToIntakeWorklist ? artifactRef(root, artifactPath(root, latestLocalSeedToIntakeWorklist, 'candidate-seed-worklist.csv')) : '')
- }) : null,
- realGapMaterialAudit: latestRealGapMaterialAudit || latestFormIndexSummary?.realGapMaterialAudit ? normalizeRealGapMaterialAudit({
- ...(latestFormIndexSummary?.realGapMaterialAudit || {}),
- ...(realGapMaterialAuditSummary || {}),
- markdown: latestFormIndexSummary?.realGapMaterialAudit?.markdown || (latestRealGapMaterialAudit ? artifactRef(root, artifactPath(root, latestRealGapMaterialAudit, 'real-gap-material-audit.md')) : ''),
- csv: latestFormIndexSummary?.realGapMaterialAudit?.csv || (latestRealGapMaterialAudit ? artifactRef(root, artifactPath(root, latestRealGapMaterialAudit, 'real-gap-material-audit.csv')) : ''),
- summary: latestFormIndexSummary?.realGapMaterialAudit?.summary || (latestRealGapMaterialAudit ? artifactRef(root, artifactPath(root, latestRealGapMaterialAudit, 'real-gap-material-audit-summary.json')) : '')
- }) : null,
- proofActionOrder: proofActionOrderPath ? {
- doc: rel(root, proofActionOrderPath),
- purpose: '先按 15 步补齐真实历史 Brief、真实视频资源、商务复核和客户效果证明,再启动长跑或宣称效果。'
- } : null,
- supportDocs,
- businessProofProgress: latestBusinessProofProgress ? {
- dir: latestBusinessProofProgress,
- summary: artifactRef(root, artifactPath(root, latestBusinessProofProgress, 'business-proof-progress-summary.json')),
- report: artifactRef(root, artifactPath(root, latestBusinessProofProgress, 'business-proof-progress-report.md')),
- complete: Boolean(businessProofProgressSummary?.complete),
- counts: businessProofProgressSummary?.counts || {},
- operatorPackOwnerArtifactCount: Number(businessProofProgressSummary?.operatorPackOwnerArtifactCount || (Array.isArray(businessProofProgressSummary?.operatorPackOwnerArtifacts) ? businessProofProgressSummary.operatorPackOwnerArtifacts.length : 0)),
- operatorPackOwnerArtifacts: normalizeProofGapOperatorOwnerArtifacts(businessProofProgressSummary?.operatorPackOwnerArtifacts || []),
- proofGapOperatorPackOwnerArtifactCount: Number(businessProofProgressSummary?.observed?.proofGapOperatorPackOwnerArtifactCount || 0),
- businessExecutionOperatorPackOwnerArtifactCount: Number(businessProofProgressSummary?.observed?.businessExecutionOperatorPackOwnerArtifactCount || 0),
- businessExecutionOperatorPackOwnerArtifactRowCount: Number(businessProofProgressSummary?.observed?.businessExecutionOperatorPackOwnerArtifactRowCount || 0)
- } : null,
- businessProofNextActions: latestBusinessProofNextActions ? {
- dir: latestBusinessProofNextActions,
- summary: artifactRef(root, artifactPath(root, latestBusinessProofNextActions, 'business-proof-next-actions-summary.json')),
- report: artifactRef(root, artifactPath(root, latestBusinessProofNextActions, 'business-proof-next-actions-report.md')),
- csv: artifactRef(root, artifactPath(root, latestBusinessProofNextActions, 'business-proof-next-actions.csv')),
- complete: Boolean(businessProofNextActionsSummary?.complete),
- actionCount: Number(businessProofNextActionsSummary?.actionCount ?? (Array.isArray(businessProofNextActionsSummary?.actions) ? businessProofNextActionsSummary.actions.length : 0)),
- ownerGroupCount: Number(businessProofNextActionsSummary?.ownerGroupCount ?? (Array.isArray(businessProofNextActionsSummary?.ownerGroups) ? businessProofNextActionsSummary.ownerGroups.length : 0)),
- ownerArtifactCount: Number(businessProofNextActionsSummary?.ownerArtifactCount ?? (Array.isArray(businessProofNextActionsSummary?.ownerArtifacts) ? businessProofNextActionsSummary.ownerArtifacts.length : 0)),
- sourceState: businessProofNextActionSourceState,
- topActions: normalizeBusinessProofNextTopActions(
- Array.isArray(businessProofNextActionsSummary?.topActions) && businessProofNextActionsSummary.topActions.length
- ? businessProofNextActionsSummary.topActions
- : businessProofNextActionsSummary?.actions
- ),
- ownerGroups: businessProofNextActionsSummary ? businessProofNextActionsSummary.ownerGroups || [] : [],
- ownerArtifacts: normalizeOwnerArtifacts(root, latestBusinessProofNextActions, businessProofNextActionsSummary)
- } : null,
- businessExecutionIndex: latestBusinessExecutionIndex ? {
- dir: latestBusinessExecutionIndex,
- summary: artifactRef(root, artifactPath(root, latestBusinessExecutionIndex, 'business-execution-index-summary.json')),
- report: artifactRef(root, artifactPath(root, latestBusinessExecutionIndex, 'business-execution-index.md')),
- csv: artifactRef(root, artifactPath(root, latestBusinessExecutionIndex, 'business-execution-index.csv')),
- passed: Boolean(businessExecutionIndexSummary?.passed),
- rowCount: Number(businessExecutionIndexSummary?.rowCount || 0),
- repairRowCount: Number(businessExecutionIndexSummary?.repairRowCount || 0),
- operatorPackOwnerArtifactRowCount: Number(businessExecutionIndexSummary?.operatorPackOwnerArtifactRowCount || 0),
- operatorPackOwnerArtifactCount: Number(businessExecutionIndexSummary?.operatorPackOwnerArtifactCount || (Array.isArray(businessExecutionIndexSummary?.operatorPackOwnerArtifacts) ? businessExecutionIndexSummary.operatorPackOwnerArtifacts.length : 0)),
- operatorPackOwnerArtifacts: normalizeProofGapOperatorOwnerArtifacts(businessExecutionIndexSummary?.operatorPackOwnerArtifacts || []),
- proofOpenCount: Number(businessExecutionIndexSummary?.proofOpenCount || 0),
- directCustomerProof: Boolean(businessExecutionIndexSummary?.directCustomerProof),
- longRunReadiness: normalizeBusinessExecutionLongRunReadiness(businessExecutionIndexSummary, longRunReadinessSummary),
- optimizationCompletion: normalizeBusinessExecutionOptimizationCompletion(businessExecutionIndexSummary, optimizationCompletionSummary)
- } : null,
- proofGapClosure: latestProofGapClosure ? {
- dir: latestProofGapClosure,
- summary: artifactRef(root, artifactPath(root, latestProofGapClosure, 'proof-gap-closure-summary.json')),
- report: artifactRef(root, artifactPath(root, latestProofGapClosure, 'proof-gap-closure-report.md')),
- complete: Boolean(proofGapClosureSummary?.complete),
- openCount: Number(proofGapClosureSummary?.openCount || 0),
- closedCount: Number(proofGapClosureSummary?.closedCount || 0),
- businessOpenCount: proofGapClosureCounts.businessOpenCount,
- businessClosedCount: proofGapClosureCounts.businessClosedCount,
- businessGapCount: proofGapClosureCounts.businessGapCount,
- totalRows: proofGapClosureCounts.totalRows,
- precheckRowCount: proofGapClosureCounts.precheckRowCount,
- precheckOpenCount: proofGapClosureCounts.precheckOpenCount,
- precheckClosedCount: proofGapClosureCounts.precheckClosedCount,
- countSemantics: proofGapClosureCounts.countSemantics,
- intakeReady: Boolean(proofGapClosureSummary?.intakeReady),
- rows: normalizeProofGapClosureRows(proofGapClosureSummary)
- } : null,
- feedbackLoopClosure: latestFeedbackLoopClosure ? {
- dir: latestFeedbackLoopClosure,
- summary: artifactRef(root, artifactPath(root, latestFeedbackLoopClosure, 'feedback-loop-closure-summary.json')),
- report: artifactRef(root, artifactPath(root, latestFeedbackLoopClosure, 'feedback-loop-closure-report.md')),
- csv: artifactRef(root, artifactPath(root, latestFeedbackLoopClosure, 'feedback-loop-closure.csv')),
- passed: Boolean(feedbackLoopClosureSummary?.passed),
- complete: Boolean(feedbackLoopClosureSummary?.complete),
- directCustomerProof: Boolean(feedbackLoopClosureSummary?.directCustomerProof),
- proofLevel: feedbackLoopClosureSummary?.proofLevel || '',
- negativeFeedbackCount: Number(feedbackLoopClosureSummary?.negativeFeedbackCount || 0),
- blockedCreatorCount: Number(feedbackLoopClosureSummary?.blockedCreatorCount || 0),
- leakedCount: Number(feedbackLoopClosureSummary?.leakedCount || 0),
- teamRuleSuggestionCount: Number(feedbackLoopClosureSummary?.teamRuleSuggestionCount || 0),
- missingInputs: feedbackLoopClosureSummary?.missingInputs || []
- } : null,
- homepageEvidenceReadiness: latestHomepageEvidenceReadiness ? {
- dir: latestHomepageEvidenceReadiness,
- summary: artifactRef(root, artifactPath(root, latestHomepageEvidenceReadiness, 'homepage-evidence-readiness-summary.json')),
- report: artifactRef(root, artifactPath(root, latestHomepageEvidenceReadiness, 'homepage-evidence-readiness-report.md')),
- csv: artifactRef(root, artifactPath(root, latestHomepageEvidenceReadiness, 'homepage-evidence-repair-actions.csv')),
- ready: Boolean(homepageEvidenceReadinessSummary?.ready),
- complete: Boolean(homepageEvidenceReadinessSummary?.complete),
- directCustomerProof: Boolean(homepageEvidenceReadinessSummary?.directCustomerProof),
- proofLevel: homepageEvidenceReadinessSummary?.proofLevel || '',
- failureCount: Number(homepageEvidenceReadinessSummary?.failureCount || 0),
- providerEvidenceCreators: Number(homepageEvidenceReadinessSummary?.counts?.providerEvidenceCreators || 0),
- creatorsWithPosts: Number(homepageEvidenceReadinessSummary?.counts?.creatorsWithPosts || 0),
- creatorsWithEnoughRecentPosts: Number(homepageEvidenceReadinessSummary?.counts?.creatorsWithEnoughRecentPosts || 0),
- repairActionCount: Array.isArray(homepageEvidenceReadinessSummary?.repairActions) ? homepageEvidenceReadinessSummary.repairActions.length : 0
- } : null,
- proofGapSoftwareForm: latestProofGapSoftwareForm ? {
- dir: latestProofGapSoftwareForm,
- summary: artifactRef(root, artifactPath(root, latestProofGapSoftwareForm, 'tihao-proof-gap-software-form-summary.json')),
- markdown: artifactRef(root, artifactPath(root, latestProofGapSoftwareForm, 'tihao-proof-gap-software-form.md')),
- csv: artifactRef(root, artifactPath(root, latestProofGapSoftwareForm, 'tihao-proof-gap-software-form.csv')),
- passed: Boolean(proofGapSoftwareFormSummary?.passed),
- rowCount: Number(proofGapSoftwareFormSummary?.rowCount || 0),
- duplicateIdCount: Number(proofGapSoftwareFormSummary?.duplicateIdCount || 0),
- headerMatches: Boolean(proofGapSoftwareFormSummary?.headerMatches),
- rowWidthOk: Boolean(proofGapSoftwareFormSummary?.rowWidthOk)
- } : null,
- intakeFieldChecklist: latestIntakeFieldChecklist ? {
- dir: latestIntakeFieldChecklist,
- summary: artifactRef(root, artifactPath(root, latestIntakeFieldChecklist, 'intake-field-checklist-summary.json')),
- report: artifactRef(root, artifactPath(root, latestIntakeFieldChecklist, 'intake-field-checklist.md')),
- csv: artifactRef(root, artifactPath(root, latestIntakeFieldChecklist, 'intake-field-checklist.csv')),
- passed: Boolean(intakeFieldChecklistSummary?.passed),
- itemCount: Number(intakeFieldChecklistSummary?.itemCount || 0),
- missingRequiredCount: Number(intakeFieldChecklistSummary?.missingRequiredCount || 0),
- placeholderCount: Number(intakeFieldChecklistSummary?.placeholderCount || 0),
- ownerGroups: normalizeIntakeOwnerGroups(root, intakeFieldChecklistSummary?.ownerGroups || []),
- recheckCommands: normalizeRecheckCommands(intakeFieldChecklistSummary?.recheckCommands || []),
- directCustomerProof: Boolean(intakeFieldChecklistSummary?.directCustomerProof)
- } : null,
- latestFormIndex: latestFormIndex ? {
- dir: latestFormIndex,
- summary: artifactRef(root, artifactPath(root, latestFormIndex, 'latest-form-index-summary.json')),
- report: artifactRef(root, artifactPath(root, latestFormIndex, 'latest-form-index.md')),
- passed: Boolean(latestFormIndexSummary?.passed),
- primaryFormCsv: latestFormIndexSummary?.primaryForm?.csv || '',
- clientListCsv: latestFormIndexSummary?.clientList?.csv || '',
- complete: Boolean(latestFormIndexSummary?.nextActions?.complete),
- actionCount: Number(latestFormIndexSummary?.nextActions?.actionCount || 0),
- proofOpenCount: Number(latestFormIndexSummary?.nextActions?.proofOpenCount || 0),
- ownerGroupCount: Number(latestFormIndexSummary?.nextActions?.ownerGroupCount || (Array.isArray(latestFormIndexSummary?.nextActions?.ownerGroups) ? latestFormIndexSummary.nextActions.ownerGroups.length : 0)),
- ownerArtifactCount: Number(latestFormIndexSummary?.nextActions?.ownerArtifactCount || (Array.isArray(latestFormIndexSummary?.nextActions?.ownerArtifacts) ? latestFormIndexSummary.nextActions.ownerArtifacts.length : 0)),
- sourceState: latestFormNextActionSourceState,
- topActions: normalizeBusinessProofNextTopActions(latestFormIndexSummary?.nextActions?.topActions),
- intakeFieldChecklist: buildLatestFormIndexChecklistSummary({
- root,
- latestFormIndexSummary,
- latestIntakeFieldChecklist,
- intakeFieldChecklistSummary
- }),
- manualReviewLabelGuide: normalizeManualReviewLabelGuide(latestFormIndexSummary?.manualReviewLabelGuide),
- businessFillGuide: normalizeBusinessFillGuide(latestFormIndexSummary?.businessFillGuide),
- planExecutionStatus: normalizePlanExecutionStatus(latestFormIndexSummary?.planExecutionStatus || planExecutionStatusSummary),
- proofGapRequest: normalizeProofGapRequest(latestFormIndexSummary?.proofGapRequest || (latestProofGapRequest ? {
- ...(proofGapRequestSummary || {}),
- markdown: artifactRef(root, artifactPath(root, latestProofGapRequest, 'proof-gap-request-report.md')),
- csv: artifactRef(root, artifactPath(root, latestProofGapRequest, 'proof-gap-request-table.csv')),
- summary: artifactRef(root, artifactPath(root, latestProofGapRequest, 'proof-gap-request-summary.json'))
- } : proofGapRequestSummary)),
- proofGapOperatorPack: normalizeProofGapOperatorPack(latestFormIndexSummary?.proofGapOperatorPack || proofGapOperatorPackSummary),
- realProofIntakeBundle: normalizeRealProofIntakeBundle(latestFormIndexSummary?.realProofIntakeBundle || realProofIntakeBundleSummary),
- realProofClosureWorkOrder: normalizeRealProofClosureWorkOrder(latestFormIndexSummary?.realProofClosureWorkOrder || realProofClosureWorkOrderSummary),
- localSeedToIntakeWorklist: normalizeLocalSeedToIntakeWorklist(latestFormIndexSummary?.localSeedToIntakeWorklist || localSeedToIntakeWorklistSummary),
- realGapMaterialAudit: normalizeRealGapMaterialAudit(latestFormIndexSummary?.realGapMaterialAudit || realGapMaterialAuditSummary),
- longRunReadiness: normalizeLongRunReadiness(latestFormIndexSummary?.longRunReadiness || (latestLongRunReadiness ? {
- ...(longRunReadinessSummary || {}),
- report: artifactRef(root, artifactPath(root, latestLongRunReadiness, 'long-run-readiness-report.md')),
- summary: artifactRef(root, artifactPath(root, latestLongRunReadiness, 'long-run-readiness-summary.json'))
- } : longRunReadinessSummary)),
- optimizationCompletion: normalizeOptimizationCompletion(latestFormIndexSummary?.optimizationCompletion || (latestOptimizationCompletion ? {
- ...(optimizationCompletionSummary || {}),
- report: artifactRef(root, artifactPath(root, latestOptimizationCompletion, 'optimization-completion-report.md')),
- summary: artifactRef(root, artifactPath(root, latestOptimizationCompletion, 'optimization-completion-summary.json'))
- } : optimizationCompletionSummary)),
- repairActions: latestRepairActions
- } : null,
- planExecutionStatus: latestPlanExecutionStatus || latestFormIndexSummary?.planExecutionStatus ? normalizePlanExecutionStatus({
- ...(latestFormIndexSummary?.planExecutionStatus || {}),
- ...(planExecutionStatusSummary || {}),
- markdown: latestFormIndexSummary?.planExecutionStatus?.markdown || (latestPlanExecutionStatus ? artifactRef(root, artifactPath(root, latestPlanExecutionStatus, 'plan-execution-status.md')) : ''),
- csv: latestFormIndexSummary?.planExecutionStatus?.csv || (latestPlanExecutionStatus ? artifactRef(root, artifactPath(root, latestPlanExecutionStatus, 'plan-execution-status.csv')) : ''),
- summary: latestFormIndexSummary?.planExecutionStatus?.summary || (latestPlanExecutionStatus ? artifactRef(root, artifactPath(root, latestPlanExecutionStatus, 'plan-execution-status-summary.json')) : '')
- }) : null,
- proofGapRequest: latestProofGapRequest || latestFormIndexSummary?.proofGapRequest ? normalizeProofGapRequest({
- ...(latestFormIndexSummary?.proofGapRequest || {}),
- ...(proofGapRequestSummary || {}),
- markdown: latestFormIndexSummary?.proofGapRequest?.markdown || (latestProofGapRequest ? artifactRef(root, artifactPath(root, latestProofGapRequest, 'proof-gap-request-report.md')) : ''),
- csv: latestFormIndexSummary?.proofGapRequest?.csv || (latestProofGapRequest ? artifactRef(root, artifactPath(root, latestProofGapRequest, 'proof-gap-request-table.csv')) : ''),
- summary: latestFormIndexSummary?.proofGapRequest?.summary || (latestProofGapRequest ? artifactRef(root, artifactPath(root, latestProofGapRequest, 'proof-gap-request-summary.json')) : '')
- }) : null,
- proofGapOperatorPack: latestProofGapOperatorPack || latestFormIndexSummary?.proofGapOperatorPack ? normalizeProofGapOperatorPack({
- ...(latestFormIndexSummary?.proofGapOperatorPack || {}),
- ...(proofGapOperatorPackSummary || {}),
- ownerArtifacts: latestFormIndexSummary?.proofGapOperatorPack?.ownerArtifacts || proofGapOperatorPackSummary?.ownerArtifacts || [],
- ownerArtifactCount: latestFormIndexSummary?.proofGapOperatorPack?.ownerArtifactCount || proofGapOperatorPackSummary?.ownerArtifactCount || 0,
- markdown: latestFormIndexSummary?.proofGapOperatorPack?.markdown || (latestProofGapOperatorPack ? artifactRef(root, artifactPath(root, latestProofGapOperatorPack, 'proof-gap-operator-pack.md')) : ''),
- csv: latestFormIndexSummary?.proofGapOperatorPack?.csv || (latestProofGapOperatorPack ? artifactRef(root, artifactPath(root, latestProofGapOperatorPack, 'proof-gap-operator-pack.csv')) : ''),
- summary: latestFormIndexSummary?.proofGapOperatorPack?.summary || (latestProofGapOperatorPack ? artifactRef(root, artifactPath(root, latestProofGapOperatorPack, 'proof-gap-operator-pack-summary.json')) : '')
- }) : null,
- realProofIntakeBundle: latestRealProofIntakeBundle || latestFormIndexSummary?.realProofIntakeBundle ? normalizeRealProofIntakeBundle({
- ...(latestFormIndexSummary?.realProofIntakeBundle || {}),
- ...(realProofIntakeBundleSummary || {}),
- markdown: latestFormIndexSummary?.realProofIntakeBundle?.markdown || (latestRealProofIntakeBundle ? artifactRef(root, artifactPath(root, latestRealProofIntakeBundle, 'real-proof-intake-bundle.md')) : ''),
- csv: latestFormIndexSummary?.realProofIntakeBundle?.csv || (latestRealProofIntakeBundle ? artifactRef(root, artifactPath(root, latestRealProofIntakeBundle, 'real-proof-intake-bundle.csv')) : ''),
- summary: latestFormIndexSummary?.realProofIntakeBundle?.summary || (latestRealProofIntakeBundle ? artifactRef(root, artifactPath(root, latestRealProofIntakeBundle, 'real-proof-intake-bundle-summary.json')) : '')
- }) : null,
- realProofClosureWorkOrder: latestRealProofClosureWorkOrder || latestFormIndexSummary?.realProofClosureWorkOrder ? normalizeRealProofClosureWorkOrder({
- ...(latestFormIndexSummary?.realProofClosureWorkOrder || {}),
- ...(realProofClosureWorkOrderSummary || {}),
- markdown: latestFormIndexSummary?.realProofClosureWorkOrder?.markdown || (latestRealProofClosureWorkOrder ? artifactRef(root, artifactPath(root, latestRealProofClosureWorkOrder, 'real-proof-closure-work-order.md')) : ''),
- csv: latestFormIndexSummary?.realProofClosureWorkOrder?.csv || (latestRealProofClosureWorkOrder ? artifactRef(root, artifactPath(root, latestRealProofClosureWorkOrder, 'real-proof-closure-work-order.csv')) : ''),
- summary: latestFormIndexSummary?.realProofClosureWorkOrder?.summary || (latestRealProofClosureWorkOrder ? artifactRef(root, artifactPath(root, latestRealProofClosureWorkOrder, 'real-proof-closure-work-order-summary.json')) : '')
- }) : null,
- realGapMaterialAudit: latestRealGapMaterialAudit || latestFormIndexSummary?.realGapMaterialAudit ? normalizeRealGapMaterialAudit({
- ...(latestFormIndexSummary?.realGapMaterialAudit || {}),
- ...(realGapMaterialAuditSummary || {}),
- markdown: latestFormIndexSummary?.realGapMaterialAudit?.markdown || (latestRealGapMaterialAudit ? artifactRef(root, artifactPath(root, latestRealGapMaterialAudit, 'real-gap-material-audit.md')) : ''),
- csv: latestFormIndexSummary?.realGapMaterialAudit?.csv || (latestRealGapMaterialAudit ? artifactRef(root, artifactPath(root, latestRealGapMaterialAudit, 'real-gap-material-audit.csv')) : ''),
- summary: latestFormIndexSummary?.realGapMaterialAudit?.summary || (latestRealGapMaterialAudit ? artifactRef(root, artifactPath(root, latestRealGapMaterialAudit, 'real-gap-material-audit-summary.json')) : '')
- }) : null,
- optimizationCompletion: latestOptimizationCompletion || latestFormIndexSummary?.optimizationCompletion ? normalizeOptimizationCompletion({
- ...(latestFormIndexSummary?.optimizationCompletion || {}),
- ...(optimizationCompletionSummary || {}),
- report: latestFormIndexSummary?.optimizationCompletion?.markdown || latestFormIndexSummary?.optimizationCompletion?.report || (latestOptimizationCompletion ? artifactRef(root, artifactPath(root, latestOptimizationCompletion, 'optimization-completion-report.md')) : ''),
- summary: latestFormIndexSummary?.optimizationCompletion?.summary || (latestOptimizationCompletion ? artifactRef(root, artifactPath(root, latestOptimizationCompletion, 'optimization-completion-summary.json')) : '')
- }) : null,
- longRunReadiness: latestLongRunReadiness || latestFormIndexSummary?.longRunReadiness ? normalizeLongRunReadiness({
- ...(latestFormIndexSummary?.longRunReadiness || {}),
- ...(longRunReadinessSummary || {}),
- report: latestFormIndexSummary?.longRunReadiness?.report || (latestLongRunReadiness ? artifactRef(root, artifactPath(root, latestLongRunReadiness, 'long-run-readiness-report.md')) : ''),
- summary: latestFormIndexSummary?.longRunReadiness?.summary || (latestLongRunReadiness ? artifactRef(root, artifactPath(root, latestLongRunReadiness, 'long-run-readiness-summary.json')) : '')
- }) : null,
- optimizationPipeline: latestOptimizationPipeline ? {
- dir: latestOptimizationPipeline,
- summary: artifactRef(root, artifactPath(root, latestOptimizationPipeline, 'optimization-pipeline-summary.json')),
- report: artifactRef(root, artifactPath(root, latestOptimizationPipeline, 'optimization-pipeline-report.md')),
- counts: optimizationPipelineSummary?.counts || {},
- readyForClaim: Boolean(optimizationPipelineSummary?.readyForClaim),
- nextActions: normalizePipelineNextActions(optimizationPipelineSummary)
- } : null,
- latestEvidenceIndex,
- nextCommands: buildNextCommands(),
- guardrails: [
- '不能把 sample、smoke、dry-run 或 provider fallback 当成客户效果证明。',
- '没有真实视频 URL、封面、字幕、ASR、帧图或正文时,不能声明视频分析完成。',
- '没有客户选择、历史人工补号量基线和本轮人工补号量时,不能声明客户效果完成。',
- '任何报告、日志、模板和输出都不得写入 sessionToken、鉴权头、模型 token 或 npm token。'
- ]
- };
- }
- function publicStatusItem(item) {
- return {
- id: item.id,
- requirement: item.requirement,
- evidence: item.evidence,
- next: item.next
- };
- }
- function buildNextCommands() {
- const commands = [
- {
- stage: '生成真实数据收集包',
- command: 'npm run data:intake-template -- --output outputs\\data-intake-pack-latest',
- when: '商务还没有统一模板时先运行。'
- },
- {
- stage: '真实材料就绪预审',
- command: 'npm run intake:readiness -- --data-pack outputs\\data-intake-pack-latest --video-pack outputs\\video-intake-pack-latest --output outputs\\intake-readiness-latest',
- when: '商务/投放填完历史数据、人工复核和视频资源模板后先运行;它会拦截示例数据、半成品和缺客户选择的表。'
- },
- {
- stage: '长跑前置门禁',
- command: 'npm run longrun:readiness -- --mode full-matrix --intake-readiness outputs\\intake-readiness-latest\\intake-readiness-summary.json --proof-gap outputs\\proof-gap-request-latest\\proof-gap-request-summary.json --proof-gap-closure outputs\\proof-gap-closure-latest\\proof-gap-closure-summary.json --output outputs\\long-run-readiness-latest',
- when: '启动 full-matrix/live 长跑或客户效果审计前运行;ready=false 时只能继续补真实材料,不能宣称长期目标完成。'
- },
- {
- stage: '收集包一键审计 Pipeline',
- command: 'npm run optimization:pipeline -- --data-pack outputs\\data-intake-pack-latest --video-pack outputs\\video-intake-pack-latest --current-manual-supplement-count <本轮人工补号量> --output <输出目录> --strict',
- when: '商务/投放已经按统一收集包填完真实历史数据、人工复核和视频资源后运行;它会先跑 intake readiness,再串起 history/video/review/customer-effect/evidence。'
- },
- {
- stage: '历史数据导入',
- command: 'npm run history:from-csv -- --input <历史数据CSV> --output <history-dataset目录>',
- when: '商务填完历史 Brief、人工名单、客户选择和历史人工补号量基线后运行。'
- },
- {
- stage: '历史数据审计',
- command: 'npm run history:audit -- --input <history-dataset目录> --output <历史审计输出目录> --strict',
- when: '确认历史数据能否支撑长跑和客户效果证明。'
- },
- {
- stage: '商务复核指标',
- command: 'npm run review:metrics -- --input <已标注CSV> --output <复核指标输出目录> --strict',
- when: '本轮 AI 候选已经被商务标注后运行。'
- },
- {
- stage: '主页近期内容证据就绪审计',
- command: 'npm run homepage:readiness -- --input <tihao-sourcing-result.json 或 homepage evidence JSON> --output outputs\\homepage-evidence-readiness-latest',
- when: '真实主页近期内容 provider 或本地证据补齐后运行;检查最近 10/20 篇内容、封面、标题、互动、发布时间和风险信号是否足以支撑强推荐复核。'
- },
- {
- stage: '本地种子转 intake 补表 worklist',
- command: 'npm run local-seed-to-intake:worklist -- --outputs outputs --output outputs\\local-seed-to-intake-worklist-latest',
- when: '需要把本地 DHA Brief、PoC 候选和参考账号解析转成可转写的 history/video/manual-review 草稿时运行;它不写正式模板,也不证明客户效果。'
- },
- {
- stage: '真实证明闭环工单',
- command: 'npm run real-proof:work-order -- --outputs outputs --output outputs\\real-proof-closure-work-order-latest --strict',
- when: '需要把 intake/video/proof-gap/completion 的未关闭项拆到负责人、字段、行范围、种子线索和复验命令时运行;工单不写正式模板,也不证明客户效果。'
- },
- {
- stage: '视频资源收集包',
- command: 'npm run video:intake-template -- --output outputs\\video-intake-pack-latest',
- when: '需要真实测试参考视频/候选视频风格分析前运行,交给商务补视频 URL、封面、ASR、帧图或正文证据。'
- },
- {
- stage: '视频资源就绪审计',
- command: 'npm run video:resource-readiness -- --input <video-resource-template.csv> --output <视频资源审计输出目录> --strict',
- when: '商务补齐视频资源表后运行;通过只代表 A/B 前置资源齐备,不代表视频分析已提升命中率。'
- },
- {
- stage: '视频 A/B 验收',
- command: 'npm run acceptance:video-ab',
- when: '真实 sessionToken、company、VOC social provider 和视频分析 provider 都配置好后运行。'
- },
- {
- stage: '客户效果审计',
- command: 'npm run customer-effect:audit -- --review-csv <已标注CSV> --history-audit <historical-dataset-audit.json> --current-manual-supplement-count <本轮人工补号量> --output <客户效果输出目录> --strict',
- when: '客户选择和人工补号量都到位后运行。'
- },
- {
- stage: '真实证明缺口请求包',
- command: 'npm run proof-gap:request -- --output outputs\\proof-gap-request-latest',
- when: '每轮结束时生成,交给商务或下一轮 AI 对照补齐真实证明材料。'
- },
- {
- stage: '真实证明缺口关闭审计',
- command: 'npm run proof-gap:closure -- --output outputs\\proof-gap-closure-latest',
- when: '真实历史数据、视频资源、视频 A/B、live 长跑或客户效果产物更新后运行;只有 openCount=0 才能进入长期完成判断。'
- },
- {
- stage: '优化完成度审计',
- command: 'npm run optimization:completion -- --output outputs\\optimization-completion-latest',
- when: '每轮 proof-gap closure、客户效果、视频 A/B 或 live/provider 证据更新后运行;只有 readyForClaim=true 才能进入业务效果声明。'
- },
- {
- stage: '反馈二轮闭环审计',
- command: 'npm run feedback:closure -- --feedback <反馈CSV> --memory <记忆JSON> --result <第二轮tihao-sourcing-result.json> --output outputs\\feedback-loop-closure-latest',
- when: '商务/客户负反馈导入记忆并重跑第二轮后运行,检查拉黑、跑偏、调性不符账号是否仍泄漏进可发客户名单。'
- },
- {
- stage: '15 步补证进度表',
- command: 'npm run business-proof:progress -- --output outputs\\business-proof-progress-latest',
- when: '每轮结束时运行,用于同步 15 步补证当前卡点;它不替代客户效果证明。'
- },
- {
- stage: '下一步行动队列',
- command: 'npm run business-proof:next-actions -- --output outputs\\business-proof-next-actions-latest',
- when: '每轮结束时运行,把 blocked/fail/pending 状态转成可分派的负责人、命令和通过标准。'
- },
- {
- stage: '商务执行总表',
- command: 'npm run business-execution:index -- --output outputs\\business-execution-index-latest --strict',
- when: '每轮补证行动变化后运行,把负责人行动、修复清单、最新表单和验收边界汇总成商务可执行 Markdown/CSV。'
- },
- {
- stage: '最新提号补证表单',
- command: 'npm run proof-gap:software-form -- --output outputs\\tihao-proof-gap-software-form-latest --strict',
- when: '每轮补证任务变化后运行,导出软件端固定 17 列 CSV/Markdown 表单;它只安排补证任务,不证明客户效果。'
- },
- {
- stage: '最新提号表单索引',
- command: 'npm run latest-form:index -- --output outputs\\latest-form-index-latest --strict',
- when: '需要快速定位最新补证表单、软件端候选名单和负责人行动文件时运行;常规每轮沉淀优先使用 round:refresh。'
- },
- {
- stage: '真实验收材料收集总包',
- command: 'npm run proof-gap:intake-bundle -- --output outputs\\real-proof-intake-bundle-latest --strict',
- when: '需要给商务一个一站式入口时运行;它会集中真实材料模板、字段缺口、修复清单、证明缺口和复验命令。'
- },
- {
- stage: '每轮沉淀一键刷新',
- command: 'npm run round:refresh -- --output-root outputs --strict',
- when: '每轮优化结束后优先运行,按固定顺序刷新提号补证表单、proof-gap 请求/关闭审计、业务补证进度、下一步行动队列、状态、最新表单索引、交接摘要、完成度审计、证据台账和 round deposition。'
- },
- {
- stage: '证据台账',
- command: 'npm run evidence:index -- --output outputs\\evidence-index-latest',
- when: '需要单独刷新证明等级时运行;常规每轮沉淀优先使用 round:refresh。'
- },
- {
- stage: '交接摘要',
- command: 'npm run handoff:summary -- --output outputs\\optimization-handoff-latest',
- when: '需要单独刷新交接摘要时运行;常规每轮沉淀优先使用 round:refresh。'
- }
- ];
- commands.push({
- stage: '字段级补齐核对表',
- command: 'npm run intake:field-checklist -- --data-pack outputs\\data-intake-pack-latest --video-pack outputs\\video-intake-pack-latest --output outputs\\intake-field-checklist-latest',
- when: '真实材料预审未通过时运行,把缺字段、占位内容和缺最小样本量拆成商务可逐格补齐的 CSV/Markdown。'
- });
- return commands;
- }
- function renderReport(summary) {
- const lines = [
- '# 提号优化交接摘要',
- '',
- `- 生成时间:${summary.generatedAt}`,
- `- 是否完成长期目标:${summary.complete ? '是' : '否'}`,
- '',
- '## 当前状态',
- '',
- `- 已通过能力:${summary.statusCounts.passed || 0}`,
- `- 已具备入口但未真实证明:${summary.statusCounts.ready_not_proven || 0}`,
- `- 受真实外部数据阻塞:${summary.statusCounts.blocked_by_external_data || 0}`,
- '',
- '## 真实证明缺口关闭状态',
- '',
- summary.proofGapClosure
- ? renderProofGapClosure(summary.proofGapClosure)
- : '- 尚未找到 proof-gap closure 摘要,请运行 `npm run proof-gap:closure -- --output outputs\\proof-gap-closure-latest`。',
- '',
- '## 反馈二轮闭环审计',
- '',
- summary.feedbackLoopClosure
- ? renderFeedbackLoopClosure(summary.feedbackLoopClosure)
- : '- 尚未找到反馈二轮闭环审计,请运行 `npm run feedback:closure -- --output outputs\\feedback-loop-closure-latest`。当前不得声明反馈闭环客户效果证明,`directCustomerProof=false`。',
- '',
- '## 主页近期内容证据就绪审计',
- '',
- summary.homepageEvidenceReadiness
- ? renderHomepageEvidenceReadiness(summary.homepageEvidenceReadiness)
- : '- 尚未找到主页近期内容证据就绪审计,请运行 `npm run homepage:readiness -- --output outputs\\homepage-evidence-readiness-latest`。当前不能把 fallback 当作强推荐证据。',
- '',
- '## 长跑前置门禁',
- '',
- summary.longRunReadiness
- ? renderLongRunReadiness(summary.longRunReadiness)
- : '- 尚未找到长跑前置门禁,请运行 `npm run longrun:readiness -- --mode full-matrix --output outputs\\long-run-readiness-latest`。当前不得启动真实 live/full-matrix 长跑。',
- '',
- '## 优化完成度审计',
- '',
- summary.optimizationCompletion
- ? renderOptimizationCompletion(summary.optimizationCompletion)
- : '- 尚未找到优化完成度审计,请运行 `npm run optimization:completion -- --output outputs\\optimization-completion-latest`。当前不得宣称长期优化目标完成。',
- '',
- '## 证据台账',
- '',
- `- real_evidence:${summary.evidenceCounts.real_evidence || 0}`,
- `- smoke_or_local:${summary.evidenceCounts.smoke_or_local || 0}`,
- `- not_business_proof:${summary.evidenceCounts.not_business_proof || 0}`,
- '',
- '| 类型 | 数量 |',
- '| --- | --- |',
- ...Object.entries(summary.evidenceByType || {}).sort().map(([type, count]) => `| ${escapeCell(type)} | ${count} |`),
- '',
- '## 已可本地复用的能力',
- '',
- ...summary.readyCapabilities.map(item => `- ${item.id}:${item.requirement}`),
- '',
- '## 已准备好但不能宣称效果的项目',
- '',
- ...summary.readyNotProven.map(item => `- ${item.id}:${item.requirement}。下一步:${item.next}`),
- '',
- '## 仍需真实数据的阻塞项',
- '',
- ...summary.externalBlockers.map(item => `- ${item.id}:${item.requirement}。下一步:${item.next}`),
- '',
- '## 真实数据入口',
- '',
- summary.dataIntakePack
- ? `- 历史数据模板:${summary.dataIntakePack.historyTemplate}\n- 商务复核模板:${summary.dataIntakePack.manualReviewTemplate}\n- 填写说明:${summary.dataIntakePack.readme}`
- : '- 尚未找到数据收集包,请先运行 `npm run data:intake-template -- --output outputs\\data-intake-pack-latest`。',
- '',
- '## 本地种子转 intake 补表 worklist',
- '',
- summary.localSeedToIntakeWorklist
- ? renderLocalSeedToIntakeWorklist(summary.localSeedToIntakeWorklist)
- : '- 尚未找到本地种子转 intake 补表 worklist,请运行 `npm run local-seed-to-intake:worklist -- --outputs outputs --output outputs\\local-seed-to-intake-worklist-latest`。',
- '',
- '## 中文 SOP 入口',
- '',
- summary.supportDocs && summary.supportDocs.length
- ? renderSupportDocs(summary.supportDocs)
- : '- 尚未找到中文 SOP 执行文档,请优先补齐 `docs/tihao-experience-optimization-plan.zh-CN.md` 和 `docs/business-proof-action-order.zh-CN.md`。',
- '',
- '## 补证操作顺序',
- '',
- summary.proofActionOrder
- ? `- 文档:${summary.proofActionOrder.doc}\n- 用途:${summary.proofActionOrder.purpose}`
- : '- 尚未找到 `docs/business-proof-action-order.md`,请先补齐真实补证操作顺序。',
- '',
- '## 补证进度表',
- '',
- summary.businessProofProgress
- ? renderBusinessProofProgress(summary.businessProofProgress)
- : '- 尚未找到补证进度表,请运行 `npm run business-proof:progress -- --output outputs\\business-proof-progress-latest`。',
- '',
- '## 下一步行动队列',
- '',
- summary.businessProofNextActions
- ? renderBusinessProofNextActions(summary.businessProofNextActions)
- : '- 尚未找到下一步行动队列,请运行 `npm run business-proof:next-actions -- --output outputs\\business-proof-next-actions-latest`。',
- '',
- '## Pipeline stale 摘要',
- '',
- renderPipelineStaleSummary(summary.pipelineStaleSummary),
- '',
- '## 负责人行动文件',
- '',
- summary.businessProofNextActions && summary.businessProofNextActions.ownerArtifacts.length
- ? renderOwnerArtifacts(summary.businessProofNextActions.ownerArtifacts)
- : '- 尚未找到负责人分组文件,请运行 `npm run business-proof:next-actions -- --output outputs\\business-proof-next-actions-latest`。',
- '',
- '## 商务执行总表',
- '',
- summary.businessExecutionIndex
- ? renderBusinessExecutionIndex(summary.businessExecutionIndex)
- : '- 尚未找到商务执行总表,请运行 `npm run business-execution:index -- --output outputs\\business-execution-index-latest --strict`。',
- '',
- '## 最新提号补证表单',
- '',
- summary.proofGapSoftwareForm
- ? renderProofGapSoftwareForm(summary.proofGapSoftwareForm)
- : '- 尚未找到最新提号补证表单,请运行 `npm run proof-gap:software-form -- --output outputs\\tihao-proof-gap-software-form-latest --strict`。',
- '',
- '## 真实材料字段级补齐核对表',
- '',
- summary.intakeFieldChecklist
- ? renderIntakeFieldChecklist(summary.intakeFieldChecklist)
- : '- 尚未找到字段级补齐核对表,请运行 `npm run intake:field-checklist -- --data-pack outputs\\data-intake-pack-latest --video-pack outputs\\video-intake-pack-latest --output outputs\\intake-field-checklist-latest`。',
- '',
- '## 最新提号表单索引',
- '',
- summary.latestFormIndex
- ? renderLatestFormIndex(summary.latestFormIndex)
- : '- 尚未找到最新提号表单索引,请运行 `npm run latest-form:index -- --output outputs\\latest-form-index-latest --strict`。',
- '',
- '## 长期计划执行状态面板',
- '',
- summary.planExecutionStatus
- ? renderPlanExecutionStatus(summary.planExecutionStatus)
- : '- 尚未找到长期计划执行状态面板,请运行 `npm run plan:execution-status -- --output outputs\\plan-execution-status-latest --strict`。',
- '',
- '## 真实证明缺口请求包',
- '',
- summary.proofGapRequest
- ? renderProofGapRequest(summary.proofGapRequest)
- : '- 尚未找到真实证明缺口请求包,请运行 `npm run proof-gap:request -- --output outputs\\proof-gap-request-latest`。',
- '',
- '## 提号补证操作包',
- '',
- summary.proofGapOperatorPack
- ? renderProofGapOperatorPack(summary.proofGapOperatorPack)
- : '- 尚未找到提号补证操作包,请运行 `npm run proof-gap:operator-pack -- --output outputs\\proof-gap-operator-pack-latest --strict`。',
- '',
- '## 真实验收材料收集总包',
- '',
- summary.realProofIntakeBundle
- ? renderRealProofIntakeBundle(summary.realProofIntakeBundle)
- : '- 尚未找到真实验收材料收集总包,请运行 `npm run proof-gap:intake-bundle -- --output outputs\\real-proof-intake-bundle-latest --strict`。',
- '',
- '## 真实证明闭环工单',
- '',
- summary.realProofClosureWorkOrder
- ? renderRealProofClosureWorkOrder(summary.realProofClosureWorkOrder)
- : '- 尚未找到真实证明闭环工单,请运行 `npm run real-proof:work-order -- --outputs outputs --output outputs\\real-proof-closure-work-order-latest --strict`。该工单只指导补真实材料,不证明客户效果。',
- '',
- '## Pipeline 下一步动作',
- '',
- summary.optimizationPipeline
- ? renderPipelineNextActions(summary.optimizationPipeline)
- : '- 尚未找到 `outputs/optimization-pipeline-latest`,请运行收集包一键审计 Pipeline。',
- '',
- '## 下一轮命令',
- '',
- '| 阶段 | 命令 | 使用时机 |',
- '| --- | --- | --- |',
- ...summary.nextCommands.map(item => `| ${escapeCell(item.stage)} | \`${escapeCell(item.command)}\` | ${escapeCell(item.when)} |`),
- '',
- '## 边界',
- '',
- ...summary.guardrails.map(item => `- ${item}`)
- ];
- return lines.join('\n');
- }
- function latestEvidenceDir(evidence, type) {
- const item = (evidence.entries || []).find(entry => entry.type === type);
- return item ? item.dir : '';
- }
- function latestOutputDir(outputsDir, pattern) {
- if (!fs.existsSync(outputsDir)) return '';
- const dirs = fs.readdirSync(outputsDir, { withFileTypes: true })
- .filter(entry => entry.isDirectory() && pattern.test(entry.name))
- .map(entry => path.join(outputsDir, entry.name))
- .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
- return dirs[0] ? artifactRef(ROOT, dirs[0]) : '';
- }
- function firstExistingPath(root, relativePaths) {
- for (const relativePath of relativePaths) {
- const resolved = path.join(root, relativePath);
- if (fs.existsSync(resolved)) return resolved;
- }
- return '';
- }
- function renderSupportDocs(docs) {
- return [
- '| 文档 | 路径 | 用途 |',
- '| --- | --- | --- |',
- ...docs.map(item => tableRow([item.title, item.doc, item.purpose]))
- ].join('\n');
- }
- function readBusinessProofNextActionsSummary(root, dir) {
- const summaryPath = artifactPath(root, dir, 'business-proof-next-actions-summary.json');
- if (!fs.existsSync(summaryPath)) return null;
- try {
- return JSON.parse(fs.readFileSync(summaryPath, 'utf8'));
- } catch {
- return null;
- }
- }
- function readOptimizationPipelineSummary(root, dir) {
- return readJsonSummary(root, dir, 'optimization-pipeline-summary.json');
- }
- function readJsonSummary(root, dir, name) {
- const summaryPath = artifactPath(root, dir, name);
- if (!fs.existsSync(summaryPath)) return null;
- try {
- return JSON.parse(fs.readFileSync(summaryPath, 'utf8'));
- } catch {
- return null;
- }
- }
- function renderProofGapSoftwareForm(form) {
- return [
- `- CSV:${form.csv}`,
- `- Markdown:${form.markdown}`,
- `- Summary:${form.summary}`,
- `- passed:${form.passed ? 'true' : 'false'}`,
- `- rowCount:${form.rowCount}`,
- `- duplicateIdCount:${form.duplicateIdCount}`,
- `- headerMatches:${form.headerMatches ? 'true' : 'false'}`,
- `- rowWidthOk:${form.rowWidthOk ? 'true' : 'false'}`
- ].join('\n');
- }
- function renderIntakeFieldChecklist(checklist) {
- const lines = [
- `- 报告:${checklist.report}`,
- `- CSV:${checklist.csv}`,
- `- Summary:${checklist.summary}`,
- `- passed:${checklist.passed ? 'true' : 'false'}`,
- `- itemCount:${checklist.itemCount}`,
- `- missingRequiredCount:${checklist.missingRequiredCount}`,
- `- placeholderCount:${checklist.placeholderCount}`,
- `- directCustomerProof:${checklist.directCustomerProof ? 'true' : 'false'}`,
- '- 用途:给商务/投放逐字段补齐真实历史 Brief、人工复核、客户选择和视频资源;它不证明客户效果完成。'
- ];
- if (checklist.ownerGroups?.length) {
- lines.push('', '### 按负责人补齐顺序', '', renderIntakeOwnerGroups(checklist.ownerGroups));
- }
- if (checklist.recheckCommands?.length) {
- lines.push('', '### 补齐后复验命令', '', renderRecheckCommands(checklist.recheckCommands));
- }
- return lines.join('\n');
- }
- function renderLatestFormIndex(index) {
- const lines = [
- `- 报告:${index.report}`,
- `- Summary:${index.summary}`,
- `- passed:${index.passed ? 'true' : 'false'}`,
- `- 最新补证表单:${index.primaryFormCsv || '缺失'}`,
- `- 最新候选名单:${index.clientListCsv || '缺失'}`,
- `- complete:${index.complete ? 'true' : 'false'}`,
- `- actionCount:${index.actionCount}`,
- `- proofOpenCount:${index.proofOpenCount}`,
- `- ownerGroupCount:${index.ownerGroupCount || 0}`,
- `- ownerArtifactCount:${index.ownerArtifactCount || 0}`,
- `- intakeFailureCount:${index.sourceState?.intakeFailureCount || 0}`,
- `- videoFailureCount:${index.sourceState?.videoFailureCount || 0}`,
- `- pipelineReadyForClaim:${index.sourceState?.pipelineReadyForClaim ? 'true' : 'false'}`,
- '- 用途:给商务和下一轮 AI 快速定位当前该打开的表单;它不证明客户效果完成。'
- ];
- if (Array.isArray(index.topActions) && index.topActions.length) {
- lines.push(
- '',
- '### 下一步行动队列摘要',
- '',
- '| ID | 优先级 | 负责人 | 动作 | 状态 | 命令 | 通过标准 | 缺证明项 |',
- '| --- | ---: | --- | --- | --- | --- | --- | ---: |',
- ...index.topActions.map(item => tableRow([
- item.id || 'missing',
- item.priority || item.order || 0,
- item.owner || 'missing',
- item.title || 'missing',
- item.status || 'missing',
- item.command || 'missing',
- item.acceptance || 'missing',
- item.missingProofRequirementCount || 0
- ]))
- );
- }
- if (index.intakeFieldChecklist) {
- lines.push(
- '',
- '### 字段补齐核对表索引',
- '',
- `- 报告:${index.intakeFieldChecklist.markdown || '缺失'}`,
- `- CSV:${index.intakeFieldChecklist.csv || '缺失'}`,
- `- ownerGroupCount:${Array.isArray(index.intakeFieldChecklist.ownerGroups) ? index.intakeFieldChecklist.ownerGroups.length : 0}`,
- `- recheckCommandCount:${Array.isArray(index.intakeFieldChecklist.recheckCommands) ? index.intakeFieldChecklist.recheckCommands.length : 0}`
- );
- }
- if (index.businessFillGuide?.rows?.length) {
- lines.push('', renderBusinessFillGuide(index.businessFillGuide));
- }
- if (index.manualReviewLabelGuide) {
- lines.push(
- '',
- '### 人工复核标签与归因指南',
- '',
- `- report: ${index.manualReviewLabelGuide.markdown || 'missing'}`,
- `- csv: ${index.manualReviewLabelGuide.csv || 'missing'}`,
- `- labelCount: ${index.manualReviewLabelGuide.labelCount || 0}`,
- `- attributionTypeCount: ${index.manualReviewLabelGuide.attributionTypeCount || 0}`,
- `- directCustomerProof: ${index.manualReviewLabelGuide.directCustomerProof ? 'true' : 'false'}`
- );
- }
- if (index.planExecutionStatus) {
- lines.push('', '### 长期计划执行状态面板', '', renderPlanExecutionStatus(index.planExecutionStatus));
- }
- if (index.proofGapRequest) {
- lines.push('', '### 真实证明缺口请求包', '', renderProofGapRequest(index.proofGapRequest));
- }
- if (index.proofGapOperatorPack) {
- lines.push('', '### 提号补证操作包', '', renderProofGapOperatorPack(index.proofGapOperatorPack));
- }
- if (index.realProofIntakeBundle) {
- lines.push('', '### 真实验收材料收集总包', '', renderRealProofIntakeBundle(index.realProofIntakeBundle));
- }
- if (index.realProofClosureWorkOrder) {
- lines.push('', '### 真实证明闭环工单', '', renderRealProofClosureWorkOrder(index.realProofClosureWorkOrder));
- }
- if (index.localSeedToIntakeWorklist) {
- lines.push('', '### 本地种子转 intake 补表 worklist', '', renderLocalSeedToIntakeWorklist(index.localSeedToIntakeWorklist));
- }
- if (index.realGapMaterialAudit) {
- lines.push('', '### three real gap material audit', '', renderRealGapMaterialAudit(index.realGapMaterialAudit));
- }
- if (index.longRunReadiness) {
- lines.push('', '### 长跑前置门禁', '', renderLongRunReadiness(index.longRunReadiness));
- }
- if (index.optimizationCompletion) {
- lines.push('', '### 优化完成度审计', '', renderOptimizationCompletion(index.optimizationCompletion));
- }
- const repairRows = renderLatestFormRepairActions(index.repairActions);
- if (repairRows) lines.push('', '### 修复清单入口', '', repairRows);
- return lines.join('\n');
- }
- function renderBusinessProofProgress(progress) {
- const counts = progress.counts || {};
- const lines = [
- `- 摘要:${progress.summary || 'missing'}`,
- `- 报告:${progress.report || 'missing'}`,
- `- complete: ${progress.complete ? 'true' : 'false'}`,
- `- pass: ${counts.pass || 0}`,
- `- pending: ${counts.pending || 0}`,
- `- fail: ${counts.fail || 0}`,
- `- blocked_by_external_data: ${counts.blocked_by_external_data || 0}`,
- `- operatorPackOwnerArtifactCount: ${progress.operatorPackOwnerArtifactCount || 0}`,
- `- businessExecutionOperatorPackOwnerArtifactRowCount: ${progress.businessExecutionOperatorPackOwnerArtifactRowCount || 0}`,
- '- 边界:该进度表只同步 15 步补证状态和负责人派工文件;complete=false 或 proof-gap 未关闭时,不得宣称客户效果、命中率提升或人工补号量下降。'
- ];
- if (Array.isArray(progress.operatorPackOwnerArtifacts) && progress.operatorPackOwnerArtifacts.length) {
- lines.push(
- '',
- '| 负责人 | 动作数 | Markdown | CSV | 缺口 |',
- '| --- | ---: | --- | --- | --- |',
- ...progress.operatorPackOwnerArtifacts.map(item => tableRow([
- item.owner,
- item.actionCount,
- item.markdown || 'missing',
- item.csv || 'missing',
- (item.gapIds || []).join(';') || 'missing'
- ]))
- );
- }
- return lines.join('\n');
- }
- function renderPlanExecutionStatus(status) {
- const lines = [
- `- report: ${status.markdown || 'missing'}`,
- `- csv: ${status.csv || 'missing'}`,
- `- summary: ${status.summary || 'missing'}`,
- `- passed: ${status.passed ? 'true' : 'false'}`,
- `- complete: ${status.complete ? 'true' : 'false'}`,
- `- rowCount: ${status.rowCount || 0}`,
- `- proofOpenCount: ${status.proofOpenCount || 0}`,
- `- operatorPackOwnerArtifactCount: ${status.operatorPackOwnerArtifactCount || 0}`,
- `- businessExecutionOperatorPackOwnerArtifactRowCount: ${status.businessExecutionOperatorPackOwnerArtifactRowCount || 0}`,
- `- directCustomerProof: ${status.directCustomerProof ? 'true' : 'false'}`,
- '- 边界:该面板只同步计划执行进度;proofOpenCount 不为 0 时,不得宣称客户效果、命中率提升或人工补号量下降。'
- ];
- if (Array.isArray(status.operatorPackOwnerArtifacts) && status.operatorPackOwnerArtifacts.length) {
- lines.push(
- '',
- '| 负责人 | 动作数 | Markdown | CSV | 缺口 |',
- '| --- | ---: | --- | --- | --- |',
- ...status.operatorPackOwnerArtifacts.map(item => tableRow([
- item.owner,
- item.actionCount,
- item.markdown || 'missing',
- item.csv || 'missing',
- (item.gapIds || []).join(';') || 'missing'
- ]))
- );
- }
- return lines.join('\n');
- }
- function renderProofGapRequest(request) {
- return [
- `- report: ${request.markdown || 'missing'}`,
- `- csv: ${request.csv || 'missing'}`,
- `- summary: ${request.summary || 'missing'}`,
- `- complete: ${request.complete ? 'true' : 'false'}`,
- `- unresolvedCount: ${request.unresolvedCount || 0}`,
- `- rowCount: ${request.rowCount || 0}`,
- `- proofGapClosureOpenCount: ${request.proofGapClosureOpenCount || 0}`,
- `- directCustomerProof: ${request.directCustomerProof ? 'true' : 'false'}`,
- '- 边界:该请求包只列出仍需补齐的真实证明材料;不能作为客户效果、命中率提升或人工补号量下降证明。'
- ].join('\n');
- }
- function renderProofGapOperatorPack(pack) {
- const lines = [
- `- report: ${pack.markdown || 'missing'}`,
- `- csv: ${pack.csv || 'missing'}`,
- `- summary: ${pack.summary || 'missing'}`,
- `- passed: ${pack.passed ? 'true' : 'false'}`,
- `- complete: ${pack.complete ? 'true' : 'false'}`,
- `- openCount: ${pack.openCount || 0}`,
- `- rowCount: ${pack.rowCount || 0}`,
- `- gapIds: ${(pack.gapIds || []).join(';') || 'missing'}`,
- `- fillFileCount: ${pack.fillFileCount || 0}`,
- `- recheckCommandCount: ${pack.recheckCommandCount || 0}`,
- `- ownerGroupCount: ${pack.ownerGroupCount || 0}`,
- `- ownerArtifactCount: ${pack.ownerArtifactCount || 0}`,
- `- evidenceRowCount: ${pack.evidenceRowCount || 0}`,
- `- nextActionCount: ${pack.nextActionCount || 0}`,
- `- missingProofRequirementCount: ${pack.missingProofRequirementCount || 0}`,
- `- directCustomerProof: ${pack.directCustomerProof ? 'true' : 'false'}`,
- '- 边界:该操作包只用于补证派工;proofOpenCount 不为 0 时,不得宣称客户效果、命中率提升或人工补号量下降。'
- ];
- if (Array.isArray(pack.ownerArtifacts) && pack.ownerArtifacts.length) {
- lines.push(
- '',
- '| 负责人 | 动作数 | Markdown | CSV | 缺口 |',
- '| --- | ---: | --- | --- | --- |',
- ...pack.ownerArtifacts.map(item => tableRow([
- item.owner,
- item.actionCount,
- item.markdown || 'missing',
- item.csv || 'missing',
- (item.gapIds || []).join(';') || 'missing'
- ]))
- );
- }
- return lines.join('\n');
- }
- function renderRealProofIntakeBundle(bundle) {
- const lines = [
- `- report: ${bundle.markdown || 'missing'}`,
- `- csv: ${bundle.csv || 'missing'}`,
- `- summary: ${bundle.summary || 'missing'}`,
- `- passed: ${bundle.passed ? 'true' : 'false'}`,
- `- complete: ${bundle.complete ? 'true' : 'false'}`,
- `- proofOpenCount: ${bundle.proofOpenCount || 0}`,
- `- fillRowCount: ${bundle.fillRowCount || 0}`,
- `- proofGapRowCount: ${bundle.proofGapRowCount || 0}`,
- `- recheckCommandCount: ${bundle.recheckCommandCount || 0}`,
- `- operatorPackEvidenceRowCount: ${bundle.operatorPackEvidenceRowCount || 0}`,
- `- operatorPackNextActionCount: ${bundle.operatorPackNextActionCount || 0}`,
- `- operatorPackMissingProofRequirementCount: ${bundle.operatorPackMissingProofRequirementCount || 0}`,
- `- operatorPackOwnerArtifactCount: ${bundle.operatorPackOwnerArtifactCount || 0}`,
- `- directCustomerProof: ${bundle.directCustomerProof ? 'true' : 'false'}`,
- '- 边界:该总包只集中真实材料模板、字段缺口、修复清单和复验命令;proofOpenCount 不为 0 时,不得宣称客户效果。'
- ];
- if (Array.isArray(bundle.operatorPackOwnerArtifacts) && bundle.operatorPackOwnerArtifacts.length) {
- lines.push(
- '',
- '| 负责人 | 动作数 | Markdown | CSV | 缺口 |',
- '| --- | ---: | --- | --- | --- |',
- ...bundle.operatorPackOwnerArtifacts.map(item => tableRow([
- item.owner,
- item.actionCount,
- item.markdown || 'missing',
- item.csv || 'missing',
- (item.gapIds || []).join(';') || 'missing'
- ]))
- );
- }
- return lines.join('\n');
- }
- function renderRealProofClosureWorkOrder(workOrder) {
- const lines = [
- `- report: ${workOrder.markdown || 'missing'}`,
- `- csv: ${workOrder.csv || 'missing'}`,
- `- summary: ${workOrder.summary || 'missing'}`,
- `- passed: ${workOrder.passed ? 'true' : 'false'}`,
- `- complete: ${workOrder.complete ? 'true' : 'false'}`,
- `- workOrderCount: ${workOrder.workOrderCount || 0}`,
- `- ownerGroupCount: ${workOrder.ownerGroupCount || 0}`,
- `- proofGapOpenCount: ${workOrder.proofGapOpenCount || 0}`,
- `- intakeFailureCount: ${workOrder.intakeFailureCount || 0}`,
- `- videoFailureCount: ${workOrder.videoFailureCount || 0}`,
- `- realCandidateRows: ${workOrder.realCandidateRows || 0}`,
- `- canCloseProofGap: ${workOrder.canCloseProofGap ? 'true' : 'false'}`,
- `- directCustomerProof: ${workOrder.directCustomerProof ? 'true' : 'false'}`,
- '- 边界:该工单只把缺口拆到目标模板、字段、行范围、种子线索和复验命令;不写入正式模板,不证明客户效果。'
- ];
- if (Array.isArray(workOrder.ownerArtifacts) && workOrder.ownerArtifacts.length) {
- lines.push(
- '',
- '| 负责人 | 工单数 | Markdown | CSV | 缺口 | 目标文件 |',
- '| --- | ---: | --- | --- | --- | --- |',
- ...workOrder.ownerArtifacts.map(item => tableRow([
- item.owner,
- item.workOrderCount,
- item.markdown || 'missing',
- item.csv || 'missing',
- (item.gapIds || []).join(';') || 'missing',
- (item.targetFiles || []).join(';') || 'missing'
- ]))
- );
- }
- return lines.join('\n');
- }
- function renderBusinessFillGuide(guide) {
- return [
- '### 商务填表执行视图',
- '',
- `- rowCount:${Number(guide.rowCount || guide.rows.length || 0)}`,
- `- directCustomerProof:${guide.directCustomerProof ? 'true' : 'false'}`,
- `- proofLevel:${guide.proofLevel || 'unknown'}`,
- '',
- '| 顺序 | 负责人 | 表单区域 | 填表文件 | 优先项 | 问题数 | 填表动作 | 补齐后复验 | 验收 | 边界 |',
- '| ---: | --- | --- | --- | --- | ---: | --- | --- | --- | --- |',
- ...guide.rows.map(item => tableRow([
- item.order,
- item.owner,
- item.section,
- item.file || '缺失',
- (item.firstItemIds || []).join('、') || '无',
- item.issueCount,
- item.fillAction,
- item.recheckCommand || '待补齐后运行 round:refresh',
- item.acceptance,
- item.boundary
- ])),
- '',
- `- ${guide.guardrail || '本视图只帮助商务按表补齐真实材料,不代表客户效果已达标。'}`
- ].join('\n');
- }
- function renderIntakeOwnerGroups(ownerGroups) {
- return [
- '| 负责人 | 范围 | 字段项 | 缺必填 | 占位 | 文件 | 下一步 | 通过标准 | 边界 |',
- '| --- | --- | ---: | ---: | ---: | --- | --- | --- | --- |',
- ...ownerGroups.map(item => tableRow([
- item.owner,
- item.section,
- item.itemCount,
- item.missingRequiredCount,
- item.placeholderCount,
- (item.files || []).join(';') || '缺失',
- item.nextAction,
- item.acceptance,
- item.boundary
- ]))
- ].join('\n');
- }
- function renderRecheckCommands(recheckCommands) {
- return [
- '| 阶段 | 负责人 | 命令 | 通过标准 | 边界 |',
- '| --- | --- | --- | --- | --- |',
- ...recheckCommands.map(item => tableRow([
- item.stage,
- item.owner,
- item.command,
- item.acceptance,
- item.boundary
- ]))
- ].join('\n');
- }
- function renderLatestFormRepairActions(repairActions) {
- if (!repairActions) return '';
- const rows = [repairActions.dataIntake, repairActions.videoResource, repairActions.homepageEvidence].filter(Boolean);
- if (!rows.length) return '';
- return [
- '| 类型 | CSV | 当前问题数 | 修复动作数 | 状态 |',
- '| --- | --- | ---: | ---: | --- |',
- ...rows.map(item => tableRow([
- item.title || '修复清单',
- item.csv || '缺失',
- Number(item.failureCount || 0),
- Number(item.repairActionCount || 0),
- item.ready || item.readyForVideoAbPreflight ? '已就绪' : '待补齐'
- ]))
- ].join('\n');
- }
- function buildRepairActionsSummary(root) {
- const intakeReadinessDir = latestOutputDir(/^intake-readiness-/) || 'outputs/intake-readiness-latest';
- const videoResourceReadinessDir = latestOutputDir(/^video-resource-readiness-/) || 'outputs/video-resource-readiness-latest';
- const homepageEvidenceReadinessDir = latestOutputDir(/^homepage-evidence-readiness-/) || 'outputs/homepage-evidence-readiness-latest';
- const intakeReadinessSummary = readJsonSummary(root, intakeReadinessDir, 'intake-readiness-summary.json');
- const videoResourceReadinessSummary = readJsonSummary(root, videoResourceReadinessDir, 'video-resource-readiness-summary.json');
- const homepageEvidenceReadinessSummary = readJsonSummary(root, homepageEvidenceReadinessDir, 'homepage-evidence-readiness-summary.json');
- return {
- dataIntake: {
- title: '历史数据/商务复核修复清单',
- csv: relIfExists(root, path.join(root, intakeReadinessDir, 'intake-readiness-repair-actions.csv')),
- report: relIfExists(root, path.join(root, intakeReadinessDir, 'intake-readiness-report.md')),
- summary: relIfExists(root, path.join(root, intakeReadinessDir, 'intake-readiness-summary.json')),
- failureCount: Number(intakeReadinessSummary?.failureCount || 0),
- repairActionCount: Number(intakeReadinessSummary?.repairActions?.length || 0),
- ready: Boolean(intakeReadinessSummary?.acceptance?.overallReady)
- },
- videoResource: {
- title: '视频资源修复清单',
- csv: relIfExists(root, path.join(root, videoResourceReadinessDir, 'video-resource-repair-actions.csv')),
- report: relIfExists(root, path.join(root, videoResourceReadinessDir, 'video-resource-readiness-report.md')),
- summary: relIfExists(root, path.join(root, videoResourceReadinessDir, 'video-resource-readiness-summary.json')),
- failureCount: Number(videoResourceReadinessSummary?.failureCount || 0),
- repairActionCount: Number(videoResourceReadinessSummary?.repairActions?.length || 0),
- readyForVideoAbPreflight: Boolean(videoResourceReadinessSummary?.acceptance?.readyForVideoAbPreflight)
- },
- homepageEvidence: {
- title: '主页近期内容证据修复清单',
- csv: relIfExists(root, path.join(root, homepageEvidenceReadinessDir, 'homepage-evidence-repair-actions.csv')),
- report: relIfExists(root, path.join(root, homepageEvidenceReadinessDir, 'homepage-evidence-readiness-report.md')),
- summary: relIfExists(root, path.join(root, homepageEvidenceReadinessDir, 'homepage-evidence-readiness-summary.json')),
- failureCount: Number(homepageEvidenceReadinessSummary?.failureCount || 0),
- repairActionCount: Number(homepageEvidenceReadinessSummary?.repairActions?.length || 0),
- ready: Boolean(homepageEvidenceReadinessSummary?.ready),
- directCustomerProof: Boolean(homepageEvidenceReadinessSummary?.directCustomerProof)
- }
- };
- }
- function buildLatestFormIndexChecklistSummary({
- root,
- latestFormIndexSummary,
- latestIntakeFieldChecklist,
- intakeFieldChecklistSummary
- }) {
- const indexed = latestFormIndexSummary?.intakeFieldChecklist || null;
- const ownerGroups = Array.isArray(indexed?.ownerGroups) && indexed.ownerGroups.length
- ? indexed.ownerGroups
- : normalizeIntakeOwnerGroups(root, intakeFieldChecklistSummary?.ownerGroups || []);
- const recheckCommands = Array.isArray(indexed?.recheckCommands) && indexed.recheckCommands.length
- ? indexed.recheckCommands
- : normalizeRecheckCommands(intakeFieldChecklistSummary?.recheckCommands || []);
- if (!indexed && !latestIntakeFieldChecklist && !ownerGroups.length && !recheckCommands.length) return null;
- return {
- ...(indexed || {}),
- markdown: indexed?.markdown || (latestIntakeFieldChecklist ? artifactRef(root, artifactPath(root, latestIntakeFieldChecklist, 'intake-field-checklist.md')) : ''),
- csv: indexed?.csv || (latestIntakeFieldChecklist ? artifactRef(root, artifactPath(root, latestIntakeFieldChecklist, 'intake-field-checklist.csv')) : ''),
- ownerGroups,
- recheckCommands
- };
- }
- function normalizeBusinessFillGuide(guide) {
- if (!guide || !Array.isArray(guide.rows) || guide.rows.length === 0) return null;
- const rows = guide.rows.map((item, index) => ({
- order: Number(item.order || index + 1),
- owner: item.owner || '',
- section: item.section || '',
- file: item.file || '',
- firstItemIds: Array.isArray(item.firstItemIds) ? item.firstItemIds : [],
- issueCount: Number(item.issueCount || 0),
- missingRequiredCount: Number(item.missingRequiredCount || 0),
- placeholderCount: Number(item.placeholderCount || 0),
- fillAction: item.fillAction || '',
- recheckCommand: item.recheckCommand || '',
- acceptance: item.acceptance || '',
- boundary: item.boundary || ''
- }));
- return {
- title: guide.title || '商务填表执行视图',
- directCustomerProof: Boolean(guide.directCustomerProof),
- proofLevel: guide.proofLevel || 'smoke_or_local',
- rowCount: Number(guide.rowCount || rows.length),
- rows,
- guardrail: guide.guardrail || '本视图只帮助商务按表补齐真实材料,不代表客户效果已达标。'
- };
- }
- function normalizeManualReviewLabelGuide(guide) {
- if (!guide) return null;
- return {
- markdown: guide.markdown || '',
- csv: guide.csv || '',
- summary: guide.summary || '',
- passed: Boolean(guide.passed),
- directCustomerProof: Boolean(guide.directCustomerProof),
- proofLevel: guide.proofLevel || 'smoke_or_local',
- labelCount: Number(guide.labelCount || 0),
- positiveLabelCount: Number(guide.positiveLabelCount || 0),
- negativeLabelCount: Number(guide.negativeLabelCount || 0),
- attributionTypeCount: Number(guide.attributionTypeCount || 0),
- negativeLabelsRequireAttribution: Boolean(guide.negativeLabelsRequireAttribution)
- };
- }
- function normalizePlanExecutionStatus(status) {
- if (!status) return null;
- return {
- markdown: status.markdown || status.report || status.files?.report || '',
- csv: status.csv || status.files?.csv || '',
- summary: status.summary || status.files?.summary || '',
- passed: Boolean(status.passed),
- complete: Boolean(status.complete),
- directCustomerProof: false,
- rowCount: Number(status.rowCount || 0),
- proofOpenCount: Number(status.proofOpenCount || 0),
- operatorPackOwnerArtifactCount: Number(status.operatorPackOwnerArtifactCount || (Array.isArray(status.operatorPackOwnerArtifacts) ? status.operatorPackOwnerArtifacts.length : 0)),
- operatorPackOwnerArtifacts: normalizeProofGapOperatorOwnerArtifacts(status.operatorPackOwnerArtifacts || []),
- businessExecutionOperatorPackOwnerArtifactCount: Number(status.businessExecutionOperatorPackOwnerArtifactCount || 0),
- businessExecutionOperatorPackOwnerArtifactRowCount: Number(status.businessExecutionOperatorPackOwnerArtifactRowCount || 0),
- roundPassed: Boolean(status.roundPassed),
- guardrailCount: Array.isArray(status.guardrails) ? status.guardrails.length : Number(status.guardrailCount || 0)
- };
- }
- function normalizeProofGapRequest(request) {
- if (!request) return null;
- return {
- markdown: request.markdown || request.report || request.files?.report || '',
- csv: request.csv || request.files?.csv || '',
- summary: request.summary || request.files?.summary || '',
- complete: Boolean(request.complete),
- directCustomerProof: false,
- proofLevel: request.proofLevel || 'smoke_or_local',
- unresolvedCount: Number(request.unresolvedCount || 0),
- rowCount: Array.isArray(request.rows) ? request.rows.length : Number(request.rowCount || 0),
- proofGapClosureOpenCount: Number(request.proofGapClosureOpenCount || request.observed?.proofGapClosureOpenCount || 0)
- };
- }
- function normalizeProofGapOperatorPack(pack) {
- if (!pack) return null;
- return {
- markdown: pack.markdown || pack.report || pack.files?.report || '',
- csv: pack.csv || pack.files?.csv || '',
- summary: pack.summary || pack.files?.summary || '',
- passed: Boolean(pack.passed),
- complete: Boolean(pack.complete),
- directCustomerProof: false,
- proofLevel: pack.proofLevel || 'not_business_proof',
- rowCount: Number(pack.rowCount || 0),
- openCount: Number(pack.openCount || 0),
- gapIds: Array.isArray(pack.gapIds)
- ? pack.gapIds
- : (Array.isArray(pack.rows) ? pack.rows.map(row => row.gapId).filter(Boolean) : []),
- fillFileCount: Number(pack.fillFileCount || 0),
- recheckCommandCount: Number(pack.recheckCommandCount || 0),
- ownerGroupCount: Number(pack.ownerGroupCount || (Array.isArray(pack.ownerGroups) ? pack.ownerGroups.length : 0)),
- ownerArtifactCount: Number(pack.ownerArtifactCount || (Array.isArray(pack.ownerArtifacts) ? pack.ownerArtifacts.length : 0)),
- ownerArtifacts: normalizeProofGapOperatorOwnerArtifacts(pack.ownerArtifacts || []),
- evidenceRowCount: Number(pack.evidenceRowCount || 0),
- nextActionCount: Number(pack.nextActionCount || 0),
- missingProofRequirementCount: Number(pack.missingProofRequirementCount || 0)
- };
- }
- function normalizeProofGapOperatorOwnerArtifacts(ownerArtifacts) {
- if (!Array.isArray(ownerArtifacts)) return [];
- return ownerArtifacts.map(item => ({
- owner: item.owner || '',
- actionCount: Number(item.actionCount || 0),
- topPriority: Number(item.topPriority || 0),
- markdown: item.markdown || '',
- csv: item.csv || '',
- gapIds: Array.isArray(item.gapIds) ? item.gapIds : [],
- evidenceRowCount: Number(item.evidenceRowCount || 0),
- nextActionCount: Number(item.nextActionCount || 0)
- }));
- }
- function normalizeWorkOrderOwnerArtifacts(ownerArtifacts) {
- if (!Array.isArray(ownerArtifacts)) return [];
- return ownerArtifacts.map(item => ({
- owner: item.owner || '',
- workOrderCount: Number(item.workOrderCount || item.actionCount || 0),
- topPriority: Number(item.topPriority || 0),
- markdown: item.markdown || '',
- csv: item.csv || '',
- targetFiles: Array.isArray(item.targetFiles) ? item.targetFiles : [],
- gapIds: Array.isArray(item.gapIds) ? item.gapIds : []
- }));
- }
- function normalizeRealProofIntakeBundle(bundle) {
- if (!bundle) return null;
- return {
- markdown: bundle.markdown || bundle.report || bundle.files?.report || '',
- csv: bundle.csv || bundle.files?.csv || '',
- summary: bundle.summary || bundle.files?.summary || '',
- passed: Boolean(bundle.passed),
- complete: Boolean(bundle.complete),
- directCustomerProof: false,
- proofLevel: bundle.proofLevel || 'not_business_proof',
- proofOpenCount: Number(bundle.proofOpenCount || 0),
- fillRowCount: Number(bundle.fillRowCount || 0),
- proofGapRowCount: Number(bundle.proofGapRowCount || 0),
- repairRowCount: Number(bundle.repairRowCount || 0),
- recheckCommandCount: Number(bundle.recheckCommandCount || 0),
- exportRowCount: Number(bundle.exportRowCount || 0),
- operatorPackEvidenceRowCount: Number(bundle.operatorPackEvidenceRowCount || bundle.sourceState?.operatorPackEvidenceRowCount || 0),
- operatorPackNextActionCount: Number(bundle.operatorPackNextActionCount || bundle.sourceState?.operatorPackNextActionCount || 0),
- operatorPackMissingProofRequirementCount: Number(bundle.operatorPackMissingProofRequirementCount || bundle.sourceState?.operatorPackMissingProofRequirementCount || 0),
- operatorPackOwnerArtifactCount: Number(bundle.operatorPackOwnerArtifactCount || bundle.sourceState?.operatorPackOwnerArtifactCount || (Array.isArray(bundle.operatorPackOwnerArtifacts) ? bundle.operatorPackOwnerArtifacts.length : 0)),
- operatorPackOwnerArtifacts: normalizeProofGapOperatorOwnerArtifacts(bundle.operatorPackOwnerArtifacts || [])
- };
- }
- function normalizeRealProofClosureWorkOrder(workOrder) {
- if (!workOrder) return null;
- return {
- markdown: workOrder.markdown || workOrder.report || workOrder.files?.report || '',
- csv: workOrder.csv || workOrder.files?.csv || '',
- summary: workOrder.summary || workOrder.files?.summary || '',
- passed: Boolean(workOrder.passed),
- complete: Boolean(workOrder.complete),
- directCustomerProof: false,
- canCloseProofGap: Boolean(workOrder.canCloseProofGap),
- proofLevel: workOrder.proofLevel || 'not_business_proof',
- materialType: workOrder.materialType || 'real_proof_closure_work_order',
- workOrderCount: Number(workOrder.workOrderCount || 0),
- ownerGroupCount: Number(workOrder.ownerGroupCount || 0),
- seedSuggestionCount: Number(workOrder.seedSuggestionCount || 0),
- proofGapOpenCount: Number(workOrder.proofGapOpenCount || workOrder.sourceState?.proofGapOpenCount || 0),
- intakeFailureCount: Number(workOrder.intakeFailureCount || workOrder.sourceState?.intakeFailureCount || 0),
- videoFailureCount: Number(workOrder.videoFailureCount || workOrder.sourceState?.videoFailureCount || 0),
- realCandidateRows: Number(workOrder.realCandidateRows || workOrder.sourceState?.realCandidateRows || 0),
- ownerArtifacts: normalizeWorkOrderOwnerArtifacts(workOrder.ownerArtifacts || [])
- };
- }
- function normalizeLocalSeedToIntakeWorklist(worklist) {
- if (!worklist) return null;
- const counts = worklist.counts || {};
- const countOf = (value, fallback) => {
- if (Array.isArray(value)) return value.length;
- if (Number.isFinite(Number(value))) return Number(value);
- if (Array.isArray(fallback)) return fallback.length;
- return Number(fallback || 0);
- };
- return {
- markdown: worklist.markdown || worklist.report || '',
- csv: worklist.csv || '',
- summary: worklist.summary || '',
- historyDraft: worklist.historyDraft || '',
- videoWorklist: worklist.videoWorklist || '',
- candidateWorklist: worklist.candidateWorklist || '',
- proofLevel: worklist.proofLevel || 'not_business_proof',
- materialType: worklist.materialType || 'seed_to_intake_worklist',
- complete: Boolean(worklist.complete),
- directCustomerProof: false,
- canCloseProofGap: Boolean(worklist.canCloseProofGap),
- historyDraftRows: countOf(worklist.historyDraftRows, counts.historyDraftRows),
- referenceSeedRows: countOf(worklist.referenceSeedRows, counts.referenceSeedRows),
- candidateSeedRows: countOf(worklist.candidateSeedRows, counts.candidateSeedRows),
- videoWorklistRows: countOf(worklist.videoWorklistRows, counts.videoWorklistRows),
- videoCandidateNeedsResourceRows: countOf(worklist.videoCandidateNeedsResourceRows, counts.videoCandidateNeedsResourceRows),
- missingProofRequirementCount: Number(worklist.missingProofRequirementCount ?? (Array.isArray(worklist.missingProofRequirements) ? worklist.missingProofRequirements.length : 0)),
- nextActionCount: Number(worklist.nextActionCount ?? (Array.isArray(worklist.nextActions) ? worklist.nextActions.length : 0)),
- targetFiles: Array.isArray(worklist.targetFiles) ? worklist.targetFiles : []
- };
- }
- function normalizeLongRunReadiness(readiness) {
- if (!readiness) return null;
- return {
- report: readiness.report || readiness.markdown || readiness.files?.report || '',
- summary: readiness.summary || readiness.files?.summary || '',
- mode: readiness.mode || '',
- ready: Boolean(readiness.ready),
- directCustomerProof: false,
- proofLevel: readiness.proofLevel || (readiness.ready ? 'smoke_or_local' : 'not_business_proof'),
- passCount: Number(readiness.passCount ?? readiness.counts?.pass ?? 0),
- failCount: Number(readiness.failCount ?? readiness.counts?.fail ?? 0),
- warnCount: Number(readiness.warnCount ?? readiness.counts?.warn ?? 0),
- nextCommandCount: Number(readiness.nextCommandCount ?? (Array.isArray(readiness.nextCommands) ? readiness.nextCommands.length : 0)),
- boundaryCount: Number(readiness.boundaryCount ?? (Array.isArray(readiness.boundaries) ? readiness.boundaries.length : 0))
- };
- }
- function normalizeRealGapMaterialAudit(audit) {
- if (!audit) return null;
- return {
- markdown: audit.markdown || audit.report || '',
- csv: audit.csv || '',
- summary: audit.summary || '',
- proofLevel: audit.proofLevel || 'not_business_proof',
- materialType: audit.materialType || 'three_real_gap_material_audit',
- complete: Boolean(audit.complete),
- directCustomerProof: false,
- canCloseProofGap: Boolean(audit.canCloseProofGap),
- gapCount: Number(audit.gapCount || 0),
- materialFoundCount: Number(audit.materialFoundCount || 0),
- openGapCount: Number(audit.openGapCount || 0),
- sourceState: audit.sourceState || {},
- gapIds: Array.isArray(audit.gapIds)
- ? audit.gapIds
- : (Array.isArray(audit.gaps) ? audit.gaps.map(item => item.id).filter(Boolean) : [])
- };
- }
- function normalizeOptimizationCompletion(completion) {
- if (!completion) return null;
- const blockingReasonCount = Number(completion.blockingReasonCount ?? (Array.isArray(completion.blockingReasons) ? completion.blockingReasons.length : 0));
- const blockingReasonsWithMissingProofRequirements = Number(completion.blockingReasonsWithMissingProofRequirements ?? countRowsWithMissingProofRequirements(completion.blockingReasons));
- const missingProofRequirementCount = Number(completion.missingProofRequirementCount ?? uniqueMissingProofRequirementCount(completion.blockingReasons));
- return {
- report: completion.report || completion.markdown || completion.files?.report || '',
- summary: completion.summary || completion.files?.summary || '',
- complete: Boolean(completion.complete),
- readyForClaim: Boolean(completion.readyForClaim),
- proofGapOpenCount: Number(completion.proofGapOpenCount || 0),
- blockingReasonCount,
- blockingReasonsWithMissingProofRequirements,
- missingProofRequirementCount,
- videoAbPreflightReadyForVideoAb: Boolean(completion.videoAbPreflightReadyForVideoAb),
- videoAbPreflightFailureCount: Number.isFinite(Number(completion.videoAbPreflightFailureCount)) ? Number(completion.videoAbPreflightFailureCount) : null,
- directCustomerProof: false,
- proofLevel: completion.readyForClaim ? 'real_evidence' : 'not_business_proof',
- canClaim: {
- tihaoRateImproved: Boolean(completion.canClaim?.tihaoRateImproved),
- customerEffectAchieved: Boolean(completion.canClaim?.customerEffectAchieved),
- manualSupplementReduced: Boolean(completion.canClaim?.manualSupplementReduced)
- },
- nextRequiredCommandCount: Array.isArray(completion.nextRequiredCommands) ? completion.nextRequiredCommands.length : 0
- };
- }
- function normalizeBusinessExecutionLongRunReadiness(indexSummary, readinessSummary) {
- if (!indexSummary) return null;
- const row = (Array.isArray(indexSummary.rows) ? indexSummary.rows : [])
- .find(item => String(item.title || '').includes('长跑前置门禁报告'));
- const summary = indexSummary.sourceFiles?.longRunReadiness || readinessSummary?.summary || readinessSummary?.files?.summary || '';
- if (!row && !summary) return null;
- const ready = Boolean(readinessSummary?.ready);
- const failCount = Number(readinessSummary?.counts?.fail ?? readinessSummary?.failCount ?? row?.actionCount ?? 0);
- return {
- report: row?.mainFile || readinessSummary?.report || readinessSummary?.files?.report || '',
- summary,
- status: row?.status || (ready ? 'ready' : 'blocked'),
- actionCount: Number(row?.actionCount ?? failCount),
- ready,
- failCount,
- expectedArtifact: row?.expectedArtifact || summary,
- acceptance: row?.acceptance || '',
- boundary: row?.boundary || '',
- directCustomerProof: false,
- proofLevel: ready ? 'smoke_or_local' : 'not_business_proof'
- };
- }
- function normalizeBusinessExecutionOptimizationCompletion(indexSummary, completionSummary) {
- if (!indexSummary) return null;
- const row = (Array.isArray(indexSummary.rows) ? indexSummary.rows : [])
- .find(item => String(item.title || '').includes('优化完成度审计报告'));
- const summary = indexSummary.sourceFiles?.optimizationCompletion || completionSummary?.summary || completionSummary?.files?.summary || '';
- if (!row && !summary) return null;
- const readyForClaim = Boolean(completionSummary?.readyForClaim);
- const blockingReasonCount = Number(completionSummary?.blockingReasonCount ?? (Array.isArray(completionSummary?.blockingReasons) ? completionSummary.blockingReasons.length : row?.actionCount ?? 0));
- const blockingReasonsWithMissingProofRequirements = Number(completionSummary?.blockingReasonsWithMissingProofRequirements ?? countRowsWithMissingProofRequirements(completionSummary?.blockingReasons));
- const missingProofRequirementCount = Number(completionSummary?.missingProofRequirementCount ?? uniqueMissingProofRequirementCount(completionSummary?.blockingReasons));
- return {
- report: row?.mainFile || completionSummary?.report || completionSummary?.files?.report || '',
- summary,
- status: row?.status || (readyForClaim ? 'ready_for_claim' : 'blocked'),
- actionCount: Number(row?.actionCount ?? blockingReasonCount),
- complete: Boolean(completionSummary?.complete),
- readyForClaim,
- proofGapOpenCount: Number(completionSummary?.proofGapOpenCount || 0),
- blockingReasonCount,
- blockingReasonsWithMissingProofRequirements,
- missingProofRequirementCount,
- videoAbPreflightReadyForVideoAb: Boolean(completionSummary?.videoAbPreflightReadyForVideoAb),
- videoAbPreflightFailureCount: Number.isFinite(Number(completionSummary?.videoAbPreflightFailureCount)) ? Number(completionSummary.videoAbPreflightFailureCount) : null,
- expectedArtifact: row?.expectedArtifact || summary,
- acceptance: row?.acceptance || '',
- boundary: row?.boundary || '',
- directCustomerProof: false,
- proofLevel: readyForClaim ? 'real_evidence' : 'not_business_proof'
- };
- }
- function normalizeIntakeOwnerGroups(root, ownerGroups) {
- if (!Array.isArray(ownerGroups)) return [];
- return ownerGroups.map(item => ({
- owner: item.owner || '',
- section: item.section || '',
- itemCount: Number(item.itemCount || 0),
- missingRequiredCount: Number(item.missingRequiredCount || 0),
- placeholderCount: Number(item.placeholderCount || 0),
- files: Array.isArray(item.files) ? item.files.map(file => artifactRef(root, file)) : [],
- firstItemIds: Array.isArray(item.firstItemIds) ? item.firstItemIds : [],
- nextAction: item.nextAction || '',
- acceptance: item.acceptance || '',
- boundary: item.boundary || ''
- }));
- }
- function normalizeRecheckCommands(recheckCommands) {
- if (!Array.isArray(recheckCommands)) return [];
- return recheckCommands.map(item => ({
- stage: item.stage || '',
- owner: item.owner || '',
- command: item.command || '',
- acceptance: item.acceptance || '',
- boundary: item.boundary || ''
- }));
- }
- function normalizeBusinessProofNextActionSourceState(sourceState) {
- if (!sourceState || typeof sourceState !== 'object') return {};
- return {
- progressComplete: Boolean(sourceState.progressComplete),
- progressCounts: sourceState.progressCounts || {},
- proofGapOpenCount: Number(sourceState.proofGapOpenCount || 0),
- intakeFailureCount: Number(sourceState.intakeFailureCount || 0),
- videoFailureCount: Number(sourceState.videoFailureCount || 0),
- homepageFailureCount: Number(sourceState.homepageFailureCount || 0),
- pipelineReadyForClaim: Boolean(sourceState.pipelineReadyForClaim),
- pipelineFailCount: Number(sourceState.pipelineFailCount || 0),
- pipelineNextActionCount: Number(sourceState.pipelineNextActionCount || 0),
- pipelineRawNextActionCount: Number(sourceState.pipelineRawNextActionCount || 0),
- pipelineSuppressedNextActionCount: Number(sourceState.pipelineSuppressedNextActionCount || 0),
- pipelineStale: Boolean(sourceState.pipelineStale),
- pipelineStaleReason: sourceState.pipelineStaleReason || '',
- pipelineStaleMissingProofRequirements: Array.isArray(sourceState.pipelineStaleMissingProofRequirements)
- ? sourceState.pipelineStaleMissingProofRequirements
- : []
- };
- }
- function buildPipelineStaleSummary(primarySourceState, fallbackSourceState) {
- const primaryHasState = primarySourceState && Object.keys(primarySourceState).length > 0;
- const fallbackHasState = fallbackSourceState && Object.keys(fallbackSourceState).length > 0;
- const sourceState = primaryHasState ? primarySourceState : (fallbackHasState ? fallbackSourceState : {});
- const missingProofRequirements = Array.isArray(sourceState.pipelineStaleMissingProofRequirements)
- ? sourceState.pipelineStaleMissingProofRequirements
- : [];
- return {
- pipelineStale: Boolean(sourceState.pipelineStale),
- pipelineReadyForClaim: Boolean(sourceState.pipelineReadyForClaim),
- pipelineNextActionCount: Number(sourceState.pipelineNextActionCount || 0),
- pipelineRawNextActionCount: Number(sourceState.pipelineRawNextActionCount || 0),
- pipelineSuppressedNextActionCount: Number(sourceState.pipelineSuppressedNextActionCount || 0),
- pipelineStaleReason: sourceState.pipelineStaleReason || '',
- pipelineStaleMissingProofRequirementCount: missingProofRequirements.length,
- pipelineStaleMissingProofRequirements: missingProofRequirements,
- boundary: 'stale optimization-pipeline nextActions are not current dispatch or completion evidence; rerun optimization:pipeline only after real materials are ready.'
- };
- }
- function normalizeBusinessProofNextTopActions(actions, limit = 5) {
- if (!Array.isArray(actions)) return [];
- return actions
- .slice()
- .sort((left, right) => actionSortValue(left) - actionSortValue(right))
- .slice(0, limit)
- .map(item => ({
- id: item.id || '',
- source: item.source || '',
- order: Number(item.order || 0),
- priority: Number(item.priority || 0),
- owner: item.owner || '',
- title: item.title || '',
- status: item.status || '',
- evidence: item.evidence || '',
- command: item.command || '',
- expectedArtifact: item.expectedArtifact || '',
- acceptance: item.acceptance || '',
- missingProofRequirementCount: Array.isArray(item.missingProofRequirements) ? item.missingProofRequirements.length : 0,
- missingProofRequirements: Array.isArray(item.missingProofRequirements) ? item.missingProofRequirements : []
- }));
- }
- function actionSortValue(item) {
- const priority = Number(item?.priority);
- const order = Number(item?.order);
- const primary = Number.isFinite(priority) && priority > 0 ? priority : 999999;
- const secondary = Number.isFinite(order) && order > 0 ? order / 100000 : 0;
- return primary + secondary;
- }
- function normalizeOwnerArtifacts(root, dir, summary) {
- if (!summary || !Array.isArray(summary.ownerArtifacts)) return [];
- return summary.ownerArtifacts.map(item => ({
- owner: item.owner,
- actionCount: item.actionCount,
- topPriority: item.topPriority,
- markdown: item.markdown ? artifactRef(root, artifactPath(root, dir, item.markdown)) : '',
- csv: item.csv ? artifactRef(root, artifactPath(root, dir, item.csv)) : '',
- repairArtifacts: normalizeRepairArtifacts(item.repairArtifacts || [])
- }));
- }
- function renderPipelineStaleSummary(summary) {
- if (!summary) return '- 尚未生成 pipeline stale 摘要。';
- return [
- `- pipelineStale: ${summary.pipelineStale ? 'true' : 'false'}`,
- `- pipelineReadyForClaim: ${summary.pipelineReadyForClaim ? 'true' : 'false'}`,
- `- pipelineNextActionCount: ${summary.pipelineNextActionCount || 0}`,
- `- pipelineRawNextActionCount: ${summary.pipelineRawNextActionCount || 0}`,
- `- pipelineSuppressedNextActionCount: ${summary.pipelineSuppressedNextActionCount || 0}`,
- `- pipelineStaleMissingProofRequirementCount: ${summary.pipelineStaleMissingProofRequirementCount || 0}`,
- summary.pipelineStaleReason ? `- pipelineStaleReason: ${summary.pipelineStaleReason}` : '',
- `- 边界:${summary.boundary || 'stale pipeline 动作不能作为当前派工或完成证据。'}`
- ].filter(Boolean).join('\n');
- }
- function renderBusinessProofNextActions(queue) {
- const sourceState = queue.sourceState || {};
- const lines = [
- `- 摘要:${queue.summary || 'missing'}`,
- `- 报告:${queue.report || 'missing'}`,
- `- CSV:${queue.csv || 'missing'}`,
- `- complete: ${queue.complete ? 'true' : 'false'}`,
- `- actionCount: ${queue.actionCount || 0}`,
- `- ownerGroupCount: ${queue.ownerGroupCount || 0}`,
- `- ownerArtifactCount: ${queue.ownerArtifactCount || 0}`,
- `- proofGapOpenCount: ${sourceState.proofGapOpenCount || 0}`,
- `- intakeFailureCount: ${sourceState.intakeFailureCount || 0}`,
- `- videoFailureCount: ${sourceState.videoFailureCount || 0}`,
- `- pipelineReadyForClaim: ${sourceState.pipelineReadyForClaim ? 'true' : 'false'}`,
- `- pipelineStale: ${sourceState.pipelineStale ? 'true' : 'false'}`,
- `- pipelineSuppressedNextActionCount: ${sourceState.pipelineSuppressedNextActionCount || 0}`,
- sourceState.pipelineStaleReason ? `- pipelineStaleReason: ${sourceState.pipelineStaleReason}` : '',
- '- 边界:该行动队列只把 blocked/fail/pending 转成派工动作;actionCount 不代表业务证明完成,proof-gap 未关闭时不得宣称提号率、客户效果或人工补号量改善。'
- ];
- if (Array.isArray(queue.topActions) && queue.topActions.length) {
- lines.push(
- '',
- '| ID | 优先级 | 负责人 | 动作 | 状态 | 命令 | 通过标准 | 缺证明项 |',
- '| --- | ---: | --- | --- | --- | --- | --- | ---: |',
- ...queue.topActions.map(item => tableRow([
- item.id || 'missing',
- item.priority || item.order || 0,
- item.owner || 'missing',
- item.title || 'missing',
- item.status || 'missing',
- item.command || 'missing',
- item.acceptance || 'missing',
- item.missingProofRequirementCount || 0
- ]))
- );
- }
- return lines.join('\n');
- }
- function renderOwnerArtifacts(ownerArtifacts) {
- const lines = [
- '| 负责人 | 行动数 | 最高优先级 | Markdown | CSV | 修复附件 |',
- '| --- | --- | --- | --- | --- | --- |'
- ];
- for (const item of ownerArtifacts) {
- lines.push(`| ${escapeCell(item.owner)} | ${item.actionCount} | ${item.topPriority} | ${escapeCell(item.markdown)} | ${escapeCell(item.csv)} | ${escapeCell(renderRepairArtifactSummary(item.repairArtifacts || []))} |`);
- }
- return lines.join('\n');
- }
- function renderBusinessExecutionIndex(index) {
- const lines = [
- `- 报告:${index.report}`,
- `- CSV:${index.csv}`,
- `- Summary:${index.summary}`,
- `- passed:${index.passed ? 'true' : 'false'}`,
- `- rowCount:${index.rowCount}`,
- `- repairRowCount:${index.repairRowCount}`,
- `- operatorPackOwnerArtifactCount:${index.operatorPackOwnerArtifactCount || 0}`,
- `- proofOpenCount:${index.proofOpenCount}`,
- `- directCustomerProof:${index.directCustomerProof ? 'true' : 'false'}`
- ];
- if (Array.isArray(index.operatorPackOwnerArtifacts) && index.operatorPackOwnerArtifacts.length) {
- lines.push(
- '',
- '| 负责人 | 动作数 | Markdown | CSV | 缺口 |',
- '| --- | ---: | --- | --- | --- |',
- ...index.operatorPackOwnerArtifacts.map(item => tableRow([
- item.owner,
- item.actionCount,
- item.markdown || 'missing',
- item.csv || 'missing',
- (item.gapIds || []).join(';') || 'missing'
- ]))
- );
- }
- if (index.longRunReadiness) {
- lines.push(
- `- longRunReadiness.report:${index.longRunReadiness.report || 'missing'}`,
- `- longRunReadiness.summary:${index.longRunReadiness.summary || 'missing'}`,
- `- longRunReadiness.status:${index.longRunReadiness.status || 'unknown'}`,
- `- longRunReadiness.ready:${index.longRunReadiness.ready ? 'true' : 'false'}`,
- `- longRunReadiness.failCount:${index.longRunReadiness.failCount}`,
- `- longRunReadiness.directCustomerProof:${index.longRunReadiness.directCustomerProof ? 'true' : 'false'}`
- );
- }
- if (index.optimizationCompletion) {
- lines.push(
- `- optimizationCompletion.report:${index.optimizationCompletion.report || 'missing'}`,
- `- optimizationCompletion.summary:${index.optimizationCompletion.summary || 'missing'}`,
- `- optimizationCompletion.status:${index.optimizationCompletion.status || 'unknown'}`,
- `- optimizationCompletion.readyForClaim:${index.optimizationCompletion.readyForClaim ? 'true' : 'false'}`,
- `- optimizationCompletion.proofGapOpenCount:${index.optimizationCompletion.proofGapOpenCount}`,
- `- optimizationCompletion.blockingReasonCount:${index.optimizationCompletion.blockingReasonCount}`,
- `- optimizationCompletion.videoAbPreflightReadyForVideoAb:${index.optimizationCompletion.videoAbPreflightReadyForVideoAb ? 'true' : 'false'}`,
- `- optimizationCompletion.videoAbPreflightFailureCount:${index.optimizationCompletion.videoAbPreflightFailureCount ?? 'unknown'}`,
- `- optimizationCompletion.directCustomerProof:${index.optimizationCompletion.directCustomerProof ? 'true' : 'false'}`
- );
- }
- return lines.join('\n');
- }
- function normalizeProofGapClosureRows(summary) {
- if (!summary || !Array.isArray(summary.rows)) return [];
- return summary.rows.map(row => ({
- id: row.id || '',
- title: row.title || '',
- status: row.status || '',
- evidence: row.evidence || '',
- missingProofRequirements: Array.isArray(row.missingProofRequirements) ? row.missingProofRequirements.filter(Boolean) : [],
- required: row.required || '',
- command: row.command || '',
- expectedArtifact: row.expectedArtifact || ''
- }));
- }
- function normalizeProofGapClosureCounts(summary) {
- const rows = Array.isArray(summary?.rows) ? summary.rows : [];
- const precheckRows = rows.filter(row => row.id === 'intake-readiness');
- const businessRows = rows.filter(row => row.id !== 'intake-readiness');
- const fallbackBusinessOpen = businessRows.filter(row => row.status === 'open').length;
- const fallbackBusinessClosed = businessRows.filter(row => row.status === 'closed').length;
- const fallbackPrecheckOpen = precheckRows.filter(row => row.status === 'open').length;
- const fallbackPrecheckClosed = precheckRows.filter(row => row.status === 'closed').length;
- return {
- businessOpenCount: numberOr(summary?.businessOpenCount, numberOr(summary?.openCount, fallbackBusinessOpen)),
- businessClosedCount: numberOr(summary?.businessClosedCount, numberOr(summary?.closedCount, fallbackBusinessClosed)),
- businessGapCount: numberOr(summary?.businessGapCount, businessRows.length),
- totalRows: numberOr(summary?.totalRows, rows.length),
- precheckRowCount: numberOr(summary?.precheckRowCount, precheckRows.length),
- precheckOpenCount: numberOr(summary?.precheckOpenCount, fallbackPrecheckOpen),
- precheckClosedCount: numberOr(summary?.precheckClosedCount, fallbackPrecheckClosed),
- countSemantics: summary?.countSemantics || {
- openCount: 'business_gap_open_count_excludes_precheck_rows',
- closedCount: 'business_gap_closed_count_excludes_precheck_rows',
- businessOpenCount: 'same_as_openCount',
- businessClosedCount: 'same_as_closedCount',
- precheckOpenCount: 'precheck_rows_reported_separately'
- }
- };
- }
- function numberOr(value, fallback) {
- const number = Number(value);
- return Number.isFinite(number) ? number : fallback;
- }
- function renderProofGapClosure(closure) {
- const lines = [
- `- Summary:${closure.summary}`,
- `- 报告:${closure.report}`,
- `- complete:${closure.complete ? 'true' : 'false'}`,
- `- openCount:${closure.openCount}`,
- `- closedCount:${closure.closedCount}`,
- `- businessOpenCount:${closure.businessOpenCount}`,
- `- businessClosedCount:${closure.businessClosedCount}`,
- `- businessGapCount:${closure.businessGapCount}`,
- `- totalRows:${closure.totalRows}`,
- `- precheckRowCount:${closure.precheckRowCount}`,
- `- precheckOpenCount:${closure.precheckOpenCount}`,
- `- intakeReady:${closure.intakeReady ? 'true' : 'false'}`,
- `- countSemantics.openCount:${closure.countSemantics?.openCount || 'unknown'}`,
- ''
- ];
- if (!closure.rows.length) {
- lines.push('- 暂无 proof-gap closure 行。');
- return lines.join('\n');
- }
- lines.push('| 缺口ID | 状态 | 当前证据 | 缺失证明 | 验收标准 | 下一步命令 |');
- lines.push('| --- | --- | --- | --- | --- | --- |');
- for (const row of closure.rows) {
- if (row.status !== 'open') continue;
- lines.push(`| ${escapeCell(row.id)} | ${escapeCell(row.status)} | ${escapeCell(row.evidence)} | ${escapeCell(row.missingProofRequirements.join(';') || '-')} | ${escapeCell(row.required)} | \`${escapeCell(row.command)}\` |`);
- }
- return lines.join('\n');
- }
- function renderFeedbackLoopClosure(closure) {
- return [
- `- Summary:${closure.summary}`,
- `- 报告:${closure.report}`,
- `- CSV:${closure.csv}`,
- `- passed:${closure.passed ? 'true' : 'false'}`,
- `- complete:${closure.complete ? 'true' : 'false'}`,
- `- directCustomerProof:${closure.directCustomerProof ? 'true' : 'false'}`,
- `- proofLevel:${closure.proofLevel || 'unknown'}`,
- `- negativeFeedbackCount:${closure.negativeFeedbackCount}`,
- `- blockedCreatorCount:${closure.blockedCreatorCount}`,
- `- leakedCount:${closure.leakedCount}`,
- `- teamRuleSuggestionCount:${closure.teamRuleSuggestionCount}`,
- `- missingInputs:${closure.missingInputs.length ? closure.missingInputs.join(';') : '无'}`
- ].join('\n');
- }
- function renderHomepageEvidenceReadiness(readiness) {
- return [
- `- Summary:${readiness.summary}`,
- `- 报告:${readiness.report}`,
- `- 修复 CSV:${readiness.csv}`,
- `- ready:${readiness.ready ? 'true' : 'false'}`,
- `- complete:${readiness.complete ? 'true' : 'false'}`,
- `- directCustomerProof:${readiness.directCustomerProof ? 'true' : 'false'}`,
- `- proofLevel:${readiness.proofLevel || 'unknown'}`,
- `- failureCount:${readiness.failureCount}`,
- `- providerEvidenceCreators:${readiness.providerEvidenceCreators}`,
- `- creatorsWithPosts:${readiness.creatorsWithPosts}`,
- `- creatorsWithEnoughRecentPosts:${readiness.creatorsWithEnoughRecentPosts}`,
- `- repairActionCount:${readiness.repairActionCount}`,
- '- 边界:只证明主页证据是否可用于复核,不证明客户命中率提升。'
- ].join('\n');
- }
- function renderLongRunReadiness(readiness) {
- return [
- `- report: ${readiness.report || 'missing'}`,
- `- summary: ${readiness.summary || 'missing'}`,
- `- mode: ${readiness.mode || 'unknown'}`,
- `- ready=${readiness.ready ? 'true' : 'false'}`,
- `- passCount: ${readiness.passCount || 0}`,
- `- failCount: ${readiness.failCount || 0}`,
- `- warnCount: ${readiness.warnCount || 0}`,
- `- directCustomerProof: ${readiness.directCustomerProof ? 'true' : 'false'}`,
- `- proofLevel: ${readiness.proofLevel || 'not_business_proof'}`,
- `- nextCommandCount: ${readiness.nextCommandCount || 0}`,
- `- boundaryCount: ${readiness.boundaryCount || 0}`,
- '- 边界:该门禁只判断 full-matrix/live 长跑是否可启动;ready=false 时不得宣称客户效果、命中率提升或人工补号量下降。'
- ].join('\n');
- }
- function renderLocalSeedToIntakeWorklist(worklist) {
- return [
- `- 报告:${worklist.markdown || 'missing'}`,
- `- 汇总 CSV:${worklist.csv || 'missing'}`,
- `- Summary:${worklist.summary || 'missing'}`,
- `- history-intake-draft:${worklist.historyDraft || 'missing'}`,
- `- video-resource-worklist:${worklist.videoWorklist || 'missing'}`,
- `- candidate-seed-worklist:${worklist.candidateWorklist || 'missing'}`,
- `- proofLevel: ${worklist.proofLevel || 'not_business_proof'}`,
- `- materialType: ${worklist.materialType || 'seed_to_intake_worklist'}`,
- `- directCustomerProof: ${worklist.directCustomerProof ? 'true' : 'false'}`,
- `- canCloseProofGap: ${worklist.canCloseProofGap ? 'true' : 'false'}`,
- `- complete: ${worklist.complete ? 'true' : 'false'}`,
- `- historyDraftRows: ${worklist.historyDraftRows || 0}`,
- `- referenceSeedRows: ${worklist.referenceSeedRows || 0}`,
- `- candidateSeedRows: ${worklist.candidateSeedRows || 0}`,
- `- videoWorklistRows: ${worklist.videoWorklistRows || 0}`,
- `- videoCandidateNeedsResourceRows: ${worklist.videoCandidateNeedsResourceRows || 0}`,
- `- missingProofRequirementCount: ${worklist.missingProofRequirementCount || 0}`,
- `- nextActionCount: ${worklist.nextActionCount || 0}`,
- `- targetFiles: ${(worklist.targetFiles || []).join(';') || 'missing'}`,
- '- 边界:该 worklist 只把本地种子转成补表草稿;空字段仍需商务/投放补真实材料,不能关闭 proof-gap。'
- ].join('\n');
- }
- function renderRealGapMaterialAudit(audit) {
- return [
- `- report: ${audit.markdown || 'missing'}`,
- `- csv: ${audit.csv || 'missing'}`,
- `- summary: ${audit.summary || 'missing'}`,
- `- proofLevel: ${audit.proofLevel || 'not_business_proof'}`,
- `- materialType: ${audit.materialType || 'three_real_gap_material_audit'}`,
- `- directCustomerProof: ${audit.directCustomerProof ? 'true' : 'false'}`,
- `- canCloseProofGap: ${audit.canCloseProofGap ? 'true' : 'false'}`,
- `- complete: ${audit.complete ? 'true' : 'false'}`,
- `- materialFound: ${audit.materialFoundCount || 0}/${audit.gapCount || 0}`,
- `- openGapCount: ${audit.openGapCount || 0}`,
- `- gapIds: ${(audit.gapIds || []).join('; ') || 'missing'}`,
- '- boundary: material coverage does not prove tihao-rate improvement, customer effect, video A/B lift, or manual supplement reduction.'
- ].join('\n');
- }
- function renderOptimizationCompletion(completion) {
- return [
- `- report: ${completion.report || 'missing'}`,
- `- summary: ${completion.summary || 'missing'}`,
- `- complete: ${completion.complete ? 'true' : 'false'}`,
- `- readyForClaim: ${completion.readyForClaim ? 'true' : 'false'}`,
- `- proofGapOpenCount: ${completion.proofGapOpenCount}`,
- `- blockingReasonCount: ${completion.blockingReasonCount}`,
- `- blockingReasonsWithMissingProofRequirements: ${completion.blockingReasonsWithMissingProofRequirements || 0}`,
- `- missingProofRequirementCount: ${completion.missingProofRequirementCount || 0}`,
- `- videoAbPreflightReadyForVideoAb: ${completion.videoAbPreflightReadyForVideoAb ? 'true' : 'false'}`,
- `- videoAbPreflightFailureCount: ${completion.videoAbPreflightFailureCount ?? 'unknown'}`,
- `- directCustomerProof: ${completion.directCustomerProof ? 'true' : 'false'}`,
- `- proofLevel: ${completion.proofLevel || 'not_business_proof'}`,
- `- canClaim.tihaoRateImproved: ${completion.canClaim?.tihaoRateImproved ? 'true' : 'false'}`,
- `- canClaim.customerEffectAchieved: ${completion.canClaim?.customerEffectAchieved ? 'true' : 'false'}`,
- `- canClaim.manualSupplementReduced: ${completion.canClaim?.manualSupplementReduced ? 'true' : 'false'}`,
- `- nextRequiredCommandCount: ${completion.nextRequiredCommandCount || 0}`,
- '- 边界:readyForClaim=false 时不得宣称提号率提升、客户效果达标或人工补号量下降。'
- ].join('\n');
- }
- function normalizeRepairArtifacts(repairArtifacts) {
- return repairArtifacts.map(item => ({
- title: item.title || '',
- csv: item.csv || '',
- actionCount: Number(item.actionCount || 0),
- topPriority: Number(item.topPriority || 0),
- fields: Array.isArray(item.fields) ? item.fields : []
- }));
- }
- function renderRepairArtifactSummary(repairArtifacts) {
- if (!repairArtifacts.length) return '无';
- return repairArtifacts
- .map(item => `${item.title || '修复清单'}:${item.csv || '缺失'}(${item.actionCount || 0})`)
- .join(';');
- }
- function tableRow(cells) {
- return `| ${cells.map(escapeCell).join(' | ')} |`;
- }
- function normalizePipelineNextActions(summary) {
- if (!summary || !Array.isArray(summary.nextActions)) return [];
- return summary.nextActions.map(item => ({
- priority: item.priority,
- owner: item.owner,
- title: item.title,
- step: item.step,
- command: item.command,
- expectedArtifact: item.expectedArtifact,
- acceptance: item.acceptance
- }));
- }
- function renderPipelineNextActions(pipeline) {
- const lines = [
- `- 摘要:${pipeline.summary}`,
- `- 报告:${pipeline.report}`,
- `- readyForClaim:${pipeline.readyForClaim ? 'true' : 'false'}`,
- `- pass:${pipeline.counts.pass || 0}`,
- `- fail:${pipeline.counts.fail || 0}`,
- `- nextActions:${pipeline.nextActions.length}`,
- ''
- ];
- if (!pipeline.nextActions.length) {
- lines.push('- 暂无 pipeline 下一步动作。');
- return lines.join('\n');
- }
- lines.push('| 优先级 | 负责人 | 动作 | 触发步骤 | 执行命令 | 通过标准 |');
- lines.push('| --- | --- | --- | --- | --- | --- |');
- for (const item of pipeline.nextActions) {
- lines.push(`| ${item.priority} | ${escapeCell(item.owner)} | ${escapeCell(item.title)} | ${escapeCell(item.step)} | ${escapeCell(item.command)} | ${escapeCell(item.acceptance)} |`);
- }
- return lines.join('\n');
- }
- function parseArgs(argv) {
- const args = {};
- for (let index = 0; index < argv.length; index += 1) {
- const raw = argv[index];
- if (!raw.startsWith('--')) continue;
- const key = raw.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase());
- const next = argv[index + 1];
- if (!next || next.startsWith('--')) args[key] = true;
- else {
- args[key] = next;
- index += 1;
- }
- }
- return args;
- }
- function rel(root, file) {
- return path.relative(root, file).replace(/\\/g, '/');
- }
- function artifactPath(root, dir, ...parts) {
- const base = path.isAbsolute(dir) ? dir : path.join(root, dir);
- return path.join(base, ...parts);
- }
- function artifactRef(root, file) {
- const resolvedRoot = path.resolve(root);
- const resolvedFile = path.resolve(file);
- const relative = path.relative(resolvedRoot, resolvedFile);
- if (relative && (relative.startsWith('..') || path.isAbsolute(relative))) return resolvedFile.replace(/\\/g, '/');
- return relative.replace(/\\/g, '/');
- }
- function relIfExists(root, file) {
- return fs.existsSync(file) ? rel(root, file) : null;
- }
- function countRowsWithMissingProofRequirements(rows) {
- if (!Array.isArray(rows)) return 0;
- return rows.filter(row =>
- Array.isArray(row.missingProofRequirements) &&
- row.missingProofRequirements.length >= 1
- ).length;
- }
- function uniqueMissingProofRequirementCount(rows) {
- if (!Array.isArray(rows)) return 0;
- const values = new Set();
- for (const row of rows) {
- const requirements = Array.isArray(row.missingProofRequirements) ? row.missingProofRequirements : [];
- for (const requirement of requirements) {
- if (requirement) values.add(String(requirement));
- }
- }
- return values.size;
- }
- function escapeCell(value) {
- return String(value ?? '').replace(/\|/g, '/').replace(/\r?\n/g, ' ');
- }
- function withBom(text) {
- return `\uFEFF${text}`;
- }
- if (require.main === module) main();
- module.exports = {
- buildHandoffSummary,
- renderReport
- };
|