copyleftdev/whatthediff
GitHub: copyleftdev/whatthediff
一款用 Zig 编写的零依赖确定性语料库分析工具,能在多种格式的 N 个文件之间自动识别共识、偏移、异常值和变体家族。
Stars: 0 | Forks: 0
#
WhatTheDiff
**传统的 diff 工具回答的是“发生了什么变化?”——而 WTD 回答的是“什么才是真正重要的?”**
[](https://ziglang.org)
[](#-testing)
[](#-testing)
[](#-scale)
[](#-testing)
[](#-architecture)
[](#-quick-start)
将 WTD 指向 **N 个制品** —— 配置、JSON、YAML、Markdown、日志,任何文本内容 ——
它会告诉你它们在哪里达成了一致,哪里发生了偏移,哪一个属于异类,
并展示每一个结论背后的**证据**。确定性引擎是
事实的来源;AI 只是负责解释引擎证明了什么。
```
$ wtd configs/
WhatTheDiff — corpus analysis
Corpus: 5 artifacts · 12 distinct primitives · 34 observations
Consensus
universal 2 (present in all 5 artifacts)
majority 5
minority 0
unique 5
consensus core: 7 primitives
Drift (distance from consensus core, 0 = pure consensus)
0.727 configs/svc-d.yaml ⚠ OUTLIER
0.375 configs/svc-c.yaml
0.000 configs/svc-a.yaml
...
Evidence — unique primitives
configs/svc-d.yaml (4 unique)
kv admin_backdoor=enabled (line 7)
kv tls=false (line 5)
kv db.host=10.9.9.9 (line 3)
```
## ✨ 为什么选择 WTD
- **语义重于语法。** 键的顺序、空格、引号和注释永远不会
被视为差异——只有事实会。
- **证据重于直觉。** 每一个观察结果都会回答:是什么,在哪里,在多少个
制品中,以及我能否检查证据?
- **确定性重于魔法。** 相同的语料库输入 -> 字节完全相同的报告输出。
LLM(路线图)解释结论;它绝不会捏造结论。
## ⚙️ 工作原理
```
artifacts → normalization → primitive extraction → canonical form
→ BLAKE3 identity → evidence store → consensus → drift → report
```
制品绝不会作为原始文本进行比较。每个制品都会被分解为
**原语** —— 稳定的语义事实:
| 类型 | 来源 | 规范形式 |
|-------------|---------------------------------------|--------------------------------|
| `kv` | JSON, YAML-lite, XML-lite, config | `db.port=5432`, `features[]=x` |
| `heading` | Markdown | `h2:Deployment` |
| `line` | PDF 文本,文本回退 | 规范化的文本行 |
| `chunk` | 二进制 / 可执行文件 (SSDeep 风格) | 内容定义的分块哈希 |
每个原语的身份标识是 `BLAKE3(kind ‖ 0x00 ‖ canonical)`。
**规范形式是跨格式的**:JSON 中的 `{"db":{"port":5432}}`,
YAML 中的 `db:\n port: 5432`,INI 中的 `[db]\nport = 5432`,以及
XML 中的 `
将 wtd 指向一个包含可执行文件的目录,它会执行 **SSDeep 级别的模糊
分析** —— 并且具有自我解释能力。每个二进制文件都会被切分为*内容定义的
分块*(与 SSDeep/CTPH 内部使用的基于内容触发的分段哈希技术相同:滚动哈希根据字节确定分块边界,因此
插入或删除数据只会干扰附近的分块,其余部分会自动重新同步)。
每个分块都是一个原语,因此现有的共识/偏移/**派系**引擎
可以根据共享代码对二进制文件进行聚类 —— 并告诉你*哪些*分块,以及在什么字节
偏移量处。
```
$ wtd ./samples --factions
Factions (groups deviating from consensus in the same way)
faction of 3 · cohesion 1.00
members: samples/mathapp-v1, samples/mathapp-v2, samples/mathapp-v3
shared: chunk f722a9b73035213b… (3/3 members)
faction of 3 · cohesion 1.00
members: samples/textproc-v1, samples/textproc-v2, samples/textproc-v3
shared: chunk 2123887eae9ddcfe… (3/3 members)
```
六个剥离符号的 ELF 二进制文件,两个家族各包含三个变体 —— 在没有任何其他信息的情况下,仅凭字节就正确地进行了聚类。与 SSDeep 的成对 0–100 分数不同,
你可以获得家族聚类结果、以共享与独有区域形式呈现的证据,以及
`wtd ask "which binaries are variants of the same program?"` 的提问能力。单个
`binary.format=elf/x86_64` 原语也会按平台进行分组,因此在 ELF 文件中混入的
孤零零的 PE 文件甚至在分块分析开始之前就会被识别为异类。支持识别 ELF, PE,
Mach-O, Wasm 和 JVM/ar 格式;任何其他二进制文件都会按通用方式进行分块。可执行文件扩展名(`.exe .dll .so .dylib .bin .o .wasm` ……)
会被路由到此处,而那些被探测识别为二进制文件的无扩展名文件也会进行此处理。
## 🧪 测试
三个确定性层级:
**单元测试** —— 针对每个模块的契约(提取器、存储、分桶、渲染器)。
**基于属性的测试** (`src/proptest.zig`) —— 使用带有种子的随机语料库,对照
独立的检查器进行 QuickCheck 风格的验证;每次失败都会打印其种子:
- **计数检查器** —— 分析结果必须与根据
原始成员关系矩阵重新计算的统计数据相符(分桶、核心、精度达到 1e-12 的偏移度、Σ 总数 = Σ k)
- **排列不变性** —— 输入顺序永远不会影响分析结果
- **孪生属性** —— 相同的制品获得相同的统计数据
- **植入异常文件** —— 在正常文件中混杂大量独有数据的制品*总是*
会被标记为异类
- **JSON 等价性** —— 重新序列化时打乱键顺序并添加随机
空格的文档会生成完全一致的原语
- **Pipeline 确定性** —— 相同的磁盘语料库 -> 字节完全相同的 JSON 报告
**规模基准测试** (`scripts/bench.sh`) —— 生成包含植入异常文件的确定性语料库
(使用 `gencorpus`),然后**除非 WTD 在各种规模下都精确地标出了
被植入的集合,否则测试失败**。
## 📈 规模
实测于 2026-07-07,ReleaseFast 模式 (v0.5.0 流式存储):
| 文件数 | 植入异常文件数 | 挂钟时间 | 单文件耗时 | RSS | 结论 |
|---:|---:|---:|---:|---:|:---:|
| 1,000 | 20 | 0.02 s | 20 µs | 4 MB | ✅ 精确 |
| 10,000 | 200 | 0.18 s | 18 µs | 37 MB | ✅ 精确 |
| 50,000 | 1,000 | 0.93 s | 19 µs | 186 MB | ✅ 精确 |
| 200,000 | 4,000 | 3.88 s | 19 µs | 754 MB | ✅ 精确 |
| **1,000,000** | **20,000** | **21.8 s** | **22 µs** | **3.8 GB** | ✅ 精确 |
单文件处理成本是**恒定的** —— 耗时呈线性增长,在各种规模下均无假阳性
(在 100 万文件时:包含 256 万个不同原语,4180 万条观察记录,所有
2 万个植入的异常文件均被准确标记,零假阳性)。流式
证据存储将文件内容和解析树保留在按制品划分的内存池中,该内存池会在处理完每个文件后重置,因此**常驻内存的增减与不重复的事实数量成正比,而非语料库的字节大小** —— 在 100 万文件规模下,仅引擎运行时的 RSS 为 3.35 GB
(对于该语料库配置,约等于 3.3 KB/制品);`--json` 会在此基础上额外生成物化的报告。超大(>64 MiB)的制品会被干净地跳过,永远不会
导致致命错误。
```
scripts/bench.sh # 100 → 50k files, yaml
SIZES="200000" scripts/bench.sh # bigger
FORMAT=json scripts/bench.sh # json corpora
```
## 🏗 架构
```
src/
types.zig core contracts: Artifact, Primitive, Identity, Occurrence
discovery.zig paths → sorted candidates (skips VCS/dot dirs, binaries)
extract.zig kind → extractor dispatch, graceful text fallback
extractors/ json · yamlish · config · markdown · text
hash.zig BLAKE3 primitive identity
evidence.zig identity → observation (occurrences, artifact counts)
analysis.zig consensus buckets, core, drift, outlier detection
render.zig deterministic text + JSON reports
engine.zig pipeline orchestration
cli.zig argument parsing, exit codes
tools/gencorpus.zig deterministic corpus generator for scale testing
```
契约优先,由小型可组合模块构成,没有隐藏状态,没有依赖。
每个模块都可以独立测试和替换;提取器会优雅降级
(格式错误的 JSON 会回退为行原语)而不是直接报错。
## 🗺 路线图
- [x] `wtd ask "why is contract_17 different?"` —— 解释
证据图的 AI 适配器 (v0.2.0: Anthropic / OpenAI 兼容 / 本地端点)
- [x] 跨格式规范化统一 (v0.3.0: JSON, YAML 或 INI 中的相同事实 -> 相同的身份标识;通过双向序列化的随机结构进行属性测试)
- [x] 成对相似度 / 聚类 —— 不仅仅是识别异类,还能发现派系
(v0.4.0: 少数集 Jaccard + 并查集,派系签名,通过属性测试
精确恢复被植入的派系)
- [x] 面向数百万制品的流式证据存储 (v0.5.0: 每个制品的独立内存池 + 单副本规范形式 + u32 引集;100万文件耗时 21.8 秒 /
RSS 3.8 GB,检测结果依然精确)
- [x] XML 提取器 (v0.6.0: 支持实体/CDATA/DOCTYPE 的 XML-lite;属性
与子元素统一;在随机结构上针对 JSON 进行了属性测试)
- [x] PDF 文本提取器 (v0.7.0: 零依赖 —— 通过
std.compress.zlib 实现 FlateDecode,支持文本操作符 BT/Tj/TJ/quote,转义/十六进制/CID 过滤;
对照 pandoc/LaTeX 和 ghostscript 输出进行了验证;包含往返属性测试)
- [x] 二进制 / 可执行文件模糊分析 (v0.8.0: 内容定义的分块 —— SSDeep/CTPH 的核心 —— 使得共识/偏移/派系引擎能够根据共享代码对二进制文件进行聚类;验证了对真实编译的 ELF 变体进行家族
聚类的能力;支持对 ELF/PE/Mach-O/Wasm 的格式+架构检测)
- [ ] 源代码提取器(超越行级别的语义分析)
## 📜 设计说明
完整的工程理念 —— 确定性 Pipeline、证据模型、
AI 的职责、非目标 —— 请参见 [intent.md](intent.md)。标签:Homebrew安装, Zig, 数据一致性, 文件比对, 文本分析, 模糊哈希