Files
soft_quay/docs/05-coding-rules.md

8.4 KiB

编码规则(Coding Rules)

每次写代码前先读完本文件。这是让 AI 不跑偏、代码质量稳定的硬约束。 与技术细节冲突时,以 技术栈 / 架构设计 的事实为准;与"该不该做"冲突时,以 需求 为准;协议字段以 api.md 为准。

0. 黄金法则

  1. 不臆造:数据字段、文件、接口、依赖,不确定就查证或询问。
  2. 守范围:只做当前任务要求的事,不顺手加后续功能。
  3. 照架构:使用既定技术栈和模块边界,不擅自引入新框架。
  4. 小步改:一次只解决一个问题,不夹带无关重构。
  5. 可验证:改完必须能构建、能测试、对得上验收标准。

1. 动手前

  • 按链路确认:vision → requirements → tech-stack → architecture → tasks。
  • 找到本任务对应的验收标准,写之前就知道"怎么算做对"。
  • 先找现有函数、组件、工具和测试,复用优先。
  • 如果需求含糊,或改动会偏离原则 / 架构,先问。

2. 分层与工具链纪律(本项目最容易翻车的地方)

  • core/ 的 domain 与 application 禁止 import Gio、SQLite、Windows API;下载、存储、时间、进程、系统信息一律接口注入。
  • 依赖方向只允许 app-modern/app-win7 → core;任何反向 import 都是返工。
  • core/ 与 app-win7/ 只使用 Go 1.20 可编译的语法与依赖;新增依赖前检查其 go.mod 的 go 指令。泛型可用(1.18+),但 1.21+ 的标准库函数(如 slices、maps、min/max 内建)不得进入这两个模块。
  • Gio 代码只出现在 ui/gio/;Windows 调用只出现在 platform/windows/,且必须有非 Windows stub,保证 go test ./... 在 Linux CI 可跑。
  • modern/Win7 的 Gio shell 都按同 package 镜像职责维护:shell.go 只放 AppShell 状态/生命周期和根编排,header/navigation、catalog/list、detail、theme/style 分别进入 shell_header.go、shell_catalog.go、shell_detail.go、shell_style.go;版本特有声明留在对应文件,不得为减少重复而跨 workspace 共享不兼容 Gio 代码。
  • 仅 Win10+ 存在的 Windows API 必须 LoadLibrary 动态加载、失败降级,不得成为 EXE 导入表强依赖。
  • Gio Layout 每帧禁止 IO(磁盘/网络/哈希/图片解码);后台任务只发布 application.Event,不得直接调用 ApplyIcon 或改控件/map。后台 event pump 只入有界 relay 并调用 Window.Invalidate;只有 Frame/UI goroutine可以 drain ApplyEvent。relay 满队列不得静默丢事件,关闭/取消必须解除背压等待。
  • CatalogListModel.VisibleItems() 返回当前只读 snapshot generation:refilter 只在状态变化时构造新 backing array 后发布,同 generation 的每帧读取不得复制;调用方不得修改 slice/item/Tags。旧 generation 在后续 model 变化后保持稳定,但 model 仍是单 owner、非并发安全对象。
  • 图标 Fetcher 必须返回与 context 绑定的流,由 IconCache 在分配完整响应前执行声明长度拒绝与 maxBytes+1 有界读取;不得恢复为先读任意大 []byte 再校验。缓存并发只允许按 key 去重,不得用横跨磁盘/网络的全局锁换取去重。
  • 图标缓存 entry 是 symlink/reparse point 或非普通文件时必须 fail closed:不读取/跟随、不自动 delete/rename/quarantine、不回退 Fetcher。上层只持有已验证的 icon event identity + 稳定 failure code;UI locator 只能由规范 digest + DPI 生成,不得加入绝对 root、raw error、URL/query、token 或 link target。人工处置只引用 故障排查。

