# TeaQL Runtime 架构设计：增量账本引擎 (Incremental Delta Ledger)

## 1. 架构初衷与“图查分”的偏移反思
TeaQL 的核心初衷是提供极其轻量、明确且高性能的数据持久化机制。
在项目的最初设计中，我们在实体内部引入了 `EntityRoot`，用于隐式地在 Aggregate (聚合) 内部共享变更上下文 (`ChangeSetStack`)。这本质上是 **Unit of Work (工作单元)** 与 **Event Sourcing (事件溯源)** 的变体。

然而在后续的框架演进中，架构出现了一定程度的“偏移 (Drift)”。我们引入了类似 Hibernate 的快照比对机制，通过构建 `GraphMutationPlan` 来深度遍历整个对象图，对比 `original_values` 与 `current_values` 从而计算出变更。
这种“图遍历查分”不仅带来了巨大的递归性能开销，还引发了诸如**循环引用去重 (`visited_nodes` 机制)**、**无意义的空更新 (Empty Updates)** 以及**乐观锁并发冲突**等一系列复杂的衍生 Bug。

如今，我们将回归最纯粹的初始设计：**彻底抛弃深度图遍历，使用“扁平化的增量账本”作为 Runtime 保存引擎的唯一事实来源。**

## 2. 核心设计：扁平化增量账本 (Flat Incremental Ledger)

在这个架构下，`save_entity` 不再做任何探索与对比动作，而是退化为一个极速的“账单消费器”。

### 2.1 隐式的树级共享账本
- 每个实体对象底层持有 `root: EntityRoot`。
- 通过生成的 Setter 方法（如 `update_name`），变更被直接写入 `EntityRoot` 中的 `EntityChangeSet` (一个以 `EntityKey` 为键的 Map)。
- 当父对象附加子对象（如 `attach_root_recursive`）时，子对象共享父对象的 `EntityRoot` 引用。因此，整个图的所有修改，**都被扁平化地汇总在这唯一的一个字典表里**。

### 2.2 O(1) 的修改发现与下发
保存时，Runtime 直接读取这个扁平的字典表，无需关心对象的树形嵌套结构。谁在表里，谁就生成 SQL 执行。没有修改的实体在账单中不存在，从而实现真正的零损耗。

### 2.3 客户端全局发号器 (Client-side ID Generator) 与纯粹扁平化
针对“如何处理关联新增实体的主外键依赖”这一难题，我们的最终解法是：引入内部全局 U64 ID Generator。
所有实体在实例化（`runtime_new`）的瞬间，即被赋予全局唯一的 U64 ID。因此：
- 关系赋值变成普通的字面量赋值，例如 `log.update_task_id(123456)`。
- 账本中记录的外键关系全是**真实且最终的 ID**，不依赖数据库的自增返回。
- Runtime 在下发 SQL 时，**彻底去除了延迟引用与拓扑排序的复杂度**。执行引擎无需关心实体插入的先后顺序，可以直接并发、批量地下发 Batch Insert/Update SQL，达到极致的执行效率。

## 3. 智能批处理机制 (Intelligent Batching)
基于这套扁平账单，我们在执行层发挥出了强大的合并特性（这一特性我们早期就已具备，在扁平账本下将释放更大威力）：

1. **批量插入 (Batch Insert)**：账单中所有同类型的新实体，自动拼合成 `INSERT INTO ... VALUES (...), (...), ...`，最大化写入吞吐。
2. **批量删除 (Batch Delete)**：将 `deleted_keys` 中相同实体的删除动作合并为 `DELETE FROM ... WHERE id IN (...)`。
3. **基于签名的批量更新 (Signature-based Batch Update)**：
   - 即使是同一张表的不同实体，如果它们被更新的字段不同（比如 A 更新了 name，B 更新了 status），传统 ORM 无法合并。
   - 我们的引擎会将**更新字段的组合（指纹/Signature）**进行分组。所有同样只更新了 `name` 字段的实体会被并入同一个 Batch Statement 中。这一特性对于微服务下乱序并发状态更新有着极为可观的性能提升。

## 4. 可观测性创新：基于业务意图的更新追踪与二次修改侦测

这是我们在这套机制中加入的一个极具诊断价值的独创细节。

