# 桌面与「添加到桌面」 规则引擎原型

> 设计文档 [../设计.md](../设计.md) 第 10 节的原型。静态 HTML／CSS／JS，断网可开（`file://` 直接双击，或在 `docs/modules/` 下起本地服务后开 `http://127.0.0.1:<端口>/桌面与全部模块/原型/index.html`）。画面停在 10:05，不需要时间滑块。会议、待办、日程、随手记的卡直接嵌各模块自己的原型（下文「哪些是嵌入、哪些是本原型画的」）。
>
> 10-21 第三版：对齐白晨 10-21 定稿的编辑桌面（岛、草稿、撤销／取消／完成、左上角圆钮移走、右下角拖弧改尺寸，面板改名「添加到桌面」）；卡片按 `.claude/skills/designing-module-loops/card-sizes.md` 定死外框（同档等大，行高 292）；同一模块可以放多张、面板里只有「放上桌面」（白晨 10-21）；面板默认版式改为 F「四档对照」（白晨 10-21「一次看到多个档位」）。

## 文件

| 文件 | 内容 |
| --- | --- |
| `index.html` | 页面骨架：控制带、顶栏（平时是输入胶囊，编辑桌面时变成岛）、桌面网格、「添加到桌面」面板、内容菜单、提示条、状态说明栏 |
| `base.css` | 定稿原型浮彩亮的底层样式，整份复制自会议原型（出处见文件头） |
| `proto.css` | 本原型自己的样式：控制带、岛、编辑态画布与卡上的把手（圆钮、弧、内容小牌、手机上移下移）、固定尺寸的网格与卡身、「添加到桌面」版式 F「四档对照」（默认）与留作对照的 A、E、D、预览、状态说明栏、嵌入模式、两档窄屏 |
| `icons.js` | 手画图标字典，复制自会议原型；补了定稿的 `news`、`tool`，新画 `search`、`swap`、`island`、`undo` |
| `data.js` | 数据与规则表：各模块各档的内容种类（`DK.MODS[...].contents`，与设计文档 6.4 一一对应）、四个模块嵌哪份原型的哪一帧（`DK.EMB`、`DK.embUrl`）、其余模块的数据、预设桌面、说明页场景步骤 |
| `engine.js` | 纯规则：几何（`DK.geo`，照 `card-sizes.md`）、岛上的话与提示条与尺寸牌（`DK.msg`，文案只在这一处）、卡片实例、内容种类与默认、编辑草稿（撤销栈、取消、完成、改动数）、「完成」时调哪些接口（`DK.savePlan`）、放上（上限；同一模块可以放多张，面板里只有「放上桌面」）、移走、换内容、改尺寸时内容的去留、拖弧吸附到哪一档、其余模块每档列几条（`DK.FIT`、`DK.PH`、`DK.fit`）、按模块取数与同步节流、预览数据来源与说明条（`DK.previewSource`、`DK.notices`）、对照板的摆法与档名（`DK.BOARD_ORDER`、`DK.boardShow`、`DK.boardTitle`）、按模块找卡；每个动作把「为什么」写进 `st.why` |
| `golden.js` | 标准答案表：剧本配置、case 清单、只用 `inputs` 回放（`DK.golden.replayCase`）与导出（`DK.golden.text`）；无 DOM |
| `export-golden.js` | Node 脚本：写出或核对 `标准答案表.json`（下文「标准答案表」） |
| `标准答案表.json` | 第 3 件，由上面两份生成，不手改 |
| `cards.js` | 会议、待办、日程、随手记以外的模块（云端文件夹、回顾、收件箱、项目、文档、资讯）与插件卡的画法，按「模块 × 尺寸 × 屏宽档」；外框由网格给定，这里只负责放得下 |
| `motion.js` | 动效：FLIP 让位、新卡从「添加模块」格长出来、移走、换内容 A／B、刷新转圈（设计文档第 13 节） |
| `app.js` | 交互与渲染：几何（照 `card-sizes.md`）、控制带、岛、桌面（按卡片键增量更新；四个模块的卡嵌各模块原型，`embHtml`、`embVw`）、拖弧、「添加到桌面」（对照板 `boardHtml`、比例 `fitBoard`、放大看 `zoomHtml`）、状态说明栏、地址参数、只画一个画面 |

