# MPHF 验收问题整改记录

本次修复保留不可变索引、持久游标和校验解码的原有承诺。

| 验收反馈 | 根因及修复 | 可复现证据 |
| --- | --- | --- |
| 公开数组可改变已构造映射 | `pub struct` 暴露了可变数组引用；索引、嵌套容器和已校验补丁的内部字段改为私有，数组导出接口返回副本 | `tests/public/snapshot_test.mbt` 修改输入、导出数组和解码输入缓冲区，原对象查询结果保持不变 |
| 后继游标可改变保留检查点 | 游标推进共享数组，但原来允许调用者读取并修改它；封闭游标全部状态，继续共享不可由外部修改的数据 | 外部包检查拒绝访问游标数组及位置；公共接口测试验证 set/map/multimap 分支推进、导出数据修改后旧检查点仍可重放 |
| 原始 MPHF 解码后可能返回负槽位 | 元数据未约束键数与顶点数关系，且三个表项直接用 32 位 `Int` 相加 | 完整极大计数载荷现在返回 `InvalidMetadata`；槽位、反向赋值和构建容量使用 `Int64` 中间值，容量不可表示时返回 `CapacityExceeded` |

修复前新增的两个算术回归用例均失败：极大计数载荷被接受；
槽位应为 `852516353` 时实际得到 `-1294967296`。
外部包封装检查在修复前也发现 `Mphf.values` 可直接读取。
这些用例保留在仓库中，供后续回归。

## 复现步骤

在仓库根目录运行（使用 MoonBit 工具链和 Python 3）：

```text
moon check --deny-warn
moon test --deny-warn
moon test --release --deny-warn
moon test --target js --deny-warn
python scripts/check_encapsulation.py
moon build --release --deny-warn
moon run cmd/main
moon info
moon fmt
```

`tests/public` 是独立包，仅能使用库的公开接口。
`scripts/check_encapsulation.py` 先验证外部包能正常调用查询接口，
再逐项尝试读取 41 个内部字段，要求编译器给出访问限制错误；
它不会把环境错误或任意编译失败当成封装成功。
临时探针包在检查结束时删除。CI 已纳入这一检查及可运行示例。

本地验证结果（moonc `v0.10.14`）：默认目标、release 模式和 JavaScript
后端均为 36 项测试通过；41 个字段的外部访问全部被拒绝。
`moon check --deny-warn`、release 构建及 CLI 示例通过；
`moon info`、`moon fmt`、`git diff --check` 已运行。
这些是本地结果，远端 CI 结果需在提交后另行确认。

## 算法复查与游标优化

- 增加包含 `0`、`Int` 最大值和多种规模键集的跨包检查，验证完美槽位、
  精确映射、解码后查询及分片查询一致，并检查未知键不会命中。
  其中 256 键用例的某个分片曾耗尽默认 64 次构建重试；默认上限提高为
  256 次后通过。显式配置的较小预算保持有效，构建仍可能返回
  `ConstructionFailed`，不承诺任意输入必然构建成功。
- 所有游标直接共享已封装的索引存储，创建不再复制整个索引。
- 多值游标通过全局值下标在 O(1) 时间得到剩余数量，完整扫描不再逐项
  重扫后续分组。新增跨 200 个分组、包含不同组长度的逐步遍历回归用例，
  检查组内顺序、剩余数量、耗尽行为及旧检查点重放。
- `mphf_bench.mbt` 增加创建 4,000 键游标与扫描 8,000 个多值条目的基准；
  用 `moon bench --release --deny-warn` 可重现。测量只代表本机、该数据集和
  该后端，不表示所有工作负载的性能保证。

2026-10-17 本机 Windows、默认 Wasm 目标、release 基准（moonc `v0.10.14`），
比较对象为已修正封装及算术的实现，在游标优化前后各运行一次完整基准，
每项由基准工具执行 10 批测量。下列数值为均值，存在运行噪声：

| 基准 | 游标优化前 | 游标优化后 |
| --- | --- | --- |
| 创建 4,000 键游标 | 532.75 ns | 76.23 ns |
| 扫描 8,000 个多值条目 | 2.26 ms | 1.13 ms |

这只支持上述两个游标工作负载的改善；不据此声称 MPHF 构造或所有查询更快。

## 接口与发布边界

- 原先直接读取实现字段的调用者，需要改用查询、统计、游标和副本导出方法。
- `StaticSetPatch`、`StaticIntMapPatch` 必须经 `new` 或解码器构造。
- 新增 `CapacityExceeded(Int)` 错误；穷尽匹配错误类型的调用者需要处理它。
- 构造器产生的正常 word 流保持原格式；原始 MPHF 解码仍只提供结构校验，
  没有源键清单时不能证明其对某一键集完美。
- `0.1.0` 不含本次修复；修复版为 `clbbbb/moon-mphf@0.2.0`。
  核心修复与优化对应 GitHub commit `924e5e8`，该提交的 CI 已通过。
  正式复验时应提供新版本链接和 CI 记录。
