Files
MapLibreParticleLab/docs/40_任务/STEP-070_MapLibreParticleLab_V3-06_四类场Fixture与RN通用回归_Codex任务_v1.md
OpenAI Codex 8588e6fcb8
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
feat: add V3 field fixtures and RN regression host
2026-09-11 09:56:53 +08:00

10 KiB
Raw Blame History

STEP-070 MapLibreParticleLab V3-06 四类场 Fixture 与 RN 通用回归 — Codex 任务 v1

1. 目标

基于 particle/main 当前 HEAD 3b012759838f1e1ecc44559faffe061d396b6cce,完成 V3 通用 Scalar/Vector Field 的离线业务语义映射与回归资产:Wind、Rain、Wave、Tide/Current 四类场,外加固定 synthetic Wave independence fixture。

本 Step 的重点不是增加新的 Runtime 架构,而是证明 STEP-065~069 冻结的通用契约能够由真实/可追溯数据映射并通过 .3 RN 公共 API 驱动。Android 编译/安装/ADB/设备视觉验证继续留到后续统一周期,不在本任务执行。

开始前完整阅读 AGENTS.md、PARTICLE_BASELINE.md、docs/00_项目规范/、STEP-065~069 Step/报告,以及当前实际源码。不得按记忆重建。

2. 必须保持的架构边界

  • Core/Renderer 不得出现 Wind/Wave/Rain/Tide/provider/network/vendor 业务分支。
  • Host/RN 负责业务字段到 canonical scalar/vector/validity 的映射。
  • canonical schema 继续使用 maplibre-particle-field/v2。
  • 一个 Snapshot:0/1 scalar + 0/1 vector + shared validity;neither 非法。
  • Wind / Tide(Current):vector VELOCITY,Field=VECTOR_MAGNITUDE,Particle 使用 VELOCITY。
  • Rain:scalar rain rate,Field=SCALAR,不启用 Particle。
  • Wave:scalar=wave height;vector=direction-to unit vector;semantics=DIRECTION;Field=SCALAR;Particle=DIRECTION,推进视觉速度只来自 advectionScale。
  • Wave period 不进入第二 scalar,不参与推进,不从 height/period 推导速度。
  • Rain precipitation_type 暂不进入 canonical V3.0。
  • T0/T1/MIX、Timeline、Playback、OLD_T1→NEW_T0 reuse 等 Core 逻辑不得修改。

3. 当前基线事实

  • RN package 已是 @navsea/maplibre-particle-rn@13.4.1-particle.3。
  • 正式 v2 API:FieldRuntime.submitField(reactTag, metadataJson, payloadRefs)。
  • payloadRefs 为必填 validity + optional scalar/vector local file URI,scalar/vector 至少一个。
  • .3 已提供 setFieldValueSource() 与 setParticleAdvectionScale()。
  • Android/JNI/Core multi-plane ingress 已实现,但 Android 编译留待 V3-08。
  • 现有 RN Test Host 的 REAL WEATHER 仍直接调用旧 WeatherRuntimeBridge.submitWindField();本 Step 必须迁移验证入口到 package .3 的 FieldRuntime,不能继续用旧 bridge 证明新 API。
  • 仓库已有真实 WeatherV2 Wind canonical 资产:platform/android/MapLibreAndroidTestApp/src/main/assets/integration/particle-weatherv2/ecmwf-hres-wind-20260807/。
  • WeatherV2 源树只读位于 /root/sourceserver/weatherV2;其 NSFT v1 语义以 src/dev/core/nsft.py 和当前生产 pipeline 为准。不要修改 WeatherV2。

4. 数据来源与可追溯性

先调查 /root/sourceserver/weatherV2 当前实际输出,优先从已存在的 NSFT v1 field_pmtiles//fields 等本地数值产物生成 fixture,不联网、不重新跑完整生产 pipeline。

至少为以下四类场确认一个可用 source/refTime/validTime/区域:

  • Wind
  • Rain
  • Wave
  • Tide/Current