## 尺寸怎么来（`engine.js` 的 `DK.geo`；`app.js` 的 `geo()` 只取窗口宽与是否编辑态）

照 `card-sizes.md`：窗口宽 W（超过 1440 按 1440），宽屏 ≥ 1101 是 4 条轨道、列距 18、行高 292；761～1100 小卡与中卡同宽；≤ 760 是 2 条轨道、列距 12、行高等于轨道宽 m（小卡正方形）。网格用固定行高 `grid-auto-rows: <行高>px`，卡身 `overflow: hidden`。编辑桌面时列距 30（编辑桌面定稿），轨道随之变窄，行高不变（设计文档 12.1 第 16 条）。

每档列几条：会议、待办、日程、随手记由各模块原型自己算（它们的 `engine.js`）。其余模块是本原型 `engine.js` 的示意：宽屏、中屏卡高不变，条数写在 `DK.FIT` 的 `w`、`m` 两栏；手机卡高随 m 变，`DK.fitPhone` 按 `DK.PH` 里每档的「固定部分、每行高」现算（卡身可用高＝卡高 − 64），放不下的末行写「还有 N 件」。

## 哪些是嵌入、哪些是本原型画的

**会议、待办、日程、随手记四个模块的卡，以各模块自己的原型为准，本原型不另画**（白晨 10-21 经主控转达）。凡是这四个模块的卡——桌面上的、编辑桌面里的（含拖弧改尺寸、换内容、移走、撤销）、「添加到桌面」对照板与放大看里的、版式 A／E／D 的预览、说明页「它长什么样」——一律是 `iframe` 嵌各模块原型的 `frame=` 帧：

| 模块 | 嵌的地址（相对 `docs/modules/`） | 状态对应 |
| --- | --- | --- |
| 会议 | `会议/原型/index.html?frame=<档>&cfg=default&at=1005`，小卡加 `variant=next`／`overview` | 腾讯会议从没连过：`cfg=never&at=1005`（会议原型的「从没连过」，桌面上那张会议卡嵌它）；「添加到桌面」里标「示例」的会议预览嵌 `cfg=default&at=1005&sample=1`，卡头写「腾讯会议 · 示例数据」；授权失效：`cfg=default&at=1735`（会议原型这一刻授权已失效；会议设计 4.3 两种原因 10-21 起分开画） |
| 待办 | `待办/原型/index.html?frame=<档>&cfg=new&at=1005` | 没有待办：`at=0900`；DK-19 勾掉一件：加 `do=done:t3`（待办原型同一刻排第一的「9 月活动复盘」） |
| 日程 | `日程/原型/index.html?frame=<档>&at=1005` | — |
| 随手记 | `随手记/原型/index.html?frame=<档>&cfg=day&at=1005` | — |

做法（`app.js` 的 `embHtml`、`embVw` 与 `message` 监听）：卡的 `article` 只占格子、挂编辑态的圆钮与弧，底色和阴影去掉（`proto.css` 的 `.is-emb`），里面一个 `iframe` 嵌模块原型；地址带 `vw=`，取「让模块原型按 `card-sizes.md` 算出的外框正好等于这一格」的屏宽——平时就是窗口宽，编辑态列距 30、格子变窄，就换一个屏宽（1440 时小卡 1404、中卡与大卡 1428），所以编辑态的卡也是模块原型自己按那个宽度排的。模块原型画完报 `card-size`（`w`、`h`、`pad`），这里按 `pad` 把 `iframe` 让出阴影余量摆进格子；报来的宽高与格子差超过 1 像素时按格子拉伸，比例记在 `.emb` 的 `data-sx`、`data-sy`。目前只有编辑态的大卡会拉伸：格子 614 高（两行加 30 的行距），模块原型的大卡 602 高，纵向拉伸 1.0199。

