chore: initialize insar management system v2

This commit is contained in:
2026-04-14 13:16:01 +08:00
commit ecc72ec9cd
361 changed files with 2142522 additions and 0 deletions
@@ -0,0 +1,359 @@
# SBAS 系统集成与数据管理审计报告
更新日期:2026-04-06
## 1. 审计范围
本次审计聚焦三件事:
- 当前 ISCE2 SBAS 实验是否已经真实读取并使用精密轨道
- 现有系统的数据管理方案是否适合承接 SBAS/PS-InSAR 生产口
- 如果后续要把实验方案嵌入系统,推荐怎样分阶段落地
本报告基于当前仓库实现与已成功的实验产物,不涉及对现有 D-InSAR 生产链的破坏性修改。
## 2. 结论摘要
- 结论 1:当前 SBAS 实验已经真实读取并使用精密轨道,不只是“数据库里有轨道路径”。
- 结论 2:当前系统可以完成 PS/SBAS 选片和实验产物生成,但还不能把 `psinsar` 产物作为正式生产结果注册、编目、健康检查和发布。
- 结论 3:当前数据管理整体偏“路径驱动”,原始数据身份、存储位置、运行产物三层边界不够清晰,因此用户会感到“数据管理比较松散”。
- 结论 4:轨道管理反而是当前较完整的一块,已经具备源目录扫描、池同步、一致性检查和数据库状态统计能力。
## 3. 审计发现
### P0 / 高优先级
#### 3.1 结果编目和发布入口仍然是 D-InSAR 专用,`psinsar` 实验产物无法直接接入系统
证据:
- `backend/app/services/result_catalog_service.py:707-713`
- `_load_manifest()` 只接受 `product_type == dinsar`
- `backend/app/services/result_catalog_service.py:750-753`
- 即使读入 manifest,也把 `product_type` 固定写成 `dinsar`
- `backend/app/routers/dinsar_products.py:107-140`
- 现有编目 API 和后台任务只暴露 `/dinsar-products/*`
- `backend/app/services/health_service.py:124-170`
- 结果目录健康检查只统计 `catalog_name == dinsar`
- `experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_unified_v1/manifest.json:2-9`
- 当前实验成功产物的 manifest 是 `schema_version = psinsar.publish.v1``catalog_name = psinsar`
影响:
- 实验已经能产出发布级 bundle,但系统当前不会把它识别为正式产品
- 不能复用现有结果页、目录重建、健康检查、产品详情接口
- 后续如果直接“硬塞”进 D-InSAR 目录,会污染现有 D-InSAR 语义
建议:
- Phase 1 不要新建一套完全独立的产品表,继续复用 `result_products` / `result_assets`
- 但必须让 catalog 服务显式支持 `catalog_name = psinsar`
- 最小可行改造是新增 `psinsar` manifest 解析路径,或把当前 catalog service 抽象成多 catalog 分发器
#### 3.2 `ps_task_batches` / `ps_task_items` 目前只是选片快照,不是生产记录
证据:
- `backend/app/models/orm.py:516-550`
- `PsTaskBatchORM` / `PsTaskItemORM` 只保存批次、`file_path`、日期、极化、是否有轨道和状态
- `backend/app/routers/task_batches.py:281-320`
- 创建 `/task-batches/ps` 时只是把选中的影像元数据写入 `ps_task_items`
- `backend/app/routers/pairing.py:124-147`
- 现有 `find-ps-timeseries` 只负责找 stack
- `backend/app/services/spatial_service.py:444-481`
- `find_ps_timeseries_data()` 只返回按轨道方向分组的影像栈
- `backend/app/services/job_handlers.py:306-321`
-`PS_STACK` 的后台处理目前只是复制选中的影像路径
影响:
- 系统里没有“某次 SBAS 生产运行”的业务主记录
- 无法稳定记录 `work_dir``publish_dir`、运行环境、参数版本、DEM、轨道来源、水体掩膜来源
- 无法形成真正可追溯、可重跑、可审计的生产口
建议:
- 新增业务表 `ps_timeseries_runs`
- 保留 `ps_task_batches` 作为“输入栈定义”
- 把真正的处理运行、产物发布、失败重试、步骤状态全部挂到 `ps_timeseries_runs + workflow_runs`
#### 3.3 数据身份与存储路径耦合过深,迁移和重构成本偏高
证据:
- `backend/app/models/orm.py:22-40`
- `RadarDataORM` 直接保存 `file_path``orbit_file_path``preview_cache_path`
- `backend/app/models/orm.py:82-101`
- `ResultProductORM` 直接保存 `publish_dir``manifest_path``source_primary_path``primary_asset_path`
- `backend/app/models/orm.py:182-195`
- `ResultAssetORM` 保存 `absolute_path`
- `backend/app/services/data_service.py:621-668`
- `unique_id` 通过 `os.path.relpath()` 生成,并按 `unique_id` 做 upsert
影响:
- 数据身份会受存储根目录变化影响
- Windows 根目录变更、WSL 路径调整、NAS 迁移时,数据库主身份和存储位置语义混在一起
- 产物迁移到正式发布目录后,历史绝对路径会变成系统耦合点
建议:
- 把“数据身份”和“存储位置”拆开
- 原始影像层至少补充稳定的 `scene_uid``product_uid`
- 结果层至少补充稳定的 `run_id` / `product_id` 业务主键,把绝对路径退化为可替换的存储定位信息
### P1 / 中优先级
#### 3.4 原始影像与轨道的关联粒度偏粗,缺少轨道版本与来源追踪
证据:
- `backend/app/services/data_service.py:611-612`
- 影像是否有轨道仅按 `(satellite, imaging_date)` 关联
- `backend/app/services/data_service.py:688-692`
- 后续补关联时也是按同一键更新
影响:
- 当同一天存在多个候选轨道版本时,数据库层无法区分来源和版本
- 无法在结果层明确回答“本次 SBAS 用的是哪份轨道文件、其 checksum 是多少、来自 source 目录还是 ISCE2 pool”
建议:
- 最小可行做法:在 `RadarDataORM` 或新表中增加
- `orbit_stem`
- `orbit_checksum`
- `orbit_source_type`
- `orbit_pool_path`
- 更完整做法:单独建 `orbit_assets` / `orbit_bindings`
#### 3.5 数据扫描服务职责过重,扫描、轨道同步、预览缓存、数据库写入耦合在一起
证据:
- `backend/app/services/data_service.py:426-463`
- 扫描原始轨道并同步 ENVI / ISCE2 池
- `backend/app/services/data_service.py:568-699`
- 同一流程里完成影像元数据读取、轨道关联、数据库 upsert
- `backend/app/services/data_service.py:709-739`
- 后面又继续做缓存重建候选收集
影响:
- 这个服务变成“总装配间”,测试和回归都更困难
- 后续要引入 SBAS 生产口时,很容易继续把更多责任塞进同一个服务
建议:
- 拆分为至少四块:
- `radar_inventory_service`
- `orbit_inventory_service`
- `radar_catalog_service`
- `preview_cache_service`
#### 3.6 Windows/WSL 双路径模型是当前现实,但需要收口到专门的路径层
证据:
- `backend/app/config.py:150-186`
- 同时维护 Windows 轨道池、DEM、IDL、WSL distro、WSL Python 等配置
- `experiments/isce2_sbas_timeseries/scripts/build_lt1_stack_prep.py:140-149`
- 实验准备阶段会解析 orbit XML
- `experiments/isce2_sbas_timeseries/scripts/build_lt1_stack_prep.py:171-193`
- 同时生成 Windows 路径和 WSL 路径
- `experiments/isce2_sbas_timeseries/scripts/materialize_lt1_stack_scenes.py:98-103`
- 物化阶段直接把 orbit XML 传给 ISCE2 sensor
影响:
- 当前方案能跑通,但如果没有统一的路径转换层,后续每个服务都可能自己拼接 `/mnt/*`
- 这会继续加重“数据管理松散”的体感
建议:
- 保留当前双路径现实,不要硬回避
- 但把路径转换统一收敛到 `timeseries_paths.py` 或类似组件
- 生产口只暴露业务字段,不让上层 UI 和业务逻辑直接感知 `/mnt/z``F:\`
### P2 / 正向发现
#### 3.7 轨道管理是当前系统里相对成熟的一块
证据:
- `backend/app/services/data_service.py:426-463`
- 已有源目录扫描与 ENVI / ISCE2 轨道池同步
- `backend/app/routers/orbit.py:27-108`
- 已有数据库统计、池一致性检查、缺口汇总
结论:
- 不需要为 SBAS 重新发明一套轨道管理
- 更合理的方向是复用现有轨道池和一致性检查能力,再补生产级 provenance
## 4. 关于“现在实验读取精密轨道了吗”
答案:是,已经读取,而且已进入实际处理链。
证据链如下:
1. 轨道解析入口:
- `backend/app/isce2_pipeline/lt1_input_resolver.py:165-201`
- `ensure_lt1_orbit_xml()` 会优先取已有 XML,找不到才从 LT-1 轨道 txt 生成 XML
2. Stack 准备阶段:
- `experiments/isce2_sbas_timeseries/scripts/build_lt1_stack_prep.py:140-149`
- 每景影像都调用 `ensure_lt1_orbit_xml()`
3. Stack 物化阶段:
- `experiments/isce2_sbas_timeseries/scripts/materialize_lt1_stack_scenes.py:98-103`
- `sensor.orbitFile = orbit_xml`
4. 实验 manifest 证据:
- `experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_input_manifest.json:92-95`
- `experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_input_manifest.json:123-126`
- `experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_input_manifest.json:154-157`
- manifest 已明确记录 `D:\\orbit_pools\\isce2\\LT1A_GpsData_GAS_C_*.xml`
5. 运行日志证据:
- `experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/logs/run_01_reference.log:18`
- `experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/logs/run_03_geo2rdr_coarseResamp.log:6`
- 日志中已出现 `Orbit interpolation method: hermite`
结论补充:
- 当前 SBAS 实验使用的是 ISCE2 轨道池中的 XML 精轨
- 因此“精轨是否已读入”这件事在实验层已经成立
- 真正缺的不是“有没有轨道”,而是“系统如何把这次运行及其轨道 provenance 规范地登记为生产记录”
## 5. 集成设计建议
### 5.1 集成边界
当前最合理的系统集成边界不是 MintPy 运行目录,而是发布级 bundle:
- 入口文件:`manifest.json`
- 目录结构:`assets/``preview/``metadata/`
这与现有产品规范一致:
- `docs/ISCE2_SBAS_PRODUCT_SPEC.md:69-88`
因此:
- 不要直接注册 `stack_work/mintpy_sbas_*`
- 要注册 `publish/.../manifest.json` 所代表的一整个 bundle
### 5.2 推荐最小落地架构
#### 层 1:规划层,继续复用现有能力
- 继续使用 `find-ps-timeseries`
- 继续使用 `ps_task_batches` / `ps_task_items`
- 其职责只保留为“选片与栈定义”
#### 层 2:生产层,新增业务主记录
新增 `ps_timeseries_runs`,至少包含:
- `run_id`
- `batch_id`
- `catalog_name`
- `engine_code`
- `processor_code`
- `env_name`
- `wsl_distro`
- `work_dir`
- `publish_dir`
- `manifest_path`
- `reference_date`
- `direction`
- `params_json`
- `summary_json`
- `orbit_summary_json`
- `dem_path`
- `water_mask_source`
- `status`
- `error_message`
- `started_at`
- `ended_at`
#### 层 3:编目层,扩展现有结果目录
不要单独再造一套产品表,继续复用:
- `result_products`
- `result_assets`
- `result_issues`
但要新增 `psinsar` catalog 入口,支持:
- 解析 `psinsar.publish.v1`
- 注册 `catalog_name = psinsar`
- 单独的 catalog status / rebuild / health-check
#### 层 4:接口层
建议新增:
- `POST /timeseries-production/runs`
- `GET /timeseries-production/runs`
- `GET /timeseries-production/runs/{run_id}`
- `POST /timeseries-production/runs/{run_id}/retry-step`
- `GET /ps-products`
- `GET /ps-products/{product_id}`
- `POST /ps-products/rebuild-catalog`
### 5.3 与当前设计文档的一致性
当前仓库里的 SBAS 设计文档已经提前写出了这条路线:
- `docs/ISCE2_SBAS_TIMESERIES_DESIGN.md:227`
- 建议新增 `ps_timeseries_runs`
- `docs/ISCE2_SBAS_TIMESERIES_DESIGN.md:292-296`
- 建议新增 SBAS 相关 job types
- `docs/ISCE2_SBAS_TIMESERIES_DESIGN.md:306-313`
- 建议新增 `timeseries_production` / `ps_products` / `psinsar_catalog_service`
- `docs/ISCE2_SBAS_TIMESERIES_DESIGN.md:563-575`
- TODO 中已明确列出 ORM、路由、job handler、catalog 扩展和健康检查
所以本次审计的判断不是与现有设计冲突,而是说明:
- 实验层已经坐实
- 代码现实也证明下一步确实该进入“生产层与 catalog 层补齐”
## 6. 建议 TODO
### 6.1 立即做
- [ ] 新增 `ps_timeseries_runs` ORM / schema / migration
- [ ] 新增 `timeseries_production` router
- [ ] 新增 `PUBLISH_PSINSAR_PRODUCTS` 及相关 job handlers
- [ ] 让 catalog 服务支持 `psinsar.publish.v1`
- [ ]`publish/.../manifest.json` 作为唯一注册入口
### 6.2 紧接着做
- [ ]`ps_timeseries_runs` 记录 DEM、轨道、水体掩膜、运行环境版本
- [ ] 给轨道绑定补 provenance 字段或单独轨道资产表
- [ ] 把 Windows/WSL 路径转换收敛到独立路径服务
- [ ]`psinsar` 增加 catalog health-check 与 rebuild
### 6.3 暂缓做
- [ ] 不要现在就改动现有 D-InSAR 生产链
- [ ] 不要把 SBAS 运行目录直接暴露为产品目录
- [ ] 不要为了 SBAS 先拆掉现有 `result_products`
## 7. 审计结论
如果现在问“SBAS 能不能开始往系统里接”,答案是:
- 能,但应该先接“发布 bundle + 生产记录 + psinsar catalog”
- 不能直接把实验目录粗暴塞进现有 D-InSAR 产品体系
如果现在问“系统的数据管理为什么显得松散”,核心原因是:
- 原始数据身份、物理存储路径、生产产物目录三层目前还没有彻底分开
如果现在问“下一步最值得做什么”,答案是:
- 先把 `ps_timeseries_runs + psinsar catalog` 这两个缺口补上
这样既不会动坏现有 D-InSAR 生产,又能把已经验证成功的 SBAS 实验稳稳接成系统能力。