3. 安全纪律(违反即安全事故)

  • 任何下载内容未通过 SHA-256 + 签名验证,不得解压执行;清单验签失败拒绝,不回退到未验证内容。
  • ZIP 与软件包路径必须使用 core/internal/safepath 的共享 Windows 安全相对路径策略,拒绝绝对路径、..//dot-space 归一化穿越、首尾 ASCII 空格、尾随句点、DOS 设备名、Windows 禁止字符、符号链接逃逸和 entrypoint 指向 payload 外;native 输出路径还必须验证仍在 destination 内。Catalog/storage/app.json/files.json 不得各自复制一套路径规则。
  • 任意 zip.Reader 构造前,必须以同一普通文件句柄核对已验签 Catalog 的 exact package size 与完成下载实际长度,并有界预扫描 EOCD/ZIP64:原始包、中央目录字节数和声明条目数超过硬上限,跨盘/截断/边界不一致元数据一律拒绝;不得先扫描路径后按该路径重新打开,不得仅依赖 len(archive.File)。
  • Catalog 签名域只移除顶层 signature:JSON 解析必须拒绝非法 surrogate、-0 和非整数,大整数保持原始十进制 token;signature 必须是唯一的标准 padded Base64 文本,CR/LF/空白或 padding 变体一律拒绝。跨实现测试只消费 testdata/catalog/canonical-vectors.json 的静态预期 bytes/公钥/签名,不得用当前 canonicalizer 或测试私钥自举“正确”向量。
  • ZIP 解压必须保留文件数、展开体积和压缩比硬上限。
  • 安装/更新只走 staging → current → backup 原子流程;任何写 current/ 的捷径都不允许。
  • 安装 payload 在 CRC/长度检查后必须 Sync 再 Close;staging 目录按子→根及其父目录建立栅栏。journal 临时文件内容、journal/backup rename 或删除、受控目录 rename 或删除后必须同步 app root,成功 phase 不得越过失败栅栏。Windows 目录栅栏使用 Win7 可用的 FILE_FLAG_BACKUP_SEMANTICS + FlushFileBuffers,不支持或失败必须 fail closed;单元测试不等同于物理断电证明。
  • 程序更新不得触碰 data/ 与 licenses/。
  • 不强杀用户进程;更新前等待正常退出,超时取消。
  • 私钥、真实注册码、真实机器标识不进代码、测试数据和文档;testdata/ 只放假数据和专用测试密钥对。
  • 日志不记录注册码、令牌、原始硬件标识和敏感查询参数。

4. 事实来源纪律

  • 协议字段只信 docs/api.md 与 schemas/;架构边界只信 docs/04-architecture.md;当前现实只信 docs/current-state.md 和代码。
  • 不从旧盒子的逆向笔记、备份或草稿推断当前实现;那些是设计输入,不是本仓库事实。
  • 不虚构字段、事件、错误码、配置项。
  • 数据结构变化必须同步更新 04-architecture.md、api.md、schemas/ 和相关任务。

5. 范围纪律

  • MVP 只做 02-requirements.md 中列为 P0 的功能;V1.1/V2 功能只记录,不实现。
  • 需求明确排除的非目标(社区、支付、云同步、插件、驱动)不得实现。
  • 不为"将来可能用到"提前抽象;SDK 拆分(softbox-sdk)是后续独立仓库的事,本仓库不预建。

6. 代码规范

  • 标识符使用英文;错误码用稳定英文枚举,UI 负责中文文案。
  • 错误必须处理,不吞错;每个失败路径要能落到用户可见的状态或日志。
  • 注释解释"为什么",不复述"做了什么"。
  • 使用 gofmt(必须)与 go vet(必须);不手工制造风格分裂。
  • 状态写入一律临时文件 + 原子替换。

7. 测试与验证

完成前至少检查:

  • cd core && go vet ./... && go test -count=1 ./... 通过(Linux 无头环境)。
  • 现代版可交叉编译:cd app-modern && GOOS=windows GOARCH=amd64 go build ./cmd/softbox。
  • Win7 版可用 Go 1.20 编译:cd app-win7 && GOTOOLCHAIN=go1.20.14 GOOS=windows GOARCH=amd64 go build ./cmd/softbox。
  • 状态机改动覆盖:成功、失败、取消、断电恢复、回滚。
  • UI 事件改动使用 fake submitter + ApplyEvent 测试。
  • 对得上需求验收标准;没有夹带无关改动。
  • 涉及文档事实变化时,文档已同步。
  • 已在当前任务文件(docs/tasks/T-<编号>.md)的 ## 执行记录 记录跑过的命令和结果作为证据,不靠"代码已写"判定完成。
  • 回复里如实说明跑了什么命令、结果如何。

8. 绝不

  • 绝不把密钥、token、密码、私钥写进代码或文档样例的真实值里。
  • 绝不为了让测试通过而删除断言、降低验收标准。
  • 绝不擅自删除用户已有文件或重置工作区。
  • 绝不在没说明的情况下改公共协议(manifest/app.json/许可证)、迁移数据结构或升级 Gio/Go 工具链。
  • 绝不绕过签名验证、哈希校验或回滚机制"先跑起来再说"。

9. 拿不准就问

问题要具体,说明你卡在哪里、有哪些选项、倾向哪个选项以及原因。