Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ai-plan/public/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ help the current worktree land on the right recovery documents without scanning
- Purpose: continue the CQRS migration, registry hardening, and related PR follow-up.
- Tracking: `ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md`
- Trace: `ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md`
- `data-repository-persistence`
- Purpose: continue the data repository persistence hardening plus the settings / serialization follow-up backlog.
- Tracking: `ai-plan/public/data-repository-persistence/todos/data-repository-persistence-tracking.md`
- Trace: `ai-plan/public/data-repository-persistence/traces/data-repository-persistence-trace.md`
- `documentation-governance-and-refresh`
- Purpose: continue the documentation governance, README hardening, and `docs/zh-CN` accuracy refresh work.
- Tracking: `ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md`
Expand All @@ -55,6 +59,9 @@ help the current worktree land on the right recovery documents without scanning
- Worktree hint: `GFramework-coroutine-optimization`
- Priority 1: `coroutine-optimization`
- Priority 2: `ai-plan-governance`
- Branch: `feat/data-repository-persistence`
- Worktree hint: `GFramework-data-repository-persistence`
- Priority 1: `data-repository-persistence`
- Branch: `docs/sdk-update-documentation`
- Worktree hint: `GFramework-update-documentation`
- Priority 1: `documentation-governance-and-refresh`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@
- 恢复点编号:`AI-PLAN-GOV-RP-005`
- 当前阶段:`Phase 3`
- 当前焦点:
- 将"主题内 `archive/` 已存在"升级为"active todo/trace 过长时必须归档已完成且已验证阶段"的显式规则
- 让 active `todos/` / `traces/` 只保留当前恢复点、活跃事实、活跃风险、下一步与 archive 指针
- 将 `ai-plan-governance`、`ai-first-config-system` 与 `cqrs-rewrite` 的历史阶段从默认启动入口移出
- 验证“只有早期 todo、没有 durable trace”的 legacy `local-plan` 也能迁入 `ai-plan/public/<topic>/`,且不退化为简单目录平移
- 继续扫描其他 worktree 是否仍有遗留的 `local-plan` 或其他平铺 durable recovery 目录
- 保持 active `todos/` / `traces/` 只保留当前恢复点、活跃事实、活跃风险、下一步与 archive 指针
- 确保 `ai-plan/public/README.md` 与各 topic active 文档对 worktree 映射、恢复点和下一步的描述保持同步

### 已知风险

Expand Down Expand Up @@ -59,11 +58,18 @@
- `ai-plan/public/coroutine-optimization/traces/`
- `ai-plan/public/coroutine-optimization/archive/todos/`
- `ai-plan/public/coroutine-optimization/archive/traces/`
- 已将当前工作树遗留的 settings / persistence / serialization 混合恢复文档从 `local-plan/` 迁入:
- `ai-plan/public/data-repository-persistence/todos/`
- `ai-plan/public/data-repository-persistence/traces/`
- `ai-plan/public/data-repository-persistence/archive/todos/`
- `ai-plan/public/data-repository-persistence/archive/traces/`
- 已同步更新 `ai-plan/public/README.md`,将分支 `fix/analyzer-warning-reduction-batch` 映射到新 topic
- 已同步更新 `ai-plan/public/README.md`,将分支 `docs/sdk-update-documentation` 映射到
`documentation-governance-and-refresh`
- 已同步更新 `ai-plan/public/README.md`,将分支 `feat/coroutine-optimization` 映射到
`coroutine-optimization`
- 已同步更新 `ai-plan/public/README.md`,将分支 `feat/data-repository-persistence` 映射到
`data-repository-persistence`
- 已同步更新 `AGENTS.md`、`ai-plan/README.md` 与 `gframework-boot`,明确 active 文档不是追加式日志,已完成且已验证阶段必须归档

## 验证
Expand All @@ -80,6 +86,9 @@
- `find ai-plan/public/coroutine-optimization -maxdepth 3 -type f | sort`
- 结果:通过
- 备注:更早期、只有 todo 没有 trace 的 coroutine 计划也已按治理规则补齐 active 入口与 archive
- `find ai-plan/public/data-repository-persistence -maxdepth 3 -type f | sort`
- 结果:通过
- 备注:只有单文件且混合承担 todo / trace 的 legacy `local-plan` 也已按治理规则拆分为 active 入口与主题内 archive
- `test ! -e local-plan`
- 结果:通过
- 备注:当前工作树根目录已不再保留 legacy `local-plan/`
Expand All @@ -94,6 +103,6 @@

