


修改公开发布的服务器软件包,不破坏扩展它的代码
在修改公开发布、并被其他代码通过钩子扩展的服务器软件包时使用。不把秘密放进发布内容,保持回调、钩子和中间件顺序可用,用新增迁移代替修改旧迁移,并运行软件包实际提供的测试和 lint。
要使用这个AI规则
## 确认公开发布的内容,不放入秘密信息
编辑前,识别软件包的发布目标、许可证、模块系统、语言、运行时角色和同步路径。即使在私有工作区中进行开发,也要将公开同步软件包内的每个文件视为公开发布内容。
- 绝不要把秘密信息、受许可证限制的行为或仅限内部使用的测试固件放入公开软件包。
- 服务器专用软件包应保持无头模式;不要引入浏览器或 DOM 依赖项。
- 遵循该软件包实际使用的模块和语言约定,不要照搬相邻软件包的模式。
- 记录工作区中的直接依赖方,并假定还存在其他外部软件包使用方。
即使工作区内只有 1 个可见的依赖方,公开分发也会扩大影响范围。
## 保持旧的回调形式和深层导入路径可用
不要在未作说明的情况下把回调现代化为 Promise 或 async 函数。在新旧方式混合的代码中,即使附近的调用点采用同步或 Promise 方式,扩展钩子也可能依赖回调的具体形式。
更改调用方式前:
1. 列出该扩展点的每一种实现。
2. 比较参数顺序、返回行为、回调时机和错误语义。
3. 与所改文件的风格保持一致。
4. 为每一种受支持的调用形式添加或更新测试。
在搜索下游仓库是否存在深层导入之前,不要重命名或移动看似内部使用的实用工具、中间件或模型文件。从源代码路径导入是一种隐式公开 API,可能在没有编译器警告的情况下发生破坏。
## 准确保持中间件顺序和钩子名称
明确保留中间件之间的依赖关系。当授权逻辑读取已填充的用户上下文时,身份验证或令牌解析必须先于权限检查执行。应将顺序变更视为契约变更,而不是格式清理。
对于新中间件,沿用软件包中已确立的工厂形式,例如由感知软件包的工厂函数返回请求处理器,并将其注册到中央链中的预定位置。
使用现有的变更钩子机制作为扩展接口。添加调用点之前,搜索当前所有钩子名称和实现。确认准确的名称、输入值、回调或返回形式以及默认行为;拼错钩子名称可能会在没有明显提示的情况下返回默认值。
在下游实现者能够找到的位置记录每一个新扩展点。
## 不修改已发布的迁移,改为新增迁移
遵循已确立的基础抽象,不要另行发明平行模式。新数据模型应使用共享模型插件或基础结构。新的顶级 REST 资源应扩展公共资源基类,并通过中央入口点注册路由。
将已发布的数据库迁移视为不可更改且单向的:
- 发布后绝不要编辑现有迁移;
- 每次后续修正都要添加一个新的带编号迁移;
- 使每个迁移都具备幂等性;
- 考虑中断和启动过程反复执行的情况;
- 分别在全新数据库和已经迁移的数据库上验证行为。
当下游软件包通过钩子注入模型字段或行为时,应先审查这些注入点,再更改架构、默认值、序列化或水合过程。
## 找出受影响的其他软件包,并测试两侧
实现前,先把变更映射到其使用方。更改身份验证中间件、权限处理、会话边界、共享实用工具、加密辅助程序、模型钩子或扩展点签名时,应与下游调用方协调。
将通过深层路径导入的辅助程序视为公开 API。将令牌与会话的所有权归属视为架构边界。当值以引用形式存储并在读取时水合时,应在更改其表示形式前,同时审查写入方和引用解算处理器。
对于每一项横跨多个区域的编辑:
1. 阅读相关的架构、依赖关系和已知注意事项。
2. 搜索下游实现和调用点。
3. 明确说明必须保持成立的契约。
4. 测试边界两侧。
5. 记录任何有意的契约变更及其迁移路径。
## 测试跨越虚拟机沙箱边界的值
更改虚拟机捆绑包、兼容层、评估器实例、资源限制或错误语义时,必须完整审查客户端与服务器之间的契约。保持宿主端和沙箱端兼容层一致,重新构建捆绑包,并验证值能够完好地跨越运行时边界。
不要假定活动数据库对象经过隔离运行时序列化后仍保留对象身份或原型。应双向测试标识符、引用、日期、缓冲区、错误和水合后的值。
注意模块加载时初始化的兼容层可能导致进程范围的宿主状态发生变化。即使软件包原本应保持无头模式,模拟浏览器上下文也可能创建全局状态。
将未纳入覆盖率的捆绑代码视为已知测试缺口,并添加有针对性的执行检查,不要假定常规覆盖率足以证明其正确性。
## 启动时检测数据库功能,并准备备用路径
在启动时探测能力,以支持多种数据库实现。高级排序规则、查找管线、复合嵌套路径索引以及其他超出基线的功能,都应根据探测结果设置门控,并提供经过测试的备用方案。
当运行时提供能力映射时,绝不要根据产品名称或版本字符串推断兼容性。反复被回退的变更证明,探测和备用方案路径是契约的一部分。
当公开软件包的行为依赖功能标志,而该软件包无法导入私有注册表时,应使用标志的准确键字符串调用已确立的扩展钩子。对照注册表验证该键,并测试启用和禁用两条路径。不要在公开软件包中嵌入私有注册表逻辑。
## 运行软件包实际拥有的测试、lint 和构建
根据软件包实际提供的脚本定义“通过”。对于仅使用 JavaScript 的软件包,这可能意味着运行完整的测试套件和 linter,而不是臆造并不存在的类型检查步骤。当变更影响捆绑后的运行时输出时,应执行 build。
如果测试发现不是自动完成的,应将每个新测试文件注册到测试套件的中央导入器中;未注册的测试文件无法提供任何保护。可以使用受支持的测试名称筛选器缩小调查范围,但在完成前必须运行完整的必需测试套件。
谨慎使用会自动修正问题的 lint 命令,并审查其 diff。确认测试、lint 和相关捆绑包 build 均通过,同时保留能够揭示运行时或兼容性问题的警告。
## 宣布完成前确认全部影响范围
从受影响的契约开始,而不是从最近的文件开始。搜索已知注意事项和下游依赖关系,做出保持兼容性的最小变更,并在报告完成前验证公开发布安全性。
最终审查必须确认:
- 没有秘密信息、受限制内容或仅限内部使用的材料进入公开软件包;
- 回调、钩子、深层导入和中间件顺序契约仍然成立;
- 迁移采用增量添加方式并具备幂等性;
- 在受到影响时,模型、引用、虚拟机和数据库能力边界已经过测试;
- 新测试已注册,且软件包真正的质量门均已通过;
- 已在必要位置更新跨软件包调用方和文档;
- 破坏兼容性的变更或主要版本变更已与所有发布目标协调。
不要仅仅因为工作区依赖项数量很少,就认定某项变更是孤立的;公开使用方始终是风险模型的一部分。
