fix(settings): 弹窗高度补 vh 基线,分区菜单去掉强调条(BUG-698)
Independent Staging Quality Gate / validate (push) Failing after 9m25s
Independent Staging Quality Gate / publish (push) Skipped

设置弹窗的固定高度只用 dvh 写、没有回退。不认识该单位的引擎会把整条
height 与 max-height 作废,盒子退回按内容撑开,于是切分区就跳大小——
这正是 BUG-554 现象的复发,而 BUG-554 的防复发「必须同时声明 width 与
height」只检查声明存不存在,挡不住「写了但没生效」。

实测(Chrome 151,真实产物 CSS + 复刻 DOM,1440×900):dvh 正常时四个
分区恒定 866.80×640px,**事故不复现**;摘掉 dvh 后变成 313/313/378/1130,
宽度不动——与用户描述的形状完全一致。因此机制已证实,但用户当时的浏览器
未定位,BUG-698 记为 investigating 而非 resolved。

附带发现:任务书要求照抄的重复声明式回退 `height: 100vh; height: 100dvh;`
在本仓根本发布不出去——Lightning CSS 会合并同名属性的重复声明只留最后一条,
全仓唯一那处回退(sidebar-provider)在线上早就是死的,还有一条测试专门守着
这个从未发布过的写法。改用 @supports (height: 1dvh):vh 作基线,dvh 作升级。
修复后不支持 dvh 的引擎也收敛到恒定 640px,支持的逐像素无变化。

同轮按产品决策去掉设置分区菜单的左侧/下方强调色条,选中与悬停改用面与
墨色等级区分,不用色相、不用字重。左侧会话列表的色条本轮不动。

- 新增 viewport-unit-fallback-contract(3 条,全文件),三次破坏性验证各自打红
- account-dialog-overlay 新增同尺寸契约与分区菜单契约
- 三条钉死旧 dvh 字面量的既有断言按「原值/新值/原因」更新,均未弱化
- tsc 0 错;lint 0 error / 118 warning(持平);npm test 3346/3300/fail 31,
  失败清单与基线逐字相同;/ 仍 ○ Static;样式 gzip +0.38%;
  快速门 pytest 段 792 passed / 1 skipped / 0 failed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
