Repository navigation
fix(desktop): 日志接入审计修复:操作串联、引擎日志转发、被拒事件可见和插件日志接线 - #1945
Merged
Merged
Conversation
- 被 Core 拒绝的事件按事件 ID 和错误码记录(最近 20 种),日志窗口状态栏和 collection-status.txt 显示数量与最近一条;不再算作写入失败。 - 整批编码失败的事件计入 dropped,由下一次写入的 log.dropped 报告;批内的 log.dropped 丢失时转交下一次报告,不重复计数。 - 去掉 500ms 轮询:Core 记录事实时通过 lithe_core_install_log_waker 回调安排一次 100ms 合并写入;详细诊断到期由写入器的一次性定时器关闭 Core 的 DEBUG 开关; 关闭时先移除回调再做最后一次写入。只有应用主进程的日志调用 ObserveCoreFacts。 - 自定义日志目录不可用、回退到默认目录时记录 app.logging.redirect_failed;读不出 logging.json 时记录 app.settings.decode_failed;推送 DEBUG 开关失败记录一次 app.logging.diagnostics_failed。 - 日志窗口不再把所有失败记成 app.logging.diagnostics_failed:用户操作失败记 app.notification.operation_failed,窗口自己的读取和保存失败记 app.background.operation_failed,都带 operation。 - ErrorFields 移到 core.LogErrorFields,供各处共用。
固定检出和 LITHE_CORE_RUST_DIR 共用 Cargo 编译目录,而 cargo 按成员在工作区内的相对路径 计算哈希,两个检出把 lithe-diagnostics 等成员编译到同一组文件、同一份指纹,只按修改时间判 新旧。切回原检出时 identity.txt 写着 pinned,链接的却是 override 的事件目录。 构建脚本按 target 和 profile 记录上次编译工作区成员的检出,换了检出先 cargo clean --workspace,registry 依赖仍走缓存;无变化的运行不清理。同步更新 ci-builds.md 和 worktree-resources.json 的说明。
新增 internal/core 的站点测试:从源码读出每个生产日志调用的级别、事件 id 和字段,交给当前 链接的内核按目录编码,拼错的 id、与目录不同的级别、缺少或多出的字段都在测试里失败,而不是 运行时被写入器拒绝。用户操作的 surface 改为 actionSurface 常量,测试要求常量集合与目录描述 完全一致、每个调用解析出的 surface 都在集合内,并禁止把字符串转换成该类型。 按入口修正 surface:右键菜单、拖放、工具栏、按钮分别记录;Find Action 与快捷键运行同一命令时 由命令自己带上来源(runFrom),打开设置、项目、查找等不再一律记成 menu;构建、运行、调试的 共享启动路径不再直接 emit,由按钮、菜单和插件请求各自记录。草稿恢复改记 editor.recovery.applied,后台失败、启动残留处理、VCS 提供者跳过等改用目录中声明的事件。
操作链(#1927 第 1–4 项): - 每个用户动作分配一个 op(action-N),后台工作通过 a.background 继承 origin, Core 请求带 origin(source、trigger、operation),宿主记录和失败提示都带同一个 op。 - 失败提示带“查看日志”按钮,按 op 打开日志窗口并过滤到这次动作的记录。 - 补齐缺失的失败记录;app.notification.operation_failed 只用于用户动作失败, 后台失败改记 app.background.operation_failed,被取代的模型加载记为 plugin_model_superseded。 插件日志(#1927 第 5–9 项): - 插件 ${logDir} 改为会话内的 PluginFilesPath,不再推导安装目录。 - 插件后端的 lithe/log 引擎事实转发给 Core;按设置开关 lsp.setDetailedDiagnostics,诊断详情不再只停在宿主内存。 - languageServer/start 启动前失败由宿主代记,之后通过 startupOperation 交给 Core。 宿主代记的声明式贡献(diagnostics.recordPluginOperation): - debugAdapter/start:stdio 和 hosted 适配器从解析到应答 initialize 的结果, 按 resolve/launch/timeout/exit/initialize 记录;用户停止和 Core 拒绝不记录; 写入超时记为 timeout,stdio 适配器停止读取输入记为 exit。 - lithe/build/model、lithe/build/dependencies:命令式来源按 plan/resolve/launch/exit/decode/timeout 记录;provider 请求由插件 SDK 自己记录; 项目关闭取消的加载不记录。 - Core 拒绝记录时改记 app.background.operation_failed(plugin_operation_record)。 测试用真实 Core 和复制的测试二进制端到端验证各阶段,录制内核放到 plugin_operation_record_test.go 供调试和构建测试共用。
- references/logging.md 整体改写为 Go/Viva 桌面端的记录规则、入口和校验 - SKILL.md 规则 7 与显式处理失败改为 Go 写法 - build-desktop-core.sh 固定到 Core #46 分支提交并说明合入后迁移 - 补齐 log-exempt 标记,webpreview 去掉 slog - 空编辑区快捷键提示改为结构体表,避免 i18n 检查把命令 ID 误判为界面文案
diagnostics-export 的证据补上唤醒回调、origin、插件代记、引擎事实转发、操作串联和目录校验测试, 说明改为 #1927 之后的实现;整机与 Windows 实机验收仍为 pending。
xiaoyumuxi
marked this pull request as ready for review
November 14, 2026 18:13
Lithe Review结论: ❓ 审查未完成 已由服务器取消。可以重新评论 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 Issue / Linked issue
PR 类型 / Type
改动说明 / What changes
背景 / Why
#1927 审计了 Viva 桌面端的日志接入:写入、查询、保留、导出这条主干是通的,但有 13 项接入问题,其中两项会直接丢日志:两条事件不在 Core 目录里,写入时被拒绝;Core 交给宿主的语言服务器、VCS、插件后端日志事实从未写进 v2 日志。另外,用户动作、Core 请求和宿主记录之间没有 op 串联,错误提示无法跳到对应记录;写入器空闲时每 500 ms 轮询一次 Core;插件的
${logDir}不受保留和清空约束;日志规则文档仍按已删除的 macOS 客户端描述。用户附上诊断包时,维护者看不到终端启动失败、语言服务器日志和大部分错误提示对应的记录。本 PR 修复全部 13 项。Core 侧的目录与说明调整在 Lithe-core-rust#46,它已合入 main,本 PR 固定在合入提交
e811068。改动 / Changes
1. 写入器:被拒事件可见、丢弃计数、按唤醒写入(#1927 第 3、8、11 项) —
internal/logstore、internal/core/log_waker.go、internal/logwindowcollection-status.txt显示数量与最近一条(新词条desktop.logs.rejected);不再算作写入失败。dropped,由下一次写入的log.dropped报告;批内的log.dropped丢失时转交下一次,不重复计数。kernelTick轮询:Core 记录事实时经lithe_core_install_log_waker回调安排一次 100 ms 合并写入;详细诊断由写入器的一次性定时器在 15 分钟后关闭;关闭写入器时先移除回调再做最后一次写入。只有应用主进程调用ObserveCoreFacts。app.logging.redirect_failed;读不出logging.json记录app.settings.decode_failed;推送 DEBUG 开关失败记录一次app.logging.diagnostics_failed。app.logging.diagnostics_failed:用户操作失败记app.notification.operation_failed,窗口自己的读取和保存失败记app.background.operation_failed。ErrorFields移到core.LogErrorFields,各处共用。2. 目录一致性测试与 surface 常量(第 1、5 项) —
internal/core/log_sites_test.goTestEveryLoggedEventIsAcceptedByTheKernel:从源码读出每个生产日志调用的级别、事件 ID 和字段,交给当前链接的内核按目录编码;拼错的 ID、与目录不同的级别、缺少或多出的字段都在测试里失败。surface改为actionSurface常量,测试要求常量集合与目录描述完全一致、每个调用解析出的 surface 都在集合内,并禁止把字符串转换成该类型。drag_drop,Core fix(macos): return to welcome screen when closing project #46 新增)、工具栏、按钮分别记录;Find Action 与快捷键运行同一命令时由命令自己带上来源(runFrom);构建、运行、调试的共享启动路径不再直接记录,由按钮、菜单和插件请求各自记录。terminal.session.start_failed,VCS 提供者冲突改用vcs.provider.skipped,草稿恢复记editor.recovery.applied,启动残留进程处理记app.startup.leftovers_resolved(这些事件由 Core fix(macos): return to welcome screen when closing project #46 声明)。3. 操作链(第 4 项) —
internal/core/origin.go、internal/workbench/operation.go、notifications.goaction-N),后台工作通过a.background继承来源;Core 请求带origin { source, trigger, operation },自动刷新的请求标为background。宿主记录和失败提示都带同一个 op。4. 补缺失记录、拆分通用失败事件(第 6、7、10 项)
notifyError:用户可见失败补operationFailed;不需要记录的按四类例外写// log-exempt: <类别>:<原因>。例如拖动移动文件失败、在新窗口打开工作树失败、最近项目读取失败都已记录。app.settings.decode_failed(stage=settings)。读不出后被默认值覆盖的问题不是日志问题,另开 [Bug] 设置文件读不出时以默认值启动,下一次保存覆盖用户原有的全部设置 #1943。app.notification.operation_failed只用于用户动作失败(ERROR);后台失败和降级改记app.background.operation_failed(WARN),例如语言服务器选择的警告、搜索清理、后台列目录;被新一次加载取代的构建模型记plugin_model_superseded(WARN)。5. 插件日志接线(第 2、9、12 项) —
internal/pluginbackend/trace.go、internal/core/plugin_operation.go、internal/pluginservicelithe/log和引擎日志事实(带event、catalogLevel、fields)转发给写入器,保留 Core 给的通道;语言服务器 stderr 在 Core 侧已按每秒 200 行限流。lsp.setDetailedDiagnostics,上游语言服务器的 trace 随之开关。${logDir}改为 Core 返回的会话内插件文件目录(sessions/<会话>/plugins/<id>/files,0700),纳入保留限额和“清空日志”。diagnostics.recordPluginOperation):languageServer/start启动前的失败由宿主记录,之后通过startupOperation交给 Core。debugAdapter/start:stdio 和 hosted 适配器从解析到应答initialize,按 resolve/launch/timeout/exit/initialize 记录;用户停止和 Core 拒绝不记录。lithe/build/model、lithe/build/dependencies的命令式来源按 plan/resolve/launch/exit/decode/timeout 记录;provider 请求由插件 SDK 自己记录;项目关闭取消的加载不记录。app.background.operation_failed(stage=plugin_operation_record)。6. 构建脚本:切换 Core 检出时重新编译工作区成员 —
scripts/desktop/build-desktop-core.shLITHE_CORE_RUST_DIR共用一个 Cargo 编译目录。cargo 按成员在工作区内的相对路径计算哈希,两个检出编译到同一组文件、只按修改时间判断新旧,切回固定检出后链接的仍是另一个检出的事件目录。现在脚本按 target 和 profile 记录上次编译工作区成员的检出,换检出时先cargo clean --workspace(registry 依赖仍走缓存),检出没变就不清理。同步更新docs/ci-builds.md和scripts/resources/worktree-resources.json的说明。PINNED_CORE_REVISION固定到 Core main 上 fix(macos): return to welcome screen when closing project #46 的合入提交e811068(与原分支提交6f2d185的树相同,都是d439ba0)。7. 规则文档(第 13 项)
.agents/skills/develop-lithe/references/logging.md整体重写为 Viva/Go:必须记录的情形与 Go 写法、四类例外、设计步骤和反例、只走目录、写入器与入口表、一条终态、op 和异步边界、Core 请求轨迹、插件代记、DEBUG 门与唤醒、字段与隐私、提示跳转日志、门禁现状、验证和检查清单。SKILL.md规则 7 和“显式处理失败”改为 Go 的丢弃写法与目录常量要求。8. 顺带修复:preview 上界面文案检查失败 —
internal/workbench/shell_view.gonode scripts/i18n/verify-app-language-localization.mjs把空编辑区提示里的Keymap.Label("search.everywhere")当成硬编码文案,preview 的 Desktop CI 在 “Verify shared localization” 失败。现在把提示改成结构体表(文案、未绑定手势、命令 ID),不放宽脚本,行为不变。9. 其他小改动
internal/webpreview去掉直接使用log/slog的输出。workbench.toolWindow.hide的 surface 改为context_menu。shared/platform-feature-matrix/features/diagnostics-export.json:证据和说明改为本 PR 之后的 Viva 实现,验证状态保持pending。不在本 PR 范围内 / Out of scope
PINNED_CORE_REVISION已改为 main 上的提交e811068。app.shell.environment、run.process.execution接入、editor.sync.freeze删除)和 Go 侧 span 辅助类型:[Feature] 桌面端记录 span 事件:登录环境读取和运行进程接入,删除旧编辑器同步冻结事件 #1944。类型专属:fix
复现与根因
validateCatalog: true)调用diagnostics.encodeLogBatch,terminal.session.start_failed和app.vcs.provider_conflict返回 -32053 被拒;期望全部被接受并落盘。其余各项是接线缺失:preview 上recordPluginOperation、setDetailedDiagnostics、origin、日志唤醒回调的引用数都是 0。检查项
internal/core/log_sites_test.go的站点测试做的就是 [Feature] Viva 桌面端日志接入审计:两条事件被目录拒绝、引擎日志未写入 v2、操作链断开等 13 项问题 #1927 用临时 overlay 测试复现的同一项校验(修复前的输出见 [Feature] Viva 桌面端日志接入审计:两条事件被目录拒绝、引擎日志未写入 v2、操作链断开等 13 项问题 #1927),没有在修复前代码上单独再跑一遍。写入器、操作链、插件代记各项的回归测试共 49 个(logstore/writer_test.go、workbench/operation_test.go、workbench/debug_adapter_start_test.go、workbench/build_command_record_test.go、core/plugin_operation_test.go、pluginbackend/trace_test.go等),针对修复后的行为编写。core.Client请求信封、emit系列、logstore.Store、插件${logDir}的调用方都已更新;站点测试覆盖全部生产日志调用.agents/notes/implemented/bug-fix/记录:约束写在日志参考页和 Core README,由站点测试防止复发;决策 Note 仍是.agents/notes/implemented/architecture/2026-11-03-structured-logging-channels.md范围检查 / Scope checks
功能矩阵 / Feature matrix
shared/platform-feature-matrix/features/diagnostics-export.json:两端的实现状态和验证状态、证据路径、owner、验证动作都如实填写;没有运行验证的保持pending./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh;改了平台实现路径的,还运行了./scripts/platform-feature-matrix/verify-platform-feature-matrix-change.sh origin/preview HEAD.artifacts/下生成的矩阵视图插件归属 / Plugin ownership
develop-lithe第三节“插件归属与宿主零依赖”的自查命令,结果为空shared/i18n/;插件的构建步骤、资源路径和补丁没有写进scripts/resources/、docs/ci-builds.md、Agent Note 或 Skill${logDir}指向会话内目录,插件只能把它当不透明路径使用统一日志系统 / Structured logging
rust/logging/events/<root>.json声明,再记录;没有NSLog、os_log/Logger、直接写 stderr、print或手写事件 ID。Go 侧暂无生成的事件类型([Feature] 恢复 Viva 日志事件类型生成和目录使用门禁 #1802),事件 ID 写成常量,由站点测试按目录校验;本 PR 没有新增 span([Feature] 桌面端记录 span 事件:登录环境读取和运行进程接入,删除旧编辑器同步冻结事件 #1944)path、错误用error类型,动态通道段来自已校验的 IDscripts/logging/)已移除;日志用法门禁未完成:站点测试只校验事件、级别、字段与目录一致,绕过写入器和丢弃错误由审查保证,恢复由 [Feature] 恢复 Viva 日志事件类型生成和目录使用门禁 #1802 跟踪界面文案 / i18n
shared/i18n/补齐中英词条,运行node scripts/i18n/generate-i18n.mjs并提交生成结果,没有手改生成文件;Viva 代码通过desktop/internal/i18n/的接口读取shared/i18n/node scripts/i18n/verify-app-language-localization.mjs和node scripts/i18n/generate-i18n.mjs --check,没有放宽脚本或扩大豁免名单逻辑归属 / Logic placement
性能与内存 / Performance and memory
设置 / Settings
N/A:没有新增或修改设置项和设置页。
插件契约 / Plugin contract
N/A:不改插件契约、能力版本、插件函数协议或宿主方法;Core #46 只改日志目录和说明。
发行包与资源 / Bundle and resources
./scripts/desktop/verify/verify-runtime-bundle-immutability.shscripts/resources/worktree-resources.json、scripts/resources/reuse-worktree-resources.mjs的校验路由、对应测试和docs/ci-builds.md“独立工作树的本地编译”一节(改动 6 只改变 Cargo 编译目录的清理时机,更新了说明,校验路由无需变化)无用代码与重构 / Dead code and refactoring
kernelTick轮询、写入器的旧失败计数、webpreview的 slog 输出)验证 / Verification
LITHE_CORE_RUST_DIR=<Core #46 检出> scripts/desktop/desktop-go.sh test -race ./...(rebase 到 preview 295ee28 之前)gofmt -l、desktop-go.sh vet ./...desktop-go.sh test -count=1 ./internal/core/ ./internal/workbench/ ./internal/logstore/.agents/skills/write-stable-tests/scripts/test-stability-macos.sh,本 PR 新增和改动的测试TestBuildCommandRunner是被测子进程入口);两个超过 1 s 警告线:TestEveryLoggedEventIsAcceptedByTheKernel1310 ms(解析全部生产源码并逐条交给内核编码),TestBuildCommandModelLoadIsRecordedAtTheStageItEnded1070 ms(启动 5 次真实子进程);均低于 15 s 上限node scripts/i18n/verify-app-language-localization.mjs、node scripts/i18n/generate-i18n.mjs --check./scripts/agent-notes/verify-agent-notes.sh./scripts/desktop/verify/verify-runtime-bundle-immutability.sh./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh、verify-platform-feature-matrix-change.sh origin/preview HEADdevelop-lithe第三节插件归属自查命令cargo test --workspace、generate-log-events.mjs --check、clippy、verify-docs.mjs未能执行的检查和原因:
e811068。标记 ready 前还缺整机界面检查和 PR 截图(develop-lithe第五节)。提交前确认 / Final checks
preview创建;目标分支:feat、fix、docs 为preview,release 以发布流程要求为准.build/、target/、dist/、.artifacts/等产物,没有凭据、个人路径和未脱敏的日志或截图