


为多语言基础设施即代码(IaC)库添加功能,且不破坏现有用户
在修改会为其他语言生成绑定的强类型 IaC 库时使用。把功能放进合适的层,避开绑定无法表达的写法,用功能开关保护行为变更,保持权限精简,并补上文档和测试。
要使用这个AI规则
## 保持现有用户代码可用,并开放平台的全部能力
工作应服务于库的用户、维护者和更广泛的ecosystem,而不只是提出变更请求的人。
- 保持向后兼容;现有用户代码和已合成基础设施必须默认继续正常工作。
- 遵循最小惊讶原则:API应符合用户的mental model。
- 在提供合理且可覆盖的默认值时,完整呈现平台能力面。
- 保留访问生成低层resource的逃生通道,确保高层功能缺失时不会阻碍用户。
- 规则有歧义时,不要静默猜测;应在变更说明中记录决定及其理由。
如果请求的工作超出此类库的代码编写或审查范围,应停止并指出范围不匹配。不要把专用规则套用到无关工作。
## 大多数功能放在手写的 Level 2 API 中
保持3个相互独立的抽象层级:
- Level 1由围绕provider resource schema生成的wrapper构成。绝不能手工编辑。
- Level 2由手写的、基于意图并带有实用默认值的API构成。大多数功能工作属于这一层。
- Level 3由多resource pattern构成。只有代码库明确接受该抽象层级时,才添加新pattern。
Level 2应围绕用户意图设计,而不是照搬provider raw schema。对普通caller隐藏生成schema细节、内部连接、permission action和physical identifier,同时仍提供完整的provider能力集。
用interface表示resource契约,使第三方实现能够像first-party实现一样工作。优先选择足以满足parameter要求的最小interface:先用仅含identifier的reference;只有需要便利操作时才用完整behavioral interface;concrete class只用于特殊情况。
## 为每个新功能选定 mixin、facade 或 trait
根据功能影响的对象决定其归属:
1. 没有logic的低层property直接passthrough属于轻量property mixin。
2. 改变resource自身property或lifecycle的logic属于独立mixin。
3. 服务于外部consumer的behavior,例如grant、metric或event,属于facade。
4. 供其他construct查询的cross-cutting capability属于trait。
5. 其他情况使用Level 2 construct上的method。
不要混淆这些角色。mixin面向内部,facade面向外部,trait声明与service无关的capability。
object可能跨package或language边界,因此应使用基于稳定runtime marker的static type guard,而不是`instanceof`。保留abstract base用于实现,但不要接受它作为public parameter。
## 统一公开命名,避开其他语言无法使用的类型
统一public name:class和enum用PascalCase,property和method用camelCase,behavioral interface加`I`前缀,data structure不加前缀,enum member用UPPER_SNAKE_CASE。保留正式platform术语;无法使用strong type时,应写明单位。
property object必须readonly、flat,并以construct命名。每个optional property都需要记录default,而且应说明行为,不能只说它是undefined。相比raw number或identifier string,优先使用strong duration、size和resource-reference type。
不要通过高层property暴露生成的低层type。避免union type以及binding generator不支持的其他结构;改用enum-like class、独立property object或factory method。
public type的file location属于外部契约的一部分。不要随意移动。避免mapped type、conditional type、overloaded function、language专用namespace,以及无法在target language间一致表示的export object constant。
不要使用返回`this`的fluent method;它们难以跨language转换,并会把mutation隐藏在chain之后。
## 写清楚的验证错误,并先检查未解析的值
存在construct context时使用scoped validation error,否则使用unscoped validation error。error code必须是compile-time literal;原因和解决方法相同时可复用。message应指出错误value、期望value以及必须采取的纠正措施。
优先自动纠正安全配置,而不是抛出异常。API misuse应立即失败;累积state使用构建后validation;environmental problem通过synthesis diagnostic报告。不要catch无法恢复的construction error;真正可恢复的结果应通过return value表示。
未解析值可能表示string、number、list或resource attribute。在验证length、range、iteration或truthiness前,先检查值是否未解析。tokenized list可能暴露marker length,tokenized scalar value可能表现为false。
optional value使用明确的undefined check,数值使用token-aware conversion;physical name的hash绝不能包含未解析resource attribute。
对于构建后累积的state,使用能捕获mutation call site的deferred-value box。使用list、value、map或set box;通过token adapter传给低层property;使用box operation进行更改;绝不能在lazy callback或box callback内修改construct tree。
## 保持权限精简,用功能开关保护行为变更
相比service级wildcard,优先使用具体permission action;将resource identifier限制到实际可行的最窄prefix;按resource scope组合相关action。使用库提供的grant helper,不要手工组装policy statement。
存在confused-deputy risk时,trust policy必须包含source-account和source-resource condition。encryption grant应限制为通过预期service使用。只要配置会造成public access,就必须在synthesis时发出警告。
现有API的可观察行为发生变化时,使用feature flag保护兼容性:
- 旧行为错误时,使用bug-fix flag。
- 旧行为仍有效但不再推荐时,使用API-default flag,并记录与旧行为的兼容方式。
- 未配置的application必须保留以前的行为。
- security flag可以收窄trust或permission,但绝不能静默扩大;更广的access必须通过明确API option启用。
不要仅因为replacement construct存在就使用flag。应将旧construct标记为deprecated,并通过标准annotation mechanism警告行为变更。
## 先构建受影响的包,并更新集成测试快照
运行test、lint、integration snapshot或documentation example check前,先构建受影响package。迭代期间使用范围最小的相关module或test target;handoff前回到代码库要求的package gate和compatibility gate。
明确哪些file是生成内容、stable和experimental integration test位于何处,以及agent design reference在哪些情况下优先于更长的人工guide。绝不能直接编辑生成的Level 1 source。
使用代码库本地package command和working directory,不要自行设计其他build path。只有自动lint fix产生的差异仍处于请求范围内时,才可运行。
修改logical identifier时,应更新所有受影响的integration snapshot,包括跨package snapshot。local unit test通过并不能证明生成binding、documentation example或integration template仍可compile。
## 为每个新公开 API 写文档,并保持示例可编译
记录每个新的public class、method、property和interface。先写简洁summary,然后空一行,再写解释body。适用时包含parameter、return、default、related-reference、example和generated-attribute tag。
attribute name应以resource type开头,不要使用含义模糊的名称。如果有权威platform description可用,应复制其内容;但override从base interface继承文档时,不要重复文档。
每个module guide都应说明maturity,在靠近开头的位置放置简单example,并为主要use case提供example。所有普通typed example都必须可compile;只有fixture确实无法适用时,才使用代码库指定的明确opt-out marker。
每项feature change都必须更新相关module guide。仅有documentation text不能代替API test;实现了API也不能成为保留陈旧example的理由。
## 在单元测试中断言关键属性,并补充集成测试
在unit test中,应assert真正重要的具体生成property,而不是比较整个template或接受任意value。根据意图使用partial-object、exact-object、array、regular-expression和absence matcher。
使用data-driven test覆盖boundary value。error test必须assert确切diagnostic,并在test name中指出failure behavior。utility function应与construct分开测试,并保留deprecated API的测试。
新的optional property需要backward-compatibility test,证明default behavior没有变化。grant helper必须使用已创建和import的role、user、service principal进行测试。
integration test应使用代码库指定的integration-test construct,不要额外调用synthesis。所有新test都推荐使用assertion,custom resource则必须使用。除非open access正是被测试行为,否则避免open network peer。
为新的生成resource type或property、cross-service behavior、新version和custom resource增加integration coverage。按feature area分开测试,并保持snapshot extension和location一致。
## 写关联 issue 的变更标题,绝不更改稳定的标识符
适用时使用包含受影响module的conventional change title。feature和fix change必须引用issue。feature change需要unit test、integration snapshot和module documentation更新。
breaking change只能出现在明确标为experimental的package中,并且必须在变更说明中醒目声明。每项change只包含一个concern;cosmetic edit应单独提交。
绝不能添加推测性abstraction、改变stable construct identifier、留下commented-out code或dead code,也不能通过silence lint rule来掩盖违规。identifier变更可能替换已部署resource并造成data loss。
为现有API添加validation前,应判断以前接受的input是否能够成功deploy。如果能够,应通过compatibility flag控制新的rejection。如果它过去总是在deployment时失败,应优先让synthesis提前失败,并记录更严格validation合理的原因。
handoff前检查差异,查找生成file编辑、public type移动、binding不兼容syntax、陈旧snapshot、缺少documentation、compatibility regression和无关变更。
