平台工程

风眼洪涝维度改造复盘:单因子分级会在最危险时段给出最低档

一句话:当分级依据只覆盖一条致灾路径,遇到走另一条路径的极端个例时,它不是”不够准”,而是给出反向信号——风眼按风力推档,美莎克减弱成热带低压后档位回落到四档最低的蓝色,而那正是伤亡最集中的 26 小时。

事实记录(不可修改区)


错在哪(设计事实)

不是阈值调错了,是分级依据只覆盖了一条致灾路径

台风等级(热带低压→热带风暴→…→超强台风)是按近中心最大风速定义的。风眼把它直接当成”危险程度”的代理,于是:

致灾路径风眼是否感知
大风(吹倒/吹飞)windLevel
风暴潮⚠️ 间接(nearCoast)
暴雨内涝❌ 数据模型里没有雨
山洪/滑坡
水库溃坝

美莎克走的是后三条。而后三条恰恰在台风减弱时才充分发展(残涡滞留、水汽持续输送),于是出现反向关系:致灾能力上升的同时,风力档位在下降

这比”少了个功能”严重:一个只报风的系统,在纯降雨型台风面前不是沉默,是主动给出安全信号


结果分析


方法论沉淀

⚠️ 单因子分级会在最危险时段给出最低档(首次发现)

核心:分级/评分系统若只取一个代理指标,遇到走其他致灾路径的个例时会反向失效——不是不够灵敏,是自信地报安全。风眼按风力推档,而美莎克的伤亡全部来自水;风力档位在残涡滞留阶段回落到蓝色,恰是死亡最集中的 26 小时。

来源:美莎克(2610)“弱级强灾”,官方定性;代入改版前 suggestLevel 得到的档位序列 黄→蓝→风平浪静。

操作规则:

  1. 给任何分级系统列一张致灾路径 × 是否被感知的表(见上文),空格就是盲区;
  2. 多路径系统取 max(各路径档位),不要用单一指标推导;
  3. 当次要路径档位高于主指标档位时,必须在界面上说破这件事,而不是静默取高——否则用户会拿主指标(台风等级)自行推翻你的建议;
  4. 迁移场景:健康风险评分、告警分级、风控评分、内容审核置信度——凡”用一个易测量代理去表达一个多因致的风险”都适用。

⚠️ 数据源的生命周期短于业务风险的生命周期(首次发现)

核心:上游数据源的对象生命周期,往往按它自己的业务定义,而不是按你的。台风”编号”只存在 6 天(停编即从官方 JSON 消失),但这场灾害的伤亡数字是停编 45 天后才核定的(39 → 159)。系统跟着数据源的生命周期归零,于是在灾后重建期显示”风平浪静,风来之前都是准备的好时候”。

来源:7-07 停编 → 8-21 新华社定案,中间六周页面持续显示无台风态。

操作规则:

  1. 接入外部源时明确问一句:“这个对象消失,是它的风险结束了,还是只是它在上游的记账周期结束了?”
  2. 两者不一致时自建一段”余波窗口”,由真实风险信号(此处=影响省份仍有洪涝预警在效)而非源对象存在与否来决定退出;
  3. 余波期的文案要与常态区分,不要复用”一切正常”那套话术。

⚠️ 混合行尾会让多行锚点替换静默失败,而常用命令查不出来(首次发现)

核心:E:\typhoon-eye 全部源文件为 CRLF / LF 混合(仓库既有状态,无 .gitattributes)。用 \n 拼接的多行锚点做字符串替换必然 miss,单行锚点却正常命中——症状极像”锚点写错了”,实际是行尾不匹配。更坑的是 Git Bash 的 grep -c $'\r'awk '/\r$/'cat -Awc -l 都会静默剥掉 CR,查不出问题;只有 node -e 'JSON.stringify(...)'file 看得见(实测 app.js 有 943 个 CR)。

来源:本轮连续 3 次多行锚点替换失败,先后怀疑过锚点抄错、heredoc 转义、patcher 逻辑,最后靠 node 打印原始字节定位。

操作规则:

  1. 改这类仓库,锚点替换要么只用单行锚点,要么让匹配对行尾不敏感(先按原样找,找不到再按全 CRLF 变体找);
  2. 不要为此做全库行尾规范化——那会把真实改动淹没在噪声里;git 本身配了 autocrlf,提交时会归一;
  3. 排查行尾问题一律用 node/python 看原始字节,别信 Git Bash 的文本工具;
  4. 附带一坑:本机 bash heredoc 即使用 <<'EOF' 引号形式也观察到会把 \\ 折成 \,所以 patcher 脚本里避免写正则转义(用双变体字符串匹配代替)。

⚠️ 自曝局限比被人发现更有利(首次发现)

核心:“风眼查不到美莎克”被当成了传闻的佐证。真实原因(仓库比台风晚建三天 + 只渲染在编台风)平淡且对作者不利,但由作者自己讲清楚,比等别人发现要好得多——它同时解决了传闻和信任两件事。本轮把这条写进了 README、PLAN.md 和对外专栏的最后一节,并顺势承诺了”做一个能查历史台风的版本”。

操作规则:工具的已知局限写在自己的文档里,并在对外稿里主动点名;别等它变成别人手里的证据。与打磨不等于校验律_v1互补:那条讲”看起来精致会虚假抬高信任”,这条讲”主动示弱能换回真实信任”。


顺带修掉的既有隐患

#tyKicker 内含 #tyCode / #tyEnName 两个 span,而”风平浪静”分支直接 tyKicker.textContent = "西北太平洋"把这两个子节点连根删除,此后任何 $("tyCode") 返回 null。原代码没暴露是因为无台风分支之后不再引用它们;本轮新增”影响持续期”分支需要读 code/enName,一写就崩。已改为重建结构(setKickerStorm),顺带修掉”无台风态 → 有台风态”切换时的潜在崩溃。

教训:textContent 赋值是破坏性的,凡容器内嵌有 id 的子元素,一律重建而非直接赋值。


关联文档

类型/平台工程主题/风眼主题/预警设计主题/踩坑