Files
structrail-design/.trae/documents/tracer-validation.md
skycurtain 5cc4f96b46 docs: 新增设计决策文档并实现数组追踪器校验
- 新增决策文档:移除 preset 指令,将其合并到 create 指令中,以简化生命周期和系统复杂度
- 新增决策文档:确立 SDK 侧影子状态校验机制,实现快速失败和最小必要状态原则
- 在 ArrayTracer 中实现影子状态校验,维护数组长度并进行索引边界检查
2026-02-06 01:56:52 +08:00

2.9 KiB
Raw Blame History

Tracer 指令校验机制设计决策

背景

在设计 Tracer 协议时,我们面临一个关键的架构决策:应该在哪里对 Tracer 的操作指令进行合法性校验(例如数组越界、空指针访问)?

我们有两个主要的选择:

  1. SDK 侧(生产者):在用户调用 SDK APItracer.pick(i))生成指令时即时校验。
  2. 渲染器侧(消费者)SDK 只负责生成指令,由前端渲染器在回放指令序列时进行校验。

决策SDK 侧“影子状态”校验

经过讨论,我们决定采用 SDK 侧校验 作为主要防线,并引入 “影子状态Shadow State 模式来实现。

核心设计原则

  1. Fail Fast快速失败

    • 用户的逻辑错误(如访问越界)应在代码执行阶段立即抛出异常,而不是等到生成了错误的 JSON 并在渲染器播放时才报错。
    • 这样可以将错误精确定位到用户代码的具体行号,极大提升调试体验。
  2. 最小必要状态Minimal Viable State

    • SDK 不需要维护完整的数据结构副本(那会带来巨大的内存和性能开销)。
    • SDK 只需要维护用于校验合法性的 元数据Metadata
    • 案例:对于 ArrayTracer,我们不需要存储数组的具体元素值,只需要维护一个整数 currentSize

实现方案

影子状态维护

在每个 Tracer 实例内部维护一个轻量级的状态变量:

  • ArrayTracer: 维护 int currentSize
    • create(array): 初始化 currentSize = array.length
    • scale(newSize): 更新 currentSize = newSize
    • pick/patch(index): 校验 0 <= index < currentSize

跨语言适应性

这种模式具有极强的跨语言通用性:

  • TypeScript/JS: 简单变量。
  • Java/C#: 类的私有成员字段。
  • C/C++: 结构体中的字段(即便 C 语言原生数组不带长度,通过 Tracer 封装后反而赋予了其边界检查能力)。

对比分析

维度 SDK 侧校验(采用方案) 渲染器侧校验
错误反馈时机 即时(用户运行代码时) 延迟(用户观看回放时)
错误定位能力 (直接抛出异常,有堆栈信息) (难以关联回源码行号)
实现复杂度 中(需维护影子状态) 低(仅需防御性编程)
性能开销 极低(仅维护元数据,如 int 无额外开销
用户体验 类似本地调试,符合直觉 可能会看到“崩坏”的动画

结论

虽然渲染器依然需要具备防御性编程能力以防止崩溃,但业务逻辑的正确性校验应当由 SDK 在指令生成源头保证。这不仅符合“数据源头治理”的原则,更能为用户提供更友好的开发和调试环境。