ac62dafde16879d8f5b944e61e2e1e92bac09caf
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| b7c5d8b1e7 |
跨端: 邮件转发上线(详情页缺的入口)+ 修两个真 bug(动作球重叠 / 键盘挡住按钮)
审计发现详情页缺三块功能之一 —— **转发**。服务端 `forward.go` 完整、
`MailApi.forward()` 也早就写好了,缺的只是这一页的入口。
## 一、转发(对齐 WebUI `ForwardBar`)
字段与占位文案逐条对齐:收件人 / 抄送(**可折叠**,默认收起)/ 说明 / 引用原文。
`subject` 留空让服务端自动加 `Fwd: ` 前缀(它处理了 "Fwd: Fwd:" 无限叠加)。
★ 请求体用了**专用类型** `ForwardMailRequest`,不复用 `SendMailRequest`:
服务端 `forwardRequest` 只认五个字段,而它的 `Decode()` 是 `DisallowUnknownFields()`
⇒ 多带一个(`body` / `reply_to` / `attachment_ids`…)就 **400**。
—— 这正是我今天在 `AppearancePayload` 上刚犯过的那个错,**端点一个类型一个请求体**。
★ 顺带发现:`MailApi.forward` 的签名**原本就写错了**(参数类型是 `SendMailRequest`)
—— 一直没被发现,因为**从来没有调用方**。"写好了但没人用"的代码,
连它自己的类型对不对都没人验过。
## 二、真 bug ①:两个动作球**几乎完全重叠**
转发球与回复球**各自**写在 `Stack({alignContent: BottomEnd})` 里、各带一个 margin。
实测 dump 的 bounds(密度 2.875):
转发 [2984,2010][3122,2148]
回复 [2949,1998][3110,2159] ← 重叠区 x ∈ [2984,3110]
屏幕上只看得到一个球,**转发入口等于不存在**。
根因:`Stack.alignContent` 把**每个**子元素都摆到同一个角,margin 只是各自微调。
修法:用 `Row({ space: 12 })` 包住两个球、由 Row 带 margin 到角落。
**设备实测**(修后 dump):`[2776,2021][2914,2159]` 与 `[2949,1998][3110,2159]`,不重叠。
## 三、真 bug ②:键盘一弹,「转发」按钮就被顶出屏幕
转发弹层第一版**没有高度**(只有 `padding(16)`)⇒ 尺寸由内容决定。
而 ArkUI 默认的键盘避让是 `KeyboardAvoidMode.OFFSET`(整体上移)——
上移之后 `TextArea` 与「取消 / 转发」按钮**跑到键盘下面**,点不到。
实测截图:只看得见收件人输入框 + 键盘。
修法两半(缺一不可):
① 弹层给明确高度 `height('60%')`(与回复弹层一致,它一直没出问题);
② 说明框改 `layoutWeight(1)`(不是固定 `height(70)`)—— 键盘顶上来时它自己缩短,
把按钮留在屏内。
**设备实测**(键盘弹出时 dump):`取消 [1196,2054][1426,2158]`、
`转发 [2880,2054][3110,2158]` 都在屏内(屏高 2232),且 `clickable=true`。
## 四、判据(这两条固化了上面两个形状)
`harmony-admin` 新增两条**静态形状**判据(它们抓的是写法,不需要设备):
1. **同一 `Stack` 里的多个圆形按钮必须被 `Row` 包住**(否则重叠);
2. **底部弹层必须有明确高度** + 会撑高的子元素用 `layoutWeight`
(否则键盘一弹按钮就被顶出屏幕)。
★ 为什么用静态判据而不是设备判据:这两个 bug 的**形状**在源码里就看得见
(`Stack` + 各自 margin / 弹层缺 `.height`),而设备判据要摆出"键盘弹出"这个态,
成本高且不稳。静态判据在这里是**更快更准**的那一层。
(设备判据仍保留在别处,验"真的能打开、真的渲染出来"。)
## 五、验证
`run-all.mjs` → `files=32 ran=32 checks=509 pass=509 fail=0 skip=0
red=0 broken=0 unreported=0`(`harmony-admin` 28 → 30)。`hvigorw assembleHap` 成功。
**设备实测**:转发球与回复球分开显示(各自图标可见);
点转发球 → 转发框打开(「转发「…」」+「抄送」折叠开关 + 取消/转发);
键盘弹出后按钮仍在屏内可点。
**未验**:真发一封转发(收件人输入在自动化里不稳 ——
`uitest inputText` 是**追加**而非替换,且 `keyEvent Back` 会退出页面而不是收键盘。
这条留待真人操作窗口,与 `harmony-p4c-boundary-decls` 那笔同性质)。
|
|||
| a18014e1e3 |
判据: 管理页设备判据(到期静态判据的第一条升级)+ 修设备判据基建的三个真 bug
`run-all.mjs` 的 `STATIC_ONLY` 里登记着 6 条"只能静态验"的判据,前提是
「本工作区能装、能点设备」。设备现在可用 ⇒ 它们**到期**了(欠账当场变红)。
这一批升级第一条:`harmony-admin`(用户管理页)。
## 一、新设备判据:管理页真的能打开、列表真的渲染
上面 27 条静态判据判的都是逻辑与接线形态。它们全绿时,
"管理页能不能打开、列表能不能渲染"**一句都没验过** —— 而它最容易坏:
路由注册对了但入口没接上、接口回来了但列表没渲染。
判据自己搭现场:拉起应用 → 进「我的」→ 滚到底 → 点「管理」→
断言真的在管理页(出现「新建用户」)且**渲染出用户行**。
## 二、途中撞出三个**判据自身**的 bug(都已修,都写了教训)
1. **`tapText` 从来没成功点过任何东西**(`lib/harmony-device.mjs`)
`findByText` 返回的是**数组**,我当单个节点用了 ⇒ `node.attributes` 恒
`undefined` ⇒ 恒返回 `false`。症状极隐蔽:调用方以为"没找到那个文案",
实际是帮手自己坏了。修:从数组里挑,且**优先挑可点的那个**
(同名文案常常一个可点、一个不可点)。
2. **判据之间互相干扰**(新增 `backToMain`)
每个设备判据都是写操作,会把前台留在它操作完的那一页。`harmony-admin`
把人留在管理页 —— 那是 `pushUrl` 出去的独立 `@Entry` 页,**没有侧栏**
⇒ 后面的 `cross-client-gesture` / `harmony-appearance` 找不到侧栏、
双双 skip(skip 原因写的是"宽屏侧栏找不到",看起来像功能没了)。
`launchOurApp` 解决不了(`aa start` 只切前台,不弹栈)⇒ 新增 `backToMain`。
3. **"找不到元素"要先分清是功能缺失还是判据没摆好现场**
本判据连栽四种形态,每一种都伪装成"功能缺失":
· 锚点文案错(入口是「管理」,我按「用户管理」找 —— 后者只是说明的一部分)
· 元素在滚动下方(dumpLayout 只报可见节点)
· 文字节点不可点(`.onClick` 在包住它的容器上,ArkUI 的常态)
· **滚动步长跨过了它**(诊断打印现场才发现:停在了「系统通知」那一带,
而「管理」只占 ~0.04 屏,一次 0.2 屏的滑动必然越过)
⇒ 最后改成"**先滚到底、再小步回扫**"(只管往前找在不均匀列表上必漏),
并加了 `AGENTMAIL_ADMIN_DEBUG=1` 的诊断入口把现场打出来。
## 三、判据
`run-all.mjs` → `files=32 ran=32 checks=505 pass=505 fail=0 skip=0
red=0 broken=0 unreported=0`(连跑两次稳定)。
`harmony-admin` 27 → 28 条。`hvigorw assembleHap` 成功;前端重建。
**设备实测**:管理页从「我的」页打开,显示「管理 / 用户管理 3 / 新建用户」
与三行用户(jianf 管理员 / gui-lab 用户 / test 用户)。
**仍到期未升级**:`harmony-appearance`(已加 2 条设备判据,但登记里其余部分仍静态)、
`harmony-logic`、`cross-client-theme`、`appearance-defaults`、`harmony-imageprep`
—— 按"每条缺什么设备侧验证"逐条来,不为了消数字而凑。
|
|||
| 28e3da76d4 |
跨端: 左右滑动翻页(P6 第 3 步)+ 还 gesture-semantics 债 + 修跑不起来的判据基建
★ 这一轮从用户一句「滑动手势呢?」开始。查下去发现它不是"顺手加个手势",
而是 `docs/DEBTS.json` 里挂着的一笔债 —— `gesture-semantics` 的原话是:
「P6 第 3 步:鸿蒙侧出现滑动手势代码时**立即建**判据
(此前建 = 只有一端存在的假判据)」
也就是**先有手势、再钉语义**。WebUI 2026-09-14 就有滑动翻页(用户当时
亲口提的),鸿蒙一直没有 ⇒ 之前建判据会是空真(∀x∈∅)。
## 一、手势本体(两端语义逐项对齐,数值各自定)
按 `HARMONY-ALIGN-PLAN.md:118-128` 显式选的 **(b) 口径**:
「手势的物理量本来就不该强求同值……该对齐的是**语义层**」。
· 判定逻辑放**纯逻辑层** `model/Calendar.ts` 的 `judgeSwipe`(可被 node 直跑,
写在 .ets 里就跑不了判据,语义没法被单测钉住)。四道门:位移 / 纵向优先 /
快滑窗口 / 方向。
· 阈值**不引用** WebUI 的 40 / 1.5 / 600(那是把巧合当契约),
各自定为 56vp / 1.4× / 700ms,并在注释里写出取值依据。
· 接线在 `CalendarPage.ets`:`PanGesture({direction: Horizontal})` +
`onActionStart`(记时 —— `GestureEvent` **没有时间戳字段**,我查了 SDK
的 gesture.d.ts 确认)+ `onActionEnd`(读 offsetX/offsetY)。
· ★ 挂在**网格列**上而不是整页:右栏(日程/编辑器)里有输入框与可滚内容,
整页挂会让「在表单里横划一下」变成翻月。
· ★ 翻页复用 `shiftRange()`(与 ‹ › 按钮**同一个来源**)—— WebUI 的注释
专门交代过:各写一套的话,阈值、边界、三档行为迟早分叉。
手势回调里**不准**直接改 year/month(锚点是唯一真相,年月只能由
`shiftRange → syncYearMonthFrom` 派生)。
**有意差异(记录在案,不是漏做)**:WebUI 在周/日档会额外检查「触点是否落在
可横向滚动的区域里」,是则让给滚动条(用户 2026-09-14 报过这个冲突)。
鸿蒙周档是「一行 7 格按 layoutWeight 等分」、**不横滚** ⇒ 该条件不适用。
哪天加了横滚必须同时补上它。
## 二、判据(8 条语义契约 + 行为层)
新增 `cross-client-gesture.test.mjs`:两端都真有手势 / 方向映射逐项相同 /
纵向优先 / 快滑窗口 / 复用同一翻页函数 / 无边界回弹 / 有意差异被记录 / 自检。
**只比语义、不比数值**,并反向断言鸿蒙的阈值常量不得直接取 WebUI 的那三个数。
`harmony-logic.test.mjs` 加行为判据:真跑 `judgeSwipe`,把四道门各自验一遍
(只钉字符串的话,一个 return 写漏了照样全绿)。
## 三、顺手修掉的三处**判据基建**缺陷(不修就没法验证上面这些)
1. `run-all.mjs` 只认 `# pass N`,而 node v24 打的是 `ℹ pass N`
⇒ **21 个文件被记成"没自报条数"**、套件在 HEAD 就恒红(memory 里记过这条,
修法也记过,今天终于落进代码:4 个正则加 `(?:#|ℹ)`)。修完 `unreported` 27 → 0。
代价是暴露出一批此前被"没自报"掩盖的真实问题(下面 4~6 条)。
2. `harmony-nav` 的设备判据 `navItemsOf`:宽屏过滤条件从「左边缘靠左 1/6」
改成「**整个盒子在侧栏轨道内**」。旧条件把**日历网格的格子**
(实测 `[229,511][366,794]`)也当成导航项,一屏数出 11~12 个。
这是设备实测抓出来的 —— 我第一版还以为是"底部簇混进来了",
打印真实数据才发现是隔壁页面的格子。
3. `harmony-logic` 两处:从 `NAV_ITEMS` / `NAV_SIDEBAR_ITEMS` **各自的数组**里取
label。原先把全文件 `label:` 一网打尽 ⇒ 得到 7 个(4+3 混在一起),
任何一边改对了它都会红。
## 四、被判据拦住后的正经修法(每条都按判据自己给的方向改,不改判据迁就代码)
· `cross-client-theme` A2 拦住我:新增的 `navActiveBg`/`navBrandFg`/`badgePlain`
未登记;又拦住我:`sseColorOf` 里四个裸色值。→ 抽成 `Theme.sseConnected` 等
四个令牌(取值对齐 WebUI 的 Tailwind 类)+ 登记 + 在 Theme.ets 的表里写理由。
· 同一条判据的"死令牌"检出:`Theme.durBase` 声明了却从没人读。
**查 WebUI 才发现壁纸淡入是真有的动效**(`index.css:742-752` 的
`.app-backdrop` 从 opacity:0 → 1,180ms)⇒ 补上而不是删令牌
(删掉等于把差异抹平、还说成"清理")。reset 在 `animateTo` **外**,
与 `calPaneIn` 同一条纪律。
· 玻璃登记:`NavItemBuilder` → `SidebarItem`(重构后按最近的 @Builder 命名),
登记同步跟上。
· `harmony-admin` 的退出判据:退出逻辑抽成 `api/Logout.ets` 的 `performLogout()`
(两个入口——「我的」页与侧栏底簇——必须做同一件事,尤其"先注销推送 token"
那一步)。判据相应改成**追到实际执行处**(两半都断:按钮调了 + 函数真清了全部),
并写明"别再退回直接匹配 SETTINGS_PAGE 的写法"(那会随重构假红,
下一个人只会去改判据而不看行为)。
· `harmony-widescreen` 的连接点色值:色值搬进 Theme 后,判据改成断
「令牌定义对了 + 侧栏真的用了它」两半(只断任一半都有假绿形态)。
· `align-refs`:`CalendarView.tsx` 变了,按判据要求**读一遍差异**再更新登记
(差异只有农历小字的灰阶档位 gray-300→gray-400/500,**骨架未变**)。
· `criteria-hygiene`:`harmony-contacts` 自造了一个 `code()`、`harmony-widescreen`
裸用 `readFileSync` ⇒ 都改用 `lib/read.mjs` 的共享入口。
途中撞出一个**判据自己的 bug**:`code()` 的块注释正则
`/\*[\s\S]*?\*\//` 会把注释里出现的 `/*`(如 `/」**` 这种中文夹星号)
当成块注释起点,一路吃到几十行后的 `*/`,把中间的 import 全吞掉 ——
于是 hygiene 判据假红"没 import"。改掉那处写法后正常。
## 五、验证
判据面:`run-all.mjs` → `files=32 ran=32 checks=497 pass=497 fail=0
skip=0 red=0 broken=0 unreported=0`。
其中新/改判据:gesture 8、nav 18、widescreen 7、logic 30、admin 27、
cross-client-theme 15、criteria-hygiene 6。
构建:`hvigorw assembleHap` 成功;前端 `npm run build` + 重新打 AppImage/deb
(`build-stamp` 7/7、`packaging` 5/5)。
**设备实测(HATriple 三折叠 3184×2232,hdc 连 127.0.0.1:5555)**:
· 农历在格子里真的显示(1=二十 / 7=廿六 / 19=**初九** / 11=八月),与 WebUI 一致;
这条同时验证了**服务端农历路由已部署**(之前线上是 404)。
· 日历左右两栏:编辑器出现在**右栏**、左栏月份仍可见(单栏模式下编辑器会整页盖掉它)。
· 侧栏 3 项 + 底部一簇;徽标回到图标右上角。
**仍未验(如实标注)**:滑动翻页的**手感**(阈值 56vp/1.4×/700ms 是否合适)
只能真人滑过才知道;我只验了判定逻辑与接线形态。动画同理 ——
机制已验证(`animateTo` 驱动 + reset 在窗口外),但"看起来顺不顺"未做取样验证。
docs:`DEBTS.json` 销掉 `gesture-semantics`(并记结算说明)、
`HARMONY-ALIGN-PLAN.md` P6 从「✅(滑动翻页除外)」改为 ✅。
|
|||
| c523c21e22 |
feat(harmony): 邮件详情与「我的」页 1:1 对齐 WebUI,并修两个线上 bug
用户:「为什么邮件页面没有对齐 webui?」「我的页面也没有对齐」,
选定「完全 1:1」。两个页面都不是「没做」,而是**做了一半** ——
`AuthApi` 的 logout/listKeys/createKey/revokeKey 全都写好但没人调,
`Models.ets` 的字段声明漏了服务端一直在返回的那些。
── 邮件详情页(对齐 WebUI `MailView.Header` / `CollapsibleHeader`)──
· 头部改**可折叠**(默认收起):收起只留标题 + 必须常驻的状态点
(未读 / 权限请求)+ 箭头。WebUI 的理由:顶部信息常驻会把可读区压成
一条缝(实测 1280×800 下头部 17% + 回复框 31%,正文只剩 48%)。
· 发件/收件改**三段式完整地址**:Agent → `pi@/home/program/agentmail.别名`,
人 → 只有名字。新增 `model/ReplyTarget.ts`(逐字移植 WebUI `replyTarget.ts`,
并对齐后端 `models.FormatAddress`)。
· 时间:`localDateTime()` → `2026/09/15 11:37:07`(原为裸 ISO `2026-09-15T03:37:07.14758Z`)。
· 档位:`permissionLabel()` → `只读/目录内/全权`(原为英文 `plan/workspace/full`;
这个函数早就在 `MailGrouping.ts` 里、列表页也在用,只有详情页没用)。
· 新增抄送行;回复入口改**右下悬浮球**(WebUI `reply-fab`),
不再是底部 56vp 通栏按钮。
── 「我的」页(对齐 WebUI `AccountPage`,补 5 个缺失 section)──
标题由「账号管理」改为「我的」(多账号只是其中一段,不是整页的目的)。
· 基本资料:用户名/显示名/角色/状态/创建时间/最后登录。
· 权限范围:可调用 Agent / 可访问目录(非管理员;空数组 = 不限)。
· 修改密码:三输入框 + 不一致就地提示(新增 `AuthApi.changePassword`,
该端点服务端一直有、客户端从未包)。
· 客户端连接密钥:列表 / 新建 / 吊销 + 一次性全文提示
(`AuthApi` 的三个方法终于被调用)。
· 退出登录:先注销推送 token → 清凭证 → **清全部账号** → 回登录页。
· 整页改为**一个 Scroll**:原来账号列表 `layoutWeight(1)` 占满剩余高度,
排在它后面的 section 被挤出可视区且滚不到(WebUI 注释里正是这个坑),
而「退出登录」在最下面 ⇒ 等于退不出去。
── 顺带修掉的两个线上 bug(都是判据发现的)──
① `MeApi.get()` 调 `GET /me`,但服务端**没有**这个路由(只有 `/auth/me`;
`/me/*` 下是 mail/sessions/keys/appearance 子资源)。
后果:这把调用恒 404 → `loadRole()` 恒走 catch → `isAdmin` 恒 false
→ 「管理」入口对**包括管理员在内**的所有人永远不显示。
实证:`GET /api/v1/me` → 404;`GET /api/v1/auth/me` → 200
`{"user":{"role":"admin",...}}`。修复后截图里「管理」入口已出现。
② 详情页回复写 `req.to = this.fromName + '@'`:那个游离的 `@` 让 `name@`
被后端 `ParseAddress` 解析成「有 path、无 session」⇒ 落到该 Agent 的
**默认会话**,而不是用户正在看的那条线索。改用 `replyTargetAddress()`。
── 判据(新增 7 + 8 条,全部含变异自检)──
· `harmony-reply-target.test.mjs`(新):直接执行 `ReplyTarget.ts` 断言行为
—— 空 path 必须留 `@`(否则整串被当成名字、投递 404)、人只有名字、
会话位必须带上、`from_workspace` 不得用来拼地址(会得到 `dsh@dsh`);
并读 Go 源码比对三分支结构。
· `harmony-admin.test.mjs`(+5):`/auth/me` 路径(含服务端注册与响应形状)、
八个 section 齐全、退出清全部账号、整页一个滚动容器、字段来自服务端。
变异自检:把 `/auth/me` 改回 `/me` → 判据变红(已验证)。
测试:212 passed / 0 failed;`devecocli build` 通过;
模拟器截图逐项核对(详情收起/展开两态、我的页全部 section)。
未验:真机观感;横屏 Auto Split 双栏。
|
|||
| 4af083e8b8 |
test(判据): 4 个判据读的是**另一棵树** —— 修掉硬编码的仓库根,并让 stripComments 保持行号
pi 2026-09-15 实测出来的,**这次长在判据自己身上** —— 正是我们前几轮一直在消的那个形状。
## 一、`const ROOT = '/home/program/agentmail'`:规则进来了,对象没进来
`harmony-arkts.test.mjs` 把仓库根写成了绝对路径。后果我按 pi 的步骤亲手复现了:
```
$ git worktree add --detach /tmp/wt-verify
|
|||
| 474cadaf54 |
跨端: harmony 管理页(用户管理)+ P4c 壁纸上传入口 —— 「功能做全再交付」的两块
pi 的交付清单里缺的两块(`docs/GUI-PLAN-HARMONY.md` 原先把管理后台划在首版之外, 用户明确要求「功能做全再给我」之后收进来)。 标 `跨端:` 是因为本次的判据落在 `client/electron/test/`(鸿蒙的判据目录一向量在那里), 代码本体全在 `client/harmony/`。 ## 管理页(用户管理) - `pages/AdminUsersPage.ets`:新建 / 编辑(显示名·角色·白名单)/ 启停 / 重置密码。 排布照 `AdminUsersPage.tsx`,包括「受限」徽标的口径(普通用户且白名单非空才显示)、 最后登录缺席与空串都显示「从未登录」、管理员对白名单两项忽略。 - 入口在设置页底部,**仅管理员可见**(`role === 'admin'` 严格相等,与 `App.tsx` 同口径)。 读不到身份时**不**显示也不报错(乐观放行会让每个普通用户看到一个点进去 403 的入口)。 - `api/AdminApi.ets` + `model/AdminUsers.ts`(纯逻辑,零 import ⇒ 判据能真跑)。 - 启停**只发 status 一个字段** —— 服务端是部分更新,多发字段会把显示名与白名单一起改掉。 - `model/Models.ets` 补管理端 DTO;`main_pages.json` 注册路由。 ## P4c 壁纸上传 - `model/ImagePrep.ts`:阈值与两档策略(2560/0.85 → 1280/0.78,入口 20MB,压后上限 3.5MiB)。 **一处有意不对齐 WebUI** 并写明理由:WebUI 卡 data-URL 长度(含 base64 膨胀), 鸿蒙内存直传 ArrayBuffer,卡的是字节数。 - `common/BackgroundPicker.ets`:不设 / 预设 / 自定义图片 + 浓度与模糊滑杆。 上传链:picker → 判可不可以 → 逐档按 desiredSize 解码压缩 → 上传 → **请页面以服务端为准重新同步**。 失败**必带原因**(服务端 415/413 文案原样透出)。 - `ApiClient.uploadBytes`:MultiFormData.data 收 ArrayBuffer(核了 SDK,since 11;本工程 23) ⇒ 内存直传,不需要 base64、也不需要临时文件。 - 用户取消选图**不算失败**,什么都不说。 ## 顺带修掉的两处真问题(都是变异测试逼出来的) 1. **压缩循环的第二档此前是死代码**:循环里的 break 与循环外那句 shouldRetryWithActual 互相抵消 —— 把循环里那处改成 `if (true)`(永远只压一档)整套判据照样全绿。 收成一处判定(overLimit),循环外只读结论。 2. **壁纸的模糊档一直是「只写不读」**(计划文档 §7.12 登记过):滑杆能拖、值能存、 blurStyleFor 也写了,就是**没有调用点**,壁纸一点没糊。本次补上调用点 (壁纸层 .blur(px) = 图片内容模糊;导航条材质由 blurStyleFor 映射)。 同时按 §7.12 的原承诺更新了那一行。 ## 一并修正的旧判据(都是"太宽/太窄",不是放宽标准) - 「模糊归属」:原文「壁纸层不许有**任何**模糊调用」把**图片内容模糊**与**面板材质** 混为一谈(WebUI 侧核实:.app-backdrop 的 filter 与它之上那层的 backdrop-filter 是两个不同的量)⇒ 改成按两种模糊分别钉。 - 「bgBlur 只写不读,消费侧必须为 0」:值不再成立,**形状保留**(逐文件登记 + 计数 + 理由), 标题与断言里的假话一并改掉。 - isDarkMode 那条 `/dark\s*\)/` 断的是**参数顺序**(加一个入参就误红)⇒ 改成"dark 在实参里"。 - 导航材质三处断言原本钉 `Theme.navMaterial` 字面量 ⇒ 改成钉新的映射写法。 ## 判据 新增 `harmony-admin.test.mjs`(22 条)、`harmony-imageprep.test.mjs`(29 条); `harmony-presets.test.mjs` 加 1 条(模糊档搬运与归一,含 -0 那个洞)。 全量 203 条:**201 通过**,2 条失败为**改动前就红**的既有项 (BUILD_INFO 比对、词表↔余额)—— 用 stash 对照验证过。 两个新判据文件上跑了 **48 个变异体,全部被抓**(含"接线"类:删掉「受限」徽标、 组件自己宣布成功、release 不 await、按原图尺寸解码…), 其中 2 个变异体**红不了**,因此又补了 5 条判据(纯逻辑接线、退档判定只有一处、 两档都超限必拒、解码尺寸用的是目标尺寸而非原图尺寸、模糊档搬运)。 (数字口径:按 runner 的真实条件"锚点恰好命中 1 次才算跑过"统计; 另有 4 条锚点不命中、根本没跑,不算在这 48 里。我第一次写的是"40"—— 凭记忆累加的,错了,已更正。) **未验**:本机无设备/无模拟器 ⇒ 全部观感未验(管理页排版、滑杆手感、模糊在真机上的 实际档位观感)。代码齐 ≠ 真机验过。 |