## 下一步

1. 继续扫描是否还有遗留的 `local-plan` 或其他非 `ai-plan` 的 durable recovery 文档目录,尤其关注只有 todo 没有 trace 的更早期计划
1. 继续扫描是否还有遗留的 `local-plan` 或其他非 `ai-plan` 的 durable recovery 文档目录,尤其关注单文件混合 tracking/trace 或只有 todo 没有 trace 的更早期计划
2. 后续只要某个 active 主题积累了多个已完成且已验证阶段,就在同一变更里将其细节迁入该主题自己的 `archive/`
3. 若某个主题整体完成,再将整个主题目录移入 `ai-plan/public/archive/<topic>/`
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,28 @@
### 下一步 — coroutine 早期计划迁移

1. 后续若再遇到"只有 todo、没有 trace"的更早期计划,继续按同一模式迁入 topic archive,并明确标注推导边界
2. 保持新 topic 的 active 入口精简,不把补写 trace 变成伪造逐日执行日志
2. 保持新 topic 的 active 入口精简,不把补写 trace 变成伪造逐日执行日志

### 阶段:单文件 local-plan 迁移验证(RP-005)

- 复核当前工作树后确认:遗留的 `local-plan/` 只剩一份
`settings-persistence-serialization-tracking.md`,它同时承担 todo 与 trace 角色,不符合当前 `ai-plan` 目录语义
- 按同一治理规则建立 `ai-plan/public/data-repository-persistence/`,并补齐:
- `todos/`
- `traces/`
- `archive/todos/`
- `archive/traces/`
- 将旧混合文件拆分为主题内历史跟踪归档与基于同一材料整理的历史 trace,显式保留“原始材料并非独立 trace”的边界
- 新建精简版 active tracking / trace 入口,只保留当前恢复点、活跃事实、风险与下一步
- 在 `ai-plan/public/README.md` 中建立
`feat/data-repository-persistence` -> `data-repository-persistence` 的 worktree 映射
- 删除旧 `local-plan` 目录,验证当前工作树根目录已不再保留 legacy 私有恢复入口
- 额外完成验证:
- `find ai-plan/public/data-repository-persistence -maxdepth 3 -type f | sort`
- `test ! -e local-plan`
- `dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`

### 下一步 — 单文件计划迁移

1. 后续若再遇到“单文件同时承担 tracking / trace”的更早期计划,继续按同一模式迁入 topic archive,并显式标注来源边界
2. 保持新 topic 的 active 入口精简,避免把拆分后的公共目录重新写回旧式混合日志
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Settings / Persistence / Serialization 历史任务单

> 说明:本归档由 `2026-04-19` 的 legacy `local-plan/settings-persistence-serialization-tracking.md` 迁移生成。
> 原文件同时承担 todo 与 trace 角色;本文件保留任务目标、已完成改动、验证与 backlog,供后续主题恢复引用。

## 目标

围绕 `GFramework` 当前的设置、持久化、序列化系统,先完成一轮高优先级收敛:

- 修正文档与当前实现不一致的问题
- 补足关键直接测试,避免只靠侧面覆盖
- 修复本轮实现中暴露出来的真实缺陷
- 为后续更大的存档迁移 / 持久化策略统一保留清晰恢复点

## 历史阶段完成情况

### 代码

