Actual Budget 代码评审规范完全指南:基于 code-review-rubric 的 PR 审查实践
2026/9/11 9:16:22 网站建设 项目流程

Actual Budget 代码评审规范完全指南:基于 code-review-rubric 的 PR 审查实践

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

导读

本文围绕 Actual Budget(actualbudget/actual,一款本地优先的个人财务管理应用,TypeScript + React 编写)代码库中的评审清单文档 code-review-rubric.md,系统讲解该仓库在 PR 代码审查中必须遵守的硬性规则、类型与 React 模式、导入规范、国际化要求、财务数字排版、测试策略、提交规范及重点审查路径。读完本文,你将获得一份可直接投入实际审查工作的"检查表",并理解每条规则背后的仓库源码依据——无论是人工评审还是 AI Agent 执行 review,都能据此快速定位问题、给出可粘贴的修复建议。

文档定位:一份为"持续审查"而生的浓缩清单

rubric 文档明确说明其来源:由CODE_REVIEW_GUIDELINES.mdAGENTS.md.github/agents/pr-and-commit-rules.md三份文档蒸馏而成,目的是让评审者在审查中途不必反复阅读数百行原始规范,即可保持流畅。当评审者命中某条规则时,应按照节名(如 "Type assertions")引用规则来源,方便用户回溯原始文档。

三者分工如下:

来源文档职责
CODE_REVIEW_GUIDELINES.mdLLM Agent 执行代码评审的具体准则,涵盖设置泛滥、严格模式豁免、类型断言、any/unknown、i18n、测试 Mock、财务数字排版等
AGENTS.md面向 AI Agent 的完整开发指南:项目概览、命令、架构、代码风格与约定、常见任务排查
.github/agents/pr-and-commit-rules.mdAI 生成的 PR/提交必须遵守的规则([AI]前缀、PR 模板、issue 与评论前缀等)

此外,这份 rubric 被 .claude/skills/review-actual-pr/SKILL.md 引用为"审查 diff 之前必读的浓缩规则集"。在该 skill 的审查工作流中,发现分为三档:Critical(bug、安全问题、类型/构建破坏、数据丢失风险)、Important(违反仓库规则)和Suggestion(清晰度、命名、死代码、可提取的重复模式)。

硬性拒绝项(Hard rejections)

