feat: package provider delivery as NavSea zip
This commit is contained in:
@@ -2362,3 +2362,33 @@
|
||||
- CM95 通过用户指定 Style、Sprite 与三块真实 PBF 样本执行完成,复用权威人工 assignment;2,077 occurrence、102 个实际 Visual Object,Package 校验 `PASS_WITH_WARNINGS` 并导出。警告保留未映射项和样本限制。
|
||||
- NavSea 的当前本地 Style 可读,但 Sprite 与三块候选 PBF 对 `192.168.200.184:80` 均返回 connection refused;NavSea 端到端未完成,未伪造样本或 PASS。
|
||||
- 测试、Python 编译、CLI help 与 `git diff --check` 结果记录在本任务完成报告。
|
||||
|
||||
|
||||
## 2026-10-06 PBF Provider Pipeline v1 双 Provider 最终实跑补充
|
||||
|
||||
- 前一条记录中的 NavSea 阻塞原因已确认:旧 `192.168.200.184:80` LAN 资源端点当前未监听;不是 Pipeline 逻辑或 Codex sandbox 独有问题。
|
||||
- 保留 X220 当前本地 `style.navsea-delivery-full-semantic-extentfix.json` 作为 NavSea Style 分析输入,不用公开 Style 替换它;仅在 `providers/navsea/manifest.json` 显式覆盖 PBF / Sprite / Glyph 为当前可用的 `https://pbf.jpcn.ccwu.cc/` 同数据集资源入口。
|
||||
- NavSea 已 fresh 重跑成功:
|
||||
- 三个 z12 样本 `12/3531/1641`、`12/3526/1643`、`12/3638/1613` 全部下载成功;
|
||||
- 8,484 occurrence、85 个 distinct Actual Visual Object;
|
||||
- Mapping:VISUAL_OBJECT_MATCH 27、LAYER_ONLY 7、AMBIGUOUS 11、UNKNOWN 40;
|
||||
- PBF-01~PBF-05 PASS,PBF-06 `PASS_WITH_WARNINGS`,PBF-07 `EXPORTED`。
|
||||
- CM95 已清理临时产物后 fresh 重跑成功:
|
||||
- 三个指定 z12 样本全部成功;
|
||||
- 2,077 occurrence、102 个 distinct Actual Visual Object;
|
||||
- Mapping:VISUAL_OBJECT_MATCH 9、LAYER_ONLY 47、AMBIGUOUS 2、UNKNOWN 44;
|
||||
- PBF-01~PBF-05 PASS,PBF-06 `PASS_WITH_WARNINGS`,PBF-07 `EXPORTED`。
|
||||
- 两套 warnings 都来自 `mapping:unresolved_present` 与 `limitations:present`;未将 UNKNOWN/AMBIGUOUS 静默映射为标准 Layer。
|
||||
- 最终双 Provider 端到端结果记录在 `docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v2.md`。
|
||||
|
||||
## 2026-10-06 PBF-08 NavSea Delivery ZIP
|
||||
|
||||
- 在 PBF-07 Provider Package Export 后新增 PBF-08。
|
||||
- PBF-08 自动生成单文件 `.navsea-provider.zip`,用户交付给 NavSea 时只需要复制该 ZIP,不再手工挑选多个文件。
|
||||
- ZIP 使用严格 9 文件白名单:provider-package.json、provider-policy.json、mapping-layer-assignment.json、resources-style.json、resources-sprite.json、resources-sprite.png、validation.json、validation.md、MANIFEST.json。
|
||||
- 任一必需文件缺失时禁止生成 ZIP;ZIP 完成后自动核对精确文件列表、CRC 和 SHA-256,并写入 pipeline-report.json。
|
||||
- NavSea 实跑生成 `navsea-delivery-full-semantic-extentfix-1.0.0.navsea-provider.zip`,SHA-256 `54aff8d8b882211ced6e77b3a93e8e793c780b44a1faa982ed8fc64693124fd5`,PBF-08 PACKAGED。
|
||||
- CM95 实跑生成 `cm95-s52-full-1.0.0.navsea-provider.zip`,SHA-256 `603cc004833bcff5571a32843d8ceedc7858b2fc4b28c41056db6807c7d511ee`,PBF-08 PACKAGED。
|
||||
- 两个 ZIP 均经外部 `unzip -t` 验证 9/9 文件 OK。
|
||||
- 自动测试从 6 项增加到 8 项,8/8 PASS;新增覆盖严格白名单与缺文件拒绝打包。
|
||||
- 详细结果:`docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v3.md`。
|
||||
|
||||
@@ -30,6 +30,8 @@ PBF-05 Provider Policy Compile
|
||||
PBF-06 Provider Package Validate
|
||||
↓
|
||||
PBF-07 NavSea Provider Package Export
|
||||
↓
|
||||
PBF-08 NavSea Delivery ZIP
|
||||
```
|
||||
|
||||
Pipeline 正式终点是 `NavSea Provider Package`,不是 `ProviderExecutionPlan`。
|
||||
@@ -370,7 +372,46 @@ MANIFEST 至少包含:
|
||||
|
||||
只有 PASS 或明确允许发布的 PASS_WITH_WARNINGS 才能正式 export。
|
||||
|
||||
## 10. NavSea Provider Package Contract
|
||||
## 10. PBF-08 NavSea Delivery ZIP
|
||||
|
||||
目标:把 PBF-07 已验证的最终 NavSea 正式输入打成一个单文件 ZIP,避免人工复制时漏文件、错版本或混入生产中间产物。
|
||||
|
||||
PBF-08 不改变 Provider Package Contract,只增加交付封装。ZIP 使用严格白名单,只允许包含:
|
||||
|
||||
```text
|
||||
provider-package.json
|
||||
provider-policy.json
|
||||
mapping-layer-assignment.json
|
||||
resources-style.json
|
||||
resources-sprite.json
|
||||
resources-sprite.png
|
||||
validation.json
|
||||
validation.md
|
||||
MANIFEST.json
|
||||
```
|
||||
|
||||
默认输出:
|
||||
|
||||
```text
|
||||
dist/<provider-id>/<dataset-id>/
|
||||
<provider-id>-<dataset-id>-<version>.navsea-provider.zip
|
||||
```
|
||||
|
||||
ZIP 内部使用同名顶层目录,避免多个 Provider 包解压后文件互相覆盖。
|
||||
|
||||
Gate:
|
||||
|
||||
- PBF-07 必须已经成功导出;
|
||||
- validation 必须为 PASS 或 PASS_WITH_WARNINGS;
|
||||
- 白名单中的 9 个文件必须全部存在;
|
||||
- ZIP 生成后必须重新读取并核对精确文件列表;
|
||||
- ZIP 必须通过 CRC 校验;
|
||||
- Pipeline 必须计算 ZIP SHA-256 并写入 pipeline-report.json;
|
||||
- 任何临时 PBF、`.tmp`、工具源码、测试、人工审核中间文件或未声明文件不得进入 ZIP。
|
||||
|
||||
因此用户实际交付给 NavSea 时,只需要复制这一份 `.navsea-provider.zip`。
|
||||
|
||||
## 11. NavSea Provider Package Contract
|
||||
|
||||
公开 Contract 至少覆盖:
|
||||
|
||||
@@ -396,7 +437,7 @@ MANIFEST 至少包含:
|
||||
|
||||
公开 Contract 不要求第三方使用官方 PBF 工具。
|
||||
|
||||
## 11. NavSea 接收侧
|
||||
## 12. NavSea 接收侧
|
||||
|
||||
```text
|
||||
NavSea Provider Package
|
||||
@@ -418,7 +459,7 @@ NavSea Runtime
|
||||
|
||||
NavSea 不再负责 CM95/S-52 语义研究、Visual Object 人工分类、Provider-specific 图标研究或 Provider Policy 推理生成。
|
||||
|
||||
## 12. 当前工具迁移关系
|
||||
## 13. 当前工具迁移关系
|
||||
|
||||
`tools/style-visual-object/style_vo_tool.py` → PBF-02。
|
||||
|
||||
@@ -432,7 +473,7 @@ NavSea 不再负责 CM95/S-52 语义研究、Visual Object 人工分类、Provid
|
||||
|
||||
`validate_cm95_classification.py` 暂保留为 CM95 基线校验;后续增加 Provider-neutral validator。
|
||||
|
||||
## 13. 实施顺序
|
||||
## 14. 实施顺序
|
||||
|
||||
第一优先级:冻结 Provider Policy Schema v1 和 Provider Package Schema v1。
|
||||
|
||||
@@ -442,7 +483,7 @@ NavSea 不再负责 CM95/S-52 语义研究、Visual Object 人工分类、Provid
|
||||
|
||||
第四优先级:调整 NavSea `help/chart-profile-tools/`,收敛为读取公开 Provider Package → Validate → Profile → ProviderCompiler。
|
||||
|
||||
## 14. 核心原则
|
||||
## 15. 核心原则
|
||||
|
||||
```text
|
||||
PBF = 数据生产者
|
||||
|
||||
276
docs/任务/PBF_Provider_Pipeline_v1_实现任务.md
Normal file
276
docs/任务/PBF_Provider_Pipeline_v1_实现任务.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# PBF Provider Pipeline v1 实现任务
|
||||
|
||||
日期:2026-10-06
|
||||
|
||||
## 0. 任务目标
|
||||
|
||||
在当前独立 worktree `/root/sourceserver/pbf-provider-pipeline-v1` 中,把 `docs/PBF_Pipeline_正式流程_v1.md` 定义的 PBF-01 ~ PBF-07 落成可运行、Provider-neutral 的正式 Pipeline,并实际用 NavSea 与 CM95 两套 Style/资源跑通。
|
||||
|
||||
最终终点必须是:
|
||||
|
||||
```text
|
||||
NavSea Provider Package
|
||||
```
|
||||
|
||||
不得生成 NavSea Runtime 的 `ProviderExecutionPlan`。
|
||||
|
||||
## 1. 开工前必须读取
|
||||
|
||||
先完整阅读:
|
||||
|
||||
- `AGENTS.md`
|
||||
- `docs/PBF_Pipeline_正式流程_v1.md`
|
||||
- `STEP_RECORD.md`
|
||||
- `tools/style-visual-object/README.md`
|
||||
- `tools/style-visual-object/style_vo_tool.py`
|
||||
- `tools/style-visual-object/output/navsea-standard/standard-catalog.json`
|
||||
- `tools/style-visual-object/output/cm95-manual-review/assignment/cm95-layer-assignment-v1.json`
|
||||
- `tools/style-visual-object/output/cm95-manual-review/validation-report-v1.json`
|
||||
- `tools/visual-object-instantiation/README.md`
|
||||
- `tools/visual-object-instantiation/instantiate_pbf_visual_objects.py`
|
||||
- `tools/visual-object-matcher/README.md`
|
||||
- `tools/visual-object-matcher/visual_matcher_experimental.py`
|
||||
|
||||
先按真实文件结构和字段工作,不凭记忆臆造。
|
||||
|
||||
## 2. 必做项
|
||||
|
||||
- [ ] PBF-01:实现 Provider Source Intake,支持本地路径和 HTTP(S) Style;记录 provider/dataset identity、资源、hash/fingerprint、source snapshot。
|
||||
- [ ] PBF-02:复用现有 Style Visual Object Tool;必要时补薄包装,但不得破坏已冻结 NavSea Standard Catalog。
|
||||
- [ ] PBF-03:把 `visual-object-instantiation` 正规化并 Provider-neutral 化。删除主逻辑中的 CM95 硬编码,包括固定 `source: cm95`、固定 catalog_name 等;Provider 信息必须来自参数/manifest。支持对选定 XYZ sample tiles 下载到工作目录后实例化。不得按屏幕位置拼接对象。
|
||||
- [ ] PBF-04:提供统一 Mapping ingestion/normalization。CM95 读取现有人工 assignment;NavSea 从 frozen Standard Catalog 的真实结构生成自身 Provider mapping。自动 matcher 只能作为建议,不能覆盖人工结果。
|
||||
- [ ] PBF-05:新增 `tools/provider-policy-compiler/`,定义并实现统一 Provider Policy Schema v1、编译器、validator。NavSea 与 CM95 必须使用完全相同 Schema;主逻辑禁止 `provider == cm95` 等分支。
|
||||
- [ ] PBF-06:实现 Provider Package Schema v1 与 Validator,结果严格为 PASS / PASS_WITH_WARNINGS / FAIL;FAIL 禁止 export。
|
||||
- [ ] PBF-07:实现正式 Provider Package Export,并生成 MANIFEST / fingerprints / validation report。
|
||||
- [ ] 新增一个 Provider-neutral 端到端 CLI/orchestrator,单条命令可从 manifest 执行 Pipeline。应能选择阶段或复用已存在的审核/assignment 输入,但最终输出结构一致。
|
||||
- [ ] 把两个当前未跟踪的 `tools/visual-object-instantiation/`、`tools/visual-object-matcher/` 中本任务需要的源码正规纳入版本控制;不要提交 `__pycache__`。
|
||||
- [ ] 增加最小但足够的自动测试,覆盖 schema、fingerprint 稳定性、Provider-neutral 行为、FAIL 阻止 export、NavSea/CM95 两套 contract 同构。
|
||||
- [ ] 文档全部中文;工具字段名/Schema key 可用英文。
|
||||
- [ ] 更新 `STEP_RECORD.md`,但只追加本任务进度,禁止重写历史。
|
||||
- [ ] 生成中文完成报告到 `docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v1.md`。
|
||||
|
||||
## 3. 公开 Contract 的最低字段
|
||||
|
||||
Provider Package/Policy 至少覆盖:
|
||||
|
||||
- provider identity
|
||||
- dataset identity
|
||||
- package/version identity
|
||||
- Style resource
|
||||
- PBF resource
|
||||
- Sprite
|
||||
- Glyph
|
||||
- NavSea Standard Layer mapping
|
||||
- Provider Policy
|
||||
- Display
|
||||
- Pickup
|
||||
- Planning
|
||||
- Danger
|
||||
- capabilities
|
||||
- validation requirements
|
||||
- hash / version / fingerprint
|
||||
- unresolved
|
||||
- limitations
|
||||
- provenance
|
||||
|
||||
第三方不需要使用本仓库工具,只要满足公开 Contract 即可。
|
||||
|
||||
## 4. Provider-neutral 硬要求
|
||||
|
||||
正式 Pipeline 主逻辑不得:
|
||||
|
||||
- 根据 providerId 写 `if cm95` / `if navsea`
|
||||
- 根据 source-layer 名称直接决定 NavSea Standard Layer
|
||||
- 根据 Provider 字段名直接决定 NavSea Standard Layer
|
||||
- 根据单个 icon 名称硬推完整对象语义
|
||||
- 静默把 AMBIGUOUS/UNKNOWN 变成某个 Layer
|
||||
|
||||
Provider-specific 差异必须进入:
|
||||
|
||||
- manifest
|
||||
- declarative mapping/policy
|
||||
- provenance
|
||||
- 已确认人工 assignment
|
||||
|
||||
## 5. 实际运行输入
|
||||
|
||||
### NavSea
|
||||
|
||||
Style 优先使用 X220 当前真实本地文件:
|
||||
|
||||
```text
|
||||
/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full-semantic-extentfix.json
|
||||
```
|
||||
|
||||
该文件是实际当前 Style 输入,只用于运行测试,不要把原主工作区文件纳入本 worktree Git。
|
||||
|
||||
其 Style 当前包含:
|
||||
|
||||
- vector source `navsea_delivery`
|
||||
- tile template `http://192.168.200.184/pbf-delivery-full-20260418-rebuild/{z}/{x}/{y}.pbf`
|
||||
- sprite `http://192.168.200.184/newpec/sprite-semantic/sprite`
|
||||
- glyphs `http://192.168.200.184/newpec/fonts/{fontstack}/{range}.pbf`
|
||||
|
||||
冻结 Standard Catalog:
|
||||
|
||||
```text
|
||||
tools/style-visual-object/output/navsea-standard/standard-catalog.json
|
||||
```
|
||||
|
||||
### CM95
|
||||
|
||||
Style:
|
||||
|
||||
```text
|
||||
http://192.168.200.184:18889/s52/full-style.json
|
||||
```
|
||||
|
||||
PBF:
|
||||
|
||||
```text
|
||||
http://192.168.200.184:18889/pbf/{z}/{x}/{y}.pbf
|
||||
```
|
||||
|
||||
Sprite:
|
||||
|
||||
```text
|
||||
http://192.168.200.184:18889/s52/sprite
|
||||
```
|
||||
|
||||
建议 sample tiles:
|
||||
|
||||
```text
|
||||
12/3531/1641
|
||||
12/3526/1643
|
||||
12/3638/1613
|
||||
```
|
||||
|
||||
CM95 人工权威 assignment:
|
||||
|
||||
```text
|
||||
tools/style-visual-object/output/cm95-manual-review/assignment/cm95-layer-assignment-v1.json
|
||||
```
|
||||
|
||||
## 6. NavSea sample tile
|
||||
|
||||
从 NavSea Style 的真实 vector source 自动获取 tile template。若 manifest 未指定 sample tile,CLI 应允许显式传 sample tiles。
|
||||
|
||||
为了本任务实际跑通,先通过 HEAD/GET 或目录可用性选择 1~3 个能成功下载的 NavSea z12 sample tile;不得伪造成功。如果某候选 404,继续选择真实存在的 tile,并在报告记录最终使用的 tile。
|
||||
|
||||
## 7. 依赖与运行
|
||||
|
||||
当前复制进 worktree 的旧 instantiation 脚本依赖 `mapbox_vector_tile` 和 Pillow;当前系统 Python 已观察到 `mapbox_vector_tile` 可能未安装。
|
||||
|
||||
要求:
|
||||
|
||||
- 明确声明 Python 依赖,例如独立 requirements 文件。
|
||||
- 优先创建/使用 worktree 内 `.venv`,不要污染系统 Python。
|
||||
- 依赖安装失败时明确报告,不得伪造运行成功。
|
||||
- 输出/缓存目录应通过 .gitignore 避免把大体积临时 PBF/Sprite/cache 提交进 Git。
|
||||
- 正式示例/小型 JSON 报告可提交;大 PBF、PNG cache 不提交。
|
||||
|
||||
## 8. 两套实际端到端验收
|
||||
|
||||
实现完成后必须实际运行:
|
||||
|
||||
### A. NavSea
|
||||
|
||||
目标:
|
||||
|
||||
```text
|
||||
NavSea style + real PBF sample + frozen Standard Catalog
|
||||
→ Provider Policy
|
||||
→ validated NavSea Provider Package
|
||||
```
|
||||
|
||||
必须至少证明:
|
||||
|
||||
- Style intake 成功
|
||||
- Sprite 获取/快照成功
|
||||
- 至少一个真实 vector PBF sample 成功
|
||||
- PBF-03 实例化成功
|
||||
- NavSea mapping 成功
|
||||
- Policy Schema validate 成功
|
||||
- Package Schema validate 成功
|
||||
- Export 成功
|
||||
- validation result 非 FAIL
|
||||
|
||||
### B. CM95
|
||||
|
||||
目标:
|
||||
|
||||
```text
|
||||
CM95 full-style + real PBF sample + existing manual assignment
|
||||
→ Provider Policy
|
||||
→ validated CM95 Provider Package
|
||||
```
|
||||
|
||||
必须至少证明:
|
||||
|
||||
- Style intake 成功
|
||||
- Sprite 获取/快照成功
|
||||
- 三个指定 sample tiles 尽可能全部成功;若单个不可用,明确记录
|
||||
- PBF-03 实例化成功
|
||||
- 使用现有人工 assignment,不能用 matcher 覆盖
|
||||
- Policy Schema validate 成功
|
||||
- Package Schema validate 成功
|
||||
- Export 成功
|
||||
- validation result 非 FAIL
|
||||
|
||||
## 9. 输出建议
|
||||
|
||||
建议正式输出:
|
||||
|
||||
```text
|
||||
tools/provider-pipeline/
|
||||
tools/provider-policy-compiler/
|
||||
providers/navsea/
|
||||
providers/cm95/
|
||||
contracts/
|
||||
dist/
|
||||
```
|
||||
|
||||
具体目录可根据仓库现状调整,但职责必须清晰。
|
||||
|
||||
最终至少保留可复现的 manifest/example 配置,让后续可再次执行两套 Provider。
|
||||
|
||||
## 10. Git 与工作区约束
|
||||
|
||||
当前 worktree 是隔离分支:
|
||||
|
||||
```text
|
||||
feature/provider-pipeline-v1
|
||||
```
|
||||
|
||||
不要访问或修改主工作区中的既存脏文件,除“读取 NavSea style 输入”外。
|
||||
|
||||
只提交本任务新增/修改文件。
|
||||
|
||||
完成前执行:
|
||||
|
||||
- 相关 Python tests
|
||||
- CLI help/基础 smoke
|
||||
- NavSea 实际 Pipeline
|
||||
- CM95 实际 Pipeline
|
||||
- `git diff --check`
|
||||
- `git status --short`
|
||||
|
||||
成功后在 feature branch 创建清晰 commit。不要自行 merge main;由外部流程审核后处理。
|
||||
|
||||
## 11. 完成报告
|
||||
|
||||
`docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v1.md` 必须逐项报告:
|
||||
|
||||
- 已完成 / 未完成 / 无法验证
|
||||
- 实际命令
|
||||
- NavSea 运行结果
|
||||
- CM95 运行结果
|
||||
- 每阶段产物
|
||||
- Schema/Contract 版本
|
||||
- validation result
|
||||
- warnings / unresolved / limitations
|
||||
- tests
|
||||
- Git commit
|
||||
- 最终实际使用的完整 Codex 模型配置(若运行环境可确认)
|
||||
|
||||
不得把“测试未跑”写成“通过”。
|
||||
265
docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v2.md
Normal file
265
docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v2.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# PBF Provider Pipeline v1 完成报告 v2
|
||||
|
||||
日期:2026-10-06
|
||||
分支:`feature/provider-pipeline-v1`
|
||||
状态:**PBF-01~PBF-07 已实现;NavSea 与 CM95 两套真实 Style/PBF/Sprite 端到端运行完成。**
|
||||
|
||||
## 1. 最终结论
|
||||
|
||||
PBF Provider Pipeline v1 已完成。正式边界保持为:
|
||||
|
||||
```text
|
||||
Provider Source
|
||||
→ PBF-01 Intake
|
||||
→ PBF-02 Style Visual Object
|
||||
→ PBF-03 Actual Visual Object
|
||||
→ PBF-04 NavSea Standard Mapping
|
||||
→ PBF-05 Provider Policy
|
||||
→ PBF-06 Provider Package Validate
|
||||
→ PBF-07 Provider Package Export
|
||||
```
|
||||
|
||||
Pipeline 的终点是 `NavSea Provider Package`,没有生成 `ProviderExecutionPlan`。
|
||||
|
||||
两套真实验收均完成:
|
||||
|
||||
- NavSea:`PASS_WITH_WARNINGS`
|
||||
- CM95:`PASS_WITH_WARNINGS`
|
||||
|
||||
两者 warnings 均为 `mapping:unresolved_present` 与 `limitations:present`。这表示仍有未知/歧义 Mapping,以及本轮只使用三个样本瓦片;不是 Pipeline 执行错误,也没有把 UNKNOWN/AMBIGUOUS 静默映射成某个 Layer。
|
||||
|
||||
## 2. 实现内容
|
||||
|
||||
已加入正式 Provider-neutral Pipeline runner、Provider Policy / Package v1 Schema 与 validator、NavSea/CM95 manifest、自动测试、依赖说明及中文 README。
|
||||
|
||||
现有 `tools/visual-object-instantiation/` 已正式纳入 Git,并移除主逻辑固定 CM95 provider/catalog 名称。PBF-03 额外输出 occurrence 级追溯,包括 tile、feature identity、属性证据、matched style layers、geometry 和 render components。
|
||||
|
||||
正式 Mapping 状态统一为:
|
||||
|
||||
- `VISUAL_OBJECT_MATCH`
|
||||
- `LAYER_ONLY`
|
||||
- `COMPONENT_ONLY`
|
||||
- `AMBIGUOUS`
|
||||
- `UNKNOWN`
|
||||
|
||||
`FAIL` 或其他非允许 validation 状态禁止 PBF-07 export。
|
||||
|
||||
## 3. NavSea 真实端到端结果
|
||||
|
||||
分析输入仍使用 X220 当前本地 Style:
|
||||
|
||||
```text
|
||||
/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full-semantic-extentfix.json
|
||||
```
|
||||
|
||||
Style SHA-256:
|
||||
|
||||
```text
|
||||
2ffde6af6043be2567a861a8d06d075a87b532091686bb5ac6ce889e45827e33
|
||||
```
|
||||
|
||||
原 Style 内旧 LAN `192.168.200.184:80` 的 PBF/Sprite 服务当前拒绝连接。为保持本地 Style 内容不变,同时完成真实资源验收,`providers/navsea/manifest.json` 将资源显式覆盖到同数据集当前可用的公开 HTTPS 入口:
|
||||
|
||||
```text
|
||||
PBF: https://pbf.jpcn.ccwu.cc/pbf/pbf-delivery-full-20260418-rebuild/{z}/{x}/{y}.pbf
|
||||
Sprite: https://pbf.jpcn.ccwu.cc/sprite/sprite
|
||||
Glyph: https://pbf.jpcn.ccwu.cc/fonts/{fontstack}/{range}.pbf
|
||||
```
|
||||
|
||||
因此本轮没有用公开 Style 替换本地 Style;Style 分析输入仍是上述 X220 本地文件,资源获取由 Provider manifest 显式声明。
|
||||
|
||||
NavSea Source fingerprint:
|
||||
|
||||
```text
|
||||
27a09da2a31746cff8e874fb5cd48bef7226c322fb2f193bc1b7fa5a01187f9c
|
||||
```
|
||||
|
||||
NavSea Sprite:
|
||||
|
||||
- JSON SHA-256:`e48aed662580ad437a5270966acdc906039b0d97da7892d518710d10f518f75c`
|
||||
- PNG SHA-256:`fca794509a41eda3f4a9fe6db5e39467aac7cdda07de553c97a33e31b4c7b981`
|
||||
|
||||
三个真实 z12 PBF 样本全部成功:
|
||||
|
||||
| XYZ | 字节数 | SHA-256 |
|
||||
|---|---:|---|
|
||||
| `12/3531/1641` | 181,263 | `99018718a886cd5af73554f9b453a476308a51e38591758ef2b1eaf723c6486a` |
|
||||
| `12/3526/1643` | 119,246 | `8f32aa41ab9af90122b45bda0bed9f02faed1c10e0eb3ab09109e88882704922` |
|
||||
| `12/3638/1613` | 305,970 | `25373c570684e5b06a6cdea56e8202541aab5c6aa4ec885b23c39bb9d807fd5c` |
|
||||
|
||||
PBF-03:
|
||||
|
||||
- decoded styled-layer feature:8,486
|
||||
- matched occurrence:8,484
|
||||
- occurrence 输出:8,484
|
||||
- distinct Actual Visual Object:85
|
||||
- group:34
|
||||
- unsupported component:0
|
||||
- missing sprite component:48
|
||||
|
||||
PBF-04 Mapping 共 85 个 Actual Visual Object:
|
||||
|
||||
- VISUAL_OBJECT_MATCH:27
|
||||
- LAYER_ONLY:7
|
||||
- AMBIGUOUS:11
|
||||
- UNKNOWN:40
|
||||
- COMPONENT_ONLY:0
|
||||
|
||||
阶段结果:
|
||||
|
||||
```text
|
||||
PBF-01 PASS
|
||||
PBF-02 PASS
|
||||
PBF-03 PASS
|
||||
PBF-04 PASS
|
||||
PBF-05 PASS
|
||||
PBF-06 PASS_WITH_WARNINGS
|
||||
PBF-07 EXPORTED
|
||||
```
|
||||
|
||||
导出目录:
|
||||
|
||||
```text
|
||||
dist/navsea/delivery-full-semantic-extentfix/1.0.0/
|
||||
```
|
||||
|
||||
## 4. CM95 真实端到端结果
|
||||
|
||||
Style:
|
||||
|
||||
```text
|
||||
http://192.168.200.184:18889/s52/full-style.json
|
||||
```
|
||||
|
||||
Style SHA-256:
|
||||
|
||||
```text
|
||||
b1d3d0060012a8e4b55a6053231231d742ec415b3a8398f9ae0867bbdfa5290b
|
||||
```
|
||||
|
||||
Source fingerprint:
|
||||
|
||||
```text
|
||||
aa42eb9fd575dde1b651d537ccc5b52c9dafac1bd8a3d6c5166c49a9581c9363
|
||||
```
|
||||
|
||||
Sprite:
|
||||
|
||||
- JSON SHA-256:`51519fb9a64f11dc100f894b2b54d14f56770ac9d511f15ae574ff5867af857d`
|
||||
- PNG SHA-256:`90cf4da31e01abb0676b538ebd2b5c951b6d737a31d23062ec6eb06383d729a2`
|
||||
|
||||
Style 未声明 Glyph,Package 明确记录 Glyph 不可用并保持 `capabilities.glyphs=false`。
|
||||
|
||||
三个指定真实 z12 PBF 样本全部成功:
|
||||
|
||||
| XYZ | 字节数 | SHA-256 |
|
||||
|---|---:|---|
|
||||
| `12/3531/1641` | 423,777 | `1b9521e5dd990c92c71f22a4d56bfbd1ba33e5f236ddbf2af5ce51191e2efab8` |
|
||||
| `12/3526/1643` | 285,154 | `92147b621b213a0c1fe80c2fa28ab71292b79d133b98272977defb41424ec39c` |
|
||||
| `12/3638/1613` | 82,075 | `7eeb420fe809b09f8e03b892668830efd3db3e957bf32a80fd1b92b2d90e1dba` |
|
||||
|
||||
PBF-03:
|
||||
|
||||
- decoded styled-layer feature:5,210
|
||||
- matched occurrence:2,077
|
||||
- occurrence 输出:2,077
|
||||
- distinct Actual Visual Object:102
|
||||
- group:25
|
||||
- unsupported component:0
|
||||
- missing sprite component:0
|
||||
|
||||
PBF-04 使用现有 CM95 人工 assignment,没有由 matcher 覆盖人工结论。Mapping 共 102 个 Actual Visual Object:
|
||||
|
||||
- VISUAL_OBJECT_MATCH:9
|
||||
- LAYER_ONLY:47
|
||||
- AMBIGUOUS:2
|
||||
- UNKNOWN:44
|
||||
- COMPONENT_ONLY:0
|
||||
|
||||
阶段结果:
|
||||
|
||||
```text
|
||||
PBF-01 PASS
|
||||
PBF-02 PASS
|
||||
PBF-03 PASS
|
||||
PBF-04 PASS
|
||||
PBF-05 PASS
|
||||
PBF-06 PASS_WITH_WARNINGS
|
||||
PBF-07 EXPORTED
|
||||
```
|
||||
|
||||
导出目录:
|
||||
|
||||
```text
|
||||
dist/cm95/s52-full/1.0.0/
|
||||
```
|
||||
|
||||
## 5. 验证
|
||||
|
||||
自动测试:
|
||||
|
||||
```text
|
||||
.venv/bin/python -m unittest discover -s tests -v
|
||||
```
|
||||
|
||||
结果:6/6 PASS。
|
||||
|
||||
CM95 固定分类基线:
|
||||
|
||||
```text
|
||||
.venv/bin/python tools/style-visual-object/validate_cm95_classification.py
|
||||
```
|
||||
|
||||
结果:`RESULT: PASS`。既有 7 条人工决定与 S-52 语义建议不一致 WARN 保留,WARN 不覆盖人工结果。
|
||||
|
||||
其他检查:
|
||||
|
||||
- Python compileall:PASS
|
||||
- Pipeline CLI help:PASS
|
||||
- `git diff --check`:PASS
|
||||
- NavSea fresh end-to-end run:PASS_WITH_WARNINGS / EXPORTED
|
||||
- CM95 fresh end-to-end run:PASS_WITH_WARNINGS / EXPORTED
|
||||
|
||||
## 6. Git 与 Codex
|
||||
|
||||
Pipeline 正式流程文档此前已保存到 main:
|
||||
|
||||
- `f3da1a6 docs: define PBF provider pipeline v1`
|
||||
|
||||
Codex 实现阶段:
|
||||
|
||||
- 实现提交:`aea9862 feat: implement provider-neutral PBF pipeline v1`
|
||||
- 初版完成报告提交:`804a764 docs: record provider pipeline v1 completion`
|
||||
|
||||
随后由外部 X220 shell 完成 NavSea HTTPS 资源入口修正及 NavSea/CM95 fresh end-to-end 验收。本报告 v2 记录最终实际状态。
|
||||
|
||||
Codex 本轮实际启动横幅确认配置:
|
||||
|
||||
```text
|
||||
Model: GPT-6 Luna
|
||||
Reasoning effort: High
|
||||
```
|
||||
|
||||
## 7. 当前限制
|
||||
|
||||
1. 两套验收都只采样三个 z12 tile,不代表全量数据覆盖。
|
||||
2. NavSea 本次 85 个 Actual Visual Object 中仍有 UNKNOWN/AMBIGUOUS;这些状态被明确保留,没有猜测 Layer。
|
||||
3. CM95 本次 102 个 Actual Visual Object 中仍有 44 UNKNOWN、2 AMBIGUOUS;仍以现有人工 assignment 为最终语义权威。
|
||||
4. `dist/` 与 `.tmp/` 为可重建运行产物,按设计不纳入 Git。
|
||||
5. NavSea 本地 Style 内仍保留旧 LAN URL;Pipeline 通过 Provider manifest 的资源覆盖使用当前可用公开 HTTPS 镜像。后续若 Style 本体正式更新 URL,可再移除 manifest 覆盖。
|
||||
|
||||
## 8. 复现命令
|
||||
|
||||
NavSea:
|
||||
|
||||
```bash
|
||||
.venv/bin/python tools/provider-pipeline/run_provider_pipeline.py \
|
||||
--manifest providers/navsea/manifest.json
|
||||
```
|
||||
|
||||
CM95:
|
||||
|
||||
```bash
|
||||
.venv/bin/python tools/provider-pipeline/run_provider_pipeline.py \
|
||||
--manifest providers/cm95/manifest.json
|
||||
```
|
||||
141
docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v3.md
Normal file
141
docs/报告/PBF_Provider_Pipeline_v1_Codex完成报告_v3.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# PBF Provider Pipeline v1 完成报告 v3
|
||||
|
||||
日期:2026-10-06
|
||||
分支:`feature/provider-pipeline-v1`
|
||||
主题:PBF-08 NavSea Delivery ZIP
|
||||
|
||||
## 结论
|
||||
|
||||
在既有 PBF-01~PBF-07 基础上新增 PBF-08。PBF-07 仍负责导出可审计的 Provider Package 目录,PBF-08 自动把 NavSea 最终正式输入打成一个单文件 `.navsea-provider.zip`。
|
||||
|
||||
用户后续向 NavSea 交付时,不再需要手工选择目录中的多个文件,只需要复制对应 Provider 的 ZIP。
|
||||
|
||||
## PBF-08 白名单
|
||||
|
||||
ZIP 固定且只包含 9 个文件:
|
||||
|
||||
```text
|
||||
provider-package.json
|
||||
provider-policy.json
|
||||
mapping-layer-assignment.json
|
||||
resources-style.json
|
||||
resources-sprite.json
|
||||
resources-sprite.png
|
||||
validation.json
|
||||
validation.md
|
||||
MANIFEST.json
|
||||
```
|
||||
|
||||
任何白名单文件缺失时,PBF-08 直接 FAIL,不生成 ZIP。
|
||||
|
||||
ZIP 生成后自动执行:
|
||||
|
||||
1. 精确文件列表校验;
|
||||
2. ZIP CRC 校验;
|
||||
3. ZIP SHA-256 计算;
|
||||
4. 将 PBF-08 状态、路径、文件名、SHA-256、字节数、内部根目录和文件列表写入 `pipeline-report.json`;
|
||||
5. CLI 输出 `deliveryZip` 和 `deliveryZipSha256`。
|
||||
|
||||
临时 PBF、`.tmp`、工具源码、测试、人工审核中间文件以及其他未声明文件不会进入 ZIP。
|
||||
|
||||
## 自动测试
|
||||
|
||||
```text
|
||||
.venv/bin/python -m unittest discover -s tests -v
|
||||
```
|
||||
|
||||
结果:8/8 PASS。
|
||||
|
||||
新增覆盖:
|
||||
|
||||
- ZIP 只包含规定的 NavSea 交付文件;
|
||||
- 多余文件不会进入 ZIP;
|
||||
- 缺少任意必需文件时拒绝生成 ZIP。
|
||||
|
||||
Python compileall:PASS。
|
||||
`git diff --check`:PASS。
|
||||
|
||||
## NavSea 实际结果
|
||||
|
||||
Pipeline:
|
||||
|
||||
```text
|
||||
PBF-01 PASS
|
||||
PBF-02 PASS
|
||||
PBF-03 PASS
|
||||
PBF-04 PASS
|
||||
PBF-05 PASS
|
||||
PBF-06 PASS_WITH_WARNINGS
|
||||
PBF-07 EXPORTED
|
||||
PBF-08 PACKAGED
|
||||
```
|
||||
|
||||
ZIP:
|
||||
|
||||
```text
|
||||
dist/navsea/delivery-full-semantic-extentfix/
|
||||
navsea-delivery-full-semantic-extentfix-1.0.0.navsea-provider.zip
|
||||
```
|
||||
|
||||
ZIP SHA-256:
|
||||
|
||||
```text
|
||||
54aff8d8b882211ced6e77b3a93e8e793c780b44a1faa982ed8fc64693124fd5
|
||||
```
|
||||
|
||||
ZIP 大小:933,404 bytes。
|
||||
|
||||
外部 `unzip -t`:9 个文件全部 OK,无压缩数据错误。
|
||||
|
||||
## CM95 实际结果
|
||||
|
||||
Pipeline:
|
||||
|
||||
```text
|
||||
PBF-01 PASS
|
||||
PBF-02 PASS
|
||||
PBF-03 PASS
|
||||
PBF-04 PASS
|
||||
PBF-05 PASS
|
||||
PBF-06 PASS_WITH_WARNINGS
|
||||
PBF-07 EXPORTED
|
||||
PBF-08 PACKAGED
|
||||
```
|
||||
|
||||
ZIP:
|
||||
|
||||
```text
|
||||
dist/cm95/s52-full/
|
||||
cm95-s52-full-1.0.0.navsea-provider.zip
|
||||
```
|
||||
|
||||
ZIP SHA-256:
|
||||
|
||||
```text
|
||||
603cc004833bcff5571a32843d8ceedc7858b2fc4b28c41056db6807c7d511ee
|
||||
```
|
||||
|
||||
ZIP 大小:742,008 bytes。
|
||||
|
||||
外部 `unzip -t`:9 个文件全部 OK,无压缩数据错误。
|
||||
|
||||
## 使用规则
|
||||
|
||||
以后 PBF Pipeline 正常执行完成后:
|
||||
|
||||
```bash
|
||||
.venv/bin/python tools/provider-pipeline/run_provider_pipeline.py \
|
||||
--manifest providers/<provider>/manifest.json
|
||||
```
|
||||
|
||||
只要 PBF-06 为 `PASS` 或 `PASS_WITH_WARNINGS`,Pipeline 会自动完成 PBF-07 和 PBF-08。
|
||||
|
||||
交给 NavSea 时,只复制 CLI 输出的:
|
||||
|
||||
```text
|
||||
deliveryZip
|
||||
```
|
||||
|
||||
即可。
|
||||
|
||||
`--no-export` 模式继续只运行到 Package 校验,PBF-07 与 PBF-08 都会标记为 `SKIPPED_BY_REQUEST`,不会生成 ZIP。
|
||||
@@ -1,23 +1,71 @@
|
||||
{
|
||||
"schemaVersion": "pbf-provider-source-manifest/v1",
|
||||
"provider": {"providerId": "navsea", "name": "NavSea", "version": "1"},
|
||||
"dataset": {"datasetId": "delivery-full-semantic-extentfix", "name": "Delivery Full Semantic ExtentFix"},
|
||||
"package": {"packageId": "navsea-delivery-full", "version": "1.0.0"},
|
||||
"provider": {
|
||||
"providerId": "navsea",
|
||||
"name": "NavSea",
|
||||
"version": "1"
|
||||
},
|
||||
"dataset": {
|
||||
"datasetId": "delivery-full-semantic-extentfix",
|
||||
"name": "Delivery Full Semantic ExtentFix"
|
||||
},
|
||||
"package": {
|
||||
"packageId": "navsea-delivery-full",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"resources": {
|
||||
"style": {"uri": "/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full-semantic-extentfix.json"},
|
||||
"sprite": {"uri": "http://192.168.200.184/newpec/sprite-semantic/sprite"},
|
||||
"glyphs": {"uri": "http://192.168.200.184/newpec/fonts/{fontstack}/{range}.pbf"}
|
||||
"style": {
|
||||
"uri": "/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full-semantic-extentfix.json"
|
||||
},
|
||||
"sprite": {
|
||||
"uri": "https://pbf.jpcn.ccwu.cc/sprite/sprite"
|
||||
},
|
||||
"glyphs": {
|
||||
"uri": "https://pbf.jpcn.ccwu.cc/fonts/{fontstack}/{range}.pbf"
|
||||
}
|
||||
},
|
||||
"tileSource": {"sourceId": "navsea_delivery"},
|
||||
"sampleTileCandidates": ["12/3531/1641", "12/3526/1643", "12/3638/1613"],
|
||||
"tileSource": {
|
||||
"sourceId": "navsea_delivery",
|
||||
"template": "https://pbf.jpcn.ccwu.cc/pbf/pbf-delivery-full-20260418-rebuild/{z}/{x}/{y}.pbf"
|
||||
},
|
||||
"sampleTileCandidates": [
|
||||
"12/3531/1641",
|
||||
"12/3526/1643",
|
||||
"12/3638/1613"
|
||||
],
|
||||
"probeGlyph": false,
|
||||
"mapping": {"mode": "frozen-standard-visual", "standardCatalog": "../../tools/style-visual-object/output/navsea-standard/standard-catalog.json"},
|
||||
"policy": {
|
||||
"display": {"enabled": true, "source": "provider-style"},
|
||||
"pickup": {"enabled": false, "rules": []},
|
||||
"planning": {"enabled": false, "rules": []},
|
||||
"danger": {"enabled": false, "rules": []},
|
||||
"capabilities": {"vectorTiles": true, "sprite": true, "glyphs": true, "display": true, "pickup": false, "planning": false, "danger": false}
|
||||
"mapping": {
|
||||
"mode": "frozen-standard-visual",
|
||||
"standardCatalog": "../../tools/style-visual-object/output/navsea-standard/standard-catalog.json"
|
||||
},
|
||||
"limitations": ["只使用 manifest 列出的 z12 样本瓦片进行实例化;未据此推断全数据集覆盖率。"]
|
||||
"policy": {
|
||||
"display": {
|
||||
"enabled": true,
|
||||
"source": "provider-style"
|
||||
},
|
||||
"pickup": {
|
||||
"enabled": false,
|
||||
"rules": []
|
||||
},
|
||||
"planning": {
|
||||
"enabled": false,
|
||||
"rules": []
|
||||
},
|
||||
"danger": {
|
||||
"enabled": false,
|
||||
"rules": []
|
||||
},
|
||||
"capabilities": {
|
||||
"vectorTiles": true,
|
||||
"sprite": true,
|
||||
"glyphs": true,
|
||||
"display": true,
|
||||
"pickup": false,
|
||||
"planning": false,
|
||||
"danger": false
|
||||
}
|
||||
},
|
||||
"limitations": [
|
||||
"只使用 manifest 列出的 z12 样本瓦片进行实例化;未据此推断全数据集覆盖率。"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ import json
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "tools/provider-policy-compiler"))
|
||||
from provider_policy import build_policy, export_package, fingerprint, validate_package, validate_policy
|
||||
from provider_policy import DELIVERY_FILES, build_policy, create_delivery_zip, export_package, fingerprint, validate_package, validate_policy
|
||||
|
||||
|
||||
class ProviderPipelineContractTests(unittest.TestCase):
|
||||
@@ -70,6 +71,42 @@ class ProviderPipelineContractTests(unittest.TestCase):
|
||||
self.assertIn("style", manifest["resources"])
|
||||
self.assertIn("sprite", manifest["resources"])
|
||||
|
||||
def test_delivery_zip_contains_only_required_navsea_files(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
export_dir = Path(tmp) / "1.0.0"
|
||||
export_dir.mkdir()
|
||||
for name in DELIVERY_FILES:
|
||||
path = export_dir / name
|
||||
if name == "validation.json":
|
||||
path.write_text(json.dumps({"result": "PASS_WITH_WARNINGS"}), encoding="utf-8")
|
||||
elif name.endswith(".png"):
|
||||
path.write_bytes(b"png")
|
||||
else:
|
||||
path.write_text(name, encoding="utf-8")
|
||||
(export_dir / "not-for-navsea.tmp").write_text("exclude me", encoding="utf-8")
|
||||
info = create_delivery_zip(export_dir, "provider-a", "dataset-1", "1.0.0")
|
||||
self.assertEqual(info["validationResult"], "PASS_WITH_WARNINGS")
|
||||
self.assertEqual(len(info["sha256"]), 64)
|
||||
with zipfile.ZipFile(info["path"], "r") as archive:
|
||||
expected = [f"provider-a-dataset-1-1.0.0/{name}" for name in DELIVERY_FILES]
|
||||
self.assertEqual(archive.namelist(), expected)
|
||||
self.assertNotIn("provider-a-dataset-1-1.0.0/not-for-navsea.tmp", archive.namelist())
|
||||
|
||||
def test_delivery_zip_fails_when_required_file_is_missing(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
export_dir = Path(tmp) / "1.0.0"
|
||||
export_dir.mkdir()
|
||||
for name in DELIVERY_FILES:
|
||||
if name == "resources-sprite.png":
|
||||
continue
|
||||
path = export_dir / name
|
||||
if name == "validation.json":
|
||||
path.write_text(json.dumps({"result": "PASS"}), encoding="utf-8")
|
||||
else:
|
||||
path.write_text(name, encoding="utf-8")
|
||||
with self.assertRaises(ValueError):
|
||||
create_delivery_zip(export_dir, "provider-a", "dataset-1", "1.0.0")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -9,8 +9,41 @@ python tools/provider-pipeline/run_provider_pipeline.py --manifest providers/nav
|
||||
python tools/provider-pipeline/run_provider_pipeline.py --manifest providers/cm95/manifest.json
|
||||
```
|
||||
|
||||
也可重复传入 `--sample-tile z/x/y` 覆盖 manifest 中的样本候选;Pipeline 复用 manifest 声明的现有人工 assignment 或冻结 Catalog,不会用自动 matcher 覆盖审核结果。已有视觉目录和实例化目录会从 `.tmp/provider-pipeline/` 复用;需要从头重算时删除对应 work 目录。`--no-export` 只运行到 Package 校验。
|
||||
也可重复传入 `--sample-tile z/x/y` 覆盖 manifest 中的样本候选。Pipeline 复用 manifest 声明的现有人工 assignment 或冻结 Catalog,不会用自动 matcher 覆盖审核结果。已有视觉目录和实例化目录会从 `.tmp/provider-pipeline/` 复用;需要从头重算时删除对应 work 目录。`--no-export` 只运行到 Package 校验,因此不会执行 PBF-07 和 PBF-08。
|
||||
|
||||
PBF-01 保存原 Style、Sprite 和真实 PBF 样本并计算 SHA-256 / source fingerprint。PBF-02 直接复用现有 Style Visual Object Tool。PBF-03 接收 provider/dataset 参数并为每个 feature 写 occurrence 及可追溯证据。PBF-04 从冻结 Standard Catalog 的视觉 hash 对照,或读取声明的人工 assignment。PBF-05/06 使用共享契约和校验逻辑。只有 PASS 或 PASS_WITH_WARNINGS 才能 PBF-07 导出。
|
||||
## 阶段
|
||||
|
||||
输出目录默认 `dist/<provider>/<dataset>/<version>/`,运行缓存位于 `.tmp/`,不纳入 Git。Pipeline 不生成 ProviderExecutionPlan。
|
||||
PBF-01 保存原 Style、Sprite 和真实 PBF 样本并计算 SHA-256 / source fingerprint。PBF-02 复用现有 Style Visual Object Tool。PBF-03 接收 provider/dataset 参数并为每个 feature 写 occurrence 及可追溯证据。PBF-04 从冻结 Standard Catalog 的视觉 hash 对照,或读取声明的人工 assignment。PBF-05/06 使用共享契约和校验逻辑。只有 PASS 或 PASS_WITH_WARNINGS 才能 PBF-07 导出。
|
||||
|
||||
PBF-08 在 PBF-07 成功后自动生成一个可直接交给 NavSea 的单文件 ZIP。ZIP 使用严格白名单,缺少任何规定文件都会直接失败;临时 PBF、.tmp、工具源码、人工审核中间文件和其他未声明文件不会进入 ZIP。
|
||||
|
||||
PBF-08 ZIP 固定包含:
|
||||
|
||||
```text
|
||||
provider-package.json
|
||||
provider-policy.json
|
||||
mapping-layer-assignment.json
|
||||
resources-style.json
|
||||
resources-sprite.json
|
||||
resources-sprite.png
|
||||
validation.json
|
||||
validation.md
|
||||
MANIFEST.json
|
||||
```
|
||||
|
||||
默认输出:
|
||||
|
||||
```text
|
||||
dist/<provider>/<dataset>/
|
||||
<provider>-<dataset>-<version>.navsea-provider.zip
|
||||
```
|
||||
|
||||
ZIP 内部还有一个同名顶层目录,避免解压多个 Provider 包时文件混在一起。Pipeline 在完成 ZIP 后会重新打开 ZIP,核对文件列表、CRC,并计算 ZIP SHA-256;这些信息写入 `pipeline-report.json` 的 `PBF-08` 节点,同时打印 `deliveryZip` 和 `deliveryZipSha256`。
|
||||
|
||||
PBF-07 的可审计目录仍保留在:
|
||||
|
||||
```text
|
||||
dist/<provider>/<dataset>/<version>/
|
||||
```
|
||||
|
||||
运行缓存位于 `.tmp/`,不纳入 Git。Pipeline 不生成 ProviderExecutionPlan。
|
||||
|
||||
@@ -17,7 +17,7 @@ from typing import Any
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT / "tools" / "provider-policy-compiler"))
|
||||
from provider_policy import build_package, build_policy, fingerprint, validate_package, validate_policy, export_package
|
||||
from provider_policy import build_package, build_policy, create_delivery_zip, fingerprint, validate_package, validate_policy, export_package
|
||||
|
||||
|
||||
def read_resource(location: str, timeout: int = 60) -> bytes:
|
||||
@@ -279,7 +279,7 @@ def main() -> int:
|
||||
"capabilities": manifest.get("policy", {}).get("capabilities", {}),
|
||||
"validationRequirements": {"requireStyle": True, "requirePbfSample": True, "requireSprite": True, "minimumMappingCount": 1},
|
||||
"unresolved": unresolved, "limitations": manifest.get("limitations", []),
|
||||
"provenance": {"manifest": str(manifest_path), "mappingSource": mapping_source, "pipelineVersion": "1.0.0", "generatedAt": datetime.now(timezone.utc).isoformat()},
|
||||
"provenance": {"manifest": str(manifest_path), "mappingSource": mapping_source, "pipelineVersion": "1.1.0", "generatedAt": datetime.now(timezone.utc).isoformat()},
|
||||
"fingerprints": fingerprints,
|
||||
}
|
||||
record["stages"]["PBF-05"] = {"status": "PASS", "schemaVersion": "navsea-provider-policy/v1"}
|
||||
@@ -301,11 +301,15 @@ def main() -> int:
|
||||
shutil.copy2(intake / "sprite/sprite.png", export_dir / "resources-sprite.png")
|
||||
shutil.copy2(mapping_path, export_dir / "mapping-layer-assignment.json")
|
||||
record["stages"]["PBF-07"] = {"status": "EXPORTED", "path": str(export_dir)}
|
||||
delivery_zip = create_delivery_zip(export_dir, provider_id, dataset_id, version)
|
||||
record["stages"]["PBF-08"] = {"status": "PACKAGED", **delivery_zip}
|
||||
else:
|
||||
delivery_zip = None
|
||||
record["stages"]["PBF-07"] = {"status": "SKIPPED_BY_REQUEST"}
|
||||
record["stages"]["PBF-08"] = {"status": "SKIPPED_BY_REQUEST"}
|
||||
report_path = work / "pipeline-report.json"
|
||||
report_path.write_text(json.dumps(record, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
print(json.dumps({"providerId": provider_id, "datasetId": dataset_id, "validationResult": validation["result"], "sampleTiles": [x["tile"] for x in successful_tiles], "output": None if args.no_export else str(export_dir), "report": str(report_path)}, ensure_ascii=False, indent=2))
|
||||
print(json.dumps({"providerId": provider_id, "datasetId": dataset_id, "validationResult": validation["result"], "sampleTiles": [x["tile"] for x in successful_tiles], "output": None if args.no_export else str(export_dir), "deliveryZip": None if delivery_zip is None else delivery_zip["path"], "deliveryZipSha256": None if delivery_zip is None else delivery_zip["sha256"], "report": str(report_path)}, ensure_ascii=False, indent=2))
|
||||
return 0 if validation["result"] != "FAIL" else 2
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import zipfile
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -12,6 +14,18 @@ POLICY_SCHEMA = "navsea-provider-policy/v1"
|
||||
PACKAGE_SCHEMA = "navsea-provider-package/v1"
|
||||
ASSIGNMENT_STATUSES = {"VISUAL_OBJECT_MATCH", "LAYER_ONLY", "COMPONENT_ONLY", "AMBIGUOUS", "UNKNOWN"}
|
||||
|
||||
DELIVERY_FILES = (
|
||||
"provider-package.json",
|
||||
"provider-policy.json",
|
||||
"mapping-layer-assignment.json",
|
||||
"resources-style.json",
|
||||
"resources-sprite.json",
|
||||
"resources-sprite.png",
|
||||
"validation.json",
|
||||
"validation.md",
|
||||
"MANIFEST.json",
|
||||
)
|
||||
|
||||
|
||||
def canonical(value: Any) -> bytes:
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||
@@ -160,3 +174,51 @@ def export_package(output: Path, package: dict[str, Any], policy: dict[str, Any]
|
||||
}
|
||||
(output / "MANIFEST.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
return output
|
||||
|
||||
|
||||
def _safe_delivery_component(value: str) -> str:
|
||||
cleaned = re.sub(r"[^A-Za-z0-9._-]+", "-", str(value)).strip("-._")
|
||||
return cleaned or "provider"
|
||||
|
||||
|
||||
def create_delivery_zip(export_dir: Path, provider_id: str, dataset_id: str, version: str) -> dict[str, Any]:
|
||||
"""把 PBF-07 的正式 NavSea 输入打成一个严格白名单 ZIP。"""
|
||||
export_dir = Path(export_dir)
|
||||
missing = [name for name in DELIVERY_FILES if not (export_dir / name).is_file()]
|
||||
if missing:
|
||||
raise ValueError(f"PBF-08 缺少正式交付文件,禁止生成 ZIP: {missing}")
|
||||
|
||||
validation = json.loads((export_dir / "validation.json").read_text(encoding="utf-8"))
|
||||
if validation.get("result") not in {"PASS", "PASS_WITH_WARNINGS"}:
|
||||
raise ValueError(f"PBF-08 只接受 PASS/PASS_WITH_WARNINGS,当前为 {validation.get('result')}")
|
||||
|
||||
stem = "-".join(_safe_delivery_component(x) for x in (provider_id, dataset_id, version))
|
||||
zip_path = export_dir.parent / f"{stem}.navsea-provider.zip"
|
||||
root_name = stem
|
||||
if zip_path.exists():
|
||||
zip_path.unlink()
|
||||
|
||||
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as archive:
|
||||
for name in DELIVERY_FILES:
|
||||
archive.write(export_dir / name, arcname=f"{root_name}/{name}")
|
||||
|
||||
with zipfile.ZipFile(zip_path, "r") as archive:
|
||||
actual = archive.namelist()
|
||||
expected = [f"{root_name}/{name}" for name in DELIVERY_FILES]
|
||||
if actual != expected:
|
||||
zip_path.unlink(missing_ok=True)
|
||||
raise ValueError(f"PBF-08 ZIP 内容校验失败: expected={expected}, actual={actual}")
|
||||
bad = archive.testzip()
|
||||
if bad is not None:
|
||||
zip_path.unlink(missing_ok=True)
|
||||
raise ValueError(f"PBF-08 ZIP CRC 校验失败: {bad}")
|
||||
|
||||
return {
|
||||
"path": str(zip_path),
|
||||
"filename": zip_path.name,
|
||||
"sha256": file_fingerprint(zip_path),
|
||||
"bytes": zip_path.stat().st_size,
|
||||
"root": root_name,
|
||||
"files": list(DELIVERY_FILES),
|
||||
"validationResult": validation["result"],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user