Files
ST-Bionic-Memory-Ecology/docs/architecture/storage-and-formats.md
2026-05-31 17:20:58 +00:00

81 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 存储分层与数据格式
ST-BME 的图谱数据可能存在多种位置,取决于宿主环境和服务器能力。本文档说明分层策略、快照契约,以及保证"以后改格式不用大迁移"的向前兼容纪律。
## 存储分层
| 层 | 用途 | 说明 |
| --- | --- | --- |
| **Authority SQL** | 规范主源 | 有 st-doa/Authority 时的权威存储;唯一有可靠图谱版本 |
| **Luker chat-state** | 宿主当前聊天主存储 | Luker 宿主下作为当前聊天状态的主写入目标 |
| **IndexedDB** | 浏览器本地主存储 | 普通 SillyTavern 下的默认本地存储 |
| **OPFS** | 浏览器本地存储(替代) | Origin Private File System sidecar |
| **Blob checkpoint** | 备份副本 | Authority 场景的备份,非主源 |
| **Trivium** | 搜索副本 | 向量搜索存储,非主源 |
| **metadata-full / shadow / runtime-recovery** | 仅恢复用 | 灾难兜底,**永远不能**推进持久化确认状态 |
存储层的选择是能力探测驱动的不需要用户手动配置。Authority 是增强层,缺席时优雅降级。详见 [`server-integration.md`](server-integration.md)。
**关键设计:** Luker 宿主下,浏览器全图镜像默认关闭(`cacheStorageTier = none`),避免把大图谱重复写进 IndexedDB/OPFS。只有用户显式"重建本地缓存"才写浏览器缓存。
## 快照契约
耐久快照的顶层结构被**冻结**为固定的六个键(实现见 `sync/graph-snapshot-schema.js`
```
{
schemaVersion, // 顶层快照布局版本
meta, // 图谱元信息(含 meta.schemaVersion 等)
nodes,
edges,
tombstones,
state // lastProcessedFloor / extractionCount 等运行状态
}
```
> **不变量:顶层这六个键永不增减。** 所有未来演进都放进 `meta` / `state` / 各记录字段里——这些层级已经容错(保留未知字段)。
## 向前兼容纪律
这是保证"ST-BME 以后不需要再做 v4/v5 大迁移"的核心机制。它**不是**一个信封框架或预留字段,而是一条解析纪律:
### 1. 宽容解析(保留未知嵌套字段)
> 读取方遇到不认识的**嵌套**字段(在 meta / state / 各记录里),必须保留、不报错、不丢弃。
具体现状:
- 节点 / 边 / tombstone 记录:整对象克隆,未知字段天然保留。
- `meta`:展开保留,已有 `meta.schemaVersion`
- **顶层:冻结为六键,未知顶层键会被丢弃**——顶层是契约层,新增顶层键是契约违规(`normalizeGraphSnapshotShape` 只返回这六个键)。
> **所以演进规则是:永远不要新增顶层键;新字段一律放进 `meta` / `state` / 记录对象里,那里才保证 round-trip。**
原理:如果读取代码遇到不认识的嵌套字段就崩或就丢,那么**任何**字段改动都会逼出一次迁移;如果遇到不认识的嵌套字段就忽略并原样保留,那么以后所有改动都是**加法**,老版本读新数据照样不崩,永远不需要换命名空间、不需要大搬家。这是 protobuf 这类协议几十年验证过的做法。冻结顶层 + 演进只走嵌套,是这套纪律的边界。
### 2. 只加不减
> 新字段一律可选,永不删字段、永不改已有字段的含义。
这样新版写的数据老版仍能读,反之亦然。
### 3. 就地升级upgrade-on-read
实现见 `sync/graph-snapshot-upgrade.js`,接入真实加载路径 `buildGraphFromSnapshot`
> 读到旧 `schemaVersion` 时,在内存里逐级升级一格再用,下次保存时顺手写成新版。单调、幂等、读到比当前更新的数据绝不向下改写。
当前快照布局版本是第一版,升级链为空,但框架和铁律已立住——以后改格式只是"加一个升级步骤",不是搬家。
### 关于 Luker sidecar
Luker checkpoint 存的是完整序列化图谱(`serializeGraph`),节点/边的未知字段被保留——所以图谱正文通过 Luker 是容错的。sidecar 上的信封元数据manifest 统计、checkpoint 元信息)用白名单规范化是**有意为之**:那些是可重算的运行指标,不是图谱本身,丢了能重建。
## 图谱内容版本 vs 快照布局版本
注意区分两个版本号:
- **`GRAPH_VERSION`**`graph/` 内):图谱**内容结构**的版本,有自己的 v2→v9 迁移链,管节点/关系语义的演进。
- **`schemaVersion`**(快照顶层):耐久快照**布局**的版本,管"存进磁盘的信封形状"的演进。
两者独立。本文档的向前兼容纪律针对的是后者(快照布局)。