copyleftdev/whatthediff

GitHub: copyleftdev/whatthediff

一款用 Zig 编写的零依赖确定性语料库分析工具,能在多种格式的 N 个文件之间自动识别共识、偏移、异常值和变体家族。

Stars: 0 | Forks: 0

# Peek, the WhatTheDiff mantis shrimp mascot WhatTheDiff **传统的 diff 工具回答的是“发生了什么变化?”——而 WTD 回答的是“什么才是真正重要的?”** [![Zig](https://img.shields.io/badge/Zig-0.14-f7a41d?logo=zig&logoColor=white)](https://ziglang.org) [![测试](https://img.shields.io/badge/tests-64%2F64-brightgreen)](#-testing) [![属性迭代](https://img.shields.io/badge/property_iterations-1065-brightgreen)](#-testing) [![规模](https://img.shields.io/badge/1M_files-22µs%2Ffile-blue)](#-scale) [![确定性](https://img.shields.io/badge/reports-byte--identical-8A2BE2)](#-testing) [![依赖](https://img.shields.io/badge/dependencies-0-lightgrey)](#-architecture) [![平台](https://img.shields.io/badge/platforms-Linux%20·%20macOS%20·%20Windows-informational)](#-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 中的 `` 都会哈希到相同的身份 —— 一个混合格式的 语料库能找到真正的共识,而不是根据格式分裂成不同的派系。XML 属性与子元素统一(属性与元素的区别是语法,而不是 语义)。列表没有索引(`features[]=x`),因此重新排序列表 不算偏移。每个身份都会保留其完整的出现 记录(制品 + 行号):没有任何结论是缺乏可检查证据的。假设有 N 个制品,其中 k 个包含了某个原语: **共识核心**是指由绝对多数制品持有的每一个原语。一个 制品的**偏移度** 为 1 − Jaccard(其原语, 核心);异类的 判定标准为均值 + 1.5σ (N ≥ 4)。 **派系** 的概念超越了单纯的异类识别:聚类仅在*少数派*原语 上进行(核心无法区分不同的组;独有的原语只属于单个 文件),因此一个派系精确地代表了一组共享相同偏差的文件 —— 边权重为 Jaccard ≥ 0.5,通过并查集寻找连通分量,并且每个派系都会报告其 *签名*(`region=eu (3/3 成员)`)。符合共识的文件 构成了隐式的主干组,永远不会被单独列出。 ## 🚀 快速开始 **一行命令** (Linux, macOS, Git Bash —— 自动检测操作系统/架构,验证 SHA256,安装到 `/usr/local/bin` 或 `~/.local/bin`): ``` curl -fsSL https://raw.githubusercontent.com/copyleftdev/whatthediff/main/install.sh | sh ``` **Windows PowerShell:** ``` irm https://raw.githubusercontent.com/copyleftdev/whatthediff/main/install.ps1 | iex ``` 使用 `WTD_VERSION=v0.5.0` 固定版本,使用 `WTD_INSTALL_DIR` 选择目录。或者直接从 [Releases](../../releases) 下载二进制文件 —— 静态编译,无需安装,支持 Linux (x86_64/aarch64,完全静态的 musl),macOS (Intel/Apple Silicon) 和 Windows (x86_64/aarch64)。或者从源码构建: ``` zig build -Doptimize=ReleaseFast # → zig-out/bin/wtd (Zig 0.14, zero deps) zig build test # unit + property + e2e tests zig build release # cross-compile all six targets scripts/release.sh # test + package dist/*.tar.gz|zip + SHA256SUMS ``` | 命令 | 结果 | |---|---| | `wtd ...` | 完整的人类可读报告 | | `wtd configs/ --drift` | 仅显示偏移度排名 | | `wtd configs/ --consensus` | 仅显示共识分桶 | | `wtd configs/ --factions` | 显示偏离共识的文件分组 | | `wtd configs/ --json` | 机器可读的证据图 (`wtd.report.v1`) | | `wtd configs/ --json --evidence` | 不设上限的出现记录 | | `wtd ask "" configs/` | AI 解释证据(见下文) | ## 🤖 wtd ask ``` $ wtd ask "why is svc-d.yaml different from the others?" configs/ ``` 确定性引擎首先运行,并筛选出与你的 问题相关的证据 —— 聚焦文件的独有原语(带有行号)、它*缺失*的 共识核心原语,以及语料库偏移表。该 证据块是模型**唯一**能看到的内容,它在系统提示词的约束下运行:禁止陈述证据块中不存在的任何内容,并要求使用 `(path:line)` 进行引用。引擎负责证明;AI 负责叙述。它永远无法捏造结论。 支持三种类型的提供商(按以下顺序检查): | 提供商 | 配置方式 | |---|---| | 任何自定义/本地端点 (Ollama, llama.cpp, vLLM) | `WTD_AI_URL=http://localhost:11434/v1/chat/completions WTD_AI_MODEL=` —— 无需密钥 | | Anthropic Messages API | `ANTHROPIC_API_KEY=...` (默认模型 `claude-opus-4-8`) | | OpenRouter / OpenAI 兼容 | `OPENROUTER_API_KEY=...` (支持 `OPENROUTER_BASE_URL`, `OPENROUTER_MODEL`) | `--model ` 会覆盖模型;`--dry-run` 仅打印确切的提示词 (系统提示 + 证据)而不调用任何接口 —— 这对于审计模型 被允许知道的内容非常有用,且不需要密钥。 ## 🔬 二进制和可执行文件分析 Peek in RE mode — the mascot suited up with a scanner cannon and targeting reticle for hunting through binaries 将 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, 数据一致性, 文件比对, 文本分析, 模糊哈希