# 十一月赛验收清单

2026-11-10 编制，适用于 moongeodesy 0.2.0。

清单的依据有三部分：

- 官方规则：`moonbitlang/Hackathon2026` 仓库 `src/App.tsx` 中的“验收标准”“注意事项”和 FAQ；
- 十月验收没过的三条原因；
- README 和各包说明里的每一条承诺。

每条都对应一个测试或检查。

**一键检查：** `bash tools/acceptance.sh` 依次跑完下面所有标“自动”的项，逐项打印 PASS 或 FAIL。

- 不加参数时会在 4 个后端都跑一遍示例，需要几分钟；
- `--quick` 跳过这一步；
- A2 需要联网。

GitHub CI（`.github/workflows/ci.yml`）在 Linux 和 macOS 上跑同样的检查，见 C1–C9。

标“用户”的项 AI 做不了，见仓库根目录的 [`用户要做的事.md`](../用户要做的事.md)。

## A. 官方验收标准

| ID | 要求（原文要点） | 怎么满足 | 检查 |
| --- | --- | --- | --- |
| A1 | 以 MoonBit 为主要实现语言 | 库、测试、示例全部是 MoonBit；Python 只用于 `tools/` 下生成参考数据 | 自动：`acceptance.sh` A1 统计行数，MoonBit 行数超过 Python 的 9 倍才算通过 |
| A2 | 仓库公开 | https://github.com/ChrisTu117/moongeodesy | 自动：A2 检查页面返回 200 |
| A3 | 公开仓库持续提交，保留 commits、Issues、PR 与更新记录 | 本期新增 2 个 issue（#33、#35）和 3 个 PR（#34、#36、#37），11 月以来已有 28 个以上的小提交 | 自动：A3 要求 11 月以来至少 20 个提交；人工可看 Issues 和 PR 页面 |
| A4 | 清晰的 README | README 包括包列表、安装、用法、命令行、场景、精度表、移植来源、历史、AI 说明和中文简介；各包另有 `README.mbt.md` | 自动：C3 检查 README 的代码块就是被测试的代码，`readme_claims_test.mbt` 检查代码注释里的数值 |
| A5 | 可运行示例 | demo、命令行，以及 6 个场景（s1–s6） | 自动：C7 在 4 个后端运行全部示例，每个场景结果不对就中止；C8 运行 README 列出的命令行 |
| A6 | 必要测试 | 128 个测试，每个后端都跑 | 自动：C5 运行 `moon test --target all` |
| A7 | 已有项目须包含本期完成的实质新增工作 | 新增 `magnetic` 包（WMM2025）和 `conic` 包（兰勃特、Albers），约 1850 行库代码，配有独立参考数据的测试、命令行和场景；详见 E 节 | 自动：E 节的测试；人工可看 PR #34 和 #36 |
| A8 | 使用认可的开源许可证 | MIT（`LICENSE`，`moon.mod` 中 `license = "MIT"`） | 自动：A8 |
| A9 | 说明移植或参考来源 | README 的“Port source and license”一节；移植文件的文件头都写明来源；数据文件头写明许可（WMM 是美国政府作品，GIGS 为 IOGP 条款） | 自动：A9 检查这些说明都在 |
| A10 | AI 可解释：目标、路径与质量由参赛者掌握 | [`十一月新增功能说明.md`](十一月新增功能说明.md) 用中文讲新增代码的思路、关键实现和评委可能问的问题；README 有“AI assistance”一节 | 自动：A10 检查文件存在。**用户**：答辩前读一遍说明 |
| A11 | 重复提交、拆分项目或简单修改不计 | 新功能是新包、新算法和新数据，不是十月工作的拆分或改名 | 人工：PR #34、#36 的改动内容 |
| A12 | 加入赛事交流群，群昵称改为 GitHub ID | — | **用户** |
| A13 | 按官方通知提交验收（代码、README、测试、可复现的演示说明） | 提交材料和步骤见 `用户要做的事.md` | **用户** |

## B. 十月验收没过的三条

