按 pi 复核改五处:判据的"值/行为"原则、真正的构建门、typecheck 进门、Go 判据零匹配、迁移归属
pi 用反例与变异逐条点了五处,全部**先跑变异再改**(结论都写在原地)。
## 1 判据③:形状正则已删(它永远差一个反例)
实测 pi 的反例 —— `const k = PREFIX + accountId; return PREFIX;`(拼了但没返回)——
对第三版判据**仍然全绿**:第三版锚的是"**函数体里存在**这样的表达式",不是"**返回的**表达式"。
三版的骗法各一个(签名里的参数 / 提了一下没用 / 拼了没返回),都在判"源码里有没有那个形状",
而缺陷是"算出来的值对不对" ⇒ **权威交给行为判据**(`test/stores/background.test.ts` 直接断言
`storageKey('a') !== storageKey('b')`、`=== 'agentmail.background.acct-a'`、不退回全局键),
正则那条删掉并把反例写在原地(否则下一个人会好心加回来)。
保留"键必须来自 storageKey()"那条:那是**来源**约束,不是值对不对,正则在这里合适。
鸿蒙侧只能静态判(`.ets` 本机没有运行时),已把这条限制写进判据说明。
推广进规范:CRITERIA.md §6.7 + run-all 自检关键词(10 → 11)。
## 2 真正的门:`scripts/release-linux.sh`
- 实测 pi 提的变异:**`touch dist/index.html` 时 stamp 判据是绿的** —— 它抓不到"构建失败但碰过 dist"。
stamp 是**探测器**(抓"src 改了产物没跟上"),门是**喂退出码**,两者不互替(§6.7.1)。
- `build:linux` 里**没有管道**(`&&` 链,退出码本来就传),但那次的哑巴失败是我在命令行手打
`npm run build 2>&1 | tail -4 && …` 造成的;同时发现它跑的是**裸 `vite build`,跳过 `gen:bg`**。
- 于是把配方收成 `scripts/release-linux.sh`:`set -euo pipefail` + 走 `npm run build` + 再打包。
- 判据是**行为**的:注入失败的构建(`AGENTMAIL_BUILD_CMD='exit 7'`)→ 断言退出码非 0
**且打包那步没跑**(标记文件不存在)。变异:脚本改成 `|| true` → 红 ✓。
## 3 typecheck 进 `npm test` 链
`npm run typecheck` 原本就有,但没人跑。先修掉它唯一的报错(我自己留下的未使用 import),现在干净;
`test` = run-all + vitest + typecheck。它恰好检查**没被任何测试 import 的文件**(vitest 只解析被测到的图)——
也就是那次 `is not exported by` 的形状。
## 4 Go 源码判据:零匹配 / 读不懂 都要红
改成三分:切不出函数体 → 红;字段在但值不是字面量 → 报「**判据读不懂**」(变异:`BgDim: defaultDim` → 红 ✓);
字段不在 → 红。静默放行是这类判据最危险的失败方式。
**措辞更正**:这条核对的是"与**这份服务端源码**的契约",不是"在跑的服务端二进制是 12/4"
(与"dist 是产物"同构);文档同步改。
## 5 迁移归属:定向做不到,就把"不可恢复"降级成"可恢复"
查实:`accountStore` 的 `activeId` 是**派生视图状态、不落盘**(`persist(accounts)` 只存数组),
所以**本机没有"上次活跃账号"标记可定向** —— 旧值的作者事后无法还原,定向迁移在原理上做不到。
升级前用 B、升级后先登录 A ⇒ A 接管 B 的外观,**一次性错档**,触发条件就这一条。
两件能做的都做了:**写了回读校验**(写不进去就不删旧键,避免净损失;变异:改成先删后写 → 2 条红 ✓)、
**删前另存** `agentmail.background.legacy.bak`(只写不读 ⇒ 不引入新的继承源,判据钉"只写不读")。
§7.12 把本地这半与显形方式写进同一行。
## 验证
`npm test` 退出码 0:14 个判据文件全绿 + vitest **265** 通过(+2 迁移行为测试)+ typecheck 干净;
`hvigorw assembleHap` BUILD SUCCESSFUL;安装包经新脚本重打(dist 与包同批)。
This commit is contained in:
@ -516,9 +516,9 @@ deb 也不必从 targets 里摘。已写进 `client/electron/BUILD.md`(含排
|
||||
| 动效 | 自定义 transition/时长 | `animateTo` + 系统 `curves` | 动效曲线应跟随系统设置(含"减弱动效") |
|
||||
| 遮罩 | 自声明 `--bg-scrim` + `--bg-dim` 两段式 | 系统 `sys.color.ohos_id_color_mask_regular` | 遮罩要随主题换向(浅色洗白/深色压黑),这件事系统已经做了 |
|
||||
| **品牌色** | `--c-blue-600: 37 99 235` | `Theme.accent = '#2563EB'` | **不允许差异** —— 两个客户端是同一个产品 |
|
||||
| **本地外观缓存的键** | `agentmail.background.<accountId>`(**已修**:原来全局) | `appearance.<accountId>` | **差异已消除**(2026-09-14 dsh 接手 pi 的开项):两端都按账号分键,且都留有「不许退回全局键」的判据。全局键的后果是切到服务端没有记录的账号时 `saved=false` 会把**上一个账号的外观** push 上去(新账号"继承"了外观,还写进了服务端)。WebUI 侧保留旧全局键**仅作一次性迁移源**:接管后立刻删除,且未登录时不迁移 |
|
||||
| **本地外观缓存的键** | `agentmail.background.<accountId>`(**已修**:原来全局) | `appearance.<accountId>` | **差异已消除**(2026-09-14 dsh 接手 pi 的开项):两端都按账号分键,且都留有「不许退回全局键」的判据。全局键的后果是切到服务端没有记录的账号时 `saved=false` 会把**上一个账号的外观** push 上去(新账号"继承"了外观,还写进了服务端)。WebUI 侧保留旧全局键**仅作一次性迁移源**:接管后立刻删除,且未登录时不迁移。**本地这半的归属问题(pi 指出,同一行的另一半)**:「当前账号」= **升级后第一个读到缓存的账号**,不是**写下旧值的账号**;旧值是谁写的,本机**没有记录**(`accountStore` 的 `activeId` 是**派生的视图状态**、落盘时只存 `accounts` 数组,见其 `persist(accounts)` 与「落盘在 activeId 里不合适」那句注释)⇒ **定向迁移在原理上做不到**。显形方式:**一次性外观错档**(升级前用 B、升级后先登录 A 且 A 自己没有记录 → A 接管 B 的外观),触发条件就这一条。已做的两件补救:**写了回读校验**(写不进去就不删旧键,避免净损失)、**删前另存一份** `agentmail.background.legacy.bak`(没有任何代码读它 ⇒ 不引入新的继承源,但让接管错了可以手工改回)。行为判据在 `test/stores/background.test.ts` |
|
||||
| **遮盖色的令牌** | `--bg-scrim`(浅色白 / 深色黑,"朝底色淡化") | `Theme.wallpaperScrim` = `sys.color.ohos_id_color_background`(同向);`Theme.overlay` = mask **只用于模态弹层** | **不允许混用** —— mask 两套主题下都是深色(浅色 `#99182431`),拿它当壁纸遮盖会在浅色主题下压暗(与 WebUI 反向)。两个语义两个令牌,理由与实测值见 §7.17b-2 |
|
||||
| **遮罩浓度的默认值** | `12 / 4`(**已修**:原来 store 的 `24/8` 与 `clamp` 的 `12/4` 两套并存) | 12 / 4(只有一套) | **不是审美,是服务端契约**(pi 更正了自己上一封):`DefaultAppearance()` 明写 `BgDim: 12, BgBlur: 4` 且注释宣称"与客户端默认值一致" —— WebUI 的 24/8 使那句注释为**假**。现已统一到共享常量 `src/lib/appearanceDefaults.ts`,判据**直接去 Go 源码读**这两个数比对。本来后果很重:服务端"没有记录"时客户端以本地为准推上去,**新账号的初始外观由第一个同步它的客户端决定** |
|
||||
| **遮罩浓度的默认值** | `12 / 4`(**已修**:原来 store 的 `24/8` 与 `clamp` 的 `12/4` 两套并存) | 12 / 4(只有一套) | **不是审美,是服务端契约**(pi 更正了自己上一封):`DefaultAppearance()` 明写 `BgDim: 12, BgBlur: 4` 且注释宣称"与客户端默认值一致" —— WebUI 的 24/8 使那句注释为**假**。现已统一到共享常量 `src/lib/appearanceDefaults.ts`,判据**直接去 Go 源码读**这两个数比对。**措辞要准**(pi 同封指出):这条核对的是「**与这份服务端源码的契约一致**」,**不是**「在跑的那个服务端二进制是 12/4」—— 与「`dist` 是产物、源码修好 ≠ 用户手上的包修好」同构;若服务端由别的流水线构建部署,判据对运行时**没有**发言权。本来后果很重:服务端"没有记录"时客户端以本地为准推上去,**新账号的初始外观由第一个同步它的客户端决定** |
|
||||
|
||||
**关于 `overlayColor` / `overlayAlpha` 消失**(pi 要求把删除理由记在这里,否则下一个人会当成漏改补回来):
|
||||
鸿蒙这边的模态走**系统弹窗**(`bindSheet` / 自绘 `Stack` 只做位置,遮罩本身用系统遮罩色),
|
||||
|
||||
Reference in New Issue
Block a user