{ "_": [ "欠账的**单一登记**(pi 2026-09-14 裁定 §3):三笔类型不同、但必须能一眼看全。", "为什么要一个文件:三笔原先各自表达(RESULT static=5 / t.Skip / 登记在文档里的到期前提),", "没有一处能看全 —— 而『欠账不显形,就等于没有』;分散在多处的登记,审计时只会被找到一处就当全部。", "两端都读这个文件:Go 侧判据断言自己的条目与**实测**一致(不许留一份手写的数字),", "electron 套件把它打进 RESULT 行(那是常态可见的位置)。", "已结算(2026-09-14):calendar-today-recompute —— P6 第 1 步(日历页 pages/CalendarPage.ets)落地,today 走 `@Prop @Watch('onVisibleChanged') visible` 在 pane 变可见时重算(另有 aboutToAppear 覆盖重新挂载),判据 test/harmony-calendar.test.mjs 的「★ today 在 pane **变可见时**重算」。结算即从此清单移除,余额里不再计这一笔。", "已结算(2026-09-19):gesture-semantics —— P6 第 3 步(左右滑动翻页)落地:鸿蒙侧 `CalendarPage.ets` 加了 `PanGesture`、判定逻辑在纯逻辑层 `model/Calendar.ts` 的 `judgeSwipe`。按该条自己的口径(「鸿蒙侧出现滑动手势代码时**立即建**」)同步建了语义契约判据 `test/cross-client-gesture.test.mjs`(8 条)—— 按 (b) 口径钉**语义**不钉数值:左滑=下一段/右滑=上一段/纵向优先/快滑窗口/手势与按钮共用同一翻页函数/无边界回弹/有意差异被记录/方向写反必红。另在 `harmony-logic.test.mjs` 加了行为判据(跑 `judgeSwipe` 的四道门)。结算即从此清单移除,余额里不再计这一笔。" ], "debts": [ { "id": "static-criteria", "count": 6, "due": "本工作区能装、能点设备(探针三值转 true 时自动变红)", "where": "client/electron/test/run-all.mjs 的 STATIC_ONLY(test/harmony-appearance.test.mjs、test/harmony-logic.test.mjs、test/cross-client-theme.test.mjs、test/appearance-defaults.test.mjs、test/harmony-admin.test.mjs、test/harmony-imageprep.test.mjs)", "kind": "scope" }, { "id": "mails-status-derived", "count": 1, "due": "详情/线程改为按读者派生(readStateFor)之后 —— 那时 mail_status_derived_test.go 从 Skip 转实跑", "where": "server/internal/repo/mail_status_derived_test.go", "kind": "scope" }, { "id": "observability-output", "count": 1, "due": "页面层(MainPage.ets)接上「读 presetSubstitutedFrom 并打一行日志」时;那一步同时补判据『读侧恰好出现 1 次且在日志调用里』", "where": "尚无判据 —— 这正是欠账的一部分(P6 第 1、2 步动 MainPage.ets 时一起做);形态判据在位:test/harmony-appearance.test.mjs(bgBlur 消费侧计数)", "kind": "scope" }, { "id": "unknown-preset-approval", "count": 1, "due": "有人对上表那格**追认或驳回**「未知 id 显示 aurora 而不是空白」这个方向时(我作为实现者不能自己追认自己)", "where": "client/electron/test/CRITERIA.md §10 的『未知的预设 id』行(现为『无人类批准』)", "kind": "env" }, { "id": "overlay-follows-app-theme", "count": 1, "due": "上设备后**翻转一次 colorMode**(应用深色 / 系统浅色),断言**解析出的遮罩值跟着「应用」主题变、而不是跟「系统」**;真机若证伪,正确修法是「遮罩从应用主题派生」,不是回到双常量", "where": "client/harmony/entry/src/main/ets/common/Theme.ets:58-79 的注释(机制依据:AppearanceStore.applyTheme → app.setColorMode)——**注释不是判据,所以进余额**", "kind": "env" }, { "id": "nav-dark-route-b-unguarded", "count": 1, "due": "**引入深色主题(或第一次给导航组件加 `dark:` 变体)时**必须一并堵;堵法按**文件窄豁免**写,不许写成「导航目录不许出现 dark:」(`bg-chrome-600` plain 档徽标那个先例我踩过一次)", "where": "client/electron/test/background.test.mjs 两条反向断言 —— 这是**已知未覆盖的回滚路径**(不是未验的运行时性质):`.dark .nav-rail{}` 选择器作用域与组件 `dark:` 变体,变异确认过都会逃掉", "kind": "scope" }, { "id": "nav-blur-route-c-unguarded", "count": 1, "due": "**第一次给导航元素加工具类模糊(Tailwind `backdrop-blur-*`)时**堵", "where": "同上文件 —— **已知未覆盖的回滚路径**:元素级 `backdrop-blur-lg` 不在那条选择器下,变异确认过逃得掉", "kind": "scope" }, { "id": "boundary-vocabulary-incomplete", "count": 1, "due": "**由外部读者报告时**(自查机制对这一类结构性失明 —— 发现词表外说法的机制,正是看不见它的那个机制)。收到报告后:扩词表 + 登记该处 + 保留\"上一次是谁发现的\"。**没有内部触发器,这是这条递归的不动点**:无论词表多长、判据多严,总有一类盲区只能靠\"外面有人读了一遍\"", "where": "client/electron/test/debt-visibility.test.mjs(词表键控的盲区:**已知未覆盖**——词表是采样、不是完备)", "kind": "env" }, { "id": "redeploy-script-unguarded-steps", "count": 1, "kind": "scope", "due": "**下一次改 `deploy/` 下任一脚本时**必须一并堵(`redeploy-gateway.sh` 正在被另一条会话改 ⇒ 本条目就是给它接手时的入口)。堵法:给每个副作用步骤加 `|| { bad …; exit 2; }`,或在脚本上开 `set -e`;两者都要与既有的 2=环境 / 1=检查 约定对齐。", "where": "`deploy/redeploy-gateway.sh:84` 的 `run \"cp -r '$REPO/client/electron/dist/.' ...\"` —— 脚本只有 `set -uo pipefail`(**无 `-e`**),`run()` 内部 `eval` 的失败既不中断也不被调用点接收 ⇒ 前端产物没拷进去也继续往下走。同类已在 `deploy/redeploy-plugin.sh` 修掉(2026-09-14):那次的实测形状是 `mkdir`/`cp` 被拒后仍打出 `[ OK ] 已拷入 node_modules`,再打出 `[FAIL] staging 里没有入口` —— **一段输出里两个矛盾信号,且 OK 在前**。该文件现已在 `mkdir`/`cp`/`node_modules` 三处判失败并 exit 2。" }, { "id": "deploy-space-prefix-fs", "count": 1, "kind": "判据铺得不满(不是新列)", "due": "下一次因空间问题失败时;或有人愿意补一行 df 时", "where": "deploy/lib/env-defaults.sh ②b 只判了 $TMPDIR,没判 $PREFIX 所在的文件系统" }, { "id": "pi-bridge-adopt-cwd-mismatch", "count": 1, "kind": "沙箱 rw 与 worker 实际 cwd 的第三个来源未对齐(同类已修两处,剩接管路径)", "due": "下一次动 pi 桥的会话装载 / `session-scan.mjs` 时;或有人愿意把「这一轮用哪个 cwd」完全收成父进程一处决定时", "where": "`plugins/pi-mail-bridge/src/worker.mjs` 的**接管会话**分支:worker 用会话文件 header 里的 `info.cwd`(`resolveWorkspaceCwd(info.cwd || data.to_workspace, …)`),而父进程(`src/pool.mjs` → `src/turn-cwd.mjs`)只能从 `state` 里拿 `{sessionFile, cwd}`,**读不到 header** ⇒ 接管的首回合 rw 仍可能不含 worker 真正要写的目录。父进程要拿 header 得用 `src/session-scan.mjs`,但 `readHeader` 未导出、整表 `scan()` 在父进程里代价大(worker 里实测 1431ms / 堆瞬时 240MB,见 worker.mjs 里那段注释)。★ 这类错位的**特征是没有提示**:EACCES 落在「界内」,读日志的人会以为沙箱装错了(不像 `ask` 还有一次问)。修法方向:把「这次用哪个 cwd」收成父进程一处决定(它已有 `state.sessionFile`,header 也可读),worker 只消费、不再自己推导 —— 即 `src/turn-cwd.mjs` 头注释里写的「三来源变一来源」。" }, { "id": "deploy-interrupt-trap-other-scripts", "count": 1, "kind": "只在 redeploy-gateway.sh 做了,另两个部署脚本没做", "due": "下一次动 redeploy-plugin.sh / install.sh 时", "where": "只有 redeploy-gateway.sh 有 INT/TERM/HUP trap;install.sh 与 redeploy-plugin.sh 在写系统目录期间被打断同样会留半成品(它们没有\"服务停着\"那种后果,所以优先级低)" }, { "id": "harmony-p4c-boundary-decls", "count": 5, "due": "本工作区能装、能点设备 —— 那时这几条静态判据里被替代掉的那些断言换成真机断言,声明随之减少", "where": "client/electron/test/harmony-admin.test.mjs、client/electron/test/harmony-imageprep.test.mjs", "kind": "scope" }, { "id": "deviceprobe-fixture-timing", "count": 1, "due": "把两份 fixture 变成**当场采集**(跑 hdc dump 取现场)而不是人工存文件时,这条就到期", "where": "client/electron/test/harmony-deviceprobe.test.mjs(两处提到「未验」的断言 + fixtures/aa-dump-l-*.txt)", "kind": "scope" } ] }