Files
next-tjwater-server/docs/investigation-progress-and-presentation.md
T

21 KiB
Raw Blame History

调查进展与实时展示

调查执行中可按需整理正文和流程参考图,Server 累计保留路径并生成 Mermaid,尚未形成结论时也能发布。 Server 将阅读进展、业务报告和浏览器展示请求分别保存。运行结束仍要求同轮最终报告, 图节点不绑定实际执行任务,标记只解释最近整理的路线、结果和限制;不参与调度、审批、等待或结束判断。 路线有实质调整、形成重要结果、需要保留失败尝试或整理报告时更新即可,不要求逐步发布、频繁刷新或及时同步。

进展快照

POST /api/v1/operational-tasks/{task_id}/agent-artifacts 新增可选 progress:

{
  "request_id": "<uuid>",
  "run_id": "<current-run-uuid>",
  "source_session_id": "<claimed-session-id>",
  "progress": {
    "summary": "整理投诉时段的监测核查路线,尚未形成结论。",
    "graph_update": {
      "title": "调查流程参考",
      "nodes": [{
        "node_id": "read",
        "label": "核查监测记录",
        "status": "reference",
        "evidence_refs": [],
        "action_refs": [],
        "map_targets": [{"source_id": "pipes", "feature_id": "<known-pipe-id>"}]
      }],
      "edges": []
    }
  }
}

示例中的编号由实际任务和资产替换。正文最长 20,000 字符,graph_update 可省略。 图示沿用 调查报告契约 的 Mermaid 安全限制。 节点标记可省略或为 null,均显示为参考步骤;新增量更新只接受以下五种:

status 显示 含义
reference 参考步骤 路线或分支说明,不断言是否执行
recorded 已有结果 已整理出结果或依据,不表示任务、计算或现场动作完成
needs_input 待补充条件 记录缺少的资料、权限或人工事实,不控制任务等待
failed 尝试失败 保留一次失败尝试及原因,后续路线另建节点
not_taken 未采用路线 未采用、不适用或改走其他分支

旧图读取兼容:pending/running 转为 reference,completed 转为 recorded,waiting/waiting_human 转为 needs_input, skipped/cancelled 转为 not_taken;failed 保留。仅规范化读取结果,不改写历史文档,不再显示“正在执行”或“记录时执行中”。 REST 与 MCP 使用相同的旧标记映射。MCP 的 progress/report 图示在分页及 data_path 投影之前完成转换, 读取整份说明、节点列表或单个 status 时含义一致;实际 task/run/action 状态和旧执行计划状态保持各自语义。 map_targets 只接受 junctions/pipes/valves/pumps/tanks/reservoirs/scada 七类来源和要素编号。 图中节点引用唯一,证据和动作引用必须属于该任务。新 Agent 使用下述增量更新,节点编号在任务各轮保持稳定。 Server 不验证依赖执行顺序或推断节点完工。

progress.graph_update 包含可选 title、nodes 和 edges。节点沿用 node_id/label/status/evidence_refs/action_refs/map_targets, 可用 detail 记录实际结果或失败原因;连线为 {source,target,label?}。仅提交新增或变化的内容, update_investigation_graph 合并节点、追加明确连线并生成 Mermaid,保留已有路径和引用。 尝试失败时标记 failed,重试或替代路线使用新节点及连线;原失败节点不能改写为成功。 仅更新正文或传入 diagram: null 均保留累计图,原始 Mermaid 不再由新 Agent 生成。 首次增量更新沿用最近保存的旧图,将原源码保存在 source_mermaid,保留原分支和形状后追加内容; 旧图内节点不得改名或重用为其他步骤。已被旧实现覆盖且未存入报告的内容无法还原。 尚未迁移的旧图仍接受旧客户端显式提交的完整图;仅更新正文或传入 diagram: null 时自动接管旧图, 保留原源码并转为累计图。任务启用累计图后拒绝旧客户端重画覆盖,不提供通过空值清图的入口。 省略 progress 保留原快照,同一个请求编号重试只发布一次。 workbench.operational_task_progress 每个任务和 run 保存最新一份快照,独立于七天事件清理。 任务详情和 Agent 上下文返回 latest_progress,包含 revision/run_id/execution_generation/ published_at/source_session_id/progress。优先返回当前执行代次;新轮次尚未发布时保留最近的累计图及其原始轮次。 get_task_context(section="progress") 同样允许读取上轮累计图以接续,摘要和图示不证明新轮次已执行。 报告发布时由 Server 存入累计图及其已有依据,历史报告保持独立快照;最多保留 100 个节点、200 条连线,超限显式报错,不静默裁剪。 快照更新发出 operational.progress.changed,前端据此读取最新内容。

