@metweave/parser 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +27 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +27 -3
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @metweave/parser — 解析层:METAR/SPECI(tolerant)→ IR。\n * The parsing layer: METAR/SPECI (tolerant mode) → IR.\n *\n * v0.1 实现范围:METAR 正文 + 趋势组半结构化 + RMK 认组 + 跑道状态最小形。\n * 纪律:不静默——看不懂的 token 一律进 warnings[](unknown-token,info 级),绝不丢弃;\n * 缺测电码(////、/////KT、//)与不可信值(5 位数 QNH)→ Observed missing + 告警;\n * 单位跟组走;一切产物携带原文 span。strict 模式预留给报文校验场景。\n */\nimport type {\n AltimeterReading,\n CloudAmount,\n CloudCondition,\n CloudElement,\n ConvectiveType,\n MetarReport,\n WindShearGroup,\n Observed,\n ParseOptions,\n ParseWarning,\n RemarkGroup,\n RemarkKind,\n ReportKind,\n RunwayStateGroup,\n RunwayVisualRange,\n SkyClearCode,\n Span,\n TemperatureReading,\n TrendElements,\n TrendGroup,\n VisibilityGroup,\n WeatherDescriptor,\n WeatherGroup,\n WeatherPhenomenon,\n WindGroup,\n} from \"@metweave/core\";\nimport { MetarParseError } from \"@metweave/core\";\n\ninterface Token {\n readonly text: string;\n readonly start: number;\n readonly end: number;\n}\n\nconst PHENOMENA: readonly WeatherPhenomenon[] = [\n \"DZ\",\n \"RA\",\n \"SN\",\n \"SG\",\n \"IC\",\n \"PL\",\n \"GR\",\n \"GS\",\n \"UP\",\n \"BR\",\n \"FG\",\n \"FU\",\n \"VA\",\n \"DU\",\n \"SA\",\n \"HZ\",\n \"PY\",\n \"PO\",\n \"SQ\",\n \"FC\",\n \"SS\",\n \"DS\",\n];\nconst DESCRIPTORS: readonly WeatherDescriptor[] = [\"MI\", \"PR\", \"BC\", \"DR\", \"BL\", \"SH\", \"TS\", \"FZ\"];\nconst TREND_KINDS = new Set<string>([\"NOSIG\", \"BECMG\", \"TEMPO\"]);\n/** 趋势段拖词容忍集(无 typed 语义的磨损尾/连接词——收进 trend.raw 静默保真,不产生噪声):\n * 语料实弹 VNKT 120930Z「NOSIG CB TO NE AND E」(观测员补记磨损尾)与既有回归锁契约\n * (拖词不告警、原文留 raw);含裸对流码 CB/TCU(无云量云高位的残缺云信息,无解码面)与\n * 16 方位词、TO/AND 连接词。与「交回正文恢复 typed 语义」的收窄主判据互补:\n * 有语义可恢复的(温露/QNH/$/WS/TX/TN/RVRNO)一律收口交回,纯噪声拖词保持原文静默。 */\nconst TREND_FILLER_WORDS = new Set([\n \"TO\",\n \"AND\",\n \"CB\",\n \"TCU\",\n \"N\",\n \"NNE\",\n \"NE\",\n \"ENE\",\n \"E\",\n \"ESE\",\n \"SE\",\n \"SSE\",\n \"S\",\n \"SSW\",\n \"SW\",\n \"WSW\",\n \"W\",\n \"WNW\",\n \"NW\",\n \"NNW\",\n]);\n/** 趋势段收组判据(封闭清单):只有趋势合法要素族(WMO 306 FM15 §15.14.2/§15.14.10:风/能见度/现在天气/云,\n * 加趋势专属 NSW 与 CAVOK 顶替)与风组变化组拖带形(dddVddd)可收进趋势段;其余 token 一律收口\n * 交回正文循环——正文各分支自带认组与 unknown-token 出声,语义无损恢复,冲突组自然触发重复组告警。\n *\n * 根因一(2026-09-12 复评实弹):旧收集循环只认趋势指示组,俄区报文「NOSIG RMK QFE749」把 RMK 段\n * 整段吞进 trends(RU 61/65、KZ 18/18 条命中)、remarks 反而为空。\n * 根因二(2026-09-14 复评实弹):收口改「白名单补洞」后正文专属组(温露/QNH/$/WS/TX/TN/RVRNO)\n * 仍被静默吞进 trend.raw、typed 语义蒸发——RMK、Rxx/、$ 已是三次逃逸,补洞循环就此终结:\n * 判据反转为规范封闭清单,未来一切新正文分支自动获得「交回正文 + 出声」兜底。\n * 硬边界保留:RMK(含词身粘连 startsWith)与 R 组形态——R 组收口另有 trendCloseWarning 出声。 */\nconst isTrendCollectible = (t: Token, next: Token | undefined): boolean => {\n const text = t.text;\n // 段间切换与正文硬边界:下一个趋势指示组、RMK、R 组形态(Rxx/…、R/SNOCLO)一律收口\n if (TREND_KINDS.has(text) || text.startsWith(\"RMK\")) return false;\n if (/^R(\\d{2}[RLC]?\\/|\\/SNOCLO$)/.test(text)) return false;\n // 趋势专属词与天气缺测电码\n if (text === \"CAVOK\" || text === \"NSW\" || text === \"//\") return true;\n // 拖词容忍集(见 TREND_FILLER_WORDS 注:无 typed 语义,静默保真优于 unknown 噪声)\n if (TREND_FILLER_WORDS.has(text)) return true;\n // 磨损时段词(一趋势内第二/三个 AT|TL|FM ddhh——指示组已在,按拖词静默保真;\n // tgftp/归档实弹,回归锁:标准位置时段词零告警)\n if (/^(AT|TL|FM)\\d{4}$/.test(text)) return true;\n // 风(含 /////KT 缺测、VRB、P 超上限形)与风组变化组拖带(dddVddd 单独成 token)\n if (parseWindToken(t, next) !== null || /^\\d{3}V\\d{3}$/.test(text)) return true;\n // 能见度(米制 4 位/NDV/方向组/SM 族/混分数跨 token///// 缺测家族)\n if (parseVisibilityToken(t, next) !== null) return true;\n // 现在天气(VC 邻近/-+ 强度/组合词身/裸 TS;RE 近期天气不属趋势族——交回正文按 recentWeather 认组)\n if (parseWeatherBody(text) !== null) return true;\n // 云(层组/VV/晴空码)\n if (CLOUD_LAYER_PATTERN.test(text) || VV_PATTERN.test(text) || isSkyClear(text)) return true;\n return false;\n};\nconst SKY_CLEAR_CODES: readonly SkyClearCode[] = [\"SKC\", \"NSC\", \"NCD\", \"CLR\"];\nconst CLOUD_AMOUNTS: readonly CloudAmount[] = [\"FEW\", \"SCT\", \"BKN\", \"OVC\"];\nconst SPEED_UNITS: readonly WindGroup[\"speed\"][\"unit\"][] = [\"kt\", \"mps\", \"kmh\"];\n/** QNH/A 物理可信范围:世界海平面气压极值 870(台风 Tip)–1083.8 hPa(蒙古高压 Agata 1968)——\n * 上界取 1084(极值之上即物理不可能,复评实弹 Q1087 由此拦截),下界 800 留裕量;\n * A 组(inHg)按同区间镜像换算外圆整为 23.5–32.5(800 hPa ≈ 23.62、1084 ≈ 32.02)。\n * 越界 = 值不可信 → 判缺测 + value-out-of-range 告警(与 Q10054 位数超界同纪律,绝不静默留假值)。 */\nconst QNH_HPA_MIN = 800;\nconst QNH_HPA_MAX = 1084;\nconst ALT_INHG_MIN = 23.5;\nconst ALT_INHG_MAX = 32.5;\n/** 温度物理可信范围:世界极值 +56.7°C(Death Valley 1913)/ −89.2°C(Vostok 1983),\n * 取 60/−90 留裕量(与 QNH 世界极值门同款纪律)——两位数模板空间内的物理不可能值\n * (89/85 构造实弹)不可信判缺测,绝不静默留假值。 */\nconst TEMP_C_MIN = -90;\nconst TEMP_C_MAX = 60;\n/** LTG 尾随词表(FMH-1 雷电视词与方位):放电类型 IC/CG/CC/CA、位置 OHD/ALQDS/DSNT/VCNTY 与 16 方位点。\n * 实弹(tgftp 全 cycle)LTG 后的方位词此前逐个散落成 unknown remarks(ALQDS/OHD/方位词一片)。 */\nconst LTG_TAIL_VOCAB = new Set([\n \"IC\",\n \"CG\",\n \"CC\",\n \"CA\",\n \"OHD\",\n \"ALQDS\",\n \"DSNT\",\n \"VCNTY\",\n \"N\",\n \"NNE\",\n \"NE\",\n \"ENE\",\n \"E\",\n \"ESE\",\n \"SE\",\n \"SSE\",\n \"S\",\n \"SSW\",\n \"SW\",\n \"WSW\",\n \"W\",\n \"WNW\",\n \"NW\",\n \"NNW\",\n]);\n/** 变化能见度尾组形态(RMK VIS 1/2V2 / VIS 1/4V1/2):两侧为整数或分数(可带 M/P 阈值前缀)。 */\nconst VIS_V_RANGE = /^[MP]?\\d+(?:\\/\\d+)?V[MP]?\\d+(?:\\/\\d+)?$/;\n\n// —— E3 首字符位掩码(正文循环分支分流用;可达首字符推导见正文循环内注释)\nconst M_WIND = 1 << 0;\nconst M_VIS = 1 << 1;\nconst M_R = 1 << 2;\nconst M_WEATHER = 1 << 3;\nconst M_CLOUD = 1 << 4;\nconst M_VV = 1 << 5;\nconst M_SKY_CLEAR = 1 << 6;\nconst M_TEMP = 1 << 7;\nconst M_QNH = 1 << 8;\nconst M_ALTIMETER_A = 1 << 9;\nconst M_VIS_RANGE = 1 << 10;\nconst M_DOLLAR = 1 << 11;\nconst M_WS_RWY = 1 << 12;\n\n/** 首字符(charCode)→ 候选分支位掩码;0 = 无分支可达(直接落 unknown-token) */\nfunction maskOf(code: number): number {\n if (code >= 48 && code <= 57) return M_WIND | M_VIS | M_TEMP; // 0-9\n switch (code) {\n case 47: // /\n return M_WIND | M_VIS | M_WEATHER | M_CLOUD | M_TEMP;\n case 86: // V(VRB 风 / VC 天气 / VV / VIS)\n return M_WIND | M_WEATHER | M_VV | M_VIS_RANGE;\n case 77: // M(M1/4SM / MIFG / M10/)\n return M_VIS | M_WEATHER | M_TEMP;\n case 80: // P(P6SM / PL PO PY PR)\n return M_VIS | M_WEATHER;\n case 82: // R(RVRNO / R 组 / RA…)\n return M_R | M_WEATHER;\n case 81: // Q\n return M_QNH;\n case 65: // A(AUTO 词已在前置词位收口,此处仅 A 组)\n return M_ALTIMETER_A;\n case 66: // B\n case 70: // F\n return M_WEATHER | M_CLOUD;\n case 79: // O(现象/描述符无 O 首字母)\n return M_CLOUD;\n case 83: // S\n return M_WEATHER | M_CLOUD | M_SKY_CLEAR;\n case 78: // N\n case 67: // C\n return M_SKY_CLEAR;\n case 68: // D\n case 71: // G\n case 72: // H\n case 73: // I\n case 84: // T\n case 85: // U\n case 45: // -\n case 43: // +\n return M_WEATHER;\n case 36: // $\n return M_DOLLAR;\n case 87: // W(WS 风切变组)\n return M_WS_RWY;\n default:\n return 0;\n }\n}\n\nconst isPhenomenon = (s: string): s is WeatherPhenomenon => PHENOMENA.some((p) => p === s);\nconst isDescriptor = (s: string): s is WeatherDescriptor => DESCRIPTORS.some((p) => p === s);\nconst isCloudAmount = (s: string): s is CloudAmount => CLOUD_AMOUNTS.some((p) => p === s);\nconst isSkyClear = (s: string): s is SkyClearCode => SKY_CLEAR_CODES.some((p) => p === s);\nconst isSpeedUnit = (s: string): s is WindGroup[\"speed\"][\"unit\"] =>\n SPEED_UNITS.some((p) => p === s);\nconst isConvective = (s: string): s is ConvectiveType => s === \"CB\" || s === \"TCU\";\n\nfunction tokenize(raw: string): Token[] {\n const tokens: Token[] = [];\n const rx = /\\S+/g;\n let m: RegExpExecArray | null;\n while ((m = rx.exec(raw)) !== null) {\n tokens.push({ text: m[0], start: m.index, end: m.index + m[0].length });\n }\n return tokens;\n}\n\nconst spanOf = (t: Token): Span => ({ start: t.start, end: t.end });\n\n/** 云层组形态(FEW023CB / /////01CB/// 缺测位形态)——正文循环与趋势段结构化共用一份正则防漂移 */\nconst CLOUD_LAYER_PATTERN = /^(FEW|SCT|BKN|OVC|\\/\\/\\/)(\\d{3}|\\/\\/\\/)(CB|TCU)?(\\/\\/\\/)?$/;\n/** VV 组形态(VV / VV/// / VV002)——同上共用 */\nconst VV_PATTERN = /^VV(\\/\\/\\/|\\d{3})?$/;\n\n/**\n * 趋势段内要素结构化(WMO 306 FM15 §15.14.2:风/能见度/天气/云四族 + 趋势专属 NSW(§15.14.13)与 CAVOK(§15.10)顶替)。\n * best-effort 且静默:认不出的组不产生任何告警(告警面受语料快照锁保护),原文在 raw 保真;\n * 正文循环同款的 token 级解析函数直接复用(parseWindToken/parseVisibilityToken/parseWeatherBody),\n * 组形正则取共享常量。返回 undefined = 没有任何组被识别(如裸 NOSIG)。\n */\nfunction structureTrendElements(\n tokens: readonly Token[],\n start: number,\n): TrendElements | undefined {\n let wind: WindGroup | undefined;\n let visibility: VisibilityGroup | undefined;\n let cavok: TrendElements[\"cavok\"];\n let nsw: TrendElements[\"nsw\"];\n const weather: WeatherGroup[] = [];\n let clouds: CloudCondition | undefined;\n let k = start;\n while (k < tokens.length) {\n const t = tokens[k];\n if (t === undefined) break;\n const next = tokens[k + 1];\n if (t.text === \"CAVOK\") {\n cavok = { span: spanOf(t) };\n k += 1;\n continue;\n }\n if (t.text === \"NSW\") {\n nsw = { span: spanOf(t) };\n k += 1;\n continue;\n }\n if (wind === undefined) {\n const w = parseWindToken(t, next);\n if (w !== null && w !== \"missing\") {\n wind = w.group;\n k += w.consumed;\n continue;\n }\n }\n if (visibility === undefined) {\n const vis = parseVisibilityToken(t, next);\n if (vis !== null && vis.kind === \"ok\") {\n visibility = vis.group;\n k += vis.consumed;\n continue;\n }\n }\n const wx = parseWeatherBody(t.text);\n if (wx !== null) {\n // 内部信号(outOfOrder/signWithVc)不进 IR;趋势段 tolerant 静默收下\n const { outOfOrder: _outOfOrder, signWithVc: _signWithVc, ...group } = wx;\n weather.push({ ...group, span: spanOf(t) });\n k += 1;\n continue;\n }\n const cloudM = CLOUD_LAYER_PATTERN.exec(t.text);\n if (cloudM !== null) {\n const amountRaw = cloudM[1];\n const heightRaw = cloudM[2];\n const convectiveRaw = cloudM[3];\n clouds = {\n elements: [\n ...(clouds?.elements ?? []),\n {\n kind: \"layer\",\n amount: amountRaw !== undefined && isCloudAmount(amountRaw) ? amountRaw : null,\n heightFt: {\n value:\n heightRaw !== undefined && heightRaw !== \"///\"\n ? Number.parseInt(heightRaw, 10) * 100\n : null,\n span: spanOf(t),\n },\n convective:\n convectiveRaw !== undefined && isConvective(convectiveRaw)\n ? convectiveRaw\n : undefined,\n span: spanOf(t),\n },\n ],\n ...(clouds?.clear !== undefined ? { clear: clouds.clear } : {}),\n };\n k += 1;\n continue;\n }\n const vvM = VV_PATTERN.exec(t.text);\n if (vvM !== null) {\n const heightRaw = vvM[1];\n clouds = {\n elements: [\n ...(clouds?.elements ?? []),\n {\n kind: \"vertical-visibility\",\n heightFt: {\n value:\n heightRaw === undefined || heightRaw === \"///\"\n ? null\n : Number.parseInt(heightRaw, 10) * 100,\n span: spanOf(t),\n },\n span: spanOf(t),\n },\n ],\n ...(clouds?.clear !== undefined ? { clear: clouds.clear } : {}),\n };\n k += 1;\n continue;\n }\n if (isSkyClear(t.text)) {\n clouds = { elements: clouds?.elements ?? [], clear: { code: t.text, span: spanOf(t) } };\n k += 1;\n continue;\n }\n k += 1; // 认不出的组:原文保真、静默跳过(tolerant 纪律,绝不静默丢原文)\n }\n if (\n wind === undefined &&\n visibility === undefined &&\n cavok === undefined &&\n nsw === undefined &&\n weather.length === 0 &&\n clouds === undefined\n )\n return undefined;\n return {\n ...(wind !== undefined ? { wind } : {}),\n ...(visibility !== undefined ? { visibility } : {}),\n ...(cavok !== undefined ? { cavok } : {}),\n weather,\n ...(nsw !== undefined ? { nsw } : {}),\n ...(clouds !== undefined ? { clouds } : {}),\n };\n}\n\nfunction joinSpan(tokens: readonly Token[]): Span {\n const first = tokens[0];\n const last = tokens[tokens.length - 1];\n if (first === undefined || last === undefined) return { start: 0, end: 0 };\n return { start: first.start, end: last.end };\n}\n\n/**\n * 紧凑模式出口剥除(E1)v2——重建式:遍历构造全新对象(不含 span/cavokSpan 键),零 mutation。\n * 设计权衡(实测驱动,两版对比):\n * - 构造期逐点跳过 span 的方案在 full 模式引入 ~20% 退化(分支插入组构造热路径),否决;\n * - 旧版出口就地删键(Reflect.deleteProperty)让 V8 把产物退化为 dictionary mode(慢属性):\n * 实测紧凑吞吐仅全模式 ~32%(23 万 vs 72 万行/秒)、存活对象驻留反升 ~2.2×——此为本版根因修复对象;\n * - 重建式出口一次遍历:full 模式与旧版逐字节同路径(零开销),紧凑产物保持 fast properties\n * (隐藏类不丢),实测吞吐回到全模式 ~55% 量级(40.6 万 vs 72.8 万行/秒,旧版仅 32%)、\n * 驻留与全模式持平(1.01×,旧版反升 2.21×——数字见 E 批性能冒烟锁注释)。\n * 数组重建新数组、原语透传;对象均为本次 parse 新建(无共享引用),键序保持原插入序(JSON 面稳定)。\n */\nfunction compactNode<T>(node: T): T {\n if (Array.isArray(node)) {\n const out: unknown[] = [];\n for (const item of node) out.push(compactNode(item));\n // 重建副本与原值同构(仅少 span 键)——与 structuredClone 同款「unknown → T」定型需求,断言无法避免\n // oxlint-disable-next-line no-unsafe-type-assertion\n return out as T;\n }\n if (node === null || typeof node !== \"object\") return node;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node)) {\n if (key === \"span\" || key === \"cavokSpan\") continue; // 剥除目标键:不进新对象(而非删除)\n out[key] = compactNode(value);\n }\n // 同上:键值逐项来自原对象(仅滤除 span),与 T 同构\n // oxlint-disable-next-line no-unsafe-type-assertion\n return out as T;\n}\n\n/** 天气组合词切分:把「TSRA」拆成描述符 TS + 现象 RA;无法合法切分返回 null。\n * outOfOrder = 能完整切解但语序不合电码表(描述符出现在现象之后,如 RATS=RA+TS)——\n * tolerant 纪律下仍按切解结果收下,由调用方追加 invalid-format 告警。\n * bare = 描述符单独编报(无现象)——TS 恒合法;SH 仅在 VC 邻近语境内合法(VCSH,\n * WMO 306 表 4678 注:机场附近有阵性降水但降水类型不可辨),由 parseWeatherBody 收口。 */\nfunction splitWeatherToken(body: string): {\n descriptor?: WeatherDescriptor;\n phenomena: readonly WeatherPhenomenon[];\n outOfOrder: boolean;\n bare: boolean;\n} | null {\n const chunks: string[] = [];\n for (let i = 0; i < body.length; i += 2) chunks.push(body.slice(i, i + 2));\n if (chunks.some((c) => c.length !== 2)) return null;\n const phenomena: WeatherPhenomenon[] = [];\n let descriptor: WeatherDescriptor | undefined;\n let sawPhenomenon = false;\n let outOfOrder = false;\n for (const c of chunks) {\n if (isPhenomenon(c)) {\n phenomena.push(c);\n sawPhenomenon = true;\n } else if (isDescriptor(c) && descriptor === undefined) {\n descriptor = c;\n if (sawPhenomenon) outOfOrder = true; // 电码表语序:描述符须先于现象\n } else return null;\n }\n if (phenomena.length === 0 && descriptor !== \"TS\" && descriptor !== \"SH\") return null; // TS/SH 单独编报见 bare 注\n return { descriptor, phenomena, outOfOrder, bare: phenomena.length === 0 };\n}\n\n/** 天气组词身解析:VC 邻近 / -+ 强度 / 双字母组合切分。返回 null 表示不是合法天气组。\n * signWithVc = 强度符与 VC 并存(-VCTSRA 家族,NWS 自动站实弹):4678 限定槽四选一\n * (light −/moderate 无符/heavy +/vicinity VC)、FAA AIM 明文互斥——tolerant 纪律下按切解\n * 收下(强度+邻近+现象语义可无损恢复,与 RATS→outOfOrder 容忍同构),由调用方出声。 */\nfunction parseWeatherBody(text: string): {\n intensity?: \"-\" | \"+\";\n proximity: boolean;\n descriptor?: WeatherDescriptor;\n phenomena: readonly WeatherPhenomenon[];\n outOfOrder: boolean;\n signWithVc: boolean;\n} | null {\n let rest = text;\n let proximity = false;\n let signWithVc = false;\n if (rest.startsWith(\"VC\")) {\n proximity = true;\n rest = rest.slice(2);\n }\n let intensity: \"-\" | \"+\" | undefined;\n const sign = rest.slice(0, 1);\n if (sign === \"-\" || sign === \"+\") {\n intensity = sign;\n rest = rest.slice(1);\n // 强度符后随 VC(-VCTSRA / -VCSH):非规范词序(规范语序 VC 在最前、强度符与 VC 互斥)\n if (rest.startsWith(\"VC\")) {\n proximity = true;\n signWithVc = true;\n rest = rest.slice(2);\n }\n }\n if (rest.length < 2 || rest.length % 2 !== 0) return null;\n const split = splitWeatherToken(rest);\n if (split === null) return null;\n // 裸 SH(无现象)仅在 VC 邻近形态合法(VCSH);非 VC 的裸 SH 是坏组不收\n if (split.bare && split.descriptor === \"SH\" && !proximity) return null;\n return {\n intensity,\n proximity,\n descriptor: split.descriptor,\n phenomena: split.phenomena,\n outOfOrder: split.outOfOrder,\n signWithVc,\n };\n}\n\n/**\n * 解析天气组 token(含 RE 前缀 / VC 邻近 / -+ 强度)。\n * 返回 kind「current」仅当组进入当前天气列表;「recent」= RE 近期天气(另一组位,不参与 weather 三态);\n * outOfOrder = 词身能切解但语序不合电码表;false = 不是天气组。\n */\n/** 强度符适用面(WMO 306 表 4678 注 4):降水全族可带 -/+;+SS/+FC/+DS 为 4678 表内合法电码\n * (codes.wmo.int/306/4678 稳定概念:+DS heavy duststorm、+SS heavy sandstorm、+FC 发展完好\n * 漏斗云;加拿大差异版另有官方能见度判据 <5/16 SM)——表内形态照常收下、零告警;\n * FMH-1 仅对降水族定义强度测定(美国实务不产 +DS),出处为 4678 电码表本身而非 FMH-1 容错。\n * (2026-09-14 口径归位:旧注释称「+DS 由调用方出声」与实现不符——它本就是表内电码。) */\nconst PRECIP_PHENOMENA = new Set<WeatherPhenomenon>([\n \"RA\",\n \"SN\",\n \"SG\",\n \"IC\",\n \"PL\",\n \"GR\",\n \"GS\",\n \"UP\",\n]);\nfunction intensityAllowedFor(\n intensity: \"-\" | \"+\",\n phenomena: readonly WeatherPhenomenon[],\n): boolean {\n if (phenomena.length > 0 && phenomena.every((x) => PRECIP_PHENOMENA.has(x))) return true;\n return intensity === \"+\" && phenomena.every((x) => x === \"SS\" || x === \"FC\" || x === \"DS\");\n}\n\nfunction tryWeatherToken(\n t: Token,\n weather: WeatherGroup[],\n recent: WeatherGroup[],\n):\n | {\n kind: \"current\" | \"recent\";\n outOfOrder: boolean;\n signWithVc: boolean;\n intensityMisuse?: boolean;\n }\n | false {\n const current = parseWeatherBody(t.text);\n if (current !== null) {\n const { outOfOrder, signWithVc, ...group } = current;\n weather.push({ ...group, span: spanOf(t) });\n return {\n kind: \"current\",\n outOfOrder,\n signWithVc,\n ...(current.intensity !== undefined &&\n !intensityAllowedFor(current.intensity, current.phenomena)\n ? { intensityMisuse: true }\n : {}),\n };\n }\n // RE 前缀(近期天气,15.13.2):REFC = RE + FC;RE 组不带强度符(15.13.2.1)\n if (t.text.startsWith(\"RE\")) {\n const recentBody = parseWeatherBody(t.text.slice(2));\n if (recentBody !== null) {\n const { outOfOrder, signWithVc: _signWithVc, ...group } = recentBody;\n recent.push({ ...group, span: spanOf(t) });\n return {\n kind: \"recent\",\n outOfOrder,\n signWithVc: false,\n ...(recentBody.intensity !== undefined ? { intensityMisuse: true } : {}),\n };\n }\n }\n return false;\n}\n\n/** 能见度解析结果三路:ok=有值;missing=显式缺测电码(//// 家族);\n * invalid=形态合法但值不可信(零分母 1/0SM——解码出 Infinity/NaN 的唯一入口),\n * 由调用方落 missing + value-out-of-range 告警(与 QNH 超界同款纪律,绝不留假值)。 */\ntype VisibilityResult =\n | { readonly kind: \"ok\"; readonly group: VisibilityGroup; readonly consumed: number }\n | {\n readonly kind: \"directional\";\n readonly group: { readonly value: number; readonly direction: string; readonly span: Span };\n readonly consumed: number;\n }\n | { readonly kind: \"missing\"; readonly consumed: number }\n | {\n readonly kind: \"invalid\";\n readonly message: string;\n readonly span: Span;\n readonly consumed: number;\n };\n\n/** 能见度:米制 4 位(可带 NDV 后缀)/ 美制 SM(含混分数跨 token 的预合并、P6SM 超上限)/ //// 缺测家族。 */\nfunction parseVisibilityToken(t: Token, next: Token | undefined): VisibilityResult | null {\n // 缺测家族两形态(与单位正交)://// = 米制缺测;////SM = 英里制缺测(加拿大自动站,\n // RMK VIS MISG 佐证)——同为 visibility missing + missing-expected 告警(单位不进 missing 态)\n if (t.text === \"////\" || t.text === \"////SM\") return { kind: \"missing\", consumed: 1 };\n // NDV = No Directional Variation(无方向变化,加拿大自动站惯例后缀)——\n // 语义为「能见度各方向一致」,IR 无落点:剥离丢弃(原码经组 span 回溯),按 4 位主体正常解析\n // 最低能见度方向组(VNVNVNVNDv,如 1200NW)——须在 m4 之前判(带 1–2 位方位后缀)\n const mDir = /^(\\d{4})(NE|NW|SE|SW|N|E|S|W)$/.exec(t.text);\n if (mDir !== null) {\n return {\n kind: \"directional\",\n group: {\n value: Number.parseInt(mDir[1] ?? \"0\", 10),\n direction: mDir[2] ?? \"\",\n span: spanOf(t),\n },\n consumed: 1,\n };\n }\n const m4 = /^(\\d{4})(NDV)?$/.exec(t.text);\n if (m4 !== null) {\n const digits = m4[1] ?? \"\";\n const ceiling = digits === \"9999\";\n // 0000 = 下限编码(<100m,与 9999 上限编码同族)——非实测 0 米,exact=false + beyond below\n const floor = digits === \"0000\";\n return {\n kind: \"ok\",\n group: {\n value: Number.parseInt(digits, 10),\n unit: \"m\",\n exact: !ceiling && !floor,\n ...(ceiling ? { beyond: \"above\" as const } : {}), // 9999 = 10km 或以上(上限编码)\n ...(floor ? { beyond: \"below\" as const } : {}), // 0000 = 不足下限(下限编码)\n span: spanOf(t),\n },\n consumed: 1,\n };\n }\n // 混分数跨 token:`1 1/4SM`(裸整数 + 带分数 SM 是一个组)\n if (/^\\d$/.test(t.text) && next !== undefined && /^\\d\\/\\d+SM$/.test(next.text)) {\n const whole = Number.parseInt(t.text, 10);\n const parts = next.text.slice(0, -2).split(\"/\");\n const num = parts[0];\n const den = parts[1];\n if (num === undefined || den === undefined) return null;\n if (Number(den) === 0) {\n // 零分母(1 0/0SM):解码结果 Infinity/NaN——值不可信判缺测(span 覆盖整数与分数两个 token)\n return {\n kind: \"invalid\",\n message: `能见度混分数分母为零(${t.text} ${next.text})——解码不出有限值,值不可信判缺测,原码经 span 回溯`,\n span: { start: t.start, end: next.end },\n consumed: 2,\n };\n }\n return {\n kind: \"ok\",\n group: {\n value: whole + Number(num) / Number(den),\n unit: \"sm\",\n exact: true,\n span: { start: t.start, end: next.end },\n },\n consumed: 2,\n };\n }\n const sm = /^(M|P)?(\\d+)\\/(\\d+)SM$|^(M|P)?(\\d+)SM$/.exec(t.text);\n if (sm !== null) {\n const prefix = sm[1] ?? sm[4];\n const below = prefix === \"M\";\n const above = prefix === \"P\"; // P6SM:6 英里以上(美式超上限,FAA/AF 口径)——exact=false,与 9999 同族\n const den = sm[3];\n if (den !== undefined && Number(den) === 0) {\n // 单 token 零分母(1/0SM、0/0SM、M1/0SM——0/0 解码出 NaN,同属值不可信)\n return {\n kind: \"invalid\",\n message: `能见度分数分母为零(${t.text})——解码不出有限值,值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n consumed: 1,\n };\n }\n const value =\n sm[2] !== undefined ? Number(sm[2]) / Number(den) : Number.parseInt(sm[5] ?? \"0\", 10);\n // exact 语义统一:分数(1/2SM、1 1/4SM)与整数本身是精确值;\n // 阈值性编码(M 前缀小于下界、P 前缀大于上界、9999 上限)为 false,beyond 记方向\n return {\n kind: \"ok\",\n group: {\n value,\n unit: \"sm\",\n exact: !below && !above,\n ...(below ? { beyond: \"below\" as const } : {}),\n ...(above ? { beyond: \"above\" as const } : {}),\n span: spanOf(t),\n },\n consumed: 1,\n };\n }\n return null;\n}\n\ninterface WindParsed {\n group: WindGroup;\n consumed: number;\n /** 越界发现(风向位/变化组端点 >360°):子项判缺测,由调用方落 value-out-of-range 告警 */\n rangeFindings: readonly { message: string; span: Span }[];\n /** 阵风位缺测(27010G//KT):组照常成立、gust 不设,由调用方落 missing-expected info */\n gustMissing?: boolean;\n}\n\n/** 风:33002MPS / VRB02KT / 31015G25KT / /////KT 缺测形态 + 260V050 变化组。 */\nfunction parseWindToken(t: Token, next: Token | undefined): WindParsed | \"missing\" | null {\n if (/^\\/{5}(KT|MPS|KMH)$/.test(t.text)) return \"missing\";\n // 部分缺测两形态(速度位 // / 阵风位 //,如 180//KT、27010G//KT)——此前整体落 unknown。\n // 超上限 P 前缀(P99KT/P49MPS,WMO 15.5.6 / AP-117 54 条):值存原码、beyond 标注超界端\n const m =\n /^(VRB|\\d{3}|\\/\\/\\/)(\\d{2,3}|P\\d{2}|\\/\\/\\/|\\/\\/)(?:G(\\d{2,3}|P\\d{2}|\\/\\/\\/|\\/\\/))?(KT|MPS|KMH)$/.exec(\n t.text,\n );\n if (m === null) return null;\n const span = spanOf(t);\n const dirRaw = m[1] ?? \"\";\n const speedRaw = m[2] ?? \"\";\n const unitRaw = (m[4] ?? \"kt\").toLowerCase();\n if (!isSpeedUnit(unitRaw)) return null;\n if (dirRaw === \"///\" || speedRaw === \"///\" || speedRaw === \"//\") return \"missing\";\n const variable = dirRaw === \"VRB\";\n const gustRaw = m[3];\n const speedBeyond = speedRaw.startsWith(\"P\") ? (\"above\" as const) : undefined;\n const gustBeyond =\n gustRaw !== undefined && gustRaw.startsWith(\"P\") ? (\"above\" as const) : undefined;\n const rangeFindings: { message: string; span: Span }[] = [];\n // 风向位 0–360(正北可编 360、静风 000 编 0):越界 = 值不可信 → 子项级判缺测(direction=null),\n // 风组其余子项(风速等)照常保留——两级建模:组内子项缺测 = 值字段 | null\n let direction: number | null = variable ? null : Number.parseInt(dirRaw, 10);\n if (!variable && direction !== null && direction > 360) {\n rangeFindings.push({\n message: `风向越界(${dirRaw},须 0–360)——风向位判缺测,原码经 span 回溯`,\n span,\n });\n direction = null;\n }\n let consumed = 1;\n let variation: WindGroup[\"variation\"];\n if (next !== undefined && /^\\d{3}V\\d{3}$/.test(next.text)) {\n const parts = next.text.split(\"V\");\n const min = parts[0];\n const max = parts[1];\n if (min !== undefined && max !== undefined) {\n const minDeg = Number.parseInt(min, 10);\n const maxDeg = Number.parseInt(max, 10);\n if (minDeg > 360 || maxDeg > 360) {\n // 变化组端点同为风向数值(0–360):任一越界即整组不可信 → 变化组判缺测(组已消费,不留假值)\n rangeFindings.push({\n message: `风向变化组端点越界(${next.text},须 0–360)——变化组判缺测,原码经 span 回溯`,\n span: spanOf(next),\n });\n } else {\n variation = { min: minDeg, max: maxDeg, span: spanOf(next) };\n }\n consumed = 2;\n }\n }\n // 阵风位缺测双形态:G 后 // (两位斜杠——2 字符场的逐字符惯例)与 /// (三斜杠磨损多一位,\n // 同按缺测建模——任何规范都无三斜杠形态,最合理的来源是 G// 的传输磨损;2026-09-14 补建模:\n // 此前 /// 走 parseInt 产 NaN 零告警入 IR,穿透缺测路由/gustMissing/值域门三道防线)\n const gustMissing = gustRaw === \"//\" || gustRaw === \"///\";\n const group: WindGroup = {\n variable,\n direction,\n speed: {\n value: Number.parseInt(speedRaw.startsWith(\"P\") ? speedRaw.slice(1) : speedRaw, 10),\n unit: unitRaw,\n span,\n ...(speedBeyond !== undefined ? { beyond: speedBeyond } : {}),\n },\n gust:\n gustRaw !== undefined && !gustMissing\n ? {\n value: Number.parseInt(gustRaw.startsWith(\"P\") ? gustRaw.slice(1) : gustRaw, 10),\n unit: unitRaw,\n span,\n ...(gustBeyond !== undefined ? { beyond: gustBeyond } : {}),\n }\n : undefined,\n variation,\n };\n return { group, consumed, rangeFindings, ...(gustMissing ? { gustMissing: true } : {}) };\n}\n\n/**\n * Temperature/dewpoint group shape: always dd/dd (M = negative; // on either side = that side missing).\n * 温度/露点组形态:恒为 dd/dd(M = 负;任一侧 // = 该侧缺测)——两位是形态定义本身,不是惯例:\n * WMO 电码表每个符号字母严格对应一位数字(T' 十位 / T 个位,负值加 M),官方示例含补零(01/M12、\n * 00/M00),任何规范版本无一位数形态。两侧 \\d{1,2} 曾让裸分数 token(VIS 词丢失的 1/2、2/1——\n * 上游脏输入)被误判为温露组:降序分数捏造假值且完全静默,升序触发误导性温露倒挂告警\n * (2026-09-14 复评收紧);不匹配即落 unknown-token 出声,原码经 span 回溯。\n * The regex requires the `/` separator — a bare \"//\" is the weather missing group (see the body loop) and must not be swallowed here.\n * 正则必须有 `/` 分隔——裸 `//` 是天气缺测组(见正文循环),不得被本组吞掉。\n * Exported for direct shape assertions in regression tests (red line: \"//\" must not match; \"1/2\"/\"2/1\" must not match either).\n * 导出供回归测试直接对形态断言(红线:对 \"//\" 与裸分数均不得匹配)。\n */\nexport const TEMP_DEW_PATTERN = /^(M?\\d{2}|\\/\\/)\\/(M?\\d{2}|\\/\\/)$/;\n\n/** 温度/露点组:恒为 dd/dd 形态(M = 负;// = 缺测 → null,调用方补告警)。 */\nfunction parseTempDewToken(t: Token): {\n temperature: TemperatureReading | null;\n dewpoint: TemperatureReading | null;\n span: Span;\n} | null {\n const read = (raw: string | undefined): TemperatureReading | null => {\n // undefined = 第二组整体缺失(FMH-1 12.6.10 露点缺测形态 24/);\"//\" = 显式缺测——\n // 两者同为 null,但 missing-expected 文案由调用方按形态区分\n if (raw === undefined || raw === \"//\") return null;\n const n = raw.startsWith(\"M\") ? -Number.parseInt(raw.slice(1), 10) : Number.parseInt(raw, 10);\n // −0 归一(M00 → 0):负零序列化变形(JSON 出 -0),消费方 Object.is 判别出边角差异\n const celsius = n === 0 ? 0 : n;\n return { celsius, span: spanOf(t) };\n };\n const m = TEMP_DEW_PATTERN.exec(t.text);\n if (m === null) {\n // FMH-1 12.6.10 露点缺测形态「24/」(第二组整体省略,同恒两位)——裸 // 与 /// 仍不得匹配\n const trailing = /^(M?\\d{2})\\/$/.exec(t.text);\n if (trailing === null) return null;\n return { temperature: read(trailing[1]), dewpoint: null, span: spanOf(t) };\n }\n return { temperature: read(m[1]), dewpoint: read(m[2]), span: spanOf(t) };\n}\n\nfunction beyondRangeOf(flag: string | undefined): \"above\" | \"below\" | undefined {\n if (flag === \"P\") return \"above\";\n if (flag === \"M\") return \"below\";\n return undefined;\n}\n\n/** RVR 组:R07R/1800V2200FT / R36/0500V0800D / P·M 超界 / 斜杠趋势(R13/3500FT/N、R07/P6000FT/U)。\n * R/SNOCLO 与 R10L/SNOCLO 属跑道状态语义(15.13.6.1),由 parseRunwayStateToken 收口。 */\nfunction parseRvrToken(t: Token): RunwayVisualRange | null {\n // 趋势后缀双形态:无斜杠(0500V0800D,WMO)与斜杠(3500FT/N,FAA/加式——FT 单位标记后带 /D //N //U)\n const m = /^R(\\d{2}[RLC]?)\\/(P|M)?(\\d{4})(?:V(P|M)?(\\d{4}))?(FT)?(?:\\/([DNU])|([DNU]))?$/.exec(\n t.text,\n );\n if (m === null) return null;\n const minRaw = m[3] ?? \"0\";\n const maxRaw = m[5];\n const trendRaw = m[7] ?? m[8];\n return {\n runway: m[1] ?? \"\",\n value: maxRaw === undefined ? Number.parseInt(minRaw, 10) : undefined,\n min: maxRaw !== undefined ? Number.parseInt(minRaw, 10) : undefined,\n max: maxRaw !== undefined ? Number.parseInt(maxRaw, 10) : undefined,\n beyondRange: beyondRangeOf(m[2] ?? m[4]),\n unit: m[6] === \"FT\" ? \"ft\" : \"m\",\n trend:\n trendRaw === \"U\"\n ? \"up\"\n : trendRaw === \"D\"\n ? \"down\"\n : trendRaw === \"N\"\n ? \"no-change\"\n : undefined,\n span: spanOf(t),\n };\n}\n\n/** 摩擦两位电码(15.13.6.1 表 0366)解码:01–90 → 摩擦系数 0.01–0.90;91–95 → 制动作用五档;\n * 99 → unreliable;// 或 96–98(电码表未用)→ 两字段皆 undefined(原码经 span 回溯)。 */\nfunction parseFrictionCode(\n code: string | undefined,\n): Pick<RunwayStateGroup, \"frictionCoefficient\" | \"brakingAction\"> {\n if (code === undefined || !/^\\d{2}$/.test(code)) return {};\n const f = Number.parseInt(code, 10);\n if (f <= 90) return { frictionCoefficient: f / 100 };\n if (f >= 91 && f <= 95)\n return {\n brakingAction: ([\"poor\", \"medium-poor\", \"medium\", \"medium-good\", \"good\"] as const)[f - 91],\n };\n if (f === 99) return { brakingAction: \"unreliable\" };\n return {};\n}\n\n/** 跑道状态组三形态(WMO 15.13.6):①六位状态电码(R21/490160:沉积/覆盖/深度/摩擦,位缺测 /);\n * ②CLRD 清除家族(R07L/CLRD// 标准、CLRD62 俄区、CLRD/// 非标容忍);③SNOCLO 关闭(R/SNOCLO 全机场、R10L/SNOCLO 逐跑道)。\n * 覆盖位非法电码(表 0519 外数字)不静默留值:该位判缺测 + findings 交调用方落 invalid-format 告警。 */\nfunction parseRunwayStateToken(\n t: Token,\n): { group: RunwayStateGroup; findings: readonly { message: string; span: Span }[] } | null {\n // ③ SNOCLO(15.13.6.1):跑道因雪/冰/清雪不可用\n const snoclo = /^R(\\d{2}[RLC]?)?\\/SNOCLO$/.exec(t.text);\n if (snoclo !== null) {\n return {\n group: { runway: snoclo[1] ?? \"\", closed: true, cleared: false, span: spanOf(t) },\n findings: [],\n };\n }\n // ② CLRD 家族\n const clrd = /^R(\\d{2}[RLC]?)\\/CLRD(\\d{2}|\\/\\/|\\/\\/\\/)?$/.exec(t.text);\n if (clrd !== null) {\n return {\n group: {\n runway: clrd[1] ?? \"\",\n cleared: true,\n ...parseFrictionCode(clrd[2]),\n span: spanOf(t),\n },\n findings: [],\n };\n }\n // ① 六位状态电码:沉积物类型 1 位 + 覆盖范围 1 位 + 深度 2 位 + 摩擦 2 位(各可 / 缺报)\n const num = /^R(\\d{2}[RLC]?)\\/(\\d|\\/)(\\d|\\/)(\\d{2}|\\/\\/)(\\d{2}|\\/\\/)$/.exec(t.text);\n if (num === null) return null;\n const depthCode = num[4] ?? \"\";\n // 深度解码(15.13.6.1 表 1079):00–90 = 毫米(00 即 <1mm 记 0);91 未用判缺测;92–98 = 10–40cm 段记下限;\n // 99 = 跑道不可用(同 SNOCLO 语义 → closed,深度不落值)\n const depthNum = /^\\d{2}$/.test(depthCode) ? Number.parseInt(depthCode, 10) : null;\n const depth =\n depthNum === null\n ? null\n : depthNum <= 90\n ? depthNum\n : depthNum === 91\n ? null\n : depthNum === 99\n ? null\n : (depthNum - 90) * 50;\n // 覆盖位电码合法性(15.13.6.1 表 0519):表内仅 1/2/5/9 与 /——表外数字(0/3/4/6/7/8)为非法电码,\n // 按三态纪律判缺测(null)+ invalid-format 告警,绝不把表外值留在 IR(tgftp 实弹 R24/000062 命中位 2 的 0)\n const coverageCode = num[3] ?? \"/\";\n const coverageIllegal = coverageCode !== \"/\" && !\"1259\".includes(coverageCode);\n const findings: { message: string; span: Span }[] = coverageIllegal\n ? [\n {\n message: `跑道状态覆盖位电码非法(${t.text} 覆盖位 ${coverageCode}——WMO 表 0519 仅用 1/2/5/9 与 /)——该位判缺测,原码经 span 回溯`,\n span: spanOf(t),\n },\n ]\n : [];\n return {\n group: {\n runway: num[1] ?? \"\",\n closed: depthNum === 99 || undefined,\n cleared: false,\n deposit: num[2] === \"/\" ? null : Number(num[2]),\n coverage: coverageCode === \"/\" || coverageIllegal ? null : Number(coverageCode),\n depth,\n ...parseFrictionCode(num[5]),\n span: spanOf(t),\n },\n findings,\n };\n}\n\n// ---------------------------------------------------------------- 主入口\n\n/**\n * Parse one METAR/SPECI report (tolerant mode) into the IR — the package's single entry.\n * 解析单条 METAR/SPECI 报文(tolerant)为 IR——本包唯一入口。\n *\n * Throws MetarParseError (stable machine-readable `code`) on whole-report failure\n * (non-string input / missing station / missing time / invalid time / unsupported mode); anything the\n * parser does not recognize lands in `warnings[]` with its span — never dropped.\n * 整体失败(输入非字符串/无站名/无时组/时组越界/未实现模式)抛 MetarParseError(code 稳定契约);\n * 看不懂的组带 span 进 warnings[],绝不丢弃。\n * @param raw - Report text, verbatim (kept on report.raw). 报文原文(原样保真于 report.raw)。\n * @param options - See ParseOptions (kind override, compact spans). 见 ParseOptions(类型位注入、紧凑模式)。\n */\nexport function parse(raw: string, options?: ParseOptions): MetarReport {\n // 紧凑模式(E1):spans === false 时在出口以重建式剥除全部 span(见 compactNode 注释)\n const compact = options?.spans === false;\n const compactIfEnabled = <T>(report: T): T => (compact ? compactNode(report) : report);\n // 输入校验:非字符串走 MetarParseError 稳定契约(code: \"invalid-input\")——code 是\n // 消费方分流的稳定面、EN_MESSAGES 查表英化的键,裸 Error 会同时绕过两者(此前为裸 Error)\n if (typeof raw !== \"string\") {\n throw new MetarParseError(\n \"invalid-input\",\n String(raw),\n `parse 需要一个 METAR/SPECI 报文字符串,收到 ${raw === null ? \"null\" : typeof raw}`,\n );\n }\n if ((options?.mode ?? \"tolerant\") === \"strict\") {\n // 错误面契约:strict 留在类型上(路线图项),但 v0.1 未实现——调用方 catch 不漏接裸 Error\n throw new MetarParseError(\n \"unsupported-mode\",\n raw,\n \"strict 模式尚未实现(v0.1 仅 tolerant)——请省略 mode 或显式传 'tolerant'\",\n );\n }\n const warnings: ParseWarning[] = [];\n // 报尾 = 终结符剥离(GTS/AFTN 通路报文行以 = 定界,常粘连末组如 Q1006= / NOSIG=)——\n // 仅剥尾部空白与 =,正文 token 偏移不变,span 仍对应原 raw(raw 保真含 =)。\n // 末字符预判(E2 性能项):语料大头无报尾,尾字符既非 = 也非空白时跳过整串正则——\n // 预判用单字符 \\s 测试(与 [\\s=] 字符类完全同域,行为等价),省一次全文回溯扫描\n const tail = raw.at(-1);\n const body =\n tail === undefined || tail === \"=\" || /\\s/.test(tail) ? raw.replace(/[\\s=]+$/, \"\") : raw;\n const tokens = tokenize(body);\n // 输入规模护栏(只告警不截断——截断破坏 raw 保真与「不丢弃」纪律):语料单行最大 30 token,\n // 上限 128 = 4 倍余量;超限报文照常完整解析,仅以一条聚合告警标记异常输入\n //(span 缺省 = 报文级;整体失败路径不经过此处,失败契约不受影响)\n const TOKEN_COUNT_LIMIT = 128;\n if (tokens.length > TOKEN_COUNT_LIMIT) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `输入 token 数超上限(${tokens.length} > ${TOKEN_COUNT_LIMIT})——按异常输入标记,解析照常完整,原文经 raw 保真`,\n });\n }\n let i = 0;\n const peek = (ahead = 0): Token | undefined => tokens[i + ahead];\n\n const externalKind = options?.kind;\n let kind: ReportKind = externalKind ?? \"metar\";\n let corrected = false;\n let auto = false;\n\n // —— 头部:类型词 / COR(WMO 形态)/ 站名 / 时组 / AUTO / COR(美式时组后形态)\n const head = peek();\n if (head !== undefined && (head.text === \"METAR\" || head.text === \"SPECI\")) {\n if (externalKind === undefined) kind = head.text === \"SPECI\" ? \"speci\" : \"metar\";\n i += 1; // 类型词 token 无论由谁决定 kind 都要消费\n }\n if (peek()?.text === \"COR\") {\n corrected = true;\n i += 1;\n }\n // AMD(修订发布标志,部分 CAA 用于 METAR 标题位,TAF 更常见):标题元数据词,\n // 语义为「本报告取代此前发布」——消费之不进站名位;是否置 corrected 不越权代判\n //(修订 ≠ 更正),IR 无 amended 位故仅放行不标注\n if (peek()?.text === \"AMD\") {\n i += 1;\n }\n const stTok = peek();\n if (stTok === undefined || !/^[A-Z0-9]{4}$/.test(stTok.text)) {\n // 契约:无站名组 = 整体解析失败(不是字段级三态);code 是稳定契约,message 中文为权威\n // 文案——英文经 @metweave/core EN_MESSAGES[code] 查表或渲染层 locale:\"en\" 切换\n throw new MetarParseError(\n \"missing-station\",\n raw,\n `无法识别站名组——输入不是 METAR/SPECI 报文(${stTok?.text ?? \"空输入\"})`,\n );\n }\n const station: string = stTok.text;\n i += 1;\n // CCA/CCB/CCC 与 COR 槽位磨损兜底(站名后/时组前——规范槽位:BBB 系列在时组后(见下方\n // BBB 消费位)、COR 在类型词位(见报头 COR 位)):部分 feed 的更正标记出现在此槽——此前\n // 直接 throw missing-time,「合法更正报整体失败」是最恶性失败模式。后随 token 为合法时组时\n // 消费放行并置 corrected + 出声(槽位漂移本身须可观测——不静默,2026-09-14 独立复评补\n // COR 对称缺口与出声);后随非时组则照旧走 missing-time。已知留案:标记若出现在 AUTO\n // 之前的其他相对序(如 CCA AUTO),AUTO 会落正文 unknown——语料无实证,暂不设防\n const driftTok = peek();\n if (driftTok !== undefined && /^(CC[A-Z]|COR)$/.test(driftTok.text)) {\n const afterDrift = peek(1);\n if (afterDrift !== undefined && /^\\d{2}\\d{2}\\d{2}Z$/.test(afterDrift.text)) {\n corrected = true;\n i += 1;\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `更正标记槽位漂移(${driftTok.text} 出现在站名后/时组前——已消费并置更正标志)`,\n span: spanOf(driftTok),\n });\n }\n }\n const tmTok = peek();\n const tm = tmTok !== undefined ? /^(\\d{2})(\\d{2})(\\d{2})Z$/.exec(tmTok.text) : null;\n if (tmTok === undefined || tm === null) {\n throw new MetarParseError(\n \"missing-time\",\n raw,\n `无法识别时组——输入不是完整的 METAR/SPECI 报文(${tmTok?.text ?? \"时组缺失\"})`,\n );\n }\n const time: MetarReport[\"time\"] = {\n day: Number.parseInt(tm[1] ?? \"0\", 10),\n hour: Number.parseInt(tm[2] ?? \"0\", 10),\n minute: Number.parseInt(tm[3] ?? \"0\", 10),\n };\n // 契约:时组为两态必填(无缺测形态,无 Observed)——数值越界即不可信时组,等同无效时组整体失败,\n // 绝不把假值(日 99、时 24、分 60)留在 IR(同 Q10054 脏 QNH 的「值不可信」纪律,时组无处判缺测故整体失败)\n if (time.day < 1 || time.day > 31 || time.hour > 23 || time.minute > 59) {\n throw new MetarParseError(\n \"invalid-time\",\n raw,\n `时组数值越界(${tmTok.text}:须日 01–31 / 时 00–23 / 分 00–59)——输入不是完整的 METAR/SPECI 报文`,\n );\n }\n i += 1;\n if (peek()?.text === \"AUTO\") {\n auto = true;\n i += 1;\n }\n if (peek()?.text === \"COR\") {\n corrected = true;\n i += 1;\n }\n // RRA/RRB/RRC 迟到报标记(AP-117-TM-01R2 第 21 条:报头时间组后)——标题元数据,消费放行\n if (/^RR[ABC]$/.test(peek()?.text ?? \"\")) {\n i += 1;\n }\n // CCA/CCB/CCC 更正指示符(WMO FM15 §1.3.3 BBB 系列:第一次更正 CCA、第二次 CCB 顺延;\n // 规范槽位即本位——时组后。加拿大 NAV CANADA 明文采用,中国 AFTN 实务沿用;仓库声明的\n // 编码基准含 MANOPS-MET)。语义即更正报——与 COR 同义异位(COR 在类型词位、BBB 在时组后位),\n // 消费并置 corrected;此前落 unknown-token,更正语义丢失(2026-09-14 复评:基准内形态未实现)\n if (/^CC[A-Z]$/.test(peek()?.text ?? \"\")) {\n corrected = true;\n i += 1;\n }\n\n // —— NIL:台站无观测(FM15 代码形注 2 的 NIL 码词;§15.4 是 AUTO 条款)——最小形态:站名/时组凭据保留,正文组不解析(本就无正文),零告警\n if (peek()?.text === \"NIL\") {\n return compactIfEnabled({\n kind,\n raw,\n nil: true,\n station,\n time,\n flags: { auto, corrected },\n cavok: false,\n trends: [],\n runwayStates: [],\n remarks: [],\n warnings,\n });\n }\n\n // —— 正文状态\n let cavok = false;\n let cavokSpan: Span | undefined;\n let wind: Observed<WindGroup> | undefined;\n let visibility: Observed<VisibilityGroup> | undefined;\n // 脱离主导能见度的方向组被按主导收下的局部标记(见正文循环方向组分支注释;非 IR 字段)\n let directionalAsPrimary = false;\n let rvr: Observed<readonly RunwayVisualRange[]> | undefined;\n const rvrList: RunwayVisualRange[] = [];\n // 多组 RVR 的组级 span 首组至末组(与天气组同口径——单组 span 在各自元素上)\n let rvrSpan: Span | undefined;\n let weather: Observed<readonly WeatherGroup[]> | undefined;\n const weatherList: WeatherGroup[] = [];\n const recentList: WeatherGroup[] = [];\n let clouds: CloudCondition | undefined;\n let cloudSeen = false;\n const cloudElements: CloudElement[] = [];\n let clearCode: CloudCondition[\"clear\"];\n let temperature: TemperatureReading | undefined;\n let dewpoint: TemperatureReading | undefined;\n let altimeter: AltimeterReading | undefined;\n // 双气压组口径(tolerant 惯例):末组为准(保持既有 last-wins 行为),重复组追加 info 告警不静默\n let altimeterSeen = false;\n const setAltimeter = (reading: AltimeterReading): void => {\n if (altimeterSeen) {\n dupGroupWarning(\"气压组\", altimeter?.span, reading.span);\n }\n altimeterSeen = true;\n altimeter = reading;\n };\n const trends: TrendGroup[] = [];\n const runwayStates: RunwayStateGroup[] = [];\n const remarks: RemarkGroup[] = [];\n // 重复组口径(与双气压组同款 tolerant 惯例):末组为准(保持既有 last-wins 行为),\n // 重复组出声不静默——专用码 duplicate-group(2026-09-15 五角色评测定案:此前借用\n // cross-check-conflict+info,消费方无法按「重复」分流;severity 升 warning)。\n // 前值后值原文都进 message:last-wins 会覆盖 IR 里的前值 span,前值唯一可回溯通道就是这条告警\n const dupGroupWarning = (\n label: string,\n prevSpan: Span | undefined,\n newSpan: Span | undefined,\n ): void => {\n const prevText =\n prevSpan === undefined ? `(原${label})` : raw.slice(prevSpan.start, prevSpan.end);\n const newText = newSpan === undefined ? label : raw.slice(newSpan.start, newSpan.end);\n warnings.push({\n code: \"duplicate-group\",\n severity: \"warning\",\n message: `重复${label}(前值 ${prevText},后值 ${newText})——报文只应有一组${label},以末组为准,前值经原文回溯`,\n span: newSpan,\n });\n };\n // 趋势段收口可观测性:R 组收口(RVR/跑道状态不属趋势要素)沿用既有口径出声;\n // 其余非趋势组收口(温露/QNH/WS/TX/TN/RVRNO/无法认领 token 等——2026-09-14 收窄新增)\n // 同样出声 info:该组交回正文循环认组(typed 语义无损恢复,冲突自然触发重复组告警),\n // 但趋势语境存疑须可观测——不静默。RMK/RMK 粘连与趋势指示组切换(含粘连形\n // BECMGAT0130——它本身就是趋势指示组,下一步由正文粘连分支认领)、以及规范报尾位 $\n // (FMH-1:$ 为整报最后一组,趋势段后随 $ 属规范位置)不出声(2026-09-14 独立复评补豁免)。\n const trendCloseWarning = (): void => {\n const btTok = tokens[i];\n const bt = btTok?.text;\n if (bt === undefined || btTok === undefined) return;\n if (TREND_KINDS.has(bt) || bt.startsWith(\"RMK\") || bt === \"$\") return;\n if (/^(BECMG|TEMPO)(AT|TL|FM)\\d{4}$/.test(bt)) return; // 粘连指示组:由正文粘连分支认领\n if (/^R(\\d{2}[RLC]?\\/|\\/SNOCLO$)/.test(bt)) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `趋势段收口于 R 组(${bt}——RVR/跑道状态不属趋势要素,按正文组处理,趋势语境存疑)`,\n span: spanOf(btTok),\n });\n return;\n }\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `趋势段收口于非趋势组(${bt}——不属趋势要素族,交回正文认组,趋势语境存疑)`,\n span: spanOf(btTok),\n });\n };\n // 趋势段收组:仅封闭清单内 token 收进 collected(判据见 isTrendCollectible),其余留在\n // tokens[i] 交回正文循环——三处收集入口(指示组/粘连/裸时段词)共用一份循环防漂移\n const collectTrendTokens = (collected: Token[]): void => {\n for (;;) {\n const inner = tokens[i];\n if (inner === undefined || !isTrendCollectible(inner, tokens[i + 1])) break;\n collected.push(inner);\n i += 1;\n }\n };\n // CAVOK 三面交叉校验(能见度/天气/云)。词位时对「前序」组校验;正文循环收口后对「后续」\n // 组再校验——CAVOK 让位发生在词位,其后再出现的矛盾组此前静默并存(CAVOK BKN012 形态)。\n // 判据词位/词后完全一致:确定矛盾才告警(下界编码/真值天气/低云或对流云;缺测云高不判)。\n // 告警 span 统一指 CAVOK 词位(既有契约:矛盾双方中「主张」所在)。\n const cavokConflicts = (whenLabel: string): void => {\n const at = cavokSpan;\n if (visibility?.kind === \"value\") {\n const g = visibility.value;\n const meters = g.unit === \"m\" ? g.value : g.value * 1609.344;\n const visRaw =\n visibility.span === undefined\n ? `${g.value} ${g.unit}`\n : raw.slice(visibility.span.start, visibility.span.end);\n const definitelyBelow =\n g.beyond === \"below\" ||\n (g.unit === \"sm\" && visRaw.startsWith(\"M\")) ||\n (g.exact && meters < 10_000);\n if (definitelyBelow) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}能见度组矛盾(${visRaw},CAVOK 语义要求 ≥10km)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n }\n if (weatherList.length > 0) {\n const wxRaw = weatherList\n .map(\n (g) =>\n `${g.proximity ? \"VC\" : \"\"}${g.intensity ?? \"\"}${g.descriptor ?? \"\"}${g.phenomena.join(\"\")}`,\n )\n .join(\" \");\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}天气组矛盾(${wxRaw},CAVOK 语义要求无重要天气)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n if (rvr !== undefined && rvr.kind === \"value\") {\n const rvrRaw = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}RVR 组矛盾(${rvrRaw}——AP-117 第 140 条:CAVOK 代替能见度、跑道视程、现在天气和云)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n const cloudConflict = cloudElements.some((e) => {\n if (e.kind === \"layer\" && e.convective !== undefined) return true;\n const h = e.heightFt.value;\n return h !== null && h < 5_000;\n });\n if (cloudConflict) {\n const cloudRaw = cloudElements\n .map(\n (e) =>\n `${e.kind === \"layer\" ? (e.amount ?? \"///\") : \"VV\"}${\n e.heightFt.value === null\n ? \"///\"\n : String(Math.round(e.heightFt.value / 100)).padStart(3, \"0\")\n }${e.kind === \"layer\" ? (e.convective ?? \"\") : \"\"}`,\n )\n .join(\" \");\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}云组矛盾(${cloudRaw},CAVOK 语义要求 5000ft 以下无云且无 CB/TCU)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n };\n // 风切变组累积器(同报多组 WS 合一:runways 连接、span 首组至末组)\n let windShear: WindShearGroup | undefined;\n let wsRunways: string[] | undefined;\n let wsAll = false;\n let wsSpan: Span | undefined;\n\n // —— 正文循环(RMK 交段外处理)\n while (i < tokens.length) {\n const t = tokens[i];\n if (t === undefined) break;\n const text = t.text;\n\n if (text === \"RMK\") {\n i += 1;\n break;\n }\n // RMK 磨损粘连(RMKQFE749/0998 = RMK 与后组丢空格,fuzz 实弹 35/5 万例命中):进 RMK 段\n // 但不跳过 token 本身——由 RMK 段按认组粒度收下(多为 unknown,raw 保真不蒸发)\n if (text.startsWith(\"RMK\")) {\n break;\n }\n\n // 趋势指示组:NOSIG / BECMG / TEMPO(吞到下一个指示组、RMK 或结尾)\n if (TREND_KINDS.has(text)) {\n const kindText = text;\n const collected: Token[] = [t];\n i += 1;\n let period: TrendGroup[\"period\"];\n const periodTok = peek();\n if (\n kindText !== \"NOSIG\" &&\n periodTok !== undefined &&\n /^(AT|FM|TL)\\d{4}$/.test(periodTok.text)\n ) {\n period = { text: periodTok.text, span: spanOf(periodTok) };\n collected.push(periodTok);\n i += 1;\n }\n // 收口语义见 isTrendCollectible:仅趋势合法要素族可收,其余收口交回正文(trendCloseWarning 出声)\n collectTrendTokens(collected);\n trendCloseWarning();\n const elements =\n kindText === \"NOSIG\"\n ? undefined\n : structureTrendElements(collected, period !== undefined ? 2 : 1);\n trends.push({\n kind: kindText === \"NOSIG\" ? \"nosig\" : kindText === \"BECMG\" ? \"becmg\" : \"tempo\",\n period,\n ...(elements !== undefined ? { elements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n continue;\n }\n\n // 磨损趋势段两形态(WMO 306 FM15 §15.14.3 时段词 AT/TL/FM 不得脱离指示组):\n // ①粘连——指示组与时段词丢空格(BECMGTL0350,IEM 归档实弹 10 次):宽容拆分,语义完整可恢复;\n // ②裸时段词——指示组整组丢失(Q1009 TL0730 …,IEM 归档实弹 128 次):按 kind 'unspecified'\n // 收段(要素组不再散落正文——尤其防趋势风组以 last-wins 覆盖正文真风组),告警标注指示组不可辨。\n // NOSIG 粘连不拆(NOSIG 语义上不配时段词);标准位置的时段词已在上方指示组分支内消费,此处不重复触达。\n if (\n (text.length === 6 &&\n (text.charCodeAt(0) === 65 || text.charCodeAt(0) === 84 || text.charCodeAt(0) === 70)) ||\n text.startsWith(\"BECMG\") ||\n text.startsWith(\"TEMPO\")\n ) {\n const fused = /^(BECMG|TEMPO)(AT|TL|FM)\\d{4}$/.exec(text);\n if (fused !== null) {\n const indicator = fused[1] ?? \"\";\n const collected: Token[] = [t];\n i += 1;\n collectTrendTokens(collected);\n trendCloseWarning();\n const fusedElements = structureTrendElements(collected, 1);\n trends.push({\n kind: indicator === \"BECMG\" ? \"becmg\" : \"tempo\",\n period: {\n text: text.slice(indicator.length),\n span: { start: t.start + indicator.length, end: t.end },\n },\n ...(fusedElements !== undefined ? { elements: fusedElements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `趋势指示组与时段词粘连(${text}——传输磨损丢空格,BECMG/TEMPO 与 AT/TL/FM 时段语义完整可恢复)`,\n span: spanOf(t),\n });\n continue;\n }\n if (/^(AT|TL|FM)\\d{4}$/.test(text)) {\n const collected: Token[] = [t];\n i += 1;\n collectTrendTokens(collected);\n trendCloseWarning();\n const bareElements = structureTrendElements(collected, 1);\n trends.push({\n kind: \"unspecified\",\n period: { text, span: spanOf(t) },\n ...(bareElements !== undefined ? { elements: bareElements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `趋势时段词缺指示组(${text}——§15.14.3 时段词须随 BECMG/TEMPO 出现)——按磨损趋势段收下,指示组类型不可辨`,\n span: spanOf(t),\n });\n continue;\n }\n }\n\n if (text === \"CAVOK\") {\n cavok = true;\n cavokSpan = spanOf(t);\n // 交叉校验(三面:能见度/天气/云,判据见 cavokConflicts 注)——CAVOK 语义要求能见度\n // ≥10km、无重要天气、5000ft 以下无云且无 CB/TCU;前序组确定矛盾即出声。\n // 下界语义的编码(9999 ≥10km、P6SM >9.6km)与 CAVOK 相容不告警;M 前缀(小于下界)必矛盾。\n // 让位契约照旧(vis/weather/cloud 三组让位),矛盾仅追加 cross-check-conflict 告警\n cavokConflicts(\"前序\");\n // 契约(IR):CAVOK = 能见度 ≥10km + 无低云 + 无天气,前序 vis/weather/cloud 三组让位为 undefined\n // (让位是契约行为不发告警;词位以 cavokSpan 标记,前序组原码仍可从 raw 回溯)\n visibility = undefined;\n directionalAsPrimary = false;\n weather = undefined;\n weatherList.length = 0;\n cloudSeen = false;\n cloudElements.length = 0;\n clearCode = undefined;\n i += 1;\n continue;\n }\n\n // E3 性能项——首字符位掩码分流:每轮按首字符一次 switch 得「可能匹配的分支」位集,\n // 各分支先做一次位测试再进正则——不可能匹配的分支零正则尝试。分支相对顺序与原\n // 全试链完全一致(行为等价由全量语料回放快照锁定)。可达首字符推导:\n // 风 V/数字//;能见度 数字//M/P;RVRNO 与 R 组 R;天气 = 现象/描述符首字母\n // (B D F G H I M P R S T U)+ -/+/V(VC);裸 // 与云 /;云 F/S/B/O//;\n // VV 与 VIS 的 V;晴空词 S/N/C;温露 M/数字//;QNH 的 Q;A 组的 A;维护符 $。\n const mask = maskOf(text.charCodeAt(0));\n\n // 风(含 /////KT 缺测与 260V050 变化组)\n const windParsed = (mask & M_WIND) !== 0 ? parseWindToken(t, peek(1)) : null;\n if (windParsed !== null) {\n if (wind !== undefined) dupGroupWarning(\"风组\", wind.span, spanOf(t));\n if (windParsed === \"missing\") {\n if (wind === undefined) {\n wind = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 全缺测 /////KT(自动站假报文形态)与部分缺测(180//KT 风速位缺)同口径出声\n message: t.text.startsWith(\"/////\")\n ? \"风组缺测(/////KT,疑似自动站假报文形态)\"\n : `风组缺测(${t.text},风速位缺测)`,\n span: spanOf(t),\n });\n }\n // 已有风组时:缺测电码不顶替在场值(duplicate-group 已出声)——\n // 零信息量的缺测码按 last-wins 覆盖真实观测是纯信息损失(2026-09-15 五角色评测批)\n i += 1;\n } else {\n const wg = windParsed.group;\n // 风速模板上限:三位数(≤199,WMO 15.5.6「100 单位以上以精确位数替代两位电码」注至\n // 199;FMH-1 12.6.5.a「two or three digits」)——超 199 即非规范报文(270250KT 构造探针),\n // 按 QNH 超界同款纪律整组不可信判缺测,绝不静默留假值。P 前缀超上限形态(P99KT)合法\n // NaN 终结防线(终结断言,预期不可达):任何数值入口产 NaN 即整组不可信判缺测。\n // NaN 恰是现有防线的双重盲区——值域门 >199 对 NaN 恒 false、JSON.stringify 消 NaN 为\n // null、fuzz 不变量(2026-09-14 实弹 G/// 之前)无有限性检查——故独立成支并配哨兵不变量\n if (\n !Number.isFinite(wg.speed.value) ||\n (wg.gust !== undefined && !Number.isFinite(wg.gust.value))\n ) {\n wind = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `风组解码出非有限值(${t.text})——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else if (wg.speed.value > 199 || (wg.gust?.value ?? 0) > 199) {\n wind = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `风速超出编码范围(${t.text},三位数模板上限 199 ${wg.speed.unit})——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else {\n wind = { kind: \"value\", value: wg, span: spanOf(t) };\n for (const finding of windParsed.rangeFindings) {\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: finding.message,\n span: finding.span,\n });\n }\n if (windParsed.gustMissing === true) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 缺测电码双形态(G// 标准两位 / G/// 磨损三斜杠)直出原文\n message: `阵风位缺测(${t.text}——G 后斜杠位缺测,组照常成立)`,\n span: spanOf(t),\n });\n }\n if (wg.variable && wg.variation !== undefined) {\n const vs = wg.variation.span;\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `静风变向(VRB)与风向变化组(${\n vs === undefined ? \"\" : raw.slice(vs.start, vs.end)\n })并存——VRB 本义方向不定,变化组冗余,报文自洽性存疑`,\n span: vs,\n });\n }\n }\n i += windParsed.consumed;\n }\n continue;\n }\n\n // 能见度(//// 显式缺测补 info 告警——对齐风/天气缺测口径;零分母判缺测补超界告警)\n const visParsed = (mask & M_VIS) !== 0 ? parseVisibilityToken(t, peek(1)) : null;\n if (visParsed !== null) {\n // 最低能见度方向组(WMO 15.6.2):挂到已存主导能见度(非重复组不出 duplicate 告警);\n // 脱离主导能见度单独出现属非规范形态——按能见度收下 + info 出声。\n // directionalAsPrimary = 脱离主导的方向组被按主导收下(非规范状态,解析器局部标记)——\n // 其后再来的方向组是「连挂第二枚」(1200NW 1200NE),同样出声不静默\n //(2026-09-14 独立复评补齐:此前连挂时第二枚静默覆写第一枚)\n if (visParsed.kind === \"directional\") {\n if (visibility?.kind === \"value\") {\n if (visibility.value.minimum !== undefined || directionalAsPrimary) {\n dupGroupWarning(\"最低能见度方向组\", visibility.value.minimum?.span, spanOf(t));\n }\n visibility = {\n kind: \"value\",\n value: {\n ...visibility.value,\n minimum: {\n value: visParsed.group.value,\n direction: visParsed.group.direction,\n span: visParsed.group.span,\n },\n },\n span: visibility.span,\n };\n } else {\n visibility = {\n kind: \"value\",\n value: {\n value: visParsed.group.value,\n unit: \"m\",\n exact: true,\n span: visParsed.group.span,\n },\n };\n directionalAsPrimary = true;\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `最低能见度方向组脱离主导能见度(${t.text})——按能见度收下`,\n span: spanOf(t),\n });\n }\n i += visParsed.consumed;\n continue;\n }\n if (visibility !== undefined) dupGroupWarning(\"能见度组\", visibility.span, spanOf(t));\n if (visParsed.kind === \"missing\") {\n if (visibility === undefined) {\n visibility = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 缺测电码两形态直出原文(//// 米制 / ////SM 英里制——加拿大自动站,RMK VIS MISG 佐证)\n message: `能见度组缺测(${t.text},无法观测能见度)`,\n span: spanOf(t),\n });\n }\n // 已有能见度组时:缺测电码不顶替在场值(duplicate-group 已出声)——\n // 后位 ////(温露位畸形/错位落点)按 last-wins 把 9999 冲成 missing 是纯信息损失\n //(2026-09-15 五角色评测批;WMO 正常报文能见度缺测只出现在能见度槽位,此形态仅见于错位/磨损报文)\n directionalAsPrimary = false;\n i += visParsed.consumed;\n continue;\n } else if (visParsed.kind === \"invalid\") {\n visibility = { kind: \"missing\", span: visParsed.span };\n directionalAsPrimary = false;\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: visParsed.message,\n span: visParsed.span,\n });\n } else {\n visibility = { kind: \"value\", value: visParsed.group, span: visParsed.group.span };\n directionalAsPrimary = false;\n }\n i += visParsed.consumed;\n continue;\n }\n\n // RVRNO:RVR 设备存在但明示不可用(显式缺测,区别于组省略)。\n // 正文位与 RMK 位行为统一(2026-09-15 方案一,专业判读定案):一律进 remarks(kind\n // 'rvr-no')——站级状态声明 typed 可见,原正文位不留痕的双标消除;RVRNO 单独出现\n //(此前无值组)仍 = rvr 显式缺测(既有 IR 契约不变)。\n // 值组与 RVRNO 并存 = 自相矛盾形态(规范未定义并存):值组按跑道级明细保留——具体\n // 值组是逐道运行信息、可信度高于无道号的站级状态码(预报员/塔台标准判读;NWS 官方\n // 解码器即「值组 + RVRNO 旗标并存不复算」),矛盾出声、文案描述矛盾本身不预言终态。\n if ((mask & M_R) !== 0 && text === \"RVRNO\") {\n if (rvr?.kind === \"value\") {\n const prevText = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `RVRNO(站级:应报而缺)与 RVR 值组并存(${prevText})——矛盾形态,值组按跑道级明细保留,RVRNO 经 remarks/raw 可回溯`,\n span: spanOf(t),\n });\n } else {\n rvr = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"RVR 设备在但明示不可用(RVRNO)\",\n span: spanOf(t),\n });\n }\n remarks.push({ kind: \"rvr-no\", raw: text, span: spanOf(t) });\n i += 1;\n continue;\n }\n\n // RVR 与跑道状态(同为 R 前缀组,先按 RVR 语法试解、再按跑道状态电码试解)\n if ((mask & M_R) !== 0 && text.startsWith(\"R\") && text.includes(\"/\")) {\n const rvrParsed = parseRvrToken(t);\n if (rvrParsed !== null) {\n // 反向次序对称口径:RVRNO 在前、值组在后同样出声(方案一:可解读为传感器恢复,\n // 值组按明细保留——与正序矛盾并存同一文案口径,见 RVRNO 位注释)\n if (rvr?.kind === \"missing\") {\n const prevText = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `RVRNO(站级:应报而缺)与后随 RVR 值组并存(${prevText})——矛盾形态,值组按跑道级明细保留(可解读为传感器恢复),RVRNO 经 remarks/raw 可回溯`,\n span: spanOf(t),\n });\n }\n rvrList.push(rvrParsed);\n const s = spanOf(t);\n rvrSpan = rvrSpan === undefined ? s : { start: rvrSpan.start, end: s.end };\n rvr = { kind: \"value\", value: [...rvrList], span: rvrSpan };\n i += 1;\n continue;\n }\n const runwayState = parseRunwayStateToken(t);\n if (runwayState !== null) {\n runwayStates.push(runwayState.group);\n for (const finding of runwayState.findings) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: finding.message,\n span: finding.span,\n });\n }\n i += 1;\n continue;\n }\n // RVR 全斜杠缺测:R## + / + ////(分离符 + 四位值位斜杠 = 5 斜杠,标准缺测形态)。\n // 依据:WMO 306 FM15 RVR 值位恒四位(VRVRVRVR),全斜杠即数值缺测(斜杠逐位填充的缺测惯例);\n // 4 斜杠(R10////)为磨损短一段——按缺测收下,另附 invalid-format info(tgftp/IEM 实弹均见)\n const rvrSlash = /^R\\d{2}[RLC]?(\\/{4,5})$/.exec(text);\n if (rvrSlash !== null) {\n rvr = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: `RVR 组缺测(${text}——跑道号在位、视程值位全斜杠)`,\n span: spanOf(t),\n });\n if ((rvrSlash[1] ?? \"\").length === 4) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `RVR 缺测段磨损(${text}——4 位斜杠对标准 5 位(分离符 + 四位值位),少一位;按缺测收下)`,\n span: spanOf(t),\n });\n }\n i += 1;\n continue;\n }\n }\n\n // 风切变组(WMO 306 FM15 §15.13.3 / ICAO Annex 3 模板):标准形态 WS ALL RWY(全部跑道)\n // 与 WS R##[RLC](WS RDRDR,如 WS R24——IEM 归档实弹 544 次、中国区多发且为近月主流形态)。\n // 中国区实务变体 WS RWY##[RLC](RWY 前缀 + 设计器,教材常用)与 WS RWY ALL(词序倒置)\n // 同样语义无损一等收下——四形态正文组(跑道状态之后、趋势之前)。\n // 低空风切变对起降阶段是重大危害,IR 一等字段不蒸发。\n if ((mask & M_WS_RWY) !== 0 && text === \"WS\") {\n const rwyTok = peek(1);\n const designator = rwyTok !== undefined ? /^RWY(\\d{2}[RLC]?)$/.exec(rwyTok.text) : null;\n const stdDesignator = rwyTok !== undefined ? /^R(\\d{2}[RLC]?)$/.exec(rwyTok.text) : null;\n // 全跑道两形态:标准 WS ALL RWY 与词序倒置变体 WS RWY ALL\n const isAll =\n (rwyTok?.text === \"ALL\" && peek(2)?.text === \"RWY\") ||\n (rwyTok?.text === \"RWY\" && peek(2)?.text === \"ALL\");\n if (designator !== null || isAll || stdDesignator !== null) {\n const endTok = isAll ? peek(2) : rwyTok;\n const startSpan = spanOf(t);\n const endSpan = endTok !== undefined ? spanOf(endTok) : startSpan;\n wsRunways ??= [];\n if (designator !== null) wsRunways.push(designator[1] ?? \"\");\n if (stdDesignator !== null) wsRunways.push(stdDesignator[1] ?? \"\");\n if (isAll) wsAll = true;\n wsSpan =\n wsSpan === undefined\n ? { start: startSpan.start, end: endSpan.end }\n : { start: wsSpan.start, end: endSpan.end };\n windShear = { runways: wsRunways, allRunways: wsAll, span: wsSpan };\n i += isAll ? 3 : 2;\n continue;\n }\n }\n\n // 温度预告组(TAF TX/TN 混入 METAR 通路,IEM 归档实弹 26 次——中国区 TAF 行混入 METAR 流):\n // TX25/0907Z = 最高 25°C、09 日 07Z 到达(ICAO Annex 3 附录五温度预告组,M 前缀 = 负值)。\n // 认组收下进 remarks(kind 'temperature-forecast',raw 保真)——TAF 语义不属于 METAR 趋势段,\n // 与既有 temp-extrema-6h/24h 同款认组粒度,不解码数值(RemarkGroup 无值槽,数值化留待后续 additive 扩展)\n const txTnM = (mask & M_WEATHER) !== 0 ? /^(TX|TN)M?\\d{2}\\/\\d{4}Z$/.exec(text) : null;\n if (txTnM !== null) {\n remarks.push({ kind: \"temperature-forecast\", raw: text, span: spanOf(t) });\n i += 1;\n continue;\n }\n\n // 天气组(RE 近期天气一并识别——不参与当前天气三态判定)\n const weatherParsed =\n (mask & M_WEATHER) !== 0 ? tryWeatherToken(t, weatherList, recentList) : false;\n if (weatherParsed !== false) {\n if (weatherParsed.outOfOrder) {\n // 能完整切解但语序反常(描述符在现象之后,如 RATS):按切解结果收下 + invalid-format 告警,\n // 不静默也不拒收;完全无法切解的仍走下方 unknown-token\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `天气组语序不合电码表(${text}:描述符须先于现象)——已按切解结果收下`,\n span: spanOf(t),\n });\n }\n if (weatherParsed.signWithVc) {\n // 强度符与 VC 并存(-VCTSRA 家族,NWS 自动站实弹):互斥是明文条款(4678 限定槽\n // 四选一、FAA AIM「Intensity and 'VC' will not appear together」),语义可无损恢复\n //(强度+邻近+现象俱全)故容忍切解收下并出声——此前整体落 unknown-token 语义全丢\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `强度符与 VC 邻近指示并存(${text}——强度符不与 VC 同组)——已按切解结果收下`,\n span: spanOf(t),\n });\n }\n if (weatherParsed.intensityMisuse === true) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message:\n weatherParsed.kind === \"recent\"\n ? `RE 近期天气组带强度符(${text}——15.13.2.1 RE 组无强度位)——已收下`\n : `强度符超适用面(${text}——表 4678 注 4:-/+ 仅限降水族,非降水唯 +SS/+FC/+DS)——已收下`,\n span: spanOf(t),\n });\n }\n i += 1;\n continue;\n }\n\n // 裸 // 天气缺测组(自动站无法观测天气;IR 口径 = weather missing,绝不捏造也不吞进温度组)\n if ((mask & M_WEATHER) !== 0 && text === \"//\") {\n weather = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"天气组缺测(//,无法观测天气)\",\n span: spanOf(t),\n });\n i += 1;\n continue;\n }\n\n // 云:云量位 /// 与云高 /// 双缺测形态(绝不捏造)\n const cloudM = (mask & M_CLOUD) !== 0 ? CLOUD_LAYER_PATTERN.exec(text) : null;\n if (cloudM !== null) {\n cloudSeen = true;\n const amountRaw = cloudM[1];\n const heightRaw = cloudM[2];\n const convectiveRaw = cloudM[3];\n const typeMissing = cloudM[4] !== undefined;\n const amountMissing = amountRaw === \"///\";\n const heightMissing = heightRaw === \"///\";\n if (heightMissing) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"云高缺测(///),不捏造基高\",\n span: spanOf(t),\n });\n }\n if (amountMissing) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"云量位缺测(///),探测到云但云量无法观测\",\n span: spanOf(t),\n });\n }\n if (typeMissing) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"云型位缺测(///)\",\n span: spanOf(t),\n });\n }\n cloudElements.push({\n kind: \"layer\",\n amount: amountRaw !== undefined && isCloudAmount(amountRaw) ? amountRaw : null,\n heightFt: {\n value:\n heightRaw !== undefined && heightRaw !== \"///\"\n ? Number.parseInt(heightRaw, 10) * 100\n : null,\n span: spanOf(t),\n },\n convective:\n convectiveRaw !== undefined && isConvective(convectiveRaw) ? convectiveRaw : undefined,\n span: spanOf(t),\n });\n i += 1;\n continue;\n }\n const vvM = (mask & M_VV) !== 0 ? VV_PATTERN.exec(text) : null;\n if (vvM !== null) {\n cloudSeen = true;\n const heightRaw = vvM[1];\n if (heightRaw === undefined || heightRaw === \"///\") {\n // 缺测电码形态才告警——合法数值组(VV002 = 垂直能见度 200ft)零告警\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message:\n heightRaw === \"///\"\n ? \"垂直能见度缺测(VV///,天空全遮蔽但垂直能见度不可测)\"\n : \"垂直能见度缺测(VV,兼容形态)\",\n span: spanOf(t),\n });\n }\n cloudElements.push({\n kind: \"vertical-visibility\",\n heightFt: {\n value:\n heightRaw === undefined || heightRaw === \"///\"\n ? null\n : Number.parseInt(heightRaw, 10) * 100,\n span: spanOf(t),\n },\n span: spanOf(t),\n });\n i += 1;\n continue;\n }\n if ((mask & M_SKY_CLEAR) !== 0 && isSkyClear(text)) {\n cloudSeen = true;\n clearCode = { code: text, span: spanOf(t) };\n i += 1;\n continue;\n }\n\n // 温度/露点\n const tempParsed = (mask & M_TEMP) !== 0 ? parseTempDewToken(t) : null;\n if (tempParsed !== null) {\n const dupTemp = temperature !== undefined || dewpoint !== undefined;\n if (dupTemp) dupGroupWarning(\"温度组\", temperature?.span ?? dewpoint?.span, tempParsed.span);\n // 已有温露组时:全缺测电码(/////)不顶替在场值(duplicate-group 已出声)——\n // 零信息量形态覆盖真实观测是纯信息损失;带部分值的形态(如 12//)照常 last-wins\n if (dupTemp && tempParsed.temperature === null && tempParsed.dewpoint === null) {\n i += 1;\n continue;\n }\n // 温度物理极值门(与 QNH 同款纪律):超可信范围判缺测 + value-out-of-range,\n // 绝不静默留假值;双侧同时超界合并为一条告警(M91/M95 不重复出声);\n // 显式缺测(//)另发 missing-expected,两告警互不替代\n const rawTemp = tempParsed.temperature;\n const rawDew = tempParsed.dewpoint;\n const outOfRange = (r: TemperatureReading | null): boolean =>\n r !== null && (r.celsius < TEMP_C_MIN || r.celsius > TEMP_C_MAX);\n const outT = outOfRange(rawTemp);\n const outD = outOfRange(rawDew);\n if (outT || outD) {\n const single = outT ? rawTemp : rawDew;\n const span = outT && outD ? tempParsed.span : single?.span;\n const shown = span === undefined ? `${TEMP_C_MIN}` : raw.slice(span.start, span.end);\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `温度超出可信范围(${shown},合理区间 ${TEMP_C_MIN}–${TEMP_C_MAX}°C)——值不可信判缺测,原码经 span 回溯`,\n span,\n });\n }\n temperature = outT ? undefined : (rawTemp ?? undefined);\n dewpoint = outD ? undefined : (rawDew ?? undefined);\n if (rawTemp === null || rawDew === null) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 形态判别精确到正则(2026-09-14 独立复评收口:endsWith(\"/\") 会把 12// 的标准\n // 缺测与 12/// 的磨损形都误述为 24/ 形态)\n message: /^M?\\d{2}\\/$/.test(t.text)\n ? \"露点位缺测(24/ 形态,FMH-1 12.6.10)\"\n : \"温度/露点位缺测(//)\",\n span: tempParsed.span,\n });\n }\n // 交叉校验:露点不可能高于温度(相对湿度 >100% 物理不可能)——典型传感器故障形态。\n // 两组值照常保留(含 M 负值),矛盾交由告警呈现,绝不静默也不捏造\n if (\n temperature !== undefined &&\n dewpoint !== undefined &&\n temperature.celsius < dewpoint.celsius\n ) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `温度低于露点(${t.text})——物理不可能,疑似传感器故障`,\n span: tempParsed.span,\n });\n }\n i += 1;\n continue;\n }\n\n // 气压:Q(hPa)/ A(inHg,隐含小数点);5 位数 QNH 与物理范围外值 = 脏值(Q10054 家族)\n const qM = (mask & M_QNH) !== 0 ? /^Q(\\d{4,5})$/.exec(text) : null;\n if (qM !== null) {\n const digits = qM[1] ?? \"\";\n const hpa = Number.parseInt(digits, 10);\n if (digits.length === 5 || hpa < QNH_HPA_MIN || hpa > QNH_HPA_MAX) {\n altimeter = undefined;\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `QNH 超出可信范围(${text},合理区间 ${QNH_HPA_MIN}–${QNH_HPA_MAX} hPa)——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else {\n setAltimeter({ value: hpa, unit: \"hPa\", span: spanOf(t) });\n }\n i += 1;\n continue;\n }\n const aM = (mask & M_ALTIMETER_A) !== 0 ? /^A(\\d{4})$/.exec(text) : null;\n if (aM !== null) {\n const inhg = Number.parseInt(aM[1] ?? \"0\", 10) / 100;\n if (inhg < ALT_INHG_MIN || inhg > ALT_INHG_MAX) {\n altimeter = undefined;\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `高度表设定超出可信范围(${text} → ${inhg} inHg,合理区间 ${ALT_INHG_MIN}–${ALT_INHG_MAX})——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else {\n setAltimeter({ value: inhg, unit: \"inHg\", span: spanOf(t) });\n }\n i += 1;\n continue;\n }\n\n // 变化能见度(FAA 正文位形态:主能见度组后跟「VIS 1/4V1/2」变化区间)——\n // IR 建模为 RemarkKind 'variable-visibility'(不占 visibility 槽),与 RMK 段同族同 kind\n if ((mask & M_VIS_RANGE) !== 0 && text === \"VIS\" && VIS_V_RANGE.test(peek(1)?.text ?? \"\")) {\n const nextTok = peek(1);\n if (nextTok !== undefined) {\n remarks.push({\n kind: \"variable-visibility\",\n raw: `${text} ${nextTok.text}`,\n span: { start: t.start, end: nextTok.end },\n });\n i += 2;\n continue;\n }\n }\n\n // 维护指示符(正文级孤例)\n if ((mask & M_DOLLAR) !== 0 && text === \"$\") {\n remarks.push({ kind: \"maintenance\", raw: \"$\", span: spanOf(t) });\n i += 1;\n continue;\n }\n\n // 不静默:看不懂的 token 进 warnings,绝不丢弃\n warnings.push({\n code: \"unknown-token\",\n severity: \"info\",\n message: `未识别的组(${text})——已如实收下`,\n span: spanOf(t),\n });\n i += 1;\n }\n\n // 当前天气组:仅有实组时给值;RE-only 报文 weather 保持 undefined(组省略 ≠ 缺测)\n if (weatherList.length > 0) {\n const first = weatherList[0];\n const last = weatherList[weatherList.length - 1];\n if (first !== undefined && last !== undefined) {\n weather = {\n kind: \"value\",\n value: [...weatherList],\n span:\n first.span !== undefined && last.span !== undefined\n ? { start: first.span.start, end: last.span.end }\n : undefined,\n };\n }\n }\n if (cloudSeen) {\n clouds = { elements: cloudElements, clear: clearCode };\n }\n\n // CAVOK 词后矛盾校验:词位让位后,其后新出现的能见度/天气/云组若与 CAVOK 语义确定矛盾,\n // 此前静默并存——同三面判据出声(趋势段已被围栏隔离,不会流入此处的正文状态)\n if (cavok) cavokConflicts(\"后续\");\n\n // 云组自洽(WMO 15.9.2 / 15.9.1):VV 顶替整个云组、NSC/SKC/NCD/CLR 为无云电码——\n // 与层组并存均互斥矛盾形态,出声不静默(规范外容错照旧收下)\n const hasVvElement = cloudElements.some((e) => e.kind === \"vertical-visibility\");\n const hasLayerElement = cloudElements.some((e) => e.kind === \"layer\");\n if (hasVvElement && hasLayerElement) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: \"VV 组与云层组并存(WMO 15.9.2:VV 顶替整个云组)——报文自洽性存疑\",\n span: cloudElements[0]?.span,\n });\n }\n if (clearCode !== undefined && hasLayerElement) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `${clearCode.code}(无云电码)与云层组并存——互斥形态,报文自洽性存疑`,\n span: clearCode.span,\n });\n }\n\n // —— RMK 段(认组粒度;未知 ≠ 错误,不进 warnings)\n while (i < tokens.length) {\n const t = tokens[i];\n if (t === undefined) break;\n const text = t.text;\n const push = (remarkKind: RemarkKind, consumed = 1): void => {\n const slice = tokens.slice(i, i + consumed);\n remarks.push({\n kind: remarkKind,\n raw: slice.map((c) => c.text).join(\" \"),\n span: joinSpan(slice),\n });\n i += consumed;\n };\n\n if (text === \"AO1\" || text === \"AO2\" || text === \"A01\" || text === \"A02\") {\n // A01/A02 数字形态:tgftp 通路实弹 268 站次(与 FMH-1 字母形态 AO1/AO2 并存)\n push(\"auto-type\");\n continue;\n }\n if (/^SLP(\\d{3}|NO)$/.test(text)) {\n push(\"sea-level-pressure\");\n continue;\n }\n if (/^T[01]\\d{7}(T[01]\\d{7})?$/.test(text) || /^T[01]\\d{3}$/.test(text)) {\n push(\"precise-temperature\");\n continue;\n }\n if (/^P\\d{4}$/.test(text)) {\n push(\"precip-1h\");\n continue;\n }\n if (/^[67](?:\\d{4}|\\/{4})$/.test(text)) {\n // 6/7 组降水窗口(3/24h):量值 4 位;//// = 窗口降水缺测(FMH-1 实弹 6////,tgftp 语料 17 处)\n push(\"precip-window\");\n continue;\n }\n if (/^4\\/\\d{3}$/.test(text)) {\n push(\"snow-depth\");\n continue;\n }\n if (/^I[136]\\d{3}$/.test(text)) {\n // FMH-1 冰积组 = I + 间隔位(1/3/6h) + 3 位量值(I1001 → 1 小时 0.01 英寸);\n // 旧正则 \\d{4} 多吞一位致 I1001 形态全数落 unknown(2026-09-12 复评命中)\n push(\"ice-accretion\");\n continue;\n }\n if (/^5[0-8]\\d{3}$/.test(text)) {\n push(\"pressure-tendency\");\n continue;\n }\n // 24h 温度极值组:现行 FMH-1 为 9 位(4 + 最高[符号位 3 位] + 最低[符号位 3 位],\n // 如 401280089 = 最高 +12.8 / 最低 +8.9;符号位 1 = 负),IEM/tgftp 实弹全数 9 位;\n // 8 位旧形态兼容保留\n if (/^4(?:[01]\\d{3}[01]\\d{3}|\\d{7})$/.test(text)) {\n push(\"temp-extrema-24h\");\n continue;\n }\n if (/^[12]\\d{4}$/.test(text)) {\n push(\"temp-extrema-6h\");\n continue;\n }\n if (text === \"PK\" && tokens[i + 1]?.text === \"WND\") {\n push(\"peak-wind\", 3);\n continue;\n }\n if (text === \"WSHFT\" && tokens[i + 1] !== undefined) {\n push(\"wind-shift\", 2);\n continue;\n }\n if (text === \"PRESRR\" || text === \"PRESFR\") {\n push(\"pressure-change\");\n continue;\n }\n if (text === \"VISNO\") {\n push(\"vis-no\");\n continue;\n }\n if (text === \"TSNO\") {\n // TSNO(美网高频):雷暴传感器不工作——雷暴探测不可用(≠无雷暴),认组不再 unknown\n push(\"thunderstorm-sensor\");\n continue;\n }\n if (text === \"RVRNO\") {\n // RMK 位与正文位同口径(方案一):并存矛盾出声、值组明细保留(终态不改),\n // RVRNO 自身留痕 remarks——见正文 RVRNO 位注释\n if (rvr?.kind === \"value\") {\n const prevText = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `RVRNO(站级:应报而缺)与 RVR 值组并存(${prevText})——矛盾形态,值组按跑道级明细保留,RVRNO 经 remarks/raw 可回溯`,\n span: spanOf(t),\n });\n } else {\n rvr = { kind: \"missing\", span: spanOf(t) };\n }\n push(\"rvr-no\");\n continue;\n }\n if (text === \"SFC\" && tokens[i + 1]?.text === \"VIS\") {\n // 分数尾 token(SFC VIS 2 1/2)一并吸收,不再散落 unknown(FMH-1 12.7.1.f)\n const frac = /^\\d\\/\\d(SM)?$/.test(tokens[i + 3]?.text ?? \"\") ? 1 : 0;\n push(\"surface-visibility\", 3 + frac);\n continue;\n }\n if (text === \"TWR\" && tokens[i + 1]?.text === \"VIS\") {\n // TWR VIS 塔台能见度(FMH-1 12.7.1.f,值可为分数对)\n const frac = /^\\d\\/\\d(SM)?$/.test(tokens[i + 3]?.text ?? \"\") ? 1 : 0;\n push(\"twr-visibility\", 3 + frac);\n continue;\n }\n const visDirNext = tokens[i + 1]?.text;\n const RMK_VIS_DIR = /^(N|NE|E|SE|S|SW|W|NW)$/;\n const RMK_VIS_VAL = /^[MP]?\\d+(\\/\\d+)?(SM)?$/;\n if (\n text === \"VIS\" &&\n visDirNext !== undefined &&\n RMK_VIS_DIR.test(visDirNext) &&\n tokens[i + 2] !== undefined\n ) {\n // 分区能见度(方位在前)VIS <方位> <量值>〔<方位> <量值>…〕(FMH-1 12.7.1.h,量值可为整数+分数对)\n // 多扇区实弹(PANC:VIS E 10 SE 10 S 10)整段并组保真,后续方位对不再散落 unknown\n const frac = /^\\d\\/\\d(SM)?$/.test(tokens[i + 3]?.text ?? \"\") ? 1 : 0;\n let consumed = 3 + frac;\n for (let j = i + consumed; ;) {\n const dir = tokens[j]?.text;\n if (dir === undefined || !RMK_VIS_DIR.test(dir)) break;\n const val = tokens[j + 1]?.text;\n if (val === undefined || !RMK_VIS_VAL.test(val)) break;\n const pair = /^\\d+$/.test(val) && /^\\d\\/\\d(SM)?$/.test(tokens[j + 2]?.text ?? \"\") ? 3 : 2;\n consumed += pair;\n j += pair;\n }\n push(\"sectoral-visibility\", consumed);\n continue;\n }\n if (text === \"VIS\" && visDirNext !== undefined && RMK_VIS_VAL.test(visDirNext)) {\n // 分区能见度(量值在前)VIS <量值>〔<方位>〕(FMH-1 12.7.1.h;PANC 实弹:VIS 1 1/2 N)\n let consumed = 2; // VIS + 量值\n if (/^\\d+$/.test(visDirNext) && /^\\d\\/\\d(SM)?$/.test(tokens[i + 2]?.text ?? \"\"))\n consumed += 1; // 整数+分数对\n if (\n tokens[i + consumed]?.text !== undefined &&\n RMK_VIS_DIR.test(tokens[i + consumed]?.text ?? \"\")\n )\n consumed += 1;\n push(\"sectoral-visibility\", consumed);\n continue;\n }\n if (/^CIGNO$/.test(text)) {\n // 云高计不可用(FMH-1 12.7.1.p 族,与 VISNO/TSNO/RVRNO 同族口径)\n push(\"cig-not-available\");\n continue;\n }\n const cigNext = tokens[i + 1]?.text;\n if (text === \"CIG\" && cigNext !== undefined) {\n // CIG hhhVhhh 波动 / CIG hhh LOC / CIG hhh(FMH-1 12.7.1.p)\n const nxt = cigNext;\n if (/^\\d{3}V\\d{3}$/.test(nxt)) {\n push(\"ceiling-variation\", 2);\n continue;\n }\n if (/^\\d{3}$/.test(nxt)) {\n if (tokens[i + 2]?.text === \"LOC\") {\n push(\"ceiling-at-location\", 3);\n continue;\n }\n push(\"ceiling\", 2);\n continue;\n }\n }\n if (text === \"PNO\") {\n // 降水传感器不可用(FMH-1 12.7.2.g 族)\n push(\"precip-not-available\");\n continue;\n }\n if (text === \"FZRANO\") {\n push(\"fzr-not-available\");\n continue;\n }\n if (text === \"CHINO\") {\n push(\"chino\");\n continue;\n }\n if (/^8\\/[0-9X/]{3}$/.test(text)) {\n // 8/CCC 云型组(低/中/高云型电码 0–9,X 未知,/ 缺测;FMH-1 12.7.2.b)\n push(\"cloud-type-8group\");\n continue;\n }\n if (/^933\\d{3}$/.test(text)) {\n // 933RRR 积雪水当量(英寸百分之一;FMH-1 12.7.2.a)\n push(\"snow-water-equivalent\");\n continue;\n }\n if (text === \"FUNNEL\" && tokens[i + 1]?.text === \"CLOUD\") {\n push(\"phenomenon-began-ended\", 2);\n continue;\n }\n if (text === \"LTG\") {\n // 多 token 聚合:LTG 后按词表(LTG_TAIL_VOCAB)连收 + 词表词后夹带至多一个 1–2 位\n // 数字距离 token(FMH-1 ch.12:自动站雷电视频距离为海里裸数字,如 LTG ALQDS CG 12 OHD——\n // 数字须跟在词表词后,LTG 直连裸数字无出处)。聚合仍被词表外 token 截断;\n // 数字吸收以「前一吸收 token ∈ 词表」为前置且至多一个——防无关散落数字被静默吞进\n // lightning remark(2026-09-14 收紧:实现此前与注释声明不符,语料 229 处 LTG 零裸数字)\n let consumed = 1;\n let prevInVocab = false;\n let digitsAbsorbed = 0;\n for (;;) {\n const nextTok = tokens[i + consumed];\n if (nextTok === undefined) break;\n if (LTG_TAIL_VOCAB.has(nextTok.text)) {\n consumed += 1;\n prevInVocab = true;\n continue;\n }\n if (prevInVocab && digitsAbsorbed === 0 && /^\\d{1,2}$/.test(nextTok.text)) {\n consumed += 1;\n digitsAbsorbed += 1;\n prevInVocab = false;\n continue;\n }\n break;\n }\n push(\"lightning\", Math.min(consumed, tokens.length - i));\n continue;\n }\n if (text === \"SNINCR\" && /^\\d+\\/\\d+$/.test(tokens[i + 1]?.text ?? \"\")) {\n // SNINCR <时增>/<总量>(英寸,两 token 一组)——积雪增率,2026-09-12 复评补建模\n push(\"snow-increase\", 2);\n continue;\n }\n if (text === \"VIS\" && VIS_V_RANGE.test(tokens[i + 1]?.text ?? \"\")) {\n // 变化能见度 VIS 1/2V2(IR RemarkKind 'variable-visibility' 声明补实现)\n push(\"variable-visibility\", 2);\n continue;\n }\n // began/ended 家族(FZRAB43E50 合并形态 / RAB42·RAE50 拆分形态 / B43 裸起止)——\n // 边界收紧(2026-09-12):词身须能按天气组切解(FZRA/RA/TS…),俄区 QBB(云底高度,\n // 国家组)等非天气字母组不再被 [A-Z]{2,8} 前缀误吞进本类\n const beganMerged = /^([A-Z]{2,8})B\\d{2,4}(?:E\\d{2,4})?$/.exec(text);\n const beganSplit = /^([A-Z]{2})[BE]\\d{2,4}$/.exec(text);\n const beganBodyOk = (m: RegExpExecArray | null): boolean =>\n m !== null && splitWeatherToken(m[1] ?? \"\") !== null;\n if (beganBodyOk(beganMerged) || beganBodyOk(beganSplit) || /^[BE]\\d{2,4}$/.test(text)) {\n push(\"phenomenon-began-ended\");\n continue;\n }\n if (/^QBB\\d{3}$/.test(text)) {\n // QBB(俄区国家组):云底高度(米,3 位直读,与正文云组互为印证)\n push(\"cloud-base-height\");\n continue;\n }\n if (/^QFE\\d{3,4}(\\/\\d{3,4})?$/.test(text)) {\n // QFE(俄区国家组):场面气压。值语义(查证 2026-09-12):三位数 = 毫米汞柱(QFE749 = 749 mmHg,\n // 俄区惯例报 mmHg 场压);双段 QFE746/0995 = 746 mmHg 与 995 hPa 双单位(760 mmHg = 1013.25 hPa\n // 标准大气换算互证,metar-taf.com 俄区实报 RMK R08L/QFE741/0988 同族);四位数直读 hPa(QFE1003)。\n // 认组粒度收下不解码数值(RemarkGroup 无值槽;单位歧义风险由「不解码」规避),原码经 span 可取\n push(\"aerodrome-pressure\");\n continue;\n }\n if (text === \"$\") {\n push(\"maintenance\");\n continue;\n }\n push(\"unknown\");\n }\n\n return compactIfEnabled({\n kind,\n raw,\n station,\n time,\n flags: { auto, corrected },\n cavok,\n cavokSpan,\n wind,\n visibility,\n runwayVisualRange: rvr,\n weather,\n recentWeather: recentList.length > 0 ? recentList : undefined,\n clouds,\n temperature,\n dewpoint,\n altimeter,\n seaLevelPressure: undefined,\n trends,\n runwayStates,\n windShear,\n remarks,\n warnings,\n });\n}\n\n/** Result-style parse outcome: never throws for parse-level failures — branch on `ok` instead of try/catch.\n * 结果式解析出口:解析层失败不抛出,按 ok 分流——批量回放/管道消费免 try/catch 控制流。 */\nexport type TryParseResult =\n | { readonly ok: true; readonly report: MetarReport }\n | { readonly ok: false; readonly error: MetarParseError };\n\n/**\n * `parse` 的问题式变体:整体失败返回 `{ ok:false, error }`(MetarParseError,code 契约同 parse),\n * 成功返回 `{ ok:true, report }`。仅编程性意外(非 MetarParseError 的内部异常)原样抛出——\n * 不吞实现缺陷。语义与 parse 完全一致(同一实现,确定性继承)。\n * Result-style variant of `parse`: whole-report failures come back as `{ ok:false, error }`\n * with the same stable `code` contract; unexpected non-MetarParseError exceptions still throw.\n */\nexport function tryParse(raw: string, options?: ParseOptions): TryParseResult {\n try {\n return { ok: true, report: parse(raw, options) };\n } catch (err) {\n if (err instanceof MetarParseError) return { ok: false, error: err };\n throw err;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @metweave/parser — 解析层:METAR/SPECI(tolerant)→ IR。\n * The parsing layer: METAR/SPECI (tolerant mode) → IR.\n *\n * v0.1 实现范围:METAR 正文 + 趋势组半结构化 + RMK 认组 + 跑道状态最小形。\n * 纪律:不静默——看不懂的 token 一律进 warnings[](unknown-token,info 级),绝不丢弃;\n * 缺测电码(////、/////KT、//)与不可信值(5 位数 QNH)→ Observed missing + 告警;\n * 单位跟组走;一切产物携带原文 span。strict 模式预留给报文校验场景。\n */\nimport type {\n AltimeterReading,\n CloudAmount,\n CloudCondition,\n CloudElement,\n ConvectiveType,\n MetarReport,\n WindShearGroup,\n Observed,\n ParseOptions,\n ParseWarning,\n RemarkGroup,\n RemarkKind,\n ReportKind,\n RunwayStateGroup,\n RunwayVisualRange,\n SkyClearCode,\n Span,\n TemperatureReading,\n TrendElements,\n TrendGroup,\n VisibilityGroup,\n WeatherDescriptor,\n WeatherGroup,\n WeatherPhenomenon,\n WindGroup,\n} from \"@metweave/core\";\nimport { MetarParseError } from \"@metweave/core\";\n\n// IR 类型就近供给:本包 API 的返回/告警类型即 core 的 IR 类型(唯一来源在 core,此处仅转发)——\n// 免去消费方猜测「parse 的返回类型去哪 import」(2026-09-16 五方实测评测反馈)\nexport type {\n AltimeterReading,\n CloudCondition,\n CloudElement,\n MetarReport,\n Observed,\n ParseWarning,\n ReportKind,\n RunwayStateGroup,\n RunwayVisualRange,\n Span,\n TemperatureReading,\n TrendElements,\n TrendGroup,\n TrendKind,\n VisibilityGroup,\n WeatherGroup,\n WindGroup,\n} from \"@metweave/core\";\n\ninterface Token {\n readonly text: string;\n readonly start: number;\n readonly end: number;\n}\n\nconst PHENOMENA: readonly WeatherPhenomenon[] = [\n \"DZ\",\n \"RA\",\n \"SN\",\n \"SG\",\n \"IC\",\n \"PL\",\n \"GR\",\n \"GS\",\n \"UP\",\n \"BR\",\n \"FG\",\n \"FU\",\n \"VA\",\n \"DU\",\n \"SA\",\n \"HZ\",\n \"PY\",\n \"PO\",\n \"SQ\",\n \"FC\",\n \"SS\",\n \"DS\",\n];\nconst DESCRIPTORS: readonly WeatherDescriptor[] = [\"MI\", \"PR\", \"BC\", \"DR\", \"BL\", \"SH\", \"TS\", \"FZ\"];\nconst TREND_KINDS = new Set<string>([\"NOSIG\", \"BECMG\", \"TEMPO\"]);\n/** 趋势段拖词容忍集(无 typed 语义的磨损尾/连接词——收进 trend.raw 静默保真,不产生噪声):\n * 语料实弹 VNKT 120930Z「NOSIG CB TO NE AND E」(观测员补记磨损尾)与既有回归锁契约\n * (拖词不告警、原文留 raw);含裸对流码 CB/TCU(无云量云高位的残缺云信息,无解码面)与\n * 16 方位词、TO/AND 连接词。与「交回正文恢复 typed 语义」的收窄主判据互补:\n * 有语义可恢复的(温露/QNH/$/WS/TX/TN/RVRNO)一律收口交回,纯噪声拖词保持原文静默。 */\nconst TREND_FILLER_WORDS = new Set([\n \"TO\",\n \"AND\",\n \"CB\",\n \"TCU\",\n \"N\",\n \"NNE\",\n \"NE\",\n \"ENE\",\n \"E\",\n \"ESE\",\n \"SE\",\n \"SSE\",\n \"S\",\n \"SSW\",\n \"SW\",\n \"WSW\",\n \"W\",\n \"WNW\",\n \"NW\",\n \"NNW\",\n]);\n/** 趋势段收组判据(封闭清单):只有趋势合法要素族(WMO 306 FM15 §15.14.2/§15.14.10:风/能见度/现在天气/云,\n * 加趋势专属 NSW 与 CAVOK 顶替)与风组变化组拖带形(dddVddd)可收进趋势段;其余 token 一律收口\n * 交回正文循环——正文各分支自带认组与 unknown-token 出声,语义无损恢复,冲突组自然触发重复组告警。\n *\n * 根因一(2026-09-12 复评实弹):旧收集循环只认趋势指示组,俄区报文「NOSIG RMK QFE749」把 RMK 段\n * 整段吞进 trends(RU 61/65、KZ 18/18 条命中)、remarks 反而为空。\n * 根因二(2026-09-14 复评实弹):收口改「白名单补洞」后正文专属组(温露/QNH/$/WS/TX/TN/RVRNO)\n * 仍被静默吞进 trend.raw、typed 语义蒸发——RMK、Rxx/、$ 已是三次逃逸,补洞循环就此终结:\n * 判据反转为规范封闭清单,未来一切新正文分支自动获得「交回正文 + 出声」兜底。\n * 硬边界保留:RMK(含词身粘连 startsWith)与 R 组形态——R 组收口另有 trendCloseWarning 出声。 */\nconst isTrendCollectible = (t: Token, next: Token | undefined): boolean => {\n const text = t.text;\n // 段间切换与正文硬边界:下一个趋势指示组、RMK、R 组形态(Rxx/…、R/SNOCLO)一律收口\n if (TREND_KINDS.has(text) || text.startsWith(\"RMK\")) return false;\n if (/^R(\\d{2}[RLC]?\\/|\\/SNOCLO$)/.test(text)) return false;\n // 趋势专属词与天气缺测电码\n if (text === \"CAVOK\" || text === \"NSW\" || text === \"//\") return true;\n // 拖词容忍集(见 TREND_FILLER_WORDS 注:无 typed 语义,静默保真优于 unknown 噪声)\n if (TREND_FILLER_WORDS.has(text)) return true;\n // 磨损时段词(一趋势内第二/三个 AT|TL|FM ddhh——指示组已在,按拖词静默保真;\n // tgftp/归档实弹,回归锁:标准位置时段词零告警)\n if (/^(AT|TL|FM)\\d{4}$/.test(text)) return true;\n // 风(含 /////KT 缺测、VRB、P 超上限形)与风组变化组拖带(dddVddd 单独成 token)\n if (parseWindToken(t, next) !== null || /^\\d{3}V\\d{3}$/.test(text)) return true;\n // 能见度(米制 4 位/NDV/方向组/SM 族/混分数跨 token///// 缺测家族)\n if (parseVisibilityToken(t, next) !== null) return true;\n // 现在天气(VC 邻近/-+ 强度/组合词身/裸 TS;RE 近期天气不属趋势族——交回正文按 recentWeather 认组)\n if (parseWeatherBody(text) !== null) return true;\n // 云(层组/VV/晴空码)\n if (CLOUD_LAYER_PATTERN.test(text) || VV_PATTERN.test(text) || isSkyClear(text)) return true;\n return false;\n};\nconst SKY_CLEAR_CODES: readonly SkyClearCode[] = [\"SKC\", \"NSC\", \"NCD\", \"CLR\"];\nconst CLOUD_AMOUNTS: readonly CloudAmount[] = [\"FEW\", \"SCT\", \"BKN\", \"OVC\"];\nconst SPEED_UNITS: readonly WindGroup[\"speed\"][\"unit\"][] = [\"kt\", \"mps\", \"kmh\"];\n/** QNH/A 物理可信范围:世界海平面气压极值 870(台风 Tip)–1083.8 hPa(蒙古高压 Agata 1968)——\n * 上界取 1084(极值之上即物理不可能,复评实弹 Q1087 由此拦截),下界 800 留裕量;\n * A 组(inHg)按同区间镜像换算外圆整为 23.5–32.5(800 hPa ≈ 23.62、1084 ≈ 32.02)。\n * 越界 = 值不可信 → 判缺测 + value-out-of-range 告警(与 Q10054 位数超界同纪律,绝不静默留假值)。 */\nconst QNH_HPA_MIN = 800;\nconst QNH_HPA_MAX = 1084;\nconst ALT_INHG_MIN = 23.5;\nconst ALT_INHG_MAX = 32.5;\n/** 温度物理可信范围:世界极值 +56.7°C(Death Valley 1913)/ −89.2°C(Vostok 1983),\n * 取 60/−90 留裕量(与 QNH 世界极值门同款纪律)——两位数模板空间内的物理不可能值\n * (89/85 构造实弹)不可信判缺测,绝不静默留假值。 */\nconst TEMP_C_MIN = -90;\nconst TEMP_C_MAX = 60;\n/** LTG 尾随词表(FMH-1 雷电视词与方位):放电类型 IC/CG/CC/CA、位置 OHD/ALQDS/DSNT/VCNTY 与 16 方位点。\n * 实弹(tgftp 全 cycle)LTG 后的方位词此前逐个散落成 unknown remarks(ALQDS/OHD/方位词一片)。 */\nconst LTG_TAIL_VOCAB = new Set([\n \"IC\",\n \"CG\",\n \"CC\",\n \"CA\",\n \"OHD\",\n \"ALQDS\",\n \"DSNT\",\n \"VCNTY\",\n \"N\",\n \"NNE\",\n \"NE\",\n \"ENE\",\n \"E\",\n \"ESE\",\n \"SE\",\n \"SSE\",\n \"S\",\n \"SSW\",\n \"SW\",\n \"WSW\",\n \"W\",\n \"WNW\",\n \"NW\",\n \"NNW\",\n]);\n/** 变化能见度尾组形态(RMK VIS 1/2V2 / VIS 1/4V1/2):两侧为整数或分数(可带 M/P 阈值前缀)。 */\nconst VIS_V_RANGE = /^[MP]?\\d+(?:\\/\\d+)?V[MP]?\\d+(?:\\/\\d+)?$/;\n\n// —— E3 首字符位掩码(正文循环分支分流用;可达首字符推导见正文循环内注释)\nconst M_WIND = 1 << 0;\nconst M_VIS = 1 << 1;\nconst M_R = 1 << 2;\nconst M_WEATHER = 1 << 3;\nconst M_CLOUD = 1 << 4;\nconst M_VV = 1 << 5;\nconst M_SKY_CLEAR = 1 << 6;\nconst M_TEMP = 1 << 7;\nconst M_QNH = 1 << 8;\nconst M_ALTIMETER_A = 1 << 9;\nconst M_VIS_RANGE = 1 << 10;\nconst M_DOLLAR = 1 << 11;\nconst M_WS_RWY = 1 << 12;\n\n/** 首字符(charCode)→ 候选分支位掩码;0 = 无分支可达(直接落 unknown-token) */\nfunction maskOf(code: number): number {\n if (code >= 48 && code <= 57) return M_WIND | M_VIS | M_TEMP; // 0-9\n switch (code) {\n case 47: // /\n return M_WIND | M_VIS | M_WEATHER | M_CLOUD | M_TEMP;\n case 86: // V(VRB 风 / VC 天气 / VV / VIS)\n return M_WIND | M_WEATHER | M_VV | M_VIS_RANGE;\n case 77: // M(M1/4SM / MIFG / M10/)\n return M_VIS | M_WEATHER | M_TEMP;\n case 80: // P(P6SM / PL PO PY PR)\n return M_VIS | M_WEATHER;\n case 82: // R(RVRNO / R 组 / RA…)\n return M_R | M_WEATHER;\n case 81: // Q\n return M_QNH;\n case 65: // A(AUTO 词已在前置词位收口,此处仅 A 组)\n return M_ALTIMETER_A;\n case 66: // B\n case 70: // F\n return M_WEATHER | M_CLOUD;\n case 79: // O(现象/描述符无 O 首字母)\n return M_CLOUD;\n case 83: // S\n return M_WEATHER | M_CLOUD | M_SKY_CLEAR;\n case 78: // N\n case 67: // C\n return M_SKY_CLEAR;\n case 68: // D\n case 71: // G\n case 72: // H\n case 73: // I\n case 84: // T\n case 85: // U\n case 45: // -\n case 43: // +\n return M_WEATHER;\n case 36: // $\n return M_DOLLAR;\n case 87: // W(WS 风切变组)\n return M_WS_RWY;\n default:\n return 0;\n }\n}\n\nconst isPhenomenon = (s: string): s is WeatherPhenomenon => PHENOMENA.some((p) => p === s);\nconst isDescriptor = (s: string): s is WeatherDescriptor => DESCRIPTORS.some((p) => p === s);\nconst isCloudAmount = (s: string): s is CloudAmount => CLOUD_AMOUNTS.some((p) => p === s);\nconst isSkyClear = (s: string): s is SkyClearCode => SKY_CLEAR_CODES.some((p) => p === s);\nconst isSpeedUnit = (s: string): s is WindGroup[\"speed\"][\"unit\"] =>\n SPEED_UNITS.some((p) => p === s);\nconst isConvective = (s: string): s is ConvectiveType => s === \"CB\" || s === \"TCU\";\n\nfunction tokenize(raw: string): Token[] {\n const tokens: Token[] = [];\n const rx = /\\S+/g;\n let m: RegExpExecArray | null;\n while ((m = rx.exec(raw)) !== null) {\n tokens.push({ text: m[0], start: m.index, end: m.index + m[0].length });\n }\n return tokens;\n}\n\nconst spanOf = (t: Token): Span => ({ start: t.start, end: t.end });\n\n/** 云层组形态(FEW023CB / /////01CB/// 缺测位形态)——正文循环与趋势段结构化共用一份正则防漂移 */\nconst CLOUD_LAYER_PATTERN = /^(FEW|SCT|BKN|OVC|\\/\\/\\/)(\\d{3}|\\/\\/\\/)(CB|TCU)?(\\/\\/\\/)?$/;\n/** VV 组形态(VV / VV/// / VV002)——同上共用 */\nconst VV_PATTERN = /^VV(\\/\\/\\/|\\d{3})?$/;\n\n/**\n * 趋势段内要素结构化(WMO 306 FM15 §15.14.2:风/能见度/天气/云四族 + 趋势专属 NSW(§15.14.13)与 CAVOK(§15.10)顶替)。\n * best-effort 且静默:认不出的组不产生任何告警(告警面受语料快照锁保护),原文在 raw 保真;\n * 正文循环同款的 token 级解析函数直接复用(parseWindToken/parseVisibilityToken/parseWeatherBody),\n * 组形正则取共享常量。返回 undefined = 没有任何组被识别(如裸 NOSIG)。\n */\nfunction structureTrendElements(\n tokens: readonly Token[],\n start: number,\n): TrendElements | undefined {\n let wind: WindGroup | undefined;\n let visibility: VisibilityGroup | undefined;\n let cavok: TrendElements[\"cavok\"];\n let nsw: TrendElements[\"nsw\"];\n const weather: WeatherGroup[] = [];\n let clouds: CloudCondition | undefined;\n let k = start;\n while (k < tokens.length) {\n const t = tokens[k];\n if (t === undefined) break;\n const next = tokens[k + 1];\n if (t.text === \"CAVOK\") {\n cavok = { span: spanOf(t) };\n k += 1;\n continue;\n }\n if (t.text === \"NSW\") {\n nsw = { span: spanOf(t) };\n k += 1;\n continue;\n }\n if (wind === undefined) {\n const w = parseWindToken(t, next);\n if (w !== null && w !== \"missing\") {\n wind = w.group;\n k += w.consumed;\n continue;\n }\n }\n if (visibility === undefined) {\n const vis = parseVisibilityToken(t, next);\n if (vis !== null && vis.kind === \"ok\") {\n visibility = vis.group;\n k += vis.consumed;\n continue;\n }\n }\n const wx = parseWeatherBody(t.text);\n if (wx !== null) {\n // 内部信号(outOfOrder/signWithVc)不进 IR;趋势段 tolerant 静默收下\n const { outOfOrder: _outOfOrder, signWithVc: _signWithVc, ...group } = wx;\n weather.push({ ...group, span: spanOf(t) });\n k += 1;\n continue;\n }\n const cloudM = CLOUD_LAYER_PATTERN.exec(t.text);\n if (cloudM !== null) {\n const amountRaw = cloudM[1];\n const heightRaw = cloudM[2];\n const convectiveRaw = cloudM[3];\n clouds = {\n elements: [\n ...(clouds?.elements ?? []),\n {\n kind: \"layer\",\n amount: amountRaw !== undefined && isCloudAmount(amountRaw) ? amountRaw : null,\n heightFt: {\n value:\n heightRaw !== undefined && heightRaw !== \"///\"\n ? Number.parseInt(heightRaw, 10) * 100\n : null,\n span: spanOf(t),\n },\n convective:\n convectiveRaw !== undefined && isConvective(convectiveRaw)\n ? convectiveRaw\n : undefined,\n span: spanOf(t),\n },\n ],\n ...(clouds?.clear !== undefined ? { clear: clouds.clear } : {}),\n };\n k += 1;\n continue;\n }\n const vvM = VV_PATTERN.exec(t.text);\n if (vvM !== null) {\n const heightRaw = vvM[1];\n clouds = {\n elements: [\n ...(clouds?.elements ?? []),\n {\n kind: \"vertical-visibility\",\n heightFt: {\n value:\n heightRaw === undefined || heightRaw === \"///\"\n ? null\n : Number.parseInt(heightRaw, 10) * 100,\n span: spanOf(t),\n },\n span: spanOf(t),\n },\n ],\n ...(clouds?.clear !== undefined ? { clear: clouds.clear } : {}),\n };\n k += 1;\n continue;\n }\n if (isSkyClear(t.text)) {\n clouds = { elements: clouds?.elements ?? [], clear: { code: t.text, span: spanOf(t) } };\n k += 1;\n continue;\n }\n k += 1; // 认不出的组:原文保真、静默跳过(tolerant 纪律,绝不静默丢原文)\n }\n if (\n wind === undefined &&\n visibility === undefined &&\n cavok === undefined &&\n nsw === undefined &&\n weather.length === 0 &&\n clouds === undefined\n )\n return undefined;\n return {\n ...(wind !== undefined ? { wind } : {}),\n ...(visibility !== undefined ? { visibility } : {}),\n ...(cavok !== undefined ? { cavok } : {}),\n weather,\n ...(nsw !== undefined ? { nsw } : {}),\n ...(clouds !== undefined ? { clouds } : {}),\n };\n}\n\nfunction joinSpan(tokens: readonly Token[]): Span {\n const first = tokens[0];\n const last = tokens[tokens.length - 1];\n if (first === undefined || last === undefined) return { start: 0, end: 0 };\n return { start: first.start, end: last.end };\n}\n\n/**\n * 紧凑模式出口剥除(E1)v2——重建式:遍历构造全新对象(不含 span/cavokSpan 键),零 mutation。\n * 设计权衡(实测驱动,两版对比):\n * - 构造期逐点跳过 span 的方案在 full 模式引入 ~20% 退化(分支插入组构造热路径),否决;\n * - 旧版出口就地删键(Reflect.deleteProperty)让 V8 把产物退化为 dictionary mode(慢属性):\n * 实测紧凑吞吐仅全模式 ~32%(23 万 vs 72 万行/秒)、存活对象驻留反升 ~2.2×——此为本版根因修复对象;\n * - 重建式出口一次遍历:full 模式与旧版逐字节同路径(零开销),紧凑产物保持 fast properties\n * (隐藏类不丢),实测吞吐回到全模式 ~55% 量级(40.6 万 vs 72.8 万行/秒,旧版仅 32%)、\n * 驻留与全模式持平(1.01×,旧版反升 2.21×——数字见 E 批性能冒烟锁注释)。\n * 数组重建新数组、原语透传;对象均为本次 parse 新建(无共享引用),键序保持原插入序(JSON 面稳定)。\n */\nfunction compactNode<T>(node: T): T {\n if (Array.isArray(node)) {\n const out: unknown[] = [];\n for (const item of node) out.push(compactNode(item));\n // 重建副本与原值同构(仅少 span 键)——与 structuredClone 同款「unknown → T」定型需求,断言无法避免\n // oxlint-disable-next-line no-unsafe-type-assertion\n return out as T;\n }\n if (node === null || typeof node !== \"object\") return node;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node)) {\n if (key === \"span\" || key === \"cavokSpan\") continue; // 剥除目标键:不进新对象(而非删除)\n out[key] = compactNode(value);\n }\n // 同上:键值逐项来自原对象(仅滤除 span),与 T 同构\n // oxlint-disable-next-line no-unsafe-type-assertion\n return out as T;\n}\n\n/** 天气组合词切分:把「TSRA」拆成描述符 TS + 现象 RA;无法合法切分返回 null。\n * outOfOrder = 能完整切解但语序不合电码表(描述符出现在现象之后,如 RATS=RA+TS)——\n * tolerant 纪律下仍按切解结果收下,由调用方追加 invalid-format 告警。\n * bare = 描述符单独编报(无现象)——TS 恒合法;SH 仅在 VC 邻近语境内合法(VCSH,\n * WMO 306 表 4678 注:机场附近有阵性降水但降水类型不可辨),由 parseWeatherBody 收口。 */\nfunction splitWeatherToken(body: string): {\n descriptor?: WeatherDescriptor;\n phenomena: readonly WeatherPhenomenon[];\n outOfOrder: boolean;\n bare: boolean;\n} | null {\n const chunks: string[] = [];\n for (let i = 0; i < body.length; i += 2) chunks.push(body.slice(i, i + 2));\n if (chunks.some((c) => c.length !== 2)) return null;\n const phenomena: WeatherPhenomenon[] = [];\n let descriptor: WeatherDescriptor | undefined;\n let sawPhenomenon = false;\n let outOfOrder = false;\n for (const c of chunks) {\n if (isPhenomenon(c)) {\n phenomena.push(c);\n sawPhenomenon = true;\n } else if (isDescriptor(c) && descriptor === undefined) {\n descriptor = c;\n if (sawPhenomenon) outOfOrder = true; // 电码表语序:描述符须先于现象\n } else return null;\n }\n if (phenomena.length === 0 && descriptor !== \"TS\" && descriptor !== \"SH\") return null; // TS/SH 单独编报见 bare 注\n return { descriptor, phenomena, outOfOrder, bare: phenomena.length === 0 };\n}\n\n/** 天气组词身解析:VC 邻近 / -+ 强度 / 双字母组合切分。返回 null 表示不是合法天气组。\n * signWithVc = 强度符与 VC 并存(-VCTSRA 家族,NWS 自动站实弹):4678 限定槽四选一\n * (light −/moderate 无符/heavy +/vicinity VC)、FAA AIM 明文互斥——tolerant 纪律下按切解\n * 收下(强度+邻近+现象语义可无损恢复,与 RATS→outOfOrder 容忍同构),由调用方出声。 */\nfunction parseWeatherBody(text: string): {\n intensity?: \"-\" | \"+\";\n proximity: boolean;\n descriptor?: WeatherDescriptor;\n phenomena: readonly WeatherPhenomenon[];\n outOfOrder: boolean;\n signWithVc: boolean;\n} | null {\n let rest = text;\n let proximity = false;\n let signWithVc = false;\n if (rest.startsWith(\"VC\")) {\n proximity = true;\n rest = rest.slice(2);\n }\n let intensity: \"-\" | \"+\" | undefined;\n const sign = rest.slice(0, 1);\n if (sign === \"-\" || sign === \"+\") {\n intensity = sign;\n rest = rest.slice(1);\n // 强度符后随 VC(-VCTSRA / -VCSH):非规范词序(规范语序 VC 在最前、强度符与 VC 互斥)\n if (rest.startsWith(\"VC\")) {\n proximity = true;\n signWithVc = true;\n rest = rest.slice(2);\n }\n }\n if (rest.length < 2 || rest.length % 2 !== 0) return null;\n const split = splitWeatherToken(rest);\n if (split === null) return null;\n // 裸 SH(无现象)仅在 VC 邻近形态合法(VCSH);非 VC 的裸 SH 是坏组不收\n if (split.bare && split.descriptor === \"SH\" && !proximity) return null;\n return {\n intensity,\n proximity,\n descriptor: split.descriptor,\n phenomena: split.phenomena,\n outOfOrder: split.outOfOrder,\n signWithVc,\n };\n}\n\n/**\n * 解析天气组 token(含 RE 前缀 / VC 邻近 / -+ 强度)。\n * 返回 kind「current」仅当组进入当前天气列表;「recent」= RE 近期天气(另一组位,不参与 weather 三态);\n * outOfOrder = 词身能切解但语序不合电码表;false = 不是天气组。\n */\n/** 强度符适用面(WMO 306 表 4678 注 4):降水全族可带 -/+;+SS/+FC/+DS 为 4678 表内合法电码\n * (codes.wmo.int/306/4678 稳定概念:+DS heavy duststorm、+SS heavy sandstorm、+FC 发展完好\n * 漏斗云;加拿大差异版另有官方能见度判据 <5/16 SM)——表内形态照常收下、零告警;\n * FMH-1 仅对降水族定义强度测定(美国实务不产 +DS),出处为 4678 电码表本身而非 FMH-1 容错。\n * (2026-09-14 口径归位:旧注释称「+DS 由调用方出声」与实现不符——它本就是表内电码。) */\nconst PRECIP_PHENOMENA = new Set<WeatherPhenomenon>([\n \"RA\",\n \"SN\",\n \"SG\",\n \"IC\",\n \"PL\",\n \"GR\",\n \"GS\",\n \"UP\",\n]);\nfunction intensityAllowedFor(\n intensity: \"-\" | \"+\",\n phenomena: readonly WeatherPhenomenon[],\n): boolean {\n if (phenomena.length > 0 && phenomena.every((x) => PRECIP_PHENOMENA.has(x))) return true;\n return intensity === \"+\" && phenomena.every((x) => x === \"SS\" || x === \"FC\" || x === \"DS\");\n}\n\nfunction tryWeatherToken(\n t: Token,\n weather: WeatherGroup[],\n recent: WeatherGroup[],\n):\n | {\n kind: \"current\" | \"recent\";\n outOfOrder: boolean;\n signWithVc: boolean;\n intensityMisuse?: boolean;\n }\n | false {\n const current = parseWeatherBody(t.text);\n if (current !== null) {\n const { outOfOrder, signWithVc, ...group } = current;\n weather.push({ ...group, span: spanOf(t) });\n return {\n kind: \"current\",\n outOfOrder,\n signWithVc,\n ...(current.intensity !== undefined &&\n !intensityAllowedFor(current.intensity, current.phenomena)\n ? { intensityMisuse: true }\n : {}),\n };\n }\n // RE 前缀(近期天气,15.13.2):REFC = RE + FC;RE 组不带强度符(15.13.2.1)\n if (t.text.startsWith(\"RE\")) {\n const recentBody = parseWeatherBody(t.text.slice(2));\n if (recentBody !== null) {\n const { outOfOrder, signWithVc: _signWithVc, ...group } = recentBody;\n recent.push({ ...group, span: spanOf(t) });\n return {\n kind: \"recent\",\n outOfOrder,\n signWithVc: false,\n ...(recentBody.intensity !== undefined ? { intensityMisuse: true } : {}),\n };\n }\n }\n return false;\n}\n\n/** 能见度解析结果三路:ok=有值;missing=显式缺测电码(//// 家族);\n * invalid=形态合法但值不可信(零分母 1/0SM——解码出 Infinity/NaN 的唯一入口),\n * 由调用方落 missing + value-out-of-range 告警(与 QNH 超界同款纪律,绝不留假值)。 */\ntype VisibilityResult =\n | { readonly kind: \"ok\"; readonly group: VisibilityGroup; readonly consumed: number }\n | {\n readonly kind: \"directional\";\n readonly group: { readonly value: number; readonly direction: string; readonly span: Span };\n readonly consumed: number;\n }\n | { readonly kind: \"missing\"; readonly consumed: number }\n | {\n readonly kind: \"invalid\";\n readonly message: string;\n readonly span: Span;\n readonly consumed: number;\n };\n\n/** 能见度:米制 4 位(可带 NDV 后缀)/ 美制 SM(含混分数跨 token 的预合并、P6SM 超上限)/ //// 缺测家族。 */\nfunction parseVisibilityToken(t: Token, next: Token | undefined): VisibilityResult | null {\n // 缺测家族两形态(与单位正交)://// = 米制缺测;////SM = 英里制缺测(加拿大自动站,\n // RMK VIS MISG 佐证)——同为 visibility missing + missing-expected 告警(单位不进 missing 态)\n if (t.text === \"////\" || t.text === \"////SM\") return { kind: \"missing\", consumed: 1 };\n // NDV = No Directional Variation(无方向变化,加拿大自动站惯例后缀)——\n // 语义为「能见度各方向一致」,IR 无落点:剥离丢弃(原码经组 span 回溯),按 4 位主体正常解析\n // 最低能见度方向组(VNVNVNVNDv,如 1200NW)——须在 m4 之前判(带 1–2 位方位后缀)\n const mDir = /^(\\d{4})(NE|NW|SE|SW|N|E|S|W)$/.exec(t.text);\n if (mDir !== null) {\n return {\n kind: \"directional\",\n group: {\n value: Number.parseInt(mDir[1] ?? \"0\", 10),\n direction: mDir[2] ?? \"\",\n span: spanOf(t),\n },\n consumed: 1,\n };\n }\n const m4 = /^(\\d{4})(NDV)?$/.exec(t.text);\n if (m4 !== null) {\n const digits = m4[1] ?? \"\";\n const ceiling = digits === \"9999\";\n // 0000 = 下限编码(<100m,与 9999 上限编码同族)——非实测 0 米,exact=false + beyond below\n const floor = digits === \"0000\";\n return {\n kind: \"ok\",\n group: {\n value: Number.parseInt(digits, 10),\n unit: \"m\",\n exact: !ceiling && !floor,\n ...(ceiling ? { beyond: \"above\" as const } : {}), // 9999 = 10km 或以上(上限编码)\n ...(floor ? { beyond: \"below\" as const } : {}), // 0000 = 不足下限(下限编码)\n span: spanOf(t),\n },\n consumed: 1,\n };\n }\n // 混分数跨 token:`1 1/4SM`(裸整数 + 带分数 SM 是一个组)\n if (/^\\d$/.test(t.text) && next !== undefined && /^\\d\\/\\d+SM$/.test(next.text)) {\n const whole = Number.parseInt(t.text, 10);\n const parts = next.text.slice(0, -2).split(\"/\");\n const num = parts[0];\n const den = parts[1];\n if (num === undefined || den === undefined) return null;\n if (Number(den) === 0) {\n // 零分母(1 0/0SM):解码结果 Infinity/NaN——值不可信判缺测(span 覆盖整数与分数两个 token)\n return {\n kind: \"invalid\",\n message: `能见度混分数分母为零(${t.text} ${next.text})——解码不出有限值,值不可信判缺测,原码经 span 回溯`,\n span: { start: t.start, end: next.end },\n consumed: 2,\n };\n }\n return {\n kind: \"ok\",\n group: {\n value: whole + Number(num) / Number(den),\n unit: \"sm\",\n exact: true,\n span: { start: t.start, end: next.end },\n },\n consumed: 2,\n };\n }\n const sm = /^(M|P)?(\\d+)\\/(\\d+)SM$|^(M|P)?(\\d+)SM$/.exec(t.text);\n if (sm !== null) {\n const prefix = sm[1] ?? sm[4];\n const below = prefix === \"M\";\n const above = prefix === \"P\"; // P6SM:6 英里以上(美式超上限,FAA/AF 口径)——exact=false,与 9999 同族\n const den = sm[3];\n if (den !== undefined && Number(den) === 0) {\n // 单 token 零分母(1/0SM、0/0SM、M1/0SM——0/0 解码出 NaN,同属值不可信)\n return {\n kind: \"invalid\",\n message: `能见度分数分母为零(${t.text})——解码不出有限值,值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n consumed: 1,\n };\n }\n const value =\n sm[2] !== undefined ? Number(sm[2]) / Number(den) : Number.parseInt(sm[5] ?? \"0\", 10);\n // exact 语义统一:分数(1/2SM、1 1/4SM)与整数本身是精确值;\n // 阈值性编码(M 前缀小于下界、P 前缀大于上界、9999 上限)为 false,beyond 记方向\n return {\n kind: \"ok\",\n group: {\n value,\n unit: \"sm\",\n exact: !below && !above,\n ...(below ? { beyond: \"below\" as const } : {}),\n ...(above ? { beyond: \"above\" as const } : {}),\n span: spanOf(t),\n },\n consumed: 1,\n };\n }\n return null;\n}\n\ninterface WindParsed {\n group: WindGroup;\n consumed: number;\n /** 越界发现(风向位/变化组端点 >360°):子项判缺测,由调用方落 value-out-of-range 告警 */\n rangeFindings: readonly { message: string; span: Span }[];\n /** 阵风位缺测(27010G//KT):组照常成立、gust 不设,由调用方落 missing-expected info */\n gustMissing?: boolean;\n}\n\n/** 风:33002MPS / VRB02KT / 31015G25KT / /////KT 缺测形态 + 260V050 变化组。 */\nfunction parseWindToken(t: Token, next: Token | undefined): WindParsed | \"missing\" | null {\n if (/^\\/{5}(KT|MPS|KMH)$/.test(t.text)) return \"missing\";\n // 部分缺测两形态(速度位 // / 阵风位 //,如 180//KT、27010G//KT)——此前整体落 unknown。\n // 超上限 P 前缀(P99KT/P49MPS,WMO 15.5.6 / AP-117 54 条):值存原码、beyond 标注超界端\n const m =\n /^(VRB|\\d{3}|\\/\\/\\/)(\\d{2,3}|P\\d{2}|\\/\\/\\/|\\/\\/)(?:G(\\d{2,3}|P\\d{2}|\\/\\/\\/|\\/\\/))?(KT|MPS|KMH)$/.exec(\n t.text,\n );\n if (m === null) return null;\n const span = spanOf(t);\n const dirRaw = m[1] ?? \"\";\n const speedRaw = m[2] ?? \"\";\n const unitRaw = (m[4] ?? \"kt\").toLowerCase();\n if (!isSpeedUnit(unitRaw)) return null;\n if (dirRaw === \"///\" || speedRaw === \"///\" || speedRaw === \"//\") return \"missing\";\n const variable = dirRaw === \"VRB\";\n const gustRaw = m[3];\n const speedBeyond = speedRaw.startsWith(\"P\") ? (\"above\" as const) : undefined;\n const gustBeyond =\n gustRaw !== undefined && gustRaw.startsWith(\"P\") ? (\"above\" as const) : undefined;\n const rangeFindings: { message: string; span: Span }[] = [];\n // 风向位 0–360(正北可编 360、静风 000 编 0):越界 = 值不可信 → 子项级判缺测(direction=null),\n // 风组其余子项(风速等)照常保留——两级建模:组内子项缺测 = 值字段 | null\n let direction: number | null = variable ? null : Number.parseInt(dirRaw, 10);\n if (!variable && direction !== null && direction > 360) {\n rangeFindings.push({\n message: `风向越界(${dirRaw},须 0–360)——风向位判缺测,原码经 span 回溯`,\n span,\n });\n direction = null;\n }\n let consumed = 1;\n let variation: WindGroup[\"variation\"];\n if (next !== undefined && /^\\d{3}V\\d{3}$/.test(next.text)) {\n const parts = next.text.split(\"V\");\n const min = parts[0];\n const max = parts[1];\n if (min !== undefined && max !== undefined) {\n const minDeg = Number.parseInt(min, 10);\n const maxDeg = Number.parseInt(max, 10);\n if (minDeg > 360 || maxDeg > 360) {\n // 变化组端点同为风向数值(0–360):任一越界即整组不可信 → 变化组判缺测(组已消费,不留假值)\n rangeFindings.push({\n message: `风向变化组端点越界(${next.text},须 0–360)——变化组判缺测,原码经 span 回溯`,\n span: spanOf(next),\n });\n } else {\n variation = { min: minDeg, max: maxDeg, span: spanOf(next) };\n }\n consumed = 2;\n }\n }\n // 阵风位缺测双形态:G 后 // (两位斜杠——2 字符场的逐字符惯例)与 /// (三斜杠磨损多一位,\n // 同按缺测建模——任何规范都无三斜杠形态,最合理的来源是 G// 的传输磨损;2026-09-14 补建模:\n // 此前 /// 走 parseInt 产 NaN 零告警入 IR,穿透缺测路由/gustMissing/值域门三道防线)\n const gustMissing = gustRaw === \"//\" || gustRaw === \"///\";\n const group: WindGroup = {\n variable,\n direction,\n speed: {\n value: Number.parseInt(speedRaw.startsWith(\"P\") ? speedRaw.slice(1) : speedRaw, 10),\n unit: unitRaw,\n span,\n ...(speedBeyond !== undefined ? { beyond: speedBeyond } : {}),\n },\n gust:\n gustRaw !== undefined && !gustMissing\n ? {\n value: Number.parseInt(gustRaw.startsWith(\"P\") ? gustRaw.slice(1) : gustRaw, 10),\n unit: unitRaw,\n span,\n ...(gustBeyond !== undefined ? { beyond: gustBeyond } : {}),\n }\n : undefined,\n variation,\n };\n return { group, consumed, rangeFindings, ...(gustMissing ? { gustMissing: true } : {}) };\n}\n\n/**\n * Temperature/dewpoint group shape: always dd/dd (M = negative; // on either side = that side missing).\n * 温度/露点组形态:恒为 dd/dd(M = 负;任一侧 // = 该侧缺测)——两位是形态定义本身,不是惯例:\n * WMO 电码表每个符号字母严格对应一位数字(T' 十位 / T 个位,负值加 M),官方示例含补零(01/M12、\n * 00/M00),任何规范版本无一位数形态。两侧 \\d{1,2} 曾让裸分数 token(VIS 词丢失的 1/2、2/1——\n * 上游脏输入)被误判为温露组:降序分数捏造假值且完全静默,升序触发误导性温露倒挂告警\n * (2026-09-14 复评收紧);不匹配即落 unknown-token 出声,原码经 span 回溯。\n * The regex requires the `/` separator — a bare \"//\" is the weather missing group (see the body loop) and must not be swallowed here.\n * 正则必须有 `/` 分隔——裸 `//` 是天气缺测组(见正文循环),不得被本组吞掉。\n * Exported for direct shape assertions in regression tests (red line: \"//\" must not match; \"1/2\"/\"2/1\" must not match either).\n * 导出供回归测试直接对形态断言(红线:对 \"//\" 与裸分数均不得匹配)。\n */\nexport const TEMP_DEW_PATTERN = /^(M?\\d{2}|\\/\\/)\\/(M?\\d{2}|\\/\\/)$/;\n\n/** 温度/露点组:恒为 dd/dd 形态(M = 负;// = 缺测 → null,调用方补告警)。 */\nfunction parseTempDewToken(t: Token): {\n temperature: TemperatureReading | null;\n dewpoint: TemperatureReading | null;\n span: Span;\n} | null {\n const read = (raw: string | undefined): TemperatureReading | null => {\n // undefined = 第二组整体缺失(FMH-1 12.6.10 露点缺测形态 24/);\"//\" = 显式缺测——\n // 两者同为 null,但 missing-expected 文案由调用方按形态区分\n if (raw === undefined || raw === \"//\") return null;\n const n = raw.startsWith(\"M\") ? -Number.parseInt(raw.slice(1), 10) : Number.parseInt(raw, 10);\n // −0 归一(M00 → 0):负零序列化变形(JSON 出 -0),消费方 Object.is 判别出边角差异\n const celsius = n === 0 ? 0 : n;\n return { celsius, span: spanOf(t) };\n };\n const m = TEMP_DEW_PATTERN.exec(t.text);\n if (m === null) {\n // FMH-1 12.6.10 露点缺测形态「24/」(第二组整体省略,同恒两位)——裸 // 与 /// 仍不得匹配\n const trailing = /^(M?\\d{2})\\/$/.exec(t.text);\n if (trailing === null) return null;\n return { temperature: read(trailing[1]), dewpoint: null, span: spanOf(t) };\n }\n return { temperature: read(m[1]), dewpoint: read(m[2]), span: spanOf(t) };\n}\n\nfunction beyondRangeOf(flag: string | undefined): \"above\" | \"below\" | undefined {\n if (flag === \"P\") return \"above\";\n if (flag === \"M\") return \"below\";\n return undefined;\n}\n\n/** RVR 组:R07R/1800V2200FT / R36/0500V0800D / P·M 超界 / 斜杠趋势(R13/3500FT/N、R07/P6000FT/U)。\n * R/SNOCLO 与 R10L/SNOCLO 属跑道状态语义(15.13.6.1),由 parseRunwayStateToken 收口。 */\nfunction parseRvrToken(t: Token): RunwayVisualRange | null {\n // 趋势后缀双形态:无斜杠(0500V0800D,WMO)与斜杠(3500FT/N,FAA/加式——FT 单位标记后带 /D //N //U)\n const m = /^R(\\d{2}[RLC]?)\\/(P|M)?(\\d{4})(?:V(P|M)?(\\d{4}))?(FT)?(?:\\/([DNU])|([DNU]))?$/.exec(\n t.text,\n );\n if (m === null) return null;\n const minRaw = m[3] ?? \"0\";\n const maxRaw = m[5];\n const trendRaw = m[7] ?? m[8];\n return {\n runway: m[1] ?? \"\",\n value: maxRaw === undefined ? Number.parseInt(minRaw, 10) : undefined,\n min: maxRaw !== undefined ? Number.parseInt(minRaw, 10) : undefined,\n max: maxRaw !== undefined ? Number.parseInt(maxRaw, 10) : undefined,\n beyondRange: beyondRangeOf(m[2] ?? m[4]),\n unit: m[6] === \"FT\" ? \"ft\" : \"m\",\n trend:\n trendRaw === \"U\"\n ? \"up\"\n : trendRaw === \"D\"\n ? \"down\"\n : trendRaw === \"N\"\n ? \"no-change\"\n : undefined,\n span: spanOf(t),\n };\n}\n\n/** 摩擦两位电码(15.13.6.1 表 0366)解码:01–90 → 摩擦系数 0.01–0.90;91–95 → 制动作用五档;\n * 99 → unreliable;// 或 96–98(电码表未用)→ 两字段皆 undefined(原码经 span 回溯)。 */\nfunction parseFrictionCode(\n code: string | undefined,\n): Pick<RunwayStateGroup, \"frictionCoefficient\" | \"brakingAction\"> {\n if (code === undefined || !/^\\d{2}$/.test(code)) return {};\n const f = Number.parseInt(code, 10);\n if (f <= 90) return { frictionCoefficient: f / 100 };\n if (f >= 91 && f <= 95)\n return {\n brakingAction: ([\"poor\", \"medium-poor\", \"medium\", \"medium-good\", \"good\"] as const)[f - 91],\n };\n if (f === 99) return { brakingAction: \"unreliable\" };\n return {};\n}\n\n/** 跑道状态组三形态(WMO 15.13.6):①六位状态电码(R21/490160:沉积/覆盖/深度/摩擦,位缺测 /);\n * ②CLRD 清除家族(R07L/CLRD// 标准、CLRD62 俄区、CLRD/// 非标容忍);③SNOCLO 关闭(R/SNOCLO 全机场、R10L/SNOCLO 逐跑道)。\n * 覆盖位非法电码(表 0519 外数字)不静默留值:该位判缺测 + findings 交调用方落 invalid-format 告警。 */\nfunction parseRunwayStateToken(\n t: Token,\n): { group: RunwayStateGroup; findings: readonly { message: string; span: Span }[] } | null {\n // ③ SNOCLO(15.13.6.1):跑道因雪/冰/清雪不可用\n const snoclo = /^R(\\d{2}[RLC]?)?\\/SNOCLO$/.exec(t.text);\n if (snoclo !== null) {\n return {\n group: { runway: snoclo[1] ?? \"\", closed: true, cleared: false, span: spanOf(t) },\n findings: [],\n };\n }\n // ② CLRD 家族\n const clrd = /^R(\\d{2}[RLC]?)\\/CLRD(\\d{2}|\\/\\/|\\/\\/\\/)?$/.exec(t.text);\n if (clrd !== null) {\n return {\n group: {\n runway: clrd[1] ?? \"\",\n cleared: true,\n ...parseFrictionCode(clrd[2]),\n span: spanOf(t),\n },\n findings: [],\n };\n }\n // ① 六位状态电码:沉积物类型 1 位 + 覆盖范围 1 位 + 深度 2 位 + 摩擦 2 位(各可 / 缺报)\n const num = /^R(\\d{2}[RLC]?)\\/(\\d|\\/)(\\d|\\/)(\\d{2}|\\/\\/)(\\d{2}|\\/\\/)$/.exec(t.text);\n if (num === null) return null;\n const depthCode = num[4] ?? \"\";\n // 深度解码(15.13.6.1 表 1079):00–90 = 毫米(00 即 <1mm 记 0);91 未用判缺测;92–98 = 10–40cm 段记下限;\n // 99 = 跑道不可用(同 SNOCLO 语义 → closed,深度不落值)\n const depthNum = /^\\d{2}$/.test(depthCode) ? Number.parseInt(depthCode, 10) : null;\n const depth =\n depthNum === null\n ? null\n : depthNum <= 90\n ? depthNum\n : depthNum === 91\n ? null\n : depthNum === 99\n ? null\n : (depthNum - 90) * 50;\n // 覆盖位电码合法性(15.13.6.1 表 0519):表内仅 1/2/5/9 与 /——表外数字(0/3/4/6/7/8)为非法电码,\n // 按三态纪律判缺测(null)+ invalid-format 告警,绝不把表外值留在 IR(tgftp 实弹 R24/000062 命中位 2 的 0)\n const coverageCode = num[3] ?? \"/\";\n const coverageIllegal = coverageCode !== \"/\" && !\"1259\".includes(coverageCode);\n const findings: { message: string; span: Span }[] = coverageIllegal\n ? [\n {\n message: `跑道状态覆盖位电码非法(${t.text} 覆盖位 ${coverageCode}——WMO 表 0519 仅用 1/2/5/9 与 /)——该位判缺测,原码经 span 回溯`,\n span: spanOf(t),\n },\n ]\n : [];\n return {\n group: {\n runway: num[1] ?? \"\",\n closed: depthNum === 99 || undefined,\n cleared: false,\n deposit: num[2] === \"/\" ? null : Number(num[2]),\n coverage: coverageCode === \"/\" || coverageIllegal ? null : Number(coverageCode),\n depth,\n ...parseFrictionCode(num[5]),\n span: spanOf(t),\n },\n findings,\n };\n}\n\n// ---------------------------------------------------------------- 主入口\n\n/**\n * Parse one METAR/SPECI report (tolerant mode) into the IR — the package's single entry.\n * 解析单条 METAR/SPECI 报文(tolerant)为 IR——本包唯一入口。\n *\n * Throws MetarParseError (stable machine-readable `code`) on whole-report failure\n * (non-string input / missing station / missing time / invalid time / unsupported mode); anything the\n * parser does not recognize lands in `warnings[]` with its span — never dropped.\n * 整体失败(输入非字符串/无站名/无时组/时组越界/未实现模式)抛 MetarParseError(code 稳定契约);\n * 看不懂的组带 span 进 warnings[],绝不丢弃。\n * @param raw - Report text, verbatim (kept on report.raw). 报文原文(原样保真于 report.raw)。\n * @param options - See ParseOptions (kind override, compact spans). 见 ParseOptions(类型位注入、紧凑模式)。\n */\nexport function parse(raw: string, options?: ParseOptions): MetarReport {\n // 紧凑模式(E1):spans === false 时在出口以重建式剥除全部 span(见 compactNode 注释)\n const compact = options?.spans === false;\n const compactIfEnabled = <T>(report: T): T => (compact ? compactNode(report) : report);\n // 输入校验:非字符串走 MetarParseError 稳定契约(code: \"invalid-input\")——code 是\n // 消费方分流的稳定面、EN_MESSAGES 查表英化的键,裸 Error 会同时绕过两者(此前为裸 Error)\n if (typeof raw !== \"string\") {\n throw new MetarParseError(\n \"invalid-input\",\n String(raw),\n `parse 需要一个 METAR/SPECI 报文字符串,收到 ${raw === null ? \"null\" : typeof raw}`,\n );\n }\n if ((options?.mode ?? \"tolerant\") === \"strict\") {\n // 错误面契约:strict 留在类型上(路线图项),但 v0.1 未实现——调用方 catch 不漏接裸 Error\n throw new MetarParseError(\n \"unsupported-mode\",\n raw,\n \"strict 模式尚未实现(v0.1 仅 tolerant)——请省略 mode 或显式传 'tolerant'\",\n );\n }\n const warnings: ParseWarning[] = [];\n // 报尾 = 终结符剥离(GTS/AFTN 通路报文行以 = 定界,常粘连末组如 Q1006= / NOSIG=)——\n // 仅剥尾部空白与 =,正文 token 偏移不变,span 仍对应原 raw(raw 保真含 =)。\n // 末字符预判(E2 性能项):语料大头无报尾,尾字符既非 = 也非空白时跳过整串正则——\n // 预判用单字符 \\s 测试(与 [\\s=] 字符类完全同域,行为等价),省一次全文回溯扫描\n const tail = raw.at(-1);\n const body =\n tail === undefined || tail === \"=\" || /\\s/.test(tail) ? raw.replace(/[\\s=]+$/, \"\") : raw;\n const tokens = tokenize(body);\n // 输入规模护栏(只告警不截断——截断破坏 raw 保真与「不丢弃」纪律):语料单行最大 30 token,\n // 上限 128 = 4 倍余量;超限报文照常完整解析,仅以一条聚合告警标记异常输入\n //(span 缺省 = 报文级;整体失败路径不经过此处,失败契约不受影响)\n const TOKEN_COUNT_LIMIT = 128;\n if (tokens.length > TOKEN_COUNT_LIMIT) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `输入 token 数超上限(${tokens.length} > ${TOKEN_COUNT_LIMIT})——按异常输入标记,解析照常完整,原文经 raw 保真`,\n });\n }\n let i = 0;\n const peek = (ahead = 0): Token | undefined => tokens[i + ahead];\n\n const externalKind = options?.kind;\n let kind: ReportKind = externalKind ?? \"metar\";\n let corrected = false;\n let auto = false;\n\n // —— 头部:类型词 / COR(WMO 形态)/ 站名 / 时组 / AUTO / COR(美式时组后形态)\n const head = peek();\n if (head !== undefined && (head.text === \"METAR\" || head.text === \"SPECI\")) {\n if (externalKind === undefined) kind = head.text === \"SPECI\" ? \"speci\" : \"metar\";\n i += 1; // 类型词 token 无论由谁决定 kind 都要消费\n }\n if (peek()?.text === \"COR\") {\n corrected = true;\n i += 1;\n }\n // AMD(修订发布标志,部分 CAA 用于 METAR 标题位,TAF 更常见):标题元数据词,\n // 语义为「本报告取代此前发布」——消费之不进站名位;是否置 corrected 不越权代判\n //(修订 ≠ 更正),IR 无 amended 位故仅放行不标注\n if (peek()?.text === \"AMD\") {\n i += 1;\n }\n const stTok = peek();\n if (stTok === undefined || !/^[A-Z0-9]{4}$/.test(stTok.text)) {\n // 契约:无站名组 = 整体解析失败(不是字段级三态);code 是稳定契约,message 中文为权威\n // 文案——英文经 @metweave/core EN_MESSAGES[code] 查表或渲染层 locale:\"en\" 切换\n throw new MetarParseError(\n \"missing-station\",\n raw,\n `无法识别站名组——输入不是 METAR/SPECI 报文(${stTok?.text ?? \"空输入\"})`,\n );\n }\n const station: string = stTok.text;\n i += 1;\n // CCA/CCB/CCC 与 COR 槽位磨损兜底(站名后/时组前——规范槽位:BBB 系列在时组后(见下方\n // BBB 消费位)、COR 在类型词位(见报头 COR 位)):部分 feed 的更正标记出现在此槽——此前\n // 直接 throw missing-time,「合法更正报整体失败」是最恶性失败模式。后随 token 为合法时组时\n // 消费放行并置 corrected + 出声(槽位漂移本身须可观测——不静默,2026-09-14 独立复评补\n // COR 对称缺口与出声);后随非时组则照旧走 missing-time。已知留案:标记若出现在 AUTO\n // 之前的其他相对序(如 CCA AUTO),AUTO 会落正文 unknown——语料无实证,暂不设防\n const driftTok = peek();\n if (driftTok !== undefined && /^(CC[A-Z]|COR)$/.test(driftTok.text)) {\n const afterDrift = peek(1);\n if (afterDrift !== undefined && /^\\d{2}\\d{2}\\d{2}Z$/.test(afterDrift.text)) {\n corrected = true;\n i += 1;\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `更正标记槽位漂移(${driftTok.text} 出现在站名后/时组前——已消费并置更正标志)`,\n span: spanOf(driftTok),\n });\n }\n }\n const tmTok = peek();\n const tm = tmTok !== undefined ? /^(\\d{2})(\\d{2})(\\d{2})Z$/.exec(tmTok.text) : null;\n if (tmTok === undefined || tm === null) {\n throw new MetarParseError(\n \"missing-time\",\n raw,\n `无法识别时组——输入不是完整的 METAR/SPECI 报文(${tmTok?.text ?? \"时组缺失\"})`,\n );\n }\n const time: MetarReport[\"time\"] = {\n day: Number.parseInt(tm[1] ?? \"0\", 10),\n hour: Number.parseInt(tm[2] ?? \"0\", 10),\n minute: Number.parseInt(tm[3] ?? \"0\", 10),\n };\n // 契约:时组为两态必填(无缺测形态,无 Observed)——数值越界即不可信时组,等同无效时组整体失败,\n // 绝不把假值(日 99、时 24、分 60)留在 IR(同 Q10054 脏 QNH 的「值不可信」纪律,时组无处判缺测故整体失败)\n if (time.day < 1 || time.day > 31 || time.hour > 23 || time.minute > 59) {\n throw new MetarParseError(\n \"invalid-time\",\n raw,\n `时组数值越界(${tmTok.text}:须日 01–31 / 时 00–23 / 分 00–59)——输入不是完整的 METAR/SPECI 报文`,\n );\n }\n i += 1;\n if (peek()?.text === \"AUTO\") {\n auto = true;\n i += 1;\n }\n if (peek()?.text === \"COR\") {\n corrected = true;\n i += 1;\n }\n // RRA/RRB/RRC 迟到报标记(AP-117-TM-01R2 第 21 条:报头时间组后)——标题元数据,消费放行\n if (/^RR[ABC]$/.test(peek()?.text ?? \"\")) {\n i += 1;\n }\n // CCA/CCB/CCC 更正指示符(WMO FM15 §1.3.3 BBB 系列:第一次更正 CCA、第二次 CCB 顺延;\n // 规范槽位即本位——时组后。加拿大 NAV CANADA 明文采用,中国 AFTN 实务沿用;仓库声明的\n // 编码基准含 MANOPS-MET)。语义即更正报——与 COR 同义异位(COR 在类型词位、BBB 在时组后位),\n // 消费并置 corrected;此前落 unknown-token,更正语义丢失(2026-09-14 复评:基准内形态未实现)\n if (/^CC[A-Z]$/.test(peek()?.text ?? \"\")) {\n corrected = true;\n i += 1;\n }\n\n // —— NIL:台站无观测(FM15 代码形注 2 的 NIL 码词;§15.4 是 AUTO 条款)——最小形态:站名/时组凭据保留,正文组不解析(本就无正文),零告警\n if (peek()?.text === \"NIL\") {\n return compactIfEnabled({\n kind,\n raw,\n nil: true,\n station,\n time,\n flags: { auto, corrected },\n cavok: false,\n trends: [],\n runwayStates: [],\n remarks: [],\n warnings,\n });\n }\n\n // —— 正文状态\n let cavok = false;\n let cavokSpan: Span | undefined;\n let wind: Observed<WindGroup> | undefined;\n let visibility: Observed<VisibilityGroup> | undefined;\n // 脱离主导能见度的方向组被按主导收下的局部标记(见正文循环方向组分支注释;非 IR 字段)\n let directionalAsPrimary = false;\n let rvr: Observed<readonly RunwayVisualRange[]> | undefined;\n const rvrList: RunwayVisualRange[] = [];\n // 多组 RVR 的组级 span 首组至末组(与天气组同口径——单组 span 在各自元素上)\n let rvrSpan: Span | undefined;\n let weather: Observed<readonly WeatherGroup[]> | undefined;\n const weatherList: WeatherGroup[] = [];\n const recentList: WeatherGroup[] = [];\n let clouds: CloudCondition | undefined;\n let cloudSeen = false;\n const cloudElements: CloudElement[] = [];\n let clearCode: CloudCondition[\"clear\"];\n let temperature: TemperatureReading | undefined;\n let dewpoint: TemperatureReading | undefined;\n let altimeter: AltimeterReading | undefined;\n // 双气压组口径(tolerant 惯例):末组为准(保持既有 last-wins 行为),重复组追加 info 告警不静默\n let altimeterSeen = false;\n const setAltimeter = (reading: AltimeterReading): void => {\n if (altimeterSeen) {\n dupGroupWarning(\"气压组\", altimeter?.span, reading.span);\n }\n altimeterSeen = true;\n altimeter = reading;\n };\n const trends: TrendGroup[] = [];\n const runwayStates: RunwayStateGroup[] = [];\n const remarks: RemarkGroup[] = [];\n // 重复组口径(与双气压组同款 tolerant 惯例):末组为准(保持既有 last-wins 行为),\n // 重复组出声不静默——专用码 duplicate-group(2026-09-15 五角色评测定案:此前借用\n // cross-check-conflict+info,消费方无法按「重复」分流;severity 升 warning)。\n // 前值后值原文都进 message:last-wins 会覆盖 IR 里的前值 span,前值唯一可回溯通道就是这条告警\n const dupGroupWarning = (\n label: string,\n prevSpan: Span | undefined,\n newSpan: Span | undefined,\n ): void => {\n const prevText =\n prevSpan === undefined ? `(原${label})` : raw.slice(prevSpan.start, prevSpan.end);\n const newText = newSpan === undefined ? label : raw.slice(newSpan.start, newSpan.end);\n warnings.push({\n code: \"duplicate-group\",\n severity: \"warning\",\n message: `重复${label}(前值 ${prevText},后值 ${newText})——报文只应有一组${label},以末组为准,前值经原文回溯`,\n span: newSpan,\n });\n };\n // 趋势段收口可观测性:R 组收口(RVR/跑道状态不属趋势要素)沿用既有口径出声;\n // 其余非趋势组收口(温露/QNH/WS/TX/TN/RVRNO/无法认领 token 等——2026-09-14 收窄新增)\n // 同样出声 info:该组交回正文循环认组(typed 语义无损恢复,冲突自然触发重复组告警),\n // 但趋势语境存疑须可观测——不静默。RMK/RMK 粘连与趋势指示组切换(含粘连形\n // BECMGAT0130——它本身就是趋势指示组,下一步由正文粘连分支认领)、以及规范报尾位 $\n // (FMH-1:$ 为整报最后一组,趋势段后随 $ 属规范位置)不出声(2026-09-14 独立复评补豁免)。\n const trendCloseWarning = (): void => {\n const btTok = tokens[i];\n const bt = btTok?.text;\n if (bt === undefined || btTok === undefined) return;\n if (TREND_KINDS.has(bt) || bt.startsWith(\"RMK\") || bt === \"$\") return;\n if (/^(BECMG|TEMPO)(AT|TL|FM)\\d{4}$/.test(bt)) return; // 粘连指示组:由正文粘连分支认领\n if (/^R(\\d{2}[RLC]?\\/|\\/SNOCLO$)/.test(bt)) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `趋势段收口于 R 组(${bt}——RVR/跑道状态不属趋势要素,按正文组处理,趋势语境存疑)`,\n span: spanOf(btTok),\n });\n return;\n }\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `趋势段收口于非趋势组(${bt}——不属趋势要素族,交回正文认组,趋势语境存疑)`,\n span: spanOf(btTok),\n });\n };\n // 趋势段收组:仅封闭清单内 token 收进 collected(判据见 isTrendCollectible),其余留在\n // tokens[i] 交回正文循环——三处收集入口(指示组/粘连/裸时段词)共用一份循环防漂移\n const collectTrendTokens = (collected: Token[]): void => {\n for (;;) {\n const inner = tokens[i];\n if (inner === undefined || !isTrendCollectible(inner, tokens[i + 1])) break;\n collected.push(inner);\n i += 1;\n }\n };\n // CAVOK 三面交叉校验(能见度/天气/云)。词位时对「前序」组校验;正文循环收口后对「后续」\n // 组再校验——CAVOK 让位发生在词位,其后再出现的矛盾组此前静默并存(CAVOK BKN012 形态)。\n // 判据词位/词后完全一致:确定矛盾才告警(下界编码/真值天气/低云或对流云;缺测云高不判)。\n // 告警 span 统一指 CAVOK 词位(既有契约:矛盾双方中「主张」所在)。\n const cavokConflicts = (whenLabel: string): void => {\n const at = cavokSpan;\n if (visibility?.kind === \"value\") {\n const g = visibility.value;\n const meters = g.unit === \"m\" ? g.value : g.value * 1609.344;\n const visRaw =\n visibility.span === undefined\n ? `${g.value} ${g.unit}`\n : raw.slice(visibility.span.start, visibility.span.end);\n const definitelyBelow =\n g.beyond === \"below\" ||\n (g.unit === \"sm\" && visRaw.startsWith(\"M\")) ||\n (g.exact && meters < 10_000);\n if (definitelyBelow) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}能见度组矛盾(${visRaw},CAVOK 语义要求 ≥10km)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n }\n if (weatherList.length > 0) {\n const wxRaw = weatherList\n .map(\n (g) =>\n `${g.proximity ? \"VC\" : \"\"}${g.intensity ?? \"\"}${g.descriptor ?? \"\"}${g.phenomena.join(\"\")}`,\n )\n .join(\" \");\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}天气组矛盾(${wxRaw},CAVOK 语义要求无重要天气)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n if (rvr !== undefined && rvr.kind === \"value\") {\n const rvrRaw = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}RVR 组矛盾(${rvrRaw}——AP-117 第 140 条:CAVOK 代替能见度、跑道视程、现在天气和云)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n const cloudConflict = cloudElements.some((e) => {\n if (e.kind === \"layer\" && e.convective !== undefined) return true;\n const h = e.heightFt.value;\n return h !== null && h < 5_000;\n });\n if (cloudConflict) {\n const cloudRaw = cloudElements\n .map(\n (e) =>\n `${e.kind === \"layer\" ? (e.amount ?? \"///\") : \"VV\"}${\n e.heightFt.value === null\n ? \"///\"\n : String(Math.round(e.heightFt.value / 100)).padStart(3, \"0\")\n }${e.kind === \"layer\" ? (e.convective ?? \"\") : \"\"}`,\n )\n .join(\" \");\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `CAVOK 与${whenLabel}云组矛盾(${cloudRaw},CAVOK 语义要求 5000ft 以下无云且无 CB/TCU)——让位照旧,报文自洽性存疑`,\n span: at,\n });\n }\n };\n // 风切变组累积器(同报多组 WS 合一:runways 连接、span 首组至末组)\n let windShear: WindShearGroup | undefined;\n let wsRunways: string[] | undefined;\n let wsAll = false;\n let wsSpan: Span | undefined;\n\n // —— 正文循环(RMK 交段外处理)\n while (i < tokens.length) {\n const t = tokens[i];\n if (t === undefined) break;\n const text = t.text;\n\n if (text === \"RMK\") {\n i += 1;\n break;\n }\n // RMK 磨损粘连(RMKQFE749/0998 = RMK 与后组丢空格,fuzz 实弹 35/5 万例命中):进 RMK 段\n // 但不跳过 token 本身——由 RMK 段按认组粒度收下(多为 unknown,raw 保真不蒸发)\n if (text.startsWith(\"RMK\")) {\n break;\n }\n\n // 趋势指示组:NOSIG / BECMG / TEMPO(吞到下一个指示组、RMK 或结尾)\n if (TREND_KINDS.has(text)) {\n const kindText = text;\n const collected: Token[] = [t];\n i += 1;\n let period: TrendGroup[\"period\"];\n const periodTok = peek();\n if (\n kindText !== \"NOSIG\" &&\n periodTok !== undefined &&\n // 时段词双形态:AT/TL/FM+DDHH(WMO 306 FM15 §15.14.3)与 DDHH/DDHH 斜杠时段\n //(ICAO Annex 3 模板 / 中国民航主流编法,2026-09-16 五方实测评测发现的缺失形态)\n (/^(?:AT|FM|TL)\\d{4}$/.test(periodTok.text) || /^\\d{4}\\/\\d{4}$/.test(periodTok.text))\n ) {\n period = { text: periodTok.text, span: spanOf(periodTok) };\n collected.push(periodTok);\n i += 1;\n }\n // 收口语义见 isTrendCollectible:仅趋势合法要素族可收,其余收口交回正文(trendCloseWarning 出声)\n collectTrendTokens(collected);\n trendCloseWarning();\n const elements =\n kindText === \"NOSIG\"\n ? undefined\n : structureTrendElements(collected, period !== undefined ? 2 : 1);\n trends.push({\n kind: kindText === \"NOSIG\" ? \"nosig\" : kindText === \"BECMG\" ? \"becmg\" : \"tempo\",\n period,\n ...(elements !== undefined ? { elements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n continue;\n }\n\n // 指示组缺失趋势段两形态——传输磨损所致(WMO 306 FM15 §15.14.3 时段词 AT/TL/FM 不得脱离指示组):\n // ①粘连——指示组与时段词丢空格(BECMGTL0350,IEM 归档实弹 10 次):宽容拆分,语义完整可恢复;\n // ②裸时段词——指示组整组丢失(Q1009 TL0730 …,IEM 归档实弹 128 次):按 kind 'unspecified'\n // 收段(要素组不再散落正文——尤其防趋势风组以 last-wins 覆盖正文真风组),告警标注指示组不可辨。\n // NOSIG 粘连不拆(NOSIG 语义上不配时段词);标准位置的时段词已在上方指示组分支内消费,此处不重复触达。\n if (\n (text.length === 6 &&\n (text.charCodeAt(0) === 65 || text.charCodeAt(0) === 84 || text.charCodeAt(0) === 70)) ||\n text.startsWith(\"BECMG\") ||\n text.startsWith(\"TEMPO\")\n ) {\n const fused = /^(BECMG|TEMPO)((?:AT|TL|FM)\\d{4}|\\d{4}\\/\\d{4})$/.exec(text);\n if (fused !== null) {\n const indicator = fused[1] ?? \"\";\n const collected: Token[] = [t];\n i += 1;\n collectTrendTokens(collected);\n trendCloseWarning();\n const fusedElements = structureTrendElements(collected, 1);\n trends.push({\n kind: indicator === \"BECMG\" ? \"becmg\" : \"tempo\",\n period: {\n text: text.slice(indicator.length),\n span: { start: t.start + indicator.length, end: t.end },\n },\n ...(fusedElements !== undefined ? { elements: fusedElements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `趋势指示组与时段词粘连(${text}——传输磨损丢空格,BECMG/TEMPO 与 AT/TL/FM 时段语义完整可恢复)`,\n span: spanOf(t),\n });\n continue;\n }\n if (/^(AT|TL|FM)\\d{4}$/.test(text)) {\n const collected: Token[] = [t];\n i += 1;\n collectTrendTokens(collected);\n trendCloseWarning();\n const bareElements = structureTrendElements(collected, 1);\n trends.push({\n kind: \"unspecified\",\n period: { text, span: spanOf(t) },\n ...(bareElements !== undefined ? { elements: bareElements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `趋势时段词缺指示组(${text}——§15.14.3 时段词须随 BECMG/TEMPO 出现)——按指示组缺失的趋势段收下,指示组类型不可辨`,\n span: spanOf(t),\n });\n continue;\n }\n }\n // 裸斜杠时段词(1616/1618——ICAO Annex 3 模板 / 中国民航主流趋势时段编法,指示组缺失):\n // 与 AT/TL/FM 裸词同纪律——kind 'unspecified' 收段出声,要素组不再散落正文\n //(2026-09-16 五方实测评测发现:此前该形态散落正文,趋势能见度以 last-wins 顶掉正文能见度)。\n // 前置守卫(长度 9 + 第 5 字符为斜杠)保正文热路径不为逐 token 正则付费\n if (text.length === 9 && text.charCodeAt(4) === 47 && /^\\d{4}\\/\\d{4}$/.test(text)) {\n const collected: Token[] = [t];\n i += 1;\n collectTrendTokens(collected);\n trendCloseWarning();\n const bareElements = structureTrendElements(collected, 1);\n trends.push({\n kind: \"unspecified\",\n period: { text, span: spanOf(t) },\n ...(bareElements !== undefined ? { elements: bareElements } : {}),\n raw: collected.map((c) => c.text).join(\" \"),\n span: joinSpan(collected),\n });\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `趋势时段词缺指示组(${text}——ICAO Annex 3 模板趋势时段须随 BECMG/TEMPO 出现)——按指示组缺失的趋势段收下,指示组类型不可辨`,\n span: spanOf(t),\n });\n continue;\n }\n\n if (text === \"CAVOK\") {\n cavok = true;\n cavokSpan = spanOf(t);\n // 交叉校验(三面:能见度/天气/云,判据见 cavokConflicts 注)——CAVOK 语义要求能见度\n // ≥10km、无重要天气、5000ft 以下无云且无 CB/TCU;前序组确定矛盾即出声。\n // 下界语义的编码(9999 ≥10km、P6SM >9.6km)与 CAVOK 相容不告警;M 前缀(小于下界)必矛盾。\n // 让位契约照旧(vis/weather/cloud 三组让位),矛盾仅追加 cross-check-conflict 告警\n cavokConflicts(\"前序\");\n // 契约(IR):CAVOK = 能见度 ≥10km + 无低云 + 无天气,前序 vis/weather/cloud 三组让位为 undefined\n // (让位是契约行为不发告警;词位以 cavokSpan 标记,前序组原码仍可从 raw 回溯)\n visibility = undefined;\n directionalAsPrimary = false;\n weather = undefined;\n weatherList.length = 0;\n cloudSeen = false;\n cloudElements.length = 0;\n clearCode = undefined;\n i += 1;\n continue;\n }\n\n // E3 性能项——首字符位掩码分流:每轮按首字符一次 switch 得「可能匹配的分支」位集,\n // 各分支先做一次位测试再进正则——不可能匹配的分支零正则尝试。分支相对顺序与原\n // 全试链完全一致(行为等价由全量语料回放快照锁定)。可达首字符推导:\n // 风 V/数字//;能见度 数字//M/P;RVRNO 与 R 组 R;天气 = 现象/描述符首字母\n // (B D F G H I M P R S T U)+ -/+/V(VC);裸 // 与云 /;云 F/S/B/O//;\n // VV 与 VIS 的 V;晴空词 S/N/C;温露 M/数字//;QNH 的 Q;A 组的 A;维护符 $。\n const mask = maskOf(text.charCodeAt(0));\n\n // 风(含 /////KT 缺测与 260V050 变化组)\n const windParsed = (mask & M_WIND) !== 0 ? parseWindToken(t, peek(1)) : null;\n if (windParsed !== null) {\n if (wind !== undefined) dupGroupWarning(\"风组\", wind.span, spanOf(t));\n if (windParsed === \"missing\") {\n if (wind === undefined) {\n wind = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 全缺测 /////KT(自动站假报文形态)与部分缺测(180//KT 风速位缺)同口径出声\n message: t.text.startsWith(\"/////\")\n ? \"风组缺测(/////KT,疑似自动站假报文形态)\"\n : `风组缺测(${t.text},风速位缺测)`,\n span: spanOf(t),\n });\n }\n // 已有风组时:缺测电码不顶替在场值(duplicate-group 已出声)——\n // 零信息量的缺测码按 last-wins 覆盖真实观测是纯信息损失(2026-09-15 五角色评测批)\n i += 1;\n } else {\n const wg = windParsed.group;\n // 风速模板上限:三位数(≤199,WMO 15.5.6「100 单位以上以精确位数替代两位电码」注至\n // 199;FMH-1 12.6.5.a「two or three digits」)——超 199 即非规范报文(270250KT 构造探针),\n // 按 QNH 超界同款纪律整组不可信判缺测,绝不静默留假值。P 前缀超上限形态(P99KT)合法\n // NaN 终结防线(终结断言,预期不可达):任何数值入口产 NaN 即整组不可信判缺测。\n // NaN 恰是现有防线的双重盲区——值域门 >199 对 NaN 恒 false、JSON.stringify 消 NaN 为\n // null、fuzz 不变量(2026-09-14 实弹 G/// 之前)无有限性检查——故独立成支并配哨兵不变量\n if (\n !Number.isFinite(wg.speed.value) ||\n (wg.gust !== undefined && !Number.isFinite(wg.gust.value))\n ) {\n wind = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `风组解码出非有限值(${t.text})——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else if (wg.speed.value > 199 || (wg.gust?.value ?? 0) > 199) {\n wind = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `风速超出编码范围(${t.text},三位数模板上限 199 ${wg.speed.unit})——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else {\n wind = { kind: \"value\", value: wg, span: spanOf(t) };\n for (const finding of windParsed.rangeFindings) {\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: finding.message,\n span: finding.span,\n });\n }\n if (windParsed.gustMissing === true) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 缺测电码双形态(G// 标准两位 / G/// 磨损三斜杠)直出原文\n message: `阵风位缺测(${t.text}——G 后斜杠位缺测,组照常成立)`,\n span: spanOf(t),\n });\n }\n if (wg.variable && wg.variation !== undefined) {\n const vs = wg.variation.span;\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `静风变向(VRB)与风向变化组(${\n vs === undefined ? \"\" : raw.slice(vs.start, vs.end)\n })并存——VRB 本义方向不定,变化组冗余,报文自洽性存疑`,\n span: vs,\n });\n }\n }\n i += windParsed.consumed;\n }\n continue;\n }\n\n // 能见度(//// 显式缺测补 info 告警——对齐风/天气缺测口径;零分母判缺测补超界告警)\n const visParsed = (mask & M_VIS) !== 0 ? parseVisibilityToken(t, peek(1)) : null;\n if (visParsed !== null) {\n // 最低能见度方向组(WMO 15.6.2):挂到已存主导能见度(非重复组不出 duplicate 告警);\n // 脱离主导能见度单独出现属非规范形态——按能见度收下 + info 出声。\n // directionalAsPrimary = 脱离主导的方向组被按主导收下(非规范状态,解析器局部标记)——\n // 其后再来的方向组是「连挂第二枚」(1200NW 1200NE),同样出声不静默\n //(2026-09-14 独立复评补齐:此前连挂时第二枚静默覆写第一枚)\n if (visParsed.kind === \"directional\") {\n if (visibility?.kind === \"value\") {\n if (visibility.value.minimum !== undefined || directionalAsPrimary) {\n dupGroupWarning(\"最低能见度方向组\", visibility.value.minimum?.span, spanOf(t));\n }\n visibility = {\n kind: \"value\",\n value: {\n ...visibility.value,\n minimum: {\n value: visParsed.group.value,\n direction: visParsed.group.direction,\n span: visParsed.group.span,\n },\n },\n span: visibility.span,\n };\n } else {\n visibility = {\n kind: \"value\",\n value: {\n value: visParsed.group.value,\n unit: \"m\",\n exact: true,\n span: visParsed.group.span,\n },\n };\n directionalAsPrimary = true;\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `最低能见度方向组脱离主导能见度(${t.text})——按能见度收下`,\n span: spanOf(t),\n });\n }\n i += visParsed.consumed;\n continue;\n }\n if (visibility !== undefined) dupGroupWarning(\"能见度组\", visibility.span, spanOf(t));\n if (visParsed.kind === \"missing\") {\n if (visibility === undefined) {\n visibility = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 缺测电码两形态直出原文(//// 米制 / ////SM 英里制——加拿大自动站,RMK VIS MISG 佐证)\n message: `能见度组缺测(${t.text},无法观测能见度)`,\n span: spanOf(t),\n });\n }\n // 已有能见度组时:缺测电码不顶替在场值(duplicate-group 已出声)——\n // 后位 ////(温露位畸形/错位落点)按 last-wins 把 9999 冲成 missing 是纯信息损失\n //(2026-09-15 五角色评测批;WMO 正常报文能见度缺测只出现在能见度槽位,此形态仅见于错位/磨损报文)\n directionalAsPrimary = false;\n i += visParsed.consumed;\n continue;\n } else if (visParsed.kind === \"invalid\") {\n visibility = { kind: \"missing\", span: visParsed.span };\n directionalAsPrimary = false;\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: visParsed.message,\n span: visParsed.span,\n });\n } else {\n visibility = { kind: \"value\", value: visParsed.group, span: visParsed.group.span };\n directionalAsPrimary = false;\n }\n i += visParsed.consumed;\n continue;\n }\n\n // RVRNO:RVR 设备存在但明示不可用(显式缺测,区别于组省略)。\n // 正文位与 RMK 位行为统一(2026-09-15 方案一,专业判读定案):一律进 remarks(kind\n // 'rvr-no')——站级状态声明 typed 可见,原正文位不留痕的双标消除;RVRNO 单独出现\n //(此前无值组)仍 = rvr 显式缺测(既有 IR 契约不变)。\n // 值组与 RVRNO 并存 = 自相矛盾形态(规范未定义并存):值组按跑道级明细保留——具体\n // 值组是逐道运行信息、可信度高于无道号的站级状态码(预报员/塔台标准判读;NWS 官方\n // 解码器即「值组 + RVRNO 旗标并存不复算」),矛盾出声、文案描述矛盾本身不预言终态。\n if ((mask & M_R) !== 0 && text === \"RVRNO\") {\n if (rvr?.kind === \"value\") {\n const prevText = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `RVRNO(站级:应报而缺)与 RVR 值组并存(${prevText})——矛盾形态,值组按跑道级明细保留,RVRNO 经 remarks/raw 可回溯`,\n span: spanOf(t),\n });\n } else {\n rvr = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"RVR 设备在但明示不可用(RVRNO)\",\n span: spanOf(t),\n });\n }\n remarks.push({ kind: \"rvr-no\", raw: text, span: spanOf(t) });\n i += 1;\n continue;\n }\n\n // RVR 与跑道状态(同为 R 前缀组,先按 RVR 语法试解、再按跑道状态电码试解)\n if ((mask & M_R) !== 0 && text.startsWith(\"R\") && text.includes(\"/\")) {\n const rvrParsed = parseRvrToken(t);\n if (rvrParsed !== null) {\n // 反向次序对称口径:RVRNO 在前、值组在后同样出声(方案一:可解读为传感器恢复,\n // 值组按明细保留——与正序矛盾并存同一文案口径,见 RVRNO 位注释)\n if (rvr?.kind === \"missing\") {\n const prevText = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `RVRNO(站级:应报而缺)与后随 RVR 值组并存(${prevText})——矛盾形态,值组按跑道级明细保留(可解读为传感器恢复),RVRNO 经 remarks/raw 可回溯`,\n span: spanOf(t),\n });\n }\n rvrList.push(rvrParsed);\n const s = spanOf(t);\n rvrSpan = rvrSpan === undefined ? s : { start: rvrSpan.start, end: s.end };\n rvr = { kind: \"value\", value: [...rvrList], span: rvrSpan };\n i += 1;\n continue;\n }\n const runwayState = parseRunwayStateToken(t);\n if (runwayState !== null) {\n runwayStates.push(runwayState.group);\n for (const finding of runwayState.findings) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: finding.message,\n span: finding.span,\n });\n }\n i += 1;\n continue;\n }\n // RVR 全斜杠缺测:R## + / + ////(分离符 + 四位值位斜杠 = 5 斜杠,标准缺测形态)。\n // 依据:WMO 306 FM15 RVR 值位恒四位(VRVRVRVR),全斜杠即数值缺测(斜杠逐位填充的缺测惯例);\n // 4 斜杠(R10////)为磨损短一段——按缺测收下,另附 invalid-format info(tgftp/IEM 实弹均见)\n const rvrSlash = /^R\\d{2}[RLC]?(\\/{4,5})$/.exec(text);\n if (rvrSlash !== null) {\n rvr = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: `RVR 组缺测(${text}——跑道号在位、视程值位全斜杠)`,\n span: spanOf(t),\n });\n if ((rvrSlash[1] ?? \"\").length === 4) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `RVR 缺测段磨损(${text}——4 位斜杠对标准 5 位(分离符 + 四位值位),少一位;按缺测收下)`,\n span: spanOf(t),\n });\n }\n i += 1;\n continue;\n }\n }\n\n // 风切变组(WMO 306 FM15 §15.13.3 / ICAO Annex 3 模板):标准形态 WS ALL RWY(全部跑道)\n // 与 WS R##[RLC](WS RDRDR,如 WS R24——IEM 归档实弹 544 次、中国区多发且为近月主流形态)。\n // 中国区实务变体 WS RWY##[RLC](RWY 前缀 + 设计器,教材常用)与 WS RWY ALL(词序倒置)\n // 同样语义无损一等收下——四形态正文组(跑道状态之后、趋势之前)。\n // 低空风切变对起降阶段是重大危害,IR 一等字段不蒸发。\n if ((mask & M_WS_RWY) !== 0 && text === \"WS\") {\n const rwyTok = peek(1);\n const designator = rwyTok !== undefined ? /^RWY(\\d{2}[RLC]?)$/.exec(rwyTok.text) : null;\n const stdDesignator = rwyTok !== undefined ? /^R(\\d{2}[RLC]?)$/.exec(rwyTok.text) : null;\n // 全跑道两形态:标准 WS ALL RWY 与词序倒置变体 WS RWY ALL\n const isAll =\n (rwyTok?.text === \"ALL\" && peek(2)?.text === \"RWY\") ||\n (rwyTok?.text === \"RWY\" && peek(2)?.text === \"ALL\");\n if (designator !== null || isAll || stdDesignator !== null) {\n const endTok = isAll ? peek(2) : rwyTok;\n const startSpan = spanOf(t);\n const endSpan = endTok !== undefined ? spanOf(endTok) : startSpan;\n wsRunways ??= [];\n if (designator !== null) wsRunways.push(designator[1] ?? \"\");\n if (stdDesignator !== null) wsRunways.push(stdDesignator[1] ?? \"\");\n if (isAll) wsAll = true;\n wsSpan =\n wsSpan === undefined\n ? { start: startSpan.start, end: endSpan.end }\n : { start: wsSpan.start, end: endSpan.end };\n windShear = { runways: wsRunways, allRunways: wsAll, span: wsSpan };\n i += isAll ? 3 : 2;\n continue;\n }\n }\n\n // 温度预告组(TAF TX/TN 混入 METAR 通路,IEM 归档实弹 26 次——中国区 TAF 行混入 METAR 流):\n // TX25/0907Z = 最高 25°C、09 日 07Z 到达(ICAO Annex 3 附录五温度预告组,M 前缀 = 负值)。\n // 认组收下进 remarks(kind 'temperature-forecast',raw 保真)——TAF 语义不属于 METAR 趋势段,\n // 与既有 temp-extrema-6h/24h 同款认组粒度,不解码数值(RemarkGroup 无值槽,数值化留待后续 additive 扩展)\n const txTnM = (mask & M_WEATHER) !== 0 ? /^(TX|TN)M?\\d{2}\\/\\d{4}Z$/.exec(text) : null;\n if (txTnM !== null) {\n remarks.push({ kind: \"temperature-forecast\", raw: text, span: spanOf(t) });\n i += 1;\n continue;\n }\n\n // 天气组(RE 近期天气一并识别——不参与当前天气三态判定)\n const weatherParsed =\n (mask & M_WEATHER) !== 0 ? tryWeatherToken(t, weatherList, recentList) : false;\n if (weatherParsed !== false) {\n if (weatherParsed.outOfOrder) {\n // 能完整切解但语序反常(描述符在现象之后,如 RATS):按切解结果收下 + invalid-format 告警,\n // 不静默也不拒收;完全无法切解的仍走下方 unknown-token\n warnings.push({\n code: \"invalid-format\",\n severity: \"warning\",\n message: `天气组语序不合电码表(${text}:描述符须先于现象)——已按切解结果收下`,\n span: spanOf(t),\n });\n }\n if (weatherParsed.signWithVc) {\n // 强度符与 VC 并存(-VCTSRA 家族,NWS 自动站实弹):互斥是明文条款(4678 限定槽\n // 四选一、FAA AIM「Intensity and 'VC' will not appear together」),语义可无损恢复\n //(强度+邻近+现象俱全)故容忍切解收下并出声——此前整体落 unknown-token 语义全丢\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message: `强度符与 VC 邻近指示并存(${text}——强度符不与 VC 同组)——已按切解结果收下`,\n span: spanOf(t),\n });\n }\n if (weatherParsed.intensityMisuse === true) {\n warnings.push({\n code: \"invalid-format\",\n severity: \"info\",\n message:\n weatherParsed.kind === \"recent\"\n ? `RE 近期天气组带强度符(${text}——15.13.2.1 RE 组无强度位)——已收下`\n : `强度符超适用面(${text}——表 4678 注 4:-/+ 仅限降水族,非降水唯 +SS/+FC/+DS)——已收下`,\n span: spanOf(t),\n });\n }\n i += 1;\n continue;\n }\n\n // 裸 // 天气缺测组(自动站无法观测天气;IR 口径 = weather missing,绝不捏造也不吞进温度组)\n if ((mask & M_WEATHER) !== 0 && text === \"//\") {\n weather = { kind: \"missing\", span: spanOf(t) };\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"天气组缺测(//,无法观测天气)\",\n span: spanOf(t),\n });\n i += 1;\n continue;\n }\n\n // 云:云量位 /// 与云高 /// 双缺测形态(绝不捏造)\n const cloudM = (mask & M_CLOUD) !== 0 ? CLOUD_LAYER_PATTERN.exec(text) : null;\n if (cloudM !== null) {\n cloudSeen = true;\n const amountRaw = cloudM[1];\n const heightRaw = cloudM[2];\n const convectiveRaw = cloudM[3];\n const typeMissing = cloudM[4] !== undefined;\n const amountMissing = amountRaw === \"///\";\n const heightMissing = heightRaw === \"///\";\n if (heightMissing) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"云高缺测(///),不捏造基高\",\n span: spanOf(t),\n });\n }\n if (amountMissing) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"云量位缺测(///),探测到云但云量无法观测\",\n span: spanOf(t),\n });\n }\n if (typeMissing) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message: \"云型位缺测(///)\",\n span: spanOf(t),\n });\n }\n cloudElements.push({\n kind: \"layer\",\n amount: amountRaw !== undefined && isCloudAmount(amountRaw) ? amountRaw : null,\n heightFt: {\n value:\n heightRaw !== undefined && heightRaw !== \"///\"\n ? Number.parseInt(heightRaw, 10) * 100\n : null,\n span: spanOf(t),\n },\n convective:\n convectiveRaw !== undefined && isConvective(convectiveRaw) ? convectiveRaw : undefined,\n span: spanOf(t),\n });\n i += 1;\n continue;\n }\n const vvM = (mask & M_VV) !== 0 ? VV_PATTERN.exec(text) : null;\n if (vvM !== null) {\n cloudSeen = true;\n const heightRaw = vvM[1];\n if (heightRaw === undefined || heightRaw === \"///\") {\n // 缺测电码形态才告警——合法数值组(VV002 = 垂直能见度 200ft)零告警\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n message:\n heightRaw === \"///\"\n ? \"垂直能见度缺测(VV///,天空全遮蔽但垂直能见度不可测)\"\n : \"垂直能见度缺测(VV,兼容形态)\",\n span: spanOf(t),\n });\n }\n cloudElements.push({\n kind: \"vertical-visibility\",\n heightFt: {\n value:\n heightRaw === undefined || heightRaw === \"///\"\n ? null\n : Number.parseInt(heightRaw, 10) * 100,\n span: spanOf(t),\n },\n span: spanOf(t),\n });\n i += 1;\n continue;\n }\n if ((mask & M_SKY_CLEAR) !== 0 && isSkyClear(text)) {\n cloudSeen = true;\n clearCode = { code: text, span: spanOf(t) };\n i += 1;\n continue;\n }\n\n // 温度/露点\n const tempParsed = (mask & M_TEMP) !== 0 ? parseTempDewToken(t) : null;\n if (tempParsed !== null) {\n const dupTemp = temperature !== undefined || dewpoint !== undefined;\n if (dupTemp) dupGroupWarning(\"温度组\", temperature?.span ?? dewpoint?.span, tempParsed.span);\n // 已有温露组时:全缺测电码(/////)不顶替在场值(duplicate-group 已出声)——\n // 零信息量形态覆盖真实观测是纯信息损失;带部分值的形态(如 12//)照常 last-wins\n if (dupTemp && tempParsed.temperature === null && tempParsed.dewpoint === null) {\n i += 1;\n continue;\n }\n // 温度物理极值门(与 QNH 同款纪律):超可信范围判缺测 + value-out-of-range,\n // 绝不静默留假值;双侧同时超界合并为一条告警(M91/M95 不重复出声);\n // 显式缺测(//)另发 missing-expected,两告警互不替代\n const rawTemp = tempParsed.temperature;\n const rawDew = tempParsed.dewpoint;\n const outOfRange = (r: TemperatureReading | null): boolean =>\n r !== null && (r.celsius < TEMP_C_MIN || r.celsius > TEMP_C_MAX);\n const outT = outOfRange(rawTemp);\n const outD = outOfRange(rawDew);\n if (outT || outD) {\n const single = outT ? rawTemp : rawDew;\n const span = outT && outD ? tempParsed.span : single?.span;\n const shown = span === undefined ? `${TEMP_C_MIN}` : raw.slice(span.start, span.end);\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `温度超出可信范围(${shown},合理区间 ${TEMP_C_MIN}–${TEMP_C_MAX}°C)——值不可信判缺测,原码经 span 回溯`,\n span,\n });\n }\n temperature = outT ? undefined : (rawTemp ?? undefined);\n dewpoint = outD ? undefined : (rawDew ?? undefined);\n if (rawTemp === null || rawDew === null) {\n warnings.push({\n code: \"missing-expected\",\n severity: \"info\",\n // 形态判别精确到正则(2026-09-14 独立复评收口:endsWith(\"/\") 会把 12// 的标准\n // 缺测与 12/// 的磨损形都误述为 24/ 形态)\n message: /^M?\\d{2}\\/$/.test(t.text)\n ? \"露点位缺测(24/ 形态,FMH-1 12.6.10)\"\n : \"温度/露点位缺测(//)\",\n span: tempParsed.span,\n });\n }\n // 交叉校验:露点不可能高于温度(相对湿度 >100% 物理不可能)——典型传感器故障形态。\n // 两组值照常保留(含 M 负值),矛盾交由告警呈现,绝不静默也不捏造\n if (\n temperature !== undefined &&\n dewpoint !== undefined &&\n temperature.celsius < dewpoint.celsius\n ) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `温度低于露点(${t.text})——物理不可能,疑似传感器故障`,\n span: tempParsed.span,\n });\n }\n i += 1;\n continue;\n }\n\n // 气压:Q(hPa)/ A(inHg,隐含小数点);5 位数 QNH 与物理范围外值 = 脏值(Q10054 家族)\n const qM = (mask & M_QNH) !== 0 ? /^Q(\\d{4,5})$/.exec(text) : null;\n if (qM !== null) {\n const digits = qM[1] ?? \"\";\n const hpa = Number.parseInt(digits, 10);\n if (digits.length === 5 || hpa < QNH_HPA_MIN || hpa > QNH_HPA_MAX) {\n altimeter = undefined;\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `QNH 超出可信范围(${text},合理区间 ${QNH_HPA_MIN}–${QNH_HPA_MAX} hPa)——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else {\n setAltimeter({ value: hpa, unit: \"hPa\", span: spanOf(t) });\n }\n i += 1;\n continue;\n }\n const aM = (mask & M_ALTIMETER_A) !== 0 ? /^A(\\d{4})$/.exec(text) : null;\n if (aM !== null) {\n const inhg = Number.parseInt(aM[1] ?? \"0\", 10) / 100;\n if (inhg < ALT_INHG_MIN || inhg > ALT_INHG_MAX) {\n altimeter = undefined;\n warnings.push({\n code: \"value-out-of-range\",\n severity: \"warning\",\n message: `高度表设定超出可信范围(${text} → ${inhg} inHg,合理区间 ${ALT_INHG_MIN}–${ALT_INHG_MAX})——值不可信判缺测,原码经 span 回溯`,\n span: spanOf(t),\n });\n } else {\n setAltimeter({ value: inhg, unit: \"inHg\", span: spanOf(t) });\n }\n i += 1;\n continue;\n }\n\n // 变化能见度(FAA 正文位形态:主能见度组后跟「VIS 1/4V1/2」变化区间)——\n // IR 建模为 RemarkKind 'variable-visibility'(不占 visibility 槽),与 RMK 段同族同 kind\n if ((mask & M_VIS_RANGE) !== 0 && text === \"VIS\" && VIS_V_RANGE.test(peek(1)?.text ?? \"\")) {\n const nextTok = peek(1);\n if (nextTok !== undefined) {\n remarks.push({\n kind: \"variable-visibility\",\n raw: `${text} ${nextTok.text}`,\n span: { start: t.start, end: nextTok.end },\n });\n i += 2;\n continue;\n }\n }\n\n // 维护指示符(正文级孤例)\n if ((mask & M_DOLLAR) !== 0 && text === \"$\") {\n remarks.push({ kind: \"maintenance\", raw: \"$\", span: spanOf(t) });\n i += 1;\n continue;\n }\n\n // 不静默:看不懂的 token 进 warnings,绝不丢弃\n warnings.push({\n code: \"unknown-token\",\n severity: \"info\",\n message: `未识别的组(${text})——已如实收下`,\n span: spanOf(t),\n });\n i += 1;\n }\n\n // 当前天气组:仅有实组时给值;RE-only 报文 weather 保持 undefined(组省略 ≠ 缺测)\n if (weatherList.length > 0) {\n const first = weatherList[0];\n const last = weatherList[weatherList.length - 1];\n if (first !== undefined && last !== undefined) {\n weather = {\n kind: \"value\",\n value: [...weatherList],\n span:\n first.span !== undefined && last.span !== undefined\n ? { start: first.span.start, end: last.span.end }\n : undefined,\n };\n }\n }\n if (cloudSeen) {\n clouds = { elements: cloudElements, clear: clearCode };\n }\n\n // CAVOK 词后矛盾校验:词位让位后,其后新出现的能见度/天气/云组若与 CAVOK 语义确定矛盾,\n // 此前静默并存——同三面判据出声(趋势段已被围栏隔离,不会流入此处的正文状态)\n if (cavok) cavokConflicts(\"后续\");\n\n // 云组自洽(WMO 15.9.2 / 15.9.1):VV 顶替整个云组、NSC/SKC/NCD/CLR 为无云电码——\n // 与层组并存均互斥矛盾形态,出声不静默(规范外容错照旧收下)\n const hasVvElement = cloudElements.some((e) => e.kind === \"vertical-visibility\");\n const hasLayerElement = cloudElements.some((e) => e.kind === \"layer\");\n if (hasVvElement && hasLayerElement) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: \"VV 组与云层组并存(WMO 15.9.2:VV 顶替整个云组)——报文自洽性存疑\",\n span: cloudElements[0]?.span,\n });\n }\n if (clearCode !== undefined && hasLayerElement) {\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"warning\",\n message: `${clearCode.code}(无云电码)与云层组并存——互斥形态,报文自洽性存疑`,\n span: clearCode.span,\n });\n }\n\n // —— RMK 段(认组粒度;未知 ≠ 错误,不进 warnings)\n while (i < tokens.length) {\n const t = tokens[i];\n if (t === undefined) break;\n const text = t.text;\n const push = (remarkKind: RemarkKind, consumed = 1): void => {\n const slice = tokens.slice(i, i + consumed);\n remarks.push({\n kind: remarkKind,\n raw: slice.map((c) => c.text).join(\" \"),\n span: joinSpan(slice),\n });\n i += consumed;\n };\n\n if (text === \"AO1\" || text === \"AO2\" || text === \"A01\" || text === \"A02\") {\n // A01/A02 数字形态:tgftp 通路实弹 268 站次(与 FMH-1 字母形态 AO1/AO2 并存)\n push(\"auto-type\");\n continue;\n }\n if (/^SLP(\\d{3}|NO)$/.test(text)) {\n push(\"sea-level-pressure\");\n continue;\n }\n if (/^T[01]\\d{7}(T[01]\\d{7})?$/.test(text) || /^T[01]\\d{3}$/.test(text)) {\n push(\"precise-temperature\");\n continue;\n }\n if (/^P\\d{4}$/.test(text)) {\n push(\"precip-1h\");\n continue;\n }\n if (/^[67](?:\\d{4}|\\/{4})$/.test(text)) {\n // 6/7 组降水窗口(3/24h):量值 4 位;//// = 窗口降水缺测(FMH-1 实弹 6////,tgftp 语料 17 处)\n push(\"precip-window\");\n continue;\n }\n if (/^4\\/\\d{3}$/.test(text)) {\n push(\"snow-depth\");\n continue;\n }\n if (/^I[136]\\d{3}$/.test(text)) {\n // FMH-1 冰积组 = I + 间隔位(1/3/6h) + 3 位量值(I1001 → 1 小时 0.01 英寸);\n // 旧正则 \\d{4} 多吞一位致 I1001 形态全数落 unknown(2026-09-12 复评命中)\n push(\"ice-accretion\");\n continue;\n }\n if (/^5[0-8]\\d{3}$/.test(text)) {\n push(\"pressure-tendency\");\n continue;\n }\n // 24h 温度极值组:现行 FMH-1 为 9 位(4 + 最高[符号位 3 位] + 最低[符号位 3 位],\n // 如 401280089 = 最高 +12.8 / 最低 +8.9;符号位 1 = 负),IEM/tgftp 实弹全数 9 位;\n // 8 位旧形态兼容保留\n if (/^4(?:[01]\\d{3}[01]\\d{3}|\\d{7})$/.test(text)) {\n push(\"temp-extrema-24h\");\n continue;\n }\n if (/^[12]\\d{4}$/.test(text)) {\n push(\"temp-extrema-6h\");\n continue;\n }\n if (text === \"PK\" && tokens[i + 1]?.text === \"WND\") {\n push(\"peak-wind\", 3);\n continue;\n }\n if (text === \"WSHFT\" && tokens[i + 1] !== undefined) {\n push(\"wind-shift\", 2);\n continue;\n }\n if (text === \"PRESRR\" || text === \"PRESFR\") {\n push(\"pressure-change\");\n continue;\n }\n if (text === \"VISNO\") {\n push(\"vis-no\");\n continue;\n }\n if (text === \"TSNO\") {\n // TSNO(美网高频):雷暴传感器不工作——雷暴探测不可用(≠无雷暴),认组不再 unknown\n push(\"thunderstorm-sensor\");\n continue;\n }\n if (text === \"RVRNO\") {\n // RMK 位与正文位同口径(方案一):并存矛盾出声、值组明细保留(终态不改),\n // RVRNO 自身留痕 remarks——见正文 RVRNO 位注释\n if (rvr?.kind === \"value\") {\n const prevText = rvr.span === undefined ? \"\" : raw.slice(rvr.span.start, rvr.span.end);\n warnings.push({\n code: \"cross-check-conflict\",\n severity: \"info\",\n message: `RVRNO(站级:应报而缺)与 RVR 值组并存(${prevText})——矛盾形态,值组按跑道级明细保留,RVRNO 经 remarks/raw 可回溯`,\n span: spanOf(t),\n });\n } else {\n rvr = { kind: \"missing\", span: spanOf(t) };\n }\n push(\"rvr-no\");\n continue;\n }\n if (text === \"SFC\" && tokens[i + 1]?.text === \"VIS\") {\n // 分数尾 token(SFC VIS 2 1/2)一并吸收,不再散落 unknown(FMH-1 12.7.1.f)\n const frac = /^\\d\\/\\d(SM)?$/.test(tokens[i + 3]?.text ?? \"\") ? 1 : 0;\n push(\"surface-visibility\", 3 + frac);\n continue;\n }\n if (text === \"TWR\" && tokens[i + 1]?.text === \"VIS\") {\n // TWR VIS 塔台能见度(FMH-1 12.7.1.f,值可为分数对)\n const frac = /^\\d\\/\\d(SM)?$/.test(tokens[i + 3]?.text ?? \"\") ? 1 : 0;\n push(\"twr-visibility\", 3 + frac);\n continue;\n }\n const visDirNext = tokens[i + 1]?.text;\n const RMK_VIS_DIR = /^(N|NE|E|SE|S|SW|W|NW)$/;\n const RMK_VIS_VAL = /^[MP]?\\d+(\\/\\d+)?(SM)?$/;\n if (\n text === \"VIS\" &&\n visDirNext !== undefined &&\n RMK_VIS_DIR.test(visDirNext) &&\n tokens[i + 2] !== undefined\n ) {\n // 分区能见度(方位在前)VIS <方位> <量值>〔<方位> <量值>…〕(FMH-1 12.7.1.h,量值可为整数+分数对)\n // 多扇区实弹(PANC:VIS E 10 SE 10 S 10)整段并组保真,后续方位对不再散落 unknown\n const frac = /^\\d\\/\\d(SM)?$/.test(tokens[i + 3]?.text ?? \"\") ? 1 : 0;\n let consumed = 3 + frac;\n for (let j = i + consumed; ;) {\n const dir = tokens[j]?.text;\n if (dir === undefined || !RMK_VIS_DIR.test(dir)) break;\n const val = tokens[j + 1]?.text;\n if (val === undefined || !RMK_VIS_VAL.test(val)) break;\n const pair = /^\\d+$/.test(val) && /^\\d\\/\\d(SM)?$/.test(tokens[j + 2]?.text ?? \"\") ? 3 : 2;\n consumed += pair;\n j += pair;\n }\n push(\"sectoral-visibility\", consumed);\n continue;\n }\n if (text === \"VIS\" && visDirNext !== undefined && RMK_VIS_VAL.test(visDirNext)) {\n // 分区能见度(量值在前)VIS <量值>〔<方位>〕(FMH-1 12.7.1.h;PANC 实弹:VIS 1 1/2 N)\n let consumed = 2; // VIS + 量值\n if (/^\\d+$/.test(visDirNext) && /^\\d\\/\\d(SM)?$/.test(tokens[i + 2]?.text ?? \"\"))\n consumed += 1; // 整数+分数对\n if (\n tokens[i + consumed]?.text !== undefined &&\n RMK_VIS_DIR.test(tokens[i + consumed]?.text ?? \"\")\n )\n consumed += 1;\n push(\"sectoral-visibility\", consumed);\n continue;\n }\n if (/^CIGNO$/.test(text)) {\n // 云高计不可用(FMH-1 12.7.1.p 族,与 VISNO/TSNO/RVRNO 同族口径)\n push(\"cig-not-available\");\n continue;\n }\n const cigNext = tokens[i + 1]?.text;\n if (text === \"CIG\" && cigNext !== undefined) {\n // CIG hhhVhhh 波动 / CIG hhh LOC / CIG hhh(FMH-1 12.7.1.p)\n const nxt = cigNext;\n if (/^\\d{3}V\\d{3}$/.test(nxt)) {\n push(\"ceiling-variation\", 2);\n continue;\n }\n if (/^\\d{3}$/.test(nxt)) {\n if (tokens[i + 2]?.text === \"LOC\") {\n push(\"ceiling-at-location\", 3);\n continue;\n }\n push(\"ceiling\", 2);\n continue;\n }\n }\n if (text === \"PNO\") {\n // 降水传感器不可用(FMH-1 12.7.2.g 族)\n push(\"precip-not-available\");\n continue;\n }\n if (text === \"FZRANO\") {\n push(\"fzr-not-available\");\n continue;\n }\n if (text === \"CHINO\") {\n push(\"chino\");\n continue;\n }\n if (/^8\\/[0-9X/]{3}$/.test(text)) {\n // 8/CCC 云型组(低/中/高云型电码 0–9,X 未知,/ 缺测;FMH-1 12.7.2.b)\n push(\"cloud-type-8group\");\n continue;\n }\n if (/^933\\d{3}$/.test(text)) {\n // 933RRR 积雪水当量(英寸百分之一;FMH-1 12.7.2.a)\n push(\"snow-water-equivalent\");\n continue;\n }\n if (text === \"FUNNEL\" && tokens[i + 1]?.text === \"CLOUD\") {\n push(\"phenomenon-began-ended\", 2);\n continue;\n }\n if (text === \"LTG\") {\n // 多 token 聚合:LTG 后按词表(LTG_TAIL_VOCAB)连收 + 词表词后夹带至多一个 1–2 位\n // 数字距离 token(FMH-1 ch.12:自动站雷电视频距离为海里裸数字,如 LTG ALQDS CG 12 OHD——\n // 数字须跟在词表词后,LTG 直连裸数字无出处)。聚合仍被词表外 token 截断;\n // 数字吸收以「前一吸收 token ∈ 词表」为前置且至多一个——防无关散落数字被静默吞进\n // lightning remark(2026-09-14 收紧:实现此前与注释声明不符,语料 229 处 LTG 零裸数字)\n let consumed = 1;\n let prevInVocab = false;\n let digitsAbsorbed = 0;\n for (;;) {\n const nextTok = tokens[i + consumed];\n if (nextTok === undefined) break;\n if (LTG_TAIL_VOCAB.has(nextTok.text)) {\n consumed += 1;\n prevInVocab = true;\n continue;\n }\n if (prevInVocab && digitsAbsorbed === 0 && /^\\d{1,2}$/.test(nextTok.text)) {\n consumed += 1;\n digitsAbsorbed += 1;\n prevInVocab = false;\n continue;\n }\n break;\n }\n push(\"lightning\", Math.min(consumed, tokens.length - i));\n continue;\n }\n if (text === \"SNINCR\" && /^\\d+\\/\\d+$/.test(tokens[i + 1]?.text ?? \"\")) {\n // SNINCR <时增>/<总量>(英寸,两 token 一组)——积雪增率,2026-09-12 复评补建模\n push(\"snow-increase\", 2);\n continue;\n }\n if (text === \"VIS\" && VIS_V_RANGE.test(tokens[i + 1]?.text ?? \"\")) {\n // 变化能见度 VIS 1/2V2(IR RemarkKind 'variable-visibility' 声明补实现)\n push(\"variable-visibility\", 2);\n continue;\n }\n // began/ended 家族(FZRAB43E50 合并形态 / RAB42·RAE50 拆分形态 / B43 裸起止)——\n // 边界收紧(2026-09-12):词身须能按天气组切解(FZRA/RA/TS…),俄区 QBB(云底高度,\n // 国家组)等非天气字母组不再被 [A-Z]{2,8} 前缀误吞进本类\n const beganMerged = /^([A-Z]{2,8})B\\d{2,4}(?:E\\d{2,4})?$/.exec(text);\n const beganSplit = /^([A-Z]{2})[BE]\\d{2,4}$/.exec(text);\n const beganBodyOk = (m: RegExpExecArray | null): boolean =>\n m !== null && splitWeatherToken(m[1] ?? \"\") !== null;\n if (beganBodyOk(beganMerged) || beganBodyOk(beganSplit) || /^[BE]\\d{2,4}$/.test(text)) {\n push(\"phenomenon-began-ended\");\n continue;\n }\n if (/^QBB\\d{3}$/.test(text)) {\n // QBB(俄区国家组):云底高度(米,3 位直读,与正文云组互为印证)\n push(\"cloud-base-height\");\n continue;\n }\n if (/^QFE\\d{3,4}(\\/\\d{3,4})?$/.test(text)) {\n // QFE(俄区国家组):场面气压。值语义(查证 2026-09-12):三位数 = 毫米汞柱(QFE749 = 749 mmHg,\n // 俄区惯例报 mmHg 场压);双段 QFE746/0995 = 746 mmHg 与 995 hPa 双单位(760 mmHg = 1013.25 hPa\n // 标准大气换算互证,metar-taf.com 俄区实报 RMK R08L/QFE741/0988 同族);四位数直读 hPa(QFE1003)。\n // 认组粒度收下不解码数值(RemarkGroup 无值槽;单位歧义风险由「不解码」规避),原码经 span 可取\n push(\"aerodrome-pressure\");\n continue;\n }\n if (text === \"$\") {\n push(\"maintenance\");\n continue;\n }\n push(\"unknown\");\n }\n\n return compactIfEnabled({\n kind,\n raw,\n station,\n time,\n flags: { auto, corrected },\n cavok,\n cavokSpan,\n wind,\n visibility,\n runwayVisualRange: rvr,\n weather,\n recentWeather: recentList.length > 0 ? recentList : undefined,\n clouds,\n temperature,\n dewpoint,\n altimeter,\n seaLevelPressure: undefined,\n trends,\n runwayStates,\n windShear,\n remarks,\n warnings,\n });\n}\n\n/** Result-style parse outcome: never throws for parse-level failures — branch on `ok` instead of try/catch.\n * 结果式解析出口:解析层失败不抛出,按 ok 分流——批量回放/管道消费免 try/catch 控制流。 */\nexport type TryParseResult =\n | { readonly ok: true; readonly report: MetarReport }\n | { readonly ok: false; readonly error: MetarParseError };\n\n/**\n * `parse` 的问题式变体:整体失败返回 `{ ok:false, error }`(MetarParseError,code 契约同 parse),\n * 成功返回 `{ ok:true, report }`。仅编程性意外(非 MetarParseError 的内部异常)原样抛出——\n * 不吞实现缺陷。语义与 parse 完全一致(同一实现,确定性继承)。\n * Result-style variant of `parse`: whole-report failures come back as `{ ok:false, error }`\n * with the same stable `code` contract; unexpected non-MetarParseError exceptions still throw.\n */\nexport function tryParse(raw: string, options?: ParseOptions): TryParseResult {\n try {\n return { ok: true, report: parse(raw, options) };\n } catch (err) {\n if (err instanceof MetarParseError) return { ok: false, error: err };\n throw err;\n }\n}\n"],"mappings":"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"}
|