diff --git a/docs/50_Step记录/STEP-099_RenderSource就绪与RenderSegment失效诊断_v1.md b/docs/50_Step记录/STEP-099_RenderSource就绪与RenderSegment失效诊断_v1.md new file mode 100644 index 000000000..6f7a67e7d --- /dev/null +++ b/docs/50_Step记录/STEP-099_RenderSource就绪与RenderSegment失效诊断_v1.md @@ -0,0 +1,175 @@ +# STEP-099 RenderSource 就绪与 RenderSegment 失效诊断 + +状态:**CLOSED / PASS** +日期:2026-10-06(JST) + +## 基线 + +- 仓库:`/Users/tei/dev/MapLibreParticleLab-step099` +- 分支:`step099-render-source-diagnostics` +- frozen release:`maplibre-particle/rn/13.4.1-particle.17` +- frozen release commit:`e8b451fe70054107773e82484c80e90df3889147` +- implementation commit:`8a5214d92dd2f8899db76d2194da42999fa0c87d` +- Integration/NavSea:未修改。 + +## 本 Step 完成内容 + +- Renderer readiness snapshot additive 暴露 style/image manager/render orchestrator/sprite readiness、fading、global content revision、per-source 状态和最近 mutation。 +- per-source diagnostics 暴露 sourceId/type/enabled/isLoaded;tile-backed source 提供 tileCount/incomplete/loaded/fading。 +- RenderSegment diagnostics 只读推导 `dependentSourceIds` / `unknownDependencies`;source-less layer 不制造 source dependency,共享 source 可出现在多个 segment。 +- mutation sequence/source/tile action/reason 只消费既有 renderer 事件;正式 revision 增长逻辑不变。 +- 正式 loaded 判定保持: + `renderTreeParameters->loaded = updateParameters->styleLoaded && isLoaded();` +- diagnostics snapshot 不进入正式 loaded/cache/fast path/segment execution。 +- RN 仅增加 diagnostics 类型字段;没有 NavSea 私有 API,没有改变业务 API。 +- Android Test App 提供 T1 STATIC、T2 GEOJSON_1HZ、T3 PERMANENT_UNREADY、T4 R-C-R。 + +## Native 验证 + +Metal host `RenderSegmentDiagnostics.*`: + +- 6/6 PASS; +- 新增 `ReadinessSnapshotMapsSourcesToSegmentsWithoutSideEffects` PASS; +- 覆盖 source readiness、tile stats、source→segment、shared source、source-less 与重复 query 无副作用。 + +最终源码再次尝试 Metal configure 时当前 Mac 缺 `libuv` pkg-config,因此第二次 host rerun 未进入 build;不虚报 PASS。最终代码已经被 Android 全量 native build 成功编译并由 T1~T4 运行覆盖。 + +Vulkan:因当前 Mac 缺 `libuv`,NOT RUN tests。 + +Jest:NOT RUN,用户未要求。 + +## Android 构建 + +首轮 Android NDK 暴露: + +```text +error: missing field 'tileCount' initializer +[-Werror,-Wmissing-designated-field-initializers] +``` + +只补全 `RenderSourceReadinessStats` 默认空字段显式初始化。 + +随后 native build 通过,但 strip 阶段因 Mac 磁盘仅剩约 2 GiB: + +```text +No space left on device +``` + +仅清理可再生 Gradle 9.5.1 cache / 失败中间产物后恢复约 12 GiB,再次增量构建: + +- `BUILD SUCCESSFUL in 4m 54s` +- 86 actionable tasks:7 executed / 79 up-to-date +- OpenGL Debug / x86_64 +- APK:61,923,024 bytes +- libmaplibre.so:39,602,856 bytes +- SHA-256: + `5de73f0358b835a78d3ae7e2ac22f4efdb2a66775b8c63654a8bb7313957d90a` + +设备: + +- `192.168.200.139:5555` +- FZG1-2 +- Android 13 / API 33 / x86_64 + +## T1~T4 结果 + +### T1 STATIC + +- 1 个启动 false window; +- avg/max = 204 ms; +- 随后 global loaded 稳定为 true; +- retained cache 可持续 reuse; +- fast path 可进入 active。 + +### T2 GEOJSON_1HZ + +- 两个 GeoJSON source 交错更新,总 update 122 次,约 61 次/源; +- 10 个 loaded=false window; +- avg 203 ms; +- max 205 ms; +- open 0; +- 约 60 s 中 false 总时长约 2.03 s,约 3.4%。 + +结论:存在 readiness thrash,但不是“几乎永远 false”。 + +### T3 PERMANENT_UNREADY + +`step099-unready-raster-array`: + +- 无 layer; +- enabled=false; +- isLoaded=false; +- 其他主要 source loaded。 + +结果: + +- global renderOrchestratorLoaded=false 持续; +- 观察结束 open false window = 21,459 ms; +- retained cache 持续 style-not-loaded fallback。 + +结论:单个与 segment 无关的 permanently unready source 足以拉低 V17 全局 loaded。 + +### T4 R-C-R + +- R0 deps=[step099-static] +- C deps=[particle-fixture] +- R1 deps=[org.maplibre.annotations, step099-dynamic, step099-static] +- dynamic update:61 次 + +结果: + +- loaded false windows:4 +- avg 203 ms +- max 207 ms +- contentRevision:1760 → 2540 +- diagnostics 对 dynamic source 正确给出 affected=[2] +- R0 不依赖 dynamic source,但: + - build 1 → 121 + - invalidation 20 → 200 + +结论:dependency diagnostics 已能表达 source-local 影响,但 V17 正式 content revision/cache invalidation 仍为 global。 + +## Q1~Q7 + +1. Q1:**YES**。permanently unloaded source 会造成全局 style-not-loaded。 +2. Q2:**YES**。1 Hz GeoJSON 会产生约 200 ms readiness false window;T2 avg 203 / max 205 ms。 +3. Q3:**NO(本次观测)**。双 1 Hz source 并未让 global loaded 几乎始终 false。 +4. Q4:**YES**。GeoJSON tile mutation 推进 global content revision,并使 retained cache 重建/失效。 +5. Q5:**YES**。不引用动态 GeoJSON 的 R0 仍受 global revision 影响;源码还确认 `retainedRangeIsStable` 全局检查所有 source fading。 +6. Q6:fast path 仍有 global update signature(sources/layers/images 等)、global content revision、global fade、pendingChanges、placement/light/non-particle transition/repaint、annotation mutation、retained revision/cache/topology/boundary,以及 singleContinuous gate。 +7. Q7 blocker: + - runtime confirmed:`PERMANENT_SOURCE_UNLOADED`、`DYNAMIC_SOURCE_READINESS_THRASH`、`GLOBAL_CONTENT_REVISION` + - source confirmed:`GLOBAL_FADE`、`GLOBAL_UPDATE_SIGNATURE` + - OTHER:pending/placement/light/repaint/annotation/topology/boundary/singleContinuous。 + +## 证据 + +忽略目录: + +`artifacts/maplibre-particle/android-validation/` + +- `build-info.txt` +- `build.log` +- `MapLibreAndroidTestApp-validation-opengl-debug-x86_64.apk` +- `step099-logcat.txt` +- `step099-device-info.txt` +- `step099-metal-gtest.log` + +STEP-099 log SHA-256: + +`0f15d75dde77e7dd2f4d98c46a4c1501a628205e8aae62130b0cb96db6b8482f` + +## 边界结论 + +本 Step 未修改: + +- retained cache 算法; +- fast path gate; +- singleContinuous / multi-continuous; +- segment-local invalidation 正式语义; +- RenderSegment execution; +- NavSea; +- Source isLoaded; +- RN 业务 API。 + +下一阶段应拆分处理 global source readiness、source/segment-local content revision/invalidation,再独立处理 fast-path global gates。 diff --git a/docs/报告/STEP-099_RenderSource就绪与RenderSegment失效诊断_Codex完成报告_v1.md b/docs/报告/STEP-099_RenderSource就绪与RenderSegment失效诊断_Codex完成报告_v1.md new file mode 100644 index 000000000..b39175f15 --- /dev/null +++ b/docs/报告/STEP-099_RenderSource就绪与RenderSegment失效诊断_Codex完成报告_v1.md @@ -0,0 +1,536 @@ +# STEP-099 RenderSource 就绪与 RenderSegment 失效诊断 — Codex 完成报告 v1 + +## 1. 执行结论 + +**CLOSED / PASS(诊断阶段完成)**。 + +STEP-099 按任务书保持“纯诊断、fail-closed、不优化正式语义”的范围完成。Renderer/Source/RenderSegment diagnostics、Android Test App T1~T4 场景、定向 native 测试和 Android 实机运行证据均已取得,Q1~Q7 可以据实回答。 + +本 Step **没有**修改 retained cache 算法、fast path gate、`singleContinuousSegment`、multi-continuous 行为、segment-local invalidation、RenderSegment 执行语义、NavSea、Source `isLoaded()` 定义或 RN 业务 API 语义。 + +## 2. 基线与 Git + +- 仓库:`/Users/tei/dev/MapLibreParticleLab-step099` +- branch:`step099-render-source-diagnostics` +- frozen release tag:`maplibre-particle/rn/13.4.1-particle.17` +- frozen release commit / start base:`e8b451fe70054107773e82484c80e90df3889147` +- implementation commit:`8a5214d92dd2f8899db76d2194da42999fa0c87d` +- implementation message:`diagnostics: add STEP-099 render source readiness audit` +- Integration/NavSea:未修改。 +- 文档 closeout commit、push result、`origin/particle/main` Final HEAD:Git 提交无法在自身内容中自指其最终 SHA,按项目既有规则由最终交付回读记录。 + +## 3. 实际修改范围 + +生产源码 / diagnostics: + +- `include/mbgl/renderer/render_segment.hpp` +- `src/mbgl/renderer/render_orchestrator.cpp` +- `src/mbgl/renderer/render_orchestrator.hpp` +- `src/mbgl/renderer/render_segment_json.hpp` +- `src/mbgl/renderer/render_source.hpp` +- `src/mbgl/renderer/retained_underlay_runtime_state.hpp` +- `src/mbgl/renderer/sources/render_tile_source.cpp` +- `src/mbgl/renderer/sources/render_tile_source.hpp` +- `packages/maplibre-particle-rn/src/index.ts` +- `packages/maplibre-particle-rn/src/types.ts` + +测试 / Test App: + +- `test/renderer/retained_underlay_cache.test.cpp` +- `platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/ParticleCoreLayerValidationActivity.kt` +- `platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/Step099ReadinessFixture.kt` + +项目记录: + +- `docs/50_Step记录/STEP-099_RenderSource就绪与RenderSegment失效诊断_v1.md` +- `docs/报告/STEP-099_RenderSource就绪与RenderSegment失效诊断_Codex完成报告_v1.md` +- `粒子开发记录.md` + +## 4. 诊断能力 + +### 4.1 全局 readiness + +新增只读 snapshot: + +- `styleLoaded` +- `imageManagerLoaded` +- `renderOrchestratorLoaded` +- `spriteLoaded` +- `hasFadingTiles` +- global retained `contentRevision` +- RenderSegment plan/config/topology 信息 +- 最近 mutation sequence / reason / source / affected segment diagnostics + +正式 loaded 路径保持原式: + +```cpp +renderTreeParameters->loaded = updateParameters->styleLoaded && isLoaded(); +``` + +diagnostics snapshot 在旁路采样,失败被 best-effort 隔离,不决定正式 loaded。 + +### 4.2 per-source readiness + +每个 RenderSource additive 暴露: + +- sourceId / sourceType +- enabled / isLoaded +- tileBacked +- tileCount / incompleteTileCount / loadedTileCount +- hasFadingTiles +- last source/tile mutation sequence +- last tile action / reason + +默认非 tile source 返回完整显式初始化的空统计,Android NDK `-Werror` 下已验证通过;未改变任何 Source `isLoaded()` 实现。 + +### 4.3 RenderSegment 只读依赖 + +每个 segment additive 暴露: + +- segmentIndex / strategy / beginIndex / endExclusive +- `dependentSourceIds` +- `unknownDependencies` + +规则: + +- 从实际 ordered layers 的 sourceId 推导; +- shared source 可出现在多个 segment; +- source-less background 不制造假依赖; +- symbol/custom 等无法仅靠 sourceId 完整表达的依赖标记为 unknown/global; +- 依赖图只用于诊断,不参与 cache/loaded/fast path/execution。 + +### 4.4 mutation 定位 + +Source/tile mutation 复用已有回调记录 sequence/source/reason/action。原 `retainedUnderlayContentRevision` 的增长次数与正式调用路径不变;diagnostics 不增加额外 revision。 + +query 路径不清理或修改 event history,重复 snapshot/JSON 查询保持无副作用。 + +## 5. Native 定向测试 + +### 5.1 Metal host 定向 GTest + +实际执行: + +```bash +cmake --preset macos-metal +cmake --build build-macos-metal --target mbgl-test-runner --parallel 3 +build-macos-metal/mbgl-test-runner --gtest_filter='RenderSegmentDiagnostics.*' +``` + +结果: + +- `RenderSegmentDiagnostics.*`:**6/6 PASS** +- 新增 `ReadinessSnapshotMapsSourcesToSegmentsWithoutSideEffects`:PASS +- 覆盖 source loaded/unloaded、tile stats、source→segment、shared source、source-less、重复 query、topology/cache/content revision 无副作用。 + +证据: +`artifacts/maplibre-particle/android-validation/step099-metal-gtest.log` + +SHA-256: +`f0618750ead03eae1b251126dd49488a9269a120373a66e3453fa9aaa1dc0f10` + +说明:该 6/6 发生在 Android NDK 首轮暴露“默认 readiness struct designated initializer 未显式列完 optional 字段”之前;随后仅补全默认空字段初始化。最终源码由 Android 全量 native build 成功覆盖。为了在最终源码上重跑 Metal,重新 configure 时当前 Mac 缺 `libuv` pkg-config,configure fail;没有安装系统依赖来制造 PASS。 + +### 5.2 Vulkan + +`macos-vulkan` configure:**BLOCKED / NOT RUN TESTS**。 + +原因: + +```text +The following required packages were not found: + - libuv +``` + +这是当前 Mac host 环境依赖,不是 STEP-099 源码编译错误。 + +### 5.3 Jest + +**NOT RUN**。用户未要求 Jest,任务未加入 Jest。 + +## 6. Android 构建与设备 + +### 6.1 首轮 Android 编译问题 + +首轮 x86_64 OpenGL build 在 Android NDK `-Werror` 下发现: + +```text +render_source.hpp:84:51: +error: missing field 'tileCount' initializer +[-Werror,-Wmissing-designated-field-initializers] +``` + +修复仅补全 `RenderSourceReadinessStats` 默认空字段初始化,不改变运行语义。 + +随后 native C++ 已越过原失败点并完整编译。 + +### 6.2 磁盘阻塞与恢复 + +第一次完整 native build 后,在: + +`MapLibreAndroidTestApp:stripOpenglDebugDebugSymbols` + +因 Mac 仅剩约 2 GiB 出现: + +```text +No space left on device +``` + +RDC 只清理可再生 Gradle 9.5.1 cache / 本轮失败中间产物,保留 Android native object;可用空间恢复到约 12 GiB 后增量重跑。 + +### 6.3 最终 APK + +命令: + +```bash +./tools/particle_android_validation/build_validation_apk.sh +``` + +最终结果: + +- Gradle:**BUILD SUCCESSFUL in 4m 54s** +- actionable tasks:86(7 executed / 79 up-to-date) +- variant:OpenGL Debug +- ABI:x86_64 +- APK:61,923,024 bytes +- `libmaplibre.so`:39,602,856 bytes +- APK SHA-256: + `5de73f0358b835a78d3ae7e2ac22f4efdb2a66775b8c63654a8bb7313957d90a` + +构建时 metadata: + +- base commit:`e8b451fe70054107773e82484c80e90df3889147` +- `git_dirty=true` +- 构建内容与随后形成的 implementation commit `8a5214d92` 源码一致;当前 source tree 对 implementation commit clean,剩余仅 docs closeout。 + +### 6.4 Android 设备 + +Mac ADB 直接连接: + +- serial:`192.168.200.139:5555` +- model:`FZG1-2` +- Android:13 +- API:33 +- ABI:x86_64 + +APK 覆盖安装成功,`ParticleCoreLayerValidationActivity` 冷启动成功。 + +运行 log: +`artifacts/maplibre-particle/android-validation/step099-logcat.txt` + +log SHA-256: +`0f15d75dde77e7dd2f4d98c46a4c1501a628205e8aae62130b0cb96db6b8482f` + +## 7. T1~T4 实测 + +### T1 STATIC + +场景: + +- R0:静态 GeoJSON retained +- C:本地静态 RasterArray field 驱动 WeatherColor + Particle +- R1:静态 retained +- camera fixed + +结果: + +- 启动阶段 1 个 false window:204 ms; +- 随后 `renderOrchestratorLoaded=true` 稳定; +- `particle-fixture` 与 `step099-static` 均 loaded; +- retained cache 建立后持续 reuse; +- fast path 进入 `active=true / eligible=true / reason=none`; +- 没有持续 style-not-loaded。 + +aggregate: + +```text +falseWindowCount=1 +falseWindowAvgMs=204 +falseWindowMaxMs=204 +openFalseWindowMs=0 +``` + +结论:静态基线可稳定进入 loaded/cache reuse/fast path。 + +### T2 GEOJSON_1HZ + +两个 GeoJSON source 每 500 ms 交错更新,因此每个约 1 Hz。 + +实际: + +- 总 source update:122 次,约 61 次/源; +- 60 秒量级观察中,出现 10 个 loaded=false window; +- 平均 203 ms; +- 最大 205 ms; +- 最终 open window = 0; +- 总 false 时间约 2.03 s,约占 60 s 的 3.4%,不是“几乎始终 false”。 + +aggregate: + +```text +falseWindowCount=10 +falseWindowAvgMs=203 +falseWindowMaxMs=205 +openFalseWindowMs=0 +``` + +同时 final sample: + +- global contentRevision 已到 1679; +- R0 仅依赖 `step099-static`,但 cache build=241、invalidation=362; +- R1 依赖动态 GeoJSON,也同样 build=241; +- mutation diagnostics 能正确指出动态 source 只 `affected=[2]`,但正式 cache invalidation 仍非局部。 + +### T3 PERMANENT_UNREADY + +额外加入: + +`step099-unready-raster-array` + +它: + +- 没有 layer; +- 因此 `enabled=false`; +- host-submission 无 field; +- `isLoaded=false`。 + +其他主要 source 均 loaded。 + +实测: + +- `renderOrchestratorLoaded=false` 持续; +- retained segment cache 持续 fallback; +- `lastInvalidationReason=style-not-loaded`; +- 观察结束仍没有恢复。 + +aggregate: + +```text +falseWindowCount=0 +openFalseWindowMs=21459 +``` + +结论:即使 source 与当前 layer/segment 无关且 disabled,只要仍在 `renderSources` 且 `isLoaded=false`,V17 全局 `RenderOrchestrator::isLoaded()` 就保持 false。 + +### T4 R-C-R + +结构: + +- R0:`deps=[step099-static]` +- C:`deps=[particle-fixture]`,WeatherColor + Particle +- R1:`deps=[org.maplibre.annotations, step099-dynamic, step099-static]` +- `step099-dynamic` 约 1 Hz 更新 + +实际: + +- dynamic update:61 次; +- loaded false window:4; +- 平均 203 ms; +- 最大 207 ms; +- global contentRevision:1760 → 2540; +- mutation diagnostics:`step099-dynamic` 对应 `affected=[2]`; +- R0 并不依赖 `step099-dynamic`,但: + - build:1 → 121 + - invalidation:20 → 200 +- R1 同步得到相同级别 build/invalidation 增长; +- fast path 在稳定窗口可恢复 active,但 global revision / transient readiness 会反复制造 full CPU work。 + +aggregate: + +```text +falseWindowCount=4 +falseWindowAvgMs=203 +falseWindowMaxMs=207 +openFalseWindowMs=0 +``` + +结论:依赖诊断已经能准确表达“R1 source-local”,但 V17 正式 content revision/cache invalidation 仍是 global。 + +## 8. Q1~Q7 + +### Q1:单个 permanently unloaded source 会造成 V17 style-not-loaded 吗? + +**YES / CONFIRMED。** + +T3 中 `step099-unready-raster-array` 无 layer、`enabled=false`、`isLoaded=false`;其他主要 source loaded,但整体 `renderOrchestratorLoaded=false` 持续 21.459 s 未恢复,retained cache 持续 `style-not-loaded` fallback。 + +源码事实与运行事实一致:`RenderOrchestrator::isLoaded()` 遍历全部 `renderSources`,不按 enabled/segment dependency 排除 source。 + +### Q2:1 Hz GeoJSON 会周期性让 isLoaded=false 吗?平均/最大窗口? + +**YES / CONFIRMED。** + +T2 双 source 交错各约 1 Hz: + +- 10 次 false window; +- avg 203 ms; +- max 205 ms。 + +T4 单动态 source 约 1 Hz: + +- 4 次 false window; +- avg 203 ms; +- max 207 ms。 + +### Q3:错开的多个 1 Hz GeoJSON 会导致 global loaded 几乎无法稳定为 true 吗? + +**NO / 本次观测不支持。** + +T2 约 60 s 中总 false 时间约 2.03 s,约 3.4%;绝大多数时间 global loaded=true。它确实产生 readiness thrash,但不是“几乎永远 false”。 + +### Q4:GeoJSON tile mutation 会推进 global retainedUnderlayContentRevision 并影响 retained cache 吗? + +**YES / CONFIRMED。** + +T4 global contentRevision 1760 → 2540。仅依赖静态 source 的 R0 也从 build 1 → 121、invalidation 20 → 200。 + +### Q5:不引用 GeoJSON 的 retained segment 仍会受它的 loaded/fading/tile mutation 影响吗? + +**YES。** + +运行证据: + +- T4 diagnostics 正确报告动态 source `affected=[2]`; +- 但 R0 `deps=[step099-static]` 仍随动态 source mutation 重建/失效。 + +源码证据: + +- `retainedRangeIsStable(begin,end)` 虽为 range API,但最后遍历 **全部 `renderSources`**,任一 source `hasFadingTiles()` 都让任意 retained range unstable。 + +本次 T4 稳态 `fade=false`,因此 R0 的实际反复失效主要直接证明 global content revision/tile mutation;GLOBAL_FADE 属源码确认、未在本轮场景主动触发的全局 gate。 + +### Q6:`tryRenderParticleFastFrame` 仍有哪些 global gate 会阻挡未来 localized cache CPU fast path? + +**确认仍存在:** + +1. **GLOBAL_UPDATE_SIGNATURE** + - `particleFastPathNonCameraInputsMatch` 全局比较: + - styleLoaded / spriteLoaded + - light + - images + - **sources** + - **layers** + - fontFaces / fileSource / glyphURL + - transition / placement / tile LOD 等全局输入。 + +2. **GLOBAL_CONTENT_REVISION** + - `particlePreparedContentRevision == orchestrator.getRetainedUnderlayContentRevision()`。 + +3. **GLOBAL_FADE** + - `particleFastPathDynamicState` 遍历全部 renderSources 汇总 fading; + - `retainedRangeIsStable` 也遍历全部 renderSources。 + +4. **GLOBAL_PENDING / TRANSITION / REPAINT** + - pendingChanges + - renderLight transition + - 任意 layer transition + - 任意非粒子 layer repaint + - placement transition。 + +5. **GLOBAL_ANNOTATION_MUTATION** + - AnnotationManager `hasPendingChanges()`。 + +6. **RETAINED REVISION / CACHE / TOPOLOGY / BOUNDARY** + - retained cache validity/static revision + - global retained revision tracker + - topology revision + - boundary/config revision。 + +7. **singleContinuousSegment** + - 仍要求 plan 恰好能由一个 Continuous segment 表达; + - multi-continuous 继续 fail closed,本 Step 未修改。 + +因此即使未来 cache invalidation 变成 source/segment-local,fast path 仍有多组 global gate 需要后续 Step 单独设计,不能在 STEP-099 顺手放宽。 + +### Q7:blocker 分类 + +**运行态 CONFIRMED:** + +- `PERMANENT_SOURCE_UNLOADED` +- `DYNAMIC_SOURCE_READINESS_THRASH` +- `GLOBAL_CONTENT_REVISION` + +**源码 CONFIRMED,本轮未主动触发独立运行场景:** + +- `GLOBAL_FADE` +- `GLOBAL_UPDATE_SIGNATURE` + +**OTHER:** + +- global pendingChanges +- placement/light/non-particle transition/repaint +- annotation mutation +- topology/boundary/revision/cache validity +- singleContinuous fail-closed + +## 9. 任务边界审计 + +确认未改: + +- retained cache 核心算法; +- fast path gate 逻辑; +- `singleContinuousSegment`; +- multi-continuous 策略; +- segment-local invalidation 正式语义; +- RenderSegment execution; +- NavSea; +- private NavSea Native API; +- RN 业务 API; +- Source `isLoaded()` 定义。 + +新增 dependency / affectedSegmentIndices 只是观察信息;它没有参与正式 invalidation。 + +## 10. 证据文件 + +忽略目录: + +`artifacts/maplibre-particle/android-validation/` + +主要文件: + +- `build-info.txt` +- `build.log` +- `MapLibreAndroidTestApp-validation-opengl-debug-x86_64.apk` +- `step099-logcat.txt` +- `step099-device-info.txt` +- `step099-metal-gtest.log` +- `step099-cmake-metal.log` + +APK SHA-256: + +`5de73f0358b835a78d3ae7e2ac22f4efdb2a66775b8c63654a8bb7313957d90a` + +STEP-099 log SHA-256: + +`0f15d75dde77e7dd2f4d98c46a4c1501a628205e8aae62130b0cb96db6b8482f` + +## 11. 下一阶段建议 + +STEP-099 只负责定位,不在本 Step 修复。 + +下一阶段应基于本轮证据拆开处理: + +1. 先决定 global source readiness 是否要引入“影响当前 style/render segment 的 readiness 范围”,解决 permanently unready / transient unrelated source 对全局 loaded 的影响; +2. 再设计 source/segment-local content revision 与 invalidation,避免 R1 GeoJSON mutation 重建 R0; +3. 最后单独审查 fast-path global signature/fade/pending/placement 等 gate,不能把 cache locality 与 fast-path locality 混成一个修改; +4. 保持 Style Z-order 唯一事实来源和当前通用 Render Segment 模型。 + +## 12. 最终状态 + +**STEP-099 CLOSED / PASS。** + +Pass 含义仅为: + +- diagnostics 能回答任务问题; +- Native 定向测试已有 PASS 证据; +- 最终 Android x86_64 OpenGL APK BUILD SUCCESS; +- FZG1-2 T1~T4 实跑完成; +- Q1~Q7 有源码/运行证据; +- 未改变正式渲染语义。 + +不代表: + +- Vulkan host 已通过; +- iOS runtime 已测试; +- 下一阶段 localized readiness/invalidation 已实现; +- fast path global gates 已优化。 diff --git a/粒子开发记录.md b/粒子开发记录.md index 60eba44fb..960bda9c8 100644 --- a/粒子开发记录.md +++ b/粒子开发记录.md @@ -1022,3 +1022,13 @@ Android V3-08 单次综合验收已完成并关闭。Native `13.4.1-particle.2` - 统一发行 Android 四 ABI 和 Maven Local 通过;首次 iOS Metal Bazel 在 render_weather_color_layer.cpp 编译时找不到新增 WeatherColor lifecycle 头文件。 - 在 bazel/core.bzl 的 MLN_CORE_HEADERS 精确登记该头文件;保留 WeatherColor 业务实现不变。由 RDC 重跑完整 v16 构建、公开回读,iPad 人工验收仍待执行。 + +### 2026-10-06 STEP-099 RenderSource readiness 与 RenderSegment 失效诊断(CLOSED / PASS) + +- frozen release 为 `maplibre-particle/rn/13.4.1-particle.17` / `e8b451fe70054107773e82484c80e90df3889147`;implementation commit 为 `8a5214d92dd2f8899db76d2194da42999fa0c87d`。未修改 Integration/NavSea。 +- 完成 renderer/source readiness additive snapshot、tile stats、mutation source/tile action、只读 source→segment dependency 与 Android T1~T4。正式 `renderTreeParameters->loaded = styleLoaded && isLoaded()`、Source `isLoaded()`、retained cache、fast path、singleContinuous、多 Continuous 和 RenderSegment execution 均未改变。 +- Metal host `RenderSegmentDiagnostics.*` 6/6 PASS;最终 Android x86_64 OpenGL APK BUILD SUCCESSFUL in 4m54s,APK 61,923,024 bytes,SHA-256 `5de73f0358b835a78d3ae7e2ac22f4efdb2a66775b8c63654a8bb7313957d90a`。Vulkan/最终 Metal rerun 因当前 Mac 缺 libuv pkg-config 未执行,不虚报 PASS。 +- FZG1-2 / Android 13 / API33 实跑:T1 静态仅 1 个 204ms 启动 false window 后稳定;T2 双 GeoJSON 各约 1Hz,10 个 false window、avg 203ms、max 205ms;T3 无 layer 的 disabled RasterArray 仍 isLoaded=false,使 global loaded 持续 false 21.459s;T4 61 次动态更新产生 4 个 false window、avg 203ms、max 207ms。 +- T4 证实 dependency diagnostics 能正确给动态 source `affected=[2]`,但 global contentRevision 1760→2540,R0 虽只依赖 `step099-static`,cache build 仍 1→121、invalidation 20→200,确认 `GLOBAL_CONTENT_REVISION`。源码审计同时确认 global fade/update signature/pending/placement/repaint/annotation/singleContinuous 等 fast-path gate 仍存在。 +- Q1~Q7 与 blocker 分类已闭合:runtime confirmed `PERMANENT_SOURCE_UNLOADED`、`DYNAMIC_SOURCE_READINESS_THRASH`、`GLOBAL_CONTENT_REVISION`;source confirmed `GLOBAL_FADE`、`GLOBAL_UPDATE_SIGNATURE`。 +- 完成报告:`docs/报告/STEP-099_RenderSource就绪与RenderSegment失效诊断_Codex完成报告_v1.md`;Step:`docs/50_Step记录/STEP-099_RenderSource就绪与RenderSegment失效诊断_v1.md`;运行证据保存在忽略目录 `artifacts/maplibre-particle/android-validation/`。