跨端: B 的交付物(跨端纯逻辑一致性判据)+ 照 skill 回扫修掉两处隐形债
用户:「你为什么不加载鸿蒙开发相关skill?」—— 说得对。那份
`arkts-grammar-standards` 写着 "REQUIRED before writing the first .ets file of a
session",而我这轮一直在写 `.ets`。补加载后照它的规则表**逐条回扫**,
当场抓出两处此前没人管的违规。
══ ① 用户要做的 B:`cross-client-logic.test.mjs`(新,6 条判据)
背景:两套纯逻辑各写一份且已分叉(replyTarget 214/170 行、mailGroups 178/459、
appearance 187/324、calendar 208/446)。当天已**踩到**两处分叉
(`participantAddress` 的 `||`、`ThreadPage` 字段全错)。
做法:**同一张用例表喂给两边,逐条比结果**(`--experimental-strip-types`
直接在 node 里跑两侧源码 —— 两边的 model 层都是纯逻辑、无 SDK 依赖)。
不选"生成一份共享源码":harmony 不能 import 工程外文件,
且两边类型系统不同(ArkTS 禁解构/any/对象字面量要具名类型),
生成器要维护"两边都能过"的子集,是另一个大工程。
★ **首轮运行就报出两处真分叉,都不是我踩到才发现**:
① `formatAddress('dsh', undefined, undefined)`:electron 返回 `"dsh"`,
harmony **抛** `Cannot read properties of undefined`。
—— 又是 `omitempty` 那个坑(**第三次**),这次是判据先报的。
② `monthGrid`:electron **固定 6 行**(`grid-rows-6`),harmony **4~6 行**
⇒ 翻月时网格高度跳动。WebUI 的注释明写要避免这个("行数变化会让整个
网格高度跳动,翻月时页面内容上下弹")。
③ 顺着 ② 又发现:WebUI 邻月格子**填真实日期并置灰、可点**
(`CalendarView.tsx:545-556`),harmony 留**空白格**。
★ 判据自身的两次错,都留了档(判据的 bug 与代码的 bug 一样危险):
· 第一版把 `args[0]` 当单个参数传,字符串被当可迭代对象展开 ⇒
`formatAddress('d','s','h')` —— **判据自己造出假分叉**。
· 第一版 `weekStart` 传 0(周日),而两端实际都是 1(周一)⇒ 又一处假分叉。
差一点就去"修"一个不存在的问题。
· `monthGrid` 的投影第一版按 `inMonth ? [y,m,day] : null`,
把"邻月填不填真日期"这个**真分叉**抹平了 —— 投影只该换表示,不该替我看不看。
★ 三类"不同"要分清(写进文件头):**命名不同**(投影归一,不是分叉)、
**签名不同**(ArkTS 没 Date 重载习惯;语义必须一样)、**行为不同**(是分叉,以 electron 为准)。
══ ② skill 回扫抓出的两处隐形债(编译器只告警、判据也不管)
· **正则字面量**(`arkts-no-regexp-literals`):`MailDetailPage.ets:615` 的
`/^\d+$/`(从 2026-09-19 活到今天)。
· **废弃的全局 `router`**:`api/Logout.ets:76` 的 `router.replaceUrl(...)`。
它是个独立函数(没有 `this`)⇒ 拿不到 `UIContext`,改成由调用方传
(两个调用点都持有 `getUIContext()`,零成本)。
★ 这两条为什么能活这么久:**编译器对它们只告警、不挡构建**,
全仓也**没有判据**管 ⇒ 规则事实上不存在。已补两条判据,都做了变异验证。
══ ③ 顺带修正一条**恒真的同义反复**断言
`harmony-calendar` 里 "today 不在本月:不许标在别的月" 那条:
它是在"邻月格子是空 `DayCell`(`iso` 为空串)"时写的 ⇒ `c.iso === today`
**永远不可能**匹配 ⇒ `count === 0` 恒真,**看起来守着一条规则,其实什么都没守**。
改成真不变量:**"被标为今天的那一格,iso 必须就是 today;至多一格"**,
并反向核对"2026-10-01 确实出现在 9 月网格里"(否则那段是空转)。
实测 WebUI `CalendarView.tsx:547` 是逐格 `isSameDay` ⇒ **它会标**,
所以原来那条"不许标"本身就窄了一半。
══ ④ 登记两处盘点发现(**没有**顺手改,因为需要人决定)
· `harmony-dead-pages`:`InboxPage.ets`(238 行) 不可达(不在页面表、无人导航),
`SessionsPage.ets`(170 行) 唯一引用来自 InboxPage ⇒ 一起不可达。
没删是因为 `HARMONY-ALIGN-PLAN.md:214` 把它当变异测试靶子用过 ——
删掉会永久丢代码,是否只是"早期留存"我判断不了。
· `harmony-permission-history`:WebUI 授权栏显示**待决 + 已决策历史**两段
(拿 inbox 自己分组,`PermissionList.tsx:27/174/182`);鸿蒙调专用端点
`/permission/pending`(SQL `WHERE pr.result IS NULL`)⇒ **只拿得到待决的**。
已在 `cross-client-logic` 的 gaps 里如实登记,判据会盯着"不要再少"。
══ 判据状态
`files=33 ran=33 checks=530 pass=530 fail=0 skip=0 red=0 broken=0 unreported=0`;
`baseline=7/7✓`(底本第 9 次重算,已按规矩先 `git diff --quiet HEAD` 取证 + 记录理由)。
`verdict=red` 残余仍是 5 条静态判据的**设备到期提示**(既有机制)。
══ 环境
模拟器昨天起卡死(hdc 能连、shell 超时、CPU 150%、跑了 34 小时),
导致设备判据各跑 836 秒后失败 —— 看起来像"套件卡死"。用户批准后杀掉重启
(`Emulator -start HATriple -noWindow`,`devecocli` 那套因 x11 起不来),
现在**75~150 秒**跑完整套。
This commit is contained in:
@ -108,8 +108,42 @@ test('"今天":只有传入的那一天被标出来,且标在本月格子内
|
||||
assert.ok(today[0].inMonth, '今天必须落在本月格里');
|
||||
// 不传 today:一格都不许标(否则会标到"服务器时间"或"上次渲染残留"上)
|
||||
assert.equal(C.monthGrid(2026, 9, 1).flat().filter(c => c.isToday).length, 0, '不传 today 就不该有今天');
|
||||
// today 不在本月:不许标在别的月,也不许标错格
|
||||
assert.equal(C.monthGrid(2026, 9, 1, '2026-10-01').flat().filter(c => c.isToday).length, 0);
|
||||
/*
|
||||
* ── today 落在邻月时怎么办(2026-09-20 改)──
|
||||
*
|
||||
* 原来这里断的是 `count === 0`("不许标在别的月")。**那条断言是错的**,
|
||||
* 而且错得很隐蔽 —— 它记录的是**旧实现的副作用**,不是一个被设计的不变量:
|
||||
*
|
||||
* 当时 `monthGrid` 把邻月格子填成**空 `DayCell`**(`iso` 是空串),
|
||||
* 于是 `c.iso === today` **永远不可能**匹配 ⇒ `count === 0` 是**恒真的同义反复**。
|
||||
* 它看起来在守一条规则,实际上什么都没守。
|
||||
*
|
||||
* 2026-09-20 把邻月格子改成**真实日期**(对齐 WebUI —— 见 `monthGrid` 里那段注释
|
||||
* 与 `cross-client-logic.test.mjs` 抓出的分叉)之后,这条断言立刻红了。
|
||||
*
|
||||
* ★ 那到底该标还是不该标?**实测 WebUI 的行为**(不靠推理):
|
||||
* `CalendarView.tsx:547` `const isToday = isSameDay(d, now);`
|
||||
* —— **逐格判断**,所以 2026-10-01 真的出现在 9 月网格的尾部格子里时,
|
||||
* WebUI **会**把它标成今天。这与 Google Calendar 一致,也是合理的
|
||||
* ("今天"是个客观事实,不该因为它落在你正在看的月份的尾巴上就不标)。
|
||||
* 实测:`monthGrid(2026,9,1)` 的 42 格里确实含 2026-10-01。
|
||||
*
|
||||
* ⇒ 真正的不变量不是"邻月不许标",而是**"标了的那一格必须真的是今天"**:
|
||||
* · 至多一格(42 个连续日期里,任一日期至多出现一次)
|
||||
* · 若标了,那一格的 `iso` 必须**等于** today(不是"同月",不是"差一天")
|
||||
*
|
||||
* 这才是原本那句注释里"**不许标错格**"想说的东西 ——
|
||||
* 原断言把"不许标错格"写成了"不许标",窄了一半。
|
||||
*/
|
||||
const adj = C.monthGrid(2026, 9, 1, '2026-10-01').flat().filter(c => c.isToday);
|
||||
assert.ok(adj.length <= 1, '至多一格被标为今天(今天是唯一的一天)');
|
||||
for (const c of adj) {
|
||||
assert.equal(c.iso, '2026-10-01',
|
||||
'被标为今天的那一格,它的 iso 必须**就是** today —— 不许标在同月别处、也不许差一天');
|
||||
}
|
||||
// 反向核对:today 确实会出现在 9 月网格里(否则上面那段就白跑了)
|
||||
const hasOct1 = C.monthGrid(2026, 9, 1).flat().some(c => c.iso === '2026-10-01');
|
||||
assert.ok(hasOct1, '9 月网格的尾格里应当含 2026-10-01 —— 它不在的话,上面那段是空转');
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user