fix(test): 容量合同按 fixture.psql 的 f: 字母表断言(BUG-739)
Independent Staging Quality Gate / validate (push) Successful in 11m47s
Independent Staging Quality Gate / publish (push) Successful in 13m18s

Independent Staging Quality Gate run 2683 唯一失败:
database-consultation-session-capacity 期望 false:session_missing,
实际是 f:session_missing。夹具把 boolean::text 的 false 规范成 psql -A 的 f。
五处期望值对齐既有合同;无 Docker 源码合同锁住 false→f。
This commit is contained in:
jesse-ux
2026-09-16 15:22:55 +08:00
parent 8cb1877eb3
commit 7061d0d1f3
7 changed files with 143 additions and 5 deletions
+16
View File
@@ -11534,3 +11534,19 @@
- 相关记录:BUG-554(同一现象的第一次,本条为其复发)、BUG-695~697(触控与断点轮次,同一文件相邻区段)
- 复发自:BUG-554
- 修复版本:待发布
## BUG-739 | 咨询会话容量的真实 Postgres 合同把 `false:` 写成期望值,staging 门禁从 BUG-732 起一直红
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`frontend/tests/database-consultation-session-capacity.test.ts``frontend/tests/helpers/postgres-fixture.ts``psql()`、Independent Staging Quality Gate`backend-quality-gate.yml`
- 用户现象:用户看不见产品行为变化。staging 从 `dcfc2f15`(BUG-732)起每次含门禁路径的推送都红,镜像不发布、环境不更新。
- 触发条件:质量门跑 `npm run test:db`。Gitea run `2683` / job `6103`SHA `1e3570b4`
- 根因:`fixture.psql()``boolean::text``false` 规范成 psql `-A``f`,好让 `true:f:f` 这类冒号拼接在不同 Postgres 表示之间稳定。BUG-732 的真实库合同用了 `success::text`,却把期望值写成 `"false:session_missing"`。夹具一规范化,实际是 `f:session_missing`。本机当时无 Docker,该文件 skip,带红合入。
- 修复:五处失败分支的期望值改成 `f:session_missing` / `f:invalid_question_message` / `f:session_full`,与既有 `database-billing-admin` 等合同同一套字母表。夹具改写保留,加一行说明。源码合同锁住「期望值必须是 `f:`、夹具必须保留 false→f 规范化」,不依赖 Docker。
- 验证:`consultation-session-capacity.test.ts` 新增无 Docker 源码合同;定向套件全绿。本机仍无 Docker,真实 `test:db` 留给门禁。
- 防复发:对 `fixture.psql()` 的冒号拼接结果不得断言 `"false:"`。新增真实 Postgres 合同前先对照 `postgres-fixture.ts``false→f` 规范化,并用一条不需要 Docker 的源码合同锁期望值。
- 相关记录:BUG-732(引入这条真实库合同但未在有 Docker 的机器上跑)
- 复发自:无
- 修复版本:待发布
@@ -0,0 +1,35 @@
# PROGRESS · staging 门禁容量合同 `false:` / `f:` 失配(2026-09-16
工作树:`.worktrees/session-capacity-bool-assert-20260916`
分支:`codex/session-capacity-bool-assert-20260916`
基线:`origin/staging` @ `8cb1877e`(最近门禁路径 SHA `1e3570b4`Gitea run `2683` failure
修复提交:推送 `HEAD:staging` 后回填 40 位 SHA。
本机 Windows。无 Docker。未改生产 SQL、未改 `.gitea/workflows/**`、未 bump Skill、未动 `page.tsx`
## 做了什么
- `database-consultation-session-capacity.test.ts` 五处期望值:`false:``f:``session_missing` / `invalid_question_message` / 三处 `session_full`)。`true:null` 与权限位 `true:f:f` 未动。
- `postgres-fixture.ts` 的 false→f 规范化保留,补一行说明:`boolean::text``false``psql -A``f`
- `consultation-session-capacity.test.ts` 新增无 Docker 源码合同(BUG-739):夹具必须保留该 replace;真实库合同必须写 `f:`、禁止 `"false:session_*"`
- Bug 历史 **BUG-739**,关联 BUG-732。
## 既有断言变更(AGENTS.md §7.3
| 文件 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `database-consultation-session-capacity.test.ts` 会话不存在 | `"false:session_missing"` | `"f:session_missing"` | `fixture.psql()``false` 规范成 `f`CI 实测 actual 即此 |
| 同上,超长提问 | `"false:invalid_question_message"` | `"f:invalid_question_message"` | 同上,第一条炸后未跑到 |
| 同上,额度/物理/条数满员 ×3 | `"false:session_full"` | `"f:session_full"` | 同上 |
## 测试
| 命令 | 结果 |
| --- | --- |
| `./node_modules/.bin/tsc --noEmit` | 0 错 |
| `eslint --max-warnings 0` 本单三个测试文件 | 0 error / 0 warning |
| `npx tsx --test tests/consultation-session-capacity.test.ts` | **7 passed / 0 failed**(含新增 BUG-739 源码合同) |
| `npx tsx --test tests/database-consultation-session-capacity.test.ts` | **1 skipped**`docker unavailable on this host`),不得写成通过 |
| `npm run test:db` | **blocked**:本机无 Docker |
门禁重跑证据写在推送之后。
+1
View File
@@ -243,6 +243,7 @@
| `TASK-consultation-external-evidence-cache-20260915.md` | `PROGRESS-consultation-external-evidence-cache-20260915.md` | **普通聊天性能单(Python2026-09-15 产品拍板改为排在 api-server-decomposition 之前)**:每轮每域同步等外网,cProfile 前三名全是 `api.vedastro.org` 的 HTTPS 往返(0.801 + 0.786 + 0.206 s),本地 swisseph 只有 0.022 s。三个护栏数字凑不齐:前台等 1.5 s、后台跑 8 s、线程池只有 2 个 worker,且超时**不 cancel** → 每 4 秒一轮就长期饱和,之后每轮白等再拿 `official_blocked`BUG-727)。另 `western_evidence_packet` 122 KB 前端零读取点(BUG-728)。**产品定案**:按「出生数据+岁差+交点+UTC 日期」缓存(与引擎 `_official_snapshot_reference_date` 同键,否决自定 TTL),同日 0 等待 / 跨日先用旧的(≤7 天)后台刷新 / `daily_starlanguage` 要求当天 / 冷启动才走 1.5 s。**不许「干脆不调」——那会重开 BUG-301。** 另含 staging 单域耗时实测单(代码注释里的 21 s 与本机 0.5 s 差 40 倍,三域上限就是从它推的)。BUG 段 727–728 | 已验收 | `e61535f4`BUG-727/728)。缓存目录与 `_api_chart_cache` 分开、超时 `pending.cancel()`、`daily_starlanguage` 拒隔夜;`jyotish_api_server.py` 反而净降 43 行 |
| `TASK-consultation-context-memory-20260915.md` | `PROGRESS-consultation-context-memory-20260915.md` | **记忆三缺口(TS,可并行)**:历史超预算时从最老整轮丢弃,`droppedCount` 算了却**全仓零读取点**,模型不知道少看了几轮——单条截断有「省略 N 字」标记,整轮丢弃没有(BUG-729,BUG-555 防复发只写了「头部截断」所以漏网);写摘要阈值写死 16,000,历史预算却是 `clamp((窗口−60k)×1.5, 4k, 40k)`,窗口 < **70,667** 时预算低于阈值 → 每轮静默丢(BUG-730,后台上架中等窗口模型即触发);写满时服务端存着摘要,`continueInNewChat` 只带问题不带摘要,而 `context_summary` 根本不在任何会话接口的列里(BUG-731)。**产品定案:静默继承**,且摘要文本永远不许由客户端提供(`chatSessionCreateSchema` 只收来源会话 uuid)。BUG 段 729731 | 已验收 | `149e1ec4`BUG-729~731)。丢整轮有两种诚实措辞;阈值由预算派生且越界直接 throw;静默继承只收来源会话 uuidschema 仍 `.strict()` 无 `context_summary` |
| `TASK-consultation-session-capacity-20260915.md` | `PROGRESS-consultation-session-capacity-20260915.md` | **对话上限单(一份迁移,可并行;不碰 route.ts)**`append_consultation_question` 的 200,000 字符额度里,`thinkingText`(≤4,000) + `thinkingSections`(实测 1,521/2,243/2,977) 占一半以上,而 `techniqueTruth`/`workflowReceipt`/`agentExecutionReceipt` 照样入库却不计入——同一条上限身兼二职且两职都没做好,约 **19 轮** 就「已写满」(200 条那档永远碰不到)。**产品定案:思考文本不计入**,额度只数用户读得到的正文(约 19 → 约 50 轮),另设一条按 `length(elem::text)` 把全部字段算全的物理上限(算式取 1,000,000,写进迁移注释)护住数据库行;两档都返回同一个 `session_full`。保留 advisory lock / 幂等 / 满员拒绝(BUG-464 防复发)。BUG 段 732 | 已验收 | `dcfc2f15` / `51a65d92`BUG-732 |
| `TASK-session-capacity-bool-assert-20260916.md` | `PROGRESS-session-capacity-bool-assert-20260916.md` | **门禁修复**BUG-732 的真实 Postgres 合同把期望值写成 `"false:session_missing"`,但 `fixture.psql()` 把 `boolean::text` 的 `false` 规范成 `f`。Gitea run `2683``1e3570b4`)唯一失败即此,staging 从 `dcfc2f15` 起带红。只改测试期望值 + 无 Docker 源码合同。BUG-739 | 待验收 | `codex/session-capacity-bool-assert-20260916` |
| `TASK-freeze-metric-change-20260915.md` | `PROGRESS-freeze-metric-change-20260915.md` | **规则单(后面两单的前置,无 BUG 号)**:两条增长冻结余量都用完(`page.tsx` 1,951/1,951 余 **0**`jyotish_api_server.py` 11,334/11,363 余 **29**),冻结从「逼新代码往外走」退化成「拦路」。实证:`page.tsx` 行数砍 59% 但 `Home()` 的 `useState` 从 56 涨到 **66**(拆的是代码不是状态);api server **225 个类方法只有 12 处真碰 HTTP 上下文**,4 处 `__new__` 伪造空壳就是这么来的。**产品拍板换口径**:主门改成「`Home()` 的 useState/useRef 不得增长」与「类方法数 + `__new__` 计数不得增长」,行数降级为粗护栏;**同时推翻 §6「参数式 hook 内部保持 0 个 React hook」**(那正是状态搬不走的原因)。改 `AGENTS.md` §6 + 两个合同测试,不碰业务代码 | 已验收 | `3b17c1b2`。`AGENTS.md` §6 已按新口径改写,两个合同测试到位 |
| `TASK-home-state-lowering-20260915.md` | `PROGRESS-home-state-lowering-20260915.md` | **page.tsx 状态下沉第一簇(串行在 freeze-metric-change + C2 + R3 之后)**66 个 state 里 `rectification*` 占 **15** 个,而它们服务的 `<ConversationalBirthTimeRectification>` 本来就是 `dynamic()` 懒加载子树、挂着 24 个 props;`useRectificationSurface` 要解构约 56 个参数。把这簇搬进子树,`Home()` 的 useState 从 66 降到 ≤ 53。**零行为变化**;第一步必须先把 15 个逐个分类(只服务子树 / 外壳也要读)。产品否决了 Context Provider 与外部 store 两条路。不占 BUG 号 | 已验收 | `f8e607c2`。实测 useState 66→52、useRef 41→39、残留散装 `rectification*` state 0;冻结基线**往紧里收**;全量套件两侧完全相同(3329/fail 31)。遗留:`createRectificationShellSetters` 身份不稳多 1 条 warning,已披露,并进第二批 |
| `TASK-rectification-engine-memoization-fix-20260915.md` | `PROGRESS-rectification-engine-memoization-fix-20260915.md` | **验收修复单(只改测试,一行实现不许动)**:BUG-721 的实现**等价性成立**(我在改前 `6b3248bf` / 改后 `e4788dfc` 同机跑同一 payload`candidate_scores` 逐字相同),9 条计数断言全过;但等价 golden 在本机复现不出来——4 处浮点尾数差(score 1.0e-4 ×2、`margin_percent` 1.1e-3 ×2)。**复发自 BUG-712**(「不得对全精度浮点做整体 `==`」,那一单只落在 ephemeris 一处)。而 `tests/test_rectification_*.py` 在 `CORE_PYTEST_TARGETS` 里,**staging 门禁靠机器舍入碰巧一致才是绿的**。修法:主证据换成**同进程差分**(把 static context 的四个缓存键置 `None` 即可回退旧路径,A/B 严格相等),golden 降为离散字段严格相等 + 浮点带容差(容差按实测 1.1e-3 推);**禁止重建 golden 来「修」**。另含六份 golden 的仓库级排查。BUG-733 | 已验收 | `2b7b4565`(BUG-733)。同进程差分立为主证据,golden 降为离散严格+浮点容差;本机 14 条全绿 |
@@ -0,0 +1,63 @@
# TASK · staging 门禁因容量合同 `false:` / `f:` 失配一直红(2026-09-16
基线:`origin/staging` @ `8cb1877e`。最近一次含门禁路径的 staging 提交是 `1e3570b4`(其后 `8cb1877e` 为纯文档)。Gitea Independent Staging Quality Gate run `2683` / job `6103` **failure**
## 事故实证
validate 步「Validate backend, package, frontend, and database contracts」失败。Python 快速门已通过。唯一 `not ok`
```
not ok 1109 - append_consultation_question ignores thinking fields and enforces the physical JSON cap
location: frontend/tests/database-consultation-session-capacity.test.ts:120
Expected values to be strictly equal:
+ 'f:session_missing'
- 'false:session_missing'
```
同文件后面 `"false:invalid_question_message"`、三处 `"false:session_full"` 会被同一条夹具改写打红,只是第一条先炸。
`dcfc2f15`BUG-732)起到 `1e3570b4`,staging 上每一次跑完的质量门都是 failure;中间被更新推送 cancel 的不算绿。
## 根因
`frontend/tests/helpers/postgres-fixture.ts``psql()` 对输出做:
```ts
.replace(/(^|:)false(?=:|$)/gm, "$1f")
```
`boolean::text``false``psql -A``f`。这条改写让既有合同(`true:f:f``f:grant_failed`)跨表示稳定。BUG-732 的真实库合同用了 `success::text`,却按未规范化的 `false:` 写期望值。执行方当时无 Docker,该文件 skip,带红合入。
## 决策记录
- 不删夹具的 false→f 规范化(billing / topology / report 等合同依赖它)。
- 不改 `append_consultation_question` 运行时 SQL。
- 产品授权:直接修测试并推 staging 重跑门禁。
## 硬红线
1. 不改 `.gitea/workflows/**`、不提升 `main`、不动 DNS。
2. 不改迁移、不改 RPC 签名/error_code。
3. 不顺手升级依赖、不顺手修无关 warning。
4. Bug 历史不写入姓名、出生资料、密钥。
## 任务分解
1. 五处期望值改为 `f:session_missing` / `f:invalid_question_message` / `f:session_full`。验收:源码不再出现 `"false:session_missing"` 等。
2. 夹具改写保留,加一行说明。验收:`database-billing-admin` 等既有 `f:` 断言的源码合同仍在。
3. 无 Docker 源码合同:夹具必须保留 false→f;真实库合同必须用 `f:`。验收:`consultation-session-capacity.test.ts` 新增一条,定向套件绿。
4. `docs/BUG_HISTORY.md` 连续号 **BUG-739**。关联 BUG-732。
5.`origin HEAD:staging`,门禁对**本提交 SHA** 必须绿(或明确写出环境缺口)。
## 让步顺序
改期望值即可。禁止为了让测试过而拿掉夹具规范化。禁止改生产 SQL。
## 开工前置
```
git fetch origin --prune
git status -sb # 第一行必须是独立 worktree 分支
```
BUG 编号起点:开工时最大号 **BUG-738**,本单用 **BUG-739**