Freeze validated CM93 importer baseline docs and audits

This commit is contained in:
kaotei
2026-09-02 10:28:23 +08:00
parent 9d56592cad
commit 0ca1f63320
6 changed files with 2366 additions and 245 deletions

623
README.md
View File

@@ -1,236 +1,467 @@
# CM93 → MySQL 高精度母数据库导入器 v0.2.0
# CM95 — CM93 → MySQL Importer
## 目标
CM95 当前仓库的已验证基线,是一个将 CM93 数据解析、标准化并保存到 MySQL 5.7 的 importer。
本工程完成第一阶段:
当前基线:
**CM93 Z/A/B/C/D/E/F/G → 完整解析 → MySQL 5.7.34 母数据库 → 源/库双重审计。**
```text
commit: 9d56592cadf7e047fb059e5a8746188595a08b43
tag: cm93-mysql-importer-baseline-v1
date: 2026-09-02
```
本阶段不生成 PBF。PBF 是第二阶段,可从本母数据库反复生成。
本阶段只覆盖:
## 固定环境
```text
CM93 source
→ binary parse
→ dictionary decode
→ geometry build / normalization
→ MySQL 5.7
→ audit / traceability
```
- Windows 11
- pyenv-win
- Python **3.12.10**
- MySQL **5.7.34**
- 当前 CM93 日本数据目录:`D:\Ship\CM93V2\CM93JAPAN`
- 标准化几何:经纬度/WGS84 语义,SRID 4326
- 坐标计算:Python double / MySQL WKB double
## 已实现
- CM93 256-byte substitution decode
- 10-byte prolog + 128-byte header
- 文件长度完整性检查
- vector table
- 2D point table
- 3D sounding table
- feature table
- object dictionary
- typed attribute dictionary / attribute blob
- Point / Line / Area / Sounding
- edge reverse flag
- Area contour/ring 组装
- `_m_sor` coverage
- `_wgsox/_wgsoy` 保存与标准化坐标修正
- CM93 6378388.0 m Mercator
- typed MySQL attributes
- raw feature / raw attribute
- 解码后的全部 CM93 table 分块保存
- 每 cell 独立事务
- DONE 自动跳过
- FAILED 默认重试
- 全目录断点续导
- import job / event 日志
- 源文件重新解析审计
- 数据库逐 cell 数量审计
- raw 数据字节完整性审计
- SHA-256 审计
- MySQL WKB 双精度回读审计
## 已验证的真实 CM93 小样本
开发时对用户提供的 147 个真实 CM93 cell 执行完整 parser 回归:
- Cell: 147/147 PASS
- Feature: 100,621
- Attribute: 112,746
- 未发生 record 越界或文件尾剩余
- header attribute-byte count 与解析结果一致
- header geometry-ref count 与解析结果一致
- header related-pointer count 与解析结果一致
- decoded raw table 字节合计与原文件长度一致
MySQL 写入需要在目标 Windows/MySQL 5.7.34 上做 pilot 验收;本包提供对应命令和审计。
PBF 当前继续冻结,不属于本阶段范围。
---
# 1. 升级已有 v0.1.x 工程
## 1. 当前状态
如果原目录已经有正确的 `.venv` 和 `.env`,把 v0.2.0 ZIP 中整个 `cm93-mysql-importer-starter` 目录覆盖到原工程即可。
CM93JAPAN / Dataset ID=1 已完成两套独立全库验收:
ZIP 不包含 `.env`,所以你已有的数据库密码不会被覆盖。
```text
Geometry Audit: OVERALL: PASS
Non-Geometry Audit: OVERALL: PASS
```
然后执行:
最终基线:
| 项目 | 数量 / 结果 |
|---|---:|
| Cells | 784 |
| Features | 322465 |
| Attributes | 405153 |
| Sounding points | 275700 |
| Coverages | 1156 |
| Area | 81080 |
| Area valid | 81080 / 81080 |
| Coverage valid | 1156 / 1156 |
| Feature repaired | 55 |
| Coverage repaired | 3 |
| Feature geometry issues | 0 |
| Coverage geometry issues | 0 |
| raw_geotype=16 | 4406 |
| raw_geotype=16 issues | 0 |
| Area bbox mismatch | 0 |
| Source files checked | 784 |
| Source files missing | 0 |
| Source size mismatch | 0 |
| Source SHA-256 mismatch | 0 |
---
## 2. 主要能力
Importer 当前处理并保存:
- CM93 Cell 扫描;
- CM93OBJ / CM93ATTR 字典;
- Cell header;
- vector / edge;
- 2D point;
- 3D sounding;
- Feature;
- Attribute;
- Point / Line / Area;
- Coverage;
- WGS offset;
- Sounding point;
- Feature bbox;
- raw feature / raw attribute;
- Cell 原始 table 分块;
- source SHA-256;
- import job / event;
- geometry issue / repaired 状态。
每个 Feature 必须保持:
```text
dataset_id
cell_id
source_record_index
```
从数据库记录可追溯回原始 CM93 Cell 和 source record。
---
## 3. 生产代码
核心生产文件:
```text
src/cm93db/cm93_binary.py
src/cm93db/cell_parser.py
src/cm93db/geometry.py
src/cm93db/importer.py
src/cm93db/audit.py
sql/001_schema_mysql57.sql
```
Geometry 和 importer 的当前行为已经通过全量数据验收。后续没有明确任务时,不应重写其主流程。
---
## 4. 数据库
目标数据库:
```text
MySQL 5.7
```
Schema:
```text
sql/001_schema_mysql57.sql
```
Importer 的 normalized SRID 为:
```text
EPSG:4326
```
MySQL geometry 通过 WKB 写入,坐标使用 double precision。
不要假设 MySQL 8 的 Spatial / SRID 行为适用于本项目。
数据库连接配置以项目现有 `.env.example` / 配置模块为准。
---
## 5. 导入
Windows 项目环境示例:
```powershell
cd D:\React\cm93-mysql-importer-starter
& ".\.venv\Scripts\python.exe" -m pip install -e .
& ".\.venv\Scripts\cm93db.exe" --help
& ".\.venv\Scripts\cm93db.exe" import D:\Ship\CM93V2\CM93JAPAN
```
确认出现 `import` 和 `audit`。
# 2. .env
确保:
普通导入会根据:
```text
CM93_DB_HOST=127.0.0.1
CM93_DB_PORT=3306
CM93_DB_NAME=cm93_chart
CM93_DB_USER=你的用户
CM93_DB_PASSWORD=你的密码
CM93_DB_CHARSET=utf8mb4
CM93_SOURCE_DIR=D:\Ship\CM93V2\CM93JAPAN
chart_cell.import_status
source_size
source_sha256
```
`scan / inspect-dicts / import / audit` 现在都可以省略路径,自动读取 `CM93_SOURCE_DIR`。
跳过已经成功导入且源文件 SHA-256 未变化的 Cell。
# 3. 环境/数据库检查
```powershell
& ".\.venv\Scripts\cm93db.exe" env-check
& ".\.venv\Scripts\cm93db.exe" db-check
& ".\.venv\Scripts\cm93db.exe" scan
& ".\.venv\Scripts\cm93db.exe" inspect-dicts
```
# 4. 先做 G 层 10-cell pilot
不要第一次就直接跑完整日本数据。先验证 MySQL 实际写入:
```powershell
& ".\.venv\Scripts\cm93db.exe" import --scale G --limit 10
```
然后立即审计同一批:
```powershell
& ".\.venv\Scripts\cm93db.exe" audit --scale G --limit 10 --precision-samples 32
```
目标:
典型输出:
```text
source_parse_failed : 0
db_missing_cells : 0
db_not_done_cells : 0
count_mismatches : 0
hash_mismatches : 0
raw_preservation_bad : 0
unknown_objects : 0
unknown_attributes : 0
precision_failed : 0
RESULT : PASS
SKIP ... (SHA-256 unchanged)
```
# 5. 全量导入日本数据
Pilot PASS 后:
需要强制重新解析并写入所有选中 Cell 时:
```powershell
& ".\.venv\Scripts\cm93db.exe" import
& ".\.venv\Scripts\cm93db.exe" import D:\Ship\CM93V2\CM93JAPAN --reimport
```
程序逐 cell 工作。已经 `DONE` 且 **SHA-256 未变化** 的 cell 自动跳过,因此中断后重新执行同一命令即可续导。
`--reimport` 会清理每个 Cell 已有 payload 后重新生成,因此只应在明确需要全量重导时使用。
FAILED cell 默认在下一次执行时重试。
# 6. 全量审计
```powershell
& ".\.venv\Scripts\cm93db.exe" audit --precision-samples 256
```
这会重新读取 CM93 源文件,并与数据库逐 cell 对比:
- SHA-256
- Feature 数
- Attribute 数
- Point geometry 数
- Line geometry 数
- Area geometry 数
- `_m_sor` coverage 数
- Sounding point 数
- raw table 保存字节数
- 未知 object / attribute
- 抽样 WKB 双精度 round-trip
## 更严格的 geometry validity 检查
```powershell
& ".\.venv\Scripts\cm93db.exe" audit --precision-samples 256 --validate-geometry
```
`--validate-geometry` 会额外用 Shapely 全量检查拓扑,明显更重。CM93 中存在自相交/边界类 contour 并不自动等于解析错误,因此这项结果作为信息单独显示,不会静默修复原 geometry。
# 7. 常用控制
只处理 F/G:
```powershell
cm93db import --scale F --scale G
```
只处理一个 cell:
```powershell
cm93db import --cell 04501075.G
cm93db audit --cell 04501075.G --precision-samples 16
```
强制重导:
```powershell
cm93db import --cell 04501075.G --reimport
```
只审计源文件 parser,不访问数据库内容:
```powershell
cm93db audit --source-only
```
正式母库**不建议**使用 `--no-raw-tables`。如果有意不保存 raw table,审计时需显式:
```powershell
cm93db audit --allow-missing-raw
```
如果单个 Cell 因临时数据库连接错误等原因处于 `FAILED`,普通 import 默认会重试失败 Cell,同时跳过其余未变化的 DONE Cell。
---
# 精度原则
## 6. Geometry 语义
1. CM93 raw X/Y 保持 16-bit 原始语义。
2. Cell easting/northing header 值使用 double。
3. CM93 Mercator 半长轴固定 `6378388.0`。
4. `_wgsox/_wgsoy` 以米为单位,在 Mercator→经纬度之前按 CM93 Transform 语义减去。
5. MySQL geometry 由 WKB 写入;WKB 坐标为 IEEE-754 8-byte double。
6. importer 阶段不 simplify、不 quantize、不 snap、不 round。
7. Polygon 不自动 `make_valid`。
8. 原始 decoded table + raw feature/attribute 与标准化 geometry 同时保留。
9. PBF 将来是可重新生成的发布格式,不能反向影响母数据库精度。
### 6.1 坐标
详见 `docs/精度规范.md` 和 `docs/CM93解析与审计设计.md`。
CM93 raw coordinate 按 Cell header 参数转换到 Mercator 坐标,再转换为经纬度。
# Codex 接手
Coverage 的 `_wgsox / _wgsoy` 用于最终 geometry 的 WGS offset 修正。
Codex 不需要重新实现 parser。先读:
最终数据库 geometry 使用 SRID 4326。
- `AGENTS.md`
- `codex/ARCHITECTURE.md`
- `codex/20_导入与审计接手.md`
### 6.2 Line
后续主要职责是:在你的 Win11 + MySQL 5.7.34 + CM93JAPAN 实际环境运行 pilot、分析失败 cell、修正真实兼容问题,并保留精度/审计边界。
Line 必须保留断开的多个 line parts,不得为了得到单条 LineString 而跨 discontinuity 人为连接。
### 6.3 Area / Coverage
当前冻结规则:
#### 已经 OGC-valid
```text
PASS-THROUGH
```
已经 valid 的 Polygon / MultiPolygon 不重新 normalization,不为了统一 ring 顺序而重建。
#### OGC-invalid
只有 invalid Area / Coverage 才执行:
```text
boundary noding
→ polygonize_full
→ odd-even face selection
→ union selected faces
→ GEOS normalize
→ valid Polygon / MultiPolygon
```
该规则来自 CM93 实际 topology / fill semantics 的完整审计。
生产规则明确禁止直接使用:
```text
make_valid()
ST_MakeValid()
buffer(0)
```
来覆盖原始 CM93 Polygon 语义。
Normalization 不允许创造原始 CM93 boundary linework 之外的新边界。
open ring、断裂 contour 等真实结构异常不能静默“修好”;无法安全 normalization 的 Coverage 必须阻止错误 Cell 落库。
### 6.4 raw_geotype=16
`raw_geotype=16` 是 CM93 正常的 parent/no-geometry 对象。
当前正确语义:
```text
geometry_type = META
geometry = NULL
geometry_issue = NULL
geometry_repaired = 0
```
它不是 `"geometry missing"` 错误,也不进入 `geometry_invalid_count`。
当前 Dataset ID=1 共验证:
```text
4406 / 4406
```
全部为正常 parent/no-geometry。
### 6.5 bbox
Area 发生 normalization 后:
```text
feature bbox = final normalized geometry.bounds
```
不能继续使用 normalization 前可能包含 retraced connector 的 bounds。
---
## 7. geometry_repaired / geometry_issue
`geometry_repaired=1` 表示 importer 对原 OGC-invalid CM93 polygon 执行冻结 normalization,并得到了最终 valid Polygon/MultiPolygon。
`geometry_issue` 只用于:
- geometry 真正缺失但该 primitive 应存在 geometry;
- geometry empty;
- open ring / 结构异常;
- normalization 无法安全完成;
- 其他真实 geometry 异常。
正常 META parent/no-geometry 不属于 issue。
当前已验证:
```text
Feature repaired = 55
Coverage repaired = 3
Feature issues = 0
Coverage issues = 0
```
Coverage 同时也是 `_m_sor` Feature,所以不要简单把 `55 + 3` 当作 58 个独立 CM93 source Feature。
---
## 8. Raw source 保留
标准化 geometry 不得破坏原始输入证据。
必须长期保留:
```text
chart_feature.raw_feature_blob
chart_feature.raw_attribute_blob
chart_raw_record
source_record_index
```
`chart_raw_record` 使用分块保存原始 Cell table,并在 metadata 中记录:
```text
chunk_index
chunk_count
total_bytes
```
这保证后续仍可重新核对 parser 与 CM93 原始二进制。
---
## 9. 长期回归验收
正式长期验收工具:
```text
tools/cm93_mysql_final_geometry_audit.py
tools/cm93_mysql_non_geometry_final_audit.py
```
### Geometry 全库验收
```powershell
& ".\.venv\Scripts\python.exe" .\tools\cm93_mysql_final_geometry_audit.py `
--host 127.0.0.1 `
--port 3306 `
--user root `
--database cm93_chart `
--dataset-id 1
```
当前 CM93JAPAN 基线应得到:
```text
Cells : 784
Features : 322465
Feature repaired : 55
Coverage repaired : 3
Feature issues : 0
Coverage issues : 0
Geotype16 total : 4406
Geotype16 issues : 0
Area total : 81080
Area valid : 81080
Area bbox mismatch : 0
Coverage total : 1156
Coverage valid : 1156
Failure count : 0
OVERALL: PASS
```
### 非 Geometry 全库验收
```powershell
& ".\.venv\Scripts\python.exe" .\tools\cm93_mysql_non_geometry_final_audit.py `
--host 127.0.0.1 `
--port 3306 `
--user root `
--database cm93_chart `
--dataset-id 1 `
--source-root "D:\Ship\CM93V2\CM93JAPAN"
```
当前 CM93JAPAN 基线应得到:
```text
Cells : 784
Features : 322465
Attributes : 405153
Soundings : 275700
Coverages : 1156
Cell count mismatch : 0
Feature check failures : 0
Dictionary failures : 0
Attribute failures : 0
Coverage failures : 0
Sounding failures : 0
JSON/relation failures : 0
Raw failures : 0
Source files checked : 784
Source files missing : 0
Source size mismatch : 0
Source SHA256 mismatch : 0
Failure count : 0
OVERALL: PASS
```
任何实质性修改以下部分后,都应重新执行对应验收:
- binary parser;
- dictionary decode;
- geometry build;
- Area/Coverage normalization;
- WGS offset;
- importer DB mapping;
- raw preservation;
- Feature / Attribute / Sounding / Coverage 关系;
- bbox;
- schema。
---
## 10. 历史调查脚本
仓库中保留了本次 importer 调查过程中产生的 V 系列审计脚本。
它们用于记录问题定位过程,不再作为日常回归入口。
日常回归只使用:
```text
tools/cm93_mysql_final_geometry_audit.py
tools/cm93_mysql_non_geometry_final_audit.py
```
历史调查脚本不要被新的生产代码 import,也不要把历史审计结果作为运行时依赖。
---
## 11. Git 冻结基线
当前正式可回退点:
```text
commit 9d56592cadf7e047fb059e5a8746188595a08b43
tag cm93-mysql-importer-baseline-v1
```
该 tag 表示:
```text
CM93 → MySQL importer validated baseline
```
tag 应保持不可变。
后续改动在 `main` 上正常提交;需要对比时,以此 tag 作为 importer normalization 前后已验证基线。
---
## 12. 当前不做的事情
当前 importer 阶段不包括:
- PBF 生成;
- PBF schema;
- PBF renderer;
- PBF API;
- 为 PBF 改写 MySQL importer;
- 为了下游显示而损失 raw CM93 数据;
- 对原始 CM93 文件进行写回。
PBF 只有在单独明确启动下一阶段后才进入设计和实现。