神经网络废话审查
神经网络废话不是风格问题,而是无法被代码证实的断言以及没有理由存在的代码。下面的每一条发现都会经过验证:通过代码行、命令输出、或使用者缺失来确认。不包含个人偏好和 linter 能捕获的问题。
原则
- 删除优于补充。 死选项应被删除,而非记录;营销性短语应替换为事实或直接删除。
- 断言需通过代码验证,而非记忆。 在判断 README 中的语句为虚假或正确之前,先打开它提到的文件。
- 没有证据的发现不算发现。 如果无法展示
file:line或命令输出,就不要写。 - 修改仅在对方请求时进行。默认情况下,审查结果是一个列表。
1. 工作流程
- 确定范围:diff(
git diff main...HEAD)、特定文件、或准备发布前的整个仓库。 - 运行第 3 节中的搜索命令——这些命令给出候选结果,而非最终发现。
- 通过阅读代码逐一检查每个候选,并剔除误报。
- 针对搜索无法捕获的内容,使用第 2 节的检查清单:README 与代码的一致性、UI 状态、抽象层。
- 如果可能,运行应用并查看页面:模板化的屏幕和未样式化的组件会立刻显现。
- 按照第 4 节的格式输出报告。
2. 检查清单
2.1. 生成器和模板残留
- 生成器的起始页面和块:“开始编辑”、“框架文档链接”、“utm_source=…-project”、“给个星标”、工具云服务相关模块。
- 模板文件:
example.spec.ts、仅检查模板标题的测试、public/中的模板 SVG 和图片、生成器的 README。 - 空占位符:已有文件的文件夹中的
.gitkeep、空的index.ts、无代码的层目录。
2.2. 死代码和未完成代码
- 配置文件或
switch分支中抛出“not implemented”/“pending”的值。 - 看似扩展点但只有一个值的枚举(如
type: "graphql" | "msw",实际上msw未实现)。 - 被注释的代码、无原因和链接的
TODO、未使用的导出、在package.json中但从未被导入的依赖。 package.json中无法运行的脚本(引用了已删除的文件、不存在的目标)。
2.3. 文档与代码不符
检查 README、ADR、注释和提交描述中的每一个断言:
- 名称和路径: 提及的文件、命令、环境变量必须真实存在(例如文本中是
next.config.ts但仓库中是next.config.js——这是发现)。 - 行为: “请求是直接的”、“JS 无法访问 token”、“防止开放重定向”——找到实现该行为的代码,并检查边界情况。
- 版本和数字: 库版本、token 生命周期、覆盖率。
- 将来时描述为现在时: 计划中的功能被描述为已完成。
- Markdown 中的链接和锚点应正确指向目标(标题修改会导致锚点失效)。
2.4. 语气
- 评价性词语而非事实:premium、state-of-the-art、cutting-edge、blazing/lightning-fast、seamless、robust、powerful、modern、production-ready、enterprise-grade、“不仅仅是”、“高级”、“现代”、“强大”。
- 文档标题、UI、日志和提交消息中的 emoji。
- “用心设计”、“精心制作”、无意义的徽章。
- 复述性注释(如
getUser()上方的“// 获取用户”)、历史性注释(“// 已修复”、“// 更新为 X”)、全大写注释、无解释的“IMPORTANT”标记。 - 像“🚀 产品路线图”和“(高级审美)”这样的标题和注释。
替代方案是事实:它做了什么、为什么这样做、有什么限制。
2.5. 多余抽象
- 只有一种实现且测试中无 mock 的接口或工厂。
- 无使用者或未记录理由(ADR、README 段落)的层、区域、monorepo 包、状态管理器、Storybook。
- 仅仅是重命名的封装(如
useAuthApi = () => useStrictContext(Ctx)不含逻辑的可以接受;封装之上的封装则不行)。 - “以备将来使用”:从未被调用的参数、只有一个值的配置选项。
2.6. 错误处理和异步
- 通过错误消息文本来确定错误类型(如
message === "unauthorized"、includes("invalid password"))——缺少原因注释和测试。 - 仅检查错误数组的第一个元素(
errors[0])。 throw { status, ... }—— 使用对象而非Error实例。- 空的
catch、返回空数据的catch、.catch(() => {})。 - 共享的 in-flight promise,等待者未读取其结果(例如 token 刷新:“等待后重试”但未检查是否成功)。
- 直接将服务器
error.message展示给用户。 - 缺少加载状态、错误状态、空列表状态。
2.7. 安全性和隐私
- 日志中的个人数据:电子邮件、电话、姓名;token;请求体。
- 仓库或历史中的密钥(
git log -p)、被 Git 跟踪的.env、以NEXT_PUBLIC_开头的密钥。 - 未经验证的重定向参数(
callbackUrl、next、returnTo),或仅通过startsWith("/")/!startsWith("//")验证——这会被/\.evil.com或控制字符绕过。 - 将 token 存储在
localStorage/sessionStorage中;token 出现在 URL 中且读取后未清除。 - 未使用 sanitizer 的
dangerouslySetInnerHTML。
2.8. UI
- 使用主题中不存在的样式类:从 shadcn/ui 粘贴的 token(如
bg-card、text-muted-foreground、bg-primary)在没有这些 token 的项目中——组件会静默丢失样式。 - 当 token 存在时直接使用原始 HEX 或任意值。
- 在
onChange中设置“已填充”状态——会被自动填充和reset()破坏。 - 可变列表中使用
key={index};表单内缺少type的按钮;无aria-label的图标按钮。 - 从设计稿中复制的 SVG 带有被
viewBox裁剪的滤镜(阴影、发光)——在 logo 周围出现可见矩形。
2.9. 测试
- 测试仅验证 mock 而非实际行为;大型组件树的快照。
- e2e 测试针对共享或生产后端并修改数据。
- 因 jsdom 不应用 CSS 而通过的测试(元素被类隐藏但测试仍能找到它),以及过于宽泛的选择器(如
/password/i匹配了“显示密码”)。
2.10. Git
- 一次提交中包含无关的更改;提交消息为“fix stuff”。
- 生成的文件和构建产物被 Git 跟踪(除了有意提交的生成 API 客户端)。
- 提交消息描述的内容与 diff 不符。
3. 候选搜索
以下命令产生候选结果。每个匹配项需通过阅读代码来验证。
# 生成器模板和营销内容
rg -n -i "utm_source|get started by editing|give us a star|nx cloud|welcome to|carefully crafted|designed with" \
--glob '!**/node_modules/**' --glob '!*.lock' --glob '!pnpm-lock.yaml'
rg -n -i "premium|state-of-the-art|cutting-edge|blazing|lightning|seamless|robust|enterprise-grade|production-ready|премиальн|современн|мощн" \
--glob '!**/node_modules/**'
# 代码、UI 和文档中的 emoji
rg -n --pcre2 '[\x{1F300}-\x{1FAFF}\x{2600}-\x{27BF}]' --glob '!**/node_modules/**' --glob '!*.lock'
# 未完成内容
rg -n -i "not implemented|pending implementation|todo|fixme|hack" --glob '!**/node_modules/**'
# 脆弱的错误处理
rg -n "errors\?\.\[0\]|errors\[0\]|message ===|message\.includes|\.includes\([\"'][a-z ]+[\"']\)" src app
rg -n "throw \{" src app
rg -n "catch \{\s*\}|catch \(\w*\) \{\s*\}|\.catch\(\(\) => \{\s*\}\)" src app
# 包含个人数据的日志
rg -n "(logger|console)\.\w+\(.*(email|phone|password|token)" src app
# 重定向和 token
rg -n "callbackUrl|returnTo|redirectTo|searchParams.get\([\"']next" src app
rg -n "localStorage|sessionStorage" src app
# 无 token 的 shadcn 类:找到类并与 @theme / tailwind 配置比对
rg -n -o "\b(bg|text|border)-(card|muted|popover|accent|primary|secondary|destructive)(-foreground)?\b" src app | sort -u
# 未使用的依赖和导出(如已安装 knip)
pnpm dlx knip
# 历史中的密钥
git log -p --all | rg -n -i "(api[_-]?key|secret|password|token)\s*[:=]\s*[\"'][A-Za-z0-9_\-]{16,}"
git ls-files | rg -n "(^|/)\.env($|\.)" | rg -v "\.env\.example$"
4. 报告格式
发现按重要性降序排列:安全性和隐私 → 文档中的虚假断言 → 错误处理 bug → 死代码和未完成代码 → 模板 → 语气。
<文件>:<行号> — <类别>
问题:<一句话说明问题,附带事实>
为什么重要:<对用户、审查者或维护者的影响>
修复:<具体操作;通常是“删除”或“替换为事实:…”>
最后说明哪些内容已检查但未发现任何问题,以及哪些内容未检查(例如未运行应用)。如果没有发现任何问题,则如实说明,不要牵强附会。