diff --git a/docs/40_任务/STEP-062_RNTestHost真实WeatherV2底图粒子综合验证_Codex任务_v1.md b/docs/40_任务/STEP-062_RNTestHost真实WeatherV2底图粒子综合验证_Codex任务_v1.md new file mode 100644 index 000000000..5c1004735 --- /dev/null +++ b/docs/40_任务/STEP-062_RNTestHost真实WeatherV2底图粒子综合验证_Codex任务_v1.md @@ -0,0 +1,346 @@ +# STEP-062 RN Test Host 真实 WeatherV2 底图粒子综合验证 — Codex任务 v1 + +## 1. 任务定位 + +当前正式分支:`particle/main`。 + +开工基线: + +- STEP-061 已正式 `CLOSED / PASS`。 +- 当前 local / remote HEAD 均为 `729d22169da5cb2d5a4eafbded8dde894739dee6`。 +- Native/Core 冻结制品:`org.maplibre.gl:android-sdk-opengl:13.4.1-step061`。 +- STEP-062 不进入 NavSea,只在 `MapLibreParticleRNTestHost` 内完成接近最终使用形态的天气地图综合验证。 + +本阶段目标不是继续扩展 AAR,而是证明: + +```text +GSI 底图 + + +真实 WeatherV2 canonical T0/T1/T2/T3 + + +WeatherColorLayer + + +RasterParticleLayer + + +Timeline / Playback +``` + +在 React Native Test Host APK 中可以稳定共同工作。 + +## 2. 最高优先级边界 + +本任务默认**禁止修改和禁止重新构建 AAR**: + +- 不修改 `src/`、`include/` 下 MapLibre Native/Core 粒子实现; +- 不修改 `platform/android/MapLibreAndroid`; +- 不修改 JNI; +- 不修改 `WeatherRuntime.java`; +- 不修改 STEP-061 Binary ingress; +- 不执行 `make apackage`; +- 不执行 Maven Local publish; +- 不生成新的 `13.4.1-step062` AAR; +- 不进入 NavSea。 + +Test Host 继续固定消费已经通过实机验收的: + +```text +org.maplibre.gl:android-sdk-opengl:13.4.1-step061 +``` + +如果实现或 Android 验收证明 `step061` Native/Core 存在真实阻塞缺陷,必须停止扩大 STEP-062,并在报告中明确 `BLOCKED_BY_NATIVE`;不得为了方便顺手改 Core 后重出 AAR。 + +## 3. 开工前必读与真实基线 + +必须先读取并遵守: + +1. `AGENTS.md` +2. `PARTICLE_BASELINE.md` +3. `docs/00_项目规范/` 当前规范 +4. `docs/50_Step记录/STEP-061_Binary_UV_Field_Transport_v2.md` +5. `docs/报告/STEP-061_Android最终验收报告_v1.md` +6. `docs/50_Step记录/STEP-055_Android真实WeatherV2风场综合可视化_v7.md` +7. `docs/20_调查/STEP-056_RN天气渲染桥接现状调查_v1.md` +8. `integration/react-native/MapLibreParticleRNTestHost/` 当前实际源码 +9. Android Validation 中当前 GSI / REAL WEATHER 的实际实现,不得凭记忆重写。 + +当前已确认事实: + +- RN Test Host 的底图目前只是 `background-color: #10243a`,没有真实地图瓦片。 +- Android Validation 已使用 GSI 标准地图:`https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png`,tileSize=256,maxzoom=18。 +- 当前真实 WeatherV2 数据为 ECMWF HRES 2026-08-07 四帧:`2026080700/06/12/18`。 +- 每帧 grid=`513×769`,payload=`3,155,976 bytes`。 +- bounds=`west 112.5 / south 0.0 / east 157.5 / north 55.77657301866769`。 +- canonical contract 仍是 `maplibre-particle-field/v1`、`float32-le`、`interleaved-uv`、U eastward、V northward。 +- RN bridge 已有 `submitWindField`、forecast time、PLAY/PAUSE、playback speed、WeatherColor stops、particle/trail color、粒子视觉参数、targetFps、getState;本阶段不新增 Native API。 + +## 4. 真实 WeatherV2 资产 + +源资产固定来自: + +```text +platform/android/MapLibreAndroidTestApp/src/main/assets/integration/particle-weatherv2/ + ecmwf-hres-wind-20260807/ +``` + +把本阶段实际需要的 `dataset.json`、四份 `metadata.json`、四份 `field.f32` **原样复制**到 RN Test Host 自己的受控 assets 目录,例如: + +```text +integration/react-native/MapLibreParticleRNTestHost/assets/weather/ + ecmwf-hres-wind-20260807/... +``` + +要求: + +- 不重新生成、不重采样、不裁剪、不改 metadata; +- 不把 `.f32` 转成 JSON、base64、hex 或 `number[]`; +- 复制后逐文件 SHA-256 与源资产一致; +- `field.f32` 内容必须与已有 Git blob 完全一致; +- 不创建第二套“近似 WeatherV2”测试数据。 + +## 5. RN 资产加载与 Binary transport + +继续使用 STEP-061 的正式 file-reference transport,不新增第二条路径。 + +建议实现: + +1. 将 `expo-asset` 作为 Test Host 的明确直接依赖,版本保持当前 Expo 56 兼容范围,不升级 Expo/RN。 +2. 新增 `metro.config.js`,只补充 `.f32` 为 asset extension;不得改动无关 Metro 行为。 +3. 新增一个小型 `realWeatherDataset.ts`(或等价文件),用静态 `require()` 注册四帧 `.f32` asset 与 metadata。 +4. 通过 `Asset.fromModule(...).downloadAsync()` 获得 app 本地 `file://` URI。 +5. metadata 继续以小型 JSON string 传入;payload 只传本地文件引用。 +6. 不在 JS 中把 3.01 MiB payload materialize 成数值数组;不做 base64。 + +必须明确显示并验证: + +```text +REAL DATA TRANSPORT = FILE_REF / FLOAT32_LE / INTERLEAVED_UV +``` + +若 Expo Asset 最终不能稳定给出本地文件 URI,先报告阻塞;不要退回 base64/number[]。 + +## 6. GSI 底图 + +将 RN Test Host 的纯色背景升级为真实 GSI 标准底图。 + +Style 最小结构固定为: + +```text +background +GSI raster basemap +WeatherColorLayer +RasterParticleLayer +``` + +要求: + +- raster source 使用 Android Validation 已验证 URL; +- source 写明合适 attribution(至少标明国土地理院 / GSI); +- tileSize=256,maxzoom=18; +- WeatherColor 和 Particle 必须在 GSI 之上; +- 不把 WeatherColor 或粒子烘焙进底图; +- 不增加 provider-specific Weather 逻辑。 + +使用 MLRN 11.3.6 当前真实 `Camera` API,初始视图应直接覆盖 WeatherV2 bounds 或合理聚焦日本及周边;不得让用户每次启动后手工从世界视图找数据。 + +页面至少显示: + +- `Basemap: GSI READY / ERROR / LOADING` +- map/style loading error(若存在) +- 当前 weather dataset identity。 + +## 7. T0~T3 提交与 Timeline + +新增一个明确的 `LOAD REAL WEATHER T0-T3` 综合入口。 + +每次执行前必须: + +1. `clearWindFields()`; +2. 确认四帧本地 asset 已 materialize 为 file URI; +3. 按 validTime 严格递增提交 T0/T1/T2/T3; +4. 每帧提交后记录结构化结果; +5. 最终重新读取 Native `getState()`。 + +硬断言: + +- T0 = `ACCEPTED_PENDING_INITIAL_WINDOW` +- T1 = `INITIAL_WINDOW_READY` +- T2 = `ACCEPTED_NEXT_SNAPSHOT` +- T3 = `ACCEPTED_NEXT_SNAPSHOT` +- 最终 Native state = `READY` + +任一不符都显示 `ERROR`,不得把部分成功显示为 READY。 + +UI 至少显示: + +```text +Dataset: ECMWF HRES 20260807 +T0 2026080700: +T1 2026080706: +T2 2026080712: +T3 2026080718: +Runtime: READY / ... +``` + +RN 只提交 producer timestamp,不保存第二套 T0/T1/MIX Runtime Window;Core Timeline 仍是唯一 owner。 + +## 8. Playback / Forecast 综合控制 + +在现有 Bridge API 上补齐 Test Host 可操作 UI,不新增 Native contract: + +- PLAY +- PAUSE +- HALF / NORMAL / DOUBLE +- seek T0 / T1 / T2 / T3 对应的 forecast timestamp +- FPS AUTO / 30 / 60 +- WeatherColor visible / opacity +- Particle visible +- WeatherColor stops(可使用已冻结的测试色带) +- particleColor / trailColor +- particle count / line width / length / opacity / trail opacity / trail fade + +测试 UI 可以紧凑,但必须让真实地图保持主要可视区域;不要把控制面做成遮住地图的大面板。 + +Forecast seek 必须调用现有 `setForecastTime(timestampMs)`;禁止把 index/T0/T1/MIX 暴露成 JS 业务状态。 + +## 9. 视觉与地图综合验收准备 + +代码必须让后续 Android 一次 APK 验收能够观察: + +- GSI 海岸线、地名等底图正常; +- WeatherColor 与地图地理位置对齐; +- Particle 与 WeatherColor 使用同一真实 Field; +- pan / zoom / bearing 后粒子与底图保持地理锁定; +- T0/T1/T2/T3 seek 后场景可继续渲染; +- PLAY/PAUSE/速度切换不造成 style reload; +- WeatherColor visible 与 Particle visible 相互独立; +- FPS 切换不改变 forecast/canonical 数据语义。 + +## 10. 临时文件与稳定性 + +本阶段要明确 3 MiB 级 asset 的生命周期,但不做 zero-copy 性能工程。 + +要求: + +- `expo-asset` 产生的本地文件由 Expo/系统 cache 生命周期管理;不要额外复制多份 payload; +- 若代码另建临时文件,提交结束后必须有明确清理路径; +- Fast Refresh、重复 LOAD、clear、detach 不得无限累积自建 `.f32` 临时文件; +- 不为了“减少 copy”引入 JSI、direct ByteBuffer、mmap 或新的 Native transport; +- Android 验收阶段观察连续 T0~T3 提交是否出现 OOM、长时间卡死或明显异常 GC;本任务不提前做性能优化。 + +## 11. 允许修改范围 + +优先只允许: + +- `integration/react-native/MapLibreParticleRNTestHost/App.tsx` +- `integration/react-native/MapLibreParticleRNTestHost/src/**` +- `integration/react-native/MapLibreParticleRNTestHost/assets/**` +- `integration/react-native/MapLibreParticleRNTestHost/metro.config.js` +- `integration/react-native/MapLibreParticleRNTestHost/package.json` +- `integration/react-native/MapLibreParticleRNTestHost/package-lock.json` +- `integration/react-native/MapLibreParticleRNTestHost/README.md` +- 本 Step 的中文记录/报告/开发记录。 + +如非必要,不修改 `modules/weather-runtime-bridge/**`;当前 Bridge API 已足够完成任务。 + +明确禁止提交: + +- `android/` generated build 目录; +- `node_modules/`; +- `.codex-build-logs/`; +- APK/AAR; +- 与本任务无关的历史 untracked 文件。 + +## 12. Codex 静态验证 + +Codex 必须执行并记录: + +1. `npm run typecheck`。 +2. `metro.config.js` 的 Node 语法/配置检查。 +3. 四帧 Test Host asset 与源 WeatherV2 asset 的 SHA-256 一致性检查。 +4. 检索正式 transport 不存在 `number[]` / payload JSON / base64 / hex。 +5. 检查 style layer 顺序确实为 GSI → WeatherColor → Particle。 +6. `git diff --check`。 + +未经用户明确要求:**不加入 Jest,不运行 Jest**。 + +Codex 不执行: + +- Android Gradle; +- `assembleDebug`; +- ADB; +- APK install; +- Android 设备测试; +- AAR build/publish。 + +Android APK 编译和设备综合验收仍由后续 CARBON7i 手工周期执行,并尽量一次覆盖全部 STEP-062 验收项。 + +## 13. 必做输出 + +至少完成: + +1. RN Test Host 的 GSI + Real Weather + WeatherColor + Particle + Playback 代码。 +2. 原样复用的四帧 WeatherV2 assets。 +3. 更新 Test Host 中文 README,说明 STEP-062 操作方法和冻结的 `step061` AAR。 +4. `docs/50_Step记录/STEP-062_RNTestHost真实WeatherV2底图粒子综合验证_v1.md`。 +5. `docs/报告/STEP-062_RNTestHost真实WeatherV2底图粒子综合验证_Codex完成报告_v1.md`。 +6. 追加 `粒子开发记录.md`。 + +完成报告必须明确: + +- 实际修改文件; +- GSI source/layer 与 camera 实现; +- 四帧 asset 来源、大小和 SHA 对照; +- Expo Asset → local file URI → STEP-061 bridge 的实际调用链; +- T0~T3 的预期 submit result; +- Playback/forecast/visual 控件接线; +- 是否修改任何 Native/Core/WeatherRuntime/JNI(预期:否); +- 是否构建/发布 AAR(必须:否); +- 实际静态验证结果; +- Android APK/设备仍待哪些项目验证。 + +源码阶段状态只能写: + +```text +IMPLEMENTED / WAITING_ANDROID_VALIDATION +``` + +不得提前写 Android PASS。 + +## 14. Git 收尾 + +本任务会生成/修改项目文件,因此完成后必须: + +1. 逐项对照本任务必做项; +2. `git diff --check` PASS; +3. 只 `git add` 本任务相关文件; +4. commit 到当前 `particle/main`; +5. `git push origin particle/main`; +6. 完成报告记录 final commit、commit message、push 结果、remote branch; +7. push 失败不得声称任务完成。 + +不得把现有历史 untracked 文件加入提交。 + +## 15. 最终必做清单 + +- [ ] GSI raster basemap 已进入 RN Test Host +- [ ] layer order = GSI → WeatherColor → Particle +- [ ] Camera 初始范围能直接看到 WeatherV2 区域 +- [ ] 四帧真实 WeatherV2 asset 原样复制且 SHA 一致 +- [ ] `.f32` 走 Expo Asset local file URI +- [ ] 继续使用 STEP-061 file-reference transport +- [ ] T0/T1/T2/T3 结果做严格 hard assertion +- [ ] 最终 Native state 必须要求 READY +- [ ] PLAY/PAUSE/速度/forecast seek 可操作 +- [ ] WeatherColor 与 Particle 独立显隐和视觉控制保留 +- [ ] FPS AUTO/30/60 可操作 +- [ ] 不创建第二套 T0/T1/MIX 状态 +- [ ] 不使用 number[]/payload JSON/base64/hex +- [ ] 不修改 Native/Core/JNI/WeatherRuntime +- [ ] 不构建或发布 AAR +- [ ] 不进入 NavSea +- [ ] 不加入或运行 Jest +- [ ] `npm run typecheck` PASS +- [ ] asset SHA 检查 PASS +- [ ] `git diff --check` PASS +- [ ] Step/报告/开发记录完成 +- [ ] commit + push `origin/particle/main`