| ID | 问题 | 现在的行为 | 测试 |
| --- | --- | --- | --- |
| B1 | 国外坐标被 GCJ-02 偏移（首尔、河内），与 README“国外坐标不做偏移”的承诺不符 | 框内其他国家的陆地不偏移，正算和两种反算都原样返回 | `src/cn/boundary_test.mbt` “foreign cities are not offset”（22 个外国城市）；`src/cn/README.mbt.md` 中的文档测试 “out of china” |
| B2 | 矩形边缘反算误差约 0.00545° | 中国境内所有测试点往返误差 < 1e-9° | `boundary_test.mbt` 中的 “round trip next to the box edges”（四条边各 400 点）和 “round trip over the whole box”（1° 网格）；`boundary_wbtest.mbt` 中的 “round trip next to land borders”（隔一个取国界点，距离约 200 米和 900 米，8 个方向） |
| B3 | ±90° 处 UPS 计算出 NaN | 两极映射到 (2000000, 2000000)，反算回到 ±90° | `src/utm/README.mbt.md` 中的文档测试；`src/utm/claims_test.mbt` 中的 “bad zones, latitudes, and grid coordinates raise”；包说明里过时的“极点为 NaN”一句已删除 |
| B4 | 教训：测试全过，但有一条 README 承诺没有测试 | 本清单 C、D 节逐条对应 | 本清单 |

## C. 构建与测试（与 CI 一致）

| ID | 检查 | 命令 |
| --- | --- | --- |
| C1 | 警告视为错误 | `moon check --deny-warn` |
| C2 | 格式 | `moon fmt --check` |
| C3 | README 代码块就是测试代码 | `python3 tools/sync_readme_tests.py && moon fmt && git diff --exit-code -- src/examples/readme_check` |
| C4 | 接口文件最新 | `moon info && git diff --exit-code -- '*.mbti'` |
| C5 | 全部测试，4 个后端 | `moon test --target all` |
| C6 | 库代码没有 FFI | 在 `src/geodesic`、`utm`、`cn`、`internal`、`magnetic`、`conic` 中 grep 不到 `extern` |
| C7 | 示例在 4 个后端都能跑，结果正确 | wasm、wasm-gc、js、native 各运行 demo 和 s1–s6 |
| C8 | README 列出的命令行都能运行 | 依次运行 README 中的命令；无参数时的说明里要有 `enu reverse`；未知命令必须失败 |
| C9 | 能打包 | `moon package --list` |

## D. README 承诺逐条对应（根目录 `README.md`）

精度表里的每个数都是测试断言的界限，括号里是实测值。