嵌入的卡不响应点击（各模块原型 `frame=` 帧的约定）：卡上的刷新、勾选、「还有 N 件」在本原型里点不了，DK-18 的刷新、DK-19 的勾掉由分支脚本触发，DK-20 只让整张卡闪一下（找不到卡里的那一行）。换内容、改尺寸、换编辑态时地址变了，`iframe` 重新加载一次。

**本原型自己画的**（`cards.js`）：云端文件夹、回顾、收件箱、项目、文档、资讯六个模块（本期不分档的示意，能力清单 03 P-39），飞书日历、腾讯会议两个插件卡，以及岛、圆钮、弧、内容小牌、内容菜单、「添加模块」格、提示条这些桌面外壳。没有任何一处是仿画四个模块的卡。

## 地址参数

参数名与各模块原型统一（技能 `showcase-template.md`「画面从哪来」）。本原型是界面交互原型、没有时刻，`at=`、`day=` 不适用。

| 参数 | 取值 | 作用 |
| --- | --- | --- |
| `frame` | `small`／`half`／`tall`／`full` | 只画一张卡（配 `m=` 模块、`variant=` 内容）；外框就是 `card-sizes.md` 的表值 |
| | `panel` | 只画「添加到桌面」面板（配 `m=` 选中的模块） |
| | `desk` | 只画桌面（配 `cfg=`、`do=`；带 `loop=content` 时循环换内容） |
| | `gallery`／`gallery-page` | 只取整个面板／只取右边（版式 F 是对照板，A、E、D 是模块页；配 `m=`，或配 `cfg=`、`do=<场景>:<步数>` 先在桌面上走完步骤）；面板按 900 高窗口画，静止画面裁到内容为止；A、E、D 的 `gallery-page` 默认只截第一档，`secs=<N>` 截前 N 档；带 `loop=sizes` 时取整块 |
| | `desk-row` | 只取桌面上相关的几张卡：`rows=<模块>` 的所有卡，加上刚放上的那张；编辑态时连同「添加模块」格；其余卡藏起来（位置不变）；岛挪到这几张卡正上方、提示条挪到正下方，一起裁进去 |
| | `toolbar` | 只取编辑桌面里刚动过的那张卡，连同把手、岛和内容菜单（配 `cfg=`、`do=`） |
| | 不带 | 完整原型（控制带、状态说明栏）；说明页每帧的「在原型里打开这一刻」就是同一地址去掉 `frame=` |
| `m` | 模块键（`meetings`、`todos`、`calendar`、`notes`、`news`……） | 画哪个模块；完整原型里带 `m=` 会打开「添加到桌面」并选中它 |
| `variant` | 内容键（设计文档 6.4 括号里的英文，如 `next`、`overview`） | 同一档里的哪种内容；不带就是这一档的默认 |
| `cfg` | 预设桌面（`DK.PRESETS`）：`free` 定稿默认桌面、`mini` 会议中＋待办小＋日程小、`nomeet` 没有会议卡、`mtsmall` 会议小（下一场）＋待办小＋日程小、`empty` 空桌面、`t2`／`t3`／`t4` 任务入口；可用 `+` 叠开关：`off` 腾讯会议未连接、`expired` 授权失效、`empty` 没有未完成的待办、`full` 已有 50 张 | 桌面上原有哪些卡、外部状态 |
| `do` | 逗号分隔：`<场景>:<步数>`（`add`／`content`／`offline`／`remove`／`repeat`／`sync` 的前几步，步骤在 `data.js` 的 `DK.SCENES`）、`edit`（编辑桌面）、`zoom-<尺寸>`（F 版式放大看这一档）、`all-sizes`（A 版式点了「看全部尺寸」）、`size-<尺寸>`（E 版式停在哪一档）、`pop`（打开内容菜单）、`preview`（单张卡画成预览，数据来源照 `DK.previewSource`）、`reads`（左下角显示同步与调用次数） | 叠加的用户操作 |
| `opt` | `1:F｜A｜E｜D` 面板版式、`7:A｜B` 换内容入口、`8:A｜B` 换内容动效；多条用逗号隔开 | 切换设计文档 12.1 的规则；不带时一律是默认（`1:F,7:A,8:A`）。原第 14 条（能否重复放、面板里的按钮）白晨 10-21 已定，不再能切换 |
| `loop` | `sizes`／`content` | `sizes` 只配 `frame=gallery`／`gallery-page`／`panel`：版式 E 的模块页每 2.5 秒换下一档；`content` 只配 `frame=desk`：一张会议小卡每 3 秒换一次内容（照 `opt=8`）。没有时刻，用状态代替 `HHMM,HHMM`；收到 `postMessage({type:'replay'})` 从头播 |
| `rows` | 模块键 | 只配 `frame=desk-row` |
| `secs` | 数字 | 只配 `frame=gallery-page`：截前几档 |
| `vw` | 数字 | 按这个窗口宽算几何；说明页把 iframe 的视口宽设成要模拟的窗口宽，所以单张卡不会被误画成手机版式 |
| `task`、`mark` | `2`／`3`／`4`／`free`；`DK-01`～`DK-28` | 只用于完整原型：直接进某个任务或分支 |

