# STEP-100 SourceScoped RenderSegment 局部失效 — 完成报告 v1 ## 1. 最终结论 **CLOSED / PASS(功能与 Android 运行态目标确认)**。 Codex 实现使用: - model:`gpt-6-sol` - reasoning effort:`high` RDC 独立完成: - 源码 diff 审计; - Android x86_64 OpenGL 全量 native build; - Validation APK; - FZG1-2 自动安装与 T1/T2/T3/T4; - STEP-100 60 秒 locality window; - validation build script 小型工程修复; - Git diff/status 审计。 本 Step 核心目标已确认: > 动态 GeoJSON Source 更新只影响依赖它的 RETAINED Segment;无关 R0 cache 不再跟着 invalid/rebuild,并且在 global loaded=false 时仍可安全 reuse。 Native host GTest 因当前 Intel Mac 缺 `libuv` 未执行;曾尝试 Homebrew 安装,但 Homebrew 要连带升级 CMake/OpenSSL/Python 且 Intel 已无 bottle 支持,因此 RDC 主动终止,未把环境变化作为任务依赖。Android 最终 C++ native build 与设备运行态用于本轮功能验收。 Jest:**NOT RUN**,用户未要求。 ## 2. Git / 基线 - worktree:`/Users/tei/dev/MapLibreParticleLab-step100` - branch:`step100-segment-local-source-invalidation` - start HEAD:`c4b481fd2c5b5da20d31f6ae54011f0552d7dbd0` - start remote:`origin/particle/main = c4b481fd2c5b5da20d31f6ae54011f0552d7dbd0` - frozen V17 tag:`maplibre-particle/rn/13.4.1-particle.17` - frozen V17 commit:`e8b451fe70054107773e82484c80e90df3889147` - V17 tag/release worktree:未修改。 最终 STEP-100 commit / push / remote HEAD 在 Git 收尾后由最终交付回读记录,避免文档自引用。 ## 3. 实际修改 生产源码: - `include/mbgl/renderer/render_segment.hpp` - `src/mbgl/renderer/render_orchestrator.hpp` - `src/mbgl/renderer/render_orchestrator.cpp` - `src/mbgl/renderer/renderer_impl.cpp` - `src/mbgl/renderer/retained_underlay_cache.cpp` - `src/mbgl/renderer/retained_underlay_runtime_state.hpp` - `src/mbgl/renderer/render_segment_json.hpp` - `packages/maplibre-particle-rn/src/types.ts` Test App / tests: - `platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/Step099ReadinessFixture.kt` - `platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/ParticleCoreLayerValidationActivity.kt` - `test/renderer/retained_underlay_cache.test.cpp` 工具: - `tools/particle_android_validation/build_validation_apk.sh` - RDC 修复 `unzip | awk ... exit` 在 `pipefail` 下偶发 SIGPIPE/141; - 仅移除 awk 的提前 exit,不改变 APK 验证语义。 文档: - `docs/40_任务/STEP-100_SourceScoped_RenderSegment局部失效_Codex任务_v2.md` - `docs/50_Step记录/STEP-100_SourceScoped_RenderSegment局部失效_v1.md` - 本报告; - `粒子开发记录.md` ## 4. 生产设计 ### 4.1 Source-scoped revision 新增正式 source-scoped revision bookkeeping。 明确的 Source/Tile mutation: - source diff; - feature state; - tile changed; 推进对应 sourceId revision。 现有 global `retainedUnderlayContentRevision` 继续增长,供: - compatibility; - diagnostics; - Fast Path fail-closed。 RETAINED Segment cache 不再直接以 global Source/Tile revision 作为内容 revision。 ### 4.2 Segment dependency 正式 renderer 与 diagnostics 共用 source→segment 依赖推导。 规则: - layer sourceId 决定 source dependency; - source-less background 不制造假 dependency; - shared source 可影响多个 segment; - symbol 的 glyph/image/placement 作为明确 global prerequisite; - 真正无法证明的 dependency fail closed。 ### 4.3 Per-segment readiness 未修改: - `Source::isLoaded()`; - `renderTreeParameters->loaded = styleLoaded && isLoaded()`。 full CPU retained path 增加 per-segment source readiness/stability: - dependent source unloaded → 仅该 Segment fallback; - dependent source fading → 仅该 Segment unstable; - unrelated source unloaded/fading → 不影响该 Segment; - style/image/sprite/glyph/placement/context 等 global prerequisite 仍 fail closed。 ### 4.4 Mixed Build / Reuse / Fallback 移除 retained full-CPU path 的 all-or-none `useRetainedRanges` 依赖。 每个 RETAINED Segment独立决定: - Build - Reuse - Fallback 主 buffer 按 Style Segment 顺序执行: - RETAINED Build/Reuse → composite cache - RETAINED Fallback → live render only that range - CONTINUOUS → live render 因此允许: ```text R0 = Reuse C = Live R1 = Fallback ``` 不再因为 R1 fallback 把 R0 一起变成 live redraw。 Fast Path gate / `singleContinuousSegment` / multi-continuous Fast Path:**未修改**。 ## 5. Android build 首次标准 validation script 的 Gradle 本体实际结果: ```text BUILD SUCCESSFUL in 12s 86 actionable tasks: 6 executed, 80 up-to-date ``` 但脚本在 Gradle 成功后以 141 退出。RDC 用 `bash -x` 精确定位到: ```bash LIB_BYTES="$(unzip ... | awk '/.../ {print $1; exit}')" ``` 在 `set -o pipefail` 下触发 SIGPIPE。 RDC 仅去掉 awk 的 `exit`,重跑标准脚本: ```text RC=0 [validation-apk] BUILD SUCCESS ``` 最终 APK: - variant:OpenglDebug - ABI:x86_64 - apk bytes:61,956,640 - libmaplibre.so bytes:39,636,472 - SHA-256: `86e22bf081bf7d3196f0bf0e7c56af51bde01e9f0b01e0bab238cb794273315a` 证据: `artifacts/maplibre-particle/android-validation/` ## 6. 设备 - serial:`192.168.200.139:5555` - model:FZG1-2 - Android:13 - API:33 - ABI:x86_64 APK 覆盖安装成功,`ParticleCoreLayerValidationActivity` 冷启动成功。 STEP-100 log: `artifacts/maplibre-particle/android-validation/step100-logcat.txt` log SHA-256: `e9d18ea987d12cb30e321d0d9c669b2588972aac89e5277920bf1fa9fee8146b` ## 7. T1 STATIC 运行约 20 秒。 aggregate: ```text falseWindowCount=1 falseWindowAvgMs=203 falseWindowMaxMs=203 openFalseWindowMs=0 ``` 最终: - R0 build=1 - R0 reuse=1217 - R0 decision=reuse - R1 build=1 - R1 reuse=1187 - R1 decision=reuse 静态 R-C-R 正常。 ## 8. T4 R-C-R 主验收 结构: ```text R0 -> step099-static C -> particle-fixture R1 -> step099-dynamic (+ framework annotation source if present) ``` window marker: ```text baseline tick=8 17:05:21.642 final tick=130 17:06:23.240 ``` 窗口约 61.6 秒。 dynamic update 总计:68 次。 global revision: ```text 128 -> 973 ``` 说明 global compatibility revision **仍正常增长**,没有通过停掉 global revision“作弊”。 ### R0 baseline: ```text build=1 reuse=132 invalidation=20 srcRev=5127273714767523329 decision=reuse ``` final: ```text build=1 reuse=4042 invalidation=20 srcRev=5127273714767523329 decision=reuse ``` Delta: ```text buildDelta = 0 invalidationDelta = 0 reuseDelta = +3910 sourceRevision = unchanged ``` **硬门槛 PASS。** ### R1 baseline: ```text build=5 invalidation=26 ``` final: ```text build=135 invalidation=211 ``` 动态 Source mutation 正常驱动 R1。 mutation diagnostics 持续: ```text sourceId=step099-dynamic affected=[2] scope=source-local-diagnostic ``` ### loaded false windows T4: ```text falseWindowCount=5 falseWindowAvgMs=202 falseWindowMaxMs=203 openFalseWindowMs=0 ``` 即 transient global loaded=false 仍存在,但不再让 R0 build/invalidation 增长。 ## 9. T2 双 GeoJSON readiness 回归 约 35 秒。 aggregate: ```text falseWindowCount=6 falseWindowAvgMs=203 falseWindowMaxMs=205 openFalseWindowMs=0 ``` R0 在动态窗口保持: - build=1 - invalidation=18 - revision unchanged - reuse 持续增长。 R1 随两个动态 GeoJSON 持续 build/invalidate。 结论: **DYNAMIC_SOURCE_READINESS_THRASH 仍是 global loaded 事实,但不再误伤无关 retained cache。** ## 10. T3 permanently unready unrelated source `step099-unready-raster-array`: - no layer; - enabled=false; - isLoaded=false。 global: ```text renderOrchestratorLoaded=false openFalseWindowMs=21468 ``` 约 21.468 秒持续 false。 与此同时: R0: - build=1 - invalidation=19 - reuse:11 → 1200 - decision=reuse R1: - build=1 - invalidation=19 - reuse:11 → 1200 - decision=reuse 因此: > global loaded 仍保持旧兼容语义,但 unrelated permanently-unready source 已不能把无关 RETAINED Segment 拖成 style-not-loaded fallback。 **硬门槛 PASS。** ## 11. Mixed fallback T4 中 R1 `fallbackCount` 从约 21 增长到 76,而 R0 fallback 计数保持不变,同时 R0 reuse 持续增长。 这证明运行期间真实发生了: ```text R0 = Reuse R1 = transient Fallback / rebuild ``` 而不是只有“两个段都 ready”的理想场景。 未观察到 crash / ANR。 ## 12. Fast Path 边界 RDC diff 审计确认未修改: - `tryRenderParticleFastFrame` - `particleFastPathNonCameraInputsMatch` - `singleContinuousSegment` - multi-continuous fail-closed - global Fast Path signature/fade/contentRevision/pending/placement 等 gate。 STEP-100 只修 full CPU retained locality。 ## 13. Native host tests Codex 已新增 `RenderSegmentLocality.*` C++ 测试源码。 RDC 尝试恢复 `macos-metal` test runner,但 host configure 需要 `libuv`,当前未安装。 尝试 `brew install libuv` 时发现 Intel Homebrew 会连带升级: - CMake - OpenSSL - Python - ca-certificates 等 且当前 Intel macOS 已无官方 bottle 支持。为避免污染开发环境,RDC 主动停止。 因此: - Native host GTest:**ENV BLOCKED / NOT RUN** - Android C++ full native build:**PASS** - Android device runtime:**PASS** ## 14. Jest / iOS - Jest:NOT RUN。 - iOS runtime:本 Step 未运行。 - V18 unified release:在 STEP-100 Git 收尾后单独执行。 ## 15. 最终判定 STEP-100 的核心实现目标全部成立: 1. global revision 继续增长; 2. R1 GeoJSON mutation 不再 invalid/rebuild R0; 3. R0 buildDelta=0; 4. R0 invalidationDelta=0; 5. R0 reuseDelta>0; 6. transient unrelated unloaded 不影响 R0 reuse; 7. permanent unrelated unloaded 不影响 R0 reuse; 8. mixed Reuse/Fallback 实际发生; 9. Fast Path 语义未放宽。 因此本 Step 功能与 Android runtime 验收: **PASS / CLOSED**。 下一步允许进入 V18 unified release。