二进制兼容:格式能解析不代表可以安全回退

自动关联目录:二进制兼容:格式能解析不代表可以安全回退

核心判断:二进制兼容至少包含格式、数据 Schema、编译器 ABI、内容身份和恢复副作用五层。只有在失败前没有物化任何对象时,才能安全回退到另一种编码。

一、业务问题:双读并不等于“先试二进制,失败就读 JSON”

为了缩短解析时间,发布内容同时携带二进制和 JSON。最自然的兼容策略是先解二进制,失败再读 JSON。危险在于 Decoder 可能已经创建了一部分 Lua 对象、注册 Actor 或触发属性副作用,随后 JSON 又创建一遍,最终得到重复对象和残缺索引。

因此回退条件不能只是 decode() == false,还要知道失败发生在验证阶段还是物化阶段。

二、实际实现:Header 只是第一道门

现有二进制读取会依次验证 Magic、格式版本、数据 Schema、边界与最大长度、关卡身份、源内容摘要、编译器指纹、数值 ABI 标志、整文件摘要和 Payload 摘要。发布 Reader 还要求二进制来源可信,并重新校验即将消费的准确字节。

恢复函数返回 dataRestored。若字节码在创建任何数据前被拒绝,可以清空错误并读取同版本 JSON;一旦已经进入对象恢复阶段,Reader 直接失败,不再回退。这一点非常关键:回退是 Decode Policy 的一部分,不是异常处理的兜底分支。

三、兼容策略应是显式矩阵

                 二进制可用       二进制不兼容       二进制部分物化
已验证 JSON       读二进制          读 JSON             整体失败/回滚 VM
无 JSON           读二进制          明确失败             整体失败/回滚 VM
来源不可信         禁止执行          仅解析已验证数据       禁止继续

若需要在部分物化后恢复,应把 Decoder 改成两阶段:后台/临时 VM 中 Prepare 出纯数据图,完成引用和 Schema 校验后再一次 Commit 到正式对象管理器。否则最可靠的方式是销毁整个临时 VM,而不是逐对象猜测回滚。

四、Schema 迁移不能靠修改旧升级函数

早期内容通过按版本串联的 Lua 修复脚本迁移,甚至需要多遍扫描恢复对象间关系、清理历史错误组合。这对已发布数据有效,但也暴露出字段语义与具体类结构耦合、迁移复杂度随版本累积的问题。

升级函数必须不可变,并使用黄金样本验证 vN -> current。更好的长期边界是先把旧格式解到版本化 DTO,再执行纯数据迁移,最后统一校验并物化;迁移阶段不能 Spawn Actor 或依赖当前 World。

五、验证结论

测试矩阵需要覆盖 Header 每个字段损坏、摘要错误、编译器升级、数值 ABI 不同、未知字段、旧 Schema 链式迁移、二进制失败前后是否物化,以及 JSON 与二进制解码后的规范树摘要是否一致。

二进制格式解决的是体积和解析成本;兼容系统解决的是“旧事实如何被新运行时无歧义地接受或拒绝”。两者不是同一个问题。