带 `frame=` 时：不显示控制带与状态说明栏，背景透明，画面不响应点击；画完用 `parent.postMessage({type:'card-size', …}, '*')` 报尺寸：

- 单张卡：`w`、`h` 是卡的外框（就是 `card-sizes.md` 的表值；四个模块的卡是本原型的格子，里面嵌的模块原型另向本原型报它自己的 `card-size`），`x`、`y` 是卡左上角，`pad: 16` 是说明页四周该留的阴影余量，打开了内容菜单时另报 `box`（卡与菜单合起来的范围）。
- 局部画面（`gallery`、`gallery-page`、`desk-row`、`toolbar`）：`crop: true`，`x`、`y`、`w`、`h` 是裁剪范围（页面坐标），`pad: 0`。说明页据此按 1:1 裁出，栏宽不够时才等比缩小。

## 分支

| 编号 | 情况 |
| --- | --- |
| DK-01 | 选中会议：右边四档五种按桌面的样子摆在一起、同一个比例缩放（默认版式 F「四档对照」） |
| DK-02 | 腾讯会议未连接：预览用示例并标明，照样能放上 |
| DK-03 | 授权失效：预览用示例；桌面上的会议卡要重新连接 |
| DK-04 | 没有未完成的待办：预览用示例，桌面上的待办卡是空态 |
| DK-05 | 只允许一档的模块（资讯）：只列「中」 |
| DK-06 | 编辑桌面里放上：面板先关，新卡从「添加模块」那一格长出来，岛上写「放上了…」 |
| DK-07 | 同一模块、同尺寸、同内容再放一张（允许） |
| DK-08 | 桌面空着（不在编辑态）：「添加模块」格打开面板，放上当场保存、弹提示条 |
| DK-09 | 桌面已有 50 张：放上桌面不可用，并说明原因 |
| DK-10 | 完成时保存失败：提示条说明原因，桌面按后端实际存下的样子 |
| DK-11 | 编辑桌面里换内容：点会议小卡右上角的「下一场」，选「今日概览」 |
| DK-12 | 撤销：岛上「撤销」退一步，卡回到上一步的样子 |
| DK-13 | 改尺寸时内容的去留：今日概览拖弧改成中 → 再拖回小（变回默认「下一场」） |
| DK-14 | 移走（卡左上角圆钮）：岛上写「已移走…」，可撤销 |
| DK-15 | 移走最后一张会议卡：模块的数据与同步照常 |
| DK-16 | 撤销移走：卡回到原位，尺寸、内容、卡片键都不变 |
| DK-17 | 取消：草稿里的改动全部还原，岛上写「已还原，桌面没动」 |
| DK-18 | 三张会议卡（中＋两张小），点刷新只同步一次；30 秒内再点不调用、不提示 |
| DK-19 | 两张待办卡共用一份数据，中卡上勾掉一件，小卡的计数同时少一 |
| DK-20 | 按模块找卡：从简报定位到会议「周例会」（在几张会议卡里挑画出它的那张） |
| DK-21 | 版式 D（对照用）：左边名单、右边一页长的模块页（要上下翻） |
| DK-22 | 窄窗口与手机：预览按当前窗口的几何画（把窗口缩到 1100 以下或 390 宽） |
| DK-23 | 版式 A 第一层（对照用）：格子＋右栏（右栏保留「需要」、详细说明与演示缩略图） |
| DK-24 | 版式 E（对照用）：左边名单、右边一次看一档，点尺寸换档 |
| DK-25 | 版式 A 的下一页（对照用）：点「看全部尺寸」进一页长的模块页 |
| DK-26 | 完成：岛上停「✓ 已保存 · N 处改动」再收回；改过又改回原样算 0 处 |
| DK-27 | 拖弧改尺寸：按住会议卡右下角的弧往右下拖，尺寸牌写「大 · 2 列 · 2 行」，松手吸附 |
| DK-28 | 对照板里点一张「放大看」：会议大卡按原大画出，下面一句作用与「放上桌面」 |

