AGENTS.md@src/host/storage · git:20260928.0bc633c · 2026-09-28 · sha256 21f2fcc904430e0e

AGENTS.md@src/host/storage git:20260928.0bc633cA

Immutable. This exact content never changes and is served at /api/v1/blob/21f2fcc904430e0e.

# Storage Module Rules

## 范围与职责

适用于 `src/host/storage/`。

以「单文件即单资源 + 原子发布 + 进程内/跨进程锁」保存与读取 Host 的持久化文档,并对外提供可复用的原子文件原语与崩溃恢复能力。

判断归属:该修改是否改变「什么被持久化、以什么形状持久化、并发写入如何被串行化」?只改变业务语义判断应放到对应领域模块。

## 状态所有权

- 调用方不得绕过 storage 直接写同一数据文件;需要新资源类型时在 storage 增加明确入口,而不是在别处拼路径。
- 只读方只能拿到值副本(如映射读取返回新对象),不得让调用方持有内部可变结构。
- storage 回答「存了什么」,不回答「是否该存在」。

## 读取语义

- 单资源读取遇损坏 JSON **必须抛出带路径的可诊断错误**,不得伪装成「不存在」。
- 列表读取跳过损坏项以保证可用性,但不得吞掉权限等其他错误(避免把权限问题伪装成空列表)。
- 新增读取入口必须明确选边(单资源 / 列表),并在注释与测试中固化该选择。

## 原子性与锁

- 所有写入必须经组合锁原语(磁盘锁在外、进程内锁在内),不得裸写文件。
- **读改写必须在同一临界区内完成**。
- 新增写路径必须复用既有原子原语,新增公共写方法必须能说明:其读改写位于同一临界区,且失败路径不残留临时文件或锁。

## 时间戳与版本

- `createdAt = 调用方值 ?? 既有值 ?? now`;`updatedAt` 与 `revision` 恒由 storage 生成,调用方传入值不得覆盖。
- 乐观锁只在调用方显式传入 `expectedRevision` 时生效(不得用文档内的 revision 隐式当作冲突期望)。

## 兼容与退役字段

- 旧字段只保留读取兼容语义,重新保存后被剥除;禁止新增已退役字段的写入;
- 前端临时标记与仅服务端拥有的字段必须在写入路径统一处理,不得依赖调用方自觉清理。

## 验证补充

- 并发写同一资源无丢更新(读改写仍在同一临界区);
- 失败路径无临时文件与锁残留;
- 单资源读对损坏 JSON 仍抛可诊断错误、列表读仍保持可用;
- 无旧路径残留、磁盘形状与公共错误码未被意外改变。

## 核心原则

1. 持久化事实由 storage 单独拥有。
2. 读改写不出临界区,锁顺序固定。
3. 单资源读可诊断,列表读可用。原子原语可复用。
4. 时间戳与版本由 storage 记账。
5. 跨文件一致性由调用方保证并写明不变式。
6. 磁盘形状与公共错误码属对外契约。