)
Serial-Studio Problem Center 实现拆解从 19 项任务清单看诊断中心、1 Hz 采样与 API 暴露的完整落地spec 0033【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio本文围绕 Serial-Studio 仓库中 spec 0033Problem Center项目 链路诊断的第三阶段任务清单doc/claude/specs/0033-problem-center/tasks.md展开逐项解读 19 个可独立验证的实现任务及其完成状态结合当前仓库中的真实源码与测试文件说明这套检测器注册 1 Hz 轮询 全量切片替换的诊断架构是如何从设计走到可验收代码的。读完后你能掌握如何为大型 Qt/QML 应用设计一个发现问题—聚合展示—一键跳转—API 暴露的诊断子系统以及该仓库如何用它自己的脚本化验证工具把每个任务的完成状态钉死。一、tasks.md 在项目文档体系中的位置Serial-Studio 采用四阶段规格驱动流程spec → plan → tasks → implementtasks.md是其中的Phase 3 of 4把plan.md中怎么做的技术设计拆分为小的、有序的、每一项都能独立验证的变更单元。同一目录下的三份文档构成完整脉络spec.md需求与验收标准AC1–AC10plan.md技术设计含受影响文件清单与数据流图tasks.md19 项有序任务清单T1–T19执行者按序推进并保持状态勾选。文档头部 frontmatter 标注status: approvedgate 已过全部 19 项任务完成updated: 2026-07-25。值得注意的是tasks.md 中各任务的文件路径写的是当时的app/src/...布局而当前仓库已经过目录重组C 源码主体位于core/下如app/src/Misc/ProblemCenter.h现为 ProblemCenter.h。本文引用路径以当前仓库实际位置为准并在第五节给出对照表。二、任务编写约定Conventionstasks.md 在任务列表之前定义了五条约定这些约定本身就是该仓库工程规范的一部分一个任务 一个聚焦的、可独立评审的变更。若一个任务要动超过 3 个文件或需要一整段话才能描述清楚就拆分Verify 字段是该单元的确认方式——通常是python scripts/code-verify.py --check files辅以测试或回读代码Deps 字段列出必须先落地的任务 ID形成拓扑顺序排列顺序保证树在概念上每一步之后都能编译Agent 不构建、不运行应用、不跑维护者专属步骤T18 的--dump-api-schema、--benchmark-hotpath和 live-API pytest 文件由维护者执行。每条任务都带一个勾选框[x] done和完成后的补充说明相当于把实施结果直接回写进了清单使得这份文档同时是任务书和完工记录。三、核心类型与模型T1/T2 如何建立 ProblemCenterT1 — ProblemCenter 核心类型 模型T1 引入Misc::ProblemCenterQAbstractListModel单例它是整个特性的中枢。当前实现位于 ProblemCenter.h与任务描述一一对应Severity枚举Info 0, Warning 1, Error 2与NotificationCenter::Level对齐和Trigger位掩码ProjectChanged 1, LinkSample 2, OnDemand 4见 ProblemCenter.h#L71-L83Finding结构体severity、entityUniqueId无实体时为 -1、code稳定子 ID如duplicate-frame-index、title、explanation、remedy、checkerId、jump、dataset、group、action、source或settings/page定义在 ProblemCenter.h#L101-L112registerChecker(id, triggers, fn)注册检测器Checker是std::functionvoid(QListFinding)errorCount/warningCount/infoCount/totalCount四个 Q_PROPERTY加lastRunTime全部以findingsChanged为 NOTIFY 信号供 QML 面板与任务栏徽标直接绑定见 ProblemCenter.h#L53-L67runNow()、activate(row)activate解析行对应的jump字段并发出jumpRequested(kind, uniqueId)信号见 ProblemCenter.h#L116-L119按检测器切片的全量替换 相等性比较一次运行只重建某个 checker 的连续切片拍平后的整体列表与上一轮逐字段比较只有真正变化时才触发一次beginResetModel/endResetModel——这是为了避免 1 Hz 轮询在模型未变时每秒重绘面板。T1 有一条硬性设计约束构造函数必须惰性inert——只做成员初始化不调用instance()、不connect、不建定时器、不碰 QSettings头注释里写清原因对应 spec 0001 的 ctor-edge proof。当前文件头部注释仍然保留这一说明ProblemCenter.h#L44-L49The constructor is deliberately inert... everything is wired in setupExternalConnections()。T1 的完成记录确认零外发调用边的构造函数、仅在拍平列表变化时重置模型、每次运行对新增 finding 只发一次聚合通知。T2 — 接入组合根T2 把新模块焊进启动序列改动 ModuleManager.cpp 与 CMake在instantiateCoreModules()中紧跟NotificationCenter之后加(void)Misc::ProblemCenter::instance();在setupCrossModuleConnections()中先于appState-restoreLastProject()调用ProblemCenter::instance().setupExternalConnections()保证恢复项目时 ProjectModel 的变更信号已被订阅不丢第一次触发在registerCoreContextProperties()注册Cpp_Misc_ProblemCenter上下文属性——这正是 QML 里所有Cpp_Misc_ProblemCenter.xxx绑定的来源setupExternalConnections()连接 ProjectModel 变更信号与Misc::TimerEvents::timeout1Hz并把每次运行的摘要发给NotificationCenter。任务完成记录特别强调顺序约束注册必须先于restoreLastProject()已回读确认且 spec-0001 的 ctor-edge proof 对新节点重跑通过零构造期外发边。四、三类内置检测器T3–T9任务把什么算问题的知识全部收敛到三个 checker 文件中ProblemCenter 本体对它们一无所知。当前源码位于 core/Ui/Misc/Problems/。T3 — 项目 schema 检测器spec R8ProjectCheckers.cpp 实现并注册了 spec R8 的完整检查集覆盖五类 finding完成记录中的命名检测器 ID检查内容project.frame-index按 source 分组的重复 frame index两个数据集合法共享 index 时按 plan 的 tradeoff 降为 Warningproject.empty-group既无数据集、也无输出控件的组project.reference悬空引用xAxisId、waterfallYAxis、workspaceWidgetRef、action 与输出控件的sourceIdproject.numeric-range反常/退化区间pltMin/pltMax、wgtMin/wgtMax、fftMin/fftMax、超范围的ledHigh、超范围的报警带project.alias重复的数据集别名实现要点全部回读确认过每个 finding 设置entityUniqueId与jump所有索引/引用检查都以sourceId为作用域跨源比较会产生假阳性没有项目文档QuickPlot / 纯 Console 场景时提前返回每个切片封顶 50 条超出追加一条 and N more。注册触发器为ProjectChanged | OnDemand。T4/T5 — 让链路统计可被拉取这是整套设计里最值得学的部分热路径上不加信号、不加锁只加四个无条件的整数自增。T4 在 FrameReader.h 中加入四个普通quint64计数器m_bytesIn、m_framesExtracted、m_checksumErrors、m_totalOverflowBytes配[[nodiscard]]访问器与既有的droppedFrameCount()并列和一个组合 reset。自增点全部落在已存在的分支内processData的 chunk 计字节、noteDroppedFrame旁的帧计数、ValidationStatus::ChecksumError分支、以及既有resetOverflowCount()调用之前的溢出累加旧代码在那一行把数字销毁了。顺带修复了一个既有缺陷把未限流的逐次校验和qWarning限流到noteDroppedFrame已使用的 5 秒模式——这是整个特性唯一被允许顺手改的相邻修复且必须在提交信息中点名说明。T5 解决可达性问题DeviceManager的m_frameReader原本是私有的且无访问器链路统计根本拿不到。于是给 DeviceManager.h 加[[nodiscard]] FrameReader* frameReader() const noexceptreconfigure 到 open 之间返回空给 ConnectionManager.h 加[[nodiscard]] LinkStats linkStats() const汇总所有设备LinkStats是一个小型 POD字节入、提取帧、丢弃、校验和错误、溢出字节。只在 1 Hz 被调用——无缓存、无信号、帧路径上零调用点。T6 — 链路检测器差值语义与抑制LinkCheckers.cpp 实现 spec R9且必须对上一拍快照求差值而不是绝对总量因为重连会重建FrameReader并清零计数器——从源码结构看任何计数器减少都意味着 reader 被重建此时应当重新定基rebase而不是算出负速率。完成的link.statistics检测器包含这些行为检查项持续窗口内收到字节但提不出帧提出帧但解析数为零校验和失败率超阈值帧队列丢弃环形缓冲溢出播放器抑制回放replay绕过FrameReader检测到任一 player 打开SerialStudio::isAnyPlayerOpen()或链路关闭时自我抑制采样节流采样器最多每 500 ms 推进一次防止problems.run的按需重跑把持续窗口折叠掉文本稳定性所有计数按数量级分桶decade bucket、校验和率用粗粒度区间报告——条件不变时 finding 文案不变模型才不会反复重置。触发器为LinkSample | OnDemand。T7/T8/T9 — 脚本错误检测T7 给 IScriptEngine.h 接口加errorCount()、lastError()、consecutiveTimeouts()、disabled()、resetErrorStats()。关键约束接口保持非 QObject纯虚函数JS 与 Lua 引擎在已经拼接错误消息串的既有分支里记录m_errorCount/m_lastError成功路径零分配Native/CFrameParser继承默认的零/空实现完成记录提到CFrameParser::lastError()因此补了override。T8 在 FrameBuilder.h 加m_transformErrors、m_lastTransformError、m_lastTransformDatasetUniqueId计数器在既有 transform 错误分支自增消息串只在失败的数据集与上次记录的不同时才捕获——一个每帧都抛错的 dataset 只分配一次而不是每帧一次。FrameParser::scriptStats()则遍历各 source 的引擎输出QListScriptStat。T9 的 ScriptCheckers.cpp 注册script.parser按 source被 watchdog 禁用的引擎报 Error反复失败报 Warning与script.transform逐数据集失败可跳转到该数据集同为LinkSample | OnDemand计数分桶、保留原始错误文本。五、暴露面API、Assistant、命令面板与 UIT10–T17T10/T11 — 只读 Problems API handlerProblemsHandler.h 是一个无状态、静态注册的 handler双许可 SPDXGPL 侧可用提供三个命令schema 用API/SchemaBuilder.h构建形状对齐ScriptsHandler所有结果带尾部hint字符串约定命令参数说明problems.listseverity?、checkerId?、limit?默认 50上限 200列出当前 findingsproblems.run无立即跑一轮 OnDemand 检测problems.listCheckers无列出已注册检测器T11 在 CommandHandler.cpp 的initializeHandlers()GPL 块中加#include与Handlers::ProblemsHandler::registerCommands();回读确认位于#ifdef BUILD_COMMERCIAL之前并明确不把任何名字加入destructiveCommandSet()——纯读命令不应被破坏性保护机制标记。T12 — Assistant 安全分层command_safety.json 要求每个已注册命令恰好落在一个安全层级未标注的名字会解析成Confirm导致只读调用也弹确认。因此三个命令名按字母序加入safe数组当前文件 L92-L94 可见三者都在 safe 层并在 ToolDispatcher.cpp 的scopeDescriptions()加problems顶层 scope 描述否则meta.listCategories会给它一个空 blurb。T13/T15 — 静态测试与命令清单绑定T13 的 test_problem_center_static.py 是agent 可运行的静态测试断言三个命令在 safe 层且不在其他层、C 注册位于 GPL 块、无BUILD_COMMERCIAL守卫、存在 scope 描述、未进入destructiveCommandSet()。完成记录7 项全绿后由 T15 扩到 10 项。T15 在 app.json 加app.problems清单条目kind: action、contexts: [app,dashboard,editor]、category: tools、icon: notifications/warning——该图标已带全四个层级无需新 SVG、无需改 rcc.qrc当前条目位于 app.json#L174对应的map行与QtObject写入 AppCommandBindings.qmlapp.problems 绑定见 L57与ProjectEditorCommandBindings.qml镜像app.helpCenter的写法并重跑generate-command-strings.py同步字符串顺带收编了 spec-0031 的 Undo/Redo 待处理字符串、清掉一条陈旧 Recover 条目。T14/T16/T17 — 窗口、任务栏指示器与跳转导航T14 的 ProblemCenter.qml 是Widgets.SmartWindow { category: ProblemCenter }面板ListView直接绑定Cpp_Misc_ProblemCenter展示严重度图标、标题、解释、修复建议jump ! 时出现 Go To另有严重度过滤器、刷新按钮runNow()、清空按钮与空状态main.qml提供DialogLoader与app.showProblemCenter()。图标请求遵循 16 px 槽位用 16 px、空状态 48 px 槽位用 48 px 的渲染尺寸 lint。T16 在 Taskbar.qml 的 MQTT 指示器旁加严重度指示器图标跟随最高存在的严重度、圆角Label徽标显示 error 数量、visible: Cpp_Misc_ProblemCenter.totalCount 0向上Popup展示三个计数加 Open Problem Center 按钮。该任务完成记录里有一个细节因为没有商业守卫功能本身 GPL不需要Loader包装。T17 实现jumpRequested(kind, uniqueId)的 QML 侧路由settings/page打开对应偏好页否则app.showProjectEditor()后按 uniqueId 选中实体。任务中固化了检测器契约entityUniqueId对jump source是sourceId、action是actionId、group是位置索引groupId、dataset是数据集uniqueIdQML 侧selectDatasetByUniqueId()把它映射为selectDataset()需要的(groupId, datasetId)对。硬约束C 侧绝不反向调用编辑器——回读确认没有 C 文件因此新增编辑器依赖。六、验收与完成定义T18 与 Definition of DoneT18 — 集成测试维护者运行test_problem_center.py 按plan.md命名写出 AC2–AC7 共 8 项验收测试使用api_client/device_simulator/clean_statefixtures 与tests/README.md的延迟表链路测试在断言前至少等两个 1 Hz tick实际做法是以约 1 秒为轮次流数据、轮次之间调用problems.run代替盲睡使三个持续样本在单测 30 秒超时内累计完成。标记策略四项项目/API 测试带project三项链路/脚本测试带networkslow。完成记录还诚实标注了两处对 spec 的偏差均遵循 planduplicate-frame-index按Warning断言checksum finding 通过重开链路清除而不是靠稀释比率——因为检测器累计的是 reader 存活期的总量。Definition of Done整特性闸门tasks.md 末尾的 DoD 是整个特性的验收清单全部勾选且多数条目带完成证据spec.md全部验收标准满足AC1、AC10 已核AC2–AC7 代码完成等维护者跑集成文件python scripts/code-verify.py --check对所有变更文件干净0 错误仅arch-singleton-instance预警且该预警在 plan 的风险列表中已预判scripts/registry-verify.py干净清单 schema、id、图标解析、快捷键唯一性、商业守卫扫描、QML 图标渲染尺寸 lintpython scripts/generate-command-strings.py --check干净无清单/字符串漂移pytest tests/scripts/test_problem_center_static.py绿色10 passedagent 执行C diff 跑过qt-cpp-reviewT4/T8 之前重读ss-hotpath--benchmark-hotpath由维护者执行九个门禁层级零回归spec-0001 的 ctor-edge proof 重跑并记录Misc::ProblemCenter构造期零外发边集成测试文件连同运行说明应用启动、API server 开在 7777 端口移交给维护者python scripts/sanitize-commit.py已跑工作树无 lint 债务维护者专属后续在 handoff 中标明SerialStudio --dump-api-schema app/rcc/api/api-schema.json后重跑sanitize-commit.py让 JS/Lua SDK 拾取三个新命令diff 就是所要求的、且仅此而已——唯一刻意的相邻修复校验和qWarning限流在提交信息中点名并给出理由。七、从源码结构看这套设计的三条不变量通读 tasks.md 与其在当前仓库的落地实现可以归纳出三条贯穿所有 19 个任务的不变量热路径只许加整数自增不许加信号/锁/分配。T4 的 Verify 要求回读确认没有新增 atomic、mutex、signal 或 allocationT8 的首失败每数据集才捕获字符串同理dataflow.md 的 Diagnostic Counters — Pulled at 1 Hz (spec 0033) 一节把这条规则写进了架构文档CLAUDE.md热路径块也新增了对应一行。一切诊断都是拉而不是推。检测器只读计数器和项目文档ProblemCenter 在 1 Hz tick / 项目变更 / 按需三个时机调用它们LinkStats、scriptStats()均为纯读取。重连导致的计数器归零通过减少即重置的差值语义消化而不是负速率告警。变更必须自灭。每个 checker 的 findings 切片每轮整体替换条件修复后 finding 自动消失模型只在拍平列表真正变化时 reset保证 1 Hz 轮询不引起 UI 空转。配套的文档侧改动T19也值得注意API-Reference.md 按既有的逐命令格式新增### Problems Commands (3)一节含 finding 字段表当前位于 L4226 起用户侧帮助文档见 Problem-Center.md。八、任务与当前仓库文件对照表tasks.md 写作时的app/src/...路径在当前仓库重组后大多迁至core/阅读源码时按下表对照任务主题当前仓库位置T1/T2ProblemCenter 核心 组合根接线ProblemCenter.h、ProblemCenter.cpp、ModuleManager.cppT3项目 schema 检测器ProjectCheckers.h、ProjectCheckers.cppT4FrameReader 诊断计数器FrameReader.hT5链路统计可达性DeviceManager.h、ConnectionManager.hT6链路检测器LinkCheckers.h、LinkCheckers.cppT7–T9脚本引擎错误统计与检测器IScriptEngine.h、FrameBuilder.h、ScriptCheckers.cppT10/T11Problems API handler 与注册ProblemsHandler.h、CommandHandler.cppT12Assistant 安全分层command_safety.json、ToolDispatcher.cppT13可运行静态测试test_problem_center_static.pyT14诊断中心窗口ProblemCenter.qmlT15命令清单与绑定app.json、AppCommandBindings.qmlT16任务栏严重度指示器Taskbar.qmlT17跳转导航main.qml、ProblemCenter.qmlT18集成验收测试test_problem_center.pyT19文档API-Reference.md、dataflow.md、CLAUDE.md从源码结构看core/Ui/Misc/Problems/下还存在一个 tasks.md 未列出的ExtensionCheckers.{h,cpp}推测为后续 spec 在同一检测器框架上追加的扩展类检查——这恰好印证了该框架中心只认 checker不认问题领域的可扩展设计。九、复现验证的实用命令在只读地浏览本仓库之外若在自己的构建环境中复现该特性的验证链前提已装好 Qt 构建依赖与 Python 环境且仓库完整tasks.md 给出了一组可直接照抄的检查命令# 1. 静态代码检查C/QML 变更文件 python scripts/code-verify.py --check core/Ui/Misc/ProblemCenter.h core/Ui/Misc/ProblemCenter.cpp # 2. 清单/图标/快捷键/图标渲染尺寸 lint python scripts/registry-verify.py # 3. 命令字符串与清单同步检查 python scripts/generate-command-strings.py --check # 4. agent 可运行的静态测试 pytest tests/scripts/test_problem_center_static.py -v # 5. 文档锚点校验 python scripts/documentation-verify.py # 6. 集成验收维护者侧需应用已启动且 API server 监听 7777 pytest tests/integration/test_problem_center.py需要强调的适用前提第 6 项是 tasks.md 明确划给维护者的步骤agent 不运行 live-API 测试--benchmark-hotpath与SerialStudio --dump-api-schema app/rcc/api/api-schema.json同属维护者专属后续用于九层级热路径门禁与 SDK schema 同步。总结来说tasks.md 的价值不在于它列了 19 个任务而在于它把一个诊断子系统应该怎么实现、怎么验证、谁来验收压缩成了可勾选、可重放、可审计的文本每个任务有明确的文件边界、回读式验证方式和依赖顺序完成记录直接回写状态DoD 把整特性闸门与单个任务的闸门区分开。对想在大型 Qt/QML 应用中落地类似问题中心的读者这份文档与它对应的 ProblemCenter.h、Problems 检测器目录、静态测试 构成了一条从任务书到可运行证据的完整链路值得作为规格驱动开发的参考样本研读。【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考