From 1a07406e6e11fde0425f81b54c7f4a3d2aff6d49 Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Sun, 20 Sep 2026 17:43:38 +0800 Subject: [PATCH] docs: add OpenCPN code-first S-52 audit task --- ...penCPN代码优先流程等价审计_Codex任务_v1.md | 517 ++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 docs/CM95_S52_OpenCPN代码优先流程等价审计_Codex任务_v1.md diff --git a/docs/CM95_S52_OpenCPN代码优先流程等价审计_Codex任务_v1.md b/docs/CM95_S52_OpenCPN代码优先流程等价审计_Codex任务_v1.md new file mode 100644 index 0000000..e9a902f --- /dev/null +++ b/docs/CM95_S52_OpenCPN代码优先流程等价审计_Codex任务_v1.md @@ -0,0 +1,517 @@ +# 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 HEAD` +- `git status --short --branch` +- 当前工作区是否存在与本任务无关的未提交修改。 + +本任务不得清理、重置、覆盖或提交与本任务无关的现有修改。最终如提交 Git,只允许显式 stage 本任务新增/修改的审计文档和审计产物。 + +## 3. 固定 OpenCPN 对照基线 + +不要依赖 `/tmp/opencpn-s52-audit/` 作为必要输入。统一使用仓库内已固定的上游参考快照: + +`docs/外部参考/OpenCPN源码基线_f7211b4e/` + +固定 OpenCPN commit: + +`f7211b4e1874c453e37a7f190aa191c55a25c32e` + +关键源码: + +- `docs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/gui/src/cm93.cpp` +- `docs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52cnsy.cpp` +- `docs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52plib.cpp` +- `docs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52plib.h` +- `docs/外部参考/OpenCPN源码基线_f7211b4e/上游源码/libs/s52plib/src/s52utils.cpp` +- `docs/外部参考/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.md` +- `docs/CM95_S52_语义守恒与运行时能力审计标准_v1.md` +- `docs/CM95_S52_静态物化与运行时呈现边界_v1.md` +- `docs/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 + +按以下优先级执行,并建立完整调用关系,不得把它们当成孤立函数: + +1. `OBSTRN04` +2. `WRECKS02` +3. `UDWHAZ03` +4. `SOUNDG03` +5. `LIGHTS05 / LIGHTS06` +6. `DEPARE01 / DEPARE02` +7. `DEPCNT02` +8. `SOUNDG02` +9. `QUAPOS01 / QUAPNT01 / QUALIN01` +10. `SLCONS03` +11. `RESTRN01` +12. `RESARE02` + +注意: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 → DEPARE` +- `SPOGRD → DMPGRD` +- `FSHHAV → FSHFAC` +- `OFSPRD → 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 → UDWHAZ03` +- `OBSTRN04 → SOUNDG03 / sounding formatting path` +- `OBSTRN04 → QUAPNT01` +- `WRECKS02 → UDWHAZ03` +- `WRECKS02 → SOUNDG03 / sounding formatting path` +- `WRECKS02 → QUAPNT01` +- `LIGHTS05 → 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` + +至少识别并展开: + +- `SY` +- `TX` +- `TE` +- `SOUNDG / sounding symbol chain` +- `CA` +- `AP` +- `AC` +- `LS` +- `LC` +- `OP` +- `CS` + +需要区分: + +- 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. 必须输出的架构结论 + +审计结束后必须回答: + +1. 当前是否存在同一 OpenCPN branch condition 在 Python 与 JS 中重复手写; +2. 哪些 CSP 已经因此产生已确认的不等价; +3. 哪些 CSP 即使当前画面没有暴露问题,也存在相同结构风险; +4. 是否应建立统一的 OpenCPN-compatible CSP Decision IR / Runtime Rule IR; +5. 如果建立 IR,哪些字段必须保留到 runtime; +6. 哪些 opcode 可以由通用 executor 执行,哪些需要专用 renderer; +7. 哪些现有 PBF scalar hint 会压缩或丢失有序 Rule Chain。 + +## 21. 本轮正式输出 + +本轮只允许生成/更新审计资料,不修改产品实现。 + +必须输出: + +1. `docs/报告/CM95_S52_OpenCPN渲染流程对照审计报告_v2.md` + - 在现有 v1 基础上升级; + - 以代码流程等价为主线; + - 包含 branch matrix、call graph、instruction sequence、runtime opcode coverage、real-data branch coverage 和明确缺口。 + +2. `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 继续分离。 + +3. 机器可读审计产物: + `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.md` +- `docs/CM95_S52_语义守恒与运行时能力审计标准_v2.md` +- `build/audits/cm95_s52_opencpn_code_first_equivalence_v2.json` + +不得使用会把其他工作区修改一起带入的宽泛 `git add .`。 + +完成后: + +1. 显式 stage 上述文件; +2. 检查 staged diff; +3. 提交到当前 `main`; +4. push 到 `origin/main`; +5. 在完成报告末尾记录 commit hash、commit message、push 结果; +6. push 失败时明确报告失败,不得声称远端已完成。 + +## 25. 最终判定原则 + +这次审计的目标不是让结果变成 PASS,而是让“不等价发生在哪里”可被机器和人准确定位。 + +如果当前实现只能证明部分等价,应保留 PARTIAL / FAIL / NOT_PROVEN。 + +截图只作为最后的视觉验证材料。真正的主证据必须是: + +`OpenCPN source branch → expected Rule Chain → CM95 decision/facts → runtime primitive consumer` + +只有这条链完整守恒,才允许将对应 branch 判为 PASS。