# dialnumber 开发回顾与技术解释

本文为十月最终验收整理，描述 0.8.1 的实际结构与已知边界。项目已在 10 月 27 日后续修改前通过报名初审；本文不将初审结果归因于后续改动。

## 项目要解决什么

同一个号码有国内拨号形式、带国际前缀的形式、E.164 和 tel URI。MoonBit 业务需要可复用的解析、规则校验、显示和比较能力，而不能只靠字符串长度。核心运行库全部是 MoonBit；Node/Java 用于数据生成和独立验证，用户调用库不需要它们。

## 三个主要设计取舍

### 数据与逻辑分开

地区 JSON 是生成器输入；plan_data.mbt 是编译后的派生表，不是唯一人工事实源。非地理服务使用独立的调用码表，避免把网络伪装成国家。数据同时保留总体模式、类型模式、长度、前缀及显示规则，逻辑通过 region.mbt 和 valid.mbt 查询它们。

这比为每个国家复制判断函数更便于更新和审查。代价是必须验证抽取、生成和实际引擎的一致性：每个生成器都有 check 模式，数据自带公开样例，另有独立参考期望。

### 自写有限文法的模式引擎

pattern.mbt 解析号码计划用到的正则子集，编译为 Thompson NFA，再以活状态集合模拟，不做递归回溯。匹配成本随模式和输入长度增长。无法解析的规则匹配失败，不降级为接受所有输入。

NFA 规则缓存避免每次验证重新编译。这个决定保留零外部运行时依赖，也明确放弃通用正则引擎的任意扩展语法。模式引擎有单独差异语料，电话号码语义还有独立库对照，两者不能混为同一种验证。

### 可能、有效和实际可达分开

is_possible 询问编号计划能否接受这个长度（NANP 另检查结构），is_valid 询问类型规则是否接受该号码。二者都不能证明线路存在、可拨通或归属某人。PhoneNumber 保存字符串形式的 national_number，保留意大利等计划中有意义的前导零。

## 本期功能演进

| 提交节点 | 可核对的工作 |
| --- | --- |
| 10 月 8 日起的历史 | 模块、字符串工具、号码模型、解析与格式化基础 |
| 78ee519 / d950e47 | 上下文按计划求解及回归用例 |
| e9dbea8 | 号码匹配能力 |
| 65a5b59 | 实时格式化能力 |
| 84de710 | 非地理网络支持 |
| 9ff7809 | 比较/输入前缀/非地理长度/上下文边界修复，固定参考数据及 CI 检查 |

这些历史保留原顺序，不通过空提交或拆分提交制造工作量。运行 git log 可查看完整记录。生成表和生成测试的行数不作为手写算法工作量。

## 四个实际发现的问题

1. **国家码不同但本地数字一样**：旧比较函数会产生 NSN 匹配；现在不同显式国家码直接 NoMatch，国家码 0 才表示未知。
2. **边输入边格式化丢数字**：过短模板吞掉多余输入，或给已输入号码再加一个长途前缀；现在每次模板输出必须保留所有输入数字，超出模板回退原数字。
3. **非地理号码的 possible**：只检查调用码存在会放过过短服务号码；现在使用网络各类型公布的长度集合。
4. **上下文被猜测为前缀**：任意数字 context 不能盲拼，也不能因为本地部分刚好有效就忽略它。默认仅支持明确公开编号计划约定；域名和 PBX 需要显式 authority 回调。

## 为什么参考测试不直接等于 100% 兼容

JS 参考语料固定 libphonenumber-js 1.11.20/max，含 2,299 条输入；15 条案例涉及 30 个已知字段差异，原因包括元数据年代、七位本地号范围和分隔符约定。
Google 原版 Java 9.0.17 记录 17 个号码流程、6 个比较和6 个逐键序列；13 处中间空格/括号布局不同，完整输出和数字一致。所有差异都保留两边的期望，不能删样例来声称全兼容。

原始记录、版本、校验和、生成脚本、异常清单和生成断言都随仓库提供；Java/npm 仅在重建原始记录时使用。具体清单见 compatibility.md 和 google-compatibility.md。

## AI 的参与与责任

AI 助手参与实现检查、缺陷修复、测试/语料脚本、文档整理及工具执行；用户提出项目方向、验收目标、补充审核状态并授权仓库发布。本文记录可以通过源码与日志核查的技术决策，不声称用户已经逐行人工审阅全部 AI 修改。

测试与 CI 是技术检查，不证明参赛者已经理解实现。作者应能沿着 examples/basic 的输入解释 parse、valid、format、match 和 context 的调用路径；下方问题可用于实际演示时自查。

## 演示时需要解释的五个问题

- 为什么 possible=true 仍可能 valid=false？指出长度规则与类型规则的区别。
- 为什么国家码 0 与明确不同的国家码处理不同？解释不知道与冲突的区别。
- 为什么 +1-914 能完成一个七位号，但任意 PBX context 不能？指出这是明确约定，不是 RFC 的通用拼接算法。
- 为什么用了上游数据仍有独立实现工作？展示 NFA、解析器、类型优先级和格式规则解释器。
- 为什么不删除不一致参考样例？解释元数据快照、显示约定与逻辑缺陷如何区分。

## 来源与边界

编号数据来自 Google libphonenumber，独立参考还使用其原版 Java 实现与 libphonenumber-js；许可证和变换记录见 THIRD_PARTY_NOTICES.md。
库不提供运营商在线查询、地址查询或号码归属人的判断。少数 nationalPrefixTransformRule 和完整交互编辑不在当前范围。所有边界以 known-limitations.md 为准。

验收标准及证据统一维护在 [验收材料.md](验收材料.md)，实际命令输出维护在 reproducible-demo.md。正式验收结论由组委会给出，本文是可解释性与复现材料。