Jesse_Chen
2026-09-16 03:50:38 +00:00
co-authored by Claude Opus 5
parent 5582091851
commit 111b4a8455
11 changed files with 538 additions and 20 deletions
+21 -1
View File
@@ -8576,7 +8576,7 @@
- 根因:`accountDialogClasses` 给每个分区不同宽度,高度随内容撑开。星盘资料没有列表/详情视图,添加表单始终渲染。第四个导航项直接 `router.push``/membership`
- 修复:四个分区共用 `.settings-modal` 固定尺寸。星盘资料改为列表→详情。账户与点数成为弹窗第四分区;删除 `/membership``/membership/orders`,旧链接重定向到 `/?settings=billing`。七处入口改为 `openAccountDialog("billing")`
- 验证:`frontend/tests/account-dialog-overlay.test.ts``billing-panel.test.ts``membership-page.test.ts``membership-navigation-contract.test.ts``chart-library-other-profile.test.ts``settings-url.test.ts``beam-avatar.test.ts``class-name-definition-contract.test.ts``tests/test_api_server_security.py -k capability_audit``next build --webpack``/` 为 Static,无 `/membership` 页面。
- 防复发:设置弹窗必须同时声明 width 与 height;星盘资料默认视图不得无条件渲染 `<form``/` 保持 Static,不得 `useSearchParams`;收银台仍 `window.open`;硬跳转清单不得因本单变长。
- 防复发:设置弹窗必须同时声明 width 与 height;星盘资料默认视图不得无条件渲染 `<form``/` 保持 Static,不得 `useSearchParams`;收银台仍 `window.open`;硬跳转清单不得因本单变长。**2026-09-16 修正,见 BUG-698**:「必须同时声明 width 与 height」这条防不住复发——它检查的是声明存在性,不是声明是否生效。`.settings-modal` 后来 width 与 height 都老实写着,却因为 height 只用 `dvh`、不认识该单位的引擎整条作废而再次随分区跳变。固定高度的单位回退口径以 BUG-698 为准。
- 相关记录:BUG-434、BUG-251、BUG-143
- 复发自:无
- 修复版本:`dc6598d7`
@@ -11477,3 +11477,23 @@
- 相关记录:BUG-729731(创建路由改造)、BUG-464(会话持久化归属)
- 复发自:无
- 修复版本:待发布
## BUG-698 | 设置弹窗尺寸随分区变化:dvh 无回退,且仓库唯一那处回退被压缩器吃掉
- 状态:investigating
- 首次发现:2026-09-15
- 最近更新:2026-09-16
- 影响面:`frontend/src/app/globals.css``.settings-modal` / `.account-modal` 及全文件 8 处 `height: …dvh`)、设置弹窗四分区、登录页、后台外壳、移动端侧栏
- 用户现象:「设置面板的弹窗大小不一样,选别的就立马缩小了。」宽度没动,高度在跳。
- 触发条件:登录后打开设置弹窗,在个人资料 / 星盘资料 / 账户与点数 / 通用设置之间切换。
- 根因(机制已证实,用户环境未定位):`.settings-modal``height``max-height` 只写了 `dvh`,没有 `vh` 回退。不认识该单位的引擎会**整条声明作废**,`height` 回到 `auto`,高度改由内容决定;`max-height` 同时作废后连上限都没有,于是内容多的分区高、内容少的分区矮。宽度走 `vw` 不受影响,所以看上去只有高度在跳。
- **实测(Chrome 151.0.7922.1691440×900,真实 `next build` 产物 CSS + 逐节点复刻的弹窗 DOM)**:dvh 正常时四个分区全是 866.80 × 630.40、computed height 640px —— **事故在当前浏览器上不复现**;把 dvh 摘掉后四个分区变成 313.23 / 313.23 / 378.58 / 1130.16,宽度不变 —— **与用户描述的形状完全一致**
- `dvh` 自 Chrome/Edge 108、Safari 15.4、Firefox 101、Android WebView 108 起支持,因此该机制只在旧 iOS 15.015.3、未升级的 Android System WebView、或钉死旧 WebView 的 App 内置浏览器上成立。**用户当时用的是哪个浏览器尚未确认,这是本条停在 `investigating` 而不是 `resolved` 的唯一原因。**
- 为什么 BUG-554 的防复发没拦住:BUG-554 的条款是「设置弹窗必须同时声明 width 与 height」,守着它的断言是 `assert.match(styles, /\.settings-modal \{[^}]*width:[^}]*height:/)` —— 它读 CSS 源文本,只检查**声明存不存在**,不检查声明**是否生效**。本次 width 与 height 都老实写着,条款全绿,现象照出。**BUG-554 的四个分区共用一个类这一条本轮未被推翻,且新增了直接断言常量的同尺寸契约把它钉死。**
- 附带发现(比原判更严重):任务书要求照抄 `globals.css:637` 的重复声明式回退 `height: 100vh; height: 100dvh;`。实测 **Lightning CSSTailwind v4 的压缩器)会合并同一规则内同名属性的重复声明,只保留最后一条**:源码写了两条,产物里 `.group\/sidebar-provider[data-viewport]` 只剩 `height:100dvh`。**全仓唯一那处 vh 回退在线上早就是死的**,而且 `birth-time-mobile-scroll-contract.test.ts` 还有一条断言专门守着这个从未发布过的写法。照任务书交付等于交一个 no-op。
- 修复:改用特性查询 —— `vh` 作基线,`@supports (height: 1dvh)` 内升级为 `dvh`,压缩器无法证伪条件因而整块保留。覆盖凡 `height`(不含 `max-height` / `min-height`)用 dvh 的 8 处:`.standalone-page``.app-loading``.group\/sidebar-provider[data-viewport]``.admin-app-shell``.auth-page``[data-sidebar="sidebar"]``.settings-modal`(桌面与移动端);另把 `.account-modal` / `.settings-modal``max-height` / `min-height` 一并纳入,因为实测里 `max-height` 塌成 `none` 也是尺寸失控的一环。同轮去掉设置分区菜单的强调色条并拆开选中/悬停两态(产品决策,不占编号)。
- 验证:修复后同 harness 重测 —— dvh 正常的引擎四个分区仍是 866.80 × 630.40 / 640px**与修复前逐像素一致,无回归**);模拟不支持 dvh 的引擎从 313/378/1130 收敛到恒定 640px。新增 `frontend/tests/viewport-unit-fallback-contract.test.ts`(3 条,全文件范围),三次破坏性验证各自打红对应那条、还原后全绿。`account-dialog-overlay.test.ts` 新增同尺寸契约与分区菜单契约,破坏性验证同样打红。`tsc --noEmit` 0 错,`npm run lint` 0 error / 118 warning(持平基线),`next build``/``○ Static`,快速门 pytest 段 792 passed / 1 skipped / 0 failed。
- 防复发:**`height``dvh` 必须写成 `vh` 基线 + `@supports (height: 1dvh)` 升级,不得用 `height: 100vh; height: 100dvh;` 重复声明式回退**——后者会被 Lightning CSS 吃掉,从来没发布过。由 `frontend/tests/viewport-unit-fallback-contract.test.ts` 全文件强制,三条断言分别管「dvh 必须在特性查询内」「禁止重复声明式回退」「升级过的选择器必须有 vh 基线」。设置弹窗四分区必须映射到同一个类名,由 `account-dialog-overlay.test.ts` 直接断言常量。**只检查「声明存不存在」的 CSS 文本断言不算防线**(这就是 BUG-554 的教训),新写 CSS 契约要么断到实际产物、要么断到可被破坏性验证证伪的结构。
- 相关记录:BUG-554(同一现象的第一次,本条为其复发)、BUG-695~697(触控与断点轮次,同一文件相邻区段)
- 复发自:BUG-554
- 修复版本:待发布
@@ -0,0 +1,222 @@
# PROGRESS · 设置弹窗尺寸(BUG-698)+ 分区菜单去强调条
- 日期:2026-09-16
- 任务书:`docs/tasks/TASK-settings-dialog-size-and-nav-20260915.md`
- 分支:`codex/settings-dialog-size-and-nav-20260916`
- 工作树:`.worktrees/settings-dialog-size-and-nav-20260916`
- 实际基线:`origin/staging` @ `5094fd26`(任务书写的 `6c748d86` 已被十余个提交超车;三条前提逐条复核仍成立,见 §1)
- BUG 编号:`docs/BUG_HISTORY.md` 当前最大号 **BUG-736**`BUG-698` 未被占用,按任务书使用 `BUG-698`,未顺延。
---
## 1. 开工前置:前提仍然成立
| 任务书断言 | `5094fd26` 实测 | 结论 |
|---|---|---|
| `accountDialogClasses` 四分区全是 `"settings-modal"` | `home-types.ts:211-217` 四项均为 `settings-modal` | 成立 |
| `.settings-modal` 同时写死 width 与 height | `globals.css:1757``width: min(100vw - 32px, 880px); height: min(84dvh, 640px)` | 成立 |
| 桌面强调条 `inset 2px 0 0 var(--color-action)` | `globals.css:1762` | 成立 |
| 移动端强调条 `inset 0 -2px 0 var(--color-action)` | `globals.css:1948` | 成立 |
| 选中态与悬停态共用一条规则 | `globals.css:1761` | 成立 |
| BUG-554 防复发「必须同时声明 width 与 height」 | 仍在,且仍绿 | 成立(本轮不推翻) |
`AccountDialogOverlay` 四个分区的 DOM 结构完全一致(`account-dialog-overlay.tsx:76-94`),`dialog``model.dialogClass` 在同一次 render 里都来自 `activeAccountDialog``page.tsx:1510-1512``1827-1831`),不存在切换瞬间掉类的中间帧。**所以外框尺寸只可能由 CSS 决定。**
## 2. 任务 1.1 复现:有浏览器,有数字
会话没有登录态,但本机有 `google-chrome 151.0.7922.169`。做法是绕开登录、直接量 CSS:把 `next build` 产出的**真实 chunk CSS**`.next/static/chunks/*.css`)和按 `account-dialog-overlay.tsx` 逐节点复刻的 DOM 组成离线页面,四个分区各塞 6 / 24 / 3 / 1 段内容模拟真实内容量差,headless Chrome 量 `section.account-modal.settings-modal``getBoundingClientRect()` 与 computed style。窗口 1440×900。
harness`gen.js` + `supported.html` / `nodvh.html`scratchpad,未提交)。
### 2.1 基线 `5094fd26`dvh 正常的引擎(Chrome 151
| 分区 | rect w | rect h | computed height | computed max-height |
|---|---:|---:|---|---|
| 个人资料 | 866.80 | 630.40 | 640px | 640px |
| 星盘资料 | 866.80 | 630.40 | 640px | 640px |
| 账户与点数 | 866.80 | 630.40 | 640px | 640px |
| 通用设置 | 866.80 | 630.40 | 640px | 640px |
rect 630.40 < computed 640 是 `account-dialog-enter` 入场动画的 transform,四个分区同值,不影响结论。)
**四个分区宽高完全一致,`height` 声明没有被划掉,计算值不是 `auto`。按任务书 §5 任务 1.1 的分支判断,事故在当前浏览器上不复现。**
### 2.2 同一份 CSS,去掉 dvh 支持
把 chunk 里所有 dvh 声明摘掉,模拟不认识该单位的引擎:
| 分区 | rect w | rect h | computed height | computed max-height |
|---|---:|---:|---|---|
| 个人资料 | 866.80 | 378.58 | 384.344px | none |
| 星盘资料 | 866.80 | 1130.16 | 1147.38px | none |
| 账户与点数 | 866.80 | 313.23 | 318px | none |
| 通用设置 | 866.80 | 313.23 | 318px | none |
**宽度纹丝不动(走 `vw`),高度随内容量在 313 / 378 / 1130 之间跳。** 这正是用户原话「大小不一样,选别的就立马缩小了」的形状。任务书 §2.2 推测的机制被证实为**唯一**能产生该现象的 CSS 路径,但它以「引擎不认识 dvh」为前提。
### 2.3 结论与诚实边界
- `dvh` 的支持面是 Chrome/Edge 1082022-11)、Safari 15.42022-03)、Firefox 1012022-05)、Android WebView 108。**任何当前浏览器都支持**,所以产品负责人若在新版 Chrome / Safari 上看到该现象,本机制解释不了。
- 仍然可能命中的环境:iOS 15.015.3、未升级的 Android System WebView< 108)、以及部分把旧 WebView 钉死的 App 内置浏览器(微信/QQ 等)。对一个中文消费产品这不是零概率,但**本轮无法证明用户就在其中**。
- 因此 BUG-698 记为 **`investigating`**,不是 `resolved`。机制已确认、已加固,但用户实际环境未定位。
## 3. 任务书的修复方案不成立(本轮最重要的发现)
任务书 §1.2 让我们照抄 `globals.css:637` 的写法,补成重复声明:
```css
height: min(84vh, 640px);
height: min(84dvh, 640px);
```
**这个写法在本仓根本到不了浏览器。** 先按任务书实现了一版,`next build` 后 grep 产物:
```
.settings-modal{...;width:min(100vw - 32px,880px);height:min(84dvh,640px);max-height:min(84dvh,640px);...}
```
`vh` 那条不见了。再去查任务书引为范本的那一行:
- 源码 `globals.css:637``.group\/sidebar-provider[data-viewport] { height: 100vh; height: 100dvh; ... }`
- 产物:`sidebar-provider[data-viewport]{height:100dvh;min-height:0;overflow:hidden}`
**Lightning CSSTailwind v4 的压缩器)会合并同一规则内同名属性的重复声明,只保留最后一条。** 也就是说:全仓唯一那处「标准写法」的 vh 回退,在线上**早就是死的**;任务书若原样交付,等于交一个 no-op。
改用特性查询,Lightning CSS 无法证伪条件,整块原样保留:
```css
.settings-modal { width: min(100vw - 32px, 880px); height: min(84vh, 640px); max-height: min(84vh, 640px); ... }
@supports (height: 1dvh) {
.settings-modal { height: min(84dvh, 640px); max-height: min(84dvh, 640px); }
}
```
产物核对(`@supports` 完整保留):
```
@supports (height:1dvh){.standalone-page,.app-loading,.group\/sidebar-provider[data-viewport],.admin-app-shell,.auth-page{height:100dvh}.account-modal{max-height:min(84dvh,760px)}.settings-modal{height:min(84dvh,640px);max-height:min(84dvh,640px)}}
@supports (height:1dvh){[data-sidebar=sidebar]{height:100dvh}.account-modal{min-height:100dvh;max-height:100dvh}.settings-modal{height:100dvh;max-height:100dvh}}
```
### 3.1 修复后重测(同 harness,同窗口)
| 引擎 | 四个分区 rect | computed height |
|---|---|---|
| dvh 正常(Chrome 151 | 866.80 × 630.40 ×4,全等 | 640px ×4 |
| 去掉 `@supports` 块(模拟不支持 dvh | 866.80 × 630.40 ×4,全等 | 640px ×4 |
**支持 dvh 的浏览器行为与修复前逐像素一致(无回归);不支持 dvh 的引擎从 313/378/1130 的跳变收敛到恒定 640px。**
覆盖范围:凡 `height`(不含 `max-height` / `min-height`)用 dvh 的 8 处全部改为 vh 基线 + `@supports` 升级 —— `.standalone-page``.app-loading``.group\/sidebar-provider[data-viewport]``.admin-app-shell``.auth-page``[data-sidebar="sidebar"]``.settings-modal`(桌面与移动端)。另把 `.account-modal` / `.settings-modal``max-height` / `min-height` 一并纳入,因为 §2.2 实测里 `max-height` 塌成 `none` 也是尺寸失控的一环。其余只写 `max-height` 的(`.session-actions-positioner``.account-menu-popup``.auth-shell``.select-content``.select-list`)按任务书不动 —— 作废后只是少一个上限,不会让盒子随内容跳变。
`.admin-app-shell``globals.css` 里,属于布局类而非 antd / Refine 组件,改的是同一条 dvh 规则,不触碰任务书 §4.5 的 admin 红线。
### 3.2 自查抓到一个自己引入的回归(已修)
第一版把全部 7 个选择器的 dvh 升级都放进**顶层** `@supports`。复查 diff 时发现 `.auth-page` 的高度基线只存在于 `@media (max-width: 767px)` 内(`globals.css:1952`),顶层那条 `.auth-page { display: grid; place-items: center; padding: … }` 本来**没有高度**。放到顶层等于给桌面登录页新加了一个满视口高度约束 —— 桌面登录页原本是随内容高的。已把 `.auth-page` 的升级挪进移动端作用域内的 `@supports`
**新增的契约测试没能抓到这个**:它只验「文件里某处存在 vh 基线」,不验基线与升级是否在同一个 at-rule 作用域。这条限制已写进测试文件头部注释,提醒后来者手工对齐作用域。其余 6 个选择器的基线都在顶层,作用域本就一致,逐个复核过。
## 4. 任务 1.3 防复发:从「写没写」升级到「量不量得到」
新增 `frontend/tests/viewport-unit-fallback-contract.test.ts`3 条,全文件范围):
1. `height:` 用 dvh 的声明必须落在 `@supports (height: 1dvh)` 内。
2. 禁止重复声明式回退 —— 它会被压缩器吃掉,测试里写明了原因。
3. `@supports` 里升级过的每个选择器,块外必须有 vh 基线(否则不支持的引擎干脆没有高度)。
解析前先剥 CSS 注释:本文件自己的说明注释里引用了 `height: 100vh; height: 100dvh;` 这个坏写法,不剥会自伤(首次运行就被这条打红,已修)。
**破坏性验证**(三次,跑完都还原,未提交):
| 破坏 | 预期 | 实测 |
|---|---|---|
| `.settings-modal` 基线换回 dvh | 第 1 条红 | `not ok 1`2/3 绿 |
| `.admin-app-shell` 改回 `height: 100vh; height: 100dvh;` | 第 2 条红 | `not ok 1` + `not ok 2` |
| 删掉 `.auth-page` 的 vh 基线只留 `@supports` | 第 3 条红 | `not ok 3`1/2 绿 |
| 还原 | 全绿 | `ok 1 / ok 2 / ok 3` |
`account-dialog-overlay.test.ts` 新增 2 条:
- 同尺寸契约:`accountDialogClasses` 四个设置分区映射到同一个类名(直接 import 常量断言,不再只验单个分区的渲染),且 `logout` 与之不同。
- 分区菜单契约:`[aria-current="page"]``:hover` 规则内都不含 `box-shadow`、不含 `font-weight`,且两者必须是各自独立的规则块。破坏性验证:把强调条与合并规则塞回去 → `not ok 5`,还原 → `ok 5`
原有 `assert.match(styles, /\.settings-modal \{[^}]*width:[^}]*height:/)` **未改动**(新 CSS 仍然匹配),只在上方加注释说明它是存在性检查、真正的防线是上述两处。**本轮没有修改任何既有断言,所以不涉及「原值 / 新值 / 原因」三栏。**
## 5. 任务 2:分区菜单
改动(`globals.css`):
```css
/* 前 */
.settings-dialog-nav-item:hover, .settings-dialog-nav-item[aria-current="page"] { background: var(--color-canvas-muted); color: var(--color-ink); }
.settings-dialog-nav-item[aria-current="page"] { box-shadow: inset 2px 0 0 var(--color-action); }
/* 移动端 */ .settings-dialog-nav-item[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--color-action); }
/* 后 */
.settings-dialog-nav-item:hover { background: color-mix(in srgb, var(--color-canvas-muted) 55%, transparent); color: var(--color-ink-secondary); }
.settings-dialog-nav-item[aria-current="page"] { background: var(--color-canvas-muted); color: var(--color-ink); }
/* 移动端那条整条删除 */
```
- 三态可分:默认透明 + 次级墨 → 悬停 55% 淡面 + 次级墨 → 选中实面 + 主墨。选中比悬停重一档,靠面与墨色等级,不用色相、不用 `font-weight`(任务书 §3.3)。
- 取 55% 的理由:`--color-canvas-muted` 浅色 `#ebe9e3` 压在 `--color-canvas` `#fbfaf7` 上本就只差一档,悬停若取满会和选中撞;55% 是仓库里已有的同族用法(`globals.css` 现有 84 处 `color-mix`,如 `.evidence-audit-panel` 用 68%、`.evidence-audit-row` 用 64%),**没有引入新字面色值、没有新 token**。
- 深色:`--color-canvas-muted` `#30302d``--color-ink` `#f2f0ea``--color-ink-secondary` `#b3afa4` 三者在深色块里都已定义,改动只用既有 token,`dark-theme-contract.test.ts` 无需新增条目(实跑仍绿)。深浅两套的肉眼可分辨留给真人清单。
- 移动端(≤767px)导航是顶部四栏,触摸没有 hover,选中态即实面 + 主墨,删掉下边框后仍与其余三项可分。
- 可达性:`:focus-visible` 描边规则未动;`aria-current="page"` 仍在 DOM 上,屏幕阅读器不受影响 —— 选中态不是只靠颜色。
- 左侧会话列表的 2px `--sidebar-ring` **本轮未动**(任务书 §3.2),两处观感暂时不一致,已在 `DESIGN.md` 写明是已知且授权的。
## 6. 验收
| 项 | 基线 `5094fd26` | 本轮 | 结论 |
|---|---|---|---|
| `tsc --noEmit` | 0 | 0 | 通过(中途新测试有 1 个 TS2345,已修) |
| `npm run lint` | 0 error / 118 warning | 0 error / 118 warning | 通过,warning 未上升 |
| `npm test` | tests 3341 / pass 3295 / fail 31 / skipped 15 | tests 3346 / pass 3300 / fail 31 / skipped 15 | 通过,失败清单与基线**逐字相同** |
| `next build` `/` | `○ Static` | `○ Static` | 通过 |
| 样式 gzip | 37,547 B | 37,688 B | +141 B / **+0.38%**,在 ±2% 内 |
| 快速门 pytest 段 | 792 passed / 1 skipped / 0 failed | 792 passed / 1 skipped / 0 failed | 通过 |
| `Home()` useState / useRef | 36 / 37 | 36 / 37(未碰 `page.tsx` | 未增长 |
| `page.tsx` 行数 | 1846 | 1846(未改动) | 未增长 |
gzip 口径:Next 16 的路由表不再打印 First Load JS,本轮又只改 CSS,所以量的是产物样式 chunk 本身——把新增的两个 `@supports` 块摘掉再 gzip 作对照(37,547 B),带上是 37,688 B。
本轮只动 `globals.css``DESIGN.md` 与五个测试文件,`page.tsx` 与任何 Home 级 hook 都没碰,所以没有新增 Home 级 hook,不涉及 `OPTIONAL_HOME_HOOKS` 登记(BUG-736)。
### 6.1 全量套件
`tests` 3341 → **3346**+5,正是本轮新增的 5 条),`pass` 3295 → **3300**+5),`fail` 31 → **31**`skipped` 15 → 15。测试总数没有下降。
失败清单与基线 `diff` 结果为**完全一致**(31 条,全是无 Docker 的 DB / 部署 / 引擎套件,`BLOCKED.md` BLK-002 / BLK-003):
```
comm -13 fails-baseline.txt fails-final.txt # 新增失败:空
comm -23 fails-baseline.txt fails-final.txt # 消失失败:空
diff -q fails-baseline.txt fails-final.txt # IDENTICAL
```
**中途出现过 3 条新失败,已修,原因记在 §6.1.1。**
#### 6.1.1 三条既有断言按「原值 / 新值 / 原因」改动
改 dvh 写法打红了三条把旧文本钉死的断言。三条都**保留原有意图(满视口高度 / 全视口滚动容器)**,只把断言对象换成真正会发布的写法,没有一条被弱化或删除:
| 文件 | 原值 | 新值 | 原因 |
|---|---|---|---|
| `tests/birth-time-mobile-scroll-contract.test.ts` | `/\.group\\\/sidebar-provider\[data-viewport\]\s*\{[^}]*height:\s*100vh;[^}]*height:\s*100dvh/` | 拆成两条:块内 `height:\s*100vh;`,外加 `@supports (height: 1dvh)` 内该选择器 `height: 100dvh` | **这条原本守着一个从未发布过的写法。** 重复声明式回退被 Lightning CSS 合并,产物里只剩 `height:100dvh`;断言读的是源码文本所以一直绿。换成断两半后,vh 基线与 dvh 升级都必须真在。 |
| `tests/mobile-interaction-contract.test.ts` | `css.indexOf(".auth-page { height: 100dvh; overflow-x: hidden; overflow-y: auto;")` | 同串改 `height: 100vh`,并**新增**一条断 `@supports` 内有 `.auth-page { height: 100dvh; }` | 登录页的满视口高度改为 vh 基线 + 特性查询升级。原断言只认旧字面量。断言数量从 1 增到 2,未放宽。 |
| `tests/admin-payments-contract.test.ts` | `/\.admin-app-shell \{ height: 100dvh; min-height: 0; overflow-y: auto; \}/` | 同串改 `height: 100vh`,并**新增**一条断 `@supports` 内有 `.admin-app-shell { height: 100dvh; }` | 同上。后台外壳仍是独立全视口滚动容器,只是高度写法换了。断言数量从 1 增到 2,未放宽。 |
### 6.2 快速门
`.venv/bin/python scripts/run_quality_gate.py --profile quick`**pytest 段 792 passed / 1 skipped / 0 failed**,与基线一致。
快速门整体退出 1,唯一原因是本机无 `rsync`、无 Docker 的既有环境缺口(`BLOCKED.md` BLK-002 / BLK-003),与本轮改动无关。退出码直接取自命令本身,没有隔着管道。
## 7. 环境缺口
1. **无登录态、无法在真实应用里走查。** §2 的数字是在真实产物 CSS + 逐节点复刻 DOM 的离线页面上量的,不是在跑起来的应用里量的。真实内容(星盘资料的列表/详情、账户与点数的套餐卡)可能有本 harness 没模拟到的溢出行为。浏览器级条目见 `docs/testing/settings-dialog-20260916.md`
2. **无法确认用户当时的浏览器。** 这是 BUG-698 停在 `investigating` 的唯一原因。需要产品负责人补:哪两个分区、什么浏览器与版本、窗口多大、能否截图。
3. 无 Docker:DB / 部署套件 31 条失败沿用基线(`BLOCKED.md` BLK-002 / BLK-003),与基线逐条比对见 §6.1。
4. 深浅两套主题下「悬停 vs 选中」肉眼可分辨、以及 375px 下四栏观感,都需要真人确认。
+66
View File
@@ -0,0 +1,66 @@
# 真人验收清单 · 设置弹窗尺寸与分区菜单(BUG-698 + 分区菜单产品决策)
- 日期:2026-09-16
- 分支:`codex/settings-dialog-size-and-nav-20260916`
- 对应:`docs/tasks/TASK-settings-dialog-size-and-nav-20260915.md``docs/tasks/PROGRESS-settings-dialog-size-and-nav-20260916.md`
会话侧已经量过的(**不用再做**):真实产物 CSS + 复刻 DOM 的离线页面上,四个分区在支持与不支持 `dvh` 两种引擎下都恒定 866.80 × 640px。下面全是会话做不了的:需要登录态、真实内容、真实设备、以及人眼。
---
## A. 尺寸:四个分区切换不跳变
1. 登录后打开设置弹窗。
2. 依次点 个人资料 → 星盘资料 → 账户与点数 → 通用设置 → 再点回 个人资料。
3. **看外框四条边有没有动。** 尤其是底边:星盘资料内容最多、通用设置最少,是最容易露馅的一对。
4. 通过标准:外框纹丝不动,只有右侧内容区在换;左侧 176px 导航与标题栏不动。
在这几种窗口下各走一遍:
| 场景 | 怎么弄 | 预期 |
|---|---|---|
| 桌面常规 | 浏览器最大化 | 宽 880px 上限,高 640px,四分区全等 |
| 矮窗口 | 把窗口高度拖到 600px 左右 | 高度变成 84% 视口高,**四分区仍全等** |
| 窄窗口 | 宽度拖到 900px 以下 | 宽度跟着收,四分区仍全等 |
| 手机宽度 375px | DevTools 设备模拟 或 真机 | 弹窗全屏,导航变顶部四栏,切换不跳 |
5. **星盘资料分区要展开到最满再切**:进列表 → 点开某个人的详情 → 再切到 通用设置。内容最多的一刻切走,是本 Bug 最容易复现的时机。
## B. 尺寸:旧引擎(本 Bug 的真正目标环境)
本条是**定位用**的,不是回归用的。BUG-698 停在 `investigating` 就是因为没人知道用户当时用的什么浏览器。
1. 产品负责人回忆并回答:出现「选别的就立马缩小」时,用的是**哪个浏览器、哪个版本、什么设备**?是电脑浏览器,还是微信 / QQ 里点开的?窗口多大?能否截图?
2. 若手边有 iOS 15.015.3 的旧 iPad / iPhone,或较老的安卓机(System WebView 低于 108),在上面走一遍 A 的第 1–4 步。
- 修复前:高度会随分区跳(这就是用户看到的)。
- 修复后:应当恒定。
3. 若产品负责人当时用的是**新版 Chrome / Safari**,那么本轮的修复解释不了那次现象,需要带着截图另开一轮 —— 请如实回报,不要因为现在看着正常就当作已修。
## C. 分区菜单:三态可分辨
1. 打开设置弹窗,鼠标**不要**碰导航,看当前分区那一项:应是**实心浅底 + 深墨字**。
2. 鼠标划过另外三项:应出现**比选中更淡的一层底**,字仍是次级墨(比选中浅一档)。
3. 通过标准:
- **没有任何左侧竖色条**(这是本轮产品要求删掉的东西)。
- 选中项与悬停项**一眼能分出谁是当前**:选中的底更实、字更黑。
- 字**没有变粗**(产品明确不要加粗)。
4. 把鼠标移到当前分区上(同时是选中 + 悬停):不应闪烁或变得比不悬停时更淡。
## D. 分区菜单:深色主题
1. 系统或应用切到深色,重复 C 的 1–4。
2. 通过标准:深色下悬停那层淡底**仍然看得见**(这是 55% 混透明,深色底上对比最容易不够,是本轮最需要人眼确认的一点);选中仍比悬停重一档。
3. 若深色下悬停几乎看不出来,如实回报,把 55% 调高即可 —— 不要改成加色条或加粗。
## E. 移动端(≤767px
1. 375px 宽下打开设置弹窗:导航是顶部四栏。
2. 通过标准:当前那一栏是实心底 + 深墨字;**底部没有横向色条**(本轮删掉的);四栏等宽,点哪栏切哪栏。
3. 触摸设备没有 hover,所以这里只需确认「当前」这一态够明显。
## F. 不该被碰到的(回归检查)
1. 左侧会话列表里当前会话的 **2px 竖色条仍在** —— 本轮只删设置弹窗的,会话列表那条产品说了不动。两处观感暂时不一致是已知且授权的。
2. 键盘 Tab 走到分区按钮上,**焦点描边仍在**。
3. 退出登录确认弹窗仍是 400px 的小框,没被撑成大弹窗。
4. 登录页、后台页面(`/admin`)、移动端侧栏抽屉的满屏高度正常 —— 本轮一并改了它们的 dvh 写法。