| ID | README 的说法 | 测试或检查 |
| --- | --- | --- |
| D1 | 无 FFI，支持 wasm、wasm-gc、js、native | C6、C5 |
| D2 | 北京→上海 `r.s12 = 1066676.4 m`、`r.azi1 = 152.94°` | `readme_check/readme_claims_test.mbt` 中的 “README usage comments” |
| D3 | 航线插点间距不超过 100 km | 同 D2；另见 `geodesic/claims_test.mbt` 中的 “densify keeps consecutive points at most max_step apart” |
| D4 | 多边形逆时针为正 | 同 D2 |
| D5 | 伦敦→东京恒向线比测地线长 | 同 D2 |
| D6 | `bd09_to_wgs84` 往返 < 1e-9° | 同 D2；`cn_test.mbt` 中的 “exact inverses round-trip below 1e-9 degrees” |
| D7 | UTM 带号 50N、MGRS 为 `"50SMK4850217797"`、解码取 1 米格子中心 | 同 D2；`utm/claims_test.mbt` 中的 “MGRS precisions, centring, tabs, and limits” |
| D8 | Albers 下北京东坐标 956117.8 m；北京磁偏角 −7.56° | 同 D2 |
| D9 | 出错时抛出 `UtmError` | `utmups_test.mbt` 中的 “errors and formatting”；`utm/claims_test.mbt` |
| D10 | 命令行各命令及无参数时的说明 | `cli_wbtest.mbt` 全部 14 个测试（其中 “help lists every command” 覆盖新命令）；C8 |
| D11 | 6 个场景，CI 在每个后端都跑，结果不对就中止 | C7；中止条件见下面的 D11a–D11f |
| D11a | s1：混用原始坐标误差约 764 m | s1 要求在 760–770 m 之间，且往返误差 < 1 µm |
| D11b | s2：UTM 往返 < 1 µm，MGRS 格角在 √2 m 内 | s2 检查这两项，任何转换出错都中止 |
| D11c | s3：分段表格，各段 21/55/124 例 | s3 要求个数正确且误差都 < 8 nm |
| D11d | s4：面积和周长与 geographiclib 相对差 < 1e-12 | s4 检查；参考值由 `tools/gen_s4_reference.py` 生成 |
| D11e | s5：2 km 偏 263 m；漠河 −12.8°，喀什 +4.1° | s5 要求偏差在 260–266 m，两地磁偏角各在 ±0.05° 内 |
| D11f | s6：Albers 与椭球面积一致到 1e-8；兰勃特最多差 6%，Web Mercator 最多差 176% | s6 检查三项范围 |
| D12 | 各包说明里的示例都会运行 | `README.mbt.md` 里的 `mbt check` 代码块会被 `moon test` 运行（C5） |
| D13 | 测地线反算（GeodTest 1000 例）< 8 nm | `geodtest_test.mbt` 中的 “GeodTest inverse …” |
| D14 | 测地线正算 < 10 nm | `geodtest_test.mbt` 中的 “GeodTest direct …” |
| D15 | 与 Python geographiclib 2.1 对照 2020 例，相对差 < 1e-11 | `pyref_test.mbt` 的两个测试 |
| D16 | GeodesicExact 111 例：距离 < 8 nm，位置 < 1e-13° | `geodesic_exact_test.mbt` 中的 “GeodesicExact matches GeodSolve -E …” |
| D17 | 多边形 8 例，误差 < 地球面积的 1e-14 | `polygon_test.mbt` 中的 “polygon area and perimeter match geographiclib” |
| D18 | 恒向线：反算 < 4 nm，正算 < 11 nm，面积 < 5e-15 | `rhumb_test.mbt` 中的 “rhumb inverse …” 和 “rhumb direct …” |
| D19 | 交点 139 例：< 0.5 µm，两线交会到 < 10 nm | `intersect_test.mbt` 中 closest、offset、next、segment 四个测试 |
| D20 | ECEF/ENU 与 50 位精度公式及 PROJ 对照 < 20 nm | `local_cartesian_test.mbt` 中以 “geocentric …” 和 “local cartesian …” 开头的四个测试 |
| D21 | 横轴墨卡托、UTM、UPS 与 PROJ 对照 600 点 < 10 nm | `tm_test.mbt`；`utmups_test.mbt` 中的 “UTM matches PROJ” 和 “UPS matches PROJ” |
| D22 | MGRS 315/315 与 GeoTrans 一致 | `mgrs_test.mbt` 中的 “MGRS encoding matches GeoTrans” |
| D23 | 圆锥投影：50 位精度 < 25 nm，PROJ < 0.25 µm，GIGS 在舍入范围内 | 见 E 节 |
| D24 | WMM2025 精度 | 见 E 节 |
| D25 | GCJ-02 在中国境内 141 点 < 1e-11°；境外 59 点保持不变；BD-09 200 点 < 1e-11° | `cn_test.mbt` 的前两个测试 |
| D26 | GCJ-02 在框外和框内外国陆地上是恒等变换 | B1 的测试；`cn_test.mbt` 中的 “identity outside China” |
| D27 | 与官方 GCJ-02 约差 1 m | 无法测试（官方算法不公开）。README 已改为“据报道约 1 m，本库无法核实” |
| D28 | 横轴墨卡托在中央经线 3900 km 内误差为几纳米 | README 已改为引用 Karney (2011)，并注明本库测试到约 930 km |
| D29 | 级数测地线适用于 \|f\| ≤ 1/50，恒向线 ≤ 1/150 | README 已注明这是 GeographicLib 的建议，不是本库的测试结论 |
| D30 | 基准测试表 | 与机器有关，README 注明“仅供参考、单次测量”；CI 只做冒烟运行 |
| D31 | 每个参考数据集在 `tools/` 下都有生成脚本 | `gen_*.py` 共 16 个；s3 数据由 `gen_s3_accuracy.py` 逐字节重现，s4 常数由 `gen_s4_reference.py` 打印 |
| D32 | 代码规模表 | 2026-11-10 统计（见 README）；随代码变化需要更新 |
| D33 | `moon add` 安装后能得到 `conic` 和 `magnetic` | 需要发布 0.2.0（**用户**，见 M1） |
| D34 | 精确测地线的 DST 长度：\|f\| = 0.1 时 12，\|f\| = 0.5 时 24，最大 1536 和 4096 | `geodesic_exact_wbtest.mbt` 中的 “DST length used for the exact area (README claim)” |
| D35 | 极短线需要精确的 hypot | `geodesic/claims_test.mbt` 中的 “very short lines (accurate hypot) match geographiclib” |

各包说明（`src/*/README.mbt.md`）里的接口承诺对应以下测试：

