# STEP-065 MapLibreParticleLab V3 通用 Scalar / Vector Field 架构冻结 — Codex 任务 v1 ## 0. 任务定位 本任务是 MapLibreParticleLab V3 的第一步:**只读调查当前真实实现,并冻结 V3 通用 Scalar / Vector Field Contract 与迁移方案。** 本任务不直接修改 C++、shader、JNI、Kotlin/Java、React Native Runtime 或 Android AAR。 V3 的目标不是“增加 Rain/Wave 两种天气类型”,而是把当前主要围绕 WIND + interleaved U/V 的运行时升级为: > provider-neutral、business-neutral 的二维时序 Scalar / Vector Field Rendering Runtime。 当前已冻结的上游边界: ```text WeatherV2 -> NSFT -> NavSea JS/TS -> Canonical Field -> MapLibreParticleLab V3 ``` WeatherV2 统一向 NavSea 提供 NSFT;NavSea JS/TS 负责网络、缓存、NSFT 解码、tile 拼接、业务单位与 canonical 化;MapLibreParticleLab 从 canonical field 开始接管。 ## 1. 仓库与执行基线 仓库: ```text /mnt/sda1/MapLibreParticleLab ``` 分支:`particle/main` 任务书生成时 HEAD: ```text 2e3ab26275a8d1873d764cf6927783a7b0406836 ``` 该 HEAD 已完成并冻结 STEP-064 RN 纯 Field Renderer `13.4.1-particle.2`。 执行开始时必须重新确认: ```bash git branch --show-current git rev-parse HEAD git rev-parse origin/particle/main git status --short ``` 若远端已合法推进,先阅读新增提交后再继续;禁止 reset、checkout 覆盖或回退用户工作。 当前工作区已知存在与本任务无关的用户修改和历史未跟踪文件,特别包括 STEP-062 文档、Android/Expo/build 目录、旧任务书和 tgz。 必须遵守: - 禁止 `git add .`、`git add -A`。 - 禁止删除、恢复、格式化、移动无关 modified/untracked 文件。 - 本任务只允许新增/修改 STEP-065 明确列出的文档产物和本任务书自身。 - 本任务不允许以“清理工作区”为理由处理历史文件。 ## 2. 执行前必须阅读 至少完整阅读: ```text AGENTS.md PARTICLE_BASELINE.md docs/00_项目规范/01_Codex协作规范_v1.md docs/00_项目规范/02_构建与验证规范_v1.md docs/00_项目规范/03_Step阶段记录规范_v1.md docs/00_项目规范/05_粒子架构原则_v1.md docs/40_任务/STEP-064_RN纯FieldRenderer接口V2_Codex任务_v1.md docs/50_Step记录/STEP-064_RN纯FieldRenderer接口V2_v1.md docs/报告/STEP-064_RN纯FieldRenderer接口V2_Codex完成报告_v1.md ``` 并重点阅读当前真实实现: ```text include/mbgl/particle/field/field_data_adapter.hpp src/mbgl/particle/field/field_data_adapter.cpp 所有 Timeline / Runtime Field Window 实现 WeatherColorLayer 相关 C++ / shader / shader generator RasterParticleLayer 相关 C++ / particle simulation shader GPU field texture / upload / reuse / lifecycle 实现 Android Host WeatherRuntime / JNI submission packages/maplibre-particle-rn/src/index.ts packages/maplibre-particle-rn/src/types.ts packages/maplibre-particle-rn/src/FieldRuntime.ts packages/maplibre-particle-rn/src/NativeWeatherRuntimeBridge.ts integration/react-native 中当前正式 Consumer/Test Host ``` 必须通过当前源码回答问题,不得根据历史任务书猜实现。 ## 3. WeatherV2 外部输入事实与只读核对 WeatherV2 实际目录: ```text /root/sourceserver/weatherV2 ``` 可只读核对以下文件,不得修改 WeatherV2: ```text src/dev/core/nsft.py src/dev/core/field_pmtiles.py src/dev/layers/wind.py src/dev/layers/tide.py src/dev/layers/rain.py src/dev/layers/waves.py ``` 已调查结论必须作为 V3 设计输入: - Wind NSFT:物理速度 U/V,单位 m/s,vector-only。 - Tide/Current NSFT:物理速度 U/V,单位 m/s,vector-only。 - Rain NSFT:rain rate scalar + valid mask;当前 NSFT 不保存 precipitation type。 - Wave NSFT:height scalar + period scalar + normalized direction-to U/V;direction U/V 不是 m/s。 - NSFT grid 为 `wm_grid_257`,NW origin,行 north->south,列 west->east。 - 同 zoom 相邻 257 tile 有共享边界,NavSea 拼接后 canonical grid 可保持 `(tiles*256)+1` 规则,无需 Core 理解 tile。 - Forecast target time 必须按实际 validTime/time_index 使用,Core 不假设固定 1h cadence。 这些事实如与当前 WeatherV2 代码不一致,报告差异并以当前代码为准。 ## 4. V3 冻结边界 V3 Core/Native 不得负责: - NSFT / PMTiles / WeatherV2 解析; - HTTP、provider、manifest、time_index、cache、retry、prefetch; - ECMWF / CMEMS 等业务来源; - Wind / Rain / Wave / Tide 业务分支; - kt、mm/h、m、m/s 等宿主业务单位转换; - NavSea 当前 Layer、Forecast UI 或业务状态。 V3 从 Canonical Field Submission 开始负责: - descriptor / payload validation; - Snapshot; - Timeline / target time / playback; - T0/T1/MIX; - Runtime Field Window; - OLD_T1 -> NEW_T0 reuse; - GPU channel resource 生命周期; - Field Renderer; - Particle Renderer; - MapLibre style/viewport lifecycle recovery; - fail-closed。 ## 5. 必须冻结的最小 Canonical 模型 V3.0 只设计: ```text FieldSnapshot ├─ common descriptor ├─ scalar channel? 0 or 1 ├─ vector channel? 0 or 1 (U/V) └─ shared validity ``` 禁止第一版扩成 N scalar / N vector generic graph。 必须支持三种合法组合: ```text vector-only scalar-only scalar + vector ``` Neither 必须 invalid / reject。 优先扩展当前 `ParticleFieldDescriptor / ParticleFieldSnapshot / ParticleFieldDataAdapter`,禁止并行创建 `GenericWeatherField`、`WindFieldV2` 等第二套重复模型。 当前 `fieldType == "WIND"`、`displayDomain == "GLOBAL"` 等硬编码必须被调查并给出 V3 最小迁移方案;Core 最终不得靠 WIND/WAVE/RAIN/TIDE 决定数据能力。 ## 6. Renderer Contract 必须与数据 Contract 分离 必须调查并冻结以下原则: `FieldSnapshot` 只描述“有什么数据”;Renderer config 描述“如何画”。 第一版 Field Renderer 的通用值来源建议为: ```text SCALAR VECTOR_MAGNITUDE ``` 即: - `SCALAR`:色场读取 explicit scalar channel; - `VECTOR_MAGNITUDE`:色场读取 `sqrt(U^2 + V^2)`。 不得让 Renderer 根据 business type 或“有没有 scalar”偷偷猜来源。 必须调查当前 WeatherColorLayer/shader 是否硬依赖 `length(U,V)`,以及将其泛化所需最小接口、uniform/property、GPU resource 与 style property 改动。 `FieldColorStop.value` 的 RN 公共语义保持 generic;调查 Native/JNI/C++ 内 `speedMps` 命名实际范围,并给出兼容迁移路径。 ## 7. Vector Semantics 必须业务无关 必须调查当前 Particle Integrator / shader 是否隐含: ```text U/V = physical velocity (m/s) ``` V3 需要覆盖至少两类数学语义: ```text VELOCITY DIRECTION ``` 目标映射: - Wind/Tide -> VELOCITY; - Wave direction-to U/V -> DIRECTION。 不得在 Core 增加 Wind/Wave/Tide enum 来解决。 对于 DIRECTION,设计必须说明: - T0/T1 vector mix 后是否 normalize; - 接近零向量/接近反向插值如何 fail-closed; - particle movement 的独立 advection scale 放在哪一层; - 如何保证 VELOCITY 当前 Wind 行为不被改变。 本任务只冻结方案,不实现 Wave physics。 ## 8. Binary Submission / Channel Plane 设计 当前 RN 公共入口是: ```text submitField(metadataJson, payloadFileUri) ``` 当前 Core canonical payload 是: ```text float32-le / interleaved-uv ``` 必须调查 RN -> Android bridge -> JNI -> Core 的真实 ownership、文件读取、byte[]/buffer、size limit 与 decode 流程。 V3 优先评估独立 plane: ```text metadata vectorPayload? // float32-le interleaved U/V scalarPayload? // float32-le scalar plane ``` 不得使用巨大 JS number[]、JSON Array 或 Base64 作为正式大数据通路。 必须明确:scalar-only、vector-only、scalar+vector 三种提交如何表达;文件引用是一个 container 还是两个 file URI;JNI/Core 最小修改面是什么。 独立 plane 是首选方向,但最终冻结必须依据当前代码,不能为了迎合任务书而忽略更安全的现有接缝。 ## 9. Timeline / Runtime Window 保护项 以下现有能力视为 V3 保护基线,不得在设计中推倒重来: ```text Core-owned Timeline / Playback T0 / T1 / MIX 正常连续播放 simulationRebuild=false 正常连续播放 trailCleared=false Runtime Field Window OLD_T1 -> NEW_T0 reuse only NEW_T1 upload Pause 语义 Invalid / Gap fail-closed WeatherColorLayer 与 RasterParticleLayer 分离 ``` V3 设计要说明如何把 Snapshot GPU resource 从单 vector texture 扩展成: ```text SnapshotGpuResources ├─ scalar texture? ├─ vector texture? └─ validity resource ``` 并保持整个 Snapshot 在 rollover 时一起 reuse,Host 不参与 GPU reuse。 ## 10. Canonical schema 版本决策 必须明确回答: ```text maplibre-particle-field/v1 additive extension 还是 maplibre-particle-field/v2 ``` 当前已知 v1 descriptor 是单 `layout/encoding/byteLength/stride`,Snapshot 只有 `velocity`,RN `submitField()` 只有一个 payload file URI,且 adapter 严格接受 `interleaved-uv`。 因此本任务的默认判断倾向:**如果 Scalar + Vector 会导致字段重载、隐式兼容或 ambiguous payload,则应正式升 v2,而不是污染 v1。** 但最终结论必须根据完整 parser/bridge/fixture/consumer 调查给出。 如果选择 v2,设计必须说明: - v1 Vector-only 是否继续可读; - compatibility 应放在哪个最薄层; - 是否允许 v1/v2 同时进入同一个 Runtime; - 新 RN package 版本至少应升到 `13.4.1-particle.3`,不得覆盖已发布 `.2`; - Native/AAR version 如何独立推进。 不得为了“兼容”长期维护两套 Runtime。 ## 11. Validity 与业务映射冻结 V3.0 优先保持一个 Snapshot 一个共享 validity,不提前设计 channel-specific mask。 必须给出四类 WeatherV2 -> NavSea canonical -> V3 的映射表,至少明确: ```text Wind : vector(U/V velocity) -> field=VECTOR_MAGNITUDE, particle=VELOCITY Tide : vector(U/V velocity) -> field=VECTOR_MAGNITUDE, particle=VELOCITY Rain : scalar(rainRate) -> field=SCALAR, particle=unavailable Wave : scalar(height) + vector(direction-to U/V) -> field=SCALAR, particle=DIRECTION ``` Wave `period` 当前保留在 NavSea Weather model/cache,V3.0 不因此增加第二 Scalar Channel。 Rain `precipitation_type` 当前未进入 NSFT,因此 V3 不推断、不补造该数据。 Field/Particle visibility 必须继续独立: ```text Field ON / Particle OFF Field OFF / Particle ON Field ON / Particle ON ``` 没有 vector 时 Particle unavailable / reject,不允许 scalar 伪装成 U/V。 ## 12. 必须输出的调查结论 A-J 设计文档必须逐项回答: A. 当前 Field Contract 实际结构与 Wind-only 硬编码点。 B. 当前 GPU Texture / upload / validity / shader 的实际结构。 C. 当前 Particle Integrator 对 vector 数值、单位、dt、scale 的实际假设。 D. 当前 RN -> Android -> JNI -> Core binary submission 路径与 ownership。 E. Scalar Channel 的最小扩展方案与受影响对象。 F. Wave direction-only 的最小、业务无关表达方案。 G. v1 additive extension 还是 canonical v2,并说明理由。 H. 预计受影响文件清单,按 Core / shader / Android / RN / Test Host 分类。 I. 向后兼容、性能、GPU memory、lifecycle、Timeline 风险。 J. 推荐的正式实施批次、验证门槛和 Android 最终一次综合验收范围。 ## 13. 推荐实施路线必须被审查并冻结 设计结果至少应评估以下批次是否合理: ```text V3-02 Core Contract + Scalar Snapshot/Adapter V3-03 Scalar GPU Texture + Generic Field Renderer V3-04 VectorSemantics VELOCITY/DIRECTION + Particle V3-05 Android/JNI/RN generic binary submission V3-06 Wind/Rain/Wave 三类 fixture + Tide 回归 V3-07 Linux/Core/OpenGL 精确验证与文档冻结 V3-08 用户一次 Android build/install/device 综合验收 ``` 可以根据当前代码合并或调整批次,但必须遵守: - 尽量减少 Android 重复编译/安装周期; - 在 Linux/Core 可验证的内容先集中完成; - 不因单一小按钮/日志单独触发 Android 周期; - 高风险接口分叉必须在 Android 实现前冻结。 最终路线要给每个批次明确“修改范围 / 不修改范围 / 完成门槛 / 下一批入口”。 ## 14. Validation Fixture 规划 V3 后续至少规划三类数学能力 fixture: ```text A. Vector-only : 真实 WeatherV2 Wind B. Scalar-only : 真实 WeatherV2 Rain C. Scalar+Vector: 真实 WeatherV2 Wave ``` Tide 作为第二套 VELOCITY vector 做回归,不单独创造业务代码路径。 Wave 必须规划一个独立性 synthetic fixture: ```text scalar: west low -> east high vector: 全场 north ``` 预期: ```text 色场只呈东西渐变 粒子只统一向北 ``` 该 fixture 用于证明 Field Renderer 不偷读 vector magnitude,Particle Renderer 不偷读 scalar。 同时规划 T0/T1 scalar、T0/T1 vector、共同 MIX、window rollover、style reload、visibility、invalid/gap fail-closed 验证。 ## 15. 本任务禁止事项 本任务不得: - 修改任何生产代码; - 修改 shader / generator; - 修改 Android/JNI/RN API; - 生成新的 AAR/tgz release; - 执行 Android Gradle build、APK 安装或 ADB 验收; - 把 NSFT decoder 放入 ParticleLab; - 新增 Weather Provider / HTTP / cache; - 新增 WIND/WAVE/RAIN/TIDE Core 分支; - 实现 Wave physics; - 设计 N-channel framework; - 做 JSI/zero-copy 大重构; - 加入或执行 Jest; - 修改 NavSea 或 WeatherV2。 本任务是设计冻结任务,不是实现任务。 ## 16. 必做文档输出 新增: ```text docs/20_调查/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField现状调查_v1.md docs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.md docs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.md docs/报告/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex完成报告_v1.md ``` 并追加更新: ```text 粒子开发记录.md ``` 所有文档必须使用中文,代码标识符、路径、schema/property 名保持实际英文。 设计文档必须包含至少: - 当前真实架构图; - V3 目标架构图; - Scalar / Vector / validity 数据模型; - Renderer config 与 Snapshot data 的边界; - Binary plane 方案; - Timeline/GPU reuse 迁移; - API/schema 版本决策; - WeatherV2 四层映射; - 受影响文件矩阵; - 风险与实施顺序。 ## 17. 必做清单 执行结束前逐项对照,不得静默跳过: - [ ] 读取全部项目规范与 STEP-064 冻结基线。 - [ ] 重新确认 branch / HEAD / origin / dirty worktree。 - [ ] 调查 Descriptor / Snapshot / Adapter 当前实际结构。 - [ ] 找全 WIND / GLOBAL / fieldType 等行为硬编码。 - [ ] 调查 Runtime Window / Timeline / MIX / GPU reuse。 - [ ] 调查 WeatherColorLayer value 获取和 `speedMps` 链路。 - [ ] 调查 Particle Integrator 的 velocity 假设。 - [ ] 调查 RN -> Android -> JNI -> Core binary submission。 - [ ] 只读核对 WeatherV2 NSFT 四层语义。 - [ ] 冻结 0/1 Scalar + 0/1 Vector + shared validity 模型。 - [ ] 冻结 FieldValueSource 与 VectorSemantics 方案。 - [ ] 冻结 binary payload / file-reference 方案。 - [ ] 明确 canonical v1 additive 或 v2。 - [ ] 给出 V3 分批实施路线与综合 Android 验收计划。 - [ ] 生成调查、设计、Step、完成报告。 - [ ] 追加粒子开发记录。 - [ ] 确认没有修改生产代码和无关用户文件。 ## 18. Git 收尾要求 本任务会新增/修改项目文档,因此完成后必须 Git 收尾并 push 到公开远端 `particle/main`。 提交前必须再次执行 `git status --short`,只暂存本任务明确产物: ```text docs/40_任务/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex任务_v1.md docs/20_调查/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField现状调查_v1.md docs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.md docs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.md docs/报告/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex完成报告_v1.md 粒子开发记录.md ``` 禁止把任何既有 STEP-062 修改、历史 untracked、build/cache/android/tgz 一并提交。 完成后: 1. 创建 scoped commit; 2. push 到 `origin/particle/main`; 3. 确认远端 HEAD; 4. 在完成报告记录 commit hash、commit message、push 结果、最终远端分支/HEAD。 push 失败不得声称任务完成,必须明确报告原因。 ## 19. 完成报告格式 完成报告必须按必做项逐项写: ```text 已完成 / 未完成 / 无法验证 ``` 并明确: - 本任务是否修改生产代码:预期“否”; - WeatherV2 是否被修改:预期“否”; - Android Gradle / APK / ADB:预期“未执行,按任务边界”; - Jest:预期“未加入、未执行”; - 当前最终 V3 schema 推荐; - 下一实施任务建议名称与范围; - 所有未解决设计风险。 ## 20. 最终完成标准 只有以下全部满足,STEP-065 才可标记 CLOSED / PASS: 1. 当前实际代码调查完整,并有文件/符号级依据; 2. V3 Scalar/Vector/validity Contract 已冻结; 3. Renderer data source 与 VectorSemantics 已冻结; 4. binary submission 与 schema version 路线已冻结; 5. Timeline/Runtime Window/GPU reuse 保护方案明确; 6. V3 分批实现和最终一次 Android 综合验收路线明确; 7. 四份正式文档 + 粒子开发记录完成; 8. 无生产代码、WeatherV2、NavSea 和无关工作区文件被修改; 9. scoped commit 已成功 push 到 `origin/particle/main`。