What to build: 对后端发布坐标做防御性校验。非法、缺失、零值、超范围或未校验坐标的对象不上图,但保留在列表和详情中,并显示明确原因。
Blocked by: 08
Status: resolved Labels: ready-for-agent
认领:2026-09-18 会话接手。前置 08(地图摘要分页与快照)已 resolved,依赖已解除。
实施前按 grilling 澄清了 6 个悬而未决的取舍(票面语气是「不上图 / 保留在列表」,而地图上今天一个点位都没画、 列表也还没建),维护者裁定:Q1=只交数据面准入判定(渲染归 09/22);Q2=(c) 但以数据面为主体, 另加一个地图上的可见清单作为本票的唯一可见证据;Q3=按推荐(只认后端
renderable);Q4=B(用后端全量口径); Q5=逻辑闸门 + 真机走查两件套;Q6=依赖已解除。
t07-coordinate.mjs 39/39;真机走查 20/20。已完成并关闭(2026-09-18)。 逻辑闸门 39/39、真机走查 20/20; 回归 t05(179/179 + 走查 10/10)、t08(44/44 + 走查 16/16)、t01 走查 20/20、t28 7/7、t29 6/6、t30 7/7 全绿。
领域层(新增 domain/coordinate.js,纯函数、可脱浏览器断言)
isRenderable(item) 只认后端 coordinate.renderable === true。
连 state === 'VALID' 都不作为备选判据——那是第二套判据,一旦与 renderable 分歧(后端将来加新 state),
两个答案必然有一个是错的,而错的会画到地图上。票 07 原句「前端不自动纠偏、不使用默认坐标」的代码化落点就在这里。validated:false)→「坐标未校验」(这是「缺失」,不是「非法」);
reason 命中词表 → 具体原因;其余认不出 →「无地图位置」。词表照抄后端源码(本机 E:\pipe-ner-server
的 CockpitCoordinateValidator,六个取值:UNVERIFIED_COORDINATE / MISSING_LONGITUDE / MISSING_LATITUDE /
LONGITUDE_OUT_OF_RANGE / LATITUDE_OUT_OF_RANGE / ZERO_COORDINATE),保证文案与后端结论一一对应而非前端猜一套。splitByCoordinate() 交两堆:不上图 ≠ 不存在。被拦下的对象带编码与名称进 blockedEntries(),
供列表渲染——静默丢掉正是 CONTEXT.md「无地图位置」词条点名禁止的(Avoid: 默认坐标点、静默隐藏)。coordinateOverview(objects, backendSummary):界面唯一读的那个对象,把两个口径并排给出(见下)。两个口径,主语分开(维护者裁定的 Q4=B)
这是本票最容易骗人的地方,所以分开说、不混成一个数:
backend —— 后端 coordinateValidation 汇总,全量口径。读后端源码确认:CockpitMapSnapshotService.load()
用整份 points/equipment 算完汇总再切片分页,所以它不随翻页跳动。loaded —— 前端按已加载对象算的自检口径。toMapBatch() 根本没读这段(票 05 遗留),现如实带出并单测钉住。修掉一处会骗人的措辞:票 08 的摘要文案写「已上图 N 个」而 N = loaded(含不上图对象)。
票 07 起有对象因坐标被拦下,这两个数不再相等——照旧写法会把 5 个说成上图的 5 个(实际只有 2 个画得出来)。
现在按坐标准入分开报:「已上图 2 个 · 无地图位置 3 个」;调用方没给 objects 时(纯文案单测)保持原措辞。
界面(components/MapCoordinateBlocked.vue,新增)
z-index:2 浮在其上(地图 z-index:0 且自成层叠上下文),
贴左下的浮块会被 300px 宽的左栏整块盖住 → 居中放在底部信息带之上(bottom: 100u,让开图例/标题/状态灯那一条)。data-map-blocked-* 供走查断言;原因码只上 data-*,界面上只有中文。MapCanvas.vue 追加宿主 dataset:data-map-renderable / data-map-blocked / data-map-blocked-backend / data-map-coordinate-crs。stores/mapStore.js 供货 coordinate 计算属性——组件零坐标判据(静态守卫 I3 钉住)。mock(mocks/contractMocks.js)
coordinateValidation 全量汇总,照抄后端的三桶分法(renderable 优先,其余里 state === 'INVALID' 记非法,
剩下的记未校验)——换一套算法就会让界面显示的数与后端对不上。empty / degraded 两个样例同样带上,供现场演示。node .scratch/cockpit-shell-panel-layout/verify/t07-coordinate.mjs → 39/39。八段:
A 唯一准入判据(含两条对抗:state=VALID 但 renderable=false 必须不上图;state=INVALID 但 renderable=true 照画,
以及「181° 原值不被纠正」);B 六种原因逐一命中 + validated:false 归「缺失」+ 认不出的不泄露原因码;
C 切分不静默丢对象(两堆都交出去);D 两个口径分开 + 缺失不补 0;E 汇总进批次且跨页不累加;
F mock 三桶分法与后端一致;G store 供货;H 「已上图」措辞不再把被拦下的算进去;
I 静态守卫(领域层零范围重算、准入只有一处、界面零坐标判据、界面零原因码、后端裸字段不出领域层)。node .scratch/cockpit-shell-panel-layout/verify/t07-coordinate-walkthrough.mjs → 20/20
(yarn dev @ localhost:8000,Chrome 152 headless;先核对四个改动模块确实是最新的再跑,避免拿旧模块假绿)。逐条:
翻到底后可上图 2 · 无地图位置 3 · 已加载 5;清单计数 3 且对象没被静默丢掉;
后端全量口径 3(非法 2 + 未校验 1)与已加载口径 2/5 是两个数、措辞分开;
摘要文案不再虚报「已上图 5 个」;展开后三条原因逐条中文(坐标未经校验 / 经度超出合法范围 / 零坐标(经纬度均为 0)),
原因码只出现在 data-*;空样例 未取到坐标校验汇总(不编 0);字段缺失样例落「坐标未校验」且仍被列出;
清单不出地图宿主、零横向溢出、仍只有一个地图宿主、全程零页面级报错。t08-map-summary 44/44(逻辑)+ 走查 16/16、t05-adapter 179/179 + 走查 10/10、
t01-browser-walkthrough 20/20、t28-fill-container 7/7、t29-basemap-walkthrough 6/6、
t30-intro-walkthrough 7/7,另有 t01-panel-catalog / t03-camera-contract / t04-config / t06-assets /
t21-terrain / t21-view-modes / t29-basemap / t30-view-presets 逻辑脚本全通过。yarn build(生产构建)与 git 提交——按 AGENTS.md 的验证规则,只在维护者明确要求时执行。state === 'VALID'」,结果命中的是我解释
为什么不用它 的那句注释。改成先剥注释再断言——拿注释当证据等于没守。sectionFromResult 对 EMPTY 分区不带载荷,
全零汇总在适配层就被放下。我最初断言 blockedBackend === '0' 会假红,而措辞写成「后端未发布」
更是把责任推错地方(那个 0 后端确实发布过)→ 改为「未取到坐标校验汇总」,断言与文案同步修正。advanceUntilSettled() 真翻页(票 08 踩过同型坑)。panelInsideHost: true、零横向溢出,猜测被证据替代。data-map-blocked-backend 这个名字同时挂在
地图宿主(dataset)与清单里的 <p> 上,而宿主在 DOM 里更靠前 —— querySelector 命中宿主,
拿回的是整页文本,于是 includes('全量') 恒真。改成面板内选择器 + 给 <p> 换
data-map-coordinate-backend/-loaded,复跑后 A5 的证据才变成真正那一行
(全量可上图 2/5 · 坐标非法 2 · 未校验 1 | 已加载 5 个 · 可上图 2 · 无地图位置 3)。
教训同票 08:走查绿不够,得知道绿的是什么。blockedEntries,本清单自然退为地图上的辅助提示。coordinateValidation(后端补契约见 issues/25 的 BT-4),票 14 的
「无有效坐标时显示原因」需等该契约;本票的判据已可复用(blockReason() 对缺校验段给「坐标未校验」)。map.md)。