旧任务图迁移

在 Server 仓库运行 python -m scripts.migrate_investigation_graphs --plan /受保护目录/plan.json --project-id <项目UUID>; 多个项目重复指定 --project-id。预览只读数据库,计划文件以私有权限保存原始进度文档和迁移后的完整文档。 核对项目、业务库、任务和图数量后,运行 python -m scripts.migrate_investigation_graphs --apply /受保护目录/plan.json。 连接使用 MetaDB 路由,计划中不保存连接凭据。迁移逐项目事务执行,与正常发布使用相同的事件锁和任务锁, 预览后仍为旧图但已发生变化的行会使该项目回滚;重复执行跳过已经接管的图。

迁移仅更新已有进度图及其 revision,保留原 summary、发布时间、run、会话、节点说明和引用; 原 Mermaid 字节保存在 source_mermaid,旧节点标记转换为参考标记,不解析或猜测原始连线。 历史报告保持原样,通过读取兼容显示新标记。迁移逐项目校验任务、run 和报告整行摘要未变, 并发出进度变更事件及写入独立执行回执;不产生报告更新通知。备份和回执不得提交到仓库。

浏览器实时联动

POST /api/v1/operational-tasks/{task_id}/presentation-events 接收 request_id/run_id/source_session_id/command,要求任务执行权限。 Server 校验当前 run、绑定会话、有效租约和幂等身份,记录 operational.presentation.requested。 响应为 recorded/event_seq/run_id/execution_generation,表示展示请求已保存, 不表示浏览器已显示或现场动作已执行。

command.action 参数
locate_features layer、feature_ids
zoom_to_map center:WGS84 经度纬度、zoom:0–24
highlight_features layer、feature_ids、必填 effect:steady 或 pulse
clear_highlights 无
open_chart chart_id、chart、非空 evidence_refs
close_chart chart_id
set_overlay overlay_id、title、mode:geometry 或 heatmap、evidence_id,可选 data
clear_overlay overlay_id
render_scada_analysis items:device_id 与 high/medium/low/unrated 等级,设备编号不重复
clear_scada_analysis 无

以上十种动作与 Chat 的 present_view、Dev JSONL 共用扁平 command: {action, ...字段}。Chat 使用 frontend-action@2 和执行回执;任务仍只记录展示请求,Dev 只做本地预览。三者使用独立的地图源、SCADA 图层和图表状态。Dev 的动作数据行必须为 {"record_type":"presentation","command":{...}};界面块行使用 record_type: ui_block,新示例明确带 phase: final。普通调查数据保持来源字段,不执行其中的 action。仓库示例见前端统一展示夹具,其中编号来自测试夹具。

图表使用普通折线 line、柱状 bar,或当前曲线加历史散点的 time_comparison,包含 title/chart_type/x_data/series。最多 100 个横轴值和 8 组有限数值序列, 序列长度与横轴对齐,引用证据必须属于当前任务。地图高亮来源沿用上述七类。 覆盖层的权威数据来自不可变证据。省略 data 时,Server 从证据快照提取现有 GeoJSON, 或使用已记录的 longitude/latitude 点位,将 FeatureCollection 加入事件中的 command.data。 若传入 data,必须与同一证据快照解析出的内容一致;Server 始终发布快照解析结果,不能用调用参数覆盖证据。 热力图只接受记录中的点,权重为有限非负数,未记录权重时取 1。 没有坐标的地址、空数据、非法几何、模型自绘区域均不能生成覆盖层。该接口不做地址解析、 范围推算或污染传播计算。展示事件总大小上限为 512 KiB,超限返回 422。

