Files
MapLibreParticleLab/docs/20_调查/STEP-114_FastPath安全准入与闭环判定_v1.md
tei 21a1081643
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
feat: prepare STEP-114 guarded fast smoke validation
2026-10-11 10:01:10 +09:00

79 lines
10 KiB
Markdown
Raw Permalink 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-114 Fast Path 安全准入与闭环判定 v1
日期:2026-10-11(JST)。结论:**PARTIAL;安全子集源码与独立最小场景已交付,真实 Fast 尚未验收。**
## 1. 基线、证据等级与阅读
Mac / Darwin 24.6.0 / x86_64,`/Users/tei/dev/MapLibreParticleLab`,`particle/main@b02e54de3d45fcf612126ae8f037cba204f590ea`。源码版本 `13.6.1-particle.23`,没有发行或改 Source Lock。实际模型 GPT-6.1-Sol / high 已从当前本地 rollout 的 `turn_context` 核实。
已读根 AGENTS、PARTICLE_BASELINE、项目规范全部八份、项目总则 README 与四份有效总则、本任务、STEP-112 调查/完成报告、STEP-113 完成报告/Step(含两轮 RDC 追加)、实际 Shared Core 和 Test App 源码。Integration 只读 AGENTS、README、WORKFLOW、TEAM_MODEL、C-001/C-002、Contract 版本规则、RFC-001/002/004、ADR-001、COORD-005 决议;不写跨项目文件,不改 RN/JS API/ABI。
SOURCE-PROVEN 表示本轮源码控制流;RETAINED-EVIDENCE 表示本机保留的旧 RDC JSON;IMPLEMENTED 表示已改源码;NOT RUN 表示未编译/运行。旧设备证据不是本轮改动的设备验收。
## 2. R 的真实 SourceType 与初建失败点
不能从 `unknown-dependency` 推断 source 一定是 CustomMVTVector:它还覆盖未知依赖、缺 revision 登记等情况。
本轮只读 `artifacts/maplibre-particle/android-validation/step113/source-change-after-full.json`:Native source 表为 mapple/raster、navsea_delivery/vector、org.maplibre.annotations/annotations、rn-weather-fields/raster-array、step113-source-probe/geojson。R0 `[0,63)` 的依赖为 mapple、navsea_delivery、**tide**;第2层 `tide-spots` 是 `symbol`、sourceId=`tide`,source 表却没有 tide。R0 的 sourceRevision=0、sourceReady=false、Build=0、fallback=unknown-dependency。
源码 `style/conversion/source.cpp::convertVectorSource` 创建 `VectorSource`;其构造函数指定 `SourceType::Vector`;`RenderSource::create` 创建 `RenderVectorSource`。因此该 Test App 的正式 PBF source **不是 CustomMVTVector**。任务书列出的 CustomMVTVector 限制是独立安全约束,本轮完整保留。没有改旧报告,也没有补造 tide 数据、删原正式 PBF 层或修改服务 Style。
`retainedSegmentSourceState` 原先先读取 revisionFor,缺少 tide 的登记会返回 nullopt,从而提前返回默认 unknown-dependency。现在在读取 revision 前发现缺失 RenderSource 时明确返回 `missing-source`;本例的ready/stable=false、revision=0 不变。有旧tombstone记录的缺源也提前返回revision=0,而不暴露旧登记hash;它仍不得Build/Reuse,RevisionBook登记机制不变。这是诊断修正,**不改变缓存准入**。source 存在但无 revision、CustomMVTVector、未知 layer dependency 仍 fail-closed。
后续即使 Host 合法补齐 tide,R 仍包含大量 Symbol,Placement 首建阻塞不会自动消失。缺源与 Placement 是不同失败点。
## 3. 已支持的本地 GeoJSON/circle 子集
FAST_SMOKE 选择本地 GeoJSON 非空点与 circle R,不新增 source 类型授权。其现有追踪链:
| 输入或事件 | 源码链与保护 |
|---|---|
| GeoJSON setGeoJSON | `GeoJSONSource::setGeoJSONData` 替换 immutable Impl 并通知 SourceChanged;Fast non-camera signature 比较 sources;Full `diffSources` 推进全局 content 和本 source revision |
| Source 增删/同ID重建 | `createRenderTree` 的 sourceDiff added/removed/changed 都 advanceSource;RevisionBook 保留 tombstone;PreparedTree 在 Full 更新对象前释放 |
| 异步 GeoJSON 数据/布局 | `RenderGeoJSONSource::update` → GeoJSONTile::updateData;capturedData 和 weakPtr 防陈旧/销毁回调;GeometryTile correlationID 保护 pending;`onLayout` 每次更换 layoutResult 都 onTileChanged;RenderSource → orchestrator 推进 source-local revision 和全局 content,再 invalidate |
| Tile 未就绪/淡入 | `isLoaded`、hasFadingTiles、source assessment、#17 与 R 稳定性检查继续保留 |
| Layer paint/layout/顺序 | immutable layers signature、per-R content fingerprint、resolved plan/topology;有 transition/repaint 仍阻止 |
| Camera/viewport/pixelRatio | #6/#7/#8、RetainedUnderlayKey 与 revision state;旧 texture 不能按新矩阵复用 |
| Style reload | styleLoaded/signature、配置/层序/Source 新身份、PreparedTree 生命周期保护;trace 在实际看到 loaded→false 时重置 |
| Image/Sprite | imageDiff、spriteLoaded、imageManager readiness、missing/unused image callbacks 推进全局 revision;#8 先捕获新 images 输入 |
| Glyph/fontFaces/URL | non-camera signature、glyph URL/font identity 追踪、onGlyphsLoaded 推进全局 revision;不删除资源门禁 |
| Annotation | #24 pending 检查、source/tile/图片变化与层表;实际 Symbol 继续纳入全场结构检查 |
| context/reset/destroy | markContextLost、Renderer.clearData 清 PreparedTree/trace,orchestrator 推进 revision;析构 detach observer 前排空 source/tile 工作;Test App 取消 callback、dispose runtime、删除自有 marker,MapView 原生命周期仍由 Activity 执行 |
这一闭环是现有实现的源码依据,**不是本轮已跑出的 Source mutation/GPU PASS**。异步过渡中 Full 也可能继续展示尚未更新的旧 bucket;要求 Fast 与同一时刻合法 Full 等价,而非承诺提交 API 后同步完成画面更新。成功布局后必须失效并正确重建;不可用两张稳定末态截图代替事件顺序证据。
R source policy、RevisionBook、GPU Build/Reuse 算法本轮零语义修改。新增 C++ 用例验证既有 revision/cache 状态机组合;unit 中显式推进 epoch/标记构建只用于状态机测试,不是实际 Native 帧或 GPU 成功的证据。
## 4. C、Annotation 与 Scene 聚合
`continuousRangeSupportsParticleFastPath` 要求每个 C layer 都 startsRetainedDynamicRange,并至少有粒子动画层。WeatherColor 与 RasterParticle 符合;普通 circle、Symbol、内建 Annotation Symbol 不符合。`particlePreparedSceneSupported = retainedSupported && fastContinuousSupported`,并要求单一 C。#22/#23 可以共享 C 不支持根因。
本轮没有修改 #22/#23、C GPU 复合流程、层序或 AnnotationManager。不能证明非粒子 C 与既有 Fast prepare/postRender 等价,故不放行。
独立 FAST_SMOKE 在确认 `map.annotations.isEmpty()` 后,仅从本场景 Style 删除自动生成且空的 `org.maplibre.annotations.points` layer,保留内建 source;若缺层或 remove 失败则 BLOCKED。Native annotation 更新规则未变,正式 PBF 五场景不删除该层。baseline 层序应为 background、R circle、weather-color、raster-particle,实际 JSON 仍需 RDC 核对。
ANNOTATION_BLOCKED 重新加载一个正常 Style,保留自动内建层并用现有 `map.addMarker` 加真实 marker;可单次修改其 position。内建 Symbol 位于 C,#22/#23 必须继续阻止 Fast。从该场景切回 baseline 时只删除本场景拥有的 marker,不能清除其他 Annotation。若存在其他 Annotation,baseline 拒绝启动。该场景转换含合法 Style reload,不是生产 Annotation 零重载支持的证明。
## 5. Placement:安全局部修复与 BLOCKED
正常 Continuous Full:placementIsRecent=false 则 placeLayers/commit,placementChanged=true;recent=true 则 setPlacementStale,controller.hasTransitions=true;关闭 transitions 时正常 Full changed=true、fade=1。含结构性 Symbol 的 R 无可证明的首次 Build 稳定窗口。
本轮保持 Symbol R 的三项 gate、scene placementStable、全图碰撞、fade/transition 和跨 source 规则。完整 GPU symbol 输入、bucket/atlas/opacity/duplicate/anchor 的结果证书仍不存在;建立它需要独立结果签名或更大生命周期设计。**Symbol R 准入修复 BLOCKED,不能删除 changed/stale/fade 条件。**
唯一行为修复限定于**完整非空层表没有任何结构性 Symbol**:此时 controller 的 stale/transition 没有 Symbol 像素消费者,单独阻止 #13 不代表画面可能变化。`particleFastPathHasPlacementTransition` 按完整 Style 表检查;隐藏/空数据的 Symbol 与 Annotation Symbol 一律保守保护。production 还核对层表数量与 renderLayers 数量,不一致保持原 transition;空表也保守保留。
这是 Shared Core 内部实现优化,无 Android/iOS 分叉,不新增控制 API、不禁止正常 Full Placement、不修改原始 controller。其余23项 Gate、source/cache/scene 条件全部继续生效。新增 Symbol 尚未进入旧表时,immutable layers 的 non-camera signature 不相等,且 Annotation pending 单独阻止 Fast;Full 更新后表重新包含 Symbol。未取得新层表前不得只凭这个 helper 放行。
反例边界:同场只要存在一个隐藏 Symbol、空 Symbol、C Annotation Symbol,仍使用原 controller transition;缺层表、source mutation、未完成 tile layout、image/glyph 更新、camera/viewport、style reload、debug/context 问题都不能被本修复抵消。未来若引入新的 Placement-capable layer 类型,应先扩展结构检测及测试;当前源码仅 Symbol 的 LayerTypeInfo 使用 CrossTileIndex::Required。
## 6. 实施结果、验证方案和限制
- IMPLEMENTED:缺源明确诊断、无 Symbol 场景的 #13 限定检查;3个非 Jest C++ 用例源码;独立4场景及 UI/Intent、真实 Native 快照与操作前后自动采样;中文文档和追加记录。
- 保留 fail-closed:CustomMVTVector、未知 revision、缺源;非粒子 C;所有 Symbol R Build/Placement 保护。
- NOT RUN:Native/Kotlin 编译、C++ 测试、Android build/设备/GPU/Fast 命中、像素对照、性能、iOS Metal 设备验证。
- 保留:正式 STEP-113 五个 PBF 场景实现原样、STEP-102 fixture 原样、STEP-110/111 未跟踪文件原样。新增菜单明确标识独立 smoke,不冒充63/113层等价。
验收步骤和命令见 `docs/60_测试/STEP-114_独立FastSmoke场景与RDC验收_v1.md`;Native 定向命令也直接写在本轮完成报告。baseline 必须取得真实 Native Full>0、Fast 增长、CacheBuild>0、Reuse 增长、completed fast-rendered、24 PASS/knownMask 完整/decisionMismatch=0;否则维持 PARTIAL,不能标 Fast Path 已修复。
Source/Image/Camera/缓存禁用/Reload 的反向证据需保存事件前/提交后/100/500/1500ms 快照,必要时以更早的精确帧复核;未捕获瞬间 gate 不能用计数猜测。后台/恢复/Teardown、Symbol/Annotation 与原 PBF 回归、双平台共享源码独立检查仍为 RDC/用户待执行项。