ADR 0008:output/ 目录作为数据持久化源
状态:已接受
日期:2026-08-04
关联:docs/architecture/architecture.md(第1层 数据层)
背景
GUI 需要持久化计算结果,使用户关闭并重新打开应用后不丢失工作成果。
方案选项:
A. 自定义项目文件格式(.todproj JSON/binary)
B. 以 output/ 目录为事实来源,GUI 启动时扫描重建
C. SQLite 数据库
决策
以 output/ 目录为事实来源(方案 B)。每次计算结果自动写入 output/ 对应子目录,GUI 启动时扫描并重建 Project。
文件命名约定保持与现有 output/ 结构兼容:
output/
├── dro/ dro_<timestamp>.json
├── halo/ halo_<type>_<params>_<ts>.json
├── dpo/ dpo_<params>_<ts>.json
├── ro/ ro_<params>_<ts>.json
├── ephemeris/ orbit_ephemeris_<ts>.json
└── transfer/ search_*_<ts>.json, optimization_*_<ts>.json
理由
零额外持久化层:e2m2e 算法层已有
write_ephemeris()/save_to_file()方法,结果本来就要落盘。不需要再发明格式。CLI 用户友好:用户也可以直接用 e2m2e CLI 生成 output/ 文件,GUI 能自动发现。
无锁定:数据以标准 JSON 格式存储,不依赖 tod 的专有格式。
现有 output/ 兼容:用户已有的 output/ 文件自动出现在新 GUI 中。
后果
正面
不需要实现项目文件读写
e2m2e CLI 和 GUI 共享同一数据目录
用户可手动管理 output/(复制、备份、分享)
负面
内存中未落盘的 Artifact(正在计算中的中间结果)关窗即丢失
文件命名冲突需要处理(时间戳方案已足够)
没有撤销能力(删除是永久的)
修订(2026-08-19,issue #375,关联 e2m2e ADR 0031)
e2m2e 5.8.0 落地轨道库 catalog(上游 #475 / ADR 0031)后,产物持久化的职责上收:记录格式、存储引擎与查询接口归 e2m2e 数据层与接口层,本篇决策的适用面相应收窄。
决策变更:orbit / family / ephemeris 产物的清单与持久化改经 e2m2e Facade 的 catalog(
catalog_query供数、catalog_get懒加载),design_orbit / orbit_family_generation / control_orbit 的产物由 Facade 自动入库;本仓 persistence.py 的手写 JSON+NPZ 落盘与 discovery.py 的子目录名 + 文件名正则分类退役。文件命名不再承载分类语义:多维分类(族、平动点、Jacobi、振幅、段存在性)与source_record_id由上游在生成时写入记录,不再依赖 GUI 内存与文件名推断;上文文件命名约定表移交 e2m2e ADR 0031 维护。文件是事实来源不变:catalog 的记录文件(JSON + NPZ)是唯一持久化,SQLite 索引是派生物,删除后可扫描记录文件全量重建。当年未选的方案 C 指以数据库为持久化层;派生索引不构成格式锁定,与理由 3(无锁定)不冲突。
库目录:默认钉在仓库根
catalog/(与 output/ 平级,GUI 场景 cwd 不稳定,不能依赖上游的相对默认),可在 GUI 设置中改指其他目录(QSettings 持久化)。谱系:站保产物的
source_record_id由 Facade 写入(input_record_id输入),重启后经 catalog_query 重建因果链;上游记录被删时项目树显示断链降级标记,不阻止产物使用。过渡:transfer(转移轨道)等 catalog 分类体系之外的产物沿用 output/ 目录扫描(仅限这些目录),待上游对相应产物入库立项后退役。
旧产物:output/ 旧格式不迁移(上游 ADR 0031 决策 9),需要时重算,理由 4现有 output/ 兼容随之失效。
其余部分(Project 不做持久化、删除无撤销)不变。
修订(2026-09-26,issue #491,关联 e2m2e ADR 0047)
上游 e2m2e ADR 0047(随 v5.9.5)把 catalog_enabled 默认翻转为关、catalog_dir 默认 None:未指定目录时库操作报 CATALOG_NOT_CONFIGURED,未开入库开关时 record_id 静默为 None。上一节的库目录落点随之更新:库目录不再钉仓库根 catalog/,改由本仓在 Rust 壳 app setup 显式注入 E2M2E_CATALOG_ENABLED=1 与 E2M2E_CATALOG_DIR=<用户配置目录>/catalog(Windows %APPDATA%/transfer-orbit-design/catalog,Linux 为 XDG 配置目录下的同名路径,与情景、助手会话同级),不随工作目录漂移;改指方式为预设 E2M2E_CATALOG_DIR,用户预设优先。仓库根 catalog/ 余下供脚本与测试(Python 领域层默认)使用;旧库不迁移(见上一修订的旧产物条)。