From 7c60199680a0a35bff2e17dff445433d1493c0df Mon Sep 17 00:00:00 2001 From: iomgaa Date: Fri, 7 Aug 2026 11:23:29 -0400 Subject: [PATCH] chore: release 1.1.2 README first, per the release procedure: the 1.1.* pin still covers this version, the 22-field count re-checked with inspect.signature, and the telemetry row now states that an existing table needs no schema CREATE privilege. --- CHANGELOG.md | 21 +++++++++++++++++++++ README.md | 2 +- pyproject.toml | 2 +- src/polygateway/__init__.py | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87d5d47..0251d83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 1.1.2(2026-08-07) + +Postgres 遥测撞上建表权限就整体判死的问题(issue #9)。**最小权限部署会静默丢掉全部遥测**: 应用账号有表级 `INSERT`、表也已存在,但没有 schema 的 `CREATE` 权限时,初始化的 `CREATE TABLE IF NOT EXISTS` 被拒 → recorder 永久 no-op,业务调用一切正常,只留一行 warning。下游 CHSAnalyzer3 首次端到端跑的 150+ 次调用耗时/token/成本因此全部丢失,且事后无法补回。 + +根因是 **PostgreSQL 对 schema 的 CREATE 权限检查早于 `IF NOT EXISTS` 的存在性判断**(PG 16.14 实测: 同一连接 `INSERT` 通过、`to_regclass` 看得见表,该 DDL 照样被拒)——与 issue #3 修过的 `ALTER TABLE` 是同一类问题,当时只修了补列那一半。 + +### 行为变更 + +- **PG 侧建表前先 `to_regclass` 探测,表已存在就一条 DDL 都不发**。探测不需要任何权限,且与 `INSERT` 走同一套 search_path 解析(比裸 DDL 更准: 裸 `CREATE TABLE` 落在首个**可建**的 schema,可能与写入命中的不是同一张表)。表不存在时才建,新建表列已齐全,顺带跳过补列。 +- **"结构性失能"的判据收窄为「确定写不进去」**,不再是「初始化时出过异常」。仅两种情形仍永久降级为 no-op: 建池失败(重试要在业务路径上内联吞掉连接超时)、表确定不存在且建不出来(后续 INSERT 必然全败)。探测失败、取连接失败改为**只跳过本条并 warning,下次调用重新准备**——初始化瞬间的一次抖动不再让整个进程失遥测。 +- 日志措辞随之细分: `建池失败` / `建表探测失败(跳过本条,下次重试)` / `建表失败(表不存在,记录无处可落)`,原先一律是 `初始化失败`。 + +### 不变 + +- SQLite 侧**一行未改**。实测其对已存在的表在解析期就把 `CREATE TABLE IF NOT EXISTS` 短路掉(另一连接持 `BEGIN EXCLUSIVE`、文件 `chmod 444` 时该语句均通过,而同条件的 `INSERT` 分别报 database is locked / readonly database),没有同款风险;加探测零收益,故有意不对称,只在 docstring 钉死实测结论。 +- 遥测端口签名、22 字段、列序、`ON CONFLICT DO NOTHING` 幂等、单条写失败逐行丢弃的降级方向全部未动。**错误面零变更**。 + +### 升级提示 + +若你的部署此前为了绕开本问题给应用账号授了 `CREATE ON SCHEMA`,现在可以收回——表存在时库不再需要该权限。 + ## 1.1.1(2026-08-06) stall 判定改为非生产性等待口径(issue #8)。`timeout_s ≥ stall_window_s` 时,**一次耗满超时的请求就会让整个 scope 被判死,配置的重试次数一次都用不上**——而且没有任何报错或 warning,配置方以为自己配了 3 次重试。`stall_window_s` 默认 300 恰是个很容易被 `TIMEOUT_S` 追平的值,"只配 timeout、不配 stall"这种最常见的写法正好踩中。 diff --git a/README.md b/README.md index 514ef3e..4fbf7ca 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ | 背压与判死 | 配额满可选等待或快速失败;等待期按双条件判死(本地非生产性等待与全局无进展**同时**超窗)。stall 窗口只计**非生产性**等待(429 退避/配额轮询/熔断冷却),与 `TIMEOUT_S` 无耦合 | | 响应缓存 | Redis/内存;key 含 model + messages 摘要 + namespace/租户 + salt,多模态 content 先摘要再 hash(防毒化);可 per-call 绕过(科研重采样) | | 流式看门狗 | TTFT / inter-token / 总超时三层活性;thinking token 刷活性不计结果;截断流(缺 `[DONE]`)判瞬时不入缓存 | -| 遥测与成本 | 每次调用(含缓存命中与失败)必录 22 字段;SQLite / Postgres 后端;按价格表折算成本落库(注意 `LLMResponse.cost` 本身恒为 `None`,成本只进遥测);多模态内容摘要落库不存原图 | +| 遥测与成本 | 每次调用(含缓存命中与失败)必录 22 字段;SQLite / Postgres 后端(表已存在时**不需要** schema 建表权限,最小权限账号可直接用);按价格表折算成本落库(注意 `LLMResponse.cost` 本身恒为 `None`,成本只进遥测);多模态内容摘要落库不存原图 | | 结构化输出 | json_repair 修复 / 原生 schema 双策略 + 校验失败有界带反馈重问 | | OCR | MonkeyOCR 双端点(文本转录 + 版面解析),bbox 数值防御下沉,逐源健康预检 `check_health()` | | Embedding | 分批、维度校验、与 chat 同一治理栈 | diff --git a/pyproject.toml b/pyproject.toml index 8ac7e56..50f5dcd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "polygateway" -version = "1.1.1" +version = "1.1.2" description = "PolyGateway:实验室统一的大语言模型(LLM/VLM/OCR)调度与中转库——多源、限流、重试、熔断、缓存、遥测" requires-python = ">=3.11" dependencies = [ diff --git a/src/polygateway/__init__.py b/src/polygateway/__init__.py index eaeec7d..849cab4 100644 --- a/src/polygateway/__init__.py +++ b/src/polygateway/__init__.py @@ -32,7 +32,7 @@ from polygateway.types import ( SourceConfig, ) -__version__ = "1.1.1" +__version__ = "1.1.2" __all__ = [ "DEFAULT_PROFILES",