fix(processing): 合法不支持类型改记 SKIPPED 终态,参考数据单列 RefData(ACM2-83)

- MsgKind.RefData 承接 SIS:3.1~3.14 类别码,白名单分派对齐 implementation.md
- Unsupported 由 FAILED(UNSUPPORTED) 重试改为 SKIPPED(unsupported) 终态(US-03 AC2)
- RefData 在 ReferenceDataProcessor 实装前保持可重试失败,不被吞为跳过
- 同步更新 IgnoreBranchTest / PipelineSmokeTest 旧断言,补 codec 分派回归
This commit is contained in:
windyboy
2026-09-21 11:41:34 +08:00
parent 32bbd459c1
commit 3c577b4d1e
6 changed files with 91 additions and 18 deletions
@@ -66,6 +66,8 @@ class JacksonXmlCodec : XmlCodec {
is MsgKind.Schd -> msg.schd?.let(SisWireMapper::scheduleBody)
is MsgKind.Flop -> msg.flop?.let(SisWireMapper::flopPayload)
MsgKind.Fdel -> msg.flop?.let(SisWireMapper::flopPayload)
// 参考数据类别报文的正文结构随 13 类各异(ACM2-93 实装 ReferenceDataProcessor 时绑定)
is MsgKind.RefData -> null
is MsgKind.Unsupported -> null
}
@@ -86,6 +88,8 @@ class JacksonXmlCodec : XmlCodec {
* 子类型分派必须是**白名单**:未知的 SCHD 子类型不能静默当成全量日计划(DNLD)——
* 那会让一条本该"暂不支持、等人工处置"的报文走最重的整包合并写入路径。
* 空 STYP 按 legacy 约定视为 DNLD(该约定待与 SIS 逐类对拍确认,见 Q3)。
* 静态参考数据类别码(`implementation.md`「静态参考数据」`SIS:3.1``3.14`)单列成
* [MsgKind.RefData]:它们必须走参考数据处理(US-13),不得混入"不支持"跳过。
*/
private fun kindOf(type: String, styp: String): MsgKind = when (type) {
"SCHD" -> when (styp) {
@@ -95,6 +99,12 @@ class JacksonXmlCodec : XmlCodec {
else -> MsgKind.Unsupported("SCHD-$styp")
}
"FLOP" -> if (styp == "FDEL") MsgKind.Fdel else MsgKind.Flop(styp)
in REF_DATA_TYPES -> MsgKind.RefData(type)
else -> MsgKind.Unsupported("$type-$styp")
}
private val REF_DATA_TYPES = setOf(
"COUL", "ARPT", "AIRL", "AIRC", "REGN", "ORGN", "FLTL",
"TLST", "GLST", "SLST", "CLST", "BLST", "CHLT", "RSTA",
)
}
@@ -14,13 +14,19 @@ data class MetaFields(
val dttm: Long,
)
/** 报文的种类:日计划、运行动态、FDEL(航班终止),或者还没支持的类型。分派时用穷尽 when 保证不漏分支。 */
/** 报文的种类:日计划、运行动态、FDEL(航班终止)、静态参考数据,或者还没支持的类型。分派时用穷尽 when 保证不漏分支。 */
sealed interface MsgKind {
data class Schd(val subtype: SchdSubtype) : MsgKind
data class Flop(val subtype: String) : MsgKind // 运行动态,subtype 是报文子类型;FDEL 单独成类,不走这里
data object Fdel : MsgKind
/** 还没有对应处理器的类型:先按 UNSUPPORTED 记失败并退避重试,重试次数用尽转 DEAD 等人工处置。 */
/**
* 静态参考数据(`implementation.md`「静态参考数据」:`SIS:3.1``3.14` 的类别码,3.15 是同类别的 RESP)。
* 必须走参考数据处理(US-13),不得按"不支持"跳过;处理器落地前保持可重试失败并告警。
*/
data class RefData(val type: String) : MsgKind
/** 已识别但还没有对应处理器的类型:跳过留档记 `SKIPPED(unsupported)`,不作为可重试失败占住队头。 */
data class Unsupported(val tag: String) : MsgKind
enum class SchdSubtype { RESP, DNLD, ADFT }
@@ -38,6 +44,7 @@ data class DecodedMessage(
is MsgKind.Schd -> "SCHD-${k.subtype.name}"
is MsgKind.Flop -> "FLOP-${k.subtype}"
MsgKind.Fdel -> "FDEL"
is MsgKind.RefData -> "REF-${k.type}"
is MsgKind.Unsupported -> k.tag
}
}
@@ -245,10 +245,18 @@ class MessageProcessor(
if (payload == null) return deadMalformed(head, "missing-flop-body")
flopProcessor.apply(head, decoded, payload)
}
is MsgKind.RefData -> {
// 参考数据必须走 US-13implementation.md「分派」),不得按"不支持"跳过;
// ReferenceDataProcessor 尚未实装(ACM2-93,待 Q22),先按可重试失败留队并告警。
log.warn("refdata without handler -> FAILED(UNSUPPORTED) msgId={} type={}", head.msgId, kind.type)
return procFailure.fail(head, ErrorClass.UNSUPPORTED, "refdata-pending:${kind.type}")
}
is MsgKind.Unsupported -> {
// 还没有对应处理器的报文类型:先按可重试的失败处理,等能力补齐,不直接判死
log.warn("unsupported type -> FAILED(UNSUPPORTED) msgId={} tag={}", head.msgId, kind.tag)
return procFailure.fail(head, ErrorClass.UNSUPPORTED, "no-handler:${kind.tag}")
// 合法但不支持的类型:跳过留档记 SKIPPEDUS-03 AC2markTerminal 同一条 UPDATE
// 登记回填意图),不当可重试失败占住队头
log.info("unsupported type -> SKIPPED msgId={} tag={}", head.msgId, kind.tag)
procState.markTerminal(head.msgId, ProcStatus.SKIPPED, lastError = "unsupported:${kind.tag}", now = clock.instant())
return
}
}