# 后端执行票 —— 设施总数三处口径不一致(5278 / 5276 / 5273) ## 进度 阶段闸门:票据原为 ready-for-agent,无 needs-triage/已有实施/阻塞;已认领(ASUS)。用户裁定设施统计范围为六类合法设施并集。 诊断完成:现场只读 GET 复现 5278/5276/5273。共同管网集合均5268,差异根因是三适配器读取的设施表不同:基础档案漏水源地和窨井;概览漏排水工程设施;管理信息漏水厂、泵站和排水工程设施。 实现完成:基础档案作为设施目录唯一来源,概览和管理信息投影同一目录;设施并集新增稳定 sourceKey;未知类型/缺编码明确进 excluded;修正未来日期设施片区分布缺失,保持既有年限/长度契约。 自动化验证:完整 pipe-network-service reactor `Cockpit*Test` 469/469 通过(0失败、0错误、0跳过),新增跨端点契约2/2。变基到远端最新后复跑 `*Cockpit*Test,*BusinessCockpit*Test` 465/465 通过(本票契约 2/2)。 现场验证(后端重启后):三端 facilityCount 均为5283;行业拆分 GAS537/WATER_SUPPLY1006/DRAINAGE3737/MANHOLE3 完全一致;基础档案片区合计5283;三端 excluded 全为0。旧5278/5276/5273矛盾已消失。 交付:提交 `96834794` 已推送 `origin/master`(`a4a727dd..96834794`);本票实现与测试共 11 个文件。 Type: task Status: resolved Assignee: ASUS Category: backend-execution Blocked by: Labels: ready-for-agent, backend-execution, wayfinder:task ## 来源 [票 24(前端设施点位与管线真实几何图层接线)](../cockpit-real-data-wayfinding/issues/24-24.md) 的验收第 4 条:「设施总数与后端真实口径一致」。真机走查时发现**同一屏上出现两个互相矛盾的设施总数**。 ## 实测证据(2026-10-12,只读 GET,`http://192.168.110.96:8301`) | 端点 | `totals.facilityCount` | 行业拆分 | | --- | --- | --- | | `/infrastructure/base-archives` | **5278** | 燃气 537 / 供水 1004 / **排水 3737** / 窨井 0 | | `/overview/infrastructure` | **5276** | 燃气 537 / 供水 1004 / **排水 3735** / 窨井 0 | | `/infrastructure/management-information` | **5273** | (片区×行业视图) | **三者各自内部自洽**(5278 = 537+1004+3737;5276 = 537+1004+3735),说明不是某处漏加,而是**三套服务对同一张 `app_user.pipe_network_base` 采用了不同的计数口径**。 差异定位到**排水 2 条**(3737 vs 3735)。两条链路的服务实现不同: - `CockpitInfrastructureBaseArchivesService`(5278):逐设施遍历,`typeCode` 非空 → 类型已知 → `objectKind == "FACILITY"` → 行业/设施类型/片区/建设年份分桶匹配 → 计数。 - `BusinessCockpitOverviewInfrastructureAdapter`(5276):按 `pipe_network_base.network_type` 分组,另有 `addFacilityCount(...)` 直接补 `WATER_PLANT` / `WATER_PUMP_STATION` / `DRAINAGE_PUMP_STATION` 等计数。 - `CockpitInfrastructureManagementInformationService`(5273):片区×行业聚合,又是一套。 实测 `/overview/infrastructure` 的 `industries[DRAINAGE].facilityTypes` 只有 `DRAINAGE_PIPE`(3735),即 `DRAINAGE_PUMP_STATION` 补计数为 0;具体是哪 2 条被 base-archives 计入而 overview 未计入(或反之),需在真实库上逐条比对确认。 ## 影响 驾驶舱**基础设施**面板由 `overviewStore` 把两个端点并成一张卡片:总数与行业构成取自 `/overview/infrastructure`,片区分布取自 `/infrastructure/base-archives`(见 `overviewStore.js` 文件头第 11 行)。两端点口径不一致时,同一张卡片上「设施总数 5276」与「片区分布 未分区 5278」并列出现——**自相矛盾且无人能判断哪个是真的**,值班人员无法据此判断数据完整性。 ## 交付物 1. **三套计数收敛为单一口径**(建议以 `base-archives` 为准:它字段最全,且已按票 20 的 `CockpitPipeNetworkType` 命名空间分组),`/overview/infrastructure` 与 `/infrastructure/management-information` 改为复用同一权威来源,而不是各自遍历。 2. 若某条记录确实**不该**计入(例如 `objectKind` 非 `FACILITY`、或建设年份口径不同),必须由契约表达出来并进 `excluded`,不得静默丢弃。 3. 补一条契约测试:**同一时刻三个端点的 `facilityCount` 必须相等**(或按契约声明的差异显式给出)。 ## 验收 只读 GET 实测:三个端点 `facilityCount` 一致;驾驶舱基础设施面板不再出现两个矛盾总数;`Cockpit*Test` 全绿并推送提交(基点写进票内)。 ## 关联 由[票 24](../cockpit-real-data-wayfinding/issues/24-24.md) 验收第 4 条派生。与[票 30](../cockpit-real-data-wayfinding/issues/30-untitled.md)(几何读模型)同属设施口径,建议一并排期。 ## Comments ### local — 2026-10-12T03:50:24.091Z 诊断与范围裁定:只读 GET 复现 5278 / 5276 / 5273。共同管网集合都是 5268,差异来自三套适配器的设施表集合不同,而非同一张管网表的加总算法:基础档案=5268+水厂3+供水泵站5+排水工程设施2;概览漏排水工程设施2;管理信息=5268+水源地2+窨井3,未读取水厂、泵站和排水工程设施。用户已裁定“三端点取合法设施并集”,基础档案权威来源补 WATER_SOURCE / MANHOLE,预计当前全局总数5283(供水1006/排水3737/燃气537/窨井3,待统一来源与真实复验)。实施方案:基础档案适配器作为唯一设施表读取和类型字典来源,概览与管理信息通过注入该来源投影,不再各自查询设施表;未知类型/无业务标识记录保留至 excluded,跨类型相同编码不得误去重;补真实适配器贯通三服务的契约测试,覆盖总数、行业、片区复算、合法并集和未知排除。后端工作树初始干净,基点7fb7c2c;本轮受项目规则限制不自动build/debug、启动服务或浏览器调试。 ### local — 2026-10-12T09:01:44.672Z 实现与自动化验收结果:统一设施目录覆盖管网、水厂、供排水泵站、排水工程设施、水源地、窨井;概览/管理信息复用目录;未知类型/缺编码显式落 excluded;管理信息以来源表+主键区分身份;未来日期设施仍计入片区分布;保持既有工程设施年限和概览长度精度契约。后端提交 b468fb0(基于本地 master,未推送)。完整 pipe-network-service Maven reactor Cockpit*Test:469/469,0失败、0错误、0跳过;新增契约测试2/2。现场服务仍旧版本,现场探针此前仍返回5278/5276/5273。下一步:维护者重载 192.168.110.96:8301 服务后重跑只读 GET、检查面板;同时须将提交推送至 origin 才满足票面验收。当前未推送、未部署、未完成现场验收,因此不关闭。 ### local — 2026-10-12T09:17:58.370Z 现场只读验收(后端重启后)已通过:`/infrastructure/base-archives`、`/overview/infrastructure`、`/infrastructure/management-information` 的 `totals.facilityCount` 均为 5283。三端行业拆分完全一致:GAS=537、WATER_SUPPLY=1006、DRAINAGE=3737、MANHOLE=3;基础档案片区合计=5283(全部未分区);三端 excluded 均为 0(含 duplicateRelationCount=0)。旧矛盾 5278/5276/5273 已消失。票据自动化测试此前已 469/469 通过,新增契约 2/2。当前仅剩本地提交 b468fb0 尚未推送;根据此前授权范围不自动 push,因此票保持 open,下一步是获得推送授权后 push,再关闭票并更新 map Decisions so far。 ## Answer **已解决并关闭(2026-10-12)**。三套设施计数已收敛为单一口径。 **根因**:不是同一张 `pipe_network_base` 的求和算法不同,而是三个适配器各自选择了不同的设施表集合——基础档案(管网5268+水厂3+供水泵站5+排水工程设施2=5278)漏水源地与窨井;总体概览(管网5268+水厂3+供水泵站5=5276)漏排水工程设施;管理信息(管网5268+水源地2+窨井3=5273)漏水厂、泵站与排水工程设施。 **修复**(提交 `96834794`,已推 `origin/master`): - 新增唯一设施目录 `CockpitFacilityCatalog`,基础档案适配器成为六类合法设施(管网、水厂、共用泵站、排水工程设施、水源地、窨井)的唯一读取与类型字典来源。 - `/overview/infrastructure` 与 `/infrastructure/management-information` 改为注入并投影同一目录,不再各自遍历设施表。 - 目录记录带稳定 `sourceKey`(来源表+主键),跨表同编码设施不被关系去重误合并。 - 无可信类型/缺业务编码的记录不再静默丢弃,保留内部哨兵并计入 `excluded`。 - 修正未来日期设施计入总数却漏入片区分布的不自洽。 **验收证据**: - 自动化:`Cockpit*Test` 469/469(变基后复跑 `*Cockpit*Test,*BusinessCockpit*Test` 465/465),新增跨端点契约 `CockpitFacilityCountCrossEndpointContractTest` 2/2。 - 现场只读 GET(后端重启后):三端 `totals.facilityCount` 均为 **5283**;行业拆分 GAS=537、WATER_SUPPLY=1006、DRAINAGE=3737、MANHOLE=3 三端完全一致;基础档案片区合计 5283;三端 `excluded` 全为 0。旧矛盾 5278/5276/5273 消失。 **范围裁定**:维护者确认三端点取**合法设施并集**(保留水源地与窨井),而非仅对齐到 5278。 **边界**:本票只统一统计定义与来源,不新增跨请求缓存或快照 token;设施无权威片区来源,如实全部「未分区」;排水工程设施年限映射与概览长度精度契约按原样保留。 **方法论沉淀**:跨端点计数一致性必须由贯通真实适配器与服务的契约测试锁定,而非各自单元测试;现场一致性比较要求业务数据稳定。以 `zksy-admin` 子目录单独构建会命中本地仓库旧 `zksy-system` JAR 而报「找不到 cockpit.geometry」,须从 `pipe-network-service` 完整 reactor 构建。