| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- #!/usr/bin/env node
- const fs = require('fs');
- const os = require('os');
- const path = require('path');
- const { spawnSync } = require('child_process');
- const { sanitizeCell, sanitizePublicUrl } = require('./local-seed-material-index');
- const ROOT = path.resolve(__dirname, '..');
- function main() {
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-local-seed-index-'));
- const workspaceRoot = path.join(temp, 'workspace');
- const outputs = path.join(temp, 'outputs');
- const output = path.join(temp, 'index');
- fs.mkdirSync(workspaceRoot, { recursive: true });
- fs.mkdirSync(outputs, { recursive: true });
- writeJson(path.join(outputs, 'optimization-pipeline-latest', 'optimization-pipeline-summary.json'), {
- readyForClaim: false,
- counts: { pass: 6, fail: 3 },
- inputs: { currentManualSupplementCount: '0' },
- proofGapClosure: { complete: false, openCount: 5, closedCount: 0 }
- });
- writeJson(path.join(outputs, 'optimization-pipeline-latest', 'history-audit', 'historical-dataset-audit.json'), {
- briefCount: 1,
- acceptance: {
- readyForCustomerEffectProof: false,
- readyForLongRun: false,
- categoryCoverageMet: false
- }
- });
- writeJson(path.join(outputs, 'optimization-pipeline-latest', 'customer-effect-audit', 'customer-effect-summary.json'), {
- acceptance: {
- overallPass: false,
- customerSelectedRateMeasured: false,
- referenceCustomerSelectedRateMeasured: false,
- historyReadyForCustomerEffectProof: false
- },
- missingEvidence: ['缺少客户最终选择字段']
- });
- writeJson(path.join(outputs, 'overnight-quality-live', 'aggregate-summary.json'), {
- manifest: { liveEnabled: true },
- acceptance: { overallPass: true, failedGateCount: 0 },
- failureCount: 0,
- runCount: 2,
- fixtureCount: 1,
- variantCount: 2
- });
- const result = spawnSync(process.execPath, [
- 'scripts/local-seed-material-index.js',
- '--workspace-root',
- workspaceRoot,
- '--outputs',
- outputs,
- '--output',
- output,
- '--strict'
- ], {
- cwd: ROOT,
- encoding: 'utf8',
- shell: false
- });
- if (result.stdout) process.stdout.write(result.stdout);
- if (result.stderr) process.stderr.write(result.stderr);
- assert(result.status === 0, 'local seed material index should pass without local workbooks');
- const summary = readJson(path.join(output, 'local-seed-material-index-summary.json'));
- const report = fs.readFileSync(path.join(output, 'local-seed-material-index.md'), 'utf8');
- const csv = fs.readFileSync(path.join(output, 'local-seed-material-index.csv'), 'utf8');
- assert(summary.proofLevel === 'not_business_proof', 'summary proof level should be not_business_proof');
- assert(summary.directCustomerProof === false, 'summary should not be direct customer proof');
- assert(summary.canCloseProofGap === false, 'summary should not close proof gaps');
- assert(summary.existingMaterialCount === 0, 'empty smoke workspace should have zero local materials');
- assert(summary.pipelineArtifacts.pipeline.readyForClaim === false, 'pipeline boundary should be retained');
- assert(summary.pipelineArtifacts.historyAudit.readyForCustomerEffectProof === false, 'history audit should remain not ready');
- assert(summary.pipelineArtifacts.customerEffect.overallPass === false, 'customer effect should remain not passed');
- assert(summary.liveAutomationCandidates.length === 1, 'live automation candidate should be indexed');
- assert(summary.liveAutomationCandidates[0].liveAutomationPass === true, 'live automation candidate should be detected');
- assert(summary.liveAutomationCandidates[0].canCloseProofGapNow === false, 'live automation candidate should not close proof gap directly');
- const dirtyShareUrl = 'https://www.xiaohongshu.com/discovery/item/abc123?app_version=9.26.0&xsec_token=secret-token&author_share=1#frag';
- const cleanShareUrl = sanitizePublicUrl(dirtyShareUrl);
- assert(cleanShareUrl === 'https://www.xiaohongshu.com/discovery/item/abc123', 'share URL should drop query and hash parameters');
- assert(!sanitizeCell(dirtyShareUrl).includes('xsec_token'), 'display cells should not expose share token parameters');
- const bearerValue = ['Authorization: Bearer', 'abcdefghijklmnopqrstuvwxyz'].join(' ');
- assert(sanitizeCell(bearerValue) === '[REDACTED_SECRET_LIKE_VALUE]', 'secret-like values should be redacted');
- assert(report.includes('本地种子材料索引'), 'report should render title');
- assert(report.includes('canCloseProofGap:false'), 'report should render proof boundary');
- assert(csv.includes('local-material'), 'csv should include local material rows');
- console.log(JSON.stringify({
- ok: true,
- materialCount: summary.materialCount,
- existingMaterialCount: summary.existingMaterialCount,
- liveAutomationCandidates: summary.liveAutomationCandidates.length
- }, null, 2));
- }
- function writeJson(file, value) {
- fs.mkdirSync(path.dirname(file), { recursive: true });
- fs.writeFileSync(file, JSON.stringify(value, null, 2), 'utf8');
- }
- function readJson(file) {
- return JSON.parse(fs.readFileSync(file, 'utf8'));
- }
- function assert(condition, message) {
- if (!condition) throw new Error(message);
- }
- main();
|