homepage-evidence-readiness-smoke.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const { spawnSync } = require('child_process');
  6. const ROOT = path.resolve(__dirname, '..');
  7. function main() {
  8. const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-homepage-readiness-'));
  9. const input = path.join(temp, 'homepage-evidence.json');
  10. const output = path.join(temp, 'out');
  11. fs.writeFileSync(input, JSON.stringify({
  12. candidates: [
  13. {
  14. platform: 'xiaohongshu',
  15. displayName: '高质感生活方式账号',
  16. profileUrl: 'https://example.com/profile/a',
  17. recentPosts: Array.from({ length: 10 }, (_, index) => ({
  18. title: `近期内容 ${index + 1}`,
  19. coverUrl: `https://example.com/cover-${index + 1}.jpg`,
  20. publishTime: `2026-06-${String(index + 1).padStart(2, '0')}`,
  21. likeCount: 100 + index,
  22. commentCount: 10 + index
  23. })),
  24. homepageEvidence: {
  25. source: 'provider',
  26. confidence: 'provider',
  27. recentContentWindow: 10,
  28. visualQualityScore: 88,
  29. riskHits: ['无明显下沉风险'],
  30. reviewNotes: ['近期封面稳定,标题和场景一致']
  31. }
  32. }
  33. ]
  34. }, null, 2), 'utf8');
  35. const result = run(['scripts/homepage-evidence-readiness-audit.js', '--input', input, '--output', output, '--strict']);
  36. assert(result.status === 0, 'ready provider evidence should pass strict');
  37. const summary = readJson(path.join(output, 'homepage-evidence-readiness-summary.json'));
  38. assert(summary.ready === true, 'summary.ready should be true');
  39. assert(summary.directCustomerProof === false, 'homepage readiness should not claim customer proof');
  40. assert(summary.counts.providerEvidenceCreators === 1, 'provider evidence should be counted');
  41. assert(summary.counts.creatorsWithEnoughRecentPosts === 1, 'recent 10 posts should be counted');
  42. const weakInput = path.join(temp, 'weak-homepage-evidence.json');
  43. const weakOutput = path.join(temp, 'weak-out');
  44. fs.writeFileSync(weakInput, JSON.stringify({
  45. candidates: [
  46. {
  47. platform: 'xiaohongshu',
  48. displayName: '只有主页链接的账号',
  49. profileUrl: 'https://example.com/profile/b',
  50. homepageEvidence: {
  51. source: 'fallback',
  52. reviewNotes: ['待补主页近期内容证据']
  53. }
  54. }
  55. ]
  56. }, null, 2), 'utf8');
  57. const weak = run(['scripts/homepage-evidence-readiness-audit.js', '--input', weakInput, '--output', weakOutput]);
  58. assert(weak.status === 0, 'non-strict weak evidence should still write audit artifacts');
  59. const weakSummary = readJson(path.join(weakOutput, 'homepage-evidence-readiness-summary.json'));
  60. assert(weakSummary.ready === false, 'weak evidence should not be ready');
  61. assert(weakSummary.proofLevel === 'not_business_proof', 'weak evidence should stay not business proof');
  62. assert(weakSummary.repairActions.length >= 1, 'weak evidence should produce repair actions');
  63. const strictWeak = run(['scripts/homepage-evidence-readiness-audit.js', '--input', weakInput, '--output', path.join(temp, 'strict-weak'), '--strict']);
  64. assert(strictWeak.status === 2, 'strict weak evidence should fail readiness gate');
  65. console.log(JSON.stringify({
  66. ok: true,
  67. output,
  68. weakOutput,
  69. ready: summary.ready,
  70. weakReady: weakSummary.ready,
  71. weakRepairActions: weakSummary.repairActions.length
  72. }, null, 2));
  73. }
  74. function run(args) {
  75. const result = spawnSync(process.execPath, args, {
  76. cwd: ROOT,
  77. encoding: 'utf8',
  78. shell: false
  79. });
  80. if (result.stdout) process.stdout.write(result.stdout);
  81. if (result.stderr) process.stderr.write(result.stderr);
  82. return result;
  83. }
  84. function readJson(file) {
  85. return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, ''));
  86. }
  87. function assert(condition, message) {
  88. if (!condition) throw new Error(message);
  89. }
  90. if (require.main === module) main();