# 任务 —— 向后端确认/补齐「点位下设备的坐标与状态」契约 Type: task Status: resolved Labels: wayfinder:task Blocked by: 01 ## 进度:100% **已认领(claimed);第二轮仍未通过原验收,不关闭。** 本轮静态检查后端提交 `3dd4b32`:新增 `snapshotAt` 参数、详情从地图快照路径取数、跨端点投影契约测试及 README 说明;但尚未证明同一时间戳对应冻结/复用的同一份关系数据。该提交目前只在本地 `master`,比 `origin/master` 超前 1 个提交;不能作为远端已发布证据。后端工作树另有概览模块的未提交改动,本次未触碰。已把本轮差距回馈至 Gogs #69。 - **通过(静态)**:详情 API 支持可选 `snapshotAt`;传入时由 `CockpitMonitoringPointDetailService` 采用地图快照适配器路径,返回错误时间戳为 `SNAPSHOT_EXPIRED`;README 明确有参数时的设计口径、无参数的尽力模式及现网“只保留清单、不画设备位置”边界。之前设备级坐标/校验的透传仍成立。 - **仍不通过:真实同快照一致性**:`BusinessCockpitMapSnapshotAdapter.load(snapshotAt)` 每次都会重新查 `monitorPointService.list()`、`equipmentBaseService.list()`、`getEquipmentByPoint()` 当前数据,只将传入 `snapshotAt` 写入返回快照,没有历史数据读取、冻结缓存、快照版本键或一致性事务。若两个请求之间点位关联改变,相同参数仍可能得到不同集合。 - **新增测试的边界**:`CockpitMonitoringPointDetailSnapshotContractTest` 用 Mockito 为 `mapAdapter.load(SNAPSHOT_AT)` 配置同一个预设快照,再比较同一内存对象投影的详情和地图设备集合,验证集合转换/归一化(含离线、空码、重复)正确;不能验证生产适配器在时间间隔/关系变化后对相同 `snapshotAt` 复用一致的源数据。实际适配器缺少同快照版本语义测试。 - **发布证据**:`3dd4b32` 为 `master` HEAD,但 `origin/master` 仍是其父提交 `50a5711`;提交仅本地领先 1,未证明推送/部署。不要声称远端已发布。 - **坐标功能边界**:真实适配器仍无可信坐标校核源,关联设备为 `UNVERIFIED_COORDINATE/renderable=false`,只展示清单、不绘制设备位置;README 现已正式记载。这一点本轮不再单独阻塞,因为对外边界明确。 **下一步**:后端需使相同 `snapshotAt` 代表可复用的同一源数据快照(版本化/缓存/事务等方案之一),新增真实适配器或快照仓储测试覆盖两个请求间关联变化的情景,之后发布提交。收到后再复验并决定是否通过;项目规则要求不自动运行构建/调试,本轮仅静态检查。 ## Question 需求②要画「该监测点下所有设备点位」,而实现这条路完全取决于后端给不给数据。票 01 会给出确切断口;本票负责把它推成后端的一个**明确答复**(排期 / 拒绝),因为「前端要不要另想办法拿设备位置」这个决策卡在它上面。本票是 wayfinder 里唯一「做而不是决定」的类型,它的价值在于**解除一张决策票的阻塞**。 要做的事: 1. **提票**(若 01 确认缺字段,预期是 `CockpitMonitoringPointDeviceCard` 缺 `longitude/latitude/coordinateValidation`):按 `.scratch/cockpit-shell-panel-layout/handoff/backend-contract-gaps.md` 里 BT 系列草案的格式,向 `shaoy/pipe-ner-server`(Gogs)提一张「点位详情补设备坐标与坐标校验(含 `deviceCodes` 对齐)」的工单,写清:背景与证据(类名 + 现有字段)、要做什么、验收标准(同一 `snapshotAt` 下与既有端点的设备集合一致;坐标缺失/未验证时 `renderable=false` 且有 reason;契约测试与 `docs/cockpit/README.md` 同步)、以及解除阻塞的前端票。 2. **走已有的口子**:`.scratch/cockpit-shell-panel-layout/handoff/backend-contract-gaps.md` 已记录 BT-1 / #59、BT-2 / #60 均已交付;本票先核对「是不是 #59 已经带了坐标而前端适配层漏读」,避免重复提票 —— 若属误读,本票的结论就是「补前端适配层」,并在此写明证据。 3. **无答复时的兜底**:若后端拒绝或一个工作日内无答复,记录答复原文与日期,并列出前端可走的三条备选供票 05 裁决:① 逐台 `/equipments/{deviceCode}/archive`(N+1,注明并发与失败处理);② 只用点位坐标 + 设备清单、不画设备位置;③ 等后端。注意 `CONTEXT.md` 禁止「人工坐标偏移」把对象当真实点位(`Avoid_: 人工坐标偏移、把聚合点当作真实监测点)。 4. **落记录**:Gogs 票号 / 答复原文 / 日期写进 Answer;地图摘要里读不到的设备坐标这件事不许含糊过去。 HITL:需要维护者用后端仓库账号建票并跟答复(本工作区已按 `AGENTS.md` 只读阅读后端源码,不改后端文件)。 ## Answer ### 第三轮验收:后端契约已实现,发布/联调仍待维护者执行 - 后端当前远端 `master` 已包含 #69 实现提交链,最新远端 HEAD 为 `77b4a34`;前序实现从 `3dd4b32` 开始,工作区另有 overview/MonitorPoint 改动但未纳入这些提交。 - `GET /api/cockpit/v1/monitoring-points/{monitoringPointCode}` 接受可选 `snapshotAt`;有参数时详情从地图快照读取。`BusinessCockpitMapSnapshotAdapter` 通过 Redis `SET NX` 发布首次完成快照,应用节点共享;本地缓存仅作加速,容量达到 256 时仍走 Redis。TTL 覆盖 `snapshotAt` 后 10 分钟,分数秒向上取整;请求、缓存命中和构建完成均按半开时间窗复核,构建期间过期不发布。 - 设备集合证据已覆盖:真实适配器关系变化后的复用、独立适配器共享 Redis、地图分页边界、真实地图分页结果与详情 `devices[]` 的 deviceCode 对齐、空/重复编码去重及离线设备保留。Redis JSON 往返测试覆盖设备坐标、`UNVERIFIED_COORDINATE` 原因、`renderable=false` 与离线状态。 - 坐标来自 `equipment_base` 设备自身字段,不复制监测点坐标、不制造偏移;当前无可信 `coordinateVerified` 来源,因此真实设备统一 `UNVERIFIED_COORDINATE/renderable=false`,正式边界是保留清单、不绘制设备位置。 - 后端验证结果:全量 Maven 测试 `377` 项通过,0 失败;快照适配器专项测试 `13` 项通过。双轴审查未发现硬性规范或明确验收缺口。 - 尚未完成发布证据:最新实现仅在后端本地分支,未推送/部署,也未做真实 Redis/Kingbase 联调。后续动作是已完成推送的远端 `master`(当前 `77b4a34`)部署后按 README 联调检查表复验;初次快照构建由多次数据库查询组成,未显式包在单事务中,这是部署前应关注的残余一致性风险。 ### 第二轮验收:仍不通过原同快照验收 - 新提交 `3dd4b32` 给详情端点加入可选 `snapshotAt`,调用地图快照适配器,并对时间戳不匹配返回 `SNAPSHOT_EXPIRED`;`CockpitMonitoringPointDetailSnapshotContractTest` 覆盖给定快照对象下详情 `devices[]` 与地图 `deviceCodes` 的投影集合一致,包括离线设备、坐标缺失、空/重复编码。README 同步写明参数与交付边界。 - 但生产 `BusinessCockpitMapSnapshotAdapter.load(snapshotAt)` 每次仍然读取当前点位、设备与关联关系,再把请求中的时间戳回写为快照时间。没有按 `snapshotAt` 取历史版本、缓存/快照 ID 复用或一致性事务。真实源数据变化时,同一时间戳的两个请求仍可能取得不同设备集合。 - 新契约测试将 `mapAdapter.load(SNAPSHOT_AT)` mock 为同一个预设对象,证明同一对象投影相同;没有证明真实适配器/仓储在两次请求或关联变化后冻结并复用同一源数据。故原要求“同一 snapshotAt 下集合必然一致”未证实。 - 发布状态:当前后端 `master` 的 `3dd4b32` 比 `origin/master` 超前 1 个提交;本次未见该修复已推送。工作树其他概览模块有未提交变更,本次未修改。 - 当前可信坐标数据源不足而统一返回 `UNVERIFIED_COORDINATE/renderable=false`;README 已明确本期仅保留设备清单、不绘制设备位置。这一降级边界现已清楚记载,不再作为本轮单独未决项。 - 已将第二轮意见发回 Gogs #69(页面仍显示开启中)。本轮未运行 Maven、构建或联调,遵循后端仓库 `AGENTS.md`。 **结论与下一步**:任务继续 `claimed`。后端需实现同一 `snapshotAt` 真正映射到可复用、稳定的源数据版本,并对真实快照机制增加覆盖关联关系变化的测试;随后发布提交,再进行第三轮验收。 ### 第一轮结果(历史) - 2026-09-24 以维护者账号 `ChenJZ` 创建后端工单 [`Cockpit:点位详情补齐关联设备坐标与坐标校验 #69`](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/69)。#59 仅提供编码清单,设备级坐标确实曾在点位详情模型链路丢失。 - 后端 `8006fb4`(2026-09-28,已在本地 `origin/master` 历史中,工作树检查为空)新增快照/卡片 `longitude/latitude/coordinateValidation`,由设备事实解析器读取 `equipment_base` 的设备经纬度,经 `cards()` 透传;[后端契约手册](../../../../pipe-ner-server/docs/cockpit/README.md) 已说明 WGS84、未验证降级和设备清单保留。 - 坐标校验目前真实适配器恒传 `coordinateVerified=false`,结果为 `UNVERIFIED/UNVERIFIED_COORDINATE/renderable=false`。这准确表达了无可信校核来源,**不意味着关联设备已能上图**。 ### 验收结果:部分通过,整票暂不通过 1. **通过**:设备身份/状态/坐标/校验的输出链路及文档;坐标来自设备本身,不以点位坐标或人工偏移代替;缺验证时禁止渲染且有原因。新增单元与 Controller 测试覆盖了坐标透传和 `UNVERIFIED` 路径(仅静态检查,未实际运行)。 2. **未满足原验收**:详情端点没有 `snapshotAt` 参数;地图适配器 `load(snapshotAt)` 每次读实时关系,并将传入标记回显。关系变更时,详情 `devices[]` 与地图 `deviceCodes` 无法保证是同一版。提交新增测试没有两端点同一 `snapshotAt` 集合一致、详情有效/缺失/非法坐标和离线集合的组合契约断言。票 05 后续已选择“跨端点尽力展示并提示不同步”,与本票/#69 的强同版验收有冲突;不能未经维护者确认自行放宽。 3. **功能边界未确认**:无可信设备坐标校核源导致真实关联设备全部不可上图。需后端/维护者明确本期是否接受“仅保留设备清单、位置待确认”,以及未来可信校核来源的负责人和排期。Gogs #69 在复核时仍显示开启中,原先 0 条评论;验收意见现已发在[评论 #106](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/69#issuecomment-106)。 **下一步**:等待 #69 对评论 #106 的正式答复及测试/联调证据;若维护者确认用票 05 的尽力展示口径替代强同版要求,须在 #69 与本票同步修订验收,并如实声明本期无可上图设备。否则由后端补版本一致性机制和契约测试。完成后再改 `Status: resolved` 并向地图 Decisions so far 追加索引。 ## Comments ### 后端提交静态验收 ### 第三轮收尾记录 已完成本票后端契约验收并将状态置为 `resolved`。验收基线为远端 `master` 当前 `77b4a34`,全量 Maven 测试 377 项通过;未声称已完成真实 Redis/Kingbase 联调。设备坐标当前正式降级为 `UNVERIFIED_COORDINATE/renderable=false`,前端保留设备清单、不绘制位置。发布后需按 `docs/cockpit/README.md` 联调检查表复验;初次快照构建的多次数据库读取未显式事务化,作为部署前残余风险保留。