原第 DK-10「放上桌面失败」、DK-12「换内容失败」、DK-16「放回去」、DK-17「放回去失败」随编辑桌面定稿改掉：编辑桌面里放上、换内容只进草稿，不发请求，失败只可能发生在「完成」时（DK-10）；移走不再弹「放回去」，靠撤销（DK-16）。编号沿用，只换了内容。

## 标准答案表

`标准答案表.json` 是本原型导出的期望结果：给定同样的「模块清单＋初始桌面＋开关＋你的操作」，桌面外壳（前端草稿、「添加到桌面」、工作台后端的桌面接口）算出的每张卡的尺寸、内容、叫法，岛上与提示条的话，「完成」时调哪些接口，对照板上摆哪几张、每张写什么，必须和这份表一致。**期望结果只有这一份，正本是原型的规则引擎**（`engine.js` 定规则与文案、`data.js` 定模块清单与虚构的数据）；测试只读这份表，不另写一套期望。会议、待办、日程、随手记四个模块的卡里画什么不在本表，归各模块自己的标准答案表。

### 和会议的表有什么不同

本原型是界面交互原型，没有时间滑块（第 10 节），所以「时刻」换成「第几步操作」：每个配置是初始桌面、开关与一串用户操作，case 写「回放到第几步、按多宽的窗口看」。会议表里的 `at` 在这里是 `step` 加 `viewport`；没有全天扫描（没有时刻）。其余照会议：`meta`／`inputs`／`cases` 三段、只用 `inputs` 回放自检、键顺序固定、不含生成时间。另加 `geometry` 一段（各窗口宽下每档卡的宽高），因为同档等大是本包的规则。

### 怎么生成

- 命令行：在本目录跑 `node export-golden.js`（Node 18 以上，无依赖），写出同目录的 `标准答案表.json`（UTF-8、缩进 2、同一份数据重跑逐字节相同，与本机时区无关）。`node export-golden.js --check` 只核对、不写盘，表与当前引擎算出的不一致时退出码 1。
- 脚本写盘前自检三项，任一不过即退出码 1、不写盘：case 编号不重复；**只用 `inputs` 回放**（`golden.js` 的 `replayCase`：把引擎读的模块清单 `DK.MODS`、你的数据 `DK.YOURS`、卡片上限 `DK.CARD_MAX`、档名 `DK.SIZE_NAME` 临时换成 `inputs` 里的中性 JSON 再算），每条 case 的 `expect` 与表里逐字相同；`geometry` 与 `DK.geo` 现算的一致。
- 页面上没有导出按钮（会议原型有）：本原型的画面状态与 case 一一对应不起来（动效、面板的打开关闭都是画面层的事），只在命令行导出。

### 设计改了怎么更新

