Files
MapLibreParticleLab/docs/20_调查/STEP-116_STEP113原PBF_FastPath阻塞安全修复审查_v1.md
tei c48a72a9d4
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
fix: guard STEP-113 empty annotation and expose PBF blockers
2026-10-11 11:50:03 +09:00

74 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# STEP-116 STEP-113 原 PBF Fast Path 阻塞安全修复审查 v1
日期:2026-10-11(JST)。结论:**部分实现(PARTIAL);空 Annotation 生命周期受控修复已落源码,缺源和 Symbol R 准入继续 BLOCKED。没有新的设备 Fast 证据。**
## 1. 当前事实与范围
仓库 `/Users/tei/dev/MapLibreParticleLab`,`particle/main@e2d202b560ad0165101546597c43f2ef0ccf4542`,Darwin 24.6.0 / x86_64。起点 tracked clean,只有 STEP-110/111 和本次 STEP-116 任务书未跟踪。版本仍 `13.6.1-particle.23`,不能用版本号相同推断 APK 源码相同。Integration main `80667d6c343411d03a760425438e3d292f452118` 为用户提供的 RDC 核验事实,本轮只读相关规范,没有 fetch 或跨仓写入。
已读取 AGENTS、PARTICLE_BASELINE、项目规范全部八文件、总则 README 和四份有效总则、STEP-116 任务及 STEP-112/113/114/115 当前记录/报告和相关源码;Integration AGENTS、README、WORKFLOW、TEAM_MODEL、contracts、rfc、adr、instructions、status、compatibility 只读。本轮不使用子代理,不修改公开头文件、公开 API/ABI、Host/RN/JNI 控制协议、NavSea 或公网 Style。
## 2. 缺源 R:证据成立,空依赖准入不实施
保留文件 `artifacts/maplibre-particle/android-validation/step113/source-change-after-full.json`,SHA-256:
`24a06fa1cb072a628c650723c58a880895ec656f4972fa55d3cb064bfb2aabda`
Native 原层 index=2、ID=`tide-spots`、type=`symbol`、source=`tide`。R[0,63) 依赖 `mapple/navsea_delivery/tide`。Native 实际 Source 表是 `mapple:raster`、`navsea_delivery:vector`、`org.maplibre.annotations:annotations`、`rn-weather-fields:raster-array`、`step113-source-probe:geojson`;没有 tide。该文件属于旧 SOURCE_CHANGE 完整窗口,不冒充本次 STATIC_RC 实测。原记录中 fallback=unknown-dependency;当前 STEP-114 代码已提前报 missing-source。
`RenderOrchestrator::retainedSegmentSourceState` 在查 revision 前先检查缺源及 CustomMVTVector;普通 Vector 不走 CustomMVTVector 拒绝分支。`renderSegmentDependencies` 不因隐藏或当前桶为空删依赖。`RenderSegmentRevisionBook::revisionFor` 对未登记来源返回空值,保留删除墓碑用于同名重建;墓碑存在不能代替当前 Source 的 readiness。
源码链路审查:
| 链路 | 当前实现与限制 |
|---|---|
| 零贡献候选 | createRenderTree 的 source/layer 匹配循环不会给缺源层生成 LayerRenderItem,updateList 默认 false;这支持“本轮没有对应新 RenderItem”,不等于全部旧 GPU 对象已完成禁用的证书 |
| 旧 GPU 生命周期 | RenderLayer::markLayerRenderable 调用 activateLayerGroup 提交 ChangeRequest;Symbol 还处理 collisionTileLayerGroup,layerRemoved 停用两类 group。CPU 状态、待处理 requests、旧 buckets 与实际执行时点需要一起核验;无 source 的循环边界也不能只靠 bool 推断 |
| Source 创建/删除/同名恢复 | createRenderTree 的 sourceDiff 递增全局内容及对应 source revision;prepare 输入的 immutable sources 身份变化使 NonCameraSignature 不匹配,必须先 Full |
| 同名更新/异步完成 | changed sourceDiff、onTileChanged → TileMutation → 内容/source revision + observer invalidate;feature-state 同样走 source 变更,不能按 HTTP 下载或 loaded 时间代替 |
| 全局输入 | layerDiff / 层序、imageDiff、Glyph URL/fontFaces、onGlyphsLoaded、Sprite/ImageMissing、context/style cleanup 保留原失效链 |
因此本轮**没有把 missing-source 当 empty**,没有登记虚构 tide revision,没有补假源或删除 tide-spots。后续需要“该 R 在成功 Full 中实际参与 GPU 绘制的 group/碰撞 group 已排除、无待应用资源变化”的有界证据,以及 source 出现/恢复后下一次尝试必定 Full 的回归。当前仅 Source 表缺失不足以承担这项新准入契约。服务器正式 Style 缺源仍是 BLOCKED。
本轮只在现有诊断 JSON 的每段增加可选 `missingSourceIds`,由同次 snapshot 的依赖和 Source 表计算,包含缺失来源的具体 ID。查询不写 revision、不构造缓存、不修改首错和 24 Gate。
## 3. 空 Annotation C:局部修复与保护
旧 STATIC_RC Native 66 层:原63层 + weather-color + raster-particle + 自动 points Symbol。C 从 rn-weather-color 开始,普通 Symbol 不支持 particle dynamic range,阻挡 #22,并影响聚合 #23。SOURCE_CHANGE 的额外 circle 也必须保留。
仅在 Step113PbfGateScene 的 STATIC_RC 第二次 Style 加载完成时执行一次空层调整:
1. 生产基础 ID 不含 points,生产Sources不得占用org.maplibre.annotations;SDK `map.annotations` 必须为空;实际层必须是 SymbolLayer、sourceId 为 org.maplibre.annotations,内部 Source 必须存在。来源由本次原始JSON无内部ID、Native加载路径与实际层共同核对,避免把生产同名Source误当空SDK来源。
2. 使用 `Style.removeLayer(Layer)` 对象重载,保留可重加的 wrapper;Source 保留,原63层定义/顺序及生产 Sources 原样。
3. 记录 `emptyBuiltinAnnotationLayerRemoved`、实例数0、Source保留、移除层ID/作用范围,保存 productionSources;poll/export 继续使用真实 Native 计数。静态预期正常 STATIC_RC 65 层,不能当实际计数。
4. 不周期删除任何层。后续普通 Style.addLayer 保持原行为,native immutable layer/signature/topology 变化继续 Full;Style 更换后不对新 Style 再做移除。
5. stop 在相同 Style 且该 ID 仍缺失时重加原 wrapper,已有同名层不覆盖。Style 身份改变或 Annotation/points 重新出现时,3秒 poll 撤销场景验收条件并报 BLOCKED;poll 是报告保护,不承担恢复可见内容的时序保证。
关键修复位于内部 `src/mln/annotation/annotation_manager.cpp/.hpp`:原 updateStyle 只在 Source 不存在时创建 points,Source 保留而层被删除会让后续 Marker 无绘制层。提取私有 ensurePointLayer,独立检查 Source 和层;首次添加 SymbolAnnotation、更新已有 SymbolAnnotation、Style loaded 三个入口修复缺失层。更新没有 geometry/icon 变化时也把 dirty 置真。已有同名 Layer 不被覆盖。
时序:Map::addAnnotation / updateAnnotation → AnnotationManager 修复 Style layer vector → Map::Impl::onUpdate 捕获新的 immutable layers → Fast NonCameraSignature/annotationMutation 拒绝旧树 → Full 执行正常 Annotation 渲染。恢复不依赖3秒poll,也没有在 renderer thread 的 updateData 内重写 Style。Shape Annotation 原接口/图层仍按原逻辑处理,碰撞、Fade、Glyph/Image 和 C 判断完全保留。
风险:这是 Shared Core 内部生命周期修复,所有后端共用;需 RDC 编译并跑真实图像用例,确认无锁/重入问题及旧 Annotation 行为回归。用户主动提供同名层时尊重其语义;若其配置本身无法绘制,该情况不被当作 Test App 空层安全条件。恢复失败在日志保留,不写成功。
## 4. Symbol R:首次 Build 仍 BLOCKED
已读 PlacementController、Placement::placeLayers/commit/symbolFadeChange、RenderTreeImpl::prepare、SymbolBucket::updateVertices、renderer Full 准入和 scene 聚合。
| Continuous Full 分支 | 当前 Symbol R gate |
|---|---|
| placement 不 recent | placementChanged=true;placeLayers 后 commit、setPlacement,changed 本身阻断 |
| placement recent | setPlacementStale;hasTransitions 返回 true,阻断 |
| transitions 关闭 | placementIsRecent=false,Full changed=true;symbolFadeChange 返回1,不是 settled=0 |
RenderTreeImpl::prepare 在 bucket updateVertices 中更新 opacity/dynamic attributes,并置 uploaded/dynamicUploaded/placementChangesUploaded 等状态。Placement commit 只提交 CPU placement/opacity 结果,不证明当前 R 的最终 GPU 输入一致。per-R `renderSegmentPlacementGatePassed` 和 `retainedSegmentIsStable`,全局 retainedPlacementStable / retainedSupported / preparedSceneSupported 均保留。隐藏/缺源/当前 placementData 为空的 Symbol 仍结构上具备 Placement 能力。
**需要的额外设计证据**:成功 Full 对应的 GPU 上传/绘制完成代次、R 使用的 bucket/tiles/跨瓦片ID与排序、跨Source碰撞与所有参与碰撞层的 Placement结果、text/icon opacity和dynamic vertices、atlas/glyph/image代次、Style/Source/layer identities与revision、camera/projection/viewport/pixelRatio、uniform fade及debug/3D条件、待处理requests/异步变更纪元。证书必须绑定一次成功 Cache Build,变化即 invalid/Full,并对 GL/Metal 验证等价及 shadow。现有代码没有完整证书,本轮不做跨层重写,不用毫秒阈值、loaded、无手势或counter装配代替。
## 5. 测试源码与结论边界
新增四个 `Step116Safety.*` C++ 用例:缺源/Source加入未loaded/异步revision/删除墓碑和恢复;JSON缺源审计与Placement并存、查询无副作用;Symbol两个Continuous分支及关闭transition保护、无变化/Source与全局资源revision;Annotation/层序/disable/reload多失败 shadow 全集。revision用例验证的是账本契约,不伪造实际 Glyph/Tile 回调或 GPU完成。
新增三个 `Annotations.Step116*` 用例:空points移除后真实添加在render前恢复并比对既有point_annotation图像;已有Marker no-op update恢复且出图;已有同名层不覆盖、reload恢复且出图。这些是测试源码,全部 NOT RUN;设备的annotation/Style、async mutation、GL/Metal回退还须独立验收。
本轮实现后预期消除原 STATIC_RC 的空内部 C Symbol;无法承诺 #23 清除,也无法承诺 R Build/Fast>0。旧快照、AST或diff检查均不构成新制品安全、像素或性能 PASS。