17 KiB
CM95 S-52 OpenCPN 代码优先流程等价审计 Codex 任务 v1
日期:2026-09-20
1. 任务性质
本任务是只读代码审计任务。核心不是继续从最终截图寻找差异,而是以仓库内固定的 OpenCPN 源码快照为 Source of Truth,正向还原 OpenCPN 的 S-52 渲染流程,再与当前 CM95 实现逐层比较。
本轮原则:
- 先审计,后修改。
- 不修改 CM95 功能代码。
- 不修改 Web runtime renderer。
- 不修改 builder、CSP resolver、style compiler、PBF schema 或 release gate。
- 不把任何 PREVIEW_ONLY / NOT_IMPLEMENTED 状态改成 IMPLEMENTED。
- 不通过“截图看起来接近”替代代码流程等价证明。
- 不新增或修改 Jest 测试。
- 如需临时分析脚本,只能放在
/tmp或其他非仓库临时位置,不提交。
2. 仓库与 Git 边界
仓库:/root/sourceserver/cm95
分支:main
开始任务时必须记录:
git rev-parse HEADgit status --short --branch- 当前工作区是否存在与本任务无关的未提交修改。
本任务不得清理、重置、覆盖或提交与本任务无关的现有修改。最终如提交 Git,只允许显式 stage 本任务新增/修改的审计文档和审计产物。
3. 固定 OpenCPN 对照基线
不要依赖 /tmp/opencpn-s52-audit/ 作为必要输入。统一使用仓库内已固定的上游参考快照:
docs/外部参考/OpenCPN源码基线_f7211b4e/
固定 OpenCPN commit:
f7211b4e1874c453e37a7f190aa191c55a25c32e
关键源码:
docs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/gui/src/cm93.cppdocs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52cnsy.cppdocs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52plib.cppdocs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52plib.hdocs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52utils.cppdocs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52utils.h- 以及该快照中完整的
libs/s52plib/src/。
开始审计前先运行 SHA-256 校验,确认参考源码未被修改;若校验失败,停止并报告,不得继续以损坏快照作为基准。
4. 当前 CM95 对照范围
至少审阅以下当前实际实现:
-
src/cm95pbf/s52.py -
src/cm95pbf/csp.py -
src/cm95pbf/presentation.py -
tools/cm95_s52_style_compiler.py -
tools/cm95_s52_runtime_capability_audit.py -
config/s52/cm95_s52_runtime_capabilities_web_compare_v1.json -
web/kyushu_compare.html -
与上述文件直接相关的 lookup、resource、presentation、release audit 代码。
同时阅读已有文档,避免重复调查:
docs/报告/CM95_S52_OpenCPN渲染流程对照审计报告_v1.mddocs/CM95_S52_语义守恒与运行时能力审计标准_v1.mddocs/CM95_S52_静态物化与运行时呈现边界_v1.mddocs/CM95_S52_NavSea运行时呈现契约_v1.md
已有报告中的结论只能作为线索,最终判断必须重新落到 OpenCPN 固定源码和当前 CM95 实现。
5. 审计总流程
必须从 OpenCPN 正向建立以下链路,不允许从当前 PBF 或截图反推 OpenCPN:
CM93 Object
→ CreateS57Obj / class normalization
→ S-52 Lookup
→ initial Rule chain
→ CS(...)
→ CSP branch
→ nested CSP calls
→ ordered instruction sequence
→ primitive opcode
→ resource dependency
→ mariner dependency
→ display category / priority / render order
→ renderer
然后对照 CM95 对应链路:
CM95 source
→ s52.py
→ csp.py
→ presentation.py / PBF runtime facts
→ style compiler
→ Web runtime
→ primitive consumer
6. 第一批强制审计 CSP
按以下优先级执行,并建立完整调用关系,不得把它们当成孤立函数:
OBSTRN04WRECKS02UDWHAZ03SOUNDG03LIGHTS05 / LIGHTS06DEPARE01 / DEPARE02DEPCNT02SOUNDG02QUAPOS01 / QUAPNT01 / QUALIN01SLCONS03RESTRN01RESARE02
注意:OpenCPN 当前源码中 LIGHTS05() 会进入 LIGHTS06();审计必须以真实可达执行链为准,不能只按旧函数名或注释判断。
7. Gate A:OPENCPN_FLOW_EQUIVALENCE
先确认对象在进入 CSP 前已经走到了与 OpenCPN 等价的对象视图和 Lookup。
至少核对:
- CM93 class substitution;
- geometry type;
- S-57/S-52 object class;
- Lookup table 选择;
- initial instruction string;
- display category;
- display priority;
- point/boundary table 相关选择;
- SCAMIN / scale 相关入口;
- 任何会影响后续 CSP 选择的对象属性转换。
已知至少检查:
ITDARE → DEPARESPOGRD → DMPGRDFSHHAV → FSHFACOFSPRD → CTNARE$AREAS + $SCODE=II25 → BACKGROUND
8. Gate B:CSP_BRANCH_EQUIVALENCE
对每个目标 CSP,从 OpenCPN 源码抽取完整 branch matrix。
每个 branch 至少记录:
- procedure;
- geometry;
- object class;
- attribute presence / value condition;
- mariner parameter condition;
- surrounding DEPARE/DRGARE 等关联对象条件;
- safety contour / safety depth 等阈值;
- 分支中调用的 nested CSP;
- 最终有序 instruction sequence;
- display category / priority side effect;
- resource dependency。
不能只记录“支持 OBSTRN04”或“支持 WRECKS02”。
如果 OpenCPN 某个分支是:
SY(DANGER51) + SOUNDG03 + QUAPNT01 + TX(...)
而当前实现只得到:
SY(DANGER51) + SOUNDG03
必须判定该 branch 为 FAIL。
9. Gate C:NESTED_CSP_CALL_GRAPH
建立第一批 CSP 的真实调用图。
重点确认:
OBSTRN04 → UDWHAZ03OBSTRN04 → SOUNDG03 / sounding formatting pathOBSTRN04 → QUAPNT01WRECKS02 → UDWHAZ03WRECKS02 → SOUNDG03 / sounding formatting pathWRECKS02 → QUAPNT01LIGHTS05 → LIGHTS06
如果 nested CSP 的输出在 Python、PBF、style compiler 或 Web runtime 任意一层被截断,必须在调用图中标出具体断点。
10. Gate D:INSTRUCTION_SEQUENCE_EQUIVALENCE
OpenCPN 的审计单位是完整、有序 Rule Chain,不是单个 symbol code。
对每个 branch 比较:
OpenCPN expected ordered sequence
与:
CM95 resolver / runtime actual ordered sequence
至少识别并展开:
SYTXTESOUNDG / sounding symbol chainCAAPACLSLCOPCS
需要区分:
- primitive 缺失;
- primitive 多出;
- 顺序变化;
- 参数变化;
- nested CSP 被扁平化后语义丢失;
- display side effect 丢失。
11. Gate E:RUNTIME_OPCODE_COVERAGE
对 release 实际出现且由 runtime 处理的 CSP,不能再只使用粗粒度 RUNTIME_OBSTRN、RUNTIME_WRECKS 等 capability 名称证明完整性。
必须从 branch expected sequence 逐 opcode 检查实际 consumer。
例如 OBSTRN04 某 branch 需要:
SY + SOUNDG03 + QUAPNT01 + TX
则必须分别回答:
- SY 谁执行;
- SOUNDG03 谁执行;
- QUAPNT01 谁执行;
- TX 谁执行;
- 参数来源是否与 OpenCPN 等价;
- 执行顺序是否守恒。
只实现其中一部分,整个 branch FAIL。
12. Gate F:REAL_DATA_BRANCH_COVERAGE
基于当前正式 Production Plan 与 release 数据扫描实际出现的条件组合。
当前已知正式基线:
- Builder:
cm95pbf-builder/0.4.12-opencpn-cm93-coverage - Production:
cm95pbf-production/2.3-opencpn-cm93-coverage - Plan:
build/production/cm95_s52_kyushu_production_plan_v4_opencpn_coverage.json - Plan ID:
57e72826db1d3e3e69f0b3b084bef4fb9469b5edc47dc0030fc2ec3e46adecf9 - Release:
cm95-d1-62a85bd40d3a-57e72826db1d - Release root:
build/releases-s52-v2/cm95-d1-62a85bd40d3a-57e72826db1d
如这些产物在当前机器不存在,记录为 evidence unavailable,不得伪造统计。
对实际数据生成 branch signature,至少覆盖与目标 CSP 相关的:
- geometry;
- object class;
- VALSOU present/absent/value band;
- WATLEV;
- EXPSOU;
- CATOBS / CATWRK 等类别属性;
- QUASOU / QUAPOS;
- TECSOU / STATUS;
- surrounding DRVAL1 / DRVAL2;
- safety contour / safety depth;
- isolated danger result;
- scale / display dependency。
每个真实出现的 branch signature 必须映射到 OpenCPN branch matrix,并标记当前 CM95 是否完整覆盖。
13. Gate G:RESOURCE_DEPENDENCY_EQUIVALENCE
对 branch 中引用的 SY/AP/LC 等资源逐项核对:
- OpenCPN 引用的资源名;
- CM95 resource universe 是否存在;
- style/runtime 是否能消费;
- 缺失时是否 fail-closed;
- 是否存在未经 OpenCPN 依据自行造出的 fallback。
已知 DANGER53 这类“代码可能引用但资源不存在”的情况必须单独记录为 upstream/resource anomaly,不能为了让审计 PASS 自行补造资源。
14. Gate H:MARINER_DEPENDENCY_EQUIVALENCE
至少核对:
- safety contour;
- safety depth;
- shallow contour;
- deep contour;
- symbolized boundaries;
- point table;
- boundary table;
- display category;
- SCAMIN;
- display scale;
- 其他会改变 CSP branch 或 primitive 参数的 mariner setting。
必须明确哪些值应保留到 runtime 才决定。
禁止把 mariner-dependent 最终表现提前写死进 PBF,再宣称与 OpenCPN 等价。
15. Gate I:RENDER_ORDER_EQUIVALENCE
检查 OpenCPN Rule Chain、display priority、display category、对象 geometry 与 MapLibre/style/runtime 实际绘制顺序之间是否存在语义变化。
至少识别:
- 同一对象多个 primitive 的相对顺序;
- fill / pattern / line / symbol / text 的先后关系;
- CSP side effect 导致的 DisplayBase promotion;
- runtime overlay 与静态 style layer 之间是否破坏 OpenCPN 的优先级语义。
如果当前架构无法证明严格顺序等价,应明确标记 UNKNOWN / NOT_PROVEN,不得默认 PASS。
16. 已知问题作为回归检查点
已有 v1 报告发现的以下问题必须重新从固定源码验证,不可直接抄结论:
- OBSTRN04 POINT 的 QUAPNT01;
- OBSTRN04 的 OBJNAM TX;
- OBSTRN04 LINE sounding;
- OBSTRN04 AREA sounding / QUAPNT01;
- isolated AREA 的 QUAPNT01;
- WRECKS02 POINT / AREA 的 QUAPNT01;
- WRECKS 的
TX('Wk')/WRECKS07; - 当前 Web hazard depth text 与 OpenCPN SOUNDG03 glyph chain 的差异;
- LIGHTS05 实际进入 LIGHTS06。
17. 审计状态定义
每个 CSP / branch / opcode 至少使用以下状态之一:
PASS:当前实现能够证明与固定 OpenCPN 基线等价。PARTIAL:只实现了部分 branch、部分 primitive 或近似表现。FAIL:存在明确缺失、错误条件、错误参数、错误顺序或错误 side effect。NOT_IMPLEMENTED:当前系统无对应实现。NOT_PROVEN:存在实现,但证据不足以证明流程等价。NOT_OBSERVED_IN_REAL_DATA:OpenCPN 代码存在该分支,但当前正式数据未观察到。UPSTREAM_RESOURCE_MISSING:OpenCPN 代码引用资源,但固定上游资源本身缺失;不得自行造资源后标 PASS。
不要用一个 CSP 的总体标签覆盖内部 branch 状态。
18. 必须输出的 branch 表
报告中第一批每个 CSP 至少给出一张表,列包含:
| 字段 | 含义 |
|---|---|
| branch_id | 稳定 branch 编号 |
| geometry | POINT / LINE / AREA 等 |
| condition | OpenCPN 分支条件 |
| mariner_dependency | 使用的 mariner 参数 |
| nested_csp | 调用的子 CSP |
| expected_sequence | OpenCPN 有序 instruction sequence |
| cm95_python | Python resolver 对应状态 |
| pbf_or_runtime_facts | 中间语义是否守恒 |
| style_or_runtime_consumer | 最终 consumer |
| real_data_count | 正式数据实际命中数 |
| status | PASS / PARTIAL / FAIL 等 |
| evidence | 文件、函数、行号或 artifact 证据 |
19. 必须输出的调用图
至少给出第一批 CSP 的调用图,明确:
- 顶层 CSP;
- nested CSP;
- 最终 primitive;
- mariner-dependent node;
- 当前 CM95 决策发生在哪一层;
- 语义在哪一层可能被截断。
调用图可以使用 Mermaid,但必须同时有文字说明,避免只靠图形表达关键结论。
20. 必须输出的架构结论
审计结束后必须回答:
- 当前是否存在同一 OpenCPN branch condition 在 Python 与 JS 中重复手写;
- 哪些 CSP 已经因此产生已确认的不等价;
- 哪些 CSP 即使当前画面没有暴露问题,也存在相同结构风险;
- 是否应建立统一的 OpenCPN-compatible CSP Decision IR / Runtime Rule IR;
- 如果建立 IR,哪些字段必须保留到 runtime;
- 哪些 opcode 可以由通用 executor 执行,哪些需要专用 renderer;
- 哪些现有 PBF scalar hint 会压缩或丢失有序 Rule Chain。
21. 本轮正式输出
本轮只允许生成/更新审计资料,不修改产品实现。
必须输出:
-
docs/报告/CM95_S52_OpenCPN渲染流程对照审计报告_v2.md- 在现有 v1 基础上升级;
- 以代码流程等价为主线;
- 包含 branch matrix、call graph、instruction sequence、runtime opcode coverage、real-data branch coverage 和明确缺口。
-
docs/CM95_S52_语义守恒与运行时能力审计标准_v2.md- 在现有 v1 基础上升级;
- 正式加入:
- CSP_BRANCH_EQUIVALENCE
- NESTED_CSP_CALL_GRAPH
- INSTRUCTION_SEQUENCE_EQUIVALENCE
- RUNTIME_OPCODE_COVERAGE
- REAL_DATA_BRANCH_COVERAGE
- RESOURCE_DEPENDENCY_EQUIVALENCE
- MARINER_DEPENDENCY_EQUIVALENCE
- RENDER_ORDER_EQUIVALENCE
- 明确 Data Release PASS 与 Target Portrayal PASS 继续分离。
-
机器可读审计产物:
build/audits/cm95_s52_opencpn_code_first_equivalence_v2.json
机器可读产物至少记录:
- OpenCPN commit;
- CM95 HEAD;
- Production Plan ID;
- CSP;
- branch_id;
- branch signature;
- expected ordered instructions;
- CM95 observed instructions / consumers;
- real_data_count;
- status;
- evidence paths;
- unresolved items。
如果当前机器缺少正式 release 数据,可允许 real_data_count=null 并记录 evidence unavailable,但代码流程审计仍必须完成。
22. 禁止事项
本轮禁止:
- 因发现缺陷直接修改
src/cm95pbf/csp.py; - 修改
web/kyushu_compare.html来让截图接近; - 修改 runtime capability registry 把 FAIL 改成 PASS;
- 修改 style compiler 掩盖 opcode 缺口;
- 增加未经 OpenCPN 依据的 symbol fallback;
- 删除或弱化已有 release gate;
- 用人工截图作为 branch equivalence 的主要证据;
- 因当前真实数据没有命中某分支就删除该 OpenCPN 分支;
- 把“当前 Web 有一段文字/图标”当作完整 SOUNDG03/SY/TX executor 的证明。
23. 完成前必做对照清单
结束前逐项确认,不得静默跳过:
- 已校验仓库内 OpenCPN 固定源码快照 SHA-256。
- 已记录 CM95 HEAD 与工作区状态。
- 已从 OpenCPN 正向还原 Object → Lookup → CSP → Rule Chain → primitive 流程。
- 已完成第一批 12 组 CSP 的 branch matrix。
- 已建立 nested CSP call graph。
- 已逐 branch 比较完整有序 instruction sequence。
- 已检查 runtime opcode consumer,不再只看粗粒度 capability。
- 已扫描或明确说明无法扫描正式 real-data branch coverage。
- 已检查 resource dependency。
- 已检查 mariner dependency。
- 已检查 render order / DisplayBase 等 side effect。
- 已重新验证 v1 已知 OBSTRN/WRECKS/SOUNDG/LIGHTS 缺口。
- 已输出 v2 审计报告。
- 已输出 v2 审计标准。
- 已输出机器可读 JSON。
- 未修改任何产品功能代码。
- 未把 PREVIEW_ONLY / FAIL 人为改成 PASS。
- 未新增或修改 Jest 测试。
- 已逐项回看本任务文件,确认无必做项遗漏。
无法完成的项目必须在报告中明确写出原因、缺少的证据和后续需要什么,不得静默省略。
24. Git 收尾
由于当前仓库可能存在与本任务无关的未提交修改,必须严格隔离提交范围。
只允许提交本任务产生的:
docs/报告/CM95_S52_OpenCPN渲染流程对照审计报告_v2.mddocs/CM95_S52_语义守恒与运行时能力审计标准_v2.mdbuild/audits/cm95_s52_opencpn_code_first_equivalence_v2.json
不得使用会把其他工作区修改一起带入的宽泛 git add .。
完成后:
- 显式 stage 上述文件;
- 检查 staged diff;
- 提交到当前
main; - push 到
origin/main; - 在完成报告末尾记录 commit hash、commit message、push 结果;
- push 失败时明确报告失败,不得声称远端已完成。
25. 最终判定原则
这次审计的目标不是让结果变成 PASS,而是让“不等价发生在哪里”可被机器和人准确定位。
如果当前实现只能证明部分等价,应保留 PARTIAL / FAIL / NOT_PROVEN。
截图只作为最后的视觉验证材料。真正的主证据必须是:
OpenCPN source branch → expected Rule Chain → CM95 decision/facts → runtime primitive consumer
只有这条链完整守恒,才允许将对应 branch 判为 PASS。