- 始终使用英语进行沟通和工作。
- 在开始开发之前,检查项目根目录是否存在
PRD.md。如果存在,在整个开发过程中阅读并遵循其中定义的需求。 - 重要:始终优先使用 Rust 原生实现。 避免不必要的外部依赖,尽可能利用 Rust 标准库。只有在有明确、合理的需求时才使用第三方 crate。
- 重要:遵循测试驱动开发(TDD)。 详细规则请参见下面的**测试(TDD)**部分。
- 重要:在开始任何任务之前,阅读并遵循
METHODOLOGY.md。 - 在编辑
CLAUDE.md时,使用最少的词汇和句子来传达 100% 的含义。 - 完成每个计划中的任务后,运行测试并提交,然后才能继续下一个任务。如果更改对运行时行为没有影响(例如文档、注释、CI 配置),则跳过测试。 对运行时配置文件(YAML、JSON 等会被代码读取的文件)的更改仍然必须触发测试。
- 在任何代码更改(功能添加、错误修复、重构、PR 合并)之后,检查
README.md是否需要更新。 如果项目描述、用法、设置、架构或 API 发生更改,请使用清晰简洁的语言更新README.md。保持最小化------只记录用户需要知道的内容。
测试 (TDD)
- 先编写测试。遵循红-绿-重构:(1) 失败的测试,(2) 最少的代码使其通过,(3) 重构。
- 在测试中使用真实世界的场景和真实数据。优先使用实际用例,而不是琐碎/刻意的例子。
- 切勿过度拟合测试。 实现必须解决通用问题,而不仅仅是特定的测试用例。不允许硬编码返回值、不允许输入匹配条件、不允许只处理测试值的逻辑。使用三角测量------当伪造/硬编码的实现通过时,添加不同输入的测试以强制泛化。
- 测试行为,而不是实现。断言可观察的结果,而不是内部细节------测试必须在重构后仍然有效。
- 每个新功能或错误修复都必须有相应的测试。
- 优化测试执行速度。 并行运行独立的测试。使用
cargo test的默认并行性。保持每个测试隔离------无共享可变状态------以便并行执行是安全的。 - 对于 I/O 密集型测试(网络、文件),优先使用异步或使用 mock 来避免阻塞。对于 CPU 密集型测试,使用多线程并行。
- 如果完整测试套件超过 30 秒,进行调查:将较慢的集成测试与快速单元测试分离,先运行单元测试以获得快速反馈。
- 无运行时影响时跳过测试。 在 CI/CD 中,使用路径过滤器,仅在修改源代码、测试文件或运行时配置文件时触发测试。非运行时更改(文档、README、
.md、CI 流水线配置)不应触发测试运行。
日志记录
- 在关键决策点、状态转换和外部调用处添加结构化日志------而不是每一行。仅凭日志应能揭示执行流程和根本原因。
- 包含上下文:请求/关联 ID、输入参数、耗时和结果(成功/失败及原因)。
- 使用适当的日志级别:
error!用于需要采取行动的故障,warn!用于可恢复的问题,info!用于业务事件,debug!/trace!用于开发诊断。 - 使用
tracingcrate 进行结构化、异步安全的日志记录。优先使用tracing::instrument进行自动 span 创建。 - 切勿记录敏感数据(凭证、令牌、PII)。应对其进行屏蔽或省略。
- 避免在热路径中过度记录------日志记录不得明显影响性能或增加延迟。
命名
- 名称必须是自描述的------无需阅读周围代码即可理解。避免使用晦涩的缩写(
proc、mgr、tmp)。 - 优先考虑清晰度而非简洁性,但不要过度冗长。
user_email>e,calculate_shipping_cost>calc。 - 布尔值应读作是/否问题:
is_valid、has_permission、should_retry。 - 函数/方法应描述操作和目标:
parse_config、send_notification、validate_input。
类型
- 优先使用显式类型注解而非类型推断。始终为函数签名(参数和返回类型)添加注解。
- 当变量类型从赋值中不明显时,为变量添加注解。
- 使用 newtype 来强制执行领域语义(例如,使用
struct Emu(f64)而不是裸f64)。
注释
- 解释原因,而不是内容。代码已经显示了它做了什么------注释应捕捉意图、约束和非显而易见的决策。
- 注释业务规则、变通方法和"为什么采用这种方法而不是显而易见的方法"------这些是从代码本身无法推断出的背景信息。
- 使用
TODO(reason)或FIXME(reason)标记已知限制------始终包含原因,而不仅仅是内容。 - 当代码更改时删除注释------过时的注释比没有注释更糟糕。
参考项目
- 当面临设计决策或实现挑战时,首先检查是否存在
references/INDEX.md并找到相关的参考项目。 - 如果
references/中不存在相关项目,请在网上搜索解决类似问题的维护良好的开源项目。搜索所有语言------架构模式可以跨语言迁移。 - 当发现新的有用项目且
references/存在时,将其添加到references/INDEX.md并创建相应的详细信息文件。将详细信息文件保持在 50 行以内。 - 在应用参考项目的模式时,引用是哪个参考项目启发了您的方法。
保密性
- 切勿在提交消息、PR 标题/描述、问题评论或任何公开文本中提及
tests/classified_fixtures/的内容(文件名、路径、公司名称、个人姓名、文档标题)。 - 使用通用引用代替:"机密测试夹具"、"内部测试文档"、"基准真值 PDF"等。
Git 配置
- 所有提交必须使用本地 git 配置
user.name和user.email。在提交前使用git config user.name和git config user.email进行验证。 - 所有提交必须包含
Signed-off-by行(始终使用git commit -s)。Signed-off-by名称必须与提交作者匹配。
分支与 PR 工作流
- 所有更改都通过拉取请求进行。不允许直接提交到
main。 - 分支命名:
<类型>/<简短描述>(例如,feat/add-parser、fix/table-bug)。 - 一个分支 = 一个聚焦的工作单元。
- 对所有分支工作使用 git worktrees。 不要在主仓库中使用
git checkout/git switch。- 创建:
git worktree add ../<仓库名>-<分支名> -b <类型>/<简短描述> - 在 worktree 内工作和推送。
- 不要在任务完成后立即删除 worktree------仅在新工作开始或用户确认后删除。
- 创建:
PR 合并流程
按顺序执行所有步骤:
- 如果 PR 描述为空或不清晰,通过
gh pr edit重写。包括:更改了什么、为什么更改、主要更改和相关背景。 - 交叉引用相关 issue(
gh issue list)。使用 "Related: #N"------除非另有指示,否则避免使用自动关闭关键字。 - 检查冲突。如果
main有进展,根据需要变基/合并。 - 等待 CI 通过:
gh pr checks <编号> --watch。如果测试失败则中止。 - 通过
gh pr diff <编号>进行最终代码审查------检查调试语句、硬编码路径、凭据、未使用的导入。 - 合并:
gh pr merge <编号> --merge。切勿使用--delete-branch(worktree 依赖于该分支)。 - 返回主仓库,执行
git pull同步。 - 删除 worktree:
git worktree remove ../<仓库名>-<分支名> - 删除本地分支:
git branch -d <分支名> - 删除远程分支:
git push origin --delete <分支名>
MSRV 策略 --- 6 个月滚动最低版本
本项目遵循 6 个月滚动 MSRV 策略 (与 tokio 和其他主要 crate 保持一致):
Cargo.toml中的rust-version必须目标指向至少 6 个月前发布的 Rust 稳定版- Rust 稳定版每 6 周发布一次------具体日期请查阅 releases.rs
- 当较新的 Rust 版本超过 6 个月阈值时,允许但不要求更新 MSRV------仅当较新的语言特性或依赖项要求时才升级
- 下限: MSRV 绝不能低于
Cargo.toml中edition要求的最低版本(edition 2024 = Rust 1.85)
在任何 MSRV 变更之前:
- 验证未使用目标版本以上的专属语言特性或 API
- 确认所有依赖项都能在目标版本上编译(使用目标工具链执行
cargo check,或检查依赖项 MSRV 元数据) - 更新 CI 矩阵以包含新的 MSRV 版本
视觉对比工作流
在将 PDF 输出与基准真值(机密测试夹具)进行比较时:
- 运行
cargo test -p office2pdf --test artifact_generator -- --ignored --nocapture生成产物。 - 读取
tests/classified_fixtures/_work/report.json------包含每个文件的页数、文本长度和 PNG 路径。 - 识别最差文件:页数不匹配、文本长度差异大、转换错误。
- 对于最差文件,使用读取工具 查看
tests/classified_fixtures/_work/<work_dir>/中的 PNG 图片:output-*.png--- office2pdf 输出渲染的页面gt-*.png--- 基准真值 PDF 渲染的页面output.txt/gt.txt--- 提取的文本
- 直观地比较输出和 GT 的 PNG 图片,以识别特定的渲染差异(布局、字体、表格、图片、边距、分页等)。
- 对于 macOS 上用户提供的 DOCX/XLSX/PPTX 文件,如果该文件类型有可用的 Word/Excel/PowerPoint,则首先从原生 Microsoft 应用程序导出 PDF,然后再进行推测比较。
- 通过 TDD 修复解析器/代码生成器中的根本原因。优先考虑能改进多个文件的高杠杆修复。
发布流程
当要求"发布"时,始终执行 GitHub Release 和 crates.io 发布:
- 版本升级 --- 创建一个 PR(
chore/publish-<版本号>),该 PR 在crates/office2pdf/Cargo.toml和crates/office2pdf-cli/Cargo.toml中升级version,并更新 CLI 的office2pdf依赖版本。通过标准 PR 工作流合并。 - GitHub Release ---
gh release create v<版本号>,包含更新日志和贡献者部分。- 使用
git log <上一标签>..HEAD --format='%an' | sort -u查找贡献者。列出每个贡献者并附上其 GitHub 个人资料链接。
- 使用
- crates.io 发布 --- 先发布库,再发布 CLI:
cargo publish -p office2pdfcargo publish -p office2pdf-cli
- 标签对齐 --- 确保 GitHub 发布标签(
v<版本号>)与 Cargo.toml 中的版本一致。