docs: 回写 CHANGELOG、GovDoc 迁移,以及压测那条过期注释

CHANGELOG 落在「未发布」段,按那一段自己的规矩不提前写版本号。写清了四条会抛 ValueError 的
情形与迁移写法,因为这是一次破坏性变更。

migrations/govdoc-saas.md 加一节讲租户命名空间怎么传,含迁完算不算数的四条判据,最终判据是
「同一段文本由两个租户各提交一次,各自拿到自己的那份输出」。参数一律指向 0017 不复述。这份
文档原来说 GovDoc 侧「还没有可迁移的东西」,现在有了第一条能逐条验的接入动作,文件头那句
状态说明跟着补了一句例外。

tools/soak/run_soak.py 那份空绑定上方的注释在复述旧转发规则,顺手改对。它给的理由本来就不准
——让绑定留空的真正原因是绑定的全部键值都进参数快照,每批都不同的值会让故障注入那一步续跑时
报一次假的参数漂移,和转发哪些键无关。三份压测绑定常量里都没有裸键,所以这次变更打不到压测。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-29 11:53:20 -04:00
parent fd9cae7da5
commit c0d9d7b66e
3 changed files with 91 additions and 4 deletions
+55 -1
View File
@@ -5,7 +5,8 @@
> 来源与缺口清单。
>
> **当前状态:这不是一份迁移清单,是一份需求清单。** GovDoc-SaaS 的 agent 部分还没有可迁移
> 的东西,本文的作用是防止 PolyLoop 只按 dissect 一家的形状长。
> 的东西,本文的作用是防止 PolyLoop 只按 dissect 一家的形状长。唯一已经能逐条验的接入动作是
> 租户隔离参数那一节。
PolyLoop 只有 dissect 一个硬消费者(见 `dissect.md`)。只对着一个消费者做,做出来的库会长成
那个消费者的形状,而这件事在完成之前看不出来。GovDoc 这边不做迁移验收,改做**设计级验收**:
@@ -141,6 +142,59 @@ Codex 对抗审查抓出来了,修法见 `../design/0004-stopping-and-step-rec
显式注入,重试对它们就静默失效」——那是 PolyGateway 装配的问题,要在装配点解决,不是在
Agent 层补一层。
## 租户隔离参数怎么传
**绑定**是挂在一次运行请求上的一组字符串到字符串的映射,装的是下游项目自己的坐标。PolyLoop
不解释它的内容,原样交给模型调用接缝;自带的网关适配器再从里面挑出该往 PolyGateway 那次调用
上传的键。
GovDoc 在 PolyLoop 仓库提的 issue #6 说的是:适配器挑键的老办法把租户命名空间挡在外面,而那
是 PolyGateway 指定的租户隔离手段,挡掉之后两个租户提交相同的一段文本时,第二个会读到第一个
那次的模型输出。`../design/0017-gateway-forwarding.md` 决策一换掉了挑键的机制——**绑定里键名
`gateway.` 开头的才往下传,前缀之后那一段当作网关 `chat()` 的关键字参数名**。
### 要改的地方
租户命名空间与租户标识都写成带前缀的绑定键,每次运行按这次运行属于哪个租户填值:
```python
model_binding = {
"case": "...", # GovDoc 自己的坐标,不带前缀,不往下传
"gateway.cache_namespace": ..., # 这次运行所属租户的命名空间
"gateway.tenant_id": ..., # 同一个租户的标识
}
```
两个值的字符串怎么编码由 GovDoc 自己定(它的设计记录里已经定死),PolyLoop 不解释这两个字符串
的内容,也不替它们拼任何前后缀。这两个网关参数各自是什么语义、以及租户坐标为什么走绑定而不是
走适配器的构造参数,见 `0017` 的术语节与决策三。
**issue 里提的第三个维度 `meta` 本库不做**,理由在 `0017` 决策五。它原本要带的那个自己的 trace
标识改走 `gateway.session_id`:网关那边这个槽位本来就是一个用来分组的字符串,而 PolyLoop 不往
里面填任何东西,它一直留给下游自己写。
**绑定里现有的不带前缀的 `session_id` 与 `parent_call_id` 要改成带前缀的写法。** 这两个键在旧
机制下会被转发,`0017` 之后不再转发,而且会被适配器显式拒绝——用一次报错换掉一次静默的行为
变更,理由在 `0017` 决策四的第四条防御。拒绝发生在第一次模型调用时,形态是一次「第 0 步就以
模型调用失败收尾」的运行,失败说明里带着出问题的那个键名,没有预算被花掉。落地在哪个版本、
以及网关依赖下界要不要跟着动,见 `0017`
### 迁完算不算数
**绑定里再没有不带前缀的 `session_id` 或 `parent_call_id`。** 这条装上新版就自己验了:有残留
的话,用到那份绑定的第一次运行会在第一次模型调用上失败。
**每一次运行的绑定里都带着这次运行所属租户的命名空间键,值不是空串。** 空串会被适配器拒绝
`0017` 决策四的第二条防御)。查法是拿一次真实运行的运行开始记录看参数快照:带前缀的键照旧
逐字段进快照,所以「这次运行用的是哪个命名空间」事后查得到。
**同一段文本由两个租户各提交一次,各自拿到自己的那份模型输出。** issue #6 的失败场景不再复现
——这是最终判据,前面两条都是为它服务的。
**续跑一次运行时命名空间不变。** 命名空间随绑定进参数快照,而续跑开工前会把重算的快照与日志
里那份逐字段比对,换过命名空间就会被当成参数漂移中止。撞上这条说明续跑读到的缓存可能属于另一
个租户,中止是对的。
## 缺口登记
这些是 PolyLoop 现在答不上来的问题。答不上来不等于设计错了,但每一条都得有明确结论——