generate_node_coverage 是独立的节点空间覆盖工具,适用于普通项目聊天和后台调查, 不绑定爆管、阀门隔离或固定执行顺序。调用者提供需要比较的节点分组,Server 从当前项目 gis.node_geometries 读取真实位置。监测设备、投诉、地址等须先关联模型节点, 不接受模型自由生成的坐标。具体适用范围和参数见节点覆盖工具。

计算先投影到局部米制坐标,取凹包(默认 ratio=0.25)、加展示缓冲(默认 25 m), 再以 2 m 容差简化并转回 WGS84;凹包比例与缓冲距离可在有界参数内选择。 默认展示各组的地理包络,不判断连接关系;需要时可按模型连接拆分,额外指定视为断开的连接。 少量点、重合点和共线点同样通过缓冲形成面。多组结果一起保存在 result.map_payload, 避免连续 set_overlay 覆盖前一组;result.coverage 保存来源节点、映射完整性及算法参数。 该面不推断故障、污染、实际停水、水力影响或用户服务边界,缓冲距离也不是供水服务半径。 缺失几何时标记 partial,没有可用位置时不生成面。输入最多 8 组、合计 10000 个不同节点; 几何输出遵守覆盖层顶点和大小限制,超限要求缩小范围,不静默抽样或改变原分析结果。

MCP 保存完整查询响应作为不可变证据,展示解析器同时支持响应信封中的 data.result.map_payload。Agent 使用 set_overlay 引用本次 evidence_id 并省略 data。 超过内联返回预算时,响应的 data.presentation.command 仍保留可发布的展示命令, data.presentation.groups 保留覆盖完整性计数, 完整几何留在证据中,不能把缩略返回误认为没有空间成果。调查按实际步骤同步发布展示: 地址得到明确坐标后缩放定位,取得候选资产后定位候选,检查影响节点后生成并展示覆盖示意, 形成或调整关阀方案后定位阀门,读取监测对照后展示点位及序列。 图表同样随结果返回发布:监测趋势与事件对照用折线图,可比候选评价或方案用柱状图, 水力及污染传播等模拟按实际返回的时刻、对象和指标画图。压力、流量、浓度等不同单位分图, 注明来源、范围与实测或模型属性;没有同口径基准时不计算或绘制改善量,缺测不补零。 过程图表通过 open_chart 提供 chart_id/chart/evidence_refs,每图最多100个横轴值、8组序列, 超限时分图或明确说明抽样、聚合范围;单值或无可比数据用文字或表格。 同指标、单位和窗口的同期复合图按对象分别发布稳定 chart_id,标题为“对象ID 共同标题”,每条序列名以“对象ID ”开头。共同标题、chart_type、轴名、x_data、当前序列去掉对象前缀后的名称与 sample_times 完全一致时,浏览器将对象数据集聚合为一个子图表:右侧按钮切换对象,下方图例控制序列;窄屏对象列表移到下方。普通趋势总览、柱状图和结构化 Chart 保持独立,不新增 objects 字段。原 chart_id 的 close_chart 只移除对应对象,关闭聚合卡片移除组内对象。

浏览器的总图表窗口统一管理过程图组与报告 Chart,子图表仍可手动独立弹窗放大。只有正在跟随的运行中任务新收到 open_chart 时可自动弹出总窗口;后续命令更新内容,不自动打开子窗口,用户关闭后不重弹。任务打开、切换、刷新、已完成任务载入、SSE 重连历史补载及历史导航只恢复数据,不弹窗。窗口意图是浏览器临时状态,不写入事件或历史快照,不新增协议字段;open_chart 的内容加载与窗口是否弹出是两个不同状态,Server 的 recorded 也不表示浏览器已经打开窗口。

