feat: extend operational investigation workflows
Generic Container CI/CD / test-build-publish (push) Successful in 3m53s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 3m52s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent 63af998045
commit 05183aff93
82 changed files with 4644 additions and 330 deletions
+248
View File
@@ -0,0 +1,248 @@
# 从爆管上报到处置闭环
本文定义爆管调查的完整业务路线,供维护者审阅和验收。运行时指令位于 [burst-report/SKILL.md](../resources/work-order-skills/burst-report/SKILL.md),由 Server 根据绑定任务的 `workflow=burst_report` 经 MCP 分发。
重点成果是有依据的事故候选位置、隔离阀门清单和影响范围,以及经审批执行、反馈核验后的闭环记录。Agent 根据证据选择、跳过或重做分支,不按图逐节点机械调用工具。工程图覆盖多轮调查和人工业务;每轮发布的进度图只标注实际进行的工作,不复制整图冒充执行记录。
## 完整工程图
```mermaid
flowchart TB
subgraph intake[工单进入与后台任务]
order[用户或外围系统提交爆管上报工单]
source[保存原工单及来源版本、发生时间、位置和描述]
sync[同步器按来源关联调查及工单投影]
queue[Server 保存调查任务和 queued run]
claim[Worker 投递,Agent 领取并维持租约]
context[读取任务摘要、业务 Skill、历史报告和既有动作]
order --> source --> sync --> queue --> claim --> context
end
subgraph investigation[Agent 调查与工程分析]
scope[确定事件时刻、地点、调查目标和真实或演练来源]
location[核对已有资产编号;必要时解析地点和查询附近管段]
monitor[核对相关测点映射、异常窗口、正常对照和数据质量]
cover{查询是否实际覆盖事件与对照窗口}
more[缩小对象和窗口,按需补页,核对缺测及零值]
hypothesis{是否具备定位所需观测和漏水量依据}
locate[计算爆管候选排序,保留假设、覆盖范围与证据]
candidate[整合上报、资产关联、算法与现场反馈得到候选集合]
usable{是否存在可用于隔离评估的候选资产}
isolation[逐候选分析拓扑隔离边界、必关阀及受影响节点]
isolateok{可隔离且阀门可用性有可核验依据}
alternate[纳入已知不可关闭阀门,重新评估替代隔离方案]
hydraulic[按需模拟候选关阀组合的压力和流量影响]
impact[区分拓扑停水区、水力影响区和有资料支持的用户范围]
findings[形成候选位置、阀门清单、影响对比和建议方案]
fieldbasis{是否已有足以支持具体现场核验的结论}
fielddraft[形成有位置、核验目标及回执要求的现场核验建议]
gap[真实关键数据缺失:发布 final insufficient_data 并结束本轮]
error[接口、权限或配置异常:记录具体失败并由宿主结束失败运行]
scope --> location --> candidate
scope --> monitor --> cover
cover -->|未覆盖且可补齐| more --> monitor
cover -->|已覆盖或确认实际缺失| hypothesis
hypothesis -->|具备依据| locate --> candidate
hypothesis -->|条件不具备,明确原因| candidate
candidate --> usable
usable -->|候选有效,标明待现场确认| isolation --> isolateok
isolateok -->|有可评估方案| hydraulic --> impact --> findings
isolateok -->|已知存在不可关阀| alternate --> isolation
isolateok -->|无法形成方案| fieldbasis
usable -->|尚无候选| fieldbasis
fieldbasis -->|可形成具体核验建议| fielddraft
fieldbasis -->|当前判断所需证据确实缺失| gap
monitor -->|不可恢复的查询异常| error
location -->|不可恢复的必要查询异常| error
end
subgraph approval[报告、审批与现场处置]
interim[保存本轮 interim concluded 阶段报告]
proposals[创建具体待审批草稿,关联证据和执行前置条件]
finalround[保存本轮 final 报告,由宿主结束本轮 run]
review[有权限人员审核当前草稿版本]
decision{审批结果}
revise[驳回理由保存并触发原调查新一轮]
submit[Server 通过配置的适配器幂等提交]
receipt{外部提交结果}
reconcile[使用同一执行请求号核对回执,不重复下发]
unsupported[未配置或明确失败:记录原因并重新分析]
workkind{本次获批的是核验还是处置}
fieldcheck[现场核验准确位置、漏水迹象及资产,回传实际记录]
notice[人工实施获批的通知、供水保障和应急安排]
isolatefield[现场核验阀门及实际隔离结果]
repair[现场定位、止水和抢修,回传实际故障管段及修复记录]
clean[按现场风险及获批方案清洗、消毒或冲洗]
restore[核验修复与适用复测,按批准方案恢复供水]
follow[记录恢复后压力流量、漏水复查及用户回访]
findings --> interim
fielddraft --> interim
interim --> proposals --> finalround --> review --> decision
decision -->|驳回| revise
decision -->|批准| submit --> receipt
receipt -->|结果不明或仍在执行| reconcile --> receipt
receipt -->|明确失败或不支持| unsupported
receipt -->|工单已创建或设备动作有回执| workkind
workkind -->|现场核验事项| fieldcheck
workkind -->|有依据的处置事项| notice
notice --> isolatefield --> repair --> clean --> restore --> follow
end
subgraph closure[现场反馈、复核与原事件闭环]
feedback[外围系统保存关联工单的新反馈和单调版本]
requeue[Server 校验来源并为原调查排队新 generation]
reread[重新读取现场事实、执行回执和最新监测证据]
verify[对照预测与现场结果,复核修复、恢复和风险]
faultstate{复核结果支持故障、误报还是尚待核验}
falsealarm[核对排除故障的证据及人工确认]
closed{处置及闭环证据是否齐全}
remaining[列出未完成事项及对应已有或待审批动作]
sourceclosed{原上报工单已结案且版本已核对}
readyreport[发布具备结案条件报告并结束本轮]
closedreport[发布闭环复核 final 报告并结束本轮]
closeowner[有权限人员在原工单系统核对并完成原事件结案]
closedcase[报告与来源事实一致,确认业务闭环]
follow --> feedback --> requeue
fieldcheck --> feedback
reread --> verify --> faultstate
faultstate -->|已确认故障| closed
faultstate -->|有依据排除故障| falsealarm --> sourceclosed
faultstate -->|尚需核验| remaining
closed -->|尚未齐全或复测异常| remaining --> interim
closed -->|证据齐全| sourceclosed
sourceclosed -->|是| closedreport --> closedcase
sourceclosed -->|否| readyreport --> closeowner --> feedback
reread -->|现场位置或阀门条件改变| candidate
end
subgraph presentation[贯穿调查的地图、图表与数据整理]
progress[发布真实调查进展和 Mermaid 状态]
map[高亮候选管段、闪烁建议关阀、展示已有证据覆盖层]
chart[打开异常与对照曲线,展示候选及影响对比表]
filepermit{会话是否已有文件写入权限}
jsonl[按权限整理有来源引用的 JSONL 调查数据]
reportui[通过报告 ui_blocks 发布 json-render 结构化界面]
sourceview[展示保持证据来源,失败不阻断业务调查]
progress --> map --> chart --> filepermit
filepermit -->|已获准且需要导出| jsonl --> reportui
filepermit -->|未获准或无需导出| reportui
reportui --> sourceview
end
context -->|首次或需要重新分析| scope
context -->|已有新反馈待复核| reread
revise --> requeue
unsupported --> requeue
requeue --> queue
gap -->|补充事实被 Server 接受后才重开| requeue
findings -->|无须新增动作| finalonly[无需新增动作时保存 final 报告并结束本轮]
scope -.-> progress
candidate -.-> map
impact -.-> chart
verify -.-> reportui
```
图中的现场处置由实际审批、工单与回执推进;顺序按现场紧迫性和获批方案调整。必要的紧急通知、现场核验和供水保障不应等待可选的完整模型计算。`clean` 为按风险适用的步骤,不能把每次爆管都判断为污染。`hydraulic` 在缺少模型、时序输入或权限时记录具体限制,仍可保留已完成的拓扑隔离结果。
`requeue` 表示 Server 接受了新业务事实后分配下一轮,不是 Agent 复活旧会话或自行循环等待。原工单结案由原系统有权限人员处理,后台 Agent 目前没有直接关闭原工单的工具。`completed`、`concluded`、动作 `succeeded` 和“业务闭环”分别核对,不能互相推导。
## 将业务步骤映射为现有能力
以下产品查询与计算均使用 `mcp_tjwater_` 前缀。参数以本轮实际发现的工具 schema 为准。
| 业务动作 | 已有入口 | 必须形成的结果 |
| --- | --- | --- |
| 接续原任务 | `get_task_context`,依次读取 summary、skill 及所需分节;`get_task_run_history` | 原工单来源、事件时刻、调查代次、流程版本、既有动作与现场反馈 |
| 查找地点和资产 | `geocode` / `search_project_places`、`query_nearby_elements`、`get_element_properties`、`get_node_connections` | 实际候选管段或节点、位置来源、匹配理由;邻近不代表故障确认 |
| 核对监测 | `list_scada_devices`、`get_scada_device`、`query_scada_readings`、`query_element_history` | 设备和模型节点的映射、异常及对照窗口、单位、缺测、分页覆盖 |
| 压力异常侦测 | `run_burst_detection` | 至少 5 个完整压力测点及此前 15 天数据满足时才调用;不把侦测当作定位 |
| 爆管候选定位 | `run_burst_location` | 候选排序、算法实际返回的评价值、观测范围、漏水量假设及来源 |
| 逐候选隔离 | `analyze_valve_isolation` | `accident_elements`、`isolatable`、`must_close_valves`、`optional_valves`、`affected_nodes`、`affected_node_count` 及已知 `disabled_valves` |
| 水力影响 | `analyze_valve_closure` | 指定关阀组合、时间窗、输出对象和模拟压力流量;参数不足时保留明确原因 |
| 用户影响 | 已授权资产属性、区域及外围资料查询 | 受影响对象、关联依据和覆盖限制;没有用户资料不估造户数 |
| 发布和提议 | `publish_task_progress`、`publish_task_report`、`propose_task_action` | 持久化报告、证据引用和待审批动作;动作不是执行事实 |
| 反馈接续 | Server `external-feedback` / `human-evidence` 及 worker | 同一任务的新轮次、真实来源版本、修复和复测证据 |
定位的 `burst_leakage` 必须有依据,单位为 m³/s;`pressure_scada_ids` 是模型节点 ID,不能填设备查询编号,也可省略并使用服务的项目配置。monitoring 模式正常窗可成对省略,使用前一天同窗,但这只是一项对照假设,仍要核对数据有效性。simulation 模式必须引用已有分析运行 UUID,不把在线重算当成已有分析运行。已知事故管段可直接做候选隔离;不必先完成一次没有必要的定位计算,也不能把已知答案作为算法独立定位成功的证明。
隔离工具支持明确标注的候选管段,无须等到现场确认才评估方案。多个候选的比较优先分开调用;把多个 ID 一次传入表示联合事故场景,不等同于逐个比较。`disabled_valves` 仅填已有事实支持的不可关阀;空数组不证明现场阀门均可用。`isolatable=false` 不能解释为零影响,即使 `affected_nodes` 为空也须解释返回的计数和限制。
## 像调查员一样查询、查看、比较和复核
每一步先明确待回答的问题,再查小范围资料,观察实际结果后决定下一步。例如:核实地址,查附近管段并查看属性,关联压力点,比较事件前后及正常对照,检查候选,评估关阀影响。只把必要的查询、事实和判断依据写入进度及报告,不保存模型内部推理。
- 不满足于“查过 SCADA”:必须确认返回的时间实际覆盖事件。查询 24 小时而只返回当天前 45 分钟时,应缩到事件前后的小窗,按需补页,不直接进入最终判断。
- 正常基线、实测、模型模拟、外围演练和人工反馈分别标注;缺测不是零值,异常不是爆管确认,候选评分不是校准后的概率。
- 查不到事故管段时先检查地址解析、附近资产与上下游关联;能查询的字段先查询,不能直接全部交给现场。
- 既有证据通过 `get_task_evidence` 的有界分页读取,不重复拉取同一批事实。失败、权限拒绝和存储未配置不当作“无异常”或“无数据”。
- 可以用最多两个前台 `investigation-reader` 并行核对无依赖的问题。读取、计算、发布和文件权限仍按角色执行;reader 只返回查询事实及真实证据编号。
## 地图与图表操作
后台调查统一调用 `publish_task_presentation`,每个不同命令使用不同 UUID `request_id`,相同命令重试复用原编号。以下为工具已有能力,不需要浏览器自动化。
| 调查进展 | command.action | 取值及依据 |
| --- | --- | --- |
| 找到实际候选资产 | `highlight_features` | `layer=pipes` / `junctions`,`feature_ids` 为已核实的地图要素编号,`effect=steady` |
| 正在核查候选或建议关阀 | `highlight_features` | 对应 pipes 或 valves,`effect=pulse`;闪烁只表示调查关注,不代表设备正在操作 |
| 查看异常与对照 | `open_chart` | 有限长度的时间和值,引用真实 `evidence_refs`;不同日期的对照对齐方式在标题或来源中说明 |
| 查看已有空间结果 | `set_overlay` | 提供 `overlay_id/title/mode/evidence_id`,Server 从证据提取几何,不接收手绘影响区 |
| 撤下旧的临时展示 | `close_chart` / `clear_overlay` / `clear_highlights` | 清理自己记录的临时展示;清理失败不修改业务结果 |
支持的图层为 junctions、pipes、valves、pumps、tanks、reservoirs、scada。先核实业务 ID 与地图 feature ID 的映射,不能把设备编号、节点编号与 GIS 编号混用。每次高亮最多 100 个要素,需要更多时说明所显示的子集;不要假定多次命令会累积成完整范围。没有几何时可以按已知 ID 高亮、用表格解释结果,不画包络多边形冒充影响范围。
图表最多 100 个横轴值和 8 组数值序列,单位须在系列名称或标题中明确。不能把 null 缺测填零以通过 schema;可以按有数据的区间分图,并保留缺测说明。`recorded` 仅表示请求保存。浏览器未开 Dev 跟随时仍继续调查,不能等待地图显示回执。后台接口目前没有摄像机缩放、平移、鼠标点击或任意图层开关命令;不要调用仅供聊天的 `locate_features`、`zoom_to_map` 或原生浏览器工具替代。
## JSONL 调查数据与 json-render 展示
JSONL 用于整理已经取得的数据与分析结果,不补造监测、阀门、现场反馈或审批。推荐每行一个对象,记录 `record_type/origin/source_evidence_refs`,并按对象保留时间窗、单位、模型或假设、覆盖限制和实际结果。`origin` 沿用来源分类;本地派生记录引用输入证据,并说明转换方法。不要把 JSONL 文件自身当作 Server 已保存的业务证据。
按内容选择 `event_context`、`monitoring_coverage`、`candidate`、`isolation`、`hydraulic_impact`、`field_feedback`、`closure_check`,无需为没有结果的类别制造空壳文件。候选记录写实际排序及评价值;隔离记录保留建议必关阀、可选阀、已知不可关阀及受影响节点;闭环记录逐项保留已核验、待核验或不适用及原因。JSONL 是导出约定,不新增 MCP 输入字段或服务端数据协议。
以下两行只演示文件格式,`synthetic`、`example_only` 与空证据引用表示它们不可用于实际报告或审批,不包含真实分析结果:
```jsonl
{"record_type":"candidate","origin":"synthetic","example_only":true,"source_evidence_refs":[],"element_id":"DEMO-PIPE-01","rank":null,"evaluation_value":null,"status":"not_computed","limitations":["仅说明字段,未执行定位"]}
{"record_type":"closure_check","origin":"synthetic","example_only":true,"source_evidence_refs":[],"item":"repair_verified","status":"not_verified","observed_at":null,"limitations":["无现场反馈,不能声称闭环"]}
```
如果当前会话已获准使用原生文件写入,则在当前 workspace 下写 `files/burst-investigation-<generation>.jsonl`,保留原始证据不变;通过允许的读取工具逐行复核 JSON、行数、对象 ID、时间和单位。只引用宿主绑定的 generation,不能从用户文本自选。不得读取兄弟会话、业务数据库、宿主源码或凭据;需要本地转换时只使用已获准的原生工具及沙箱 Shell,不引入 HTTP、SQL 或自由命令查询桥。
当前没有专用的免审批 JSONL 导出工具。文件权限未授予时,不通过 Shell 绕过、不让后台无限等待批准、不声称已生成文件;继续完成报告内的结构化数据,并如实说明文件未保存。恢复写入授权须由有权限的人或宿主处理,Skill 不扩大权限。
图表、表格和指标使用 `publish_task_report.report.ui_blocks`,每块为 `answer-ui@1`,包含独立 `block_id`、`fallback_text` 和 json-render 的 `spec.root/elements`,外层附真实 `evidence_refs`。最多 8 块、总计 400 KB,单块还受现有 schema 限制。优先组织以下内容:
| 展示 | 建议组件 | 数据来源 |
| --- | --- | --- |
| 候选管段及理由 | Table、Evidence、MapLocation | 地点、资产与定位证据;明确候选和已确认的区别 |
| 异常及正常对照 | Chart | 同单位的实际序列,说明时间对齐及缺测 |
| 关阀与隔离范围 | Table、Metric、MapLocation | 隔离证据、阀门属性及候选场景 |
| 水力与用户影响 | Table、Chart | 指定输出节点的模拟结果及真实用户关联资料 |
| 处置与闭环核对 | Table、Evidence | 动作回执、现场反馈、恢复监测和原工单版本 |
只用工具公布的组件属性。JSONL 可作为整理中间格式,但目前没有“把任意 JSONL 直接传给 json-render”的通道;需转换为已注册组件的 JSON 属性。后台不用 `present_answer`,不把原始 JSONL 输出到聊天正文,也不把表单提交当成已保存现场证据。小数据和简单结论可直接文字表达。
## 本轮成果与爆管闭环的验收
报告至少回答下列四类问题,逐项给出实际结果或经过查询证实的具体限制;无需固定排版或创建固定数量的动作。
1. **位置**:事故已确认还是仅有候选?每个候选的模型/地图编号、匹配或定位依据、排名及未确认事项是什么?
2. **隔离**:每个候选场景是否可隔离?应关、可选和已知不可关的阀门分别是什么?有无替代方案及现场前置核验?
3. **影响**:拓扑受影响节点、水力压降或失供范围、用户关联分别有哪些实际结果?未覆盖什么?没有水力或用户资料时分别说明,不能推定为零。
4. **处置与闭环**:当前可审批的工作是什么?已有哪些动作、审批、提交回执和现场事实?还缺什么反馈才具备结案条件?
有具体结论和动作建议时,先保存 `interim/concluded`,再 `propose_task_action`,最后保存 `final`。人工执行事项使用 `work_order_type=general`,保留原爆管事件。工单描述写位置、任务内容、依赖、执行前核验、需回传的事实和责任要求;`propose_task_action` 当前 payload 没有独立的 dependencies 或 feedback_requirements 字段,不发明字段。没有客户通知适配器时,将通知作为人工工单事项,不宣称已发送。
闭环复核至少核对实际故障资产及原因、隔离/阀门实施记录、抢修结果、适用的清洗及水质复测、恢复供水记录和恢复后监测、用户通知及回访、未决动作与遗留风险、原上报工单结案状态。不适用事项必须有事件依据;未收到结果写待核验,不把记录创建时间当现场完成时间。只齐备处置证据而原工单未结案时,结论为“具备结案条件,待原系统确认”,而非“已闭环”。误报或未发现故障的结案也要有支持排除的实际核查与人工确认。
必要查询失败、权限拒绝和存储未配置属于执行异常,按 schema 修正可纠正问题;仍无法取得当前判断必需的资料时交宿主记录失败。已通过有效查询确认关键数据确实缺失且无法补齐,才发布 `final/insufficient_data`,提供 blocking 缺口和查询依据,建议与待办为空,不在该退出分支再生成补数据工单。能够明确形成一项现场核验结论时可提议具体核验动作,但不能把“尚未开展定位”包装为“已完成定位调查”。
## 能力边界与验证
本次交付为工程图和运行时 Skill 文本,使用现有 MCP、发布、审批与反馈能力;不新增自动关单、鼠标自动化、摄像机操作、JSONL 导出接口或数据库字段。Server 目前没有按 Skill 检查定位/隔离成果的强制验收器,本文的业务验收要求仍由 Agent 执行并由人复核。
当前 Skill 仅通过 `section=skill` 整份分发,没有相对路径 reference 读取协议,因此运行时指令保持自包含,不能要求 Agent 读取本工程文档。内容需控制在既有内联预算内。Server 更新资源后,应按原发布方式让实际 Server 实例取得新文件;Agent 读取时核对 `name/version/content_sha256`,不把本地文件更新当成运行中实例已生效。
验证包含 Mermaid 语法解析、本地路径和工具 ID 核对、Skill 分发/权限/体积测试及 `git diff --check`。后续真实行为验收应分别覆盖:有效观测和漏水量依据下的定位;已知候选但缺漏水量时的候选隔离;不可关阀替代方案;SCADA 首屏未覆盖事件时继续读取;接口失败明确终止;文件权限缺失不绕过;无浏览器时照常调查;实际反馈触发新轮及最终闭环复核。没有真实模型计算或现场回执,不报告定位准确性或业务闭环已通过。
关联契约:[分析 MCP](mcp-analysis-tools.md)、[调查展示](investigation-progress-and-presentation.md)、[报告契约](investigation-report-contract.md)、[任务与多轮反馈](operational-tasks.md)、[后台工作进程](operational-task-workers.md)。
+12 -4
View File
@@ -1,6 +1,8 @@
# MCP 后台计算队列
API 保留 `uvicorn --workers 4`。长计算在项目 BizDB 持久化入队,由独立计算进程领取;所有 API 进程读取相同任务状态,不依赖粘性会话。HTTP 的 5 分钟空闲超时保留,Agent 的提交和状态查询采用 30 秒调用预算、35 秒宿主预算。`timeout_seconds` 对入队工具表示 Worker 的执行预算,不是 HTTP 等待时间,也不是模拟时间 `duration`。
API 保留 `uvicorn --workers 4`。长计算在项目 BizDB 持久化入队,由独立计算进程领取;所有 API 进程读取相同任务状态,不依赖粘性会话。HTTP 返回预算由宿主管理,Server 默认 120 秒、Agent 默认 180 秒。Server 通过工具目录 `_meta["io.tjwater/request-timeout"]` 统一发布 `defaultSeconds` 和 `maxSeconds`,所有工具(包括状态和结果读取)使用同一配置来源。Server 兼容保留 `timeout_seconds` 参数;Agent 对模型隐藏并拒绝该参数,按目录预算代填。Server 请求上限为 240 秒,Agent 加 60 秒返回余量并封顶 270 秒,原生 MCP 与本地连接的总时限为 300 秒;上游 HTTP 的 5 分钟空闲超时保留。提交、查询状态和读取结果都应及时返回,不等待整个计算。模拟时间仍由 `duration` 表示。
后台执行时限由管理员配置 `TJWATER_MCP_MAX_CALCULATION_TIMEOUT_SECONDS`(默认 3600 秒),入队时单独写入任务记录。HTTP 参数不参与作业幂等参数比较,也不会缩短或延长后台执行。任务表的内部 `timeout_seconds` 列仍保存执行时限。HTTP 超时或断开只结束本次等待,后台作业需通过独立取消工具取消。
```text
前端 / Agent → API × 4 → 项目 BizDB calculation_jobs
@@ -29,7 +31,7 @@ API 保留 `uvicorn --workers 4`。长计算在项目 BizDB 持久化入队,
| `list_calculation_jobs` | 可选 `status/limit/offset` | 当前授权会话及调查轮次的任务列表 |
| `cancel_calculation_job` | `job_id` | 排队任务可直接取消;运行任务先进入 `cancel_requested` |
状态为 `queued/running/cancel_requested/succeeded/failed/cancelled/timed_out/interrupted`。任务取消不等于在线模型写入回滚;发生失败、超时或中断时,需要核查已有写入,不能自动重算整个窗口。
状态为 `queued/running/cancel_requested/succeeded/failed/cancelled/timed_out/interrupted`。返回创建、开始、结束和排队/结果到期时间;`result_available` 表示结果是否仍可读取。任务取消不等于在线模型写入回滚;发生失败、超时或中断时,需要核查已有写入,不能自动重算整个窗口。
当前使用普通 MCP 业务工具承载队列契约,没有宣称已实现协议级 Tasks 扩展。Server 和 Agent 目录必须配套更新,旧 Agent 不应接收新的队列返回契约。
@@ -41,7 +43,13 @@ API 保留 `uvicorn --workers 4`。长计算在项目 BizDB 持久化入队,
调查的排队回执不写成分析证据。成功结果读取时,按原计算来源、任务及运行验证,并幂等地保存证据。未完成的计算阻止提交最终报告、`insufficient_data` 或将运行标记成功;中间进度仍可保存。
Agent 调查执行在原生回合空闲后由宿主短轮询等待,继续维持调查心跳,计算进入终态后再触发模型读取结果。普通聊天展示任务编号,可在当前会话后续查询。异常流结束时若无法安全继续处理新结果,会明确失败而不是虚报完成;Server 中的计算结果仍保留。
Agent 调查执行在原生回合空闲后由宿主短轮询等待,继续维持调查心跳。新作业进入终态即触发模型读取结果,其余作业继续后台运行。状态读取遇到网络、限流或临时服务错误,最多重试 3 次,采用指数退避和随机抖动;权限拒绝、上下文失效立即停止,重试耗尽明确报错,不重新提交或取消计算。普通聊天展示任务编号,可在当前会话后续查询。异常流结束时若无法安全继续处理新结果,会明确失败而不是虚报完成;Server 中的计算结果仍保留。
## 排队期限与结果保留
每项目最多 100 个未结束作业(queued/running/cancel_requested),跨 API 进程用数据库事务锁串行执行幂等检查与容量准入;同一请求的重试优先返回已有作业。排队最长 3600 秒,超过后标为 `timed_out`,错误码为 `QUEUE_TIMEOUT`;开始执行后使用独立的执行期限。提交、查询和 Worker 领取都会核查到期任务,所以 Worker 停止时,查询也能结束过期排队。部署监控仍须覆盖 Worker 进程状态和最老排队任务年龄,队列到期机制不代替服务可用性监控。
结果正文在终态后保留 7 天,到期由队列维护清除,读取返回 `RESULT_EXPIRED`。任务状态、输入、幂等标识和已归档调查证据不随之删除,也不会因结果过期重新计算。状态列表只读取状态字段,不加载完整计算结果。
## 并发、取消和恢复
@@ -53,7 +61,7 @@ Agent 调查执行在原生回合空闲后由宿主短轮询等待,继续维
## 部署
1. 先对每个目标项目的 BizDB 应用 `resources/sql/026_calculation_jobs.sql`,包括未来项目使用的相应业务模板。不要应用到 TimescaleDB。迁移为新增表及索引,不删除业务数据。
1. 先对每个目标项目的 BizDB 依次应用 `resources/sql/026_calculation_jobs.sql` 和 `resources/sql/027_calculation_job_lifecycle.sql`,包括未来项目使用的相应业务模板。已有 026 的库只需追加 027。不要应用到 TimescaleDB。027 增加时间字段与索引,不清除结果;已有结果从首次迁移起获得完整 7 天保留期。必须先迁移,再加载新 API/Worker 代码。
2. 配置 `CALCULATION_WORKER_PROJECT_IDS` 为明确的项目 UUID 列表,配置现有元数据库连接及数据库路由解密密钥。Worker 不需要新 OAuth 密钥;仅部署侧工作进程读取这些设置。
3. 同步发布 Server 和 Agent,在接入长计算前启动独立 Worker。不要从 API `lifespan` 启动,不要把调查 Worker 当作计算 Worker。
@@ -55,17 +55,24 @@ Server 校验当前 run、绑定会话、有效租约和幂等身份,记录 `o
| command.action | 参数 |
| --- | --- |
| highlight_features | layer、feature_ids、effect:steady 或 pulse |
| 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 |
| 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。仓库示例见[前端统一展示夹具](../../next-tjwater-frontend/tests/fixtures/unified-presentation.jsonl),其中编号来自测试夹具。
图表限定折线和柱形,包含 `title/chart_type/x_data/series`。最多 100 个横轴值和 8 组有限数值序列,
序列长度与横轴对齐,引用证据必须属于当前任务。地图高亮来源沿用上述七类。
覆盖层输入不接受模型提供的 `data`。Server 从证据的不可变数据快照提取现有 GeoJSON,
覆盖层的权威数据来自不可变证据。省略 `data` 时,Server 从证据快照提取现有 GeoJSON,
或使用已记录的 `longitude/latitude` 点位,将 `FeatureCollection` 加入事件中的 `command.data`。
若传入 `data`,必须与同一证据快照解析出的内容一致;Server 始终发布快照解析结果,不能用调用参数覆盖证据。
热力图只接受记录中的点,权重为有限非负数,未记录权重时取 1。
没有坐标的地址、空数据、非法几何、模型自绘区域均不能生成覆盖层。该接口不做地址解析、
范围推算或污染传播计算。展示事件总大小上限为 512 KiB,超限返回 422。
@@ -98,7 +105,7 @@ Server 校验当前 run、绑定会话、有效租约和幂等身份,记录 `o
实际 worker 曾成功投递指定调查,模型发布进展和报告,但因 service 账号的任务权限过滤
导致 `approved_data_scopes` 为空,误作数据不足结束。这不是业务数据确实不足。
用户确认开放规则后,任务 API 已移除该额外过滤,沿用账号已有的项目读取权限。
在线上下文返回七类来源,同一身份实际读取 SCADA 设备和外围合成工单成功;没有新增
在线上下文返回七类来源,同一身份实际读取 SCADA 设备和外围系统工单成功;没有新增
角色权限或放宽跨项目、审批和设备控制边界。旧委托路径保留兼容,已有权限无需委托凭据。
用户级 `tjwater-operational-worker.service` 已重新启用。旧报告保留,未自动重新调查,
不能把旧报告视为修复后的业务验收。任务创建时间下界和并发配置见
+2 -1
View File
@@ -43,7 +43,8 @@
完整图语法的解析失败只影响图示,正文、依据和审核仍可阅读。
每条 node_ref 包含 `node_id`、`label`、`evidence_refs`、`action_refs`;后两项默认空数组。
node_id 为最多 80 字符的 ASCII 标识符,必须以字母或下划线开头,在本图引用内唯一;
node_id 为最多 80 字符的 ASCII 标识符,必须以字母或下划线开头,在本图引用内唯一,
并与 Mermaid 源码中实际节点使用完全相同的 ID;禁止为同一节点另造引用 ID;
最多 100 条引用。证据必须来自报告 evidence_refs,动作必须属于当前任务。
节点可以说明候选方向与条件关系;图中的分支、状态文字不能证明实际并发、动作执行或现场完成。
图的颜色、字体和交互由前端统一配置。正文不包含 SVG 或 HTML。
+22 -2
View File
@@ -52,17 +52,37 @@ Agent 原生工具统一使用 `mcp_tjwater_` 前缀。Server目录共67项:42
- 数据源和计算假设必须有依据。定位漏水量和DMA总漏损约束使用m³/s;冲洗使用服务实际接收的m³/h,不沿用旧REST误标的L/s。工频泵序列0/1,变频泵序列为Hz;每项对应模型水力步长。冲洗当前限LPS/CMH模型。选址当前推荐压力点,不冒充污染溯源优化。
- 调查结果经现有快照/证据/回执链保存,只有返回evidence_id后才引用为系统证据;普通聊天不自动保存调查证据。模拟结果始终是analysis而非实测。已知模拟事件源管段是输入背景,不是算法定位准确性的证明。
## 关阀隔离输入与影响范围
REST `/api/v1/valve-isolation-analyses` 与 MCP `analyze_valve_isolation` 共用同一服务。
`accident_element_type` 默认为 `auto`:先识别管段 ID,再识别节点 ID;指定 `link` 时只匹配管段,指定 `node` 时只匹配节点。
节点表和管段表分别保证 ID 唯一,但不同类型可以重号;分析同名节点必须显式指定 `node`。
多个 ID 表示联合事故,不表示分别比较;类型参数作用于本次调用中的所有 ID。
服务从模型主表的一致快照读取连接关系、初始开关状态和水源,不依赖 GIS 几何或物化视图刷新。
不可关阀按保持现状处理;已关闭的管段、泵和阀门不参与连通,已关闭阀门不再列为建议关阀。
未知的事故 ID、未知的不可关阀 ID 和空事故列表会被拒绝。
- `affected_nodes` / `affected_node_count` 仍表示最近可关阀门围成的直接隔离区。不可隔离时列表为空,计数保留。
- `supply_affected_nodes` / `supply_affected_node_count` 表示按建议关阀后新增失去水源连接的节点,包含间接受影响区域,排除原本就不连通水源的节点。不可隔离或缺少水源资料时为 `null`。
- `source_check_performed` 表示是否已执行水源连通检查。`isolatable=true` 要求存在关阀边界,且关闭这些阀门后直接隔离区不再连通任何水源。
- `isolation_failure_reason` 可为 `connected_to_water_source`、`water_sources_unavailable`、`no_boundary_valves`;可隔离时为 `null`。
以上是模型初始开关状态下的无向拓扑分析,水库和水池均按潜在水源处理;不模拟泵或止回阀的单向性、时变控制、水池蓄水量、压力与流量。
因此“失去水源连接”不能直接当作经过水力计算或现场核实的停水范围。已保存的旧调查证据不会自动重算,需重新调用隔离分析生成新结果。
本次无需数据库迁移。
## 资源边界与发布
长计算采用[后台计算队列](calculation-queue.md)。10项分析计算与2项重计算写入的正式执行阶段快速返回任务编号,再使用 `get_calculation_job`、`get_calculation_result`、`list_calculation_jobs`、`cancel_calculation_job` 管理。原有预览与审批仍有效;排队回执不作为分析证据。
`timeout_seconds` 对队列工具表示计算 Worker 的执行预算,与模拟时间 `duration` 和单次 HTTP 请求时限独立。各工具默认值与管理员上限继续由目录公布。Agent的提交/查询采用30秒调用预算和35秒宿主预算,不延长Bun的5分钟HTTP空闲超时。
HTTP 预算由宿主从目录元数据读取,Server 默认 120 秒、Agent 默认 180 秒;爆管定位不再设置单独的长超时。`timeout_seconds` 保留在 Server 兼容入口,Agent 对模型隐藏并拒绝覆盖。Server 上限 240 秒,Agent 加 60 秒余量并封顶 270 秒,外层原生 MCP 保留 300 秒总时限与上游 Bun 的 5 分钟空闲超时。后台执行时限由管理员配置 `TJWATER_MCP_MAX_CALCULATION_TIMEOUT_SECONDS`(默认 3600 秒),不受该 HTTP 参数控制;模拟时间仍由 `duration` 表示。
`analyze_valve_isolation` 和 `calculate_demand_allocation` 保持同步。队列消费者独立于Uvicorn的4个API进程,默认全部配置项目合计并发2项,并通过元数据库单实例锁防止重复启动。取消、超时和租约失效需要停止计算子进程组;成功结果按原运行授权保存证据,未完成计算阻止调查提前结案。
在线重算逐个时刻写入基线,超时或中途失败可能已有部分时刻更新,不能把工具失败解释为整个窗口已回滚;不要自动重试整个窗口。
队列接入需要在目标项目BizDB应用 `resources/sql/026_calculation_jobs.sql` 并启动独立计算Worker。Server与Agent需配套发布,client模式还需重载原生连接。既有OAuth与项目权限保持不变;完整部署与回滚步骤见后台计算队列文档。
队列接入需要在目标项目BizDB依次应用 `resources/sql/026_calculation_jobs.sql`、`resources/sql/027_calculation_job_lifecycle.sql` 并启动独立计算Worker。Server与Agent需配套发布,client模式还需重载原生连接。既有OAuth与项目权限保持不变;完整部署与回滚步骤见后台计算队列文档。
本次验证限schema、权限、协议目录和mock业务函数,不运行真实模拟、优化或付费模型。真实项目的模板同步状态、运算耗时、SCADA覆盖和结果准确性仍需另行验收。
+3 -3
View File
@@ -4,7 +4,7 @@
`run_simulation` 是在线重算,复用 REST 在线计算服务而不复制数据库;按水力步长更新模型条件和实时基线,不创建正式方案。MCP 时长为秒,原 REST 时长仍为分钟。其 annotation 为 `readOnlyHint=false`、`destructiveHint=true`;只读 reader 不能调用,其他方案模拟继续使用隔离临时模型。详细边界见 [MCP 分析工具说明](mcp-analysis-tools.md)。
长计算使用持久化队列,原工具快速返回任务编号,新增状态、结果、列表和取消工具。`timeout_seconds` 对队列工具表示执行预算;HTTP保持短调用,不延长5分钟空闲超时。独立计算Worker、迁移与权限边界见[后台计算队列](calculation-queue.md)。
长计算使用持久化队列,原工具快速返回任务编号,新增状态、结果、列表和取消工具。HTTP 返回预算由目录元数据和宿主管理,Server 默认120秒、Agent默认180秒;模型不再提供 `timeout_seconds`,Server保留兼容入口。后台执行时限由管理员独立配置。提交和读取保持短调用,不延长上游5分钟空闲超时。独立计算Worker、迁移与权限边界见[后台计算队列](calculation-queue.md)。
## 认证与数据边界
@@ -14,13 +14,13 @@ Agent 根据401 challenge 或路径/根 well-known 发现受保护资源元数
调查数据返回前,在短事务内追加现有任务证据并保存调用回执。同一主体、会话、任务、run 和原生 call ID 的重试复用证据;不同参数或失效范围明确报错。七类原有访问申请 scope 保持原契约,MCP 的新增来源只扩充快照来源枚举。没有新增报告发布、审批、控制、Shell 或递归委派权限。
普通查询默认20条;目录类最多500条,时序最多10000条、20个标识、24小时;offset 最大10000。Agent 首次优先单对象、必要的短时间窗和小页,仅在证据不足时按需扩大,不自动遍历全网。SQL 有 limit/offset 和 statement_timeout。历史对比在同一条SQL中按序列、时间对数据点分页,返回 page.has_more;非零offset也标明覆盖不完整。历史曲线展示调用初始每页500点,`RESULT_TOO_LARGE` 时原位减半重试,最多读取1000条、发出16次请求,共用120秒超时(单次普通查询仍为30秒),图表最多100个有效点;这不改变模型首次查询默认值或时序接口上限。
普通查询默认20条;目录类最多500条,时序最多10000条、20个标识、24小时;offset 最大10000。Agent 首次优先单对象、必要的短时间窗和小页,仅在证据不足时按需扩大,不自动遍历全网。SQL 有 limit/offset 和 statement_timeout。历史对比在同一条SQL中按序列、时间对数据点分页,返回 page.has_more;非零offset也标明覆盖不完整。历史曲线展示调用初始每页500点,`RESULT_TOO_LARGE` 时原位减半重试,最多读取1000条、发出16次请求,共用120秒超时(单次请求同时受该剩余总预算约束),图表最多100个有效点;这不改变模型首次查询默认值或时序接口上限。
单份结果超过8MiB报错;超过12KB的调查工具消息只返回证据资源引用,完整快照仍保存,Server 的 `resources/read` 可以读取它。Agent 本地 MCP 只提供工具,将上游资源引用转为 `evidence_read` 中的 `mcp_tjwater_get_task_evidence` 参数,不向 OpenCode 泄露不可在本地读取的链接。`get_task_evidence` 在数据库中按 data_path、limit、offset 选页,嵌套集合和超过256字符的字符串返回路径描述;字符串按 Unicode 字符分页。页和完整资源均在数据库返回前检查8MiB上限,保留原证据编号和合成来源;普通查询要求缩小范围。其他结果仍保留执行后的整体8MiB检查,不能把它理解为所有查询均有数据库端字节限制。原始/清洗实测、模型基线、分析结果、比较和 synthetic 均明确标记。非有限数值转为 null 并记录数据缺口。
`get_task_context` 默认 section=summary,只查固定元数据、160字符任务标题及200字符结论预览,并返回 available_sections;preview_only 和 truncated 明确说明不是完整报告。按 section=task/report/evidence/actions/progress/access_requests/plan/run 读取详情,report_revision 保留选择旧报告的语义。data_path 选择嵌套值,limit 默认20、最多500,offset 最大10000;证据、动作和授权申请集合以稳定 ID 为键,按 ID 字典序分页。字符串按字符分页。详情在数据库返回前检查8KB预算,超限缩页或选更深路径。缺少可选进度或授权申请表时返回 metadata.available=false,不冒充空事实。绑定权限范围只读取七类既有 scope,不再加载整个任务上下文。不增加工具数量、数据库表或迁移,也不改变原 REST 完整上下文契约。
外围 MCP 直接读取所选项目 BizDB 的样板事实和既有时序。它不执行外围样板 HTTP 的故障场景注入;混有合成记录的结果按 synthetic 保守标记。DEMO-* 观测在数据库端拒绝超过8MiB的完整样本,预算内仍需读全样本、核验摘要后筛选并保留 synthetic;此限制不能通过缩小查询窗口解决。监测点列表沿用设备目录,不把未登记的合成点冒充实测设备。
外围 MCP 直接读取所选项目 BizDB 的工单事实和既有时序。外围工单统一返回 `system_data`;测试数据和 DEMO-* 观测仍按各自数据来源处理。DEMO-* 观测在数据库端拒绝超过8MiB的完整样本,预算内仍需读全样本、核验摘要后筛选;此限制不能通过缩小查询窗口解决。监测点列表沿用设备目录,不把未登记的测试点冒充实测设备。
## 启用步骤
+8 -5
View File
@@ -109,8 +109,9 @@ Server 校验该会话属于当前活动运行。跨用户投递查询与任务
原对话用户可以确认收到的回复,但不能改写目标会话或原生消息 ID。
既有 worker 每轮最多对账四页、每页 50 条私有待投递消息,即使调查并发已满仍继续对账,
不增加进程或配置项。临时网络错误保留消息等待重试;权限拒绝、不存在等确定性
拒绝保存失败结果。消息正文、发送人和会话归属不写入项目事件日志。
不增加进程或配置项。临时网络错误保留消息等待重试;400、403、410、422 等确定性
拒绝保存失败结果。404 可能表示目标会话属于另一个 Agent 实例,因此保持待投递,
不把路由未命中误记为消息终态失败。消息正文、发送人和会话归属不写入项目事件日志。
待投递接口按创建时间与消息 ID 返回 keyset 游标,worker 跨轮保留扫描位置;
扫到末页后下一轮从头重试。长期空闲对话的待收消息不会一直占住首屏、阻止后续调查投递。
@@ -122,6 +123,8 @@ Server 校验该会话属于当前活动运行。跨用户投递查询与任务
`resources/sql/015_workbench_events_and_task_runs.sql` 在项目 BizDB 中增加 `domain_event_log` 和 `operational_task_runs`。后续迁移默认只应用到 `tjwater_v2`,扩展规则见 [`workbench-database-rollout.md`](workbench-database-rollout.md)。事件与业务投影在同一事务提交,`LISTEN/NOTIFY` 只负责唤醒;浏览器与 worker 始终按持久游标补读。每个 API 进程对活跃项目最多保留一条 LISTEN 连接,无订阅者 60 秒后关闭。
`resources/sql/030_operational_run_agent_ownership.sql` 为运行增加 `agent_instance_id`。Worker 从目标 Agent 的 `/health` 读取实例标识,只恢复、续期该实例拥有的本地会话,并在投递时要求 Agent 回显同一标识。Server 在领取、心跳和完成时保存或校验归属,避免多个独立 Agent 共用项目队列时,一个实例反复刷新另一个实例并不存在的 session。部署顺序是:先迁移各目标 BizDB,再发布 Server、Agent 与 Worker;每个 Agent 的 `AGENT_INSTANCE_ID` 必须唯一且跨重启稳定。旧运行的归属保持为空,不会由任意 Worker 猜测接管。
事件默认保留 7 天。清理脚本会从 Metadata DB 解析项目路由,并在发现多个项目共享同一 BizDB 时拒绝运行。先确认 `OPERATIONAL_WORKER_PROJECT_ID` 对应 `tjwater_v2`,然后运行定向 dry-run:
```bash
@@ -147,11 +150,11 @@ conda run -n server python scripts/sync_peripheral_work_orders.py --once
conda run -n server python scripts/sync_peripheral_work_orders.py
```
使用相同工作身份,并配置 `OPERATIONAL_ACTION_PERIPHERAL_URL`。同步器订阅源工单变更事件,收到消息即读取分页工单,将外围版本投影到 `external_work_order` 任务;默认每 300 秒兜底对账。合成来源在摘要和证据中明确标注;工单完成只表示该外部任务完成,不代表其他调查自动完成。事件协议、`tjwater_v2` 范围与启用步骤见 [外围工单主动同步](peripheral-work-order-events.md)。
使用相同工作身份,并配置 `OPERATIONAL_ACTION_PERIPHERAL_URL`。同步器订阅源工单变更事件,收到消息即读取分页工单,将外围版本按系统数据投影到 `external_work_order` 任务;默认每 300 秒兜底对账。工单完成只表示该外部任务完成,不代表其他调查自动完成。事件协议、`tjwater_v2` 范围与启用步骤见 [外围工单主动同步](peripheral-work-order-events.md)。
工况任务面板的刷新按钮只重新读取当前项目的工作台快照,不直接触发外围系统全量对账。外围工单由独立同步器使用服务身份响应后端事件,避免多标签页或普通用户刷新放大全量扫描,也避免浏览器项目与同步器固定项目不一致。
通用合成检查工单不属于预约任务。早期种子脚本创建的通信、压力和零流量检查工单已经退役,种子脚本不再恢复它们;同步器按不可编辑的专用 seed actor 跳过旧种子工单。投诉、爆管事件以及调查动作实际创建的现场工单继续同步。`018_remove_synthetic_check_task_projections.sql` 只清理专用 seed actor 创建的旧检查投影,不按用户可编辑的标题或状态删除任务。三张独立演示工单已迁入外围样板,由同一同步器维护。
早期种子脚本创建的通信、压力和零流量检查工单已经退役,种子脚本不再恢复它们;`018_remove_synthetic_check_task_projections.sql` 清理了当时错误生成的预约投影。当前同步器投影所有有效外围工单,`029_peripheral_work_orders_system_data.sql` 将既有工单及任务快照统一为系统数据。投诉、爆管事件以及调查动作实际创建的现场工单继续同步。
水质投诉和爆管上报类型的外围工单同时创建关联调查,即使当时没有浏览器打开也会入队。两类事件从外围样板测试面板模拟上报;工况页负责展示调查。调查中创建的外围工单通过回执编号关联,后续反馈送回原调查,由 Agent 重新分析。
@@ -165,7 +168,7 @@ conda run -n server python scripts/sync_peripheral_work_orders.py
## 人工确认后的动作
- `OPERATIONAL_ACTION_PERIPHERAL_URL`:使用既有 `/api/sample/v1/work-orders` 创建合成外围工单。成功回执说明工单已创建,不表示现场工作已经完成。
- `OPERATIONAL_ACTION_PERIPHERAL_URL`:使用既有 `/api/sample/v1/work-orders` 创建外围工单。成功回执说明工单已创建,不表示现场工作已经完成。
- `OPERATIONAL_ACTION_COMMAND_GATEWAY_URL`:可选设备命令网关。未配置时明确返回不支持执行,不能生成成功回执。
- `OPERATIONAL_ACTION_TIMEOUT_SECONDS`:外部请求超时,默认 10 秒。
+10 -6
View File
@@ -1,8 +1,12 @@
# 外围样板服务
# 外围系统接入服务
该 FastAPI 子应用提供历史监测回放、固定合成数据,以及 synthetic 测试工单和测试数据的版本化 CRUD。生产环境挂载在主 Server 的 `/peripheral`,随 `next-backend` 单容器发布;源码仍可独立启动用于本地隔离调试。管理入口位于供水工作台“外围样板”。它不控制设备,也不修改正式业务资产。
该 FastAPI 子应用接入真实业务工单,提供版本化 CRUD、处理反馈和事件调查入口,同时保留独立的历史监测回放与演练数据接口。生产环境挂载在主 Server 的 `/peripheral`,随 `next-backend` 单容器发布;源码仍可独立启动用于本地隔离调试。管理入口位于供水工作台“外围系统”。
浏览器通过 `TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL` 连接样板服务。服务复用主系统的 Bearer 身份和 `X-Project-Id`,读取需要 `simulation.view`,写入需要 `simulation.run`。
外围工单的 `origin` 固定为 `system_data`,前端录入、同步器、任务快照、执行回执和工单查询均使用该来源,不再提供演练来源分支。业务录入代表系统中的上报,不代表投诉内容或故障原因已核实,Agent 仍需查询实际证据。
此次变更不修改表结构;部署时需在每个项目业务库执行 `resources/sql/029_peripheral_work_orders_system_data.sql`,统一修正源工单、修订记录、任务快照和外围反馈证据。API 路径、配置键中的 `sample` 为兼容名称,不代表工单是模拟数据。更新需发布 Server、同步器、Agent 与前端对应版本。
浏览器通过 `TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL` 连接外围服务。服务复用主系统的 Bearer 身份和 `X-Project-Id`,读取需要 `simulation.view`,写入需要 `simulation.run`。权限键沿用现有契约,不用于判断数据来源。
生产环境不需要为外围服务新增域名。前端设置
`TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL=/peripheral`,在现有前端 NPMplus Proxy Host 中增加以下
@@ -37,8 +41,8 @@ Forward Hostname 后追加 `/api/sample/v1`。本机开发和预览模式也将
演示数据通过 `scripts/seed_peripheral_sample.py` 写入 `tjwater_v2` 的 `peripheral_sample` schema。当前固定窗口为 2026-09-17,所有记录标记为 `synthetic`,并使用 `DEMO-` 前缀。
## 水质投诉 Agent 演示
## 工单事件调查
`POST /api/sample/v1/work-orders` 可创建 `work_order_type=water_quality_complaint` 的合成投诉事件,或 `work_order_type=burst_report` 的合成爆管上报。二者由外围同步器转换为统一事件调查任务,再由后端 worker 可靠交给 Agent;浏览器不再负责启动调查。事件和执行请求 ID 均由稳定业务身份确定,回执恢复或重试不会重复创建任务。
`POST /api/sample/v1/work-orders` 可创建 `work_order_type=water_quality_complaint` 的水质投诉事件,或 `work_order_type=burst_report` 的爆管上报,均默认使用业务来源。二者由外围同步器转换为统一事件调查任务,再由后端 worker 可靠交给 Agent;浏览器不再负责启动调查。事件和执行请求 ID 均由稳定业务身份确定,回执恢复或重试不会重复创建任务。普通业务录入无需绑定演练场景码,也不会向 Agent 注入预设监测结果或邻区投诉情况。
样板服务只保存工单,不直接调用 Agent。`scripts/sync_peripheral_work_orders.py` 使用受认证的后台身份同步外部版本并创建调查任务,`scripts/run_operational_worker.py` 再将持久化的待执行任务交给 Agent,因此浏览器关闭后流程仍可继续。
外围服务只保存工单,不直接调用 Agent。`scripts/sync_peripheral_work_orders.py` 使用受认证的后台身份同步外部版本并创建调查任务,`scripts/run_operational_worker.py` 再将持久化的待执行任务交给 Agent,因此浏览器关闭后流程仍可继续。