优先选日本及周边、相邻两个实际 validTime,便于 T0/T1/MIX。若某层当前本地没有可用正式 NSFT 数值产物,不得伪称“真实 WeatherV2”;应在报告明确说明并使用最小可追溯 synthetic/decoder-derived fallback,同时保留该层的业务语义。Wind 已有真实 canonical 基线可直接复用/升级。

不得把旧 QBIN 当作正式未来 transport。若为数据核验读取旧 BIN,只能作为来源调查/对照,最终 fixture 必须输出 v2 canonical planes。

5. 新建通用 fixture/converter 工具

在 tools/ 下新增 provider-neutral 或 WeatherV2-to-canonical 的离线工具,具体目录名由实际实现确定,但不得只为 Wind 特化。

工具至少应支持把已解码/NSFT 数值场规范化为:

  • metadata.json
  • validity.u8
  • optional scalar.f32
  • optional vector.f32(interleaved U/V)
  • conversion_summary.json

约束:

  • float32-le;validity uint8;NW-origin row-major;rows north→south;cols west→east。
  • U eastward,V northward。
  • 每个输出文件记录 byteLength、SHA-256、grid、bounds、validTime、generation、source provenance。
  • vector DIRECTION 必须在 valid cell 上接近 unit length;允许原始量化误差,转换后可规范化,但近零/非 finite 必须 invalid/fail-closed,不得任造方向。
  • shared validity 必须由源有效性与所有存在 channel 的有限性共同约束;invalid cell 的具体 payload 值可为 0,但 validity=0 才是权威。
  • metadata 中不允许 Wind/Wave/Rain/Tide capability enum;fieldId 可包含可读 fixture 名称但 Core 不依赖它。

6. 四类 fixture 目录

新增仓库内固定测试资产,建议: integration/particle-v3-fields/

至少:

  • wind-real/:两个相邻 validTime,vector-only VELOCITY。
  • rain-real/:两个相邻 validTime,scalar-only。
  • wave-real/:两个相邻 validTime,scalar+vector DIRECTION。
  • tide-real/:两个相邻 validTime,vector-only VELOCITY。
  • wave-synthetic-independence/:两个兼容时次或至少足以验证 T0/T1 的 fixture。

若某 *-real 因本机数据缺失只能 fallback,目录名不得误用 real;改用 *-decoder-fixture 或等价明确命名,并在 dataset manifest/报告写明来源。

每组 fixture 提供 dataset.json,列出 frame 顺序、metadata/plane 路径、expected FieldValueSource、particle expected on/off、vector semantics、建议 advectionScale(Wave synthetic 可指定非 1 值用于验证 scale 独立性)。

7. Synthetic Wave Independence 固定语义

必须实现并静态验证:

  • scalar(wave height)西侧低、东侧高,形成明显 E→W 或 W→E 的横向数值梯度;
  • vector 在所有 valid cell 固定向北 (u=0, v=1);
  • vectorSemantics=DIRECTION;
  • Field source=SCALAR;
  • Particle 方向应只由 vector 决定为北向;scalar 改变不得改变粒子方向/推进 magnitude;
  • 改 advectionScale 只改变 DIRECTION visual movement magnitude,不改变 field scalar。

增加无 Android 的数据 oracle/脚本验证该 fixture:scalar 的东西梯度与 vector 的北向独立,不允许只靠人工阅读 JSON。

8. RN Test Host 升级到 .3 正式 API

只修改 Test Host 的 JS/TS 与离线 assets/config,不执行 Gradle。

