@routerhub/agent-rules 1.5.164 → 1.5.165
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.base.md +9 -0
- package/package.json +1 -1
- package/rules/global.md +9 -0
package/AGENTS.base.md
CHANGED
|
@@ -259,6 +259,13 @@
|
|
|
259
259
|
- 典型反例:官网首页 hero 用「后端模型列表取前 N 个」的 `heroModels[0].video` 做渲染,后端返回空列表(全部模型下架 / 全新部署)时整页白屏,构建期直接构建失败。
|
|
260
260
|
- 自查:凡对动态数组做下标访问,先问「这个数组会不会是空」?会 → 加「长度 > 0」守卫或用 `.find()`/首元素判空兜底,空数组渲染空态而不是崩溃。
|
|
261
261
|
|
|
262
|
+
### ⑩ 盲重试掩盖确定性失败:重试次数耗尽 ≠ 问题解决
|
|
263
|
+
|
|
264
|
+
- ⚠️ 后台任务 / 定时调度 / 请求重试机制必须区分两类失败:**可重试的瞬时故障**(网络抖动、超时、上游 5xx)与**不可重试的确定性错误**(参数不被上游接受、SQL 类型错误、请求本身非法)。对确定性错误反复重试,每次都会同样失败——重试只是把同一次失败重复 N 遍,最终退化成「重试耗尽 → 永久 failed」,日志里堆满重复失败,真实根因反而被淹没。
|
|
265
|
+
- **类比:电梯按钮按一次没反应,按十次电梯也不会更快到达。如果电梯本身坏了(确定性故障),按再多按钮都是白按;只有先查明「是电梯坏了还是只是慢」,才能决定要不要再按。**
|
|
266
|
+
- 典型反例:`byteplus/seedance-2.0-mini` 视频生成,上游(火山引擎 t2v)拒绝 `resolution` 参数返回 400「the parameter resolution ... is not valid」,调度器仍按通用重试逻辑重试 3 次、每次同样 400,重试耗尽后模型被标成红色 failed 徽章,官网视频一直生成不出来。根因是「该参数不该传」这个确定性错误,重试多少次都不会成功。
|
|
267
|
+
- 自查:写重试逻辑时先问「这次失败重试一次会不会成功?」会(瞬时故障)→ 重试;不会(确定性错误)→ 不重试,直接暴露根因/告警。看到「重试 N 次全部失败」时,第一反应必须是研究「为什么每次都会失败」,而不是加大重试次数或加长间隔。
|
|
268
|
+
|
|
262
269
|
## ⚠️ 网关后端编码铁律(来自 PR 评审沉淀)
|
|
263
270
|
|
|
264
271
|
⚠️ 本章来自 routerhub-gateway 92 个已合入 PR 中多位评审者(hankWaling / baikaifa / sam-pomex / rachelPomex / eason-qing / enzo0824)的 review 评论沉淀,每条都有真实 PR 出处。写 Go 后端(网关/代理/计费/路由类)代码时对照本节自查。本节所有条目均为强制规则,命中即自检。
|
|
@@ -288,6 +295,7 @@
|
|
|
288
295
|
- ⚠️ **日志禁止输出请求/响应 body**:上游请求 body 可能带签名 URL、密钥、内部错误详情,全量打 Info 日志=敏感信息进日志系统;默认只输出摘要/trace id。**外部内容写日志前必须截断 + redact + 限长**:高基数动态消息记 hash + length 代替原文,禁止无长度上限地记录上游回显内容(PII/secret 长期进 Cloud Logging,且攻击者可诱导上游回显敏感内容刷爆日志费用)。
|
|
289
296
|
- ⚠️ **凭据必须按真实格式校验/适配**:明文 API key 与结构化 JSON 凭据(如 SigV4)需区分处理,禁止只做非空校验就原样透传——格式不匹配在上游 401/403,且启动时静默放行、运行期才暴露。
|
|
290
297
|
- ⚠️ **声明支持外部能力/版本/协议必须基于实测**:禁止从通用版本表推导或移植注释即认可——外部平台可能对推导出的版本返回 400,文档会误导排障方向。
|
|
298
|
+
- ⚠️ **外部 API 参数支持范围逐模型/逐产品线不同,禁止全局传同一套参数**:凭「该 API 文档支持 X 参数」或「同系列其他模型传了没问题」推断所有模型都支持 X,是参数类 400 的常见来源。上游对不支持参数返回 4xx 时,必须把「该模型实际支持哪些参数」固化成模型级参数白名单(如按 slug 判定),而不是对全部模型统一传参或统一删参。接入新模型时逐个核对「这个模型实际接受哪些参数」,用最小参数集实测通过后再逐步放开,白名单随模型名单同步维护。
|
|
291
299
|
- ⚠️ **上游/外部服务错误消息透传客户端前必须独立 sanitize**:禁止「成功解析上游文本 = 文本安全」的假设——上游 JSON 里的 error.message 可能含 `dial tcp 10.x.x.x: connection refused`、`api_key=sk-secret` 等内部信息,JSON 路径同样要走 sanitizer。
|
|
292
300
|
- ⚠️ **新增行为的 gate 开关必须覆盖该行为的所有入口(含 400/错误路径)**:错误响应路径是最容易绕过 observation 的——开关=false 不代表新行为关闭,未清洗的错误消息仍可能进入生产客户端。
|
|
293
301
|
|
|
@@ -396,6 +404,7 @@
|
|
|
396
404
|
|
|
397
405
|
- 值传递优先,软删除用 `gorm.DeletedAt`(禁止 `*time.Time`)。
|
|
398
406
|
- 禁止无条件执行 GORM AutoMigrate,必须由开关控制,默认关闭。
|
|
407
|
+
- ⚠️ **GORM / 原生 SQL 混合类型运算必须显式标注参数类型**:参数与不同类型表达式混算(如 `timestamptz + interval`、数值 × `interval`)时,PG 对未类型化参数(`$1`)按参与运算的另一侧推断类型,推断错会报 SQLSTATE 42804 且查询永远失败。必须在参数上显式标注(如 `?::timestamptz`),禁止依赖 PG 自动推断。
|
|
399
408
|
|
|
400
409
|
## ⚠️ 数据存储选型铁律(Redis vs PostgreSQL)
|
|
401
410
|
|
package/package.json
CHANGED
package/rules/global.md
CHANGED
|
@@ -259,6 +259,13 @@ name: "通用规则"
|
|
|
259
259
|
- 典型反例:官网首页 hero 用「后端模型列表取前 N 个」的 `heroModels[0].video` 做渲染,后端返回空列表(全部模型下架 / 全新部署)时整页白屏,构建期直接构建失败。
|
|
260
260
|
- 自查:凡对动态数组做下标访问,先问「这个数组会不会是空」?会 → 加「长度 > 0」守卫或用 `.find()`/首元素判空兜底,空数组渲染空态而不是崩溃。
|
|
261
261
|
|
|
262
|
+
### ⑩ 盲重试掩盖确定性失败:重试次数耗尽 ≠ 问题解决
|
|
263
|
+
|
|
264
|
+
- ⚠️ 后台任务 / 定时调度 / 请求重试机制必须区分两类失败:**可重试的瞬时故障**(网络抖动、超时、上游 5xx)与**不可重试的确定性错误**(参数不被上游接受、SQL 类型错误、请求本身非法)。对确定性错误反复重试,每次都会同样失败——重试只是把同一次失败重复 N 遍,最终退化成「重试耗尽 → 永久 failed」,日志里堆满重复失败,真实根因反而被淹没。
|
|
265
|
+
- **类比:电梯按钮按一次没反应,按十次电梯也不会更快到达。如果电梯本身坏了(确定性故障),按再多按钮都是白按;只有先查明「是电梯坏了还是只是慢」,才能决定要不要再按。**
|
|
266
|
+
- 典型反例:`byteplus/seedance-2.0-mini` 视频生成,上游(火山引擎 t2v)拒绝 `resolution` 参数返回 400「the parameter resolution ... is not valid」,调度器仍按通用重试逻辑重试 3 次、每次同样 400,重试耗尽后模型被标成红色 failed 徽章,官网视频一直生成不出来。根因是「该参数不该传」这个确定性错误,重试多少次都不会成功。
|
|
267
|
+
- 自查:写重试逻辑时先问「这次失败重试一次会不会成功?」会(瞬时故障)→ 重试;不会(确定性错误)→ 不重试,直接暴露根因/告警。看到「重试 N 次全部失败」时,第一反应必须是研究「为什么每次都会失败」,而不是加大重试次数或加长间隔。
|
|
268
|
+
|
|
262
269
|
## ⚠️ 网关后端编码铁律(来自 PR 评审沉淀)
|
|
263
270
|
|
|
264
271
|
⚠️ 本章来自 routerhub-gateway 92 个已合入 PR 中多位评审者(hankWaling / baikaifa / sam-pomex / rachelPomex / eason-qing / enzo0824)的 review 评论沉淀,每条都有真实 PR 出处。写 Go 后端(网关/代理/计费/路由类)代码时对照本节自查。本节所有条目均为强制规则,命中即自检。
|
|
@@ -288,6 +295,7 @@ name: "通用规则"
|
|
|
288
295
|
- ⚠️ **日志禁止输出请求/响应 body**:上游请求 body 可能带签名 URL、密钥、内部错误详情,全量打 Info 日志=敏感信息进日志系统;默认只输出摘要/trace id。**外部内容写日志前必须截断 + redact + 限长**:高基数动态消息记 hash + length 代替原文,禁止无长度上限地记录上游回显内容(PII/secret 长期进 Cloud Logging,且攻击者可诱导上游回显敏感内容刷爆日志费用)。
|
|
289
296
|
- ⚠️ **凭据必须按真实格式校验/适配**:明文 API key 与结构化 JSON 凭据(如 SigV4)需区分处理,禁止只做非空校验就原样透传——格式不匹配在上游 401/403,且启动时静默放行、运行期才暴露。
|
|
290
297
|
- ⚠️ **声明支持外部能力/版本/协议必须基于实测**:禁止从通用版本表推导或移植注释即认可——外部平台可能对推导出的版本返回 400,文档会误导排障方向。
|
|
298
|
+
- ⚠️ **外部 API 参数支持范围逐模型/逐产品线不同,禁止全局传同一套参数**:凭「该 API 文档支持 X 参数」或「同系列其他模型传了没问题」推断所有模型都支持 X,是参数类 400 的常见来源。上游对不支持参数返回 4xx 时,必须把「该模型实际支持哪些参数」固化成模型级参数白名单(如按 slug 判定),而不是对全部模型统一传参或统一删参。接入新模型时逐个核对「这个模型实际接受哪些参数」,用最小参数集实测通过后再逐步放开,白名单随模型名单同步维护。
|
|
291
299
|
- ⚠️ **上游/外部服务错误消息透传客户端前必须独立 sanitize**:禁止「成功解析上游文本 = 文本安全」的假设——上游 JSON 里的 error.message 可能含 `dial tcp 10.x.x.x: connection refused`、`api_key=sk-secret` 等内部信息,JSON 路径同样要走 sanitizer。
|
|
292
300
|
- ⚠️ **新增行为的 gate 开关必须覆盖该行为的所有入口(含 400/错误路径)**:错误响应路径是最容易绕过 observation 的——开关=false 不代表新行为关闭,未清洗的错误消息仍可能进入生产客户端。
|
|
293
301
|
|
|
@@ -396,6 +404,7 @@ name: "通用规则"
|
|
|
396
404
|
|
|
397
405
|
- 值传递优先,软删除用 `gorm.DeletedAt`(禁止 `*time.Time`)。
|
|
398
406
|
- 禁止无条件执行 GORM AutoMigrate,必须由开关控制,默认关闭。
|
|
407
|
+
- ⚠️ **GORM / 原生 SQL 混合类型运算必须显式标注参数类型**:参数与不同类型表达式混算(如 `timestamptz + interval`、数值 × `interval`)时,PG 对未类型化参数(`$1`)按参与运算的另一侧推断类型,推断错会报 SQLSTATE 42804 且查询永远失败。必须在参数上显式标注(如 `?::timestamptz`),禁止依赖 PG 自动推断。
|
|
399
408
|
|
|
400
409
|
## ⚠️ 数据存储选型铁律(Redis vs PostgreSQL)
|
|
401
410
|
|