time_comparison 的 x_data 使用精度一致、按窗口排列的 UTC+8 HH:mm 或 HH:mm:ss 共享槽,允许跨午夜但短于一天,不追加历史日期。series 同时包含当前 line 与历史 scatter,不混入 bar;sample_times 与 data 等长,有效值和真实带时区时间成对保留,缺测值与时间均为 null。时间转换后须与横轴槽一致,当前线使用同一窗口,每条历史序列来自同一历史日的对应窗口,不接受当天或未来日期。新任务展示与报告发布不满足这些规则时返回 TIME_COMPARISON_INVALID,旧保存内容保持结构读取。普通 line/bar 跳过同期语义,但不能将 line/scatter 复合图标为 line。

前端维护的脚本 scripts/export-view-command-contract.mjs 同步 Agent/Server 的结构协议及 tests/fixtures 下的统一 JSONL 和 chart-publication-cases.json;JSON Schema 不代替跨字段语义校验。Server 的独立测试用相同正反例校验 Pydantic 边界和 validate_time_comparison_chart;Agent 主机、原生工具及 Dev 的新图表输入也执行对应规则。

关键趋势与比较结论保留到报告中,最终报告的图表不替代过程发布。

SCADA 设备展示覆盖

SCADA 异常初次调查的监测过程图使用可选的 chart.scada 结构: role=current|comparison、metric=pressure|flow、unit、带时区的 window_start/window_end, 窗口固定为本轮截止时刻之前三小时;采样槽保持真实采样相位,截止非整刻不平移。超过100槽按连续时间分图,使用不同稳定chart_id,元数据仍声明完整三小时窗口;Server逐点核实后合并覆盖,缺少任一槽仍拒绝收尾。同期历史只取完整窗口末三个采样槽,同设备同期分图不得重叠。低频设备窗口无计划采样槽时,完整读取对应当天/历史三小时并核实无读数后,以截止时刻的单个null保留设备入口,标记no_scheduled_samples,不计作漏采。value_field 默认为 monitored_value,可显式选 cleaned_value。 每条序列绑定 device_id 和 day_offset(当天 0,此前七天 1 至 7)。 同期图每个设备包含当天 line 和七组 scatter,历史仅末三个对应采样槽有值。 Server 校验设备属性、单位、完整采样槽、真实时间与引用快照的对应值,允许数值四舍五入保留 1 至 6 位小数, 保留负流量;缺测必须有完整查询或明确空值记录证明,未查询不能视为缺测。 chart.scada.gaps 由 Server 生成并存入展示事件,前端保留设备入口并展示缺测点数。 回放全量查询的 coverage.frozen_start 记录服务端已冻结的最早时刻;历史早于该边界时, 以本轮匹配 replay/batch 的完整回执证明 outside_frozen_window,无需虚构一次成功的历史读取。

地图的 SCADA 定位/标记、已验证图表和最终报告 scada_device_ids 累计本轮目标; 监测明细表使用该字段声明完整设备集合。按指标和单位分图,跨多张总览取设备并集, 同一 chart_id 更新只采用最新覆盖,累计目标不缩小。关闭图表及清空地图只影响浏览器, 不撤销产物覆盖。最终报告及成功结束均拒绝遗漏,返回 409 SCADA_PRESENTATION_INCOMPLETE, related_refs 列出待补设备;Agent 补图后可重试原请求。普通进度和 interim 报告可继续发布。 “仅作参考”不豁免展示;确有缺测时仍发布有空槽的图表并保留设备, 完整查询无法完成时保留 interim 和具体失败原因,不伪造缺测来通过 final。

覆盖事实保存在 workbench.operational_task_runs.artifact_manifest.scada_presentation, JSON 包含累计 targets、按 chart_id 保存的最新验证 charts 及 updated_at。 它与 Run 一起保留,独立于七天展示事件清理;不依赖浏览器在线或回执。 不同 Run、项目和截止窗口不能抵数。恢复复核阶段沿用恢复证据门禁,不要求重画异常轮次图表。 历史读取不要求新字段,已完成报告不回写;旧 Agent 的无绑定图表仍可读,但不能通过新轮次的覆盖门禁。

