From 44999edb256ae73c3abc94ef3f0d208730c47897 Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Thu, 10 Sep 2026 21:53:56 +0800 Subject: [PATCH] docs: freeze V3 scalar vector field contract --- ...cleLab_V3通用ScalarVectorField现状调查_v1.md | 44 ++ ..._V3通用ScalarVectorField运行时架构设计_v1.md | 117 ++++ ...€š用ScalarVectorField架构冻结_Codex任务_v1.md | 532 ++++++++++++++++++ ...cleLab_V3通用ScalarVectorField架构冻结_v1.md | 25 + ...¨ScalarVectorField架构冻结_Codex完成报告_v1.md | 29 + 粒子开发记录.md | 8 + 6 files changed, 755 insertions(+) create mode 100644 docs/20_调查/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField现状调查_v1.md create mode 100644 docs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.md create mode 100644 docs/40_任务/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex任务_v1.md create mode 100644 docs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.md create mode 100644 docs/报告/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex完成报告_v1.md diff --git a/docs/20_调查/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField现状调查_v1.md b/docs/20_调查/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField现状调查_v1.md new file mode 100644 index 000000000..261418e24 --- /dev/null +++ b/docs/20_调查/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField现状调查_v1.md @@ -0,0 +1,44 @@ +# STEP-065 MapLibreParticleLab V3 通用 Scalar / Vector Field 现状调查 + +状态:完成(只读调查) +基线:`particle/main` / `2e3ab26275a8d1873d764cf6927783a7b0406836`,`origin/particle/main` 同一提交。 + +## 调查范围与方法 + +已完整阅读项目基线、协作/构建/Step/架构/官方基线规范、STEP-064 任务与冻结记录/报告;只读核对 Particle Core、两 renderer、GLSL、RasterArray Timeline、Android Host/JNI、RN package、两个 RN Test Host,以及 `/root/sourceserver/weatherV2` 指定六文件。未修改 WeatherV2/NavSea/生产代码,未执行 Gradle、APK、ADB 或 Jest。 + +## A. 当前 Field Contract 与 Wind-only 点 + +`include/mbgl/particle/field/field_data_adapter.hpp` 的 `ParticleFieldDescriptor` 只有一个 `layout/encoding/byteLength/stride`,`ParticleFieldSnapshot` 只有 `velocity: vector` 与 `valid: vector`。`field_data_adapter.cpp` 只接受 `interleaved-uv` + `float32-le`、每 cell 两 float;`isValid()` 与 decode 末尾硬性要求 `fieldType == "WIND"`、`displayDomain == "GLOBAL"`。`local_particle_field_feed.cpp` 的 `maplibre-particle-field/v1` parser 也强制 `vector` 与一个 `payload`。 + +`fieldType` / `displayDomain` 还参与 timeline-compatible 比较;当前 fixture、Consumer metadata 皆为 `WIND/GLOBAL`。这不是 provider-neutral 的能力表达,且不能承载 scalar-only 或 Wave 的 direction vector。 + +## B. GPU、validity、shader 的真实结构 + +`render_weather_color_layer.cpp` 每快照把 U/V 按快照最大绝对值编码进 RG、validity 编入 A;T0/T1 各一张 `Texture2D`。`render_particle_validation_layer.cpp`(正式 `RasterParticleLayer` 也经此 renderer)同样把 U/V+validity 压入 RGBA,维护 `fieldTexture/nextFieldTexture`、各自 scale 和 image。二者独立拥有资源,不共享 GPU texture;均以 `sameFieldGpuContent()` 比较并可把 OLD_T1 移至 NEW_T0,仅上传新内容。 + +`shaders/particle_gpu_validation.fragment.glsl` 的 Field pass 从 RG 恢复 U/V,A 同时是 shared validity;`weatherRampColor(length(velocity))` 是图场唯一值来源。无独立 scalar texture、mask texture 或 channel-level validity;粒子另有验证用 coast mask,但不属于 field validity。 + +## C. Particle 数值与单位假设 + +GLSL `fieldVelocityAt()` 混合 T0/T1 的 U/V,要求两时刻 A 有效且 `length > 1e-5`。状态 pass 用 `dx=u*simulationSeconds/EarthCircumference`、`dy=-v*simulationSeconds/(EarthCircumference*cos(latitude))`,明确 U east、V north、物理 m/s。C++ 的 `VisualSimulationSecondsPerRealSecond=1200` 只是展示时钟;不会改变 canonical U/V 单位。故现状不适合直接把 Wave unit direction 当 velocity。 + +## D. RN 到 Core binary ingress 与 ownership + +公共 `FieldRuntime.submitField(metadataJson, payloadFileUri)` 在 RN 薄映射内部 `submitWindField`。Kotlin bridge 只接受 `file://` 或绝对本地路径,metadata 上限 1 MiB、payload 1..64 MiB,读为 `ByteArray`;无 number[]/JSON array/Base64。`WeatherRuntime.submitWindField()` 传给 `MapLibreMap.submitRasterArraySourceHostField()`,JNI `NativeMapView::submitRasterArraySourceHostField` 把 Java `byte[]` 复制为 C++ `vector`,再调用 `RasterArraySource::submitHostField()`;Core adapter 再复制解码为 float vector。因此当前 ownership 是同步、三次宿主/核心内存持有,而非 zero-copy。 + +## Timeline / Runtime Window + +`RasterArraySource::submitHostField()` 首帧 pending、第二帧原子建立 Source-owned `RasterArrayTimelineRuntime` T0/T1;后续按 `validTime/generation` 单调 append,容量 8。`RasterArrayTimelineRuntime` 输出 immutable T0/T1 + MIX,暂停不推进。`RenderWeatherColorLayer` 与 `RenderRasterParticleLayer` 都取同一 Source timeline;正常 overlap rollover 保持 `simulationRebuild=false`、`trailCleared=false`,无 overlap 才 reset。invalid/gap 由 timeline 状态 fail-closed。 + +## Field Renderer 与 speedMps 链路 + +`WeatherColorStop.speedMps` 位于 C++ `weather_color_stop.hpp`,Android `WeatherRuntime.ColorStop`、Kotlin native bridge 和 generated TurboModule 均仍使用该内部 ABI;RN `.2` 已将公开 `FieldColorStop.value` 薄转换为 `speedMps`。当前 shader 默认 0..30 m/s palette,stop 值也按 speed 解释。因此 V3 必须新增明确 value source,不能以有无 scalar 猜测。 + +## WeatherV2 输入核对 + +`nsft.py` / `field_pmtiles.py` 证实 NSFT PMTiles `wm_grid_257`、NW origin(row north→south、column west→east)、同 zoom tile 257 样本。Wind 与 current 都写物理 U/V;`wind.py`、`tide.py` 计算 speed 为 `sqrt(u²+v²)`。Rain 写 `rain_mm_h + valid`;虽 decoder 有 `precipitation_type`,`encode_rain_tile()` 未写它。Wave 写 `height_m`、`period_s` 和 `unit_to_u/v`;`waves.py` 将 from 转 to 后归一化,非 m/s。`target_time` 由实际任务时间写入 header,不能推定小时 cadence。任务书给出的事实与代码一致。 + +## 直接结论 + +V3 应保留现有 Source-owned timeline、两个独立 renderer 和 overlap reuse 的行为,但将单个 velocity snapshot 升级为一个快照的 optional scalar、optional vector、shared validity 三资源。业务名称、单位换算、NSFT/PMTiles、tile 拼接、provider/缓存必须停在 NavSea 侧。 diff --git a/docs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.md b/docs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.md new file mode 100644 index 000000000..00a6973da --- /dev/null +++ b/docs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.md @@ -0,0 +1,117 @@ +# MapLibreParticleLab V3 通用 Scalar / Vector Field 运行时架构设计 + +状态:冻结(V3.0 Contract,尚未实现) +决策:新 canonical schema 为 `maplibre-particle-field/v2`;RN package 首个 V3 实现版至少 `13.4.1-particle.3`,Native AAR 独立升版,绝不覆盖 `.2`/`.1`。 + +## 边界与目标 + +V3 从 NavSea canonical Field submission 开始,是 provider-neutral、business-neutral 的二维时序 Scalar / Vector runtime。它不解析 NSFT/PMTiles,不做 HTTP、manifest、time_index、缓存、业务单位转换,也不以 WIND/WAVE/RAIN/TIDE 决定能力。V3.0 固定为 **0/1 scalar + 0/1 vector + 1 shared validity**,拒绝 neither;不设计 N-channel graph。 + +```text +WeatherV2 → NSFT → NavSea JS/TS(解码、拼接、单位/业务 canonical) + │ metadata + local scalar/vector file reference + ▼ +MapLibreParticleLab V3: validate → Snapshot → Source Timeline T0/T1/MIX + ├─ Generic Field Renderer (config.valueSource) + └─ Particle Renderer (config.vectorSemantics) +``` + +当前实现为 `v1 vector(U/V)+valid → Timeline → 两个各自 RGBA U/V texture renderer`;V3 仍是一份 Source snapshot,两 renderer 独立显示、独立 GPU resource,而非两份 host field。 + +## 冻结数据 Contract + +```text +FieldSnapshot + descriptor: fieldId, generation, validTime, grid, bounds, dataVersion, content hash + scalar?: Float32[width*height] // scalar plane + vector?: Float32[width*height*2], interleaved U/V // vector plane + valid: UInt8[width*height] // shared validity + vectorSemantics?: VELOCITY | DIRECTION // only when vector exists +``` + +- 所有 plane 必为 `float32-le`、NW-origin row-major;vector U=east、V=north。 +- scalar-only、vector-only、scalar+vector 合法;neither、尺寸/byteLength/finite/validity 不一致均 reject。 +- `valid` 是一个 snapshot-wide shared logical mask;V3.0 不加 channel mask。任何无效 cell 对全部现有 channel 无效。 +- `validTime` 是实际时刻,不假设固定间隔;T0/T1 必须相同 grid/bounds/channel presence/vector semantics/encoding,且都递增。 +- `fieldId` 是 opaque identity,删除 `fieldType` / `displayDomain` 对能力、adapter validation 和 compatibility 的强制依赖。领域/mask 选择若仍需要,作为 renderer config 的 business-neutral spatial policy,不能作为天气 enum。 + +### v2 JSON 与 binary plane + +```json +{ + "schema":"maplibre-particle-field/v2", "fieldId":"opaque-id", "generation":1, + "validTime":1760000000000, "dataVersion":1, + "grid":{"width":257,"height":257,"origin":"north-west","rowOrder":"north-to-south"}, + "bounds":{"west":0,"south":0,"east":1,"north":1}, + "validity":{"encoding":"uint8","byteLength":66049}, + "scalar":{"encoding":"float32-le","byteLength":264196,"noData":-9999}, + "vector":{"layout":"interleaved-uv","encoding":"float32-le","byteLength":528392,"noData":-9999,"semantics":"DIRECTION"} +} +``` + +提交 API 冻结为 `submitField(metadataJson, payloadRefs)`,其中 `payloadRefs={validityFileUri, scalarFileUri?, vectorFileUri?}`;每个 URI 独立 local file、独立限额、先验证存在性与总大小再同步读入。metadata 仍小,绝不采用 JS number[]、JSON array、Base64。v2 validity 采用显式 `uint8` plane,避免让任一 channel 的 noData 充当隐式共享 mask;Kotlin/JNI 最小修改为从单 `byte[]` 改为三个 nullable byte[](或等价 native struct),Core parser/adapter 接收 plane bundle。若实施时 JNI 参数数量/ABI 风险高,可在 Kotlin 读三文件后封装为有明确 offsets/lengths 的 **v2 binary container**;不能复用 v1 的单 payload 产生歧义。 + +## v1/v2 版本决策 + +选择 **v2**,而非 v1 additive:v1 单 `vector`、单 payload、`velocity` snapshot 和 WIND/GLOBAL validation 都是结构性约束;在同 schema 内重载 payload 会令 scalar-only 与 scalar+vector 的 bytes、validity、noData、compatibility ambiguous。 + +- v1 vector-only 继续由旧 parser/adapter 可读,作为 compatibility ingress;最薄兼容层将 v1 decode 规范化成 v2 内部 snapshot(vector=present、shared validity 从 v1 U/V noData 派生、semantics=VELOCITY)。 +- Runtime 内只使用一个 V3 snapshot/timeline 实现;允许 v1 首帧与 v2 vector-only 共同进入同 Runtime,前提是 normalize 后 descriptor/semantics/channel presence 完全 compatible。否则 fail-closed,不维护两套 runtime。 +- v1 不增加 scalar 字段;发布 `.3` 才公开 v2 `payloadRefs`,旧 `.2` ABI 可继续作为 legacy ingress,Native/AAR coordinate 独立推进。 + +## Renderer Contract(与数据分离) + +`FieldSnapshot` 只回答“有什么”;renderer config 显式回答“怎样画”: + +```text +FieldRendererConfig.valueSource = SCALAR | VECTOR_MAGNITUDE +ParticleRendererConfig.vectorSemantics = VELOCITY | DIRECTION +ParticleRendererConfig.advectionScale (finite, >0; display/config policy) +``` + +`SCALAR` 要求 scalar present;`VECTOR_MAGNITUDE` 要求 vector present;不满足即该 renderer unavailable/reject,绝不猜。`FieldColorStop.value` 保持 generic public semantics。Native 内部 `speedMps`、shader default 0..30m/s 和 speed-color 命名将在 V3-03 统一改为 generic `fieldValue`/`value`; legacy JNI ABI 可薄转换,不能改变 RN `.2`。 + +`SnapshotGpuResources` 为每一个 T0/T1 快照包含 `scalarTexture?`、`vectorTexture?`、`validityTexture` 与各 plane scale/format。rollover 把整个 bundle(而不是单 texture)从 OLD_T1 原子复用为 NEW_T0;只上传 NEW_T1 bundle。style reload/context loss 清空 renderer-owned resource,Source timeline 保留;下一帧从当前 immutable window 重建。Field ON/Particle OFF、Field OFF/Particle ON、双 ON 都继续合法;无 vector 时 Particle 不可用,不让 scalar 伪装 U/V。 + +## Vector semantics + +`VELOCITY` 保持当前 Wind/Tide 行为:T0/T1 component-wise mix,m/s 地理推进,`advectionScale=1` 默认。 + +`DIRECTION` 用 unit U/V 表示方向,不代表速度。先 component-wise mix,再 normalize;若长度非 finite 或小于冻结阈值(建议 `1e-5`)则 cell invalid、粒子不移动/respawn,fail-closed。反向邻帧在 mix 约 0.5 归零亦遵此规则,不能任选方向。实际视觉推进量只由 particle renderer 的 `advectionScale`(及现有 visual clock)控制,必须明确由宿主/renderer 配置提供,不能从 Wave height/period 或业务名称推算。本任务未定义 Wave physics。 + +## WeatherV2→NavSea→V3 映射 + +|业务输入|NavSea canonical V3|Field renderer|Particle| +|---|---|---|---| +|Wind|vector U/V, `VELOCITY`|`VECTOR_MAGNITUDE`|`VELOCITY`| +|Tide/Current|vector U/V, `VELOCITY`|`VECTOR_MAGNITUDE`|`VELOCITY`| +|Rain|scalar rainRate + shared valid|`SCALAR`|unavailable| +|Wave|scalar height + unit direction-to U/V, `DIRECTION`|`SCALAR`|`DIRECTION`| + +Wave period 留在 NavSea model/cache,不增加第二 scalar;Rain precipitation type 未写入 NSFT,V3 不推断或补造。NavSea 在拼接 257 tile 时保持 `(tiles*256)+1`,Core 不理解 tile。 + +## 受影响文件矩阵与风险 + +|区域|预计修改| +|---|---| +|Core|`field_data_adapter.*`、`local_particle_field_feed.cpp`、`raster_array_source.*`、fixtures/tests| +|shader/renderer|`render_weather_color_layer.cpp`、`render_particle_validation_layer.cpp`、`particle_gpu_validation.fragment.glsl`、UBO/manifest/generator 后端产物| +|Android|`WeatherRuntime.java`、`MapLibreMap.java`、`native_map_view.*`、JNI registration| +|RN|`types.ts`、`FieldRuntime.ts`、`NativeWeatherRuntimeBridge.ts`、Kotlin TurboModule/codegen、package version| +|Test Host|style fragment、v1 regression 与 Wind/Rain/Wave/synthetic fixtures;不引入业务逻辑到 package| + +风险:plane 增加 GPU memory、3 URI read 后 Java/C++ copy 峰值、texture precision/scale、v1/v2 ABI 共存、direction opposite interpolation、style/context lifecycle 和 timeline compatibility。缓解是 bounded total bytes、明确 channel-presence compatibility、bundle-level reuse、fail-closed 和先 Linux/Core verification。 + +## 实施批次与门槛 + +|批次|修改范围 / 不修改范围|完成门槛 / 下一入口| +|---|---|---| +|V3-02 Core Contract + Scalar Adapter|v2 descriptor/snapshot/parser、v1 normalize;不改 GPU/JNI|单元/fixture覆盖三组合、invalid/compatibility;进入 V3-03| +|V3-03 GPU + Generic Field|scalar/vector/validity bundle、`FieldValueSource`;不改 particle semantics/JNI|OpenGL Core fixture:scalar 与 magnitude 不混读;进入 V3-04| +|V3-04 Vector Semantics|DIRECTION normalize、advectionScale;不改 Wave physics|VELOCITY Wind 回归、opposite/zero fail-closed;进入 V3-05| +|V3-05 Android/JNI/RN ingress|v2 plane refs、新 `.3`,保留 v1 thin ingress|payload limits/ownership/static checks;进入 V3-06| +|V3-06 fixtures|真实 Wind/Rain/Wave,Tide 回归、wave synthetic|T0/T1/MIX/reuse/style/visibility/gap coverage;进入 V3-07| +|V3-07 Linux freeze|Core/OpenGL 精确验证与文档|双 renderer/lifecycle/perf evidence;进入唯一 Android 周期| +|V3-08 Android 综合验收|一次 AAR/APK/device;不分散小周期|Wind/Rain/Wave/Tide、三 visibility 组合、seek/play/pause/rollover/style reload、hard-gate log 与 memory/perf evidence| + +Wave synthetic fixture 固定:scalar west-low→east-high、vector 全场 north;色场必须只东西渐变,粒子必须只向北。所有 fixture还覆盖 T0/T1 scalar、T0/T1 vector、共同 MIX、OLD_T1→NEW_T0、only NEW_T1 upload、invalid/gap fail-closed。 diff --git a/docs/40_任务/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex任务_v1.md b/docs/40_任务/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex任务_v1.md new file mode 100644 index 000000000..b3bd44fce --- /dev/null +++ b/docs/40_任务/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex任务_v1.md @@ -0,0 +1,532 @@ +# 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`。 diff --git a/docs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.md b/docs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.md new file mode 100644 index 000000000..6f81610c6 --- /dev/null +++ b/docs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.md @@ -0,0 +1,25 @@ +# STEP-065 MapLibreParticleLab V3 通用 Scalar / Vector Field 架构冻结 + +状态:冻结 + +## 目标与基线 + +在 `2e3ab262` 对当前真实实现做只读调查,冻结 V3.0 generic Scalar/Vector Contract 和迁移路线;不实现。开始与结束均为 `particle/main`,开始时 `HEAD == origin/particle/main == 2e3ab262`。 + +## 必做项结果 + +- [x] 读取全部规范、STEP-064 基线,复核 branch/HEAD/origin/dirty worktree。 +- [x] 调查 descriptor/snapshot/adapter、WIND/GLOBAL、Timeline/MIX/window reuse、WeatherColor `speedMps`、Particle velocity m/s、RN→Android→JNI→Core。 +- [x] 只读核对 WeatherV2 Wind/Tide/Rain/Wave NSFT 语义。 +- [x] 冻结 0/1 scalar + 0/1 vector + shared validity、`FieldValueSource`、`VectorSemantics`、独立 plane file refs。 +- [x] 冻结 `maplibre-particle-field/v2`、v1 thin normalize compatibility、分批路线和单次 Android 综合验收。 +- [x] 生成调查、设计、Step、报告并追加开发记录。 +- [x] 确认未修改生产代码、WeatherV2、NavSea、STEP-062 或历史无关 untracked 文件。 + +## 允许/禁止与验证 + +仅新增/更新任务指定文档;不改 C++、shader、JNI、Android、RN API 或 fixture,不生成 AAR/tgz。未执行 Android Gradle、APK、ADB、Jest,原因是任务明确禁止。执行只读代码/文本审计与 `git diff --check`/精确 staged 文件审计;不宣称构建或设备 PASS。 + +## 当前结果与下一步 + +详见调查及设计文档。下一任务建议:`STEP-066 V3-02 Core Contract + Scalar Snapshot/Adapter`,只实现 v2/v1 normalize 与 Core fixture/验证,先不进入 GPU 或 Android。未解决风险:v2 具体 Kotlin/JNI ABI 形态、plane 总内存预算、direction 视觉 scale 默认值须在实施前用目标设备约束量化。 diff --git a/docs/报告/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex完成报告_v1.md b/docs/报告/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex完成报告_v1.md new file mode 100644 index 000000000..4bbbe304e --- /dev/null +++ b/docs/报告/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_Codex完成报告_v1.md @@ -0,0 +1,29 @@ +# STEP-065 MapLibreParticleLab V3 通用 Scalar / Vector Field 架构冻结 Codex 完成报告 + +状态:CLOSED / PASS(设计冻结;非实现/构建验收) + +## 已完成 + +已依据文件/符号级真实代码完成 Contract、GPU、粒子单位、binary ingress、timeline/reuse、RN ABI 与 WeatherV2 指定源文件的只读调查;正式冻结 `maplibre-particle-field/v2`、0/1 scalar + 0/1 vector + shared validity、`SCALAR|VECTOR_MAGNITUDE`、`VELOCITY|DIRECTION`、独立 plane file references、v1 thin normalize 和 V3-02 至 V3-08 实施/验收路线。四类 WeatherV2 映射、Wave synthetic independence fixture、风险和受影响文件矩阵均已记录。 + +## 逐项状态 + +|项目|结果| +|---|---| +|生产代码修改|未完成(按任务边界:否)| +|WeatherV2/ NavSea 修改|未完成(按任务边界:否)| +|Android Gradle / APK / ADB|未执行(按任务边界)| +|Jest|未加入、未执行(按任务边界)| +|只读架构调查与 V3 Contract|已完成| +|文档/记录|已完成| +|构建/运行验证|无法验证(任务禁止且本任务不实现)| + +## 未完成项与风险 + +没有本 Step 的文档交付阻塞。后续实现未解决项:Kotlin/JNI 采用三 nullable `byte[]` 或带 offsets 的 v2 container 的 ABI 决策、64 MiB 单文件限制向总 plane 上限的调整、GPU texture format/内存实测、DIRECTION 的产品 advection scale 默认值、Android GL/Vulkan 与未来 Metal 验证。它们均不应由本设计任务臆断为已通过。 + +建议下一任务为 `STEP-066 V3-02 Core Contract + Scalar Snapshot/Adapter`:只改 Core Contract/adapter 和离线 fixture,首先锁定 v1 normalize、三组合 validation、timeline compatibility;不得提前提交 Android build。 + +## Git 收尾 + +本报告将在本任务 scoped commit 创建、push 及远端 HEAD 复核后回填最终 hash/结果;除任务书与五个文档/记录外不暂存任何文件。 diff --git a/粒子开发记录.md b/粒子开发记录.md index cc564217e..8acdaece4 100644 --- a/粒子开发记录.md +++ b/粒子开发记录.md @@ -619,3 +619,11 @@ WeatherColorLayer 的 `ParticleGpuValidationUBO` designated initializer 补齐 ` - 正式 HTTPS tgz 为 10,660 bytes,SHA256 `ace9e0401824839d18a93cc4201c1f5d4cccbff0636570cfde82fd80b60779b5`,NAS 与公网下载字节一致。 - Win11 Consumer 已从正式 HTTPS URL 安装并通过 TypeScript/依赖树检查;此前 Android Consumer 已通过 FieldRuntime、T0–T3、Runtime READY 与 Field/Particle 独立开关。 - Native AAR 继续使用 `13.4.1-particle.1`;STEP-064 冻结,后续 RN 修改从 `.3` 开始。 + +# 2026-09-10 — STEP-065 V3 通用 Scalar / Vector Field 架构冻结 + +- 只读核对当前 v1 Core/RasterArray Timeline/两 renderer/GLSL、Android/JNI/RN binary ingress,以及 WeatherV2 NSFT Wind/Tide/Rain/Wave;未修改生产代码、WeatherV2 或 NavSea,未执行 Gradle/APK/ADB/Jest。 +- V3.0 冻结为 `maplibre-particle-field/v2`:一个 Snapshot 最多一个 scalar plane、一个 interleaved U/V vector plane 和一个 shared validity plane;scalar-only、vector-only、scalar+vector 合法,neither fail-closed。 +- Renderer policy 与数据分离:Field 明确选择 `SCALAR` 或 `VECTOR_MAGNITUDE`,Particle 明确选择 `VELOCITY` 或 `DIRECTION`;Wave direction 是归一化方向,插值近零/反向时 fail-closed,推进 scale 独立于业务数据。 +- 保留 v1 作为最薄 ingress normalize,运行时只保留一套 V3 Timeline/GPU bundle;保护 T0/T1/MIX、pause、OLD_T1→NEW_T0 bundle reuse、only NEW_T1 upload、normal rollover 不重建 simulation/clear trail。 +- 下一步为 V3-02 Core Contract + Scalar Snapshot/Adapter;先完成 Linux/Core fixture 与 compatibility,再统一进入 GPU、Android/JNI/RN 与一次 Android 综合验收。