From c41afe26a2d355e80f677171c55dfb841e7e2275 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Wed, 9 Sep 2026 19:16:04 +0800 Subject: [PATCH] fix(frontend): unblock staging gate by aligning two stale contract tests (BUG-622) is-changed now has a CSS rule, so it cannot stay on knownUnstyled. The question-gap contract still expected verified_idle && ( after BUG-620 added verifiedIdleCopy and !showSelectionCards. Co-authored-by: Cursor --- docs/BUG_HISTORY.md | 26 +++++++++++++++---- .../class-name-definition-contract.test.ts | 9 ++++--- .../rectification-surface-contract.test.ts | 5 +++- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 95c008a3..ce37579d 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -9537,8 +9537,8 @@ - 根因:`column_times_for_compare` 只取引擎分数前三,卡片列按后验前三投影。缺键时投影把空表当成 0 次吻合、把缺窗口当成「没有窗」。 - 修复:`columns` 改为引擎 `candidate_times` 去重全集(上限 9)。客户端缺键写 `fit: null` / `windows: null`,灰字「这一分钟还没对照」,不得回退成 0。经历对照改成「N 件里 M 件对得上」;无窗写「未来一年没有明显的时段」。三列共有的性格句只出现在卡顶一次。 - 验证:`tests/test_rectification_v5_services.py::test_compare_ledgers_cover_all_engine_candidate_times`;`frontend/tests/rectification-range-delivery-20260907.test.ts` 后验前三与引擎前三不同时 `fit` 非 null,缺键 DOM 出现「这一分钟还没对照」、不出现 `0 · 0 · 0`。 -- 防复发:`set(ledgers) == set(candidate_times)`;用户可见文案禁用「强相关 / 有关联 / 弱关联」;列内不得再出现 `

`「经历对照 / 往后 12 个月」。 -- 相关记录:BUG-597、BUG-615、`TASK-rectification-compare-card-polish-20260909.md` +- 防复发:`set(ledgers) == set(candidate_times)`;用户可见文案禁用「强相关 / 有关联 / 弱关联」;列内不得再出现 `

`「经历对照 / 往后 12 个月」。对照盘高亮一旦给 `.is-changed` 写规则,该类名必须离开 `knownUnstyled`(见 BUG-622)。 +- 相关记录:BUG-597、BUG-615、BUG-622、`TASK-rectification-compare-card-polish-20260909.md` - 复发自:BUG-597(三列对照的 by_time 只覆盖引擎前三) - 修复版本:待发布 @@ -9630,8 +9630,24 @@ - 触发条件:交付卡出现后点其中一列「更像这个」;尤其是没有后续核对题、`next_user_action` 为 `start_consultation` 时。 - 根因:`showSelectionCards` 用 `!busy` 整张卸卡;采用请求把对话标成 busy。收尾句用未定义样式的 `.rectification-pending-note` 直接挂在消息列表里,没有助手列让位。采用后若 live offer 锚点被清掉,卡也不再回到原消息。 - 修复:采用中或已采用时 busy 不再卸卡;用 resultId 锁住首次出示卡片的那条消息。收尾句改到卡片下方,样式与卡片同一条左边线。已采用列按钮保持按下并禁用。不恢复输入框上方状态条。 -- 验证:`frontend/tests/rectification-adopt-cards-stay-20260909.test.ts`、`frontend/tests/rectification-candidate-offer-anchor.test.ts`。 -- 防复发:交付卡不得因采用 busy 卸载;`verified_idle` 不得使用无 inset 的裸段落;不得把采用状态写回 composer。 -- 相关记录:BUG-595、BUG-619 +- 验证:`frontend/tests/rectification-adopt-cards-stay-20260909.test.ts`、`frontend/tests/rectification-candidate-offer-anchor.test.ts`。`rectification-surface-contract.test.ts` 锁 `verified_idle` 为 `verifiedIdleCopy && !showSelectionCards`(BUG-622)。 +- 防复发:交付卡不得因采用 busy 卸载;`verified_idle` 不得使用无 inset 的裸段落;不得把采用状态写回 composer。改 `verified_idle` JSX 条件时必须同步表面合同正则。 +- 相关记录:BUG-595、BUG-619、BUG-622 +- 复发自:无 +- 修复版本:待发布 + +## BUG-622 | staging 质量门因两条过期前端合同红掉,Deploy staging 未派发 + +- 状态:resolved +- 首次发现:2026-09-09 +- 最近更新:2026-09-09 +- 影响面:Gitea Independent Staging Quality Gate(`npm test --prefix frontend`)、`class-name-definition-contract.test.ts`、`rectification-surface-contract.test.ts` +- 用户现象:staging 推送后质量门失败,镜像不发布。产品 UI 无新故障。 +- 触发条件:`ca921c3f`(BUG-618–620)改了 `verified_idle` JSX;`5c476ba7`(BUG-614/615)给 `.personal-report-chart-cell.is-changed` 写了填充。随后 `af70ae77` 再推 staging 仍是同一对失败(runs 2514 / 2516 / 2517)。 +- 根因:产品代码已改,合同测试仍锁旧字面量。`knownUnstyled` 还列着已有 CSS 规则的 `is-changed`;表面合同仍要求 `questionGap === "verified_idle" && (`,实际已是 `verifiedIdleCopy && !showSelectionCards`。 +- 修复:`is-changed` 移出 allowlist;`verified_idle` 断言改跟现行 JSX。不改业务组件。 +- 验证:`frontend/tests/class-name-definition-contract.test.ts`、`frontend/tests/rectification-surface-contract.test.ts`。 +- 防复发:给已在 allowlist 的 class 加规则必须同时删 allowlist 行;改 `verified_idle` 条件必须改表面合同正则,并写原值/新值/原因。 +- 相关记录:BUG-614、BUG-615、BUG-620 - 复发自:无 - 修复版本:待发布 diff --git a/frontend/tests/class-name-definition-contract.test.ts b/frontend/tests/class-name-definition-contract.test.ts index 9c0fdfa3..cb8c44a0 100644 --- a/frontend/tests/class-name-definition-contract.test.ts +++ b/frontend/tests/class-name-definition-contract.test.ts @@ -48,13 +48,14 @@ const tailwindCollisions = new Set([ // // The `is-*` entries are state hooks whose visual is carried by a sibling // element instead — the thinking step's marker icon, the board minute's -// "当前时间" / "已更新" note. `sidebar-header` and `chart-nav` land on shadcn -// components that style themselves. The rest are modifiers sitting beside an -// already-styled class on the same element. +// "当前时间" / "已更新" note. `is-changed` left this list in BUG-622 once +// `.personal-report-chart-cell.is-changed` got a fill/stroke rule. +// `sidebar-header` and `chart-nav` land on shadcn components that style +// themselves. The rest are modifiers sitting beside an already-styled class +// on the same element. const knownUnstyled = new Set([ "birth-time-evidence-receipt", "chart-nav", - "is-changed", "is-done", "is-live", "is-working", diff --git a/frontend/tests/rectification-surface-contract.test.ts b/frontend/tests/rectification-surface-contract.test.ts index 99f3d303..8adca588 100644 --- a/frontend/tests/rectification-surface-contract.test.ts +++ b/frontend/tests/rectification-surface-contract.test.ts @@ -79,7 +79,10 @@ test("the question gap is a live row with retries, then a reload; it never tells assert.match(chat, /const questionGap = rectificationQuestionGapState\(\{/); assert.match(chat, /questionGap === "preparing" && \(/); assert.match(chat, /questionGap === "unavailable" && \(/); - assert.match(chat, /questionGap === "verified_idle" && \(/); + // 原值:questionGap === "verified_idle" && ( + // 新值:questionGap === "verified_idle" && verifiedIdleCopy && !showSelectionCards && ( + // 原因:BUG-620 把收尾句挪到对照卡下,无 copy 或卡仍在时不单独贴一段;门禁仍锁旧字面量会红(BUG-622) + assert.match(chat, /questionGap === "verified_idle" && verifiedIdleCopy && !showSelectionCards && \(/); assert.match(chat, /RECTIFICATION_QUESTION_UNAVAILABLE_COPY/); assert.match(chat, /RECTIFICATION_QUESTION_RELOAD_LABEL/); assert.match(chat, /useVisibilityAwarePoll\(\{\s*enabled: questionGap === "preparing",\s*intervalMs: RECTIFICATION_QUESTION_RETRY_INTERVAL_MS,/);