### 4.1 问题的产生
在正常的业务代码中，同一个事物在一个请求周期内，针对某一个字段的赋值理应只有一次（例如 `task.update_status(READY)`）。
然而，同一个字段往往会被不规范的代码覆盖赋值多次（二次修改）。这往往是业务流程混乱或无目标性动作的先兆，是隐藏 Bug 的重灾区。

### 4.2 诊断记录机制与意图追踪 (Intent-Driven Tracking)
`EntityRoot` 除了维护属性状态，还持有着当前的业务上下文：`comment`。
我们的 `EntityChangeSet` 在内部维护着一张细粒度的**修改流水表 (update_history)**。
- 当调用 Setter 时，系统会将修改的**字段名、旧值、新值，以及此刻 `EntityRoot` 中的 `comment`（业务意图）** 一并打包推入历史流。
- 如果发生二次覆盖，历史流会清晰记录：
  * 第一次修改: `status` -> 1, 意图: `"执行自动化状态流转"`
  * 第二次修改: `status` -> 2, 意图: `"管理员强制纠偏状态"`
- **生成时机**：这份意图流水的拦截与生成，发生在系统正式的数据库 Audit（如 `TaskExecutionLog` 持久化）**之前**。它是构建高级 Audit 的原材料。
- **跨系统追踪号 (Change ID)**：在未来，我们会为每一次带有意图的组合变更分配一个唯一的**变更编号 (Change ID)**，使其能够跨越多个系统进行核对与追踪。

### 4.3 面向 AI 编程时代的可观测性延展
引入极细粒度的“意图-变更映射”并不仅仅是为了找 Bug。
在 **AI 辅助编程 (AI Coding)** 全面普及的未来，系统通常由 AI 和人类共同编写与维护。这就要求系统底层动作的**透明化 (Transparency)** 达到极高的标准。
通过精确记录每一处数据修改背后的业务意图，我们能够为未来更高级的线上与离线基础设施（如自动化排错平台、可观测性诊断工具）提供最核心的数据支撑，使系统的运行轨迹彻底白盒化。

## 5. 乐观锁 (Optimistic Locking) 与标记删除 (Logical Delete) 的安全闭环

在企业级应用中，所有的删除（Delete）往往都是标记删除（更新 `version = -1` 或 `is_deleted = true`），且所有的增删改操作都必须受限于乐观锁保护。如果单纯抛弃图遍历而生成无版本的 Batch SQL，会导致灾难性的“脏更新”和“脏删除”。增量账本通过引入静态版本锚点完美解决了此问题。

### 5.1 版本号注册表 (Version Registry)
在 `EntityRoot` / `RootContext` 内部，维护一张 `original_versions: BTreeMap<EntityKey, i64>` 的注册表。当任何实体被加载到内存或挂载时，系统立刻将其原始版本号登记在册。这是绝对的防线。

### 5.2 安全组装 Batch SQL
无论是普通的更新还是标记删除，执行器在读取扁平的账本（`ChangeSet` 和 `deleted_keys`）时，都必须去 `original_versions` 里查阅该实体的基准版本。
- **更新**：翻译为 `UPDATE ... SET ... version = version + 1 WHERE id = ? AND version = {基准版本}`
- **标记删除**：翻译为 `UPDATE ... SET version = -1 WHERE id = ? AND version = {基准版本}`
如果有任何实体在操作间隙被其他事务修改，批处理 SQL 的影响行数会返回 `0`，从而精准抛出 `OptimisticLockConflict`。

### 5.3 严格拦截“版本号篡改”与“漂移”
版本号是底层框架的神圣元数据。借助我们在 4.2 节设计的“意图追踪流水”，系统能轻松实现针对版本号的最高级别告警：
1. **拦截人工篡改**：如果发现 `version` 字段作为被更新的属性出现在了修改流水中（即业务代码手动调用了 `update_version`），框架将发出 `FATAL` 级告警，拦截这种极易破坏乐观锁的违规操作。
2. **侦测上下文漂移**：如果同一个对象在单次请求周期内发生基准版本号变更，同样意味着数据上下文已失控，系统会精准曝光这一危险行为。

---
*注：此架构文档确立了 TeaQL Runtime 未来的核心执行逻辑准则，即从“声明式的状态侦查”向“确定性的增量事件账本”彻底转变。当前为理论固化阶段，优先解决现有系统最高优先级的 Bug，本重构暂缓实施。*
