feat(investigations): add event impact and work-order feedback flows

Add isolated burst and pollution impact evidence, parallel work-order workflows, persisted notifications and graph updates.

Checkpoint current code. Known follow-ups remain for large pollution result previews and graceful geometry failure.
This commit is contained in:
2026-11-14 15:14:02 +08:00
parent 471ad92a47
commit 2e4f6cb93b
49 changed files with 1826 additions and 93 deletions
+27 -8
View File
@@ -8,10 +8,12 @@
flowchart TD
order[爆管上报工单] --> context[读取原工单与当前任务]
context --> asset[核对地点并关联管网资产]
asset --> isolation[分析隔离边界与阀门方案]
isolation --> impact[说明事件与隔离方案影响]
impact --> report[保存阶段报告与处置建议]
report --> approval[人工审批与现场执行]
asset --> interim[保存定位阶段报告]
interim --> approval[立即发起工单草稿、人工审核派发]
interim --> burst[爆管模拟与同刻在线压力差]
burst --> coverage[保存并展示爆管后、处置前影响覆盖]
coverage --> isolation[分析隔离边界与阀门方案]
isolation --> report[补充阶段报告与处置建议]
approval --> feedback[接收实际处置与恢复反馈]
feedback --> verify[复核影响与结案条件]
verify --> close[Server 完成任务并解除告警]
@@ -20,10 +22,11 @@ flowchart TD
1. **接收核对**:保留来源工单ID、单调版本、发生时间、位置、描述、现场反馈和已有动作;后续轮次从新增事实接续。
2. **资产关联**:优先核对上报资产编号。坐标或地址通过地理编码、附近资产、属性和连接关系形成有依据的关联;位置歧义列为具体待确认项。
3. **隔离方案**:用 analyze_valve_isolation 分析关联资产,保留必关阀、可选阀、直接隔离与供水失源节点;已知失效阀门用于替代方案分析,现场可操作性列为执行条件。
4. **影响说明**:先展示拓扑范围,再按可用SCADA、水力结果和用户关联资料解释事件当前影响、方案预计影响和保障需求。
5. **报告与处置**:保存阶段报告后提出核验、通知、保障、抢修和恢复等动作草稿;关联现场任务采用 general 工单。审批、派发和现场完成分别核对回执。
6. **反馈复核**:已派发的关联工单保持 `waiting_work_order`,全部收到有效 `completed` 反馈后进入 `waiting_scada`。以现场反馈业务时间为 T,取严格晚于 T 的最近一个 SCADA 采样时刻进行复核;正常范围使用事件前15天同采样相位的正常包络。数据未到或仍异常时保持等待,后台工作进程定期复核;通过后持久保存恢复证据并接续 Agent。Agent 最终报告必须引用该证据,运行完成后才能完成任务并解除对应告警。现场资料缺项仅限定未核实细节,不新增本任务的关闭门槛。来源系统另有明确行政结案流程时,按其实际状态另记。
3. **并行工单与影响估计**:定位到管道后保存 interim/concluded 阶段报告,随即提出现场核查/抢修 general 工单草稿;复用同一 action_id,人工审核、确认派发保持现有权限和版本校验。待审核或现场处理期间继续独立的影响模拟,不等待模型完成才发起工单。
4. **隔离方案**:用 analyze_valve_isolation 分析关联资产,保留必关阀、可选阀、直接隔离与供水失源节点;已知失效阀门用于替代方案分析,现场可操作性列为执行条件。
5. **影响说明**:先保留爆管后、处置前的压力下降覆盖步骤,再展示隔离方案的拓扑范围;结合可用SCADA、水力与用户关联说明影响。
6. **报告与处置**:定位阶段已发起现场工单,后续复用原动作;更新报告后按新增需要提出通知、保障或恢复等动作草稿;关联现场任务采用 general 工单。审批、派发和现场完成分别核对回执。
7. **反馈复核**:已派发的关联工单保持 `waiting_work_order`,全部收到有效 `completed` 反馈后进入 `waiting_scada`。以现场反馈业务时间为 T,取严格晚于 T 的最近一个 SCADA 采样时刻进行复核;正常范围使用事件前15天同采样相位的正常包络。数据未到或仍异常时保持等待,后台工作进程定期复核;通过后持久保存恢复证据并接续 Agent。Agent 最终报告必须引用该证据,运行完成后才能完成任务并解除对应告警。现场资料缺项仅限定未核实细节,不新增本任务的关闭门槛。来源系统另有明确行政结案流程时,按其实际状态另记。
SCADA作为事件影响的辅助证据,按目标测点和事件/对照窗口读取。具备水力输入且工具已授权时,使用 analyze_valve_closure 评估给定阀门方案;各步骤记录实际结果、适用范围或具体待补项。
@@ -64,3 +67,19 @@ SCADA作为事件影响的辅助证据,按目标测点和事件/对照窗口
检查Skill名称、版本、摘要与正文digest一致、内联体积、角色权限、工单工具隔离和SCADA定位回归。Agent类型检查与会话工具策略测试共同覆盖运行时入口。发布后分别验收工单事件处理报告和SCADA候选定位,原有报告按既有修订保留。
关联契约:[分析 MCP](mcp-analysis-tools.md)、[调查展示](investigation-progress-and-presentation.md)、[报告契约](investigation-report-contract.md)、[任务与多轮反馈](operational-tasks.md)。
## 爆管压力下降覆盖与历史还原
`run_burst_simulation` 新增可选 `include_impact_coverage=true`,原默认行为保留。指定已定位管道、带时区的事件起算时刻及有来源或明确估计依据的破口面积(cm²)。计算保持隔离临时模型、不保存分析方案、不重算在线基线,不施加新的关阀或抢修操作。
在筛选最多20个展示节点之前,以原生模拟全网节点的起算首帧为计算对象,严格读取同一时刻已有在线模拟压力。不同压力单位换算为米水头,下降量为在线压力减爆管压力,互斥划分 `1≤Δ<3 m`、`3≤Δ<5 m`、`Δ≥5 m`。小于1米与缺少可比数据分别计数;错时、缺测、无效值或未知单位不补零、不取邻近值,不从代表测点外推全网。需要 `simulation.run`、`scada.view`,影响比较另需 `simulation.view`。
输出 `impact` 保留每个可比节点的在线压力、爆管压力、下降量、分组、缺测清单、比较时刻和读取来源;`coverage` 和 `map_payload` 使用实际GIS节点坐标生成三档空间包络。缺坐标、覆盖节点超过10000或几何超预算时明确报告,不截取前若干节点冒充完整范围。地图采用黄/橙/红,图例保留每档已绘制/分组节点数。
爆管模型使用 PDA 需水方式和原有10模型压力单位的服务压力设定;在线模型方式、当前模型时态及在线压力单位推定来源一并保留。在线记录没有独立版本化单位元数据,不能把此估计称为严格历史同模型反事实或现场停水边界。
携带 `replay_context` 的调查只开放启用影响覆盖的爆管情景,起算时刻不得超过 `knowledge_cutoff`。使用当前模型的独立假设情景,初始化及扩展模拟均传入空SCADA边界映射,禁止从实时SCADA回填冻结观测;同刻在线结果仅作为计算时读取的模型参考,标明非冻结基线。未来样本属于预测,不能作为已发生的观测。
完成持久计算后,Agent按回执 `data.presentation.command` 用证据编号发布覆盖,并保存三档计数、假设与缺口表。Server从任务所属的不可变证据解析几何,将完整展示命令写入事件。历史播放还原这份命令,前进到隔离范围和后退到事件影响均不重新查询在线模型,也不派单。工单审核、派发与反馈继续由通知和标准工单窗口记录;模型结果补入同一调查,不重复创建工单。
全网结果超过单次工具回执上限时,默认 `get_calculation_result` 返回标明缩略的计数与模型条件、保存证据资源链接及可发布地图命令。原始逐节点结果和几何保持完整,可通过证据资源或 `data_path=["result","impact","comparisons"]` 分页读取;不将全网计算缩为20个展示节点。
@@ -55,6 +55,23 @@ 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,保留已有路径和引用。
“保留路径”约束图的结构,不冻结已有节点的标记。`nodes` 按 `node_id` 合并:新增节点必须提供 `label`;
修改已保存节点时可只提交 `node_id` 与变化字段,无需再提供 `label`、全部节点或连线。
省略字段保留原值,`label: null` 也保留名称;`status: null` 显式恢复为参考步骤。
证据、动作和地图引用继续按集合累加,空列表不移除已有引用。资料或条件补齐后,应显式修订原 `needs_input` 节点,
新增下游节点不会自动改变上游标记,也不根据节点顺序推断执行结果。例如已有节点 `read` 可更新为:
```json
{
"summary": "补充资料已核对,更新原核查节点。",
"graph_update": {
"nodes": [{"node_id": "read", "status": "recorded", "detail": "已核对收到的现场记录。"}]
}
}
```
上述更新不增加节点或连线,也不改写已归档的报告图。旧图已保存于 `node_refs` 的节点支持相同的局部修订;
仅存在于旧 Mermaid 源码、尚无节点元数据的编号仍不能作为新增步骤重用。
尝试失败时标记 `failed`,重试或替代路线使用新节点及连线;原失败节点不能改写为成功。
仅更新正文或传入 `diagram: null` 均保留累计图,原始 Mermaid 不再由新 Agent 生成。
首次增量更新沿用最近保存的旧图,将原源码保存在 `source_mermaid`,保留原分支和形状后追加内容;
@@ -236,3 +253,12 @@ git diff --check
```
这些检查覆盖隔离 HTTP 与状态机,不代替共享数据库迁移、真实模型运行或现场复测验收。
## 工单通知与历史展示
工单审核通知保存提议时的 `work_order_action` 快照。外部工单的新来源修订在反馈事务中同时保存 `work_order_feedback` 通知与 `operational.notification.changed` 事件,`work_order_reference` 记录来源、修订、证据及状态;关联动作存在时一并保存反馈时的动作快照。重复请求或已处理来源修订不重复生成通知。字段保存在现有通知 JSON 文档中,无新增数据库迁移。
前端通过事件流刷新通知及关联任务详情,初始快照满页时补取后续通知,并补载首屏任务列表以外的未读通知任务。报告、通知和标准浮动工单窗口定位到同一任务/动作。已读状态与通知生命周期独立,关闭窗口不执行审核或派单。
历史演示保留已解决通知,并按通知发生时间还原审核、反馈窗口及历史提醒。历史节点只读,不能调用审批、派单或反馈写接口;打开当前工单须退出历史,使用当前动作及来源最新修订。旧通知缺少工单快照时只能标注当前资料,不宣称精确恢复当时的工单。
+2 -1
View File
@@ -5,11 +5,12 @@ Agent 原生工具统一使用 `mcp_tjwater_` 前缀。Server目录共67项:42
| 工具名(不含前缀) | 能力与边界 | 必要权限 |
| --- | --- | --- |
| `run_simulation` | 在线模拟:按水力步长直接计算业务库,不复制数据库;更新模型条件和实时基线,返回指定节点/管段,不创建方案或正式分析运行 | `simulation.run` + `scada.view` |
| `run_burst_simulation` | 假设管道破口正向模拟;可选全网同刻在线压力差与1/3/5米水头覆盖,详见[爆管流程](burst-response-workflow.md) | `simulation.run` + `scada.view`,影响比较另需 `simulation.view` |
| `run_burst_detection` | 指定时刻的15天压力异常侦测,至少5个完整监测节点;不定位 | `burst.run` + `scada.view` |
| `run_burst_location` | 异常/正常压力、可选流量及漏水量假设的候选管段排序 | `burst.run` + 对应数据的 `scada.view` 或 `simulation.view` |
| `analyze_valve_isolation` | 拓扑隔离边界、候选关阀及影响节点;不是水力计算或真实关阀 | `simulation.run` |
| `run_leakage_identification` | SCADA压力约束下的DMA漏损分配估计;需总漏损量依据 | `burst.run` + `scada.view` |
| `run_contaminant_simulation` | 已假设污染源的正向浓度传播;不是源头反演 | `simulation.run` + `scada.view` |
| `run_contaminant_simulation` | 假设源正向传播;可选按全网全时段浓度汇总累计范围、首个超阈值报告时刻与峰值,详见[污染流程](water-pollution-response-workflow.md);与工单并行,不承担反演或安全判定 | `simulation.run` + `scada.view` |
| `analyze_valve_closure` | 给定关阀组合的水力影响 | `simulation.run` + `scada.view` |
| `analyze_flushing` | 指定排放节点和流量的冲洗水力影响;不证明消毒合格 | `simulation.run` + `scada.view` |
| `analyze_pressure_regulation` | 给定调泵序列、水箱初始水位的压力影响;不自动优化调度 | `simulation.run` + `scada.view` |
+53
View File
@@ -0,0 +1,53 @@
# 水污染侦测事件调查
水质监测侦测到异常后创建 `workflow=water_pollution`、`event_kind=water_pollution` 的事件调查,分发 [water-pollution-event](../resources/work-order-skills/water-pollution-event/SKILL.md)。`water_quality_complaint` 保持供水水质投诉上报语义,使用原投诉流程。两者不共用触发条件;污染事件不依赖爆管评分、压力下降或工单上报。
```mermaid
flowchart TD
detection[有效水质观测命中业务规则] --> task[独立水污染事件调查]
task --> evidence[全量观测及七天同期核验]
evidence --> trace[快速候选溯源]
trace --> node[展示已核验节点]
node --> report[候选源阶段结论]
report --> action[立即提出现场核查采样工单供审批派发]
report --> simulation[污染传播模拟与累计浓度影响范围]
report --> isolation[节点隔离与阀门边界]
simulation --> impact[同一调查补充证据地图与报告]
isolation --> impact
action --> feedback[采样处置复测反馈]
feedback --> review[接续原调查复核]
impact --> review
review --> final[最终报告及事件收尾]
```
## 侦测入口
现有 `ScadaReplayService` 使用冻结的水质设备类型 `quality` / `water_quality` 判别水质规则事件。仪表无效值、缺测产生的 `data_quality` 告警单独处理。水质业务规则命中直接创建污染调查,即使同时运行压力/流量周期诊断,也不被合并成爆管调查。持续规则事件沿用同一任务,规则恢复后接续该任务的新一轮。压力/流量与水质同时异常时各自保留调查。
当前侦测来源沿用既有 SCADA 历史回放处理器;本次没有新增实时采集或常驻水质侦测调度器。其他可信侦测生产者可经现有 operational-tasks 创建接口提交同一 workflow,保留实际侦测信号与发生时间;普通任务无需 replay_context。
## 临时溯源契约
`run_contaminant_source_trace` 要求 `simulation.run`,只读当前项目模型,禁止只读调查子角色调用。输入包含从水质设备映射或资产查询取得的 `candidate_node_ids`(1–20 个不同节点)及带时区、最长24小时的 `start/end`。回放窗口不能越过知识截止。接口直接返回结果,当前不入计算队列。
临时实现从提交的候选中核验模型节点,按字符串排序返回首个存在的节点,不执行反演或拟合。返回 `located_node`、`top_candidates`、`validated_node_ids`、`missing_node_ids`、`selection_basis`、`algorithm_status=provisional`;证据 `origin=synthetic`,不编造相似度或置信度。所有节点不存在时明确返回 `no_candidate`。后续正式算法替换服务内部选择逻辑,保留节点结果契约及后续调查步骤。
候选节点只是当前可分析目标;定位后先保存 `interim/concluded`,立即提出关联 `general` 现场核查/采样处置工单,随后继续污染传播模拟和 `accident_element_type=node` 的隔离。审核和派发不依赖模拟完成;等待工单时继续独立分析,模拟结果补入同一 `task_id`,不重复创建工单或改写已审核动作,权限与版本校验保持原有流程。
## 污染传播模拟与影响覆盖
`run_contaminant_simulation` 增加 `include_impact_coverage`(默认 false)与 `impact_threshold_mg_l`(默认0,严格大于)。开启时,在筛选最多20个展示节点之前,使用原生结果的全网节点、整个模拟窗口的报告采样汇总累计超阈值节点数、各节点首个超阈值报告时刻和峰值。原生浓度 `MGL` / `UGL` 分别转换为 mg/L 后比较;缺失、无效浓度、错误时间网格或不支持的单位保留为缺口,不能转成零浓度或安全范围。几何超过10000节点上限时仍返回数值估计,并明确地图不可用。
阈值仅为模型展示条件,默认0表示模型正浓度,不是水质安全限值。沿用当前模型初始水质、已有源和反应条件;统计的是总模型浓度,不能称为本次源的独立贡献。源浓度、模式、业务起算时刻、预测时长及其假设必须有依据,不能把余氯下降或浊度换算成污染源浓度。
回放同样允许该工具,要求启用影响覆盖且起算不晚于知识截止;预测时段可以越过截止,但后续时刻只是模型预测。与爆管情景一样,使用当前模型和空 SCADA 映射传入临时模型计算,不读取可变实时监测,不重建历史模型。仍禁止借此放开未授权观测或其他水力工具。
工具沿用计算队列和 owner/run 校验,返回终态后通过 `get_calculation_result` 读取并持久保存证据。`presentation_preview` 提供基于 `evidence_id` 的地图请求;用正式调查展示事件保存模型曲线和覆盖,历史播放还原已保存证据。审批、派发可在计算排队或运行期间进行;存在未终态计算时继续保留原运行,不允许发布 final 或成功结束调查,已有工单不受模拟失败影响。
## 展示、反馈与收尾
水质图表使用 `chart.scada.metric=quality`,沿用真实单位、三小时当前趋势、前七天同期散点及证据校验;不同指标分图。同单位不同水质指标通过图表纵轴名称区分展示分组。Server、Agent、Frontend 的图表协议同步支持 quality,正式报告仍需引用本轮全量 SCADA 证据。
关联现场任务使用 general 工单。成功创建后保存在 `handling_context.work_orders`,进入 `waiting_work_order`;全部有效工单 completed 后进入 `field_review`,接续 Agent,而非执行爆管压力恢复计算。最终 concluded 报告必须引用全部有效工单最新的 `feedback_evidence_id`,然后由 Server 完成任务并解除关联告警。完工反馈或新版本复测资料会重新进入复核;证据不齐时 Agent 使用现有提问/新动作流程等待事实。该机制校验反馈引用与调查收尾,不自动判断实验室水质合格。
所有新增状态保存在既有 JSON 文档,无数据库迁移、环境配置或新服务。现有服务更新代码及流程包后才生效;单元测试和契约校验不等同真实模型 Agent 调查验收。