要求:

  • REAL WEATHER/V3 验证入口从内部 WeatherRuntimeBridge.submitWindField 迁移到 @navsea/maplibre-particle-rn 的 FieldRuntime。
  • 不从 package 内部路径 import bridge。
  • 通过 app cache/local file URI 提交 metadata + plane refs;不得 JS number[] / base64 / giant JSON。
  • 提供四类场选择/加载能力,至少能在 UI/fixture runner 中选择 Wind/Rain/Wave/Tide 和 synthetic Wave。
  • 每次切换 dataset 前 clearFields(),设置正确的 setFieldValueSource()、Particle visibility、setParticleAdvectionScale(),再顺序提交 T0/T1。
  • 对每个 dataset 明确断言:T0=ACCEPTED_PENDING_INITIAL_WINDOW,T1=INITIAL_WINDOW_READY,runtime state=READY。
  • Rain 必须 Particle OFF;Wind/Tide Particle ON;Wave Particle ON 且 DIRECTION 数据不被改成 VELOCITY。
  • Field/Particle visibility 仍独立。
  • 不在 JS 保存 T0/T1/MIX 第二份 Runtime 状态;JS 只保存 fixture/选择 UI 与调用结果。
  • 现有 GSI/base map 与已验证 UI 可保留,不做无关重构。

9. Core/Linux 回归

新增最小 C++/数据 contract 测试,重点不是复制完整 Android bridge,而是验证:

  • 四类 canonical shape 能被 LocalParticleFieldFeed / RasterArraySource 接受。
  • Wind/Tide vector-only VELOCITY compatible T0/T1。
  • Rain scalar-only compatible T0/T1。
  • Wave scalar+vector DIRECTION compatible T0/T1。
  • channel presence/semantics mismatch 继续 fail-closed。
  • synthetic Wave 的 scalar/vector independence oracle。
  • normal T0→T1 / next snapshot 不修改 Runtime 算法。

如果现有 test 已覆盖底层形状,不重复堆测试;新增 fixture-specific contract test 即可。

10. 本 Step 不做

  • 不执行 Android Gradle/AAR/APK/ADB/设备测试。
  • 不执行 Jest。
  • 不修改 NavSea。
  • 不修改 WeatherV2 源项目。
  • 不联网下载天气数据。
  • 不引入 provider/network/cache/manifest runtime 到 C++ Core。
  • 不改 v2 schema、Timeline/Playback、shader 数学、DIRECTION 算法。
  • 不发布 npm/tgz/tag;.3 仅保持源码版本。
  • 不修改 STEP-062 两处现有用户 dirty 文档,不清理历史 untracked/build/cache。

11. 必须验证

至少执行并记录:

  1. fixture converter/validator 自检 PASS,含 plane byteLength/SHA/grid/bounds/time/finite/validity。
  2. synthetic Wave independence oracle PASS。
  3. package .3 TypeScript tsc --noEmit PASS。
  4. RN Test Host TypeScript/typecheck PASS(使用项目现有命令,不跑 Jest)。
  5. RN TurboModule codegen schema 检查 PASS,确保 STEP-069 ABI 未被破坏。
  6. 受影响 Core 精确对象编译 PASS。
  7. 相关 C++ fixture/Source 过滤测试 PASS。
  8. git diff --check PASS。

所有 noisy build 使用 $build-output-throttle。若完整 mbgl-test/runner 已经最新可直接使用;若因改 C++ test 触发重链,允许 Linux 重链。

12. 文档输出

必须生成/更新:

  • 本任务书。
  • docs/50_Step记录/STEP-070_MapLibreParticleLab_V3-06_四类场Fixture与RN通用回归_v1.md
  • docs/报告/STEP-070_MapLibreParticleLab_V3-06_四类场Fixture与RN通用回归_Codex完成报告_v1.md
  • 追加 粒子开发记录.md
  • 新工具 README / fixture dataset manifest 必须中文说明为主。

状态上限:IMPLEMENTED / WAITING_ANDROID_VALIDATION。不得标记 Android CLOSED/PASS。

13. Git 收尾

所有本任务实际修改必须 scoped commit 并 push origin/particle/main。

  • 开始/结束都核对 branch、HEAD、origin。
  • 严禁 git add . / git add -A。
  • 不提交 STEP-062 两处用户 dirty、历史任务 MD、build/cache/tgz。
  • 可使用 1 个实现 commit + 1 个文档 handoff commit;必要时再用一个纯 Git 元数据收尾 commit。
  • 完成报告记录 implementation/handoff commit、push result、remote branch、Final HEAD、HEAD == origin/particle/main。
  • push 失败不得声称完成。