


为分层桌面应用添加功能,并测试每一种构建
当AI修改分为核心、桌面宿主和Web UI的桌面应用时使用。它把规则放在核心中,限制工具可以使用的命令和文件夹,按真实依赖拆分可选功能,并在每一种受支持的构建上测试后才算完成。
要使用这个AI规则
## 确定核心、桌面宿主和UI各自负责什么
更改代码前,定义要交付的平台、受支持的客户端、进程拓扑和信任边界。
- 将业务规则、持久化、执行和领域行为保留在权威核心中。
- 让桌面宿主负责生命周期、原生能力、安全桥接和打包。
- 让面向Web的UI负责呈现、导航和编排;不要在渲染器中重复实现核心规则。
- UI到核心的调用应通过一个经过身份验证的传输抽象层,不要采用临时的直接访问。
- 将实验性客户端视为独立的兼容性界面,并明确其传输方式、加密方式和发布状态。
- 维护一份架构图,列出每一层、该层拥有的状态、公开接口和禁止承担的职责。
## 按风险给命令分类,并让工具只在用户的文件夹内操作
集中管理配置,并对所有执行操作的工具应用统一的默认拒绝策略。
- 通过类型化配置模块读取环境值;功能代码不得直接访问进程环境变量或构建时环境变量。
- 将自主程度建模为明确的层级,并与工作区限制、受信任根目录和安装权限结合。
- 将命令分为读取、写入、网络、安装或破坏性操作;无法识别的命令按写入操作处理。
- 根据当前层级,把每个类别解析为允许、请求确认或阻止。系统位置和凭据位置始终必须阻止。
- 将用户操作根目录与应用内部状态分离。工具只能在操作根目录内执行,并且绝不能直接写入内部状态。
- 交互式变更的审批关卡默认保持启用,为未获答复的请求设置有效期,并在到期时拒绝操作。
- 将应用层路径验证与操作系统或容器沙箱结合使用;沙箱属于纵深防御,不能替代策略检查。
## 在核心中为每个领域建立独立模块
为每个领域提供专用模块,明确其所有权,并把文件保持为小型、可组合的单元。
### 使用规范的模块结构
- 模块门面应专注于导出,不得包含业务逻辑。
- 如果存在相应职责,应将可序列化的领域类型、持久化、操作、控制器模式、代理工具、事件订阅器和测试分别放在不同文件中。
- 领域拥有的工具应放在该领域中;共享工具基础设施只用于真正的横切行为。
- 传输模块仅处理身份验证、分派、日志、可观测性和协议问题。
通过由模式和处理器配对组成的注册表公开控制器。新增行为时,应添加领域控制器并在一个组合点注册,不要在整个传输代码中不断增加按命令名称分支的逻辑。
## 把运行时的开关与编译时功能分开处理
将它们建模为两个相互独立的维度:
- 服务集合选择要运行的后台服务和传输方式。
- 领域集合选择运行时可用的领域族。
- 编译时功能针对不同产品变体,将代码和依赖项排除在构建之外。
运行时筛选必须把已禁用领域的控制器、工具、存储和订阅器从运行时可用范围中移除。编译时关卡必须与这一行为组合,同时不得改变默认构建。将注册位置保持为权威来源,防止模式、分派、工具和启动服务彼此偏离。
## 根据真实依赖,选择关闭可选功能的方式
选择能够保留始终启用行为的最小关卡。
1. 如果每个外部引用都是注册位置,则使用叶级关卡;禁用后的能力接口应完全不存在,不要把它注册为必然失败的存根。
2. 只有在始终编译的调用方需要可调用符号时,才使用带有行为存根的门面。
3. 将不依赖外部项的共享类型拆分到始终编译的模块中,并且只为行为提供存根。绝不要在启用和禁用的构建之间重复定义类型。
4. 如果部分工具服务于始终启用的领域,则拆分目录;应控制真实的依赖边,而不是根据文件夹名称设置关卡。
5. 即使支撑运行的辅助函数位于可选领域之下,也要保留它们。不要用表面上返回成功的存根替代必要实现。
如果功能已从编译中排除但命令仍然可见,应返回明确的禁用构建错误,不要返回会误导用户的未知命令错误。对于编译时不参与运行但仍带有禁用组件名称的数据,应让解析过程容忍缺失的标识符,并测试这一契约。
绝不要仅凭编译成功就声称功能关卡移除了依赖项。应在禁用配置下执行反向依赖树查询,逐项证明所声称移除的依赖项确实不存在。
## 分别测试启用和禁用可选功能的构建
将测试视为架构的一部分,并覆盖行为、集成和打包。
- 将目标明确的单元测试放在相关代码附近,并优先测试可观察行为而不是实现细节。
- 使用共享模拟服务构建结果确定的集成测试;单元测试套件中禁止真实网络访问和依赖时间的休眠。
- 在实现前定义端到端场景,包括正常路径、失败、授权关卡和恢复。
- 从两个方向测试可选功能:证明启用时会注册,并证明禁用时不存在。
- 明确运行禁用构建的测试套件。只进行编译的冒烟通道不会编译测试代码,因此无法证明受关卡控制的测试仍然有效。
- 强制执行变更行覆盖率阈值;如果共享配置或基础契约发生变化,则改为运行完整测试套件。
- 如果构建系统允许,高成本的平台产物只构建一次,再从该产物分发执行各项测试。
## 添加不记录秘密和个人数据的诊断日志
新增或变更的流程需要在进入、退出、分支、外部调用、重试、超时、状态转换和错误处提供诊断信息。
- 使用稳定且便于grep搜索的领域前缀,以及请求ID、方法名称等关联字段。
- 普通日志应保持简洁,同时让debug和trace级别具备针对性调查所需的充分信息。
- 绝不要把秘密、生凭据、完整个人数据、用户编写的内容、实体标识符、文件名或原始错误消息记录到分析系统。
- 分析事件应通过一个能够感知用户同意状态的功能API,并使用稳定且不包含内容的事件名称。
- 如果变更新增了执行路径但缺少诊断,应将实现视为未完成。
## 翻译所有UI文字,生成的文档不要手动修改
使用集中式状态、传输和本地化机制,不要采用局部捷径。
- 优先使用指定的应用状态层,不要把状态分散到浏览器存储中。
- 所有核心调用都使用共享核心客户端,并让并行传输方式的行为保持一致。
- 通过受支持的运行时检测器和错误边界保护仅限原生环境的API。
- 所有可见字符串都必须经过本地化,为每个受支持的语言区域添加真实翻译,并完整保留插值占位符。
- 完成前运行本地化语法、英文残留和覆盖率检查。
- 绝不要手动编辑生成的文档块。更新其源标记后重新生成,并让漂移检查对陈旧结果报错。
- 避免向嵌入式第三方视图添加脚本注入;新行为应通过原生处理器、协议工具或受控IPC钩子实现。
## 从核心到UI逐层实现功能,每层测试后再继续
遵循固定的纵向流程:
1. 根据现有领域契约、命名约定、安全策略和端到端场景定义行为。
2. 实现权威的领域逻辑并编写单元测试。
3. 通过集成测试证明控制器或RPC边界。
4. 通过共享客户端在UI中呈现行为,同时把规则保留在核心中。
5. 添加UI单元测试和平台端到端覆盖。
6. 添加、移除或重命名功能时,更新面向用户的功能元数据和架构文档。
当前层尚未经过测试时,不要进入下一层。模块应保持小型且职责单一,并让文档与其管理的行为一起更新。
## 不跳过必需的检查,看到结果后再宣布完成
在专用分支上进行更改,以仓库指定的集成分支为目标,并让生产发布始终关联到声明的发布来源。
- 从仓库根目录使用规范的包管理器、固定版本的工具链、格式化工具、linter、类型检查器和测试运行器。
- 让分别构建的原生组件之间保持等效的构建配置设置同步。
- 绝不要为了掩盖失败而绕过必需的钩子或检查。如果钩子生成了文件,应检查并纳入结果,然后重新运行该钩子。
- 修复由当前变更引起的失败;对于与当前变更无关的既有阻碍,应记录下来,不要悄悄削弱保护措施。
- 审查最终差异,确认实现、测试、模式、生成产物、本地化和文档保持一致。
- 如果没有直接获得与每个已变更层以及每种受支持构建配置相关的检查结果,不得宣布完成。
