09: 运行时资产 manifest 与版本策略规格
Type: spec
Status: ready-for-agent
Label: ready-for-agent
Blocked by: 04
Category: spec
本规格固化运行时资产 manifest 与版本策略的讨论结论,作为同一张蓝湖正式素材替换地图的子规格单。100% 仅表示规格交付,不表示 manifest、资源解析器或正式素材已经实现。
Problem Statement
蓝湖正式素材需要进入城市生命线 Web 驾驶舱,但当前资源替换如果直接由各组件引用物理文件路径,会导致资源来源不可追溯、文件改名引发业务代码修改、缓存新旧混用、qiankun 基址不一致,以及单个资源失败时缺少稳定的语义降级和诊断。
运行时资源还必须区分原始设计归档、正式资源、临时资源、推导资源和降级资源,避免把临时占位误报为正式设计交付。
Solution
建立统一的运行时资产解析层,以 manifest 作为资源唯一权威入口。组件、地图服务和设备资产选择层只消费稳定语义 key,不直接引用蓝湖导出文件路径。
原始蓝湖设计包独立归档;运行时资源、manifest、来源和校验元数据进入驾驶舱自有资源边界。运行时资源通过 BASE_URL/宿主注入路径解析,兼容真实 /cockpit 与 qiankun 宿主。
发布使用人工版本号与资源内容 hash;生产物理文件名带 hash。manifest 与资源原子发布,manifest 短缓存/协商缓存,hash 资源长期不可变缓存。核心资源组或整包校验失败时回滚到上一版或内置基线,普通非核心资源按显式 fallback key 降级。
User Stories
- 作为设计交付负责人,我想保留原始蓝湖设计包,以便后续追溯和重新导出。
- 作为开发者,我想通过稳定语义 key 获取资源,以便设计文件改名不会牵动业务代码。
- 作为开发者,我想让 manifest 成为唯一资源入口,以便避免组件散落物理路径。
- 作为部署人员,我想把运行时资源放在驾驶舱自有资源边界,以便不依赖 TvT 插件资源目录。
- 作为 qiankun 宿主维护者,我想让资源基址随宿主注入路径解析,以便嵌入环境不会出现资源 404。
- 作为发布人员,我想为每次发布记录人工版本号,以便沟通、审计和回滚。
- 作为发布人员,我想为每个资源记录内容 hash,以便确认内容是否真正变化。
- 作为用户,我想在更新后获得新资源,而不是被浏览器长期缓存旧文件。
- 作为发布人员,我想让 hash 文件名支持长期缓存,以便降低重复下载。
- 作为发布人员,我想让 manifest 与资源原子发布,以便页面不会读取到互相不匹配的版本。
- 作为系统,我想校验 manifest schema,以便拒绝结构不合法的资源清单。
- 作为系统,我想校验语义 key 唯一性,以便同一语义不会出现不确定解析结果。
- 作为系统,我想校验路径安全性,以便资源不能越出受控资源目录。
- 作为系统,我想校验 hash 格式和资源完整性,以便检测部署过程中的替换或损坏。
- 作为系统,我想校验 fallback 引用存在,以便失败时不会进入断链回退。
- 作为系统,我想限制远程资源域名,以便未登记的外部 URL 不被加载。
- 作为用户,我想在非核心资源失败时仍能使用驾驶舱,以便单个装饰资源不会阻塞业务查看。
- 作为值班人员,我想看到资源失败后的语义降级结果,以便知道当前视觉是否是正式资源。
- 作为开发者,我想在 fallback 自身失败时继续使用内置通用资源,以便资源故障不会造成空白 UI。
- 作为值班人员,我想让品牌、点位状态、设备状态和事件等级保持各自语义,以便错误资源不会混淆业务含义。
- 作为部署人员,我想在核心资源组不可用时回滚上一版或内置基线,以便驾驶舱保持可用。
- 作为开发者,我想在开发环境查看完整路径、版本、hash 和错误,以便快速排查资源问题。
- 作为生产用户,我想只看到可理解的失败类别和回退状态,以便诊断信息不会泄露内部路径。
- 作为测试人员,我想观察宿主
data-* 资产状态,以便无需依赖内部实现验证外部行为。
- 作为实现者,我想复用图标、点位标记和设备资产现有接缝,以便减少跨模块改动。
- 作为实现者,我想让 manifest 解析层承载校验、回退和诊断,以便组件不重复实现资源策略。
Implementation Decisions
- 新增统一运行时资产解析层,负责 manifest 加载、schema 校验、版本和 hash 校验、路径安全、远程域名校验、语义 key 解析、fallback、核心资源回滚和诊断状态。
- 现有 UI 图标注册表、点位状态标记生成、设备资产计划和视觉 token 继续作为消费接缝;它们从解析层取得资源,不再各自拼接蓝湖物理路径。
- 运行时资源归入驾驶舱自有
public/cockpit 边界;路径通过应用基址解析,不硬编码绝对 /cockpit/...。
- manifest 条目必须包含稳定语义 key、运行时路径或受控远程 URL、蓝湖来源画板/交付标识、格式、尺寸、透明度或密度属性、人工发布版本、内容 hash、资产状态、适用对象/状态、核心标记和 fallback key。
> 成员定义出处(2026-10-08 交叉引用):本规格使用「核心资源组」与条目字段
核心标记,但不在此定义谁是核心。核心资源组的成员由字体授权与缺失资源降级规格补全(品牌标识、点位与设备的状态形状语义、状态色语义)。此处只加指针,不改本规格原有口径。
- 语义 key 不随文件改名变化;生产物理文件名允许并默认使用内容 hash。
- 原始设计包不作为生产运行时目录的一部分;仓库保存运行时资源、manifest、来源和校验信息。
- 生产默认拒绝远程资源。远程例外必须记录来源、允许域名、CORS/安全策略、缓存策略、超时、版本标识和 fallback;未登记远程 URL 拒绝加载。
- 环境只允许覆盖资源根路径和受控发布版本,不允许改变语义 key、状态语义和 fallback 关系。
- manifest 与资源作为原子发布包部署;manifest 使用短缓存或协商缓存,hash 资源使用长期不可变缓存。
- 构建期和运行时校验 schema、发布版本、条目完整性、语义 key 唯一性、路径安全性、hash 格式、fallback 引用和远程域名。
- manifest 或资源整包校验失败、核心资源组不可用、版本不兼容时回滚上一版或内置基线;普通非核心资源按条目 fallback。
- fallback 顺序为显式 fallback key、有限 fallback 链、内置通用资源;每一级失败都产生诊断记录。
- 诊断状态至少区分 manifest 不可用、条目缺失、路径不安全、版本/hash 不匹配、远程域名未登记、资源加载失败、fallback 生效和最终通用资源生效。
- 开发/测试暴露完整诊断;生产仅暴露语义 key、失败类别、回退状态和用户提示,不暴露内部路径或敏感配置。
- 以宿主
data-* 作为高层观察接缝,覆盖真实 /cockpit 和 qiankun 宿主的资源解析结果。
Testing Decisions
- 优先测试统一资产解析层的外部行为:给定 manifest、资源状态和环境基址,验证解析结果、回退结果、回滚结果和诊断结果;不测试内部函数调用顺序。
- 测试 manifest schema、语义 key 唯一、路径安全、hash/版本、fallback 引用和远程域名规则。
- 测试正常资源、非核心资源失败、fallback 失败、核心资源组失败、整包校验失败和上一版/内置基线回滚。
- 测试
BASE_URL、相对 publicPath 和 qiankun 注入路径下的 URL 解析。
- 测试开发/测试与生产诊断面的信息差异,确认生产不泄露内部路径。
- 测试图标、点位标记、设备位置符号和详情图片通过语义入口消费 manifest,而不是散落物理路径。
- 测试外部
data-* 观察结果,确认核心资源回滚、普通资源 fallback 和最终通用资源状态可被宿主观察。
- 复用仓库已有的纯领域逻辑测试、静态资源检查和真实浏览器走查先例;不新增第二套浏览器测试框架。
- 真实
/cockpit 与 qiankun 宿主走查覆盖资源 200、资源版本切换、普通资源失败、核心资源回滚、诊断读数和页面结构未变化。
Out of Scope
- 直接实现 manifest 解析器、资源下载器或资源文件替换。
- 修改四个一级模式、16 个二级面板、
mode、panelId、数据契约、地图图层、状态语义、拾取、定位、聚合或面板联动。
- 生产部署流程本身和 CDN/对象存储采购。
- 设备或城市真三维模型、地形、DEM、影像和 3D Tiles。
- 蓝湖画板具体视觉值、字体授权裁定、点位/设备状态图形矩阵;这些由其他规格票负责。
- 允许任意远程 URL 作为隐式回退。
Further Notes
- 本规格来源于已关闭的讨论票 04,具体发布策略见该票的独立决策记录。
- 该规格挂在
lanhu-cockpit-asset-replacement 地图下,前置依赖为讨论票 04。
ready-for-agent 只表示规格完整,可进入后续实现排期,不表示业务代码或正式素材已经交付。
- 当前项目规则要求修改代码后不得自动运行 build/dev;实现阶段需由用户明确要求后再执行验证命令。