35-createdat.md 20 KB

后端执行票 —— 监测三端点 createdAt 真实契约缺失

问题

阶段工单前端真实接口联调与阶段收口本轮已授权只读预检:2026-10-13约16:34,真实后端 http://192.168.110.96:8301/api/cockpit/v1 的 /monitoring/overview、/monitoring/distribution、/monitoring/situation 均业务 code=200 / readOnly=true,但 data 缺少自有 createdAt 字段;不是显式 createdAt:null。监测概览真实监测点6、设备9。最新历史审计亦仅此三项失败。

实施依据与边界

沿用监测数据时间字段规格及监测数据时间字段决策,无需重新裁定业务口径。在后端仓库补三端点分区/信封与逐对象 createdAt,来源为真实 create_time,无数据显式null;不得用 updatedAt/serverUpdatedAt/sampledAt 冒充。本阶段验收票不修改功能代码。前端消费已由数据时间与片区/行业接线交付;后端补齐后验证现有消费。

验收

  1. 三端点按规格字段落点显式返回 createdAt,distribution台账与situation异常设备逐对象字段齐备;空态显式null,非空取真实来源。
  2. 异构来源跨类型max(create_time)与逐对象来源可核对,不伪造时间。
  3. 保持sampledAt等旧字段各自语义,不在map-snapshot/archive新增无消费字段。
  4. 有意义的契约测试、同运行版本真实只读复验、前后端数据时间/采样时间标签核对;提交推送并登记运行绑定。

下一步

ready-for-agent,等待后端执行会话认领;本轮仅发现并建票,未实施、未测试。它是整体阶段收口的技术阻断,不由真人验收豁免。

进度

  • 2026-10-14 诊断(只读,未改业务代码):未动工阶段,票面 Status: ready-for-agent 与 needs-triage 双状态冲突已消除。
  • 现象已复现:真实后端三端点 200/code=200,data 顶层与逐对象均无 createdAt(不是显式 null)。
  • 根因:字段从未实现(高置信)——后端 com.zksy.cockpit 全包 createdAt 零命中、git log -S createdAt 零提交;已排除「部署滞后」「Jackson NON_NULL 省略」「字段名/落点不同」三个候选。
  • 冗余检查:后端与前端消费层均无已实现版本,非「已实现 → wontfix」;本仓库无 .out-of-scope/,无既往拒绝。
  • 分流:bug + ready-for-agent(终态),已摘 needs-triage;Agent Brief 已作为评论附上。
  • 待确认(不阻塞标签):后端改动落在 E:\pipe-ner-server,本会话沙箱只覆盖前端工作区,需由后端工作区执行会话认领;票 18 记有维护者并行修改期间的暂停指示,实际认领时机待放行。

实施与验收(2026-10-14,维护者裁定 Q1 已放权在本会话执行)

实施完成:新增单一口径来源 cockpit/foundation/CockpitCreatedAt(只做 create_time → createdAt 的格式化与跨来源 max,不读时钟,故结构上无法用响应时间冒充数据时间);三端点响应类、三个适配器、三个快照类与三个响应内嵌对象(MonitoringPointMarker / UnassociatedEquipmentMarker / AbnormalEquipment)全部按规格 08 落点补齐。

  • overview:信封级 createdAt,取值域=筛选后参与本响应的设备 + 点位,跨类型 max。
  • distribution:信封级 + 点位 marker(monitor_point.create_time)+ 未关联设备 marker(equipment_base.create_time);信封取分页前全量台账 max(与三份分布同口径,故不随翻页跳动)。
  • situation:信封级取异常设备来源表 create_time max(维护者 Q3 裁定,与逐对象同源可复算)+ 异常设备逐对象 createdAt;事件时间仍由 warningTrend/alarmTrend 的 bucketStart 承载。
  • sampledAt / updatedAt / freshness.serverUpdatedAt 语义与取值不变;map-snapshot 与 archive 未新增该字段(真实探测 createdAt 出现次数均为 0)。

