# 0.4.0 支持范围

## 多库查询与分析

Enricher 支持 1—4 个命名数据源；非法 IP 为整条输入错误，各库查询错误单独保留。单库投影与资源策略不变。enrich-many 先检查所有配置和数据库，再读取日志；单库和合计文件上限均为 256 MiB。完整处理结束才输出汇总，异常终止不会报告成功完成。配置、状态、退出码与独立分析模块限制见 [多库说明](MULTI_SOURCE.md)。新增 source-limit、invalid-source、duplicate-source、invalid-config 与分析示例的 group-limit 错误。

## 格式与查询

| 项目 | 支持状态 |
|---|---|
| MMDB 主版本 2 | 支持；保留 minor，不拒绝未知元数据字段 |
| 24/28/32 位节点 | 支持，官方 IPv4/IPv6/mixed 样例验证 |
| 更宽合法节点 | 不支持，返回 unsupported-record-size |
| IPv4 与 IPv6 | 支持严格文本解析；无 DNS、zone id、CIDR、方括号或带前导零 IPv4 |
| IPv4 查询 IPv6 库 | 按高 96 位零遍历；返回 IPv4 地址族前缀长度 |
| IPv6 查询 IPv4 库 | 返回 ip-version-mismatch |
| 映射/6to4 地址 | 遵循数据库别名；不自行重写 Teredo 或其他过渡地址 |
| 元数据指针 | 以元数据段为基址，区别于记录数据段 |
| 未命中 | Lookup.value=None，保留终止前缀长度 |
| 整库合法性认证 | 不提供；open 只验证元数据、布局及分隔符，lookup 验证实际访问路径 |

## 类型与 JSON

Value 区分 Text、Blob、Boolean、Unsigned16/32/64/128、Signed32、Real32/64、List、Object。UInt128 使用精确十进制字符串；UInt64 使用 MoonBit UInt64。Real32 / Real64 携带 Float32Value / Float64Value：bits 保存原始位，number() 提供运算数值。这是相对 0.1.0 的类型变更，可保留 signaling NaN 的原始位。map 保留原条目顺序；重复 key 被本读取器策略拒绝，不宣称所有此类编码都违反格式。

CLI 使用带类型 JSON，例如 `{"type":"uint128","value":"340282366920938463463374607431768211455"}`。所有整数的 value 都是字符串；字符串与布尔保留对应 JSON 类型；bytes 是小写十六进制；map 的 value 是对象，array 的 value 是数组。浮点包含 type、展示用 value 字符串、精确 bits 十六进制，可保留非有限值和负零。

JSON 编码是 MoonMMDB 的接口约定，不保证与其他 CLI 的无类型输出相同。用户自行构造的 Value 不经过读取器的资源限制；限制承诺针对通过 Reader 解码得到的结果。

## 资源策略

| 参数 | 默认值 | 可配置上限 |
|---|---:|---:|
| max_depth | 128 | 256 |
| max_values | 65,536 | 1,000,000 |
| max_payload_bytes | 2 MiB | 64 MiB |
| max_file_bytes | 256 MiB | 512 MiB |

每次 open 或 lookup 使用自己的预算。max_values 是解码工作量计数，容器、键、值及指针控制也计数；与规范示例中不单独计指针的计数方式不同，可能更早拒绝指针密集数据。max_payload_bytes 按每次展开的字符串/bytes 字节收费，在复制和 UTF-8 解码前检查；不是整个进程的 RSS 上限。查找树最多遍历 32/128 位，未终止则报错。数组/map 在进入子项前预检声明数量，避免由声明长度直接大规模分配。

Reader 打开时保存输入快照，避免 JS 宿主修改原始 Uint8Array 后使已验证布局失效；这会增加打开时间和一份数据库存储。当前未做缓存、mmap 或惰性字段解码。

CLI 数据库上限固定为每份 256 MiB。JSONL 从普通文件或标准输入逐行读取，默认总量 8 MiB、单行 8 MiB、10,000 行；总量可配置至 1 GiB，记录数可配置至 1,000,000，单行最多 8 MiB（包含 CR，不包含 LF）。等待每行输出完成后再继续处理。输入缓冲区有界，但数据库快照、解码结果和输出字符串仍占内存，这不是进程 RSS 上限。

某行错误不撤销此前输出，最终退出码 2 表示运行存在错误。超限、损坏 UTF-8 或输出失败会停止读取；整次处理可能已产生部分输出。空白行是错误，最后一行可以没有换行；仅文件起始的 UTF-8 BOM 被移除。原 JSON 对象直接嵌入结果，数值不重新编码。默认取 /ip，可用 --ip-path 读取嵌套属性和数组；只访问对象自身属性，JSON.parse 的重复键取末值语义保持不变。输出管道失败尽可能记录在 stderr，退出码 2。