改 `engine.js` 或 `data.js` → 重跑 `node export-golden.js` → 看 `git diff 标准答案表.json` 是否只变了该变的 case → 与改动一起提交。新增分支时在 `golden.js` 的 `CASES` 加一行；要新的初始桌面、开关或操作时在 `CONFIGS` 加一个配置。表的结构变了时改 `golden.js` 的 `SCHEMA_VERSION` 并同步改本节字段说明。

### 实现阶段测试怎么用

见[契约](../契约.md)第 6 节：后端只回放会落到接口的步骤（桌面空着时放上、「完成」时 `expect.save.requests` 的每一条），比 `expect.saved_desk`；前端单元测试驱动草稿与对照板，比其余字段。原型的卡片键 `k1`、`k2`…在测试里按顺序映射到真的 uuid。

### 结构

| 位置 | 内容 |
| --- | --- |
| `meta` | `schema_version`、设计文档与原型路径、原型版本说明、`replay`（怎么回放）、`not_covered`（不出表的部分：版式 A、E、D，对照板的缩放比例，四个模块卡里画什么）、`display_enum`（卡片画哪种样子）、`config_ids`、`case_count` |
| `geometry[]` | 窗口宽 `viewport`（1440、1000、390、360）× 是否编辑桌面 `editing`（手机编辑桌面尺寸不变，不另列）：列数、列距、行高、每档 `sizes.<档>.width／height`（设计文档 6.0、`card-sizes.md`） |
| `inputs.<config>` | `note`；`card_limit`（50）；`size_names`（档名）；`manifest`（模块清单：`module`、`name`、`default_size`、`needs_connection`、`contents.<档>[]` 的 `key`／`name`／`say`，第一项是这一档的默认，即契约 1.2 的 `CardInfo.contents`）；`switches`（`tencent_meeting`：`connected`／`never_connected`／`token_invalid`，`todos_empty`，`desk_full`：桌面已有 50 张、只画出 `initial_desk` 那几张，`next_request_fails`：`save_on_done`／`add_on_empty_desk`／空）；`your_data`（待办 `todo_id`、`title`；会议 `headline_item_id` 与 `items[]` 的 `item_id`、`subject`、`start`、`state`，只给按模块找卡与勾掉计数用）；`initial_desk[]`（`card_id` 按顺序 `k1`…，`content` 为空＝升级前的旧卡）；`user_actions[]` |
| `inputs.*.user_actions[]` | 按 `step` 顺序执行。`type`：`open_desk`（`at_seconds`：打开桌面的时刻，秒）、`begin_edit`、`open_panel`（岛上「＋」或「添加模块」格）、`select_module`（`module`）、`zoom`（`size`、`content`：对照板里放大看）、`place`（`module`、`size`、`content`：点那张预览的「放上桌面」）、`remove`（`card_id`：卡左上角圆钮）、`set_content`（`card_id`、`content`：内容菜单里选一项）、`drag_arc`（`card_id`、`cols`、`rows`：拖弧松手时指针跨过的列数、行数，按 `DK.snapSize` 吸附）、`undo`、`cancel`、`done`、`refresh`（`card_id`、`at_seconds`：点会议卡的刷新）、`complete_todo`（`todo_id`）、`locate`（`module`、`item_id`：从简报定位某一条） |
| `cases[]` | `id`（`<分支>@<配置>@<步>`，窗口不是 1440 时再接 `@<宽>`，如 `DK-22@board_meetings@4@390`；补充项分支写 `EXTRA-…`）、`branch`（DK 编号，补充项为空）、`config`、`step`、`viewport`、`note`、`expect` |
| `expect.editing`、`changes`、`island`、`island_buttons` | 是否在编辑桌面；改动数（和进来时一样就是 0）；岛上这一刻那句话 `text`／`sub`／`ok`（`ok` 是「✓ 已保存」前面那个勾；刚按「完成」「取消」时虽已退出编辑态，岛上仍停这一句）；岛上的按钮（有改动时「添加模块」「撤销」「取消」「完成」，没有时只有「添加模块」「完成」） |
| `expect.toast`、`size_badge` | 这一步弹出的提示条 `text`（没有为空；编辑桌面里不弹，结果写在岛上）；拖弧时跟手的尺寸牌（如「大 · 2 列 · 2 行」） |
| `expect.desk[]` | 按桌面顺序的每张卡：`card_id`、`module`、`size`、`content`（换算好的 key）、`label`（卡片叫法，7.4）、`display`（`normal`／`never_connected`／`unconnected`／`empty`，与会议表 `cards.display` 同名）、`content_badge`（编辑桌面里卡右上角内容小牌的字，这一档只有一种内容时为空）、`saved`（与后端存的一样） |
| `expect.saved_desk[]`、`card_total` | 工作台后端此刻存的桌面（编辑中是进来时的样子）；卡片总数（含没画出来的） |
| `expect.save` | 只在 `done` 这一步有：`result`（`saved`／`failed`／`nothing_to_save`）与 `requests[]`（依次调的接口：`DELETE /api/desk/cards/{id}`、`POST /api/desk/cards` 带 `{module, size, content}` 与 `draft_card_id`、`PATCH /api/desk/cards/{id}` 带 `{size?, content}`、`PUT /api/desk/order` 带 `{ids}`；保存失败时是试着发的那几条） |
| `expect.panel` | 「添加到桌面」开着时：`module`（还没选为空，这时 `empty_hint` 是「选一个模块看看」）、`notices[]`（`kind`：`never_connected`／`token_invalid`／`no_data`／`card_limit`，`text`，`button`）、`items[]`（对照板上按摆放顺序的每张：`size`、`content`、`title`（卡下第一行的档名）、`say`、`preview_data`（`yours`／`sample`）、`sample_tag`、缩放前的 `width`／`height`、`add_button.enabled`）、`zoom`（放大看的那一张，同 `items` 的形状） |
| `expect.meeting_sync` | `this_step`（这一步的同步：`synced`／`throttled`／`not_connected`，没同步为空）、累计 `syncs`、腾讯会议调用 `tencent_calls`（一次同步 2 次）、30 秒内被挡掉的刷新 `throttled_refreshes`、这一步一起转圈的会议卡 `spinning_card_ids` |
| `expect.todos_open`、`locate` | 未完成的待办件数（同模块所有待办卡共用这一份）；按模块找卡的结果 `card_id`（没有为空）与 `opens_detail` |