以下条目来自 CODE_REVIEW_GUIDELINES.md,除非 PR 中带有成文的理由说明,否则不可协商

  • 为 UI 微调新增设置项(Important)。Actual Budget 刻意抵制"设置膨胀"(settings bloat)。如果 PR 为某个本可用主题/设计 token 表达的内容新增用户可见的开关或偏好项,应标记为 Important,并提出基于主题的替代方案。原始文档的立场是:优先硬编码值或基于主题的解决方案,评估设置是否对用户提供有意义的价值,并检查是否与 Actual 的设计准则一致。
  • 新增@ts-strict-ignore注释(Important,若掩盖真实类型错误则为 Critical)。项目通过typescript-strict-plugin执行严格类型检查,新增豁免会削弱类型安全。应建议修复底层类型问题。注意 AGENTS.md 明确说明:新文件必须类型严格(type-strict),不得添加// @ts-strict-ignore;存量文件被"祖父条款"豁免。从源码看,仓库中确实存在历史遗留的豁免点,例如 FixedSizeList.tsx、ManageRules.tsx、Modals.tsx 等文件均含有@ts-strict-ignore——这正是"存量豁免、新增禁止"策略的体现。
  • 新增eslint-disableoxlint-disable注释。逻辑同上:规则的存在有其理由,应提出满足规则的修复方案而非抑制规则。仓库当前同时使用 oxlint(配置见 .oxlintrc.json)与自定义的actual/*规则集。
  • 代码中的密钥/凭据(Critical)。永远如此,无例外。

TypeScript 类型规则(来自 AGENTS.md + CODE_REVIEW_GUIDELINES.md)

rubric 将类型层面的约定归纳为五条,每条都能在仓库中找到对应实践:

  1. 优先type而非interface
  2. 禁止enum——使用对象映射。仓库的 eslint-plugin-actual 中就有no-enum规则在 lint 层面强制这一约定。
  3. 禁止无理由的any/unknown在提出新类型之前,先到 packages/loot-core/src/types/(含models/子目录、prefs.tsserver-handlers.ts等)查找是否已存在合适类型。loot-core是整个应用的类型定义中心,业务模型、处理器签名与偏好项类型都在此集中维护。
  4. 优先x satisfies SomeType而非x as SomeTypesatisfies能保留更精确的推断并在编译期捕获类型不匹配;唯一例外是真正的运行时类型守卫——此时必须加注释说明为何as是安全的。CODE_REVIEW_GUIDELINES.md 对该例外有完整表述。
  5. 禁止React.FCReact.FunctionComponent及泛化的React.*用法。应使用具名导入并直接标注 props 类型。这与 AGENTS.md 中"React.* → 具名导入"的迁移方向一致——仓库正在逐步清除历史遗留的React.*模式。

React 模式

  • React Compiler 已开启。AGENTS.md 指出,desktop-clientcomponent-library等包含 React 代码的应用包均启用了babel-plugin-react-compiler,编译器会自动记忆化组件体。因此,除非某个未编译的依赖确实需要稳定引用(stable identity),否则不要手动添加useCallback/useMemo/React.memo;多余的记忆化应标记为 Suggestion。
  • 使用路由器的<Link>,而非<a>标签。仓库的 eslint 插件提供了 no-anchor-tag.js 规则来强制这一点。
  • Hooks 必须来自项目自己的封装useNavigate等来自 src/hooks(例如其中的 useNavigate.ts,该目录下还有 100+ 个业务 hooks),而不是react-router-domuseDispatchuseSelectoruseStore来自src/redux,而不是react-redux
  • 避免在组件内部定义嵌套组件(会导致引用不稳定)。

导入规范

  • UUID 导入:必须使用import { v4 as uuidv4 } from 'uuid';,绝不允许默认导入uuid
  • 禁止直接导入颜色,一律使用主题。颜色必须经由主题系统(设计 token)消费,packages/component-library/src/themes/下的dark.csslight.cssmidnight.csspalette.css是主题变量的实际载体。
  • loot-core内禁止@actual-app/web/*导入。依赖方向必须保持单向:核心逻辑包不得反向引用 UI 包。
  • 导入顺序:React → 内置模块 → 外部依赖 → actual 内部包(loot-core@actual-app/components)→ 父级 → 同级 → index。各组之间保留空行。该规则由 lint 强制,违反时标记为 Suggestion。这与 AGENTS.md 中"绝对导入、平台特定导出经 package.json exports 解析"的整体约定配合。

国际化(i18n)

  • 所有用户可见字符串必须翻译。优先使用<Trans>组件而非t()函数。
  • 自定义 ESLint 规则 actual/no-untranslated-strings 能捕获大多数遗漏,但评审者仍应人工抽查明显漏网之鱼(例如<Button>Save</Button>这类硬编码文本)。
  • 配套规则 prefer-trans-over-t.js 在 lint 层强制"优先 Trans 组件";桌面端应用的实际文案则通过 desktop-client 的 i18n 体系 管理,修改文案后可用yarn generate:i18n重新生成语言文件(见 AGENTS.md)。

财务排版(Financial typography)

  • 独立的财务数字必须包裹在FinancialText中,或在无法包裹时直接应用styles.tnum等宽数字(tabular figures)对预算类 UI 的可读性至关重要——金额在列中对齐才不会"跳动"。
  • 仓库中的实际实现位于 FinancialText.tsx,评审时可将该组件作为标准答案对照;设计 token 与排版基准则可参考 component-library 的 tokens.ts。

测试规范

  • 最小化 Mock:单元测试与组件测试优先使用真实实现(real implementations)而非桩(stubs)。仅对外部网络、单元测试环境下的文件系统等确实不切实际的依赖进行 Mock。过度 Mock 会使测试脆弱且不可靠(见 CODE_REVIEW_GUIDELINES.md)。
  • Vitest 全局变量(describeitexpectbeforeEach)直接可用,无需显式导入。这与 AGENTS.md 的说明一致:Vitest 是单元测试运行器,测试文件采用.test.ts/.test.tsx/.spec.js命名。
  • E2E 测试位于 packages/desktop-client/e2e/,其中page-models/下的页面模型应复用而非重复编写;移动端测试使用.mobile.test.ts后缀,视觉回归快照存放在各*-snapshots/目录。

平台特定代码

  • 非平台代码禁止直接.api/.electron导入。平台解析在构建期通过loot-core的 package.jsonexports条件导出完成(node 与 browser 各有实现)。如果直接 import 另一平台的模块,会破坏这一构建期解耦。

Commit / PR 规则(来自 pr-and-commit-rules.md)

以下规则对 AI 生成的 PR 是强制性的,评审时应逐条核对并将遗漏标记为Important

  • 提交信息必须以[AI]前缀开头。
  • PR 标题必须以[AI]前缀开头("AI generated"标签会基于此前缀自动应用,无需单独验证)。
  • PR 模板不得填写(除非人类明确要求填写——此时必须使用中文填写)。模板本体位于 .github/PULL_REQUEST_TEMPLATE.md,默认情况下应原样保留空白与占位注释。
  • 禁止--no-verify--no-gpg-sign、强推 main 分支及任何破坏性 git 操作。

补充背景:根据 .github/agents/pr-and-commit-rules.md,Agent 还不得创建 GitHub issue,且所有发往 GitHub 的评论/评审/issue 内容必须以 🤖 前缀标记——这些虽非评审必须验证项,但属于同一规则体系。

需要额外重点审查的文件与路径

rubric 明确指出以下区域在评审中需要额外投入,并给出了默认严重级别:

  • packages/loot-core/src/server/migrations/——数据库模式迁移。必须幂等(idempotent);任何不幂等、或在没有回填(backfill)方案的情况下删除/重写数据的迁移,默认按Critical处理。该目录中既有.sql也有.js迁移(如1722717601000_reports_move_selected_categories.js),说明历史迁移包含程序化数据搬迁,评审时要特别关注这类"带逻辑的迁移"。
  • packages/loot-core/src/server/budget/——预算数学。这里的 off-by-one 或舍入错误会直接在用户的报表中造成金钱损失,必须逐行细读。
  • packages/desktop-client/src/components/budget/——主 UI 面。重渲染模式与 selector 使用在此处至关重要(叠加 React Compiler 的语义,记忆化取舍尤其需要谨慎)。
  • packages/sync-server/——服务端。CRDT / 同步变更需仔细检查排序与竞态条件;核心 CRDT 实现在 packages/crdt/src/crdt/。
  • [packages/desktop-client/e2e/ 下的*-snapshots/目录——VRT 快照。如果 PR 更新了这些快照,diff 本身就是评审对象:打开新的 PNG,确认视觉变化与 PR 声明的意图一致。

评审时可以跳过的内容

  • 生成文件:packages/component-library/src/icons/下的图标组件是自动生成的,不需要评审(AGENTS.md 同样强调"不要手动编辑")。
  • 构建产物:*/dist*/build*/lib-dist本就不应出现在 PR 中。
  • 翻译源文件:机器生成的翻译无需逐字评审。

