diff --git a/docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v1.md b/docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v1.md new file mode 100644 index 000000000..974512e9b --- /dev/null +++ b/docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v1.md @@ -0,0 +1,40 @@ +# STEP-071A V3-07 Linux 综合冻结:测试 Fixture 修正 + +## 基线 +- 仓库:`/mnt/sda1/MapLibreParticleLab` +- 分支:`particle/main` +- 基线 HEAD:`fcc533dc9518395d0c25794131f53f0fae20d51c` +- 只允许修改:`test/style/source.test.cpp` + +## 已确认问题 1:Host duplicate 测试数据错误 +`HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField` 当前用同一份 `uniform-east` payload 提交 T0/T1。 +Runtime 先按 GPU content identity 返回 `Duplicate` 是正确行为;测试预期 `InitialWindowReady` 已过时。 + +修正要求: +- T0 使用 `uniform-east/field.f32`。 +- T1 使用兼容但内容不同的 `uniform-north/field.f32`。 +- 后续 invalid/non-monotonic 检查使用不会与当前 lastValid 重复的 payload;尤其 non-monotonic 必须真正到达 non-monotonic 判定,而不是先命中 Duplicate。 +- 不修改 `sameFieldGpuContent`、Duplicate 顺序或任何 Runtime 生产逻辑。 + +## 已确认问题 2:Timeline 测试时间重复 +`RasterArrayTimelineCandidatesReachReadyThroughFieldAdapter` 使用 east/north/vortex 三份旧 fixture;三份 metadata 的 `timeIndex` 均为 0。 +当前 `OfflineFixtureParticleAdapter` 保留 `validTime = timeIndex + 1`,因此旧测试会形成重复时间,Timeline 正确 fail-closed,而测试无限等待。 +修正要求: +- 不改共享 fixture 文件。 +- 仅在该测试内部把 north/vortex metadata 的 `timeIndex` 调整为严格递增值,例如 east=0、north=1、vortex=2。 +- 保持 grid/bounds/vector semantics/encoding 不变。 +- 保持测试仍通过真实 `OfflineFixtureParticleAdapter` / Source preload / Timeline 路径验证,不改成绕过适配器的伪测试。 +- 若需要小型局部 helper,只能放在 `test/style/source.test.cpp`,不得扩散生产 API。 + +## 禁止事项 +- 不修改 `src/`、`include/`、shader、JNI、Android、RN、WeatherV2、NavSea。 +- 不修改 STEP-062 用户 dirty 文件。 +- 不执行编译、测试、代码审计、搜索、Android Gradle、ADB、Jest。 +- 不执行 git add/commit/push。 +- 不创建额外完成报告;验证与 Git 收尾由 ChatGPT 在 tmux `rdc` 中直接完成。 + +## 完成输出 +修改完成后只报告: +1. 修改了 `test/style/source.test.cpp` 哪两个测试; +2. 每处如何避免 Duplicate / 重复 validTime; +3. 是否修改了任何生产代码(必须为“否”)。 diff --git a/docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v2.md b/docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v2.md new file mode 100644 index 000000000..2d8c11186 --- /dev/null +++ b/docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v2.md @@ -0,0 +1,27 @@ +# STEP-071A V3-07 Linux 综合冻结:测试 Fixture 修正 v2 + +## 基线与现状 +- 当前基线:`fcc533dc9518395d0c25794131f53f0fae20d51c` + 未提交的 v1 测试修正。 +- v1 的 Host duplicate 修正已实测 PASS,不得回退。 +- 只允许修改:`test/style/source.test.cpp`。 + +## 唯一问题 +`RasterArrayTimelineCandidatesReachReadyThroughFieldAdapter` 中 v1 使用: +`northMetadata.find("\"timeIndex\":0")` +实际共享 fixture metadata 格式是: +`"timeIndex": 0` +因此 `find()` 返回 `npos`。 + +## 必做修正 +- 保留 v1 已完成的 east/north distinct payload 修正。 +- 将 north/vortex 的测试内 `timeIndex` 替换逻辑改为匹配实际 JSON 文本格式。 +- north 必须得到 `timeIndex = 1`,vortex 必须得到 `timeIndex = 2`。 +- 不修改共享 fixture 文件。 +- 不修改任何生产代码或 Runtime 行为。 + +## 禁止 +- 不编译、不测试、不搜索/审计、不运行 Git。 +- 不修改其他文件。 +- 不运行 Android/ADB/Jest。 + +完成后只报告修改内容和是否修改生产代码。 \ No newline at end of file diff --git a/docs/50_Step记录/STEP-071_MapLibreParticleLab_V3-07_Linux综合冻结_v1.md b/docs/50_Step记录/STEP-071_MapLibreParticleLab_V3-07_Linux综合冻结_v1.md new file mode 100644 index 000000000..5a86c2df3 --- /dev/null +++ b/docs/50_Step记录/STEP-071_MapLibreParticleLab_V3-07_Linux综合冻结_v1.md @@ -0,0 +1,37 @@ +# STEP-071 — MapLibreParticleLab V3-07 Linux 综合冻结 + +状态:CLOSED / PASS(Linux) +日期:2026-09-11 +基线:`fcc533dc9518395d0c25794131f53f0fae20d51c` + +## 目标 +在进入 V3-08 Android 统一验收前,对 V3-02~V3-06 的 canonical field、Host ingress、Timeline、RasterParticle 与 RN 公共桥接做一次 Linux 综合冻结。 + +## 冻结链结果 +- [x] canonical fixture validator:PASS。 +- [x] `packages/maplibre-particle-rn` TypeScript:PASS。 +- [x] RN Test Host `npm run typecheck`:PASS。 +- [x] RN TurboModule codegen:PASS。 +- [x] `mbgl-test` / `mbgl-test-runner` Linux OpenGL target:PASS / up-to-date。 +- [x] V3 综合过滤测试:21/21 PASS。 +- [x] `git diff --check`:PASS。 +- [ ] Android Gradle/AAR/APK/ADB/Jest:本 Step 不运行。 + +## 综合测试覆盖 +过滤范围:`Source.ParticleField*`、`Source.HostField*`、`Source.RasterArrayTimeline*`、`Source.RasterArraySharesCanonicalSnapshotsWithWeatherColorLayer`、`Layer.RasterParticle*`。 +最终 18 个 Source + 3 个 Layer,共 21 项全部 PASS。 + +## 冻结中发现并修正的测试问题 +1. `HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField` 旧测试用同一 `uniform-east` payload 构造 T0/T1,正确 Runtime 会先返回 Duplicate。测试改为 east→north 两份兼容但不同内容。 +2. `RasterArrayTimelineCandidatesReachReadyThroughFieldAdapter` 使用的 east/north/vortex 旧 fixture 均为 `timeIndex=0`;当前 Adapter 保留 `validTime=timeIndex+1`,导致 Timeline 正确 fail-closed。测试仅在局部 metadata 副本中改为 0/1/2,未修改共享 fixture。 +3. 两处均为 test fixture 陈旧,不修改 Runtime、Duplicate 判定顺序、Timeline fail-closed 或生产 API。 + +对应 Codex 任务: +- `docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v1.md` +- `docs/40_任务/STEP-071A_V3-07_Linux综合冻结_测试Fixture修正_Codex任务_v2.md` + +## 边界 +- 未修改 `src/`、`include/`、shader、JNI、Android、RN runtime、WeatherV2 或 NavSea。 +- 已知既有 `Layer.WeatherColorUsesIndependentFixedOpacity` 断言债不属于本 Step,不修、不作为 V3-07 gate。 +- STEP-062 用户 dirty 与历史 untracked/build/cache/tgz 均保持隔离。 +- 下一步:V3-08,一次 Android 编译/安装/实体机综合验收。 diff --git a/docs/报告/STEP-071_MapLibreParticleLab_V3-07_Linux综合冻结_Codex完成报告_v1.md b/docs/报告/STEP-071_MapLibreParticleLab_V3-07_Linux综合冻结_Codex完成报告_v1.md new file mode 100644 index 000000000..b17f1743f --- /dev/null +++ b/docs/报告/STEP-071_MapLibreParticleLab_V3-07_Linux综合冻结_Codex完成报告_v1.md @@ -0,0 +1,29 @@ +# STEP-071 — MapLibreParticleLab V3-07 Linux 综合冻结完成报告 + +结论:CLOSED / PASS(Linux)。 +日期:2026-09-11 + +## 实际完成 +V3-07 在 `particle/main` 上完成 Linux 综合冻结。最终验证链从 canonical fixture、RN/TS/codegen 到 Linux OpenGL test target 和 V3 相关 Source/Layer 回归全部通过。 + +最终结果: +- fixture validator:PASS; +- package TypeScript:PASS; +- RN Test Host typecheck:PASS; +- TurboModule codegen:PASS; +- `mbgl-test` / `mbgl-test-runner`:PASS / up-to-date; +- V3 综合过滤:21/21 PASS; +- `git diff --check`:PASS; +- 最终验证链退出码:0。 + +## 冻结中修正 +综合回归暴露两个旧测试 fixture 问题:Host T0/T1 使用重复 payload,以及 Timeline preload 三帧 `timeIndex` 全为 0。两处都通过测试侧局部修正解决;生产 Runtime 行为未改变。 + +## 未执行与边界 +- 未运行 Android Gradle/AAR/APK/ADB/Jest,因此没有 Android PASS 声明。 +- 未修改 `src/`、`include/`、shader、JNI、Android、RN runtime、WeatherV2 或 NavSea。 +- 已知 `Layer.WeatherColorUsesIndependentFixedOpacity` 既有断言债未纳入本 Step gate,也未修复。 +- STEP-062 两份用户 dirty 与历史无关 untracked/build/cache/tgz 未纳入。 + +## 下一步 +进入 V3-08:按既定策略仅安排一次 Android 编译、安装和实体机综合验收,覆盖 V3-05/V3-06 尚未完成的 Android/JNI/RN v2 multi-plane 与四类场路径。 diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp index 1109914e2..9d3259397 100644 --- a/test/style/source.test.cpp +++ b/test/style/source.test.cpp @@ -701,12 +701,14 @@ TEST(Source, HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField) { style::RasterArraySource source{"host-submission"}; source.setObserver(&test.styleObserver); source.loadDescription(*test.fileSource); - const auto field = fixtureBytes("uniform-east", "field.f32"); - const std::vector payload(field.begin(), field.end()); + const auto eastField = fixtureBytes("uniform-east", "field.f32"); + const auto northField = fixtureBytes("uniform-north", "field.f32"); + const std::vector eastPayload(eastField.begin(), eastField.end()); + const std::vector northPayload(northField.begin(), northField.end()); - EXPECT_EQ(source.submitHostField(localMetadata(0), payload), + EXPECT_EQ(source.submitHostField(localMetadata(0), eastPayload), style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow); - EXPECT_EQ(source.submitHostField(localMetadata(1), payload), + EXPECT_EQ(source.submitHostField(localMetadata(1), northPayload), style::RasterArrayHostFieldSubmitResult::InitialWindowReady); ASSERT_TRUE(source.impl().timeline); const auto lastValid = source.impl().timeline->lastEntry().field; @@ -715,31 +717,31 @@ TEST(Source, HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField) { const auto fieldID = invalidIdentity.find("production-t2"); ASSERT_NE(fieldID, std::string::npos); invalidIdentity.replace(fieldID, std::string("production-t2").size(), ""); - EXPECT_EQ(source.submitHostField(invalidIdentity, payload), + EXPECT_EQ(source.submitHostField(invalidIdentity, eastPayload), style::RasterArrayHostFieldSubmitResult::RejectedAdapter); auto unsupportedLayout = localMetadata(2); const auto layout = unsupportedLayout.find("interleaved-uv"); ASSERT_NE(layout, std::string::npos); unsupportedLayout.replace(layout, std::string("interleaved-uv").size(), "planar-uv"); - EXPECT_EQ(source.submitHostField(unsupportedLayout, payload), + EXPECT_EQ(source.submitHostField(unsupportedLayout, eastPayload), style::RasterArrayHostFieldSubmitResult::RejectedAdapter); auto unsupportedEncoding = localMetadata(2); const auto encoding = unsupportedEncoding.find("float32-le"); ASSERT_NE(encoding, std::string::npos); unsupportedEncoding.replace(encoding, std::string("float32-le").size(), "float64-le"); - EXPECT_EQ(source.submitHostField(unsupportedEncoding, payload), + EXPECT_EQ(source.submitHostField(unsupportedEncoding, eastPayload), style::RasterArrayHostFieldSubmitResult::RejectedAdapter); auto invalidDimensions = localMetadata(2); const auto width = invalidDimensions.find("\"width\":16"); ASSERT_NE(width, std::string::npos); invalidDimensions.replace(width, std::string("\"width\":16").size(), "\"width\":0"); - EXPECT_EQ(source.submitHostField(invalidDimensions, payload), + EXPECT_EQ(source.submitHostField(invalidDimensions, eastPayload), style::RasterArrayHostFieldSubmitResult::RejectedAdapter); - auto shortPayload = payload; + auto shortPayload = eastPayload; shortPayload.pop_back(); EXPECT_EQ(source.submitHostField(localMetadata(2), shortPayload), style::RasterArrayHostFieldSubmitResult::RejectedAdapter); @@ -748,7 +750,7 @@ TEST(Source, HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField) { const auto validTime = nonMonotonic.find("1704074400000"); ASSERT_NE(validTime, std::string::npos); nonMonotonic.replace(validTime, std::string("1704074400000").size(), "1704069000000"); - EXPECT_EQ(source.submitHostField(nonMonotonic, payload), + EXPECT_EQ(source.submitHostField(nonMonotonic, eastPayload), style::RasterArrayHostFieldSubmitResult::RejectedNonMonotonicSnapshot); EXPECT_EQ(source.impl().timeline->size(), 2u); @@ -756,7 +758,7 @@ TEST(Source, HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField) { EXPECT_EQ(source.impl().timeline->frame().state, style::RasterArrayPlaybackState::Ready); style::RasterArraySource fixtureSource{"fixture", "uniform-east", "metadata", "field"}; - EXPECT_EQ(fixtureSource.submitHostField(localMetadata(2), payload), + EXPECT_EQ(fixtureSource.submitHostField(localMetadata(2), eastPayload), style::RasterArrayHostFieldSubmitResult::RejectedSourceMode); } @@ -764,10 +766,16 @@ TEST(Source, RasterArrayTimelineCandidatesReachReadyThroughFieldAdapter) { SourceTest test; const auto eastMetadata = fixtureBytes("uniform-east", "metadata.json"); const auto eastField = fixtureBytes("uniform-east", "field.f32"); - const auto northMetadata = fixtureBytes("uniform-north", "metadata.json"); + auto northMetadata = fixtureBytes("uniform-north", "metadata.json"); const auto northField = fixtureBytes("uniform-north", "field.f32"); - const auto vortexMetadata = fixtureBytes("vortex", "metadata.json"); + auto vortexMetadata = fixtureBytes("vortex", "metadata.json"); const auto vortexField = fixtureBytes("vortex", "field.f32"); + const auto northTimeIndex = northMetadata.find("\"timeIndex\": 0"); + ASSERT_NE(northTimeIndex, std::string::npos); + northMetadata.replace(northTimeIndex, std::string("\"timeIndex\": 0").size(), "\"timeIndex\": 1"); + const auto vortexTimeIndex = vortexMetadata.find("\"timeIndex\": 0"); + ASSERT_NE(vortexTimeIndex, std::string::npos); + vortexMetadata.replace(vortexTimeIndex, std::string("\"timeIndex\": 0").size(), "\"timeIndex\": 2"); test.fileSource->sourceResponse = [&](const Resource& resource) -> Response { Response response; const std::string* text = nullptr; diff --git a/粒子开发记录.md b/粒子开发记录.md index b51cfb8f5..ed4b59d88 100644 --- a/粒子开发记录.md +++ b/粒子开发记录.md @@ -668,3 +668,8 @@ WeatherColorLayer 的 `ParticleGpuValidationUBO` designated initializer 补齐 ` - Rain 仍为明确“非真实场值”的 PMTiles decoder fallback,generation=1/2;RN Host 已将 Wave/Tide 指向 real fixture,并继续只用 `.3` `FieldRuntime` 公共 API。 - fixture validator、package tsc、Host typecheck、RN codegen 与 `/tmp/step070-ccache` 精确 Core object PASS。随后 Linux OpenGL 完整依赖闭包构建 459/459 完成,`mbgl-test-runner` 成功链接,`Source.ParticleFieldV3*` 过滤测试 6/6 PASS,验证链退出码 0,`git diff --check` PASS。Android Gradle/AAR/APK/ADB/Jest 均未运行,STEP-070 保持 IMPLEMENTED / WAITING_ANDROID_VALIDATION。 - STEP-070 implementation `8588e6fcb4f3f5d874159c2e42619c5227cb7921` 已 scoped push 到 `origin/particle/main`;STEP-062 与历史 untracked/build/cache/tgz 未纳入。 + +## 2026-09-11 — STEP-071 V3-07 Linux 综合冻结 +- 最终冻结链:fixture validator、package tsc、RN Test Host typecheck、RN codegen、Linux OpenGL `mbgl-test`/`mbgl-test-runner` target 均 PASS;V3 综合过滤 21/21 PASS,`git diff --check` PASS,验证链退出码 0。 +- 综合回归发现并修正两个测试 fixture 陈旧问题:Host T0/T1 重复 GPU content 导致 Duplicate,以及旧 east/north/vortex `timeIndex=0` 导致 Timeline fail-closed。只改测试数据组合,不改 Runtime/Timeline/Renderer 生产逻辑。 +- Android Gradle/AAR/APK/ADB/Jest 未运行;V3-07 Linux 冻结关闭,下一步统一进入 V3-08 Android 综合验收。STEP-062 用户 dirty 与历史 untracked/build/cache/tgz 未纳入。