部署按工作台数据库变更门禁核实目标 BizDB、备份和回滚演练。 先停止目标项目的任务写入并安排配套切换,在维护窗口应用 035 迁移,随后发布 Server、Agent 和前端。 迁移只为 Run 新增通用 JSON 产物清单,默认空对象;不会自动回填旧图或自动迁移其他项目。 未应用迁移的 SCADA 写入与收尾返回明确的 503,历史读取保持可用。 Run 读取投影显式排除内部清单,REST 与 MCP 原有 Run 结构保持一致。 若回退到本次读取兼容修复之前的 Server,须先备份清单再移除新增列;旧代码的整行读取不能直接带着新列回退。 本次实现不代表迁移或上线已执行。 业务 Skill 说明本步骤应展示什么,调查指令统一说明发布方法、非空几何检查、去重和失败处理。 同一阶段批量展示,数据或方案没有变化时不重复请求;不为地图动作增加无关业务分析。 报告的 map_targets 仅为手动定位入口。关键步骤的数据缺失或展示失败需记录具体限制, 没有浏览器连接也不阻止分析或报告收尾。

GET /api/v1/operational-tasks/{task_id}/presentation-cursor 在同一事务中读取 task_id/execution_generation/active_run/event_cursor,其中活跃 run 仅返回 run_id/generation/status。 浏览器打开 Dev 联动、切换任务或断线重连时,以此建立新基线,只消费之后的展示事件。 跟随开关只影响当前浏览器的临时展示,正文和图示更新始终可读,调查仍由后台继续执行。 关闭 Dev 面板不改变跟随开关。关闭跟随开关、切换任务或断线时清理临时效果, 执行结束停止执行态动效,已显示的图表与覆盖层保留供阅读。不回放历史请求,不重新执行调查。

人工反馈续调

外围同步器根据动作回执找到关联子工单。样板创建固定为 revision=1,首次创建回执不作为 新的现场反馈入队。后续版本可唤醒已结束调查,旧报告和证据保留,生成新的执行代次。 现场备注从工单 activity.kind=feedback 的记录进入反馈证据,仍标明样板合成来源。 重复请求或同一源版本重放不增加执行代次,取消调查拒绝新反馈。

同步器先送达各父调查反馈,再推进预约工单投影的源版本。定向源事件和动作回执补查保留, 处理源更新早于回执保存的情况。全量对账只为源版本变化补查已结束调查,本次不回填历史反馈。 原投诉收到新版本后同步推进其已有来源修订号。数据不足仍正常结束本轮, 只有新的可信业务输入进入后续轮次,不依赖图示节点制造人工等待。

部署与验证

新增 023 迁移 仅适用于 tjwater_v2, 增加进展表和两个事件 topic 的 CHECK 取值。2026-10-10 已在目标库完成全库备份、 迁移事务回滚演练及正式应用,其他项目和旧任务未改动。

实际 worker 曾成功投递指定调查,模型发布进展和报告,但因 service 账号的任务权限过滤 导致 approved_data_scopes 为空,误作数据不足结束。这不是业务数据确实不足。 用户确认开放规则后,任务 API 已移除该额外过滤,沿用账号已有的项目读取权限。 在线上下文返回七类来源,同一身份实际读取 SCADA 设备和外围系统工单成功;没有新增 角色权限或放宽跨项目、审批和设备控制边界。旧委托路径保留兼容,已有权限无需委托凭据。 用户级 tjwater-operational-worker.service 已重新启用。旧报告保留,未自动重新调查, 不能把旧报告视为修复后的业务验收。任务创建时间下界和并发配置见 执行 worker,未回填旧任务。 进展读接口在表尚未部署时返回空,写入口须在迁移与 Server 更新后启用。 按现有数据库发布流程应用迁移,再更新 Server、Agent 和前端,运行中的 worker 需要加载更新。

聚焦检查:

conda run -n server python -m pytest tests/unit/test_operational_tasks.py tests/unit/test_operational_presentation.py tests/unit/test_peripheral_task_sync.py tests/unit/test_peripheral_push_sync.py tests/api/test_operational_task_dynamic_flow.py tests/api/test_openapi_contract.py -q
git diff --check

这些检查覆盖隔离 HTTP 与状态机,不代替共享数据库迁移、真实模型运行或现场复测验收。