## 字段提取

`Value.at_pointer`、`Reader.project`、`validate_paths` 使用 [RFC 6901](https://www.rfc-editor.org/rfc/rfc6901) 字符串形式，支持 `/country/iso_code`、`/array/0`、空路径（根记录）、~0 与 ~1。不提供 URI fragment 形式；数组前导零、负数、越界或非数字下标作为未解析字段。不存在的键、标量的子字段返回 None / missing；语法错误返回 invalid-path。对象键按原字符比较，不做 Unicode 归一化。

project 允许 1–64 个不同路径，每个最长 2,048 个 UTF-16 码元、128 段；超出返回 path-limit。先完整解码并验证记录一次，再选字段。每条结果保留 record_found / prefix_length，字段缺失独立表达。投影全部字段的值数与载荷另用一份同额预算，重叠路径重复计数，不允许借多次输出放大载荷。这个预算针对数据内容，不是 JSON 输出长度或进程总 RSS。CLI enrich 在读取记录前验证路径，因此空文件不会掩盖错误配置。

prepare_fields 返回不透明 FieldSelector，保存路径数组的副本并预先解析路径。Reader.project_prepared 可跨查询和 Reader 复用选择器；不缓存数据库记录，修改调用方的配置数组或上一次返回结果不会污染下一次查询。Reader.project 作为兼容入口仍可使用。

## 数据库差异检查

Reader.compare / compare_prepared 对同一个 IP 查询两份 Reader，分别应用各自的解码与选择预算。返回 RecordDiff，独立报告 record_changed、prefix_changed 和 changed_fields，并包含 before / after 字段值。map 顺序不参与比较，数组顺序、整数类型、字节与浮点原始位参与比较。仅选择 /country/iso_code 时，不报告未选择的城市字段变化；命中状态与前缀仍参与比较，包括两侧均未命中但终止前缀不同的情况。

CLI diff 未给 --field 时选择整个记录（空路径），只检查输入中的 IP，不枚举整个数据库。stdout 每行包含 input 与 diff，完成后 stderr 给出 processed / changed / unchanged / errors 汇总。退出码为 0 无差异、1 有差异、2 有错误；发生输入流中断时不输出完成汇总。数据库类型、构建时间等元数据不作为 IP 记录差异，可通过 metadata 单独检查。两份完整数据库与快照同时驻留内存。

## 错误

主要 code：invalid-ip、ip-version-mismatch、missing-metadata、invalid-metadata、unsupported-version、unsupported-record-size、invalid-layout、invalid-separator、invalid-tree、invalid-tree-pointer、out-of-bounds、invalid-size、invalid-utf8、invalid-map-key、duplicate-key、unsupported-type、pointer-to-pointer、pointer-cycle、depth-limit、value-limit、payload-limit、file-limit、invalid-limits。CLI 的 host-input-error 与 invalid-jsonl 属于宿主输入层。

新增 code：invalid-path、path-limit、host-output-error；流式宿主还报告 input-limit、line-limit、record-limit、invalid-utf8，并在可定位时给出行号。offset 以整份文件的字节位置计数；无法定位到具体编码字段的树/路径/非文件错误返回 -1。错误不会转为 not_found 或无差异。

## 后端

后端验证范围为 JavaScript、Wasm GC 及固定 Windows x64、MoonBit 0.10.11、GCC 16.2.0 的 Native。Ubuntu CI 还运行 Linux Native 核心及独立分析模块测试；范围不含 Linux 产品 CLI。当前证据见 [0.4.0 验证](VERIFICATION_0_4.md)，0.2.0 / 0.3.0 历史证据保留。当前 MoonBit nightly 文档推荐的 Windows MSVC 路径尚未验证；不能外推为最新工具链支持。

产品 CLI 仍使用 Node.js。独立 Native 文件验证程序见 examples/native_probe，宿主 C 代码只负责路径、文件与计时，核心 MMDB 包不依赖 C 读取器。Windows 实际运行已覆盖中文、空格及非 BMP 字符路径。未验证 macOS、Linux 文件宿主、浏览器 UI 或 WASI Component。

Windows Native 与 JS 分别读取完整的 DB-IP Lite 2026-09 Country（8,340,464 字节）、City（127,339,927 字节）与 ASN（9,511,026 字节）文件，每库抽查 5,000 地址。额外对 City＋ASN 联合查询每库抽查 7,114 地址，两个后端分别完成 14,228 次结果对照，并由独立 Python maxminddb 3.2.0 核对分析统计。结果是抽样读取正确性证据，不是全记录、真实定位准确率、商业数据库或长期服务稳定性证明。[当前证据与复现](VERIFICATION_0_4.md)
