import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; const repoRoot = process.cwd(); const scannedDocs = [ 'README.md', 'docs/refactor/backend-open-items-and-capacity-20260701.md', 'docs/refactor/backend-handoff-roadmap.md', 'docs/refactor/legacy-feature-gap-matrix.md', 'docs/refactor/next-development-todo.md', 'docs/refactor/taro-h5-deployment.md', 'docs/refactor/taro-frontend-integration.md', 'docs/refactor/taro-production-integration-checklist.md', 'docs/refactor/web-launch-acceptance-checklist.md', ]; function readLines(relativePath) { const absolutePath = path.join(repoRoot, relativePath); if (!fs.existsSync(absolutePath)) return []; return fs.readFileSync(absolutePath, 'utf8').replace(/\r\n/g, '\n').split('\n').map((text, index) => ({ file: relativePath, line: index + 1, text, })); } function hasAny(text, patterns) { return patterns.some(pattern => pattern.test(text)); } const lines = scannedDocs.flatMap(readLines); const failures = []; for (const item of lines) { const text = item.text.trim(); if (!text) continue; if ( hasAny(text, [/头像上传/, /头像裁剪/, /裁剪头像/, /第三方头像(?:同步|落库)/]) && !hasAny(text, [/不做/, /不支持/, /不允许/, /不得/, /不能/, /禁止/, /拒绝/, /不会/, /不要/, /不接/, /只保留/, /only/i, /preset/i]) ) { failures.push(`${item.file}:${item.line} 学生头像只能描述为预设-only,不应重新进入待办:${text}`); } if ( /排行榜/.test(text) && hasAny(text, [/待补/, /仍缺/, /未完成/, /下一步/, /继续补/, /TODO/i]) && !hasAny(text, [/默认关闭/, /默认不开启/, /默认不请求/, /不默认/, /不是默认/, /可选活动/, /显式开启/, /明确购买/, /专项压测/]) ) { failures.push(`${item.file}:${item.line} 排行榜不能作为默认主线待办:${text}`); } if (/前端消息中心/.test(text) && hasAny(text, [/仍缺/, /待补/, /未完成/, /缺/])) { failures.push(`${item.file}:${item.line} 学生前端消息中心已经完成第一版,不能继续写成待补:${text}`); } if ( /smoke:taro:h5:interaction/.test(text) && hasAny(text, [/26 项/, /租户后台六个主模块/, /平台后台四个主模块/, /租户题库内容\/财务、平台租户\/账务中心/]) ) { failures.push(`${item.file}:${item.line} H5 交互烟测已经覆盖 32 项和后台真实写操作,不能回退到旧描述:${text}`); } } assert.deepEqual(failures, [], `Product scope guardrails failed:\n${failures.join('\n')}`); console.log('[PASS] product scope guardrails');