### 覆盖

25 个配置、43 条 case：DK-01～DK-20、DK-22、DK-26～DK-28 每条 1～3 个步（DK-13 三步、DK-20 三个桌面），补充 1 条 `EXTRA-add-fail`（桌面空着时放上失败，设计文档 4.5）；`geometry` 6 行。不出表：DK-21、DK-23～DK-25（版式 A、E、D 只在原型里对照，不进产品）；对照板的缩放比例（前端按面板可视高量，6.6.1）；动效。

2026-10-21 核对：脚本连跑两次 `shasum` 一致，换时区（`TZ=America/New_York`）`--check` 仍通过。把文案、几何、说明条、对照板摆法收进 `engine.js` 前后，说明页用到的 18 个本包原型帧（1440、390 两宽）与完整原型 DK-01～DK-28 的画面文字、桌面卡片签名逐字相同（Playwright 抓取比对，脚本在仓库外），只有 DK-18 按下面一条改过。

### 第二轮顺手改的

- 控制带 DK-18：原来页面刚打开就点会落在「打开桌面那次同步」的 30 秒节流里，第一下刷新也不调用；改成把打开桌面算在 2 分钟前（`app.js` 的 DK-18 一行），与设计文档第 8 节第 4 条「刷新一次只加 2 次调用，30 秒内再点 0 次」一致。说明页不用这一帧。

## 不在本原型里

- 拖动换位置：照编辑桌面定稿，本原型不演示（手机上画了上移、下移）。
- 会议、待办、日程、随手记卡片里的业务规则与交互：嵌入的是各模块原型的静止一帧（照常推演到 10:05），要点卡里的东西去各模块原型。
