Commit Graph

3 Commits

Author SHA1 Message Date
iomgaa fd9cae7da5 fix(adapters): 转发改按 gateway. 前缀,四条防御各自报错
落实 0017。模块级白名单换成三个常量:保留前缀、结构性参数拒绝集合、历史裸键元组。
_forwarded_binding 按排序后的键遍历(多个键同时违规时报出来的总是同一个),带前缀的剥掉前缀
当关键字参数名,不带前缀的照旧不传也不报错。

**这是一次破坏性的行为变更**:绑定里不带前缀的 session_id 与 parent_call_id 从静默转发变成抛
ValueError,错误信息里给出 gateway.session_id 这个改法。静默不传是又一次静默的行为变更——
下游的网关遥测会悄悄不再按会话分组而没有任何提示;不设弃用期是因为那要求这一版继续按旧机制
转发,等于把要拆的撞名机制再留一个版本。

空值那条防御拒的是「空串或纯空白」,不只是空串。这一条是 Codex 对抗审查抓出来的:空白在网关
那边是真值,会被原样当成命名空间用,于是所有拿到这份坏配置的租户共用同一格,正是 issue #6
那个跨租户串读场景换了个入口。判据是这个取值带不带信息,不是格式对不对——本库不解释绑定的
取值,值原样转发不做 strip,"acme:v1:tenant:" 这种少了一截的它拦不住也不该拦。

四条判断都在 chat() 的实参求值阶段完成,所以出错那次调用一次都没发出去,每条用例都断言了
替身的 calls 为空。空值那条用例是 2 个参数名 × 3 种取值的参数化——独立审查指出单参数版本
钉不住「对所有带前缀的键一视同仁」:把实现写成只认 cache_namespace 也照样绿,而那个错实现下
gateway.cache_salt="" 会被转发成一次读到缓存的调用。

371 passed / 16 skipped,六条 import 契约全 KEPT。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 11:53:00 -04:00
iomgaa 1fac387e75 feat(testing): 契约套件搬进 polyloop.testing 随包发布,五套全部接上实现
tests/ 不进 wheel,所以那套被 CLAUDE.md §0 称作「任何新适配器的准入标准」的用例,第一个
下游根本拿不到。**接法同时换掉**:pytest 的 conftest 只沿被收集文件的目录链查找,装在
site-packages 里的测试模块看不见下游的 conftest,原来那个「在自己的 conftest 里覆盖同名
fixture」的接法在发布之后走不通。改成继承契约基类,下游的子类定义在自己的目录链上。

**搬的过程中发现这套准入标准从来没被执行过。** test_model_client.py 有四条用例调用
records.model_call(...),而工厂里根本没有这个方法——它没炸是因为那个 fixture 默认 skip。
五个接缝里只有存储那套被真跑过(15 条跳过里有 15 条是这四套)。

所以这个提交的另一半是让它真的跑起来。存储接两个实现(一份契约同时验多个实现,正是换接法
换来的);动作执行接注册表分发器,外加一个有真实等待点的替身,否则那条取消用例的断言半边
永远走不到;模型调用接网关适配器,落在 integration,它连的是真网关;决策解释与事件出口各
接一个测试替身——替身住在 tests/ 里不进 wheel,下游拿不到,所以不违反「库不带默认实现」,
判据是下游拿不拿得到。

**一并清掉两类坏用例。** 五条函数体只有 docstring、一个断言都没有却报 PASSED 的假绿——一个
准入标准里出现假绿比出现跳过糟得多,下游看到全绿会以为验过了。以及一条端口从没承诺过的
长度断言(len(history_text) <= len(reply.content)):压测的 AppWorld 场景为了迁就它,刻意
不补被复刻的实现真的会补的三个反引号,注释里写着「补一个字符就违约」。七条「这一层验不了」
统一成无条件 skip,理由字符串写全「承诺是什么/为什么验不了/你该在哪儿自己验」。

**发一个 pytest11 entry point,只为换回断言重写。** 契约模块不在下游的 python_files 里,
默认不被重写,于是一条契约失败时下游看到的是光秃秃的 AssertionError。不做的话没有任何东西
会报错,纯静默退化。实测过:editable 安装下 entry point 注册了但重写不生效(RECORD 里没有
包文件),要装真 wheel 才验得出来。
2026-08-27 03:59:16 -04:00
iomgaa 39417a21ec feat(adapters): 落成网关适配器,十个模块全部有内容
design 0012(待确认)定六条:收一个已经装配好的客户端而不自己装配(治理参数按 §1.5 不归本库
管,而且项目常要在多个用途间共享同一个限流器和缓存);同时收那份配置只为算模型身份(客户端
把源列表与 scope 收在内部不公开);内容块按顺序拼成一个字符串不加分隔符;绑定里只有网关认得
的两个键往下传、其余留在参数快照里且不报错;网关异常原样穿出去不翻译不重试;空串的调用标识
映射成空值。

参数快照不用网关内部那个 build_model_fingerprint:它不在 __all__ 里(用它就得从子模块 import,
他们重排一次我们就断),而且它是为缓存键设计的、按模型名去重。续跑守卫怕的是「配置变了而我
没发现」,所以宁可更严——改一个源名也报出来,那意味着这次运行打的可能是另一个端点。

tests/integration/ 这一层第一次有内容:用的是网关真实的 GatewaySettings / LLMResponse /
异常类型,装配守卫也真的跑了,只把「真的发出去」那一下换成受控替身。没装 polyloop[gateway]
时整份文件跳过——一个因为可选依赖没装而常年红的套件会训练所有人忽略红。

环境:从 ~/Projects/PolyGateway(活版本 1.1.2,比 reference/ 那份 1.1.1 新)复制一份装进
conda 环境。没有配私有源,polygateway 不在任何可达的 index 上。
2026-08-10 03:57:50 -04:00