feat(flight): UNMAPPED_FIELD、SRVT/VIPF 明细与白名单内未映射留档(ACM2-89/99/100)

V5 迁移;集合段出现才写;白名单 7 类内未落态写入 UNMAPPED_FIELD,不扩白名单。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
windyboy
2026-09-21 15:54:55 +08:00
co-authored by Cursor
parent 54b383fa9d
commit 02b0b2f189
14 changed files with 464 additions and 13 deletions
@@ -6,12 +6,14 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText
import com.gzzn.omms.msgexchange.domain.flight.ScheduleRecord
import com.gzzn.omms.msgexchange.domain.flight.UnmappedFieldEntry
/** Stable payload boundary used by processing. It is deliberately not an XML model. */
data class FlopPayload(
val flid: String,
val scalars: Map<String, String> = emptyMap(),
val collections: Map<String, List<Map<String, String>>> = emptyMap(),
val unmapped: List<UnmappedFieldEntry> = emptyList(),
)
data class ScheduleBody(
@@ -20,10 +22,8 @@ data class ScheduleBody(
)
/**
* 只保留在 wire/domain、尚未映射到持久化明细的集合键(`[G-SRVT-VIPF]`)。
*
* 它们不参与合并、不进快照、不落库;保留的目的是不让入站事实在解码层被静默抹平,并让真实
* 流量里的出现情况可观测——决定"缺席是否等于删除"的 `Q2` 需要真实报文才能定案。
* `SRVT`/`VIPF` 集合键(`[G-SRVT-VIPF]`):用于入站出现次数指标;明细落库见 `FLIGHT_SRVT`/`FLIGHT_VIPF`
* 不参与合并层与 Redis 快照。
*/
private val UNPERSISTED_COLLECTION_KEYS: Set<String> = setOf("SRVT", "VIPF")
@@ -160,11 +160,30 @@ data class FlightRecordXml(
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ROUT") val rout: List<RoutXml> = emptyList(),
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ERUT") val erut: List<RoutXml> = emptyList(),
// SRVT/VIPF 用可空表达"段是否出现":null = 未出现;出现即为列表(空元素得到一行空行)。
// 两者都不落明细表、不参与合并,清空语义待 `Q2``[G-SRVT-VIPF]`
// 明细表见 `G-SRVT-VIPF`;缺席是否清除待 `Q2`,现行默认不删已有行
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "SRVT") val srvt: List<SrvtXml>? = null,
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "VIPF") val vipf: List<VipfXml>? = null,
@param:JacksonXmlProperty(localName = "FDIV") val fdiv: FdivXml? = null,
@param:JacksonXmlProperty(localName = "FRET") val fret: FretXml? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class FdivXml(
@param:JacksonXmlProperty(isAttribute = true, localName = "DDES") val ddes: String? = null,
@param:JacksonXmlProperty(isAttribute = true, localName = "DDIR") val ddir: String? = null,
) {
@field:JacksonXmlText
var text: String? = null
}
@JsonIgnoreProperties(ignoreUnknown = true)
data class FretXml(
@param:JacksonXmlProperty(isAttribute = true, localName = "REID") val reid: String? = null,
) {
@field:JacksonXmlText
var text: String? = null
}
@JsonIgnoreProperties(ignoreUnknown = true)
class FdelXml