- [x] `JsonSerializer` 支持注入 `JsonSerializerSettings`
- [x] `JsonSerializer` 暴露 `Converters` 入口,允许按实例追加 converter
- [x] `JsonSerializer` 反序列化失败会带上目标类型上下文
- [x] `JsonSerializer.Serialize(object, Type)` 保持 `obj == null` 时输出 `"null"` 的兼容行为
- [x] `JsonSerializer` 不再把参数校验抛出的 `ArgumentException` 包装成 `InvalidOperationException`
- [x] `DataRepository.SaveAllAsync(...)` 改为批量提交语义,只发送 `DataBatchSavedEvent`
- [x] `DataRepository.DeleteAsync(...)` 仅在目标真实存在时发送删除事件
- [x] `DataRepository` 在批量保存时保留运行时数据类型,避免自动备份读取到退化的 `IData` 类型
- [x] `SettingsModel.GetData<T>()` 在初始化后新增设置数据时会立即注册数据类型
- [x] `SettingsModel.RegisterApplicator<T>()` 会同步注册 applicator 绑定的数据类型
- [x] `SettingsModel.RegisterMigration(...)` 会失效对应类型的迁移缓存,避免 cache warm-up 后新增迁移不生效
- [x] 修复 `UnifiedSettingsDataRepository.SaveAsync(...)` 首次保存时可能发生的自锁死锁
- [x] `UnifiedSettingsDataRepository` 对齐 `DataRepositoryOptions` 契约,支持统一文件级自动备份
- [x] `UnifiedSettingsDataRepository.LoadAsync<T>()` 改为发送 `DataLoadedEvent<T>`,不再退化为
`DataLoadedEvent<IData>`
- [x] `UnifiedSettingsDataRepository.SaveAllAsync(...)` 改为批量提交语义,不再隐式重复发送单项保存事件
- [x] `UnifiedSettingsDataRepository` 改为“快照 -> 持久化 -> 交换缓存”的提交模型,避免失败写入污染内存中的已提交状态
- [x] `ISaveRepository<T>` 增加正式的 `ISaveMigration<T>` 迁移接口
- [x] `SaveRepository<T>` 在 `LoadAsync(slot)` 时支持按版本链自动迁移并回写升级后的存档
- [x] `SaveRepository<T>` 的迁移注册表增加并发访问保护,禁止同一 `FromVersion` 重复注册被静默覆盖

### 测试

- [x] 新增 `JsonSerializer` 直接单测
- [x] 新增 `SettingsModel` 直接单测
- [x] 新增 `FileStorage` / `SaveRepository` / `UnifiedSettingsDataRepository` 持久化测试
- [x] 新增 `SaveRepository` 迁移链、重复注册和缺失迁移链的直接单测
- [x] 新增 `DataRepository` 批量事件与自动备份直接单测
- [x] 新增 `DataRepository.SaveAllAsync(...)` 运行时类型批量覆盖回归测试
- [x] 新增 `SettingsSystem` 直接测试,覆盖 `ApplyAll / Reset / SaveAll / ResetAll`
- [x] 新增 `UnifiedSettingsDataRepository` 事件开启场景下的上下文集成测试
- [x] 新增 `UnifiedSettingsDataRepository` 保存/删除失败时缓存一致性回归测试
- [x] 定向测试通过:`JsonSerializerTests | SettingsModelTests | PersistenceTests`
- [x] 定向测试通过:`SettingsModelTests | PersistenceTests | SettingsSystemTests`
- [x] 定向测试通过:`PersistenceTests | SettingsSystemTests`
- [x] 定向测试通过:`PersistenceTests | SettingsSystemTests | SettingsModelTests`
- [x] 全量 `GFramework.Game.Tests` 通过

### 文档

- [x] 重写 `docs/zh-CN/game/setting.md`,对齐当前 `ISettingsModel` / `SettingsSystem` / `ISettingsData`
- [x] 修正 `docs/zh-CN/game/data.md`,把存档迁移文档更新为 `ISaveRepository<T>.RegisterMigration(...)` 的内建能力说明
- [x] 修正 `docs/zh-CN/game/data.md`,补充 `IDataRepository` / `UnifiedSettingsDataRepository` 的统一事件与备份语义说明
- [x] 修正 `docs/zh-CN/game/data.md`,补充 `UnifiedSettingsDataRepository` 的最小接入示例、
`RegisterDataType(...)` 说明与 `DataLoadedEvent<T>` 兼容性说明
- [x] 修正 `docs/zh-CN/game/index.md` 中 `JsonSerializer` 示例缺少 `Newtonsoft.Json` using 的问题
- [x] `setting.md` 中迁移接口示例统一改为 `ISettingsData`,清掉残留旧术语
- [x] 当时已更新 `AGENTS.md`,强调实现完成后必须同步维护恢复文档;当前仓库已由 `ai-plan` 治理规则接管该职责

## 历史改动文件

### 生产代码

- `GFramework.Game/Serializer/JsonSerializer.cs`
- `GFramework.Game/Setting/SettingsModel.cs`
- `GFramework.Game/Data/UnifiedSettingsDataRepository.cs`
- `GFramework.Game/Data/DataRepository.cs`
- `GFramework.Game.Abstractions/Data/ISaveMigration.cs`
- `GFramework.Game.Abstractions/Data/ISaveRepository.cs`
- `GFramework.Game/Data/SaveRepository.cs`
- `GFramework.Game.Abstractions/Data/DataRepositoryOptions.cs`