- `geodesic/claims_test.mbt`、`utm/claims_test.mbt`、`cn/claims_test.mbt`；
- 各包已有的测试；
- 说明里的 `mbt check` 文档测试。

审计中查出的错误说法都已改正。逐条审计记录见 PR #37 的说明。

## E. 本期新增功能

| ID | 承诺 | 测试 |
| --- | --- | --- |
| E1 | WMM2025 与 NOAA 100 个官方双精度测试点一致：Y、Z < 2.5e-6 nT；X、H、F < 1e-3 nT；年变化率 < 2e-6 nT/yr；D、I 在打印的 2 位小数内 | `magnetic_test.mbt` 中的 “WMM2025 matches the 100 official double-precision test values” |
| E2 | 与技术报告表 6 的 12 个标准值一致（含格网磁偏角） | 同文件中的 “… report Table 6 …” |
| E3 | 与技术报告表 3b 的逐步算例在 10 位小数内一致 | 同文件中的 “report Table 3b …” |
| E4 | 格网磁偏角与表 3d 一致，UTM 收敛角来自本库 `utm` | 同文件中的 “report Table 3d …” |
| E5 | 与独立的 40 位精度计算（119 点）一致：< 1e-10 nT，年变化率 < 1e-13 nT/yr | 同文件中的 “WMM2025 matches an independent 40-digit evaluation” |
| E6 | 极点有限且连续；经度有周期性；年变化率与有限差分一致；派生量自洽 | 同文件中对应的 4 个测试 |
| E7 | 超出纬度、高度（−1 km 到 850 km）、日期（2025.0 到 2030.0）范围时报错 | 同文件中的 “domain errors” |
| E8 | `decimal_year` 与 NOAA 一致，包括闰年和非法日期 | 同文件中的 “decimal_year follows …” |
| E9 | 禁用区（H < 2000 nT）和警告区（H < 6000 nT） | 同文件中的 “compass zones …” |
| E10 | 罗盘方位与真方位互换，格网磁偏角 | 同文件中的 “bearing conversions”；`magnetic/README.mbt.md` 中的文档测试 |
| E11 | 圆锥投影与 50 位精度 EPSG/Snyder 公式一致（16 套投影、1592 点）：< 2.5e-8 m，收敛角 < 1e-12°，k < 1e-13，反算 < 2.5e-7 m | `conic_test.mbt` 中的 “matches a 50-digit evaluation …” |
| E12 | 与 PROJ 9.5 对照 < 2.5e-7 m；标准纬线极近的一组 < 1 cm | 同文件中的 “agrees with PROJ” |
| E13 | 通过 IOGP GIGS 5102、5103、5109 | 同文件中的 “IOGP GIGS 5102, 5103, 5109” |
| E14 | EPSG 指南 7-2 算例、Snyder 算例 | 同文件中的两个对应测试；`conic/README.mbt.md` 中的牙买加文档测试 |
| E15 | 兰勃特等角、Albers 等积，都用本库测地线量出来验证 | 同文件中的 “Lambert is conformal …” 和 “Albers is equal-area …” |
| E16 | 标准纬线上比例为 1；墨卡托和 UPS 极限；标准纬线极近时的情况 | 同文件中的 “scale is 1 …” 和 “limits …” |
| E17 | 参数非法时抛出 `ConicError` | 同文件中的 “invalid parameters raise ConicError” |
| E18 | 新增命令 `mag`、`lcc`、`albers` | `cli_wbtest.mbt` 中的对应测试；C8 |
| E19 | 新增场景 s5、s6 | C7，结果检查见 D11e、D11f |
| E20 | 参考数据可重现 | `tools/gen_wmm.py`、`gen_wmm_independent.py` 和 `gen_conic.py`。下载的数据文件校验 SHA-256，参考数据不使用被测代码的写法 |

## M. 需要用户做的事

| ID | 事项 | 怎么确认做完了 |
| --- | --- | --- |
| M1 | 发布 0.2.0 到 mooncakes.io | https://mooncakes.io/docs/ChrisTu117/moongeodesy 显示 0.2.0，并能看到 `conic` 和 `magnetic` |
| M2 | 同意合并 PR #34、#36、#37 | 三个 PR 都显示 Merged |
| M3 | 加入交流群，群昵称改为 GitHub ID `ChrisTu117` | 用户自查 |
| M4 | 按官方通知提交十一月验收 | 收到官方确认（QQ 邮箱或微信，请转告调度会话） |
