A document can forge both a console message and its source (KaTeX's \errmessage, data: scripts, sourceURL, encoded paths), so the display handler logs a line number and nothing the page wrote. The page's own diagnostics reach the app over elyQuery: a missed reveal sends its line; the visual failure and diagram lines already did. A test calls the real handler and checks the captured log. Round 5 found only the missing test; it is added and mutation-checked, with no sixth review under the five-round cap. M-15 is new: the print page runs a document's scripts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 KiB
缺陷清单
2026-10-09 对首版六个应用(ElyDoc、ElyTable、ElyShow、ElyPDF、ElyMark、ElyTree)与其共用 crate 的全量静态审查。逐行读了 apps/ 六个应用、crates/ 全部源码(含 C 垫片与 ElyMark 网页脚本);Calc 与 Impress 的内核行为对照上游 LibreOffice libreoffice-26-2 分支源码核实(sc/source/ui/view/*.cxx、sd/source/ui/view/*.cxx、desktop/source/lib/init.cxx)。审查容器里没有引擎与组件库,没有运行与构建;凡标“已确认”都是沿调用链读到底的结论,“可能”是路径成立但依赖未能运行核实的条件。
编号前缀:T ElyTable,S ElyShow,P ElyPDF,D ElyDoc,M ElyMark,G ElyTree,K LOK 桥(crates/ely-lok),X 共用外壳(ely-office、ely-files、ely-ui、ely-platform、ely-ipc)。严重度:致命=崩溃、丢数据或功能不可用;高=常见路径结果错或功能坏;中=边缘路径坏或界面误导;低=小问题。
统计
| 节 | 致命 | 高 | 中 | 低 | 合计 |
|---|---|---|---|---|---|
| T ElyTable 与 LOK 画布 | 1 | 1 | 7 | 6 | 15 |
| S ElyShow | 2 | 0 | 2 | 6 | 10 |
| P ElyPDF | 1 | 3 | 4 | 6 | 14 |
| D ElyDoc | 0 | 2 | 2 | 4 | 8 |
| M ElyMark | 0 | 1 | 5 | 8 | 14 |
| G ElyTree | 0 | 0 | 3 | 11 | 14 |
| K LOK 桥 | 0 | 1 | 1 | 2 | 4 |
| X 共用外壳与平台 | 1 | 2 | 4 | 7 | 14 |
| 合计 | 5 | 10 | 28 | 50 | 93 |
致命:T-01 内核的图块与命中按像素网格,Ely 的光标、选区、表头按文档 twips,越远越错位;S-01 切换幻灯片后主画布不重画;S-03 ElyShow 的缩放一两帧后弹回“适合幻灯片”,缩放功能不可用;P-01 文件系统的 PermissionDenied 被拼成不存在的文案键,应用崩溃;X-01 设置窗口在前时 Cmd+Q 直接退出,跳过未保存询问并抹掉恢复点。
高:T-02 单元格光标露出边缘即把视图滚到中央,点击与拖选时视图跳动;D-01 导出或打印对话框开着时关闭其标签即崩溃;D-02 邮件合并以当前标签为模板,预览后生成的每份都是同一条记录;P-02 每次编辑落地清掉全部图块与缩略图,页面空白、刚画的墨迹消失;P-03 “编辑文字和图片”先命中图片对象再命中文字;一点抖动就移动了背景图;P-04 TEXT_BLOCKS 对每个文字块重跑一遍整页内容过滤,编辑工具长时间无反应;M-01 键入期间外部以相同内容重写文件,丢掉上次停顿之后键入的全部文字;K-01 非 macOS 的 worker 不运行 VCL 主循环,内核的回调与异步输入永远不送达;X-02 共用 settings.json 读不出时 Doc、Table、Show 根本起不来;X-03 第二个实例启动即清掉运行中实例的工作目录与恢复点。
用户报告的三个问题
ElyTable:点一个单元格,光标跳到别处;拖不出多格选区
根因是 T-01:Ely 把 Calc 的“打印 twips”(文档坐标)与“图块 twips”(按内核像素网格对齐的坐标)当成同一套。内核画图块与命中测试都按它自己每行每列取整后的像素网格(ScViewData::ToPixel 截断),而单元格光标、选区、表头几何都以文档 twips 报回;越往右下,两套坐标相差越多,到第 300 行左右相差整整一行。点击落在内核的像素网格上(选中的是鼠标下画出的那格),但光标框与表头按文档 twips 画,出现在相邻的格上,看起来就是“跳到别处”。T-02 让部分可见的格一被点中就把视图滚半屏,拖选到边缘时内容在指针下移动,选区随之错位。T-03、T-04 是同一组问题的两个侧面。
ElyShow:换幻灯片后主视图不变,要拉一下窗口才刷新
根因是 S-01:Impress 在 SwitchPage 期间压掉一切图块作废通知(sd::Window::LogicInvalidate 里 IsInSwitchPage() 直接返回),只发 LOK_CALLBACK_SET_PART;LokView 收到 SET_PART 只加计数,不作废图块,Input::Part 落地时也不作废。旧幻灯片的图块一直显示,直到窗口尺寸变化让适合缩放变了、全部图块退役重画。
ElyPDF:编辑不工作、画不出
鼠标、命中与坐标换算本身是对的(pages.rs 按工具分派到 press/drag_to/release 或 sketch_*,page_at/from_view 与垫片 placed() 互逆)。失败来自状态与时序:P-02 每次编辑落地都清掉全部图块与缩略图,页面先变成空白纸再一块一块重画,刚画的墨迹要等所在图块重画后才出现,重的页面上像“什么也没画出来”;P-05 上一笔还在落地时结束的下一笔被拒并提示“文档已改动”,连续手绘会丢笔画;P-03 “编辑文字和图片”先命中图片再命中文字,整页背景图或扫描件上永远点不到文字,点击稍一抖动就成了移动背景图;P-04 该工具的层读取在每个文字块上重跑一遍整页内容过滤,密集页面要等很久,等待期间点击被静默忽略;P-06 字体默认“原字体”,嵌入 Type 1/Type 3 字体的文件一应用就报原始引擎错误。另有 P-01:写到无权限目录等任何 PermissionDenied 都被拼成不存在的文案键,直接崩溃。
T ElyTable 与 LOK 画布(Calc)
T-01 内核的图块与命中按像素网格,Ely 的光标、选区、表头按文档 twips,越远越错位
- 严重度:致命 | 置信度:已确认(上游源码核实)
- 位置:
crates/ely-lok/src/view/scroll.rs:112(doc_point线性换算)、crates/ely-lok/src/view/render.rs:275-330(图块按TILE_TWIPS线性排布)、apps/ely-table/src/grid.rs:96-121(表头按place()线性换算)、crates/ely-lok/src/view.rs:382-387(单元格光标按打印 twips 直接用) - 现象:滚到几百行之后点一格,名称框显示的地址是鼠标下画出的那格,但光标框画在相邻行列上,表头标号也对不上;拖选时选区高亮与格线错开;行高非默认(如 0.2 cm)的表十几行就错一行。
- 原因:上游
ScGridWindow::PaintTile(sc/source/ui/view/gridwin4.cxx:1459-1600)把图块起点换成像素(fTilePosXPixel = nTilePosX * nOutputWidth / nTileWidth),再用ScPositionHelper/ScBoundsProvider在累加取整的像素网格里找首行首列,以该列的像素起点为原点画;ScModelObj::postMouseEvent(docuno.cxx:852)把 twips 乘GetPPTX()成像素后GetPosFromPixel(viewdata.cxx:2858)逐行ToPixel累加命中。默认行高 256 twips 取整成 17 像素(真值 17.07),每行差 0.067 像素,约 255 行差一行;默认列宽 1280 twips 取整成 85 像素,约 256 列差一列。而sc_print_twips_msgs下 CELL_CURSOR、TEXT_SELECTION、SheetGeometryData都是文档 twips,上游专门有ScViewData::GetPrintTwipsPosFromTileTwips(viewdata.cxx:2637)做两套坐标的换算,Collabora Online 的客户端也以SheetGeometry在两者之间换算;Ely 没有这一步。 - 复现:新建工作簿,键入 1 回车三百次(或打开任何几百行的 xlsx),滚到第 300 行,点 A300:光标框落在 A301 附近,左侧表头标的是 299;拖选 A300:C305,高亮与格线错开。
- 修法:以
.uno:SheetGeometryData为准在客户端建像素网格(按内核同样的ToPixel截断累加),把鼠标与可见区从文档 twips 换成图块 twips 再发给内核,把 CELL_CURSOR、选区、引用标记从文档 twips 换回图块 twips 再画;并调用setClientZoom让内核的 PPTX 与 Ely 的图块比例一致(见 T-04)。
T-02 单元格光标露出边缘即把视图滚到中央,点击与拖选时视图跳动
- 严重度:高 | 置信度:已确认
- 位置:
crates/ely-lok/src/view/scroll.rs:45-64(show),调用处crates/ely-lok/src/view.rs:372-387 - 现象:点一个只露出一半的格(右缘或底缘),整张表横向跳半屏、纵向跳三分之二屏;拖选拖到边缘时内容在指针下滑走,选区落错位置。
- 原因:
show()对任何不完全可见的矩形都重置滚动:scroll.0 = x - fx - vw / 2、scroll.1 = y - fy - vh / 3,不是最小滚动量;而apply_batch对每次光标或单元格光标变化都调它。 - 复现:把窗口缩到只露出 A 到 H 列,点半露的 H 列;或从 A1 向右下拖选到视口边缘。
- 修法:
show()只滚到刚好露出目标(scroll = x + w - vw或x),与一般表格软件一致;拖选期间不因选区变化滚动。
T-03 视口比工作表宽时网格先居中再左移一次
- 严重度:中 | 置信度:已确认
- 位置:
crates/ely-lok/src/view/render.rs:243-253(spare居中)、crates/ely-lok/src/view/scroll.rs:99-108(extent) - 现象:宽屏上打开工作簿,表格先出现在视口中央、两侧是空底色,内核按
setClientVisibleArea扩大平铺区并报DOCUMENT_SIZE_CHANGED后整张表再跳到左边;窗口每次拉宽都重现一次。 - 原因:
prepare把窄文档居中(slack(viewport.0, extent.0)),这对 Writer 页面合理,对 Calc 的网格不合理:Calc 的文档尺寸只是已用区加余量(上游GetTiledRenderingArea),随可见区增长。 - 修法:Calc 文档不居中(
spare = (0, 0)),或以reach先把extent撑到至少一个视口宽。
T-04 从不调用 setClientZoom,内核命中与几何按默认缩放算
- 严重度:中 | 置信度:已确认
- 位置:
crates/ely-lok/src/ffi/document.rs(无对应调用)、crates/ely-lok/src/view/zoom.rs:44-62(缩放只改本地geom) - 现象:Ely 缩放到 125% 或 200% 后,内核的 PPTX 仍是 100% 的 1/15,
getDocumentSize、GetPosFromPixel的像素取整都按 100% 网格算;与 T-01 叠加,缩放越大错位越明显(图块按 Ely 的比例画,命中按内核的比例算,两套像素网格的取整不同)。 - 原因:上游
ScModelObj::setClientZoom(docuno.cxx:1100)是客户端告知像素/twips 比例的唯一入口,Collabora Online 在载入与每次缩放时都调;Ely 的Document没有包装它。 - 修法:载入与每次
zoom_at后发setClientZoom(tile_pixels, tile_pixels, TILE_TWIPS, TILE_TWIPS)。
T-05 文档尺寸按内核像素取整,表尾被裁
- 严重度:低 | 置信度:已确认(上游源码核实)
- 位置:
crates/ely-lok/src/view.rs:360-368(doc_size直接取getDocumentSize) - 现象:
getDocumentSize(上游docuno.cxx:740-780)返回“像素累加后再除 PPTX”的 twips(85 像素×15=1275 twips 一列,而不是 1280),平铺区越大短得越多;滚动到最右最下时最后一列、最后几行露不全。 - 修法:以几何(
SheetGeometryData)算 Calc 的文档范围,不用getDocumentSize。
T-06 滚轮向下被内核平铺区卡住
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-lok/src/view/scroll.rs:20-28(clamp_scroll以extent为界)、render.rs:264-268(可见区在绘制时才发) - 现象:快速向下滚动空白区时每次只能滚到当前文档底,内核收到可见区后再扩 25 行,下一次滚动才能继续;连续滚动一顿一顿。
- 修法:Calc 下
extent至少放到scroll + 2 个视口,或滚动时提前发可见区。
T-07 表头点选、行高列宽拖动是“按编号的命令”,而每次点击与拖选都推进修订,紧接着的表头操作被当作过期拒绝
- 严重度:中 | 置信度:已确认(时序窗口为一次后台读取)
- 位置:
crates/ely-lok/src/commands/sheet.rs:154-164(select.column/select.row的Col/Row在NUMBERED内,commands.rs:63-72)、crates/ely-office/src/lok.rs:187-202(run_in对编号命令取read_at发 EXPECT)、crates/ely-lok/src/worker/revision.rs:51-66(鼠标按下、松开、按键拖动都bump)、apps/ely-table/src/grid.rs:204-211、:306-327、apps/ely-table/src/book.rs:199-246(reread之后read_at才更新) - 现象:点一格(或拖选、键入)后马上点列头或行头、或拖完列边:命令带着上一次读取的修订发 EXPECT,内核修订已被鼠标事件推进,回
stale:,弹“文档在此间已改动,请重试”,整列没有选中。read_at还没来得及由reread更新时(刚打开工作簿、worker 忙于画图块时)必现。 - 原因:列号、行号不会被光标移动改变,EXPECT 的保护在这里是多余的;而所有鼠标按下与松开(含拖选的每一步移动)都计入修订。
- 修法:
select.column、select.row、columns.width、rows.height不作编号命令(或run_in对它们不带at),只保留对工作表、对象、参考线等真会被改动重排的编号做 EXPECT。
T-08 自动筛选的列菜单对光标所在的表而不是按钮所在的表筛选、排序
- 严重度:中 | 置信度:可能(内核侧按补丁追到;取决于单元格光标在哪)
- 位置:
apps/ely-table/src/data.rs:412-437(column_asked发data.filter/data.sort)、:379-409(ask_column);内核patches/libreoffice/0017-lok-calc-filter-validation-columns.patch的lcl_Query(rView.GetDBData())与SID_SORT路径(GetDBData()) - 现象:单元格光标在筛选区之外(刚在别处键入)时点列头的筛选箭头、勾选值或“升序”:要么弹内核错误(
Check::Undoable失败),要么筛选、排序了光标所在的另一块数据。菜单本身能开,因为.uno:AutoFilterValues?col=&row=用的是按钮格。 - 原因:内核自己的菜单对按钮格
GetDBAtCursor(nCol, nRow)操作,补丁后的LaunchAutoFilterMenu不移动光标;Ely 的答复却经GetDBData()(当前光标或选区)解析。 - 修法:
column_asked先cell.goto到address(column, row)(Dialog::Column记下row),或让补丁按按钮格取数据区。
T-09 导入文本文件时整文件的 UTF-8 校验在界面线程跑
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-table/src/text.rs:241-245(in_window里Pending::new)、:58-63、:108-116(guess_encoding对全文from_utf8) - 现象:打开几百 MB 的 CSV,导入对话框出现前整窗冻结几百毫秒到数秒(树莓派更久)。
- 原因:读字节在后台,
Pending::new(编码与分隔符猜测)却在主线程闭包里。 - 修法:猜测放进后台任务,
in_window只接现成的Pending。
T-10 CSV 导入对话框开着时打开任何别的对话框,待导入的文件静默消失
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-table/src/text.rs:254-262(next_import把Pending移进Dialog::Import);无条件self.dialog = Some(..)的:apps/ely-table/src/output.rs:218、rules.rs:146、:278、:341、analysis.rs:123、:149、page.rs:146、protect.rs:61、formulas.rs:119、:209、data.rs:231、:317、:397 - 现象:访达双击 .csv 出现导入对话框,按 Cmd+E 再取消:
Pending(已检查字节的唯一副本)被丢,文件再也不打开,无提示。 - 修法:替换
Dialog::Import时把它放回imports队头,或有对话框开着时拒绝再开。
T-11 对话框比其标签活得久:导出、定义名称、重命名不可见却“开着”,挡住导入;名称表的“转到”激活已关闭的标签
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-table/src/dialog.rs:644-648(导出sheet_in(*tab)?)、:563-571、:542-545;apps/ely-table/src/text.rs:255-257(next_import要dialog.is_none());apps/ely-table/src/formulas.rs:255-258(core.active = tab不核对) - 现象:Cmd+E 后 Cmd+W 关掉该标签:对话框不画了但
self.dialog仍为Some,无法关闭,之后打开 .csv 没反应,直到再开关一次别的对话框;名称表的“转到”把core.active指到已关标签,正文显示“没有打开的文档”。ElyDoc 的 D-01 是同一类问题(那里直接崩溃)。 - 修法:
Book实现Host::tab_closed清掉指向该标签的dialog与choices;“转到”先核对tab(tab).is_some()。
T-12 打印区域是整列或整行时页面设置无法应用
- 严重度:中 | 置信度:可能(内核以
$A:$D格式化整列区域) - 位置:
apps/ely-table/src/page.rs:75-83(cell_ok要求字母加数字)、:86-97(areas)、:169-176(page_asked以table.page.bad_reference拒绝) - 现象:Excel 文件的打印区域
=Sheet1!$A:$D预填进对话框,只改方向或缩放再按应用也被拒“Write ranges like A1:D20…”;不重写区域就用不了页面设置。 - 修法:
areas()接受COL:COL与ROW:ROW(内核ParseAny本就接受),或内核给的原值免校验。
T-13 打印失败报成“导出失败”(非 macOS 必现)
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-table/src/output.rs:147-150(print把print_later的失败交给output_failed,文案table.export.failed)、crates/ely-platform/src/print.rs:87-89 - 修法:单独的
table.print.failed文案;平台未实现时禁用或说明。
T-14 导入扫描把整个文件的每个字段都建成字符串
- 严重度:低 | 置信度:已确认(影响随文件大小)
- 位置:
apps/ely-table/src/text.rs:78-106(scan)、:158-173(split返回全部行的Vec<Vec<String>>) - 现象:只需要 8 行预览与每列的类型标志,却为 200 MB 的 CSV 分配约 1–2 GB 堆,树莓派上可能耗尽内存。
- 修法:
split改为迭代器,只留前SHOWN行与列标志。
T-15 非 UTF-8 文本的默认编码跟系统区域而不是界面语言
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-table/src/text.rs:236(i18n::resolve(&locale::system())) - 现象:英文系统上把应用语言设成简体中文,打开 GB18030 的 CSV 默认仍是 Windows-1252(反之亦然),与 agents.md 的“中文界面 GB18030、英文界面 Windows-1252”不符。
- 修法:用
ely_ui::i18n解析后的当前语言。
S ElyShow(Impress)
S-01 切换幻灯片后主画布不重画
- 严重度:致命 | 置信度:已确认(上游源码核实)
- 位置:
crates/ely-lok/src/events.rs:274(SET_PART只加cell.sheets)、crates/ely-lok/src/view/input.rs:231-235(show_part只排队Input::Part)、crates/ely-lok/src/view/lane.rs:95-124(Input落地不作废图块)、apps/ely-show/src/slides.rs:244-247、apps/ely-show/src/deck.rs:308-314(只在母版视图切换时invalidate) - 现象:在左侧缩略图条点另一张幻灯片(或经批注栏、演示检查跳转),缩略图高亮变了,主画布仍是上一张;拖一下窗口边才变。
- 原因:上游
DrawViewShell::SwitchPage(sd/source/ui/view/drviews1.cxx:1003-1012)只发LOK_CALLBACK_SET_PART;切换期间sd::Window::LogicInvalidate(sd/source/ui/view/sdwindow.cxx:1016-1020)因IsInSwitchPage()直接返回,不发 INVALIDATE_TILES。Collabora Online 的图块请求自带part,切页即换缓存;Ely 的paint_tile不带 part,图块缓存按坐标键保留,所以旧页一直显示。窗口尺寸变化时fit_zoom改了缩放、retire_tiles才重画。Calc 切表经SetTabNo走PaintGrid会发作废,所以 ElyTable 没有这个症状。 - 复现:新建演示,“幻灯片›新建”,点第一张缩略图。
- 修法:
LokView在Input::Part落地(或收到SET_PART)时retire_tiles()并清failed,或把 part 编进图块键。
S-02 deck.rs 超过 500 行
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-show/src/deck.rs(506 行) - 原因:违反规则 5(文件不超过 500 行);工作区内只有这一个文件超限。
- 修法:把
reread的读取闭包或Extra的图片管理拆到独立模块。
S-03 ElyShow 的缩放一两帧后弹回“适合幻灯片”,缩放功能不可用
- 严重度:致命 | 置信度:已确认
- 位置:
apps/ely-show/src/deck.rs:139-150(Host::observed每次都view.fit_page(cx))、crates/ely-office/src/open.rs:253(每个Reported都调observed)、crates/ely-lok/src/view/lane.rs:121与view.rs:413(任何输入落地、任何内核事件批次都发Reported)、crates/ely-lok/src/view.rs:262-268(fit_page置fit = true)、crates/ely-lok/src/view/zoom.rs:51(zoom_at置fit = false)、render.rs:256、:286-289 - 现象:Cmd+=、Cmd+-、Cmd+滚轮、捏合、状态栏缩放控件、“视图”菜单:幻灯片放大一帧,随即跳回适合页面,状态栏百分比也跳回。agents.md 写的“手动缩放即停止适合”不成立。
- 原因:缩放后重绘改变了可见区,排队
Input::Visible,落地即Reported→observed→ 重新fit_page;没有可见区变化时下一批内核事件也一样。 - 复现:打开任一演示,Cmd+=。
- 修法:只在标签首次观察时适合一次(
Extra里记标志),observed不再调fit_page;Cmd+0 已由Zooming::zoom(Reset)处理。
S-04 选屏对话框被别的对话框顶掉后,show_starting 卡住、放映副本泄漏
- 严重度:中 | 置信度:可能(多屏才会到选屏对话框)
- 位置:
apps/ely-show/src/slideshow/start.rs:180-183(置show_starting、开对话框)、:289-310(只有取消与开始两条路清理)、无条件覆盖self.dialog的:apps/ely-show/src/new.rs:298、apps/ely-show/src/table.rs:24-28、apps/ely-show/src/remarks.rs:80、apps/ely-show/src/chart.rs:453-454;守卫start.rs:123-125只记日志 - 现象:两块屏,F5 出选屏对话框时按 Cmd+N(或插入›表格、批注、图表)顶掉它;此后 F5、Shift+F5、放映菜单都没反应也无提示,
show-N.odp副本留在内核与磁盘里直到下次启动。同样的覆盖也会丢掉打了一半的批注或图表数据。 - 修法:任何
ask_*替换对话框时(或watch_dialogs发现种类离开Dialog::Show)跑与取消相同的清理;或有对话框开着时拒绝再开。
S-05 一条批注的时间恰为午夜或只有日期,整个批注栏不显示
- 严重度:中 | 置信度:可能(上游
utl::toISO8601时分秒全零时不写时间部分;jiff 的civil::DateTime要求有时间) - 位置:
apps/ely-show/src/remarks.rs:28-36(逐条parse::<jiff::civil::DateTime>()?)、:168-176(一条失败整栏换成错误文字);内核sd/source/ui/unoidl/unomodel.cxx以utl::toISO8601写dateTime - 现象:含 00:00:00 批注(LibreOffice “去除个人信息”保存的文件、只写
dc:date的工具)的演示,右栏只显示“a bad comment time 2025-03-01: …”,画布上的标记还在但栏内无法编辑删除。ElyDoc 的 D-04 是同一类问题。 - 修法:无时间部分时按
civil::Date解析,单条失败只影响该条。
S-06 导出或打印的“从–到”填 0 时导出全部幻灯片
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-show/src/output/dialog.rs:82(value.round() as u32,无下限)、apps/ely-show/src/output.rs:53-59(pages()只排序)、crates/ely-lok/src/worker.rs:403-430(from == 0表示全部)、apps/ely-show/src/output.rs:117-125(targets的number as usize - 1,0 时溢出:发行构建回绕、调试构建 panic) - 修法:
set里夹到1..=last,pages()再校验。
S-07 母版视图下演示检查的行按幻灯片序号跳转
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-show/src/check.rs:184-194(show_part(part)用幻灯片序号)、:112(check_show无母版视图守卫,slides.rs:93-99有) - 现象:显示母版时点“第 3 张”,内核对母版列表
setPart(2),显示的是第 3 个母版或空白,对话框关闭。 - 修法:先退出母版视图,或母版视图下禁用行。
S-08 刚编辑过幻灯片就进备注栏键入,备注可能丢
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-show/src/notes.rs(notes.at在聚焦期间冻结在上次读完的修订;run_on(tab, &at, "notes.set", …)是编号命令,EXPECT 拒绝过期修订;强制重读后内核旧备注覆盖输入框,而shown已置为键入文字) - 现象:编辑幻灯片后在后台重读完成前点进备注框键入、失焦:提示“文档在此间已改动,请重试”,键入的备注被旧备注换掉;再失焦不再发送(
text == shown)。 - 修法:聚焦时取视图的
read_at()更新notes.at;发送失败时让shown保持内核文字以便下次失焦重发。
S-09 改尺寸失败后 size_asked 一直留着
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-show/src/design.rs:62-64(命令前置size_asked)、apps/ely-show/src/deck.rs:343-347(只在读回 0.5 mm 内才清);用它的deck.rs:71-74、apps/ely-show/src/insert.rs:144、apps/ely-show/src/media.rs:116、apps/ely-show/src/guides.rs:200、:318 - 现象:
slide.size失败(worker 错误、无撤销步)后宽高字段显示内核没接受的尺寸,新参考线、媒体按它定位裁剪。transition_asked有落地判定,尺寸没有。 - 修法:命令报错时清掉,或像切换那样按序号落定。
S-10 开始放映的两处拒绝无提示(规则 2)
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-show/src/slideshow/start.rs:194-198(标签或屏幕已不在 → 只记日志并discard;选屏对话框开着时关掉标签再按开始可达)、:123-125(正在启动 → 只记日志) - 修法:两处都弹提示。
P ElyPDF(MuPDF)
P-01 文件系统的 PermissionDenied 被拼成不存在的文案键,应用崩溃
- 严重度:致命 | 置信度:已确认(文案层缺键即失败)
- 位置:
apps/ely-pdf/src/view.rs:123-126(restricted拼pdf.may.{needed})、:228(fail对一切PermissionDenied都走restricted(&error.to_string()))、apps/ely-pdf/src/protect.rs:315、apps/ely-pdf/src/ask.rs:507-509 - 现象:导出、提取、拆分、签名、保护、附件另存写到不可写文件夹,或任何 OS 权限错误,不显示错误而是崩溃。
- 原因:
restricted假定错误文字是 worker 的restricted:<名>(client.rs:297-302),但ely_files::export→save_atomic保留 OS 的错误类别,holder()→same_file→canonicalize同样,annotate()里的user::name()读设置也可能是PermissionDenied;得到的键pdf.may.Permission denied (os error 13)不在任何表里。 - 复现:文件›导出… 到只读文件夹。
- 修法:只在文字是
may::NAMES之一时走restricted,否则走pdf.failed/office.error.save;或给 worker 的拒绝单独的错误类型。
P-02 每次编辑落地清掉全部图块与缩略图,页面空白、刚画的墨迹消失
- 严重度:高 | 置信度:已确认
- 位置:
apps/ely-pdf/src/edits.rs:102-111(refresh清tiles、thumbs)、apps/ely-pdf/src/pages.rs:272-279(每帧只请求一块) - 现象:任何编辑(一笔手绘、勾一个复选框、填一个字段)后可见页面变成空白纸,再以每帧一块 512 像素的速度填回;期间刚加的批注看不见;缩略图也全部重画。图多的页面上每次编辑要几秒,感觉“画了没反应”。
- 原因:LOK 画布作废时旧图继续显示到新图到达(agents.md 已定),PDF 视图没有照做:
retire_tiles()直接清空self.tiles,page_view画bg(paper)加空的tiles。 - 修法:旧图块保留到替换到达时才退役(
paint()的tiles.insert处已这样做),缩略图同。
P-03 “编辑文字和图片”先命中图片对象再命中文字;一点抖动就移动了背景图
- 严重度:高 | 置信度:已确认
- 位置:
apps/ely-pdf/src/content.rs:172-187(命中顺序)、:206(1 点阈值) - 现象:整页背景图、扫描件、包裹整页的表单 XObject 上,点任何文字选中的都是图片(面板显示替换/删除);按下与松开相差 1 个页面点(适合宽度下约 1 像素)即成“移动对象”编辑,把背景图挪走。图下的文字永远编辑不到。
- 原因:
layer.drawn.iter().rposition(|d| inside(..))先于文字块查找,不看目标大小;release()的阈值是页面点不是窗口像素。 - 修法:对象整页或包住文字块时优先文字块;移动阈值按窗口像素(如 3 像素)。
P-04 TEXT_BLOCKS 对每个文字块重跑一遍整页内容过滤,编辑工具长时间无反应
- 严重度:高 | 置信度:可能(代价推断,未计时)
- 位置:
crates/ely-pdf-engine/shim/ely_text.c:227-245、:156-179、:133-145(每块一次pdf_filter_page_contents);apps/ely-pdf/src/content.rs:129-156(逐页读)、:169-171(层未到即静默返回) - 现象:密集页面上开编辑工具很久不出框,点击被忽略,图块与缩略图也停住(worker 单线程被占满)。
- 修法:每页一遍干跑记下全部字形原点与字符,再逐块比对;或只对点中的块判定可编辑。
P-05 连续快画或快点被拒:“文档在此间已改动,未执行”
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-pdf/src/annotate.rs:189-203(settled_edit)、apps/ely-pdf/src/content.rs:209-214、apps/ely-pdf/src/writes.rs:176-190、apps/ely-pdf/src/edits.rs:56-93 - 现象:上一笔还在落地(
annotate+重读页数、页框、书签)时结束的下一笔、下一个矩形、下一个复选框点击被丢弃,并把原因说成“文档改动”;多笔手绘丢笔。 - 原因:
settled()是队列为空且不在编辑中;按坐标的批注不会被在途编辑作废(按编号的才会,worker 已以stale:拒绝),却被一律拒绝而不是排队。 - 修法:按坐标的批注进编辑队列;拒绝只留给按编号的编辑,并改正文案。
P-06 默认字体“原字体”在 Type 1/Type 3 字体的文件上失败,只给引擎原话
- 严重度:中 | 置信度:可能(
pdf_font_writing_supported只认 TrueType/CFF/OpenType) - 位置:
apps/ely-pdf/src/editing.rs:77、crates/ely-pdf-engine/shim/ely_write.c:61-67、apps/ely-pdf/src/writes.rs:115、:138-142 - 现象:LaTeX 或旧 PDF 上“应用”报“previewing text failed: the document's font cannot write new text”,不提示换字体(缺字形的情形倒有
pdf.text.missing提示)。 - 修法:像
Wrote::Missing一样在面板里提示换字体,或读块时预判可写性、默认 Helvetica。
P-07 含连字的文字块永远不可编辑
- 严重度:中 | 置信度:可能
- 位置:
crates/ely-pdf-engine/shim/ely_text.c:91-109(block_targets按 stext 字符计数)、:112-130(take_glyph按字形计数)、:167 - 现象:含 fi、fl、ffi 连字的段落不出编辑框、点击无效;真放过去
ely_remove_block也会报“N of M glyphs were found”。 - 修法:按同一原点的字符分组计字形,或每字形按
ucslen多计命中。
P-08 页面读取失败后每帧重试、每帧弹提示
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-pdf/src/annotate.rs:76-110(ask_notes)、:113-134、apps/ely-pdf/src/content.rs:129-156(ask_layers)、apps/ely-pdf/src/attach.rs:184-205、apps/ely-pdf/src/sign.rs:49-75 - 现象:某页的批注、层、附件、名称或签名读一次失败后,
fail弹提示、notify重绘、重绘再问、再失败,没完没了;worker 死掉后每个可见页每帧一条错误提示,直到按“重新打开”。 - 原因:失败不记页(图块有
failed/thumbs_failed,这些没有)。 - 修法:各类读取加按页的失败集合(
refresh()清),引擎已结束时不再问。
P-09 识别文字的写入被拒后仍弹“成功”
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-pdf/src/ocr.rs:510-513(toast(.., Success)在on_same之后无条件执行) - 修法:成功提示移进
on_same的闭包。
P-10 预览回复被丢弃时“应用”静默无事
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-pdf/src/writes.rs:72-86、apps/ely-pdf/src/view.rs:241-247(read丢弃编辑前的回复而不调then) - 修法:改用带版本核对的
off,不符即提示pdf.object.changed。
P-11 撤销或重做在 MuPDF 侧失败后 worker 的步数不再同步
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-pdf-engine/src/bin/ely-pdf-worker/main.rs:62-86、:161-165 - 修法:失败时
doc.sync(&self.mupdf, None)。
P-12 unhook 中途抛出时泄漏保留的对象
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-pdf-engine/shim/ely_insert.c:17-49、:352-356(n只在返回时发布,fz_always以 0 释放) - 修法:以
int *n传入并逐个递增。
P-13 优化导出的“之前”大小取磁盘文件而非当前文档
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-pdf/src/output.rs:217-224 - 修法:量 worker 的快照,或标签有改动时不写“之前”。
P-14 文字块含控制字符时 JSON 回复不可解析
- 严重度:低 | 置信度:可能
- 位置:
crates/ely-pdf-engine/shim/ely_text.c:240(%q不是 JSON 转义;别处用的是ely_json_string) - 现象:ToUnicode 坏掉的文件文字里有 U+0001–U+001F,
text_blocks解析失败,编辑工具永远读不到该页,并落入 P-08 的循环。 - 修法:
text、font用ely_json_string写。
D ElyDoc(Writer)
D-01 导出或打印对话框开着时关闭其标签即崩溃
- 严重度:高 | 置信度:已确认
- 位置:
apps/ely-doc/src/actions.rs:84-86(self.tab(*tab).expect("a modal keeps its tab")),对话框由apps/ely-doc/src/output.rs:38-48打开;关闭路径crates/ely-office/src/close.rs:38-42、:142-154、:191-221 - 现象:开着“导出…”或“打印…”对话框按 Cmd+W、点窗口关闭钮或 Cmd+Q,标签被移除后下一帧渲染
expect失败,进程崩溃;Cmd+Q 时先于其余脏标签的保存询问崩溃,这些标签只剩 10 秒一次的恢复点。 - 原因:
Dialog::Output记着标签号,dialog_element每帧无条件解包;没有任何地方在标签关闭时清self.dialog(Docs未实现Host::tab_closed),release_tab还把output()排队的when_settled续动作丢掉。其他对话框(Ask、Link、Reference、外壳的Unsaved)都是防御性写法。 - 复现:打开任一文档 → 文件›导出… → Cmd+W。
- 修法:
dialog_element在tab()为None时清掉对话框并返回None;Docs实现tab_closed丢掉指向该标签的Dialog::Output。
D-02 邮件合并以当前标签为模板,预览后生成的每份都是同一条记录
- 严重度:高 | 置信度:已确认
- 位置:
apps/ely-doc/src/merge.rs:88-94(source()返回core.active)、:152-164(预览)、:178-195(生成);apps/ely-doc/src/merge/run.rs:351-371(预览经load_into开新标签)、crates/ely-office/src/open.rs:231(新标签成为当前) - 现象:选 CSV、插字段、点“预览”(填好的副本开成新标签并成为当前标签,合并面板仍在右侧)再点“生成”:模板成了预览副本,字段早已替换成第 N 条记录,N 个输出文件内容相同,文件名还带预览标签名;再点预览是预览的预览。无任何提示。
- 原因:
Merge不记来源标签,每次点击时取core.active;单测a_merge_keeps_its_source_when_the_tab_changes直接传source,没覆盖界面路径。 - 复现:任一含
«Name»的文档 → 邮件合并 → 三行 CSV → 预览 → 生成。 - 修法:选 CSV 或插字段时记下来源标签号(或在
Extra标记预览标签),面板显示来源名,预览与生成都用它,当前标签是预览副本时拒绝。
D-03 界面线程同步持 worker 锁读内核(样式、字体、书签、公式、分节名)
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-doc/src/insert.rs:318-324(insert_section)、apps/ely-doc/src/refs.rs:81-86(read,书签、交叉引用、公式对话框用)、apps/ely-doc/src/props.rs:116-122(read_fonts)、:133-137(read_styles,每次切标签与Reported都跑) - 现象:保存大文档、邮件合并几百条记录(每条载入、替换、另存、关闭都持锁)期间,切标签或打开“插入›书签…”整窗冻结到锁空出来为止。
- 原因:违反 2026-10-05 决策“界面线程不碰 worker”,这四处直接
worker.lock()而不走read_in/read_off。 - 修法:改为后台读取,回来时核对仍是同一标签与视图。
D-04 一条批注的时间读不出,全部批注与修订都不显示
- 严重度:中 | 置信度:可能(内核对无日期批注写
0-00-00,utl::toISO8601的空日期即如此) - 位置:
apps/ely-doc/src/review.rs:164-167、:373-393(threads遇第一个解析失败即整体Err)、:179-181 - 现象:打开含无日期批注的 DOCX(
w:comment无w:date),批注与修订两栏都空,并弹引擎错误提示;每次审阅事件重读再失败再弹。 - 原因:单条解析失败被提升为整表失败,
and_then连已解析的changes一起丢掉。 - 修法:逐条解析时间,失败的那条用占位时间;
changes不因批注失败而丢。
D-05 邮件合并某条记录失败时内核文档泄漏
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-doc/src/merge/run.rs:464-470 - 原因:
fill/save_as以?提前返回,close_doc不执行,Doc无Drop;每次重试多漏一份,worker 的N documents open计数漂移。 - 修法:先取结果再一律
close_doc,最后传出首个错误。
D-06 导航栏大纲点击按当前列表取下标,后台重读后可能越界
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-doc/src/navigate.rs:277-283(navigator.outline[at]) - 修法:用
get(at),或在渲染时把目标矩形放进行的闭包。
D-07 导航栏隐藏时仍随每次光标移动重读大纲与书签
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-doc/src/chrome.rs:236-245(left_view不看navigating就navigator.show(tab))、apps/ely-doc/src/navigate.rs:79、:91-123 - 现象:关掉导航栏后每次按键仍排两次内核读取,与键入争 worker 锁(规则 9:空闲不做事)。
- 修法:隐藏时
show(None),显示时重读一次。
D-08 Linux、Windows 上“打印…”可用,导出 PDF 后才报“此平台未构建”
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-doc/src/output.rs:28-30、:80-88;crates/ely-platform/src/print.rs:87-89 - 现象:菜单与页码范围对话框都正常,最后一步弹出带临时路径的错误提示。各文档应用同(见 X-13)。
- 修法:平台未实现时禁用菜单项或在对话框里写明;错误文字去掉路径。
M ElyMark(CEF)
M-01 键入期间外部以相同内容重写文件,丢掉上次停顿之后键入的全部文字
- 严重度:高 | 置信度:已确认
- 位置:
apps/ely-mark/src/outside.rs:223-224((true, _) | (false, false) => take_disk)、:243-268(take_disk)、apps/ely-mark/src/view.rs:184-196(refresh把changed、reported归零)、apps/ely-mark/web/src/main.js:52-59(全文停手 300 毫秒才送)、:179-187(refresh清掉待送) - 现象:连续键入时外部进程以相同字节重写文件(
touch、同内容的git checkout/stash pop、云同步重盖、格式化器输出相同),编辑器以旧文字重建,上次停顿以来键入的字全部消失,标签还显示已保存;无提示。 - 原因:页面只在停手 300 毫秒后送全文,键入中 Rust 侧
doc.current是停顿前的文字;disk.text == current的分支不看dirty(它含edit_pending),直接take_disk。与 agents.md “有未保存内容(含页面还没送回的编辑)即不动磁盘与编辑器”相悖。 - 复现:打开
a.md连续键入几秒,期间在终端touch a.md。 - 修法:
disk.text == current而视图未落定时不take_disk:等when_settled后重判,或当作Outside::Changed;落定且相同时只换指纹不动编辑器。
M-02 refresh 归零版本计数却不换代,在途的一键让标签一直“未落定”
- 严重度:中 | 置信度:可能
- 位置:
apps/ely-mark/src/view.rs:193、:264-272(Loaded路径有换代)、apps/ely-mark/web/src/main.js:179-187、crates/ely-web-content/src/engine.rs:127-143;受影响crates/ely-office/src/close.rs:96-99、save.rs:325-326、apps/ely-mark/src/compare.rs:381-382 - 现象:干净标签被外部改动刷新后,Cmd+S、Cmd+W、Cmd+Q、比较与自动保存都静静等
when_settled,直到再键入一个字才一起执行。 - 原因:刷新前排队的一键在渲染进程里先产生
changed = N+1,再执行refresh丢掉待送全文;Rust 已归零又收到changed,没有text跟上,settled()为假;refresh不像Loaded那样换代,旧回报没被丢。 - 修法:
refresh自己换一代(self.load += 1传给ely.refresh(text, load))。
M-03 干净标签接过磁盘文字后关闭仍问“是否保存”
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-mark/src/outside.rs:243-268(take_disk不更新tab.mark)、apps/ely-mark/src/view.rs:192、apps/ely-mark/src/engine.rs:133-136、crates/ely-office/src/close.rs:107-128 - 现象:文件在别处被改、ElyMark 静默重载后,Cmd+W 对没动过的标签弹未保存询问;比较对话框选“用磁盘上的”后同。
- 原因:
request_close比较Engine::history(磁盘文字散列)与tab.mark(载入或上次保存时的散列),不等即问。 - 修法:
take_disk(与合并采用后)同步tab.mark = mark(&disk.text)。
M-04 第二次打印或导出 PDF 悄悄取消第一次,没有文件也没有错误
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-mark/src/export.rs:93-97、:276(打印与导出共用print-{id}.html)、:315-334(self.printing = Some(..)覆盖) - 原因:
Desk.printing只有一个槽,赋新值即丢掉上一个的隐藏WebView与订阅,第一份的Event::Printed无人接。 - 修法:按作业编号保存多份,或一份未完时拒绝第二份并提示。
M-05 点页面里的链接什么也不发生
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-mark/src/view.rs:274(Event::Leave(url) => log::info!(..))、crates/ely-web-content/src/fence.rs:319-324 - 现象:预览与可视模式里点
http(s)/mailto链接:不跳转、不开浏览器、不提示。PRD 允许用户主动打开外部链接,agents.md 说“交给应用”,应用没处理。 - 修法:
Leave时http、https、mailto交系统打开,其他协议提示拒绝(同 ElyPDF 的链接策略)。
M-06 on_app_quit 无条件删恢复点与崩溃锁,AppKit 直接终止时丢未保存内容
- 严重度:中 | 置信度:可能(依赖 GPUI 对非 Quit 动作的终止也跑
on_app_quit) - 位置:
apps/ely-mark/src/desk.rs:244-248、apps/ely-mark/src/restore.rs:145-155(Keeping::close) - 现象:注销、关机或 Dock 的“退出”经
terminate:结束进程,proceed(After::Quit)的未保存流程不跑,退出观察者却删掉session.lock与recovery/;下次启动读到“干净结束”,什么也不回来。外壳的Recovering::end有同样假设(见 X-01)。 - 修法:退出观察者只在无标签(或全部干净)时清理,否则留下锁与恢复点。
M-07 崩溃恢复的未命名副本按“第一个显示的未命名标签”配对,内容可能落错标签
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/src/restore.rs:195-201、apps/ely-mark/src/desk.rs:226-228 - 修法:
Waiting条目记下为它新建的标签号,restore_shown按号配对。
M-08 页面重载后悬着的渲染回调永不完成,导出既不成功也不报错
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/src/view.rs:264-272(Loaded不清renders)、:210-220、apps/ely-mark/src/export.rs:165-185 - 修法:
Loaded、Failed时把renders全部以错误结束。
M-09 导出的保存面板出错被当作取消
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/src/export.rs:129-131(let Ok(Ok(Some(path))) = chosen.await else { return log::info!(..) }) - 修法:照
Desk::open_picked分三种情形,错误走panel_failed。
M-10 关闭查找框只清当前标签的高亮
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/src/finding.rs:116-124(close_find只对active_view发unfind)、:60-69、apps/ely-mark/web/src/main.js:132、:270-273 - 修法:对每个标签的视图发
unfind。
M-11 页面把搜索词写进应用日志
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/web/src/main.js:246(console.warn带place.query)、crates/ely-web-content/src/handlers.rs:272-275(控制台警告进log::warn!) - 原因:违反规则 4(日志不含正文)。
- 修法:只记行号与是否标题。
M-12 浏览器创建完成前 WebView 已释放,浏览器泄漏
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-web-content/src/view.rs:582-587(Drop时还没有浏览器)、crates/ely-web-content/src/handlers.rs:349-354(on_after_created无条件存入)、crates/ely-web-content/src/engine.rs:165-170 - 现象:开了标签在约 100 毫秒内关掉,渲染进程留到退出。
- 修法:
on_after_created发现surface.closed即close_browser(true)。
M-13 编辑器构建失败时页面空白且不上报
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/web/src/main.js:117-139(show无try/catch)、apps/ely-mark/web/src/visual.js:106-109 - 现象:Milkdown
create()或newTable抛出时没有shown也没有Failed,#document空着,MarkView.shown永为假(跳转、外观等一直等)。 - 修法:
build包try/catch,可视失败退回源码并tell({kind:'failed'})。
M-14 render_pdf 在界面线程内嵌图片并写文件
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-mark/src/export.rs:276-282(渲染回调里inline、read_to_string、fs::write);对照:172-176的write_output已在后台 - 修法:暂存步骤移到
background_spawn。
M-15 打印与导出 PDF 的暂存页执行文档里的脚本
- 严重度:中 | 置信度:已确认(M-11 第 2、3 轮审查在 Windows 与 WSL 的 CEF 上复现)
- 位置:
apps/ely-mark/web/src/render.js(allowDangerousHtml原样保留 HTML 块)、apps/ely-mark/src/export.rs(render_pdf、打印把同一 HTML 暂存后交不显示的 CEF 视图) - 现象:Markdown 里的
<script src="data:...">在打印与导出 PDF 时运行,可调console、elyQuery,可读暂存页。 - 修法:暂存页不运行脚本。
G ElyTree(Git)
G-01 打开“文件历史”或“逐行追溯”后,中间区不再响应任何别的选择
- 严重度:中 | 置信度:已确认
- 位置:
apps/ely-tree/src/view.rs:185-187(body先于match self.side返回look_pane);入口apps/ely-tree/src/hist_pane.rs:43-66、apps/ely-tree/src/pane.rs:483 - 现象:按下差异标题栏的“文件历史”或“逐行追溯”后,点改动列表里另一个文件、历史里另一个提交、分支或储藏,中间区都不变;只有历史面板的小叉能退出。
- 原因:
show()(pick.rs:302)、pick_commit、pick_place、set_side都不清self.look,只有close_look与 blame 的show_commit清。 - 修法:任何新选择都清
self.look,或只在side == Changes且所选文件不变时画它。
G-02 进行中操作读取失败被吞掉;git am 冲突无提示条无错误
- 严重度:中 | 置信度:已确认(
git am细节为可能) - 位置:
apps/ely-tree/src/ops.rs:81-98(doing)、apps/ely-tree/src/moves.rs:74、apps/ely-tree/src/conflict_pane.rs:62、:106-109 - 现象:
doing()出错时opened.doing = Some(Err(..)),没有任何显示或日志;冲突文件列出来了,却没有“继续/跳过/中止”提示,冲突栏两侧退回泛称。 - 原因:
rebase-apply一律当变基读onto,git am的rebase-apply/没有onto,整个读取NotFound;describe()失败(如MERGE_HEAD指向已被清理的对象)同样整体失败。违反规则 2。 - 复现:终端里
git am停在冲突,在 ElyTree 打开该仓库。 - 修法:
Some(Err)以提示条显示 Git 原话并记日志;无onto的rebase-apply视为git am进行中。
G-03 新建的空仓库在“仓库”页显示两段 Git 致命错误(引用日志、LFS)
- 严重度:中 | 置信度:可能
- 位置:
apps/ely-tree/src/recover.rs:50-69(reflog … HEAD --)、apps/ely-tree/src/structure.rs:137-138(git lfs ls-files)、apps/ely-tree/src/places.rs:40-50、apps/ely-tree/src/side_places.rs:261-264、:279-281 - 现象:“新建仓库…”后仓库页出现 “fatal: bad revision 'HEAD'” 与 “Git can't resolve ref: HEAD” 两块红字;仓库没有问题,空列表才是正确状态。
- 原因:HEAD 未诞生时显式传
HEAD的reflog show以 128 退出,run_or_one不接受;git lfs ls-files同样先解析 HEAD。 - 修法:
status.head.oid为空时两项直接给空列表。
G-04 停止取回/拉取/推送失败的提示写成“克隆没有停下”
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/network.rs:126(stop_remote复用tree.error.stop)、crates/ely-ui/src/i18n/tree.rs:53 - 修法:加一条不限动词的文案。
G-05 合并结果保存失败报成“Git 失败”,tree.error.save 是死文案
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/work.rs:424((_, Err(error)) => failed("tree.error.write", …))、crates/ely-ui/src/i18n/tree_ops.rs:127、:255(定义却无人用,规则 6) - 修法:
written()加(Write::Save, Err)分支用tree.error.save。
G-06 首次提交后紧接着取消暂存,按过期的“已有提交”判定跑成 git rm --cached
- 严重度:低 | 置信度:可能(竞争窗口为一次状态重读)
- 位置:
apps/ely-tree/src/work.rs:352(born取自缓存的opened.status)、:426-427(read异步、next_write同步)、:85-93、:103-112 - 现象:新仓库里暂存、提交,列表刷新前按“全部取消暂存”:第二条写操作仍按
oid: None跑rm --cached -f -r -q -- .,把刚提交的全部文件标为删除(可恢复,但吓人)。 - 修法:写操作执行前在后台
rev-parse --verify -q HEAD判定,不用缓存状态。
G-07 任一引用没有创建日期,整个分支页读不出
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-tree/src/branches.rs:33(%(creatordate:unix))、:106(空串解析失败整体Err)、apps/ely-tree/src/side_refs.rs:227-235 - 复现:
git tag blobtag HEAD:README.md,打开分支页。 - 修法:日期可缺(显示“—”),或跳过非提交对象的引用。
G-08 清理预览后文件被外部删除,对话框只给裸 OS 错误
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/work.rs:270(symlink_metadata(&at)?)、:415-422 - 现象:标题“Git did not do it”,正文 “No such file or directory (os error 2)”,没有路径,Git 并未运行。
- 修法:映射成带路径的“自预览后已变”文案。
G-09 后台读取回来的对话框覆盖用户同时打开的对话框
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/network.rs:186(推送选远程)、:237(强制推送)、apps/ely-tree/src/recovering.rs:116(移动分支) - 现象:按“推送”(无上游)后立刻按“储藏改动…”并开始键入,
git remote回来时储藏对话框连同输入被换掉。 - 修法:只在
tree.ask仍为空(或仍是本次请求)时赋值。
G-10 选中的分支、标签、位置是窗口级的,跨仓库标签串台
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/tree.rs:107-108(picked_ref、picked_place在Tree上)、apps/ely-tree/src/refs_pane.rs:25-33、apps/ely-tree/src/side_refs.rs:238-245 - 现象:仓库 A 选中
main,切到仓库 B,B 的分支页显示它自己的main为已选并带动作按钮。 - 修法:移入
Opened,或activate()时清掉。
G-11 已选边的冲突块再选另一边,提示“结果已手改”
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/conflict.rs:219-224 - 修法:给“该块已选定”单独文案,或支持改选。
G-12 符号链接父目录下,当前打开的工作树被当成别的工作树而可“移除”
- 严重度:低 | 置信度:可能
- 位置:
apps/ely-tree/src/places_pane.rs:253-255、:265-271、apps/ely-tree/src/structure.rs:245-247 - 原因:
here用git worktree list记录的原始路径比对已规范化的opened.repo.root(macOS/tmp→/private/tmp)。 - 修法:比对前
canonicalize。
G-13 非 macOS 平台的死入口
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/running.rs:167-173(停止远程命令非 Unix 报未构建)、apps/ely-tree/src/tools.rs:109-115(“在终端中打开”非 macOS 报未构建)、crates/ely-ui/src/i18n/tree_places.rs:147、:281(“在访达中显示”文案在 Linux、Windows 照样显示) - 修法:按
cfg禁用或隐藏,reveal换平台中性文案。
G-14 repo.rs 的孤立文档注释
- 严重度:低 | 置信度:已确认
- 位置:
apps/ely-tree/src/repo.rs:10(“How many repositories the recent list keeps.” 的常量早已移到ely_files::recent,注释挂到了struct Repo上) - 修法:删掉。
K LOK 桥(crates/ely-lok 的 worker、客户端、事件)
T-01、T-04、T-07 与 S-01 的根源都在这一层,这里只列此外的问题。
K-01 非 macOS 的 worker 不运行 VCL 主循环,内核的回调与异步输入永远不送达
- 严重度:高 | 置信度:可能(代码已读;Linux、Windows 未运行)
- 位置:
crates/ely-lok/src/worker.rs:149-164(非 macOS 的serve只是阻塞的read_frame循环)、patches/libreoffice/0001-lok-macos-tile-painting.patch(CallbackFlushHandler::scheduleFlush非 MACOSX 分支仍Application::PostUserEvent) - 现象:Linux、Windows 上 worker 能答同步请求(载入、画图块、保存),但作废、光标、状态、对话框关闭等回调一条也推不出来,键盘与鼠标(内核经
SfxLokHelper::post*EventAsync以用户事件派发)也到不了文档——编辑器是一张静止的图。树莓派是明确目标。 - 原因:用户事件只在
Application::Yield/lo_runLoop里派发;只有 macOS 路径以 GCD 加run_loop跑循环。 - 修法:各平台都以 unipoll 的
runLoop加轮询回调驱动请求队列,照 macOS 的做法。
K-02 图块的代际在画完之后才取,画到一半的作废被盖掉
- 严重度:中 | 置信度:可能
- 位置:
crates/ely-lok/src/worker/input.rs:76-81(painted:先paint,再events::generation(id))、crates/ely-lok/src/view.rs:466(tile.generation >= self.generation即接受) - 现象:
paintTile期间内核发出作废(Writer 画时懒排版、Impress 空闲任务),返回的像素是作废前的,却带着新代际;视图接受并不再重画,旧内容留到下一次无关的作废。 - 修法:
paint()之前先读代际并盖到图块上。
K-03 rect_of 宽容解析把读不出的载荷悄悄吞掉
- 严重度:低 | 置信度:可能
- 位置:
crates/ely-lok/src/events/parse.rs:25-34,用于events.rs:212、:217-218、:221、:248 - 现象:不是 “x, y, w, h…” 的载荷(如 Impress/Writer 表格多选时 GRAPHIC_SELECTION 的 JSON)要么被静默丢掉(选区框与手柄消失、不报 fault),要么凑出四个数字就被误读。与规则 2 相悖。
- 修法:严格解析开头的数字字段,读不出像
found_of一样进faults。
K-04 Sheets.current 用 as u64 转有符号的 part
- 严重度:低 | 置信度:可能
- 位置:
crates/ely-lok/src/worker.rs:377(doc.part() as u64、count as u64)、crates/ely-lok/src/client/doc.rs:40 - 现象:
getPart()返回 -1(没有视图外壳,关闭或重排期间)时current成了 2^64-1;今天的应用用.get不会 panic,但列表与标签页会错。 - 修法:
try_from,为负即报错。
X 共用外壳与平台(ely-office、ely-files、ely-ui、ely-platform、ely-ipc)
X-01 设置窗口在前时 Cmd+Q 直接退出,跳过未保存询问并抹掉恢复点
- 严重度:致命 | 置信度:已确认
- 位置:
crates/ely-ui/src/run.rs:77(应用级on_action(Quit → cx.quit()))、crates/ely-ui/src/commands.rs:170(secondary-q不带键位上下文)、:150(菜单项)、crates/ely-ui/src/settings/window.rs(设置窗口根上没有Quit处理)、crates/ely-office/src/recover.rs:59-71、crates/ely-files/src/crash.rs:29-46 - 现象:文档应用开着设置窗口(Cmd+,)时按 Cmd+Q 或选应用菜单“退出”,进程立即结束:未保存文档没有询问;
on_app_quit跑Keeping::end()把这次运行标为干净结束,下次启动Crash::check读到干净、prune删光恢复点,内容也找不回。 - 原因:动作先沿聚焦窗口的树派发,没人处理才落到应用级监听;文档宿主只在自己窗口根上截
Quit(走Closing::proceed(After::Quit)),设置窗口的Shell不截,于是直接cx.quit()。 - 复现:ElyDoc 新建文档键入几字,Cmd+, 打开设置,Cmd+Q。
- 修法:全局
Quit改为让每个文档窗口走自己的退出流程(遍历cx.windows()派发),或设置窗口把Quit转发给主窗口宿主;Keeping::end只在全部标签干净时删恢复点。
X-02 共用 settings.json 读不出时 Doc、Table、Show 根本起不来
- 严重度:高 | 置信度:已确认
- 位置:
crates/ely-office/src/lok.rs:135(启动任务里set_author(&user::name()?))、:82(restart同)、crates/ely-platform/src/user.rs:7(Shared::load()?) - 现象:
<数据目录>/ElyOffice/settings.json不能解析、version大于 1 或某字段类型不对时,三个 LOK 应用都以“the document engine did not start: …settings.json…”的致命对话框退出(码 1);引擎崩溃后的“重新打开文档”同样失败。agents.md 规定设置读不出“即用默认值、记下原因”,settings::install也确实这样做,唯独这条路径把它变成致命错误。 - 复现:往 settings.json 写
{"version": 2},启动 ElyDoc。 - 修法:
start/restart里设置读不出时退回user::account()并记日志(设置窗口已有 Banner 说明);或让user::name()用ely_ui::settings::current已读好的值。
X-03 第二个实例启动即清掉运行中实例的工作目录与恢复点
- 严重度:高 | 置信度:机制已确认;频率为可能(Linux 桌面每个文件起一个进程;macOS
open -n或开发构建) - 位置:
crates/ely-office/src/lib.rs:219-226(fresh_work无条件remove_dir_all),调用crates/ely-office/src/lok.rs:128、apps/ely-pdf/src/viewer.rs:102、apps/ely-mark/src/desk.rs:162;crates/ely-office/src/recover.rs:59-71与crates/ely-files/src/crash.rs:40-46(锁里 pid 活着=干净结束) - 现象:实例 B 启动时 (a) 删掉
<data>/work——A 的每个tab.work——此后 A 的每次保存都在消失的目录里写save.{format}失败(files.rs:48-50),状态变“保存失败”、自动保存停止;(b)Crash::check见 A 的 pid 活着判为干净,prune删掉 A 的全部恢复点与index.json;(c)Crash::open把session.lock改成 B 的 pid,A 正常退出时删掉 B 的锁,B 之后崩溃被当作干净结束。 - 复现:Linux 从文件管理器连开两个 .docx;macOS
open -n -a ElyDoc;然后在第一个实例 Cmd+S。 - 修法:数据目录加单实例锁(flock),已有实例在时把文件交给它;或工作目录按进程分(
work/<pid>)、恢复点按锁 pid 存活判定不清理。
X-04 属性栏字号菜单的 expect("sizes are numbers") 是脆弱点,但当前不可达
- 严重度:低 | 置信度:已确认(上游源码核实)
- 位置:
crates/ely-office/src/panel.rs:220-228、:283-285 - 说明:上游
FontHeightPayload(sfx2/source/control/unoctitm.cxx:960-966)只发=<数字>(禁用时为 0),不发disabled;混合选区经补丁 0003 的 JSON 走MIXED被过滤。所以这里不会 panic。保留为脆弱点:任何将来改动内核状态格式都会让整个属性栏崩溃,points应改为可失败。
X-05 恢复点写不成时每 10 秒弹一次提示
- 严重度:中 | 置信度:已确认
- 位置:
crates/ely-office/src/recover.rs:227-231、crates/ely-files/src/recovery.rs:105-116 - 现象:快照超过恢复点容量上限(默认 64 MB,可设到 32 MB;带视频的 PPTX、大 XLSX),或磁盘满、数据目录只读,只要标签还脏,每个计时周期都弹“office.recovery.failed”。
- 原因:失败时
slot.written不变、也没有像keeping.behind那样记住上次失败,下个周期due又含该标签。 - 修法:按槽记上次失败文字,变了或成功才再提示;超容量时写
written = Some(edited)并解释一次。
X-06 session.lock 空或损坏即永久关闭恢复功能
- 严重度:中 | 置信度:已确认
- 位置:
crates/ely-files/src/crash.rs:21-25(非原子写)、:29-50(其他内容返回InvalidData)、crates/ely-office/src/recover.rs:59、:134-141 - 现象:断电截断
session.lock后,每次启动都显示“office.recovery.off: bad session lock”、不写恢复点;没有任何代码重写该文件,用户得手删。 - 修法:解析不出当作
Marker::Crashed(给出恢复点并重写锁),锁文件原子写。
X-07 加密文档的恢复点每次写入都解密全部已有点,且持 worker 锁
- 严重度:中 | 置信度:可能
- 位置:
crates/ely-files/src/recovery.rs:120-121、:164-190、:193-199、:225-237;调用crates/ely-office/src/recover.rs:201-214(在read_in内) - 现象:带密码的 PDF 每 10 秒写点时读并 AES-GCM 解密每个
.enc(至多 20 份×文档大小)只为列出;RecoveryKey::load()(钥匙串加 1 秒锁循环)也每次都跑;PDF 视图排队的编辑与读取随之停顿(树莓派上更久)。 - 修法:按文件名列点,恢复时才解密;密钥每次运行读一次。
X-08 另存为在等待关闭或退出时被拒绝,关闭链悬空,ElyMark 的会话清单冻结
- 严重度:中 | 置信度:已确认
- 位置:
crates/ely-office/src/save.rs:219-246(identity出错、office.error.format、office.error.taken、office.error.convert四处提前返回不调close_cancelled),对照:191-194、:419-424有调;apps/ely-mark/src/desk.rs:85-88、apps/ely-mark/src/restore.rs:282-285、:341-343、:362-366 - 现象:退出或关窗途中对未命名标签答“保存”、选了不可保存的扩展名或别的标签正打开的文件:弹一条提示,退出静静停住;ElyMark 的
keeping.leaving留在true,keep()不再写session.json,到下次尝试退出前打开、关闭、改名的标签都不进清单,崩溃后恢复缺它们。 - 复现:ElyMark 新建未命名文档,Cmd+Q → 保存 → 选
notes.txt。 - 修法:
write_as的每个提前返回在then.is_some()时调close_cancelled。
X-09 保存期间落地的编辑可能让自动保存停摆
- 严重度:低 | 置信度:可能(与事件次序有关)
- 位置:
crates/ely-office/src/open.rs:241-251(只在ModifiedStatus假→真时session.edit())、crates/ely-office/src/save.rs:68-70、:131-132、crates/ely-files/src/session.rs(票据按写入时的修订) - 现象:
save_owned清掉内核 modified、随后导出期间键入的=true若在导出续动作调ely_files::save之前处理,reported看到(true, true)不调edit(),finish_save置Saved;tab.dirty()为真而state != Dirty,自动保存不再触发直到手动保存。 - 修法:导出开始时取票据,或每次
Engine::edited递增都session.edit()。
X-10 别的标签的文件所在卷消失时,本标签的另存为失败并被标为保存失败
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-office/src/save.rs:32-41(holder对每个标签same_file(open, target)?)、:231-234、:429-450(report→save_failed()) - 修法:
holder里解析不出的别的标签路径视为“不是同一文件”并记日志;写入前的拒绝不调save_failed()。
X-11 worker 的 stderr 中继遇到第一行非 UTF-8 即永久停止
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-ipc/src/relay.rs:31-34(lines()出错即return) - 现象:LibreOffice 或 MuPDF 打出一行非 UTF-8(Linux 上 Latin-1 文件名)后,之后的结构化日志、崩溃栈与
Relay::last_error全丢。 - 修法:
read_until(b'\n')加from_utf8_lossy,出错继续。
X-12 恢复路径在界面线程做文件 I/O
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-office/src/recover.rs:89-98(flush_index的暂存写加sync_all,keep_tab/forget_tab调)、:287、:316(restore同步调钥匙串与拷贝) - 现象:每次开关标签都在界面线程 fsync
index.json;崩溃后首启在界面线程查钥匙串(最多等 1 秒锁)并逐个拷贝恢复点。慢介质(树莓派、SD 卡)上可见卡顿(规则 9)。 - 修法:移到后台执行器,
in_window续。
X-13 非 macOS 构建里仍提供只会报“未构建”的入口
- 严重度:低 | 置信度:已确认
- 位置:
crates/ely-platform/src/print.rs:87-89(打印,各文档应用“文件›打印…”与 Cmd+P 照常)、crates/ely-platform/src/trust.rs:23(PDF 签名对话框)、crates/ely-platform/src/media.rs:52(ElyShow 插入媒体)、crates/ely-files/src/rename.rs:63(改名) - 修法:按
cfg或能力标志禁用菜单项,或补齐平台实现。
X-14 agents.md 引用的 docs/engineering-risks.md 不存在
- 严重度:低 | 置信度:已确认
- 位置:
agents.md(三处引用“证据见docs/engineering-risks.mdR-01”等);docs/下无此文件 - 修法:补回文件或改引用。