### 测试

- `GFramework.Game.Tests/Serializer/JsonSerializerTests.cs`
- `GFramework.Game.Tests/Setting/SettingsModelTests.cs`
- `GFramework.Game.Tests/Setting/SettingsSystemTests.cs`
- `GFramework.Game.Tests/Data/PersistenceTestUtilities.cs`
- `GFramework.Game.Tests/Data/PersistenceTests.cs`

### 文档

- `AGENTS.md`
- `docs/zh-CN/game/setting.md`
- `docs/zh-CN/game/data.md`
- `docs/zh-CN/game/index.md`

## 已验证结果

已执行:

```bash
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj --filter "JsonSerializerTests"
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj --filter "JsonSerializerTests|SettingsModelTests|PersistenceTests"
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "PersistenceTests"
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "PersistenceTests|SettingsSystemTests"
dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "PersistenceTests|SettingsSystemTests|SettingsModelTests"
```

结果:

- `JsonSerializerTests`:通过
- `JsonSerializerTests | SettingsModelTests | PersistenceTests`:12 个通过
- `PersistenceTests`(Release):7 个通过
- `PersistenceTests | SettingsSystemTests`(Release):16 个通过
- `PersistenceTests | SettingsSystemTests | SettingsModelTests`(Release):18 个通过
- `PersistenceTests | SettingsSystemTests`(Release,补充回归后):19 个通过
- `PersistenceTests | SettingsSystemTests | SettingsModelTests`(Release,补充回归后):21 个通过
- `GFramework.Game.Tests` 全量(Release):89 个通过

## 本轮发现的真实问题

### 已修复

- `UnifiedSettingsDataRepository.SaveAsync(...)` 在未加载状态下会先拿 `_lock`,再进入 `EnsureLoadedAsync()`,
导致首次保存等待同一把 `SemaphoreSlim`,形成死锁
- `UnifiedSettingsDataRepository` 在删除或保存时先原地修改 `_file` 再写盘,如果持久化失败会让内存缓存领先于
磁盘状态,后续无关保存可能把失败修改意外落盘;现已改为快照提交模型
- `SaveRepository<T>` 的迁移注册表在注册与加载并发时缺少同步保护,且重复注册相同 `FromVersion` 会被静默覆盖,
已改为加锁访问并显式拒绝重复注册

### 已确认但暂未展开

- `SettingsSystem` / `SettingsModel` 仍依赖上下文事件发送,单元测试需要显式提供上下文

## 当前剩余待办

### P0

- [x] 统一 `DataRepository` 与 `UnifiedSettingsDataRepository` 的持久化策略约定

### P1

- [ ] 评估是否要给 `JsonSerializer` 增加更明确的只读配置说明,例如线程安全和实例级 converter 使用方式
- [x] 为 `SettingsSystem` 增加直接测试,覆盖 `ApplyAll / Reset / SaveAll` 的系统层语义
- [x] 为 `UnifiedSettingsDataRepository` 增加事件开启场景下的上下文集成测试

### P2

- [ ] 评估把设置、存档、通用仓库的版本迁移模型做统一抽象
- [ ] 评估压缩 / 加密 / 元数据策略是否应放进更明确的 codec / persistence pipeline

## 下次恢复建议

建议从这里继续:

1. 先评估 `JsonSerializer` 的只读配置、线程安全与实例级 converter 使用说明
2. 再考虑设置 / 存档 / 通用仓库的迁移模型是否进一步统一
3. 最后评估压缩 / 加密 / 元数据策略是否抽成更明确的 codec / persistence pipeline

恢复时优先查看:

- `GFramework.Game/Data/SaveRepository.cs`
- `GFramework.Game/Data/UnifiedSettingsDataRepository.cs`
- `GFramework.Game/Data/DataRepository.cs`
- `GFramework.Game/Setting/SettingsModel.cs`
- `GFramework.Game/Setting/SettingsSystem.cs`
- `GFramework.Game/Serializer/JsonSerializer.cs`
- `GFramework.Game.Tests/Data/PersistenceTests.cs`
- `GFramework.Game.Tests/Setting/SettingsSystemTests.cs`
- `docs/zh-CN/game/data.md`

## 备注

- 该历史阶段形成时,仓库存在大量与本任务无关的既有改动
- 后续继续实施时,应继续把改动严格收敛在设置 / 持久化 / 序列化相关文件,避免误碰其他重构主线
Loading
Loading