自动化验证:Cockpit*Test 507/507(0 失败、0 错误、0 跳过),新增契约测试 18 项:CockpitCreatedAtTest(格式化/空值/max 取真实时刻而非字符串序)5 项 + 三端点控制器契约(信封=max(逐对象)、与 updatedAt 取值不同、空态显式 null、取值域跟随筛选、翻页不变)13 项;三个适配器测试各加一项 create_time 列来源与 sampledAt/statusTime 分离的断言(显式令两列取不同值,证明确实未互相冒充)。

真实只读复验(http://192.168.110.96:8301,运行实例 PID 18576):

  • 三端点 HTTP 200 / 业务 code=200 / readOnly=true,data.createdAt 均存在且不等于 updatedAt(未拿快照/响应时间冒充)。
  • data.createdAt = 2026-10-12T15:15:47+08:00;distribution 6/6 点位与 9/9 未关联设备逐对象字段齐备;situation 8/8 异常设备齐备。
  • 自洽复算:distribution 与 situation 的信封值 == 各自逐对象 createdAt 的 max(逐条比对通过)。
  • 反例核对:t18-real-audit.mjs 由 140/143 → 143/143,0 失败,原三项 monitoring-createdAt-* 失败清零。
  • 前端消费侧真实数据核对:三面板「数据时间」读数由 — 变为 2026-10-12T15:15:47+08:00(此前 real 下恒为占位符)。

独立数据源核对(不是只看响应自证):用 Kingbase JDBC 直连 192.168.110.96:54321/pipi_ner(app_user schema)逐表核对 —— monitor_point 六个点位 create_time 全部为 NULL、equipment_base 中 21119740 为 NULL 而 41010500001320000001/…002 分别为 15:15:12/15:15:47。故逐对象 createdAt: null(前端显示「—」)是数据真实缺失,不是映射缺口;空态显式 null 行为符合规格 08,未被伪造成时间。

交付:提交 05c23774 已推送 origin/master(5a821872..05c23774),20 个文件(13 主源码 + 7 测试);变基到远端最新后复跑 Cockpit*Test 507/507 通过。运行绑定:运行实例 target/classes 已含 getCreatedAt 与 CockpitCreatedAt.class,与本提交一致。

并行在制品处置(纪律):入 E:\pipe-ner-server 时工作树另有并行会话的 #32 直径几何在制品(4 源文件 + .idea)与本地图无关改动。提交只裁剪本票 20 个文件;为推送做变基时临时 stash 该在制品并在推送后按字节还原(5 文件逐一 git hash-object 比对 IDENTICAL),分支 tip 复位到会话开始时的 a96091ce,其后 git stash drop 仅删本会话临时条目;未代表他人提交或推送其改动(该本地提交 a96091ce 至今不在任何远端分支,与原状一致)。

未做:未修改前端功能代码;未触碰 map-snapshot/archive;无写操作与 DDL(create_time 列已存在)。

Status: resolved Type: bug Blocked by: Assignee: ASUS Labels: ready-for-agent, wayfinder:task, backend-execution, bug

Comments

local — 2026-10-14T02:21:21.131Z

This was generated by AI during triage.

local — 2026-10-14T02:33:50.050Z

This was generated by AI during triage.

维护者裁定已回(2026-10-14)

  • Q1 = 已放权,在本会话执行 → 本会话(前端工作区沙箱已放开为 danger-full-access)直接执行后端仓库 E:\pipe-ner-server 的实现。标签保持 ready-for-agent。
  • Q2 = 现在放行 → 不等票 18 的并行窗口,立即开工。
  • Q3 = 按推荐 → situation 信封级 createdAt 取异常设备来源表的 create_time max(与逐对象字段同源可复算);事件时间继续由 warningTrend/alarmTrend 的 bucketStart 承载,不并入信封读数。

Agent Brief 的 Acceptance criteria 据此已明确:信封读数与逐对象字段必须同源可复算。

开始实施,进度回写本票 ## 进度。

Answer

已解决并关闭(2026-10-14)。三端点 createdAt 真实契约已补齐、测试、真实复验并推送。

根因:字段从未实现 —— 后端 com.zksy.cockpit 全包 createdAt 零命中、git log -S createdAt 对 cockpit 路径零提交,三个响应类与适配器均未读取 create_time。已排除「部署滞后」「Jackson NON_NULL 省略字段」「字段名/落点不同」三个候选(反证:同一响应中 district/reason/longitude 等 null 值均显式序列化,且运行实例已带同批新契约)。

修复(提交 05c23774,已推 origin/master 5a821872..05c23774):

  • 新增单一口径来源 CockpitCreatedAt:只做 create_time → createdAt 格式化与跨来源 max,不读时钟,故结构上无法用 updatedAt/serverUpdatedAt/sampledAt/status_update_time 冒充数据时间。
  • 按规格 08 落点补齐:overview 信封级(筛选后设备+点位跨类型 max);distribution 信封级 + 点位 marker + 未关联设备 marker;situation 信封级(异常设备来源表 max,维护者 Q3 裁定)+ 异常设备逐对象。
  • 空态显式 null;取值域跟随筛选;distribution/situation 信封取分页前全量(不随翻页跳动);map-snapshot 与 archive 不加该字段。

验收证据:

  • 自动化:Cockpit*Test 507/507(0 失败/0 错误/0 跳过),新增契约测试 18 项;变基到远端最新后复跑仍 507/507。
  • 真实只读 GET:三端点 data.createdAt 均存在、均不等于 updatedAt;distribution 6/6 点位 + 9/9 未关联设备、situation 8/8 异常设备逐对象字段齐备;信封值 == 各自逐对象 max(自洽复算通过)。
  • 权威审计脚本 t18-real-audit.mjs:140/143 → 143/143,0 失败。
  • 前端消费侧:三面板「数据时间」由 — 变为真实 2026-10-12T15:15:47+08:00。
  • 独立数据源核对(Kingbase JDBC 直连 app_user schema 逐表比对,非只看响应自证):monitor_point 六点位 create_time 全 NULL、21119740 为 NULL 而另两台为 15:15:12/15:15:47 —— 逐对象 null(界面「—」)属数据真实缺失,非映射缺口。

边界:不改前端功能代码;sampledAt 语义不变;无 DDL(create_time 列已存在);无写操作。

并行在制品纪律:提交只裁剪本票 20 个文件;推送所需变基时临时 stash 并行会话的 #32 几何在制品,推送后按字节还原(5 文件 git hash-object 逐一 IDENTICAL)并复位分支 tip,未代表他人提交或推送其改动。

方法论沉淀:createdAt 类「真实契约缺失」应当单一口径来源 + 不读时钟实现,使「拿响应时间冒充」在结构上不可达;跨端点信封读数的正确性判据是与自身逐对象字段自洽复算(本次两处均 pass),而不是与 updatedAt 比较大小;逐对象 null 必须回到源表核对才能区分「数据缺失」与「映射缺口」——只看响应无法自证。

Triage Notes(2026-10-14)

阶段判定:未动工。 票面 Status: ready-for-agent,同时又挂着 needs-triage(两个状态角色冲突)。读全正文/评论/标签后确认:本票自建立起只有发现记录,没有任何实施痕迹、没有认领人、## 进度 为空。按阶段闸门「未动工 → 正常诊断」处理。

一、现象(本轮已复现,2026-10-14 10:16 +08:00)

真实后端 http://192.168.110.96:8301/api/cockpit/v1 三端点实测仍缺 createdAt:

端点 HTTP / 业务 code 信封级 createdAt 逐对象 createdAt
/monitoring/overview 200 / 200 无 —(本端点无逐对象)
/monitoring/distribution 200 / 200 无 monitoringPoints[6]、unassociatedEquipment[9] 均无
/monitoring/situation 200 / 200 无 abnormalEquipment[7] 无

data 顶层 key 实测枚举(overview):requestId, apiVersion, readOnly, displayName, timezone, range, updatedAt, freshness, counts, status, onlineRate, typeDistribution, mapFilter, excluded —— 无任何等价时间字段。是字段整体不存在,不是显式 createdAt: null,与票面记载一致。

最小复现(纯只读,无需改代码):

$base='http://192.168.110.96:8301/api/cockpit/v1'
foreach ($p in '/monitoring/overview','/monitoring/distribution','/monitoring/situation') {
  $d = ((Invoke-WebRequest "$base$p" -UseBasicParsing).Content | ConvertFrom-Json)
  [pscustomobject]@{ route=$p; code=$d.code; envelopeCreatedAt=($d.data.PSObject.Properties.Name -contains 'createdAt') }
}
# 实测:三行 code=200 / envelopeCreatedAt=False

二、影响范围

  • 前端消费侧已交付,real 下恒显示占位符:src/modules/cockpit/domain/monitoringPanels.js 三处 createdAt: reader.optionalStr('createdAt')(overview / distribution / situation),缺失经 valueText(null) → '—'。后果是运行监测三面板「数据时间」在 real 模式恒为「—」,台账卡与异常设备清单的 dataTime 同样为「—」。mock 契约里有值(mocks/contractMocks.js),所以 mock 走查看不出这个缺口。
  • 票 18 阶段收口的直接技术阻断:verify/t18-real-audit.mjs 的 monitoring-createdAt-* 三项是当前审计唯一的失败项(21 项 18 过 / 3 失败);票 18 的 Blocked by 已含本票。
  • 不影响其余 15 个端点,不涉及写操作,后端只读边界不变。

三、根因候选

# 候选 置信度 判定依据
1 字段从未实现(响应类/适配器/快照均无 createdAt,也从未读 create_time) 高(≈95%) 后端 com.zksy.cockpit 全包 createdAt 零命中;git log -S createdAt 对 cockpit 路径零提交;CockpitMonitoring{Overview,Distribution,Situation}Response 三类字段清单无该字段;overview 适配器只用 status_update_time(即 sampledAt),distribution 适配器完全不传时间,situation 的 SourceMetricDevice 只有 sampledAt
2 部署滞后(实现已在 master、运行实例是旧构建) 极低(<5%) 反证:仓库 HEAD 与远端都不存在任何含该字段的提交;且运行实例已带八桶 pointStatus、district、infrastructure/geometry、设施总数 5283 等新契约,产物并不旧
3 Jackson 把 null 字段省略(NON_NULL) 已排除 反证:同一响应里 mapFilter.district:null、districtName:null、reason:null、longitude:null 均显式出现;后端无 setSerializationInclusion / default-property-inclusion 配置
4 字段名或落点不同(后端另有名字/位置) 已排除 反证:顶层与逐对象 key 全量枚举后无等价时间字段;updatedAt(快照加载时刻)与 freshness.updatedAt/serverUpdatedAt(响应生成时刻)语义已由决策 03 明确区分;distribution 的 statusTime 是现状被丢弃在响应外的字段

结论:单一根因、置信度高 —— 后端从未实现该契约。 规格 08 与决策 03 已把字段语义、三端点落点、空态与「不冒充」规则全部定死,无需重新裁定业务口径。

四、冗余与既往拒绝检查

  • 冗余:按领域概念(数据时间 / createdAt / create_time)检索后端 cockpit 包与前端消费层,未发现任何已实现版本,不是「已实现 → wontfix」。
  • 既往拒绝:本仓库不存在 .out-of-scope/ 目录,无同类请求被拒记录。

五、实施落点(供执行会话参考,本轮不动作)

三端点响应类各加可空 createdAt + 适配器/快照携带真实 create_time;来源实体 EquipmentBase.createTime、MonitorPoint.createTime 均已存在(无需 DDL);空态显式 null(当前序列化已确认会输出 null,无需额外配置);map-snapshot 与 archive 不加。


Agent Brief

Category: bug Summary: 后端为 /monitoring/overview、/monitoring/distribution、/monitoring/situation 补上自有 createdAt(记录创建时间 = create_time)契约:三端点信封级 + distribution/situation 逐对象级,空态显式 null,不用响应时间或采样时间冒充。

Current behavior: 三端点 HTTP 200 / 业务 code=200 / readOnly=true,但 data 中没有 createdAt(也不是显式 null)。前端消费侧(domain/monitoringPanels.js 的 createdAt 读取 + valueText(null) → '—')已交付并在 mock 下验证通过,real 下三面板「数据时间」与台账/异常清单时间恒为「—」。

Desired behavior: 按规格 08 与决策 03 的字段落点显式返回 createdAt:

  • overview:信封级一个读数,取聚合源真实 create_time 的跨类型 max;
  • distribution:信封级 + 点位 marker(monitor_point.create_time)+ 设备 marker(equipment_base.create_time);
  • situation:信封级 + 异常设备逐对象(来源表 create_time);
  • 无 create_time 或集合为空 → 显式 null;不得用 updatedAt / serverUpdatedAt / sampledAt / status_update_time 冒充;sampledAt 等旧字段语义不变;map-snapshot 与 archive 不新增该字段。

Key interfaces: 三端点响应类(CockpitMonitoring{Overview,Distribution,Situation}Response)各增一个可空 createdAt;三个适配器(BusinessCockpitMonitoring{Overview,Distribution,Situation}Adapter)在构建快照时携带来源 create_time;快照类(CockpitMonitoring*Snapshot)透传;MonitoringPointMarker / UnassociatedEquipmentMarker / AbnormalEquipment 三个逐对象结构各加 createdAt。来源实体 EquipmentBase.createTime、MonitorPoint.createTime 均已存在。

Acceptance criteria:

  • 三端点响应顶层含 createdAt 键(空态为 null,不是缺键)
  • distribution.monitoringPoints[]、distribution.unassociatedEquipment[]、situation.abnormalEquipment[] 逐对象含 createdAt
  • 非空取值等于对应来源表真实 create_time(可逐表核对),跨类型 max 语义可自洽复算
  • sampledAt / updatedAt / freshness.serverUpdatedAt 语义与取值不变
  • map-snapshot 与 archive 响应不含 createdAt
  • 有意义的契约测试;同运行版本真实只读复验三端点字段齐备;提交推送并登记运行绑定

Out of scope: 前端消费侧改动(已由票 15 交付,本轮只验证现有消费);sampledAt 语义变更;刷新/取数时机(归票 04/09);在 map-snapshot/archive 新增时间字段;任何写操作。


分流建议: 分类 bug;状态落 ready-for-agent(保持),摘除 needs-triage。理由:现象已复现、根因单一且置信度高、规格 08 已把口径与落点定死、验收标准可独立验证、无设计裁定待办;后端执行有大量同族先例(票 20/28/29/30/31 均由执行会话落地并推送 origin/master)。附两条待确认事项(见下),按「有小疑问可附待确认事项一起转,不阻塞」处理。

待确认事项(不阻塞转 ready-for-agent):

  1. 本会话文件沙箱只覆盖前端工作区 E:\City-Lifeline-Cockpit-TvT,而本票改动落在后端仓库 E:\pipe-ner-server —— 需确认由后端工作区的执行会话认领(先例如此)。
  2. 票 18 记有维护者「其他会话正在修改相关内容,等待正常后继续」的暂停指示 —— 本票标签照转,实际认领时机需维护者放行。

本轮未做: 未修改任何业务代码、未关闭票、未开始修复实施、未提交或推送;只做了只读检索与只读接口复现。

Answer