评审输出的格式要求

rubric 的最后一段对"评审意见本身"提出了硬性要求——每条 finding 必须包含:

  1. path:line(或path:line-line范围),取自 diff hunk 而非估算;
  2. 1~2 句问题描述
  3. 具体的建议修改——替换代码或 unified-diff 片段,可直接粘贴。

不允许给出"考虑重构一下"这类模糊建议,要给出重构本身。在 .claude/skills/review-actual-pr/SKILL.md 的完整工作流中,这一要求被进一步强化:报告必须包含 Head SHA 与 Reviewed 时间戳(用于重跑时检测过期),且每档(Critical / Important / Suggestions)即使零发现也要显式声明"no Critical issues found",让用户确信该维度已被检查。

总结:把 rubric 变成日常审查习惯

这份 rubric 的价值在于它把三个来源文档(评审准则、Agent 开发指南、提交规则)压成了一张单页检查表。实际操作时,建议按以下顺序过一遍:先扫硬性拒绝项(设置膨胀、严格模式豁免、lint 抑制、凭据),再按"类型 → React → 导入 → i18n → 财务排版"逐层审代码风格,随后核对测试质量与平台隔离,最后确认提交/PR 元数据合规,并针对迁移、预算数学、预算 UI、sync-server、VRT 快照五个高风险区域做重点深挖。最终每条意见都带上path:line与可粘贴的修复代码——这正是 Actual Budget 仓库对高质量代码评审的完整定义。

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询