fix(tests): read every CSS rule for a selector, not the first one
The sidebar contract read a selector with indexOf, so it returned whichever rule appeared earliest in the file. A responsive override added above the base rule made the gate report a missing min-height that was never removed, which blocked staging on a change that was correct. Share one helper that strips comments, parses rule by rule, accepts a whole group as the query, and returns the declarations of every matching rule. The union also makes a negative assertion mean no rule may declare the property, which is what these contracts intend. The helper was duplicated in two files and had no tests of its own; it now has regressions for each way it read the wrong block. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3604,3 +3604,17 @@
|
||||
前两次 `calculation_failed` 的服务端原因尚未定位(工作流超时为 90s,两次失败均在 20s 内,可排除超时)。本条修复只保证瞬时失败可恢复,不替代对失败本身的排查。
|
||||
|
||||
排查所需的可观测性已随本批补齐:`calculation_failed` 是 `safeToolError()` 的兜底码,除中止与超时外的一切失败都会被压成它,而上游真实错误文本属于 provider payload,按 `agent-observability.ts` 的封闭契约不得进入日志。因此改为按封闭机器码分类:`runConsultationWorkflow` 抛出带 `code` 的 `ConsultationWorkflowError`,按 HTTP 状态区分 `workflow_rate_limited`(429)、`workflow_bad_request`(400)、`workflow_queue_full`(503)、`workflow_server_error`(5xx) 等,并单独标识 `workflow_contract_invalid`(HTTP 通过但响应未过 `consultationWorkflowResponseSchema`,此种情况 Python 侧日志显示成功,仅凭访问日志无法发现)。该码记入运行步骤的 `failureCode`,经 `agentObservabilityToolCallSchema` 的新增受控可选字段进入观测日志。同时把 `request_id` 透传给 Python API,用于与其访问日志交叉对齐;此前两侧无任何关联标识,只能靠时间戳猜测。公开回执改由 `publicConsultationRuntimeSteps()` 按白名单构建,内部 `failureCode` 不出现在对外契约中——`executionStepSchema` 是 strict,若直接透出会让成功运行在解析回执时报错。
|
||||
|
||||
## BUG-215 | CSS 契约测试取错规则块,假阳性阻断 staging 发布
|
||||
|
||||
- 状态:resolved(本地修复,未提交、未发布)
|
||||
- 首次发现:2026-08-17
|
||||
- 最近更新:2026-08-17
|
||||
- 影响面:`backend-quality-gate` 的前端契约测试;间接影响该 gate 上所有等待发布的改动。
|
||||
- 用户现象:quality gate 以 `makes SidebarContent the only sidebar scroll owner` 失败,报 `[data-sidebar="content"]` 缺少 `min-height: 0`,但该声明实际存在且未被改动。staging 因此停留在 `7050f7ee`,`bced1b9d` 与其后两批后端修复均无法部署。
|
||||
- 根因:`cssBlock()` 以 `globalStyles.indexOf(selector + " {")` 取**首个**匹配规则。`bced1b9d` 在媒体查询中新增了一条同名规则 `[data-sidebar="content"] { -webkit-overflow-scrolling: touch; }`,位置早于第 333 行的基础规则,helper 因而返回媒体查询块。该 helper 在 `sidebar-contract` 与 `membership-page` 两个文件各有一份副本,且自身没有任何测试。修复过程中又暴露两个同源缺陷:CSS 注释写在规则上方时会被计入捕获的选择器文本(`.membership-page` 因此找不到);调用方会把整个选择器组当作 key 传入(`".membership-plan-card, .membership-credit-card"`),旧实现仅靠字面量子串匹配碰巧生效。
|
||||
- 修复:抽出共享 `tests/css-contract-test-support.ts` 的 `cssDeclarations()`,先剥离注释再逐条规则解析,按逗号拆分并归一化空白后做精确或后代组合匹配,支持以整组作为查询,并返回**所有**命中规则声明的并集而非首个。并集使 `assert.match` 语义为“任一规则声明即可”、`assert.doesNotMatch` 为“任何规则都不得声明”,后者比原实现更严格,也更贴近“唯一滚动容器”这类断言的本意。未放宽任何既有断言,未改动 `globals.css`。
|
||||
- 验证:新增 9 个 helper 回归,覆盖媒体查询先于基础规则、注释引入的规则、跨行选择器、选择器组查询、后代组合、以及选择器缺失时必须响亮报错;`sidebar-contract` 与 `membership-page` 合计 78/78 通过;全量非数据库套件 1577/1578,唯一失败为需要真实 Postgres 的 v9 迁移测试。
|
||||
- 防复发:被多处断言复用的测试辅助函数必须有自己的回归,不得以副本形式散落在各测试文件。以字符串匹配近似 CSS 语义时,必须按规则解析并覆盖同名选择器的全部声明;`indexOf` 式首个匹配不可用于可能重复出现的选择器。
|
||||
- 相关记录:BUG-214
|
||||
- 修复版本:本地未提交候选
|
||||
|
||||
Reference in New Issue
Block a user