historical-dataset-audit-smoke.js 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const { auditRecords, loadRecords } = require('./historical-dataset-audit');
  6. function main() {
  7. const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-history-audit-'));
  8. writeJson(path.join(dir, 'dha.json'), sample({
  9. id: 'dha-history',
  10. category: '母婴',
  11. selectedName: '营养师妈妈',
  12. rejectedName: '婚礼布置号'
  13. }));
  14. writeJson(path.join(dir, 'skincare.json'), sample({
  15. id: 'skincare-history',
  16. category: '护肤',
  17. selectedName: '敏感肌成分党',
  18. rejectedName: '泛美妆硬广号'
  19. }));
  20. writeJson(path.join(dir, 'home.json'), sample({
  21. id: 'home-history',
  22. category: '家清',
  23. selectedName: '真实家居清洁实验室',
  24. rejectedName: '装修设计号'
  25. }));
  26. const summary = auditRecords({ inputPath: dir, records: loadRecords(dir), minBriefs: 3 });
  27. assert(summary.acceptance.readyForLongRun, 'complete history dataset should be ready for long run');
  28. assert(summary.acceptance.readyForCustomerEffectProof, 'complete history dataset should be ready for customer effect proof');
  29. assert(summary.briefCount === 3, 'should count history briefs');
  30. assert(summary.withCustomerDecision === 3, 'should count customer decision coverage');
  31. assert(summary.withRejectionReason === 3, 'should count rejection reason coverage');
  32. assert(summary.withManualSupplementBaseline === 3, 'should count manual supplement baseline coverage');
  33. const missingBaselineDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-history-audit-missing-baseline-'));
  34. writeJson(path.join(missingBaselineDir, 'missing-baseline.json'), sample({
  35. id: 'missing-baseline',
  36. category: '护肤',
  37. selectedName: '敏感肌记录者',
  38. rejectedName: '硬广导购号',
  39. includeManualSupplementBaseline: false
  40. }));
  41. const missingBaselineSummary = auditRecords({ inputPath: missingBaselineDir, records: loadRecords(missingBaselineDir), minBriefs: 1 });
  42. assert(missingBaselineSummary.acceptance.readyForLongRun, 'missing manual supplement baseline should not block basic long-run readiness');
  43. assert(!missingBaselineSummary.acceptance.readyForCustomerEffectProof, 'missing manual supplement baseline should block customer effect proof');
  44. console.log(`historical dataset audit smoke ok: ${dir}`);
  45. }
  46. function sample({ id, category, selectedName, rejectedName, includeManualSupplementBaseline = true }) {
  47. return {
  48. id,
  49. name: id,
  50. category,
  51. ...(includeManualSupplementBaseline ? { manualSupplementBaseline: 6 } : {}),
  52. briefText: `${category} 品类真实历史 Brief,包含预算、平台、参考账号和排除项。`,
  53. referenceLinks: [{ url: 'https://example.com/reference-video', platform: 'xiaohongshu', contentType: 'video' }],
  54. manualFinalList: [
  55. { platform: '小红书', creatorName: selectedName, profileUrl: `https://example.com/${id}/a`, manualReviewLabel: '可直接发客户', customerDecision: '客户选中' },
  56. { platform: '小红书', creatorName: rejectedName, profileUrl: `https://example.com/${id}/b`, manualReviewLabel: '跑偏', customerDecision: '客户拒绝', rejectReason: '内容方向偏离 Brief' }
  57. ],
  58. customerFeedback: [
  59. { creatorName: selectedName, finalDecision: '客户选中', reason: '客户认可调性和内容结构' },
  60. { creatorName: rejectedName, finalDecision: '客户拒绝', rejectReason: '跑偏,不能承接本次 Brief' }
  61. ]
  62. };
  63. }
  64. function writeJson(file, value) {
  65. fs.writeFileSync(file, JSON.stringify(value, null, 2), 'utf8');
  66. }
  67. function assert(condition, message) {
  68. if (!condition) throw new Error(message);
  69. }
  70. if (require.main === module) main();