Skip to content
Open in github.dev Open in a new github.dev tab Open in codespace
redhat-etPublic

The ripgrep of AI context: a zero-dependency C++23 CLI + MCP server giving coding agents a ranked, deterministic map of any repo, blast radius, tests-to-run and quality deltas. Signatures at 80% fewer bytes than bodies; ~5% of a grep-and-read pass's tokens.

Apache License 2.0
Public repository

Add file

Latest commit

93c8eda · Sep 6, 2026

History

1,724 Commits

Folders and files

NameName
Last commit message
Last commit date
Aug 5, 2026
Sep 6, 2026
Sep 6, 2026
Aug 27, 2026
Sep 6, 2026
Sep 5, 2026
Aug 3, 2026
Sep 5, 2026
Aug 8, 2026
Sep 3, 2026
Sep 5, 2026
Sep 5, 2026
Sep 6, 2026
Sep 6, 2026
Aug 21, 2026
Aug 3, 2026
Aug 1, 2026
Aug 3, 2026
Aug 29, 2026
Aug 5, 2026
Aug 23, 2026
Sep 6, 2026
Jul 31, 2026
Sep 4, 2026
Sep 5, 2026
Aug 27, 2026
Jul 31, 2026
Aug 29, 2026
Jul 31, 2026
Sep 6, 2026
Jul 31, 2026
Aug 21, 2026
Aug 27, 2026
Aug 2, 2026

Repository files navigation

ripwire — the ripgrep of AI context

CI Release Licence Standard Runtime dependencies Slides

Rip'n Fast. Less Tokens. Better Code.极速运行。更少 Token。更好代码。

Give your coding agent a map before it reads the repo.在你的编程智能体读取代码库之前,先给它一张地图。

ripwire is the ripgrep of AI context. Point it at any repository and your agent gets a ranked, deterministic call graph — what to touch, what it breaks, which tests to run — instead of grepping around and reading whole files.ripwire 是 AI 上下文领域的 ripgrep。只需将其指向任何代码库,你的智能体就能获得一份带排名的确定性调用图——明确哪些代码需要修改、哪些会引发破坏、哪些测试需要运行——而无需到处 grep 或阅读整个文件。

Languages: Rust · C++ · Objective-C/C++ · C · Metal · CUDA · Python · Go · Swift · TypeScript · JavaScript · Java · Ruby · PHP · Lua · Bash · C# · JSON · TOML · YAML · Markdown — twenty-one vendored grammars, and adding another is a vendored tree-sitter grammar plus one row in a declarative table.支持语言:Rust · C++ · Objective-C/C++ · C · Metal · CUDA · Python · Go · Swift · TypeScript · JavaScript · Java · Ruby · PHP · Lua · Bash · C# · JSON · TOML · YAML · Markdown —— 内置了 21 种语法,添加新语法只需一个内置的 tree-sitter 语法文件,并在声明式表中添加一行即可。

See the map — not just the numbers查看地图,而不仅仅是数字

ripwire --html --color-by=cx: the depth-2 call-graph neighbourhood of lexicalScoresTiered (240 nodes) in this repository, force-directed, nodes on a blue-to-orange complexity scale

One self-contained HTML file (--html[=FILE]), no server, no CDN, click any node to recentre. --color-by=lang|community|cx|churn|tested sets the initial node colour; the page embeds all five and keeps a live selector. Shown here: cx — cyclomatic complexity — over the depth-2 neighbourhood of lexicalScoresTiered, 240 of this repository's own symbols; churn colours the same graph by git history instead. Both share one five-stop blue-to-orange scale rather than the usual green-to-red, so reading it never depends on telling red from green.提供一个自包含的 HTML 文件 (--html[=FILE]),无需服务器,无需 CDN,点击任意节点即可重新居中。--color-by=lang|community|cx|churn|tested 可设置初始节点颜色;页面嵌入了全部五种维度并保留实时选择器。此处展示的是:cx(圈复杂度)—— 在 lexicalScoresTiered 的深度为 2 的邻域内,涵盖了该代码库自身的 240 个符号;churn(变动率)则根据 git 历史记录对同一图表进行着色。两者共享一个从蓝到橙的五级色阶,而非传统的红绿配色,因此阅读时无需依赖对红绿颜色的辨别。

No API key. No embeddings. No index server. No daemon.无需 API 密钥。无需 Embedding。无需索引服务器。无需守护进程。

One self-contained binary on your own machine, offline, installed in one line — and the same line installs and activates the task-shaped skills that teach your agent when to reach for it, not just how, for every agent it finds on the machine. If your agent can run shell commands — Claude Code, Codex, Cursor, Windsurf, Gemini, opencode, aider — it is set up the moment the install finishes; the MCP server is the optional second interface. Install it and ask it something before you finish reading this page:本机运行的单个自包含二进制文件,完全离线,一行命令即可安装——同一行命令还会安装并激活任务技能,教你的智能体何时使用它,而不仅仅是知道如何使用。只要你的智能体能运行 shell 命令——如 Claude Code、Codex、Cursor、Windsurf、Gemini、opencode、aider——安装完成即可立即使用;MCP 服务器是可选的第二接口。安装它,并在读完本页之前问它一个问题:

RIPWIRE_REPO=redhat-et/ripwire bash -c "$(curl -fsSL https://raw.githubusercontent.com/redhat-et/ripwire/main/scripts/install.sh)"
ripwire . --for="incremental cache invalidation"

One deterministic, token-budgeted answer: the relevant symbols, their callers, the change risks, and the tests that reach them. Run on this repository (2026-08-30), that second line answers in about 4.3K tokens with:一个确定性的、受 Token 预算限制的答案:相关的符号、它们的调用者、变更风险以及涉及的测试。在此代码库上运行(2026-08-30),第二行命令在大约 4.3K Token 内给出了答案,包含:

  • The ranked symbols, in rank order — the cache-header constant kCacheMagic first (with its doc comment quoted in place and the one next= call that opens it), then spanTierMemoPath (the cache-path composer), ingestCommitTree, … ingest — each row with its file, line, and signature.按排名顺序排列的符号——首先是缓存头常量 kCacheMagic(附带引用的文档注释和打开它的唯一 next= 调用),然后是 spanTierMemoPath(缓存路径组合器)、ingestCommitTree,…… ingest——每一行都包含其所在文件、行号和签名。
  • Risk, annotated in place — complexity, git churn (ingest shows 128 recent edits), change amplification (touch ingest and 266 graph nodes feel it), purity and test coverage. The fragile spots are visible before anything touches them.风险标注——复杂度、git 变动率(ingest 显示有 128 次近期编辑)、变更放大效应(修改 ingest 会影响 266 个图节点)、纯度及测试覆盖率。在触碰代码之前,脆弱点一目了然。
  • One-hop call context — spanTierMemoPath calls shaKeyedCachePath, headSnapRepoHex, exclConfigHex; no second query needed to see the neighbourhood.一跳(One-hop)调用上下文——spanTierMemoPath 调用了 shaKeyedCachePath、headSnapRepoHex、exclConfigHex;无需二次查询即可查看邻域。
  • Its own confidence — this answer says confidence="high" with the score margin attached; a flat ranking says low, so it reads as a starting point instead of masquerading as an answer.置信度说明——该答案标注了 confidence="high" 并附带分值余量;平坦的排名则标记为 low,因此它被视为起点,而非伪装成最终答案。
The actual wire format — what your agent reads (minified XML; trimmed and line-wrapped here)实际线路格式——你的智能体读取的内容(压缩后的 XML;此处经过修剪和换行)
<ctx task="incremental cache invalidation" confidence="high" margin_pct="20"
     bundle="compact" bodies="0" reason="compact-route" est_tokens="3995">
  <sigs shown="23" total="40" capped="1">
    <d l="106" n="kCacheMagic" p="src/ingest_cache.h" cx="0" in="0" churn="11" amp="71" pure="1" r="1"
       next="--expand=src/ingest_cache.h:kCacheMagic">
      <doc>incremental cache (--cache): per-file content hash + raw facts so a
           re-run re-parses ONLY …</doc>constexpr std::uint32_t kCacheMagic = …</d>
    <d l="1307" n="spanTierMemoPath" p="src/ingest_astquery.h" cx="1" in="2" churn="5" amp="44" r="2"> … </d>
    <d l="247" n="ingestCommitTree" p="src/dmm.h" cx="6" in="1" churn="6" amp="27" r="3"> … </d>
    …
    <d l="191" n="ingest" p="src/ingest.cpp" cx="4" in="14" churn="128" amp="266" tested="1" r="13"> … </d>
    … </sigs>
  <hops shown="2" total="6" capped="1" noedge="2">
    <h l="1307" p="src/ingest_astquery.h" n="spanTierMemoPath">
      <calls total="3"><c n="shaKeyedCachePath" l="1621"/> … </calls></h> … </hops>
</ctx>

cx= complexity, churn= git edit frequency, amp= change amplification, r= rank; <hops> rows carry the one-hop call context, caps disclosed. Every attribute is defined in the one legend at the top of the real output, which also self-reports the bundle's cost — est_tokens="3995" here.cx= 复杂度,churn= git 编辑频率,amp= 变更放大效应,r= 排名;<hops> 行携带一跳调用上下文,大写字母表示已披露。每个属性都在真实输出顶部的图例中定义,该图例还会自报告包的成本——此处为 est_tokens="3995"。

The agent without a map The agent with ripwire
greps a common word, gets hundreds of hits across dozens of files one ranked answer — est_tokens="3995" on this repository (re-derived 2026-09-05, the run above)
reads whole files to find the symbols that matter those symbols, with complexity, churn and test coverage inline
finds the callers only if it thinks to grep for them too callers, blast radius and the tests to run, in the same bundle
pays for every line it read, right or wrong measured at 5.0% of what that grep-and-read pass spends (re-derived 2026-08-23)

And against five retrieval competitors on a held-out LocBench slice, it finds all gold files in the top 10 on 58.3% of instances — the best alternative lands 40.0% — while indexing in 0.31 s. The full leaderboard, losses included ↓在 LocBench 的留存切片上与五个检索竞品相比,它在 58.3% 的实例中将所有黄金文件(gold files)找入前 10 名——最佳替代方案为 40.0%——同时索引仅耗时 0.31 秒。完整排行榜及损失情况 ↓

Same answer, a fraction of the tokens — read this table first if your agent is on a budget同样的答案,更少的 Token——如果你的智能体有预算限制,请先阅读此表

Ten everyday moments, re-measured on this repository, 2026-08-08. Figures are ~tokens (≈ bytes/4); every ratio comes from a real run, reproduced by the command in its row — raw byte counts and exact commands in docs/EVALS.md §5.十个日常场景,于 2026-08-08 在此代码库上重新测量。数字约为 Token 数(≈ 字节/4);每个比率均来自真实运行,并可通过其所在行的命令复现——原始字节数和精确命令见 docs/EVALS.md §5。

Ordered understand → navigate → review-the-change:按“理解 → 导航 → 评审变更”排序:

Ask it Command ripwire naive read token savings
"Orient me in this repo" ripwire . ~5.6K tok ~20K–25K tok — read README.md (+docs/ARCHITECTURE.md) 3.6×–4.5×
"Where is X handled?" ripwire . --for="…" ~2.1K tok ~4.9K–20K tok — grep -rn <term> src/, then read the file it points at 2.3×–9.3×
"What do I already know?" ripwire . --recall="…" ~15K tok ~445K tok — read all 119 markdown docs this repo carries 29.2×
"Set me up for this task" ripwire . --pack-task="…" ~2.1K tok ~16K–80K tok — read every relevant file, whole 7.7×–37.7×
"Show me this one function" ripwire . --expand=SYM --top-k=0 ~260–16.5K tok body (+~5.7K for the ranked-neighborhood bundle) ~43K–174K tok — read the whole file it lives in 2.6×–670×
"Who calls this function?" ripwire . --callers=SYM ~580 tok ~40K–52K tok — grep -rn SYM src/ (mostly noise), then open 2–3 files to sort real calls from mentions 69.2×–89.1×
"Is it safe to change this?" ripwire . --impact=SYM + --uses=SYM ~1.3K tok ~18K tok — open every direct-use file, whole 14.4×
"I have a stack trace" ripwire . --from-trace=FILE ~1.4K tok ~124K–298K tok — grep all 7 frame names, then open the innermost file(s) 86.9×–208.6×
"I changed these files — tests? blast radius?" ripwire . --situ ~410 tok ~3K–132K tok — git diff + grep -rn <syms> test/, then open the candidates 7.3×–324.2×
"Review this PR/diff" ripwire . --pr-context=REF ~1.9K tok ~4.8K–51K tok — git diff REF, then open the touched files 2.6×–27.5×
Same-correct-answer verification, and the honesty line these ratios come with相同正确答案的验证,以及这些比率背后的诚实准则

These aren't summaries that gamble with information. Each row is scored same-correct-answer-or-it-doesn't-count, and both sides were checked, not assumed: orient surfaces this repo's own pipeline files (ingest.cpp, graph.h, serialize.h) in the first screen, the same three docs/ARCHITECTURE.md names as central; the --for row lands mcpStale (src/mcpindex.h:633), the actual staleness check, 5th-ranked; --recall lands the container-rule doc (AGENTS.md) that states, verbatim, the same "no std::map" rule CONTRIBUTING.md explains in full; --pack-task names the same three touch points a human would — cachelint.h, mergeCachePack (src/main.cpp:1787), the lintrules.h helpers it reuses; --expand --top-k=0 hands back the requested function's complete, unmodified body — the ranked-neighborhood addition costs the same ~22.6 KB regardless of which function you ask for, confirmed on two (a fixed floor, not per-function variance); --callers on langOfPath names its 2 real callers, the same ones a grep hit-list buries under 5 files of comment-only mentions; --impact+--uses on coversOrEquals names the same 2 direct call sites --uses alone would, plus (disclosed) a transitive reach --uses doesn't cover at all; --from-trace resolves all 7 frames of a real call chain by name to the same definitions a per-frame grep would eventually find, mixed with call sites and comments; --situ on a 2-file diff names the same 6 real test harnesses, 2 of which a filename grep across test/ cannot find even after opening every one of its 41 candidates — a completeness gap, not just a byte one; --pr-context surfaces co-change partners (test/regression.sh, src/main.cpp) a raw git diff has no way to know were usually touched and weren't this time. The map ranks and discloses — it never paraphrases your code — and every truncation is disclosed in the header.这些不是拿信息博弈的摘要。每一行都根据“相同正确答案才算数”进行评分,双方均经过核实而非假设:orient 在首屏展示了该代码库自身的流水线文件(ingest.cpp, graph.h, serialize.h),与 docs/ARCHITECTURE.md 中列出的三个核心名称一致;--for 行定位到 mcpStale (src/mcpindex.h:633),即实际的陈旧度检查,排名第 5;--recall 定位到容器规则文档 (AGENTS.md),其中逐字说明了 CONTRIBUTING.md 中详述的“无 std::map”规则;--pack-task 列出了人类会触碰的三个点——cachelint.h、mergeCachePack (src/main.cpp:1787) 以及它重用的 lintrules.h 辅助函数;--expand --top-k=0 返回所请求函数的完整、未修改主体——无论你要求哪个函数,排名邻域的添加成本均为 ~22.6 KB(固定下限,无函数间差异);--callers 对 langOfPath 命名了 2 个真实的调用者,而 grep 列表会将它们淹没在 5 个仅提及注释的文件中;--impact+--uses 对 coversOrEquals 命名了 --uses 单独会命名的 2 个直接调用点,外加(已披露)--uses 完全未覆盖的传递性关联;--from-trace 按名称解析了实际调用链的所有 7 帧,指向每帧 grep 最终会找到的相同定义,并混合了调用点和注释;--situ 在一个 2 文件 diff 上命名了 6 个真实的测试工具,其中 2 个是跨 test/ 目录的 grep 即使打开全部 41 个候选文件也找不到的——这是一个完整性差距,而不仅仅是字节差距;--pr-context 展示了原始 git diff 无法知晓的共同变更伙伴(test/regression.sh, src/main.cpp)。地图进行排名并披露——它从不改写你的代码——且每次截断都在标题中披露。

The honesty line, made concrete: the same auto-selection behind the --expand row also runs the other way. On a small file (pageRankDouble in src/pagerank.cpp, 5,559 B) the ranked bundle would cost 27,916 B — nearly 5× more than the file — so ripwire serves the file itself instead, disclosed as mode="whole-file" on the response, not silently. docs/EVALS.md §7 lists that and the other counterexamples this project publishes against itself.诚实准则的具体化:--expand 行背后的自动选择逻辑同样适用于其他情况。对于一个小文件(src/pagerank.cpp 中的 pageRankDouble,5,559 B),排名包的成本将达到 27,916 B——几乎是文件本身的 5 倍——因此 ripwire 直接提供文件本身,并在响应中披露为 mode="whole-file",而非静默处理。docs/EVALS.md §7 列出了该项目针对自身发布的这些及其他反例。

Against the leading graph-database code-context MCP server对比领先的图数据库代码上下文 MCP 服务器

Won 27 · lost 7 · tied 14 on 48 matched questions across django, webpack and this repository, spending ~77K tokens against its ~486K for the whole sweep.在 django、webpack 和本代码库的 48 个匹配问题中,胜 27 · 负 7 · 平 14,消耗约 77K Token,而对方在整个扫描过程中消耗约 486K。

The full result, how it was measured, and where ripwire still loses完整结果、测量方法以及 ripwire 依然落后的地方

The 48 questions span symbol lookup, conceptual search, blast radius, and one-call task orientation. ripwire indexes the same three repositories in 0.25–0.45 s and 6.6–16.5 MB, against that server's 23–52 s and 391–623 MB, and answers a warm query in a median 197 ms against its 1,082 ms. Its seven wins are real and named one by one in the method.48 个问题涵盖了符号查找、概念搜索、影响范围(blast radius)和单调用任务导向。ripwire 在 0.25–0.45 秒和 6.6–16.5 MB 内索引了相同的三个代码库,而该服务器需要 23–52 秒和 391–623 MB,并且热查询的响应时间中位数为 197 毫秒,而对方为 1,082 毫秒。其七次失败是真实的,并在方法中逐一列出。

Both arms warm with a pre-built index, median of 3 timed calls, stdout to a file rather than a pipe. The competitor ran in its stronger retrieval configuration; its numbers were recorded once and then frozen, and ripwire's side was re-run after the fixes the first pass produced. Per class, as a share of the competitor's bytes on totals: symbol lookup 1.35×, conceptual search 1.23×, blast radius 0.39×, task orientation 0.06×.双方均使用预构建索引预热,取 3 次定时调用的中位数,标准输出重定向至文件而非管道。竞品在其更强的检索配置下运行;其数字记录一次后即锁定,ripwire 的一侧在第一轮产生修复后重新运行。按类别计算,占竞品总字节数的份额为:符号查找 1.35 倍,概念搜索 1.23 倍,影响范围 0.39 倍,任务导向 0.06 倍。

Where it loses: on a plain one-symbol lookup the competitor answers in about a kilobyte carrying callers and callees, and ripwire spends roughly three times that to also hand back the body. It ranks a chunk-id plugin first on one webpack query where ripwire never surfaces the directory at all — a ranking miss, and a fix for it was built, met its pre-registered band, and was reverted anyway for failing a separate standing requirement. Its depth-labelled blast radius and its import edges are both better presentations than ripwire's flat reaching-set.落后之处:在简单的单符号查找中,竞品在大约 1 KB 内回答并携带调用者和被调用者,而 ripwire 消耗大约三倍的字节数来同时返回主体。在某次 webpack 查询中,它将 chunk-id 插件排在第一位,而 ripwire 根本没有显示该目录——这是一个排名缺失,虽然为此构建了修复程序并达到了预设指标,但因未能通过单独的现行要求而被撤回。其带深度的影响范围和导入边缘呈现方式比 ripwire 的平坦可达集更好。

Full method, pins, per-class tables, the carried-versus-re-judged ledger, and the complete list of what the competitor does better: docs/EVALS.md §2.完整方法、固定项、分项表格、已执行与重新评估的分类账,以及竞品表现更好的完整列表:docs/EVALS.md §2。

Nothing it is unsure about reaches your agent unlabelled — and nothing it could not see goes unnamed. Every guess is marked in the output, and every mark has a next step — up to handing it a compiler-grade index. Point it at a repository whose main language it has no grammar for and the map's first line says so (unindexed="ml:793,mli:607,…" on a facebook/infer clone); a file it indexed but cannot vouch for carries a parse-health row; every file the crawl passed over is itemized with its reason. A confident-looking map that lies by omission is the failure mode this tool refuses. What it misses, and what to run next →任何不确定的内容都不会在未标注的情况下到达你的智能体——任何无法看到的内容都不会被漏掉。每一个猜测都在输出中标记,每个标记都有后续步骤——最高可提供编译器级的索引。将其指向一个它没有语法的代码库,地图的第一行会说明(在一个 facebook/infer 克隆上显示 unindexed="ml:793,mli:607,…");它索引了但无法担保的文件会带有一行 parse-health;爬虫跳过的每个文件都列出了原因。一个通过遗漏来撒谎的伪自信地图,正是该工具拒绝的失败模式。下一步运行什么 →

Saves Tokens: It answers for a fraction of the context节省 Token:它仅用极少量的上下文即可回答

On mid-task questions it had never seen, ripwire answers at 5.0% of what a grep-and-read pass spends — 5.2% on the questions both arms fully answered. --pack-signatures returns 81% fewer bytes than full bodies at top-50. The output is already dense enough that running a dedicated context compressor over it saved exactly 0 tokens.对于它从未见过的任务中途问题,ripwire 的回答消耗量仅为 grep-and-read 方式的 5.0%——在双方都能完全回答的问题上为 5.2%。--pack-signatures 返回的字节数比前 50 名的完整主体少 81%。输出已经足够密集,以至于在其上运行专门的上下文压缩器节省了 0 个 Token。

Both of those first two figures moved when they were re-derived on 2026-08-23, and they moved in opposite directions — 7.3% → 5.0% overall, but 1.7% → 5.2% on the both-answered subset. Same frozen questions, same frozen verb ladders, same corpus pin, same tokenizer; the naive arm reproduced to the token. What changed is where ripwire spends: the compact conceptual route made its misses much cheaper, while richer default bundles made the questions it answers dearer. Both numbers are printed because printing only the one that improved would be the failure this project exists to not commit. The full per-question re-derivation is in the Round 3 note under Measured.前两个数字在 2026-08-23 重新推导时发生了变动,且变动方向相反——总体从 7.3% 变为 5.0%,但在双方均能回答的子集中从 1.7% 变为 5.2%。相同的冻结问题、相同的冻结动词阶梯、相同的语料库固定、相同的分词器;原始分支精确复现了 Token 数。改变的是 ripwire 的消耗位置:紧凑的概念路径使其遗漏成本更低,而更丰富的默认包使它能回答的问题代价更高。打印两个数字是因为只打印改善的那个,正是该项目旨在避免提交的失败。完整的每题重新推导过程见 Measured 下的 Round 3 注释。

It is also cheap enough to call on reflex: this repository parses in ~0.15 s cold and ~0.10 s warm (time ./build/ripwire . --no-cache), so the agent asks instead of guessing.它足够便宜,可以作为反射动作调用:此代码库冷启动解析耗时 ~0.15 秒,热启动 ~0.10 秒(time ./build/ripwire . --no-cache),所以智能体可以直接提问,而不是猜测。

Graph-Ranked Retrieval: It finds the right files more often than the alternatives图排名检索:它比替代方案更频繁地找到正确文件

58.3% against 40.0% for the best tool tested — and it answers before they finish indexing. Every arm below was re-run in full on 2026-08-08 — one ripwire binary (the profile-guided release build that now ships), one evaluator, one 60-instance held-out LocBench slice: paired, zero exclusions, same gold set, and the metric code imported unmodified into every arm. Strict file@10 = all gold files inside the top 10, which is whether your agent starts in the right place at all.58.3% 对阵测试工具中最佳的 40.0%——而且它在对方完成索引之前就给出了答案。下方每个分支均于 2026-08-08 全面重新运行——一个 ripwire 二进制文件(现已发布的配置引导版本)、一个评估器、一个包含 60 个实例的 LocBench 留存切片:配对、无排除、相同的黄金集,且指标代码以未修改形式导入每个分支。严格的 file@10 = 前 10 名内包含所有黄金文件,这决定了你的智能体是否从正确的起点开始。

Round 4 — LocBench, Python-dominant strict file@10 any@10 index (median) query (median)
ripwire --for 58.3% 85.0% 0.31 s 0.108 s
codebase-memory-mcp 0.9.0 40.0% 63.3% 1.24 s 0.075 s
repowise 0.37.0 33.3% 53.3% 34.0 s 1.159 s
graphify 0.9.34 31.7% 46.7% 7.82 s 0.614 s
Aider repo-map 0.86.2 20.0% 35.0% (inside query) 2.920 s
codeseek 0.1.31 (better of its two arms) 15.0% 20.0% 3.37 s 0.040 s

Ripwire leads every arm on both accuracy metrics and in both strata. Paired, the losses are small and they are published: 2 instances to codebase-memory-mcp, 2 to repowise, 1 each to graphify and aider. Cold from nothing to an answer — parse, rank, reply, no cache — ripwire takes 0.213 s, against a ~35 s index-then-query for repowise; its worst single index in this run was 352 s.Ripwire 在两个准确性指标和两个层级上均领先所有分支。配对来看,损失很小且已公开:2 个实例输给 codebase-memory-mcp,2 个给 repowise,各 1 个给 graphify 和 aider。从零到回答的冷启动——解析、排名、回复,无缓存——ripwire 耗时 0.213 秒,而 repowise 需要 ~35 秒的索引加查询;本轮中其最差的单次索引耗时 352 秒。

Three things this table costs us, said plainly. codebase-memory-mcp is the real runner-up at 40.0%, not repowise — an earlier round credited it with 26.7%, and re-running it fairly raised it. The margin over the best competitor is therefore 1.46×, not the 1.75× two separately-dated tables used to imply. And multi-file gold is hard for everyone: ripwire leads the stratum at 21.4% strict, but its own any@10 there is 78.6% — it finds a gold file and misses the siblings, and no arm in this table solves that.此表明确了三个代价。codebase-memory-mcp 是以 40.0% 领先的真正亚军,而非 repowise——早期回合将其评为 26.7%,公平重新运行后有所提升。因此,相对于最佳竞品的优势是 1.46 倍,而不是两个不同日期表格所暗示的 1.75 倍。多文件黄金集对所有人来说都很难:ripwire 在严格层级上以 21.4% 领先,但其 any@10 为 78.6%——它找到了一个黄金文件却错过了兄弟文件,表中没有任何分支能解决这个问题。

Held out wider — 243 instances across 78 repositories — ripwire lands 60.9% against 27.6% for its own pre-routing baseline: +33.3pp paired, clustered-bootstrap 95% lower bound +25.0pp, bought for +3.4% warm latency and −39.4% tokens. Full provenance, the losing instances one by one, and a third round against a compression-layer competitor: Measured and bench/headtohead/r4-2026-08-06/, whose harness is committed so anyone can re-run the whole comparison.在更广泛的留存集上——跨 78 个代码库的 243 个实例——ripwire 达到 60.9%,而其自身的预路由基准为 27.6%:配对提升 +33.3pp,聚类自举 95% 置信下限 +25.0pp,换取了 +3.4% 的热延迟和 -39.4% 的 Token 消耗。完整来源、逐个失败实例,以及针对压缩层竞品的第三轮对比:Measured 和 bench/headtohead/r4-2026-08-06/,其测试工具已提交,任何人都可以重新运行整个对比。

Test scaffolding does not pollute the ranking from inside source files either: #[cfg(test)] mod tests, describe() blocks, Test* classes and [Fact] attributes are detected syntactically, wherever they live — not by file path alone. On an astral-sh/ruff clone (5,945 files), --ignore-tests removes 23,907 test symbols where path rules alone caught 18,532 (ripwire <ruff> --ignore-tests, 2026-08-14; the per-language fixtures are pinned by test/testscopecheck.sh).测试脚手架也不会从源文件内部污染排名:#[cfg(test)] mod tests、describe() 块、Test* 类和 [Fact] 属性无论位于何处,均通过语法检测——而非仅仅通过文件路径。在一个 astral-sh/ruff 克隆(5,945 个文件)上,--ignore-tests 移除了 23,907 个测试符号,而仅路径规则捕获了 18,532 个(ripwire <ruff> --ignore-tests, 2026-08-14;各语言固定装置由 test/testscopecheck.sh 固定)。


The table above, read two other ways. Every figure in both is one of its measured numbers; only the manners and the cynicism are editorial.上表有两种解读方式。两者中的每个数字都是其测量值;只有语气和嘲讽是编辑性的。

📖  The same table, as narrated by Jane Austen简·奥斯汀叙述的同一张表📖  简·奥斯汀叙述的同一张表

A Survey of the Neighbourhood's Eligible Instruments — being an account of five gentlemen of retrieval, and one lady of no pretension whatsoever.邻里合格工具调查——关于五位检索绅士和一位毫无矫饰的女士的叙述。

It is a truth universally acknowledged, that an engineer in possession of a large repository must be in want of a map.这是一个举世公认的真理:拥有大型代码库的工程师必然需要一张地图。

Mrs. Codebase-Memory must be named first, for she has risen a great deal in the estimation of the neighbourhood — two-fifths of her answers entirely correct, which is more than any other caller can say, and she is ready in a second and a quarter. It must nevertheless be recorded that her card announces accomplishments in the semantic line; that upon enquiry the semantic line is not at home; and that the household denies all knowledge of it. One is left with the impression of a capable woman ill-served by whoever prints her cards.Codebase-Memory 夫人必须首当其冲,因为她在邻里间的评价大幅提升——五分之二的回答完全正确,这比任何其他调用者都要好,且她在一秒又四分之一内即可准备就绪。尽管如此,必须指出她的名片宣称具备语义能力;但经询问,语义能力并不在家;且该家庭否认对此有任何了解。人们留下的印象是一位能干的女士,却被印名片的人坑惨了。

Mr. Repowise is by common consent the most substantial of the party, and no one who has waited upon him would dispute it. He is possessed of a handsome index and a manner of great thoroughness; but he must be seen to. One does not simply address Mr. Repowise. One sends word, and dresses, and waits — three-and-thirty seconds on an ordinary morning, and upon one memorable occasion in the country, seven minutes and four seconds — during which interval a less consequential neighbour has answered the question, taken her leave, and thought no more about it. He answers creditably when at last he arrives, one time in three; whether that is worth the toilette, each family must determine for itself.Repowise 先生是公认最稳重的一位,任何等待过他的人都不会质疑这一点。他拥有漂亮的索引和极其彻底的行事风格;但必须得有人盯着他。人们不能简单地向 Repowise 先生提问。必须先传话,然后更衣,然后等待——普通早晨需要三十三秒,在乡下某次难忘的场合需要七分零四秒——在此期间,一位不太重要的邻居可能已经回答了问题,告辞离开,并把这事忘得一干二净。他最终到达时回答得相当可靠,三次中能有一次;这是否值得梳洗打扮,每个家庭必须自行决定。

Mr. Graphify enjoys a great many admirers. He does not rank his acquaintances; he calls upon them in whatever order his walk happens to take him, and reports the order of the walk as though it were an opinion. He has been known to arrive carrying a hundred and thirty megabytes of correspondence. Pressed once for any answer at all, he replied that no matching nodes were found, and considered the matter closed.Graphify 先生拥有许多崇拜者。他不给熟人排名;他以散步时碰巧遇到的任何顺序拜访他们,并把散步的顺序当作意见汇报。据了解,他曾带着一亿三千万字节的信件到达。有一次被催促给出任何答案时,他回答说没有找到匹配的节点,并认为事情已经结束。

Mr. Aider is the most gentlemanly of the company and by far the most difficult to consult. He cannot be asked a question — the thing is simply not done. One may mention names in his hearing and hope he takes the hint; he does take it, and is fully ten points the better for it, which says more about the hint than about Mr. Aider. But he forms his view of the neighbourhood before you speak and retains it after, and one cannot escape the feeling that the conversation was never truly with you.Aider 先生是公司里最绅士的一位,也是最难咨询的一位。不能向他提问——这事根本行不通。人们可以在他耳边提及名字并希望他领会暗示;他确实领会了,而且表现提升了整整十分,这说明暗示比 Aider 先生本身更有用。但他会在你开口之前就形成对邻里的看法,并在之后保持不变,人们无法摆脱那种对话从未真正与你进行的感受。

Mr. Codeseek is a young gentleman of quick habits who suffers from an affliction of address. Speak to him plainly, in the language of ordinary complaint, and he will regard you with perfect composure and say nothing whatever — nothing, upon sixty occasions out of sixty. Name a person precisely as that person is named, and he grows animated directly. It is not stupidity; it is a want of imagination in the matter of introductions.Codeseek 先生是一位习惯敏捷的年轻绅士,患有一种交流障碍。用普通抱怨的语言与他直白地交谈,他会以完美的镇定看着你,什么也不说——六十次中有六十次什么也不说。精确地按名字称呼某人,他会立刻变得生动起来。这不是愚蠢;这是在介绍方面缺乏想象力。

And there is ripwire, of whom nothing is said in the drawing rooms, because she has already gone home. She was asked; she answered, in thirteen hundredths of a second; every gold file within the first ten, in eight-and-fifty cases of the hundred. She keeps no establishment, corresponds with no distant authority, and has never once been indexed at a party. Mr. Repowise finds her abrupt.还有 ripwire,客厅里没人提起她,因为她已经回家了。她被问到了;她在十三百分之一秒内回答;每一百个案例中有五十八个,前十名内包含了所有需要的黄金文件。她不设办事处,不与任何远方权威通信,也从未在聚会上被索引过。Repowise 先生觉得她唐突。

She is.确实如此。

Every figure above is a measured number from the round-4 table on this page: the index medians (1.24 s, 34.0 s, 3.37 s) and repowise's 352 s worst case, the 40.0% and 33.3% strict file@10, the 0-results-on-60/60 fallback arm, the absent semantic_query tool, graphify's 129 MB largest graph and its 1-of-60 empty ranking, aider's +10 pp personalization delta, and ripwire's 0.108 s / 58.3%. Provenance in bench/headtohead/r4-2026-08-06/ and docs/EVALS.md; only the manners are editorial. These are other people's real work, and the joke is aimed at the trade-offs, never at the authors.以上每个数字都是本页第 4 回合表格中的测量值:索引中位数(1.24 秒, 34.0 秒, 3.37 秒)和 repowise 最差的 352 秒,40.0% 和 33.3% 的严格 file@10,60/60 的零结果回退分支,缺失的 semantic_query 工具,graphify 129 MB 的最大图及其 1-of-60 的空排名,aider 的 +10 pp 个性化增量,以及 ripwire 的 0.108 秒 / 58.3%。来源见 bench/headtohead/r4-2026-08-06/ 和 docs/EVALS.md;只有礼仪是编辑性的。这些是别人的真实工作,笑话针对的是权衡,从不针对作者。

🕵️  The same table, worked as a case file以案件档案形式呈现的同一张表 — a private eye who trusts no index he didn't build himself🕵️  以案件档案形式呈现的同一张表——一位不信任非自建索引的私家侦探

The Long Index — in which a man asks six informants one simple question, and only one of them has the decency to answer it.长索引——一个人问了六个线人一个简单的问题,只有其中一个有体面回答它。

It was a million lines of somebody else's mistakes, and I needed one file out of it before the coffee went cold. So I did what you do. I went and talked to the people who say they know the neighborhood.那是一百万行别人的错误,我需要在咖啡变凉之前从中找到一个文件。所以我做了该做的事。我去找了那些自称了解这个社区的人。

Codebase-Memory had the best record in the room and she knew it — two answers right out of every five, handed over in a second and a quarter, which in this business is practically a kindness. Trouble was the card. Right under her name it said semantic query, real classy, real expensive-looking. I asked to see it. She said it wasn't in. I asked the house. The house had never heard of it. I've known a lot of good people ruined by whoever printed their cards.Codebase-Memory 有房间里最好的记录,她自己也知道——每五次回答中有两次是正确的,在一秒又四分之一内交出,在这行里这简直是仁慈。麻烦的是那张名片。在她的名字下面写着“语义查询”,真高级,看起来真贵。我要求看看。她说不在。我问了这家人。这家人从未听说过。我认识很多好人被印他们名片的人给毁了。

Repowise was the heavyweight — everybody told me so before I got through the door. Big index, good tailoring, thorough as a tax man. Only you don't just ask Repowise a question. You send word. You wait. Thirty-three seconds on a good day, and one bad morning out in the country, seven minutes and four seconds — long enough to get the same answer somewhere else, drive home, and forget his name. He came through one time in three. For some outfits that's worth the wait. I've got a metabolism.Repowise 是重量级人物——我进门前每个人都这么告诉我。大索引,好剪裁,像税务员一样彻底。只是你不能直接问 Repowise 问题。你得传话。你得等。好日子三十三秒,乡下糟糕的早晨七分零四秒——足够去别处得到同样的答案,开车回家,并忘记他的名字。他三次里有一次能搞定。对某些机构来说,这值得等待。我可没那闲工夫。

Graphify never met a fact he wouldn't hand you. Ask him one thing and he turns up with a hundred and twenty-nine megabytes of everything, unsorted, in whatever order he tripped over it — and he'll report that order like it's a considered opinion. It isn't. Leaned on him once for anything at all; he looked me dead in the eye, said no matching nodes, and figured we were square.Graphify 从没见过他不愿递给你的事实。问他一件事,他就会带回一亿两千九百万字节的任何东西,未排序,以他绊倒的任何顺序——而且他会像汇报经过深思熟虑的意见一样汇报这个顺序。并不是。有一次逼他给点什么;他直视我的眼睛,说没有匹配的节点,并认为我们扯平了。

Aider was a gentleman, which is another way of saying you couldn't file a straight question into him in triplicate. Wouldn't be asked. You mention things, loud, and hope — and sure enough, drop the right names and he's ten points sharper, which tells you everything about the names and nothing about Aider. He'd made up his mind about the place before I opened mine, and kept it after. You never did feel the conversation was with you.Aider 是个绅士,换句话说,你无法向他提交一份一式三份的直白问题。不愿被问。你大声提及事情,并抱有希望——果然,丢出正确的名字,他就会敏锐十分,这说明了名字的一切,而对 Aider 一无所知。他在我开口前就对这个地方有了定见,之后也保持不变。你永远不会感觉到对话是在和你进行。

Codeseek was young and had a condition. Talk to him like a human being — plain, tired, the way a man actually asks for help — and he'll look clean through you and say nothing. Sixty times out of sixty, nothing. But name the thing exactly, badge number and all, and the kid lights right up. It isn't that he's slow. He just never learned how people knock on a door.Codeseek 年轻且有某种状况。像对待人类一样与他交谈——平淡、疲惫,像一个人真正寻求帮助的方式——他会看穿你并什么也不说。六十次中有六十次,什么也不说。但精确地命名事物,带上徽章编号,这孩子立刻就亮了起来。不是他慢。他只是从未学会人们如何敲门。

And ripwire. Nobody at the table brought her up, on account of she'd already left. Took the question, answered it in thirteen hundredths of a second — every file I needed inside the first ten, fifty-eight times out of a hundred — keeps no office, wires no head branch, never once got herself indexed at a party. Repowise says she's abrupt.还有 ripwire。桌上没人提起她,因为她已经走了。接过问题,在十三百分之一秒内回答——我需要的每个文件都在前十名内,一百次中有五十八次——不设办公室,不连接任何总部分支,从未在聚会上被索引过。Repowise 说她唐突。

She is. That's why I hired her.确实。这就是我雇佣她的原因。

Every figure above is a measured number from the round-4 table on this page: the index medians (1.24 s, 3.37 s, 34.0 s), repowise's 352 s / six-minute worst case, the 40.0% and 33.3% strict file@10, codeseek's 0-of-60 plain-language arm, codebase-memory's advertised-but-absent semantic tool, graphify's 129 MB largest graph and its 1-in-60 empty return, aider's +10 pp name-drop delta, and ripwire's 0.108 s / 58.3%. Provenance in bench/headtohead/r4-2026-08-06/ and docs/EVALS.md; only the cynicism is editorial. These are other people's real work, and the joke is aimed at the trade-offs, never the authors.以上每个数字都是本页第 4 回合表格中的测量值:索引中位数(1.24 秒, 3.37 秒, 34.0 秒),repowise 的 352 秒/六分钟最差情况,40.0% 和 33.3% 的严格 file@10,codeseek 的 60 次平铺语言分支,codebase-memory 的广告宣传但缺失的语义工具,graphify 129 MB 的最大图及其 1-in-60 的空返回,aider 的 +10 pp 提名字增量,以及 ripwire 的 0.108 秒 / 58.3%。来源见 bench/headtohead/r4-2026-08-06/ 和 docs/EVALS.md;只有愤世嫉俗是编辑性的。这些是别人的真实工作,笑话针对的是权衡,从不针对作者。


Name a symbol and it is the first hit — and it is never a mystery which ranker answered. Every --for query is served by one of three lanes; a confidence-gated router picks by reading the query's shape, discloses its choice on the output (route=), and --no-route overrides it. Routing lifts recall@1 on name-shaped queries 61.1% → 91.3% in src/, 59.2% → 85.5% at the repository root — and the gate is load-bearing in both directions: route everything to the name lane and prose queries collapse from 0.967 MRR to 0.016. Both numbers ship together. Reproduce with ripwire <dir> --eval-retrieval, which grades EVERY doc-commented symbol in the corpus and prints its own population=/scored=/rule=; the full per-ranker tables are in bench/ANSWERQUALITY.md.命名一个符号,它就是第一条命中结果——而且永远不会搞不清是哪个排名器回答的。每个 --for 查询由三个通道之一服务;置信度门控路由器通过读取查询的形状进行选择,在输出中披露其选择 (route=),--no-route 可覆盖它。路由将名称查询的 recall@1 在 src/ 中提升了 61.1% → 91.3%,在代码库根目录提升了 59.2% → 85.5%——且该门控在两个方向上都起到了负载作用:将所有内容路由到名称通道,散文查询的 MRR 会从 0.967 崩溃到 0.016。两个数字同时发布。使用 ripwire <dir> --eval-retrieval 复现,它会对语料库中每个带文档注释的符号进行评分,并打印其 population=/scored=/rule=;完整的每排名器表格在 bench/ANSWERQUALITY.md 中。

Lane Built for Why it wins there Where it loses
name-exact identifier-shaped queries (chooseForRanker, pack task) whole-name match ignores body noise: 91.3% recall@1, 0.960 MRR in src/ scores zero on any word that is not literally a name — forced onto prose it dies (0.016 MRR)
subtoken+body prose and task queries ("where is the content hash computed") the only lane that matches vocabulary living in doc comments and bodies exact names drown in shared subtokens (61.1% recall@1 on name queries)
mention anchor a pasted path, Type.method, or issue URL a literal mention is lifted above any score — paste the ticket, don't paraphrase it adds nothing when the query names no artifact
How each lane finds things, and how the router picks — step by step每个通道如何查找事物,以及路由器如何选择——一步一步

How the conceptual lane finds what you didn't name. The subtoken+body lane is why a query with no symbol name in it still lands:概念通道如何找到你未命名的内容。子 Token+主体通道是查询中没有符号名称也能命中的原因:

  • Both sides are split into subtokens. SplitChunksPlugin becomes split+chunks+plugin, and so does your query — so words match pieces of names you never typed.双方都被拆分为子 Token。SplitChunksPlugin 变为 split+chunks+plugin,你的查询也是如此——所以单词匹配了你从未输入过的名称片段。
  • Three evidence fields, not one. A symbol is scored on its name subtokens, its doc comment, and its body — vocabulary that only exists in a comment or an implementation still finds its symbol.三个证据字段,而非一个。符号根据其名称子 Token、文档注释和主体进行评分——仅存在于注释或实现中的词汇仍然能找到其符号。
  • BM25 with per-query IDF. Rare, discriminating words dominate the score; words the whole corpus shares contribute almost nothing. Type the three words only the right function uses and they carry the query.带每查询 IDF 的 BM25。罕见、具有辨别力的词主导分数;整个语料库共享的词几乎没有贡献。输入只有正确函数使用的三个词,它们就能承载查询。
  • Lookalikes are down-weighted, not hidden. Fixture, test-data, and generated paths score at a fraction, so a test vocabulary-twin cannot outrank the real source (adversarial-class pollution@5: 28% → 0%, docs/EVALS.md §4) — but they stay in the index and are still found when asked for.相似项被加权下调,而非隐藏。Fixture、测试数据和生成的路径评分较低,因此测试词汇双胞胎无法超过真实源(对抗类污染@5:28% → 0%,docs/EVALS.md §4)——但它们保留在索引中,在被要求时仍能找到。
  • The list ends at a cliff, not a quota. The cut is adaptive: output stops where the scores drop off, so a sharp answer is a short list and a diffuse one is disclosed as such, instead of a fixed top-k padding both.列表在悬崖处结束,而非配额。切分是自适应的:当分数下降时输出停止,因此尖锐的答案是一个短列表,而分散的答案会被披露为分散,而不是用固定的 top-k 填充两者。

How the router picks. The gate is built on cheap, corpus-derived evidence, and its bias reflects an asymmetry the table above makes plain: a missed name-route costs a few ranks; a false one is catastrophic (0.016 MRR).路由器如何选择。门控建立在廉价的、语料库衍生的证据之上,其偏差反映了上表所明确的不对称性:错过的名称路由只损失几个排名;错误的路由是灾难性的 (0.016 MRR)。

  1. Identifier shape is trusted outright. A camelCase/snake token — or a short query carrying one — routes name-exact. Someone who types chooseForRanker is naming, not describing.标识符形状被直接信任。camelCase/snake Token——或携带它的短查询——路由到名称精确匹配。输入 chooseForRanker 的人是在命名,而不是在描述。
  2. The all-words test. If every content word equals some symbol's whole name (pack task where both pack and task are real symbols), that is strong evidence of a name query.全词测试。如果每个内容词等于某个符号的完整名称(pack task,其中 pack 和 task 都是真实符号),那是名称查询的有力证据。
  3. The plausibility test. Present is not enough — each matched name must be specific: few definitions, and not a subtoken carried by half the corpus's symbol names (thresholds derived from the index itself, not a hardcoded stdlib list). This is what catches split chunks: every word names a symbol, but split names a String method defined everywhere — so the route is declined and the conceptual lane runs, which finds SplitChunksPlugin easily.合理性测试。存在是不够的——每个匹配的名称必须是特定的:定义很少,且不是被语料库中一半符号名称携带的子 Token(阈值源自索引本身,而非硬编码的 stdlib 列表)。这就是捕获 split chunks 的原因:每个词都命名了一个符号,但 split 命名了一个随处定义的 String 方法——所以路由被拒绝,概念通道运行,从而轻松找到 SplitChunksPlugin。
  4. Every decision is disclosed. route= states the lane that ran; a decline names the anchor that failed and why. --no-route forces the conceptual lane when you disagree.每个决定都已披露。route= 说明了运行的通道;拒绝则命名了失败的锚点及其原因。--no-route 在你不同意时强制使用概念通道。

The proof the gate earns its keep: the routed lane matches the best single lane on both query modes simultaneously — 0.960 MRR on names (equal to forced name-exact) and 0.967 on prose (within noise of pure subtoken+body, src/). No single lane does that.门控赢得其地位的证明:路由通道在两种查询模式上同时匹配最佳单通道——名称上 0.960 MRR(等于强制名称精确匹配),散文上 0.967(在纯子 Token+主体噪声内,src/)。没有单个通道能做到这一点。

The honest boundary: the router classifies the query's shape — it cannot rescue vocabulary that is not in the index. A prose query whose concept lives only in a compound class name (SplitChunksPlugin contains no splits subtoken) is correctly sent to the conceptual lane, which then has little to grab; that gap is measured and recorded in docs/EVALS.md §7, not hidden. Numbers re-derived 2026-08-08 on this tree; per-lane table and history in docs/EVALS.md §4.诚实的边界:路由器对查询的形状进行分类——它无法挽救索引中不存在的词汇。概念仅存在于复合类名中的散文查询(SplitChunksPlugin 不包含 splits 子 Token)被正确发送到概念通道,该通道随后几乎没有抓取对象;该差距已在 docs/EVALS.md §7 中测量和记录,而非隐藏。数字于 2026-08-08 在此树上重新推导;每通道表格和历史见 docs/EVALS.md §4。

Better Code: It automates the review judgments nobody has time to make — every lens from published research更好代码:它自动化了没人有时间做的评审判断——来自已发表研究的每一个镜头

--quality-panel runs the calls a good reviewer makes by hand — is this function too tangled, is it named badly, does it hide control flow inside an idiom, does its history say it keeps breaking, must you read five other files to follow it, does it mutate state three hops away — as six independent evidence families, and ranks by how many of them agree, never as one blended score. Each family implements published work — McCabe on shape, Butler on naming, Gopstein's atoms of confusion on idiom, Nagappan & Ball on churn, Beck & Diehl on colocation, Henry & Kafura on state — with the lesson taken from each paper, and the rules measured and withdrawn, in docs/LINEAGE.md. Pooled over five corpora (n = 27,889) the largest correlation between any two families is +0.168: they really are measuring different things, so two families firing on the same function is corroboration rather than one metric counted twice.--quality-panel 运行了优秀评审员手动进行的调用——这个函数是否太纠结,命名是否糟糕,是否将控制流隐藏在习语中,历史记录是否显示它不断崩溃,你是否必须阅读五个其他文件才能跟随它,它是否在三跳之外改变状态——作为六个独立的证据家族,并按它们中有多少个达成一致进行排名,从不作为单一混合分数。每个家族都实现了已发表的工作——McCabe 的形状、Butler 的命名、Gopstein 的混淆原子、Nagappan & Ball 的变动率、Beck & Diehl 的共位、Henry & Kafura 的状态——汲取了每篇论文的教训,并在 docs/LINEAGE.md 中测量和撤回了规则。在五个语料库(n = 27,889)中汇总,任何两个家族之间的最大相关性为 +0.168:它们确实在测量不同的东西,所以两个家族在同一个函数上触发是确证,而不是一个指标被计算了两次。

That matters most for code an agent wrote. Empty-catch error masking is +47% more common in AI-authored commits, a function rewritten again inside two weeks +15% more likely, and reuse is declining as AI's share of commits grows (GitClear, AI Copilot Code Quality, 2026). Each of --quality-delta's 10 kinds targets one measured mode like those, and it reports only what your change made worse — then --exemplar shows the pattern in your own repo to copy, and --test-gate names the tests that must run before "done."这对智能体编写的代码最重要。空捕获错误屏蔽在 AI 编写的提交中常见程度高出 +47%,两周内重写的函数可能性高出 +15%,且随着 AI 在提交份额中增长,重用率正在下降(GitClear, AI Copilot Code Quality, 2026)。--quality-delta 的 10 种类型中的每一种都针对像那样的测量模式,它只报告你的变更导致变差的内容——然后 --exemplar 展示了你代码库中可供复制的模式,--test-gate 命名了在“完成”之前必须运行的测试。

Tree-local numbers above are reproducible with the commands shown; the rest are dated, sourced measurements in docs/EVALS.md — each with its instrument, its corpus, and its counterexamples, because the losses ship beside the wins. Zero runtime dependencies, C++23, builds with the network off.上述树本地数字可用显示的命令复现;其余是 docs/EVALS.md 中注明日期的来源测量——每个都有其工具、语料库和反例,因为损失与胜出一起发布。零运行时依赖,C++23,在断网情况下构建。

Built for Codex, Claude Code, Cursor, Windsurf, Gemini, opencode, aider, and any agent that can call a CLI.为 Codex、Claude Code、Cursor、Windsurf、Gemini、opencode、aider 以及任何可以调用 CLI 的智能体构建。

What comes back返回的内容 — real output from this repository, pretty-printed and trimmed (re-captured 2026-09-05; rows are served in rank order, each naming its file)返回的内容——来自此代码库的真实输出,美化打印并修剪(2026-09-05 重新捕获;行按排名顺序服务,每行命名其文件)
<ctx task="incremental cache invalidation" route="routed: subtoken+body BM25 (--for's default) — no strong
     name hit, multi-word conceptual query" confidence="high" margin_pct="20"
     bundle="compact" bodies="0" reason="compact-route" est_tokens="3995">
  <sigs shown="23" total="40" capped="1">
    <d l="106" n="kCacheMagic" p="src/ingest_cache.h" cx="0" ccx="0" in="0" churn="11" amp="71" pure="1" r="1"
       next="--expand=src/ingest_cache.h:kCacheMagic"><doc>incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…</doc>constexpr std::uint32_t kCacheMagic = 0x4b505443</d>
    <d l="1307" n="spanTierMemoPath" id="src/ingest_astquery.h::rw::spanTierMemoPath" p="src/ingest_astquery.h" cx="1" ccx="0" in="2" churn="5" amp="44" r="2"><doc>Composed exactly the way every OTHER blob family is (quality.h): one fixed-width identity hex pe…</doc>inline std::string spanTierMemoPath( const std::string&amp; diskPath )</d>
    <d l="247" n="ingestCommitTree" id="src/dmm.h::rw::dmm::ingestCommitTree" p="src/dmm.h" cx="6" ccx="5" in="1" churn="6" amp="27" r="3"><doc>Ingest the tree at `sha`, materialized out of `root`&apos;s object store. …</doc>inline bool ingestCommitTree( const std::string&amp; root, const std::string&amp; sha, … )</d>
    <d l="841" n="mcpRefreshedThisRequest" id="src/mcpindex.h::rw::mcpRefreshedThisRequest" p="src/mcpindex.h" cx="1" ccx="0" in="2" churn="20" amp="43" r="4"><doc>P1-15 — the `_reingest` envelope field for a response whose handling ran an INCREMENTAL pass, …</doc>inline bool mcpRefreshedThisRequest( std::uint64_t passesAtEntry )</d>
    …
  </sigs>
  <hops shown="2" total="6" capped="1" noedge="2">
    <h l="1307" p="src/ingest_astquery.h" n="spanTierMemoPath">
      <calls total="3"><c n="shaKeyedCachePath" l="1621"/><c n="headSnapRepoHex" l="1359"/><c n="exclConfigHex" l="1554"/></calls>
    </h>
    <h l="247" p="src/dmm.h" n="ingestCommitTree">
      <calls total="10" shown="7" capped="1">…</calls>
    </h>
  </hops>
</ctx>

The cache cluster, ranked and annotated in place: cx/ccx complexity, in reuse count, churn recent commits, amp change amplification, tested coverage — the fragile spots are visible before the agent touches them, in a few thousand tokens (est_tokens="3995", self-reported in the header) instead of five whole files. This is a conceptual query, so the bundle is the compact shape: the ranked map plus one-hop callee edges, no inline bodies, and the root says so rather than leaving you to notice. Read the map, then --expand=SYM the one you want — or pass --auto-bodies to get bodies inline as before.缓存集群,按排名原地标注:cx/ccx 复杂度,in 重用计数,churn 近期提交,amp 变更放大效应,tested 覆盖率——在智能体触碰它们之前,脆弱点就已可见,仅需几千个 Token(est_tokens="3995",在标题中自报告),而不是五个完整文件。这是一个概念查询,所以包是紧凑的形状:排名地图加上一跳被调用者边缘,无内联主体,且根目录说明了这一点,而不是让你自己去发现。阅读地图,然后 --expand=SYM 你想要的那个——或者传递 --auto-bodies 以像以前一样内联获取主体。

What the quality panel shows质量面板显示的内容 — real output from this repository, trimmed (legend comment elided)质量面板显示的内容——来自此代码库的真实输出,修剪后(图例注释省略)
$ ripwire . --quality-panel --limit=1
<quality_panel preset="default" families="6" enabled_n="6" cut="2" eligible="6497" ranked="524" …>
<s p="src/graph.h:723" n="buildGraph" fam="4" of="6" fired="structural,confusion,historical,colocation">
<e f="structural" counted="1" why="ccx=764 loc=1368 nest=8 humps=34 deep=315 ev=98 rrank=1"/>
<e f="confusion" counted="1" why="atom-embedded-crement*4"/>
<e f="historical" counted="1" why="hrank=12 churn=36"/>
<e f="colocation" counted="1" why="crank=32"/>
</s>
…
</quality_panel>

Four of six independent evidence families corroborate on buildGraph, each with its own reason shown inline — never a single blended score. eligible="6497" narrows to ranked="524" (2-of-6 agreement): an 8.1% shortlist of this repository's own functions, not a guess (re-derived 2026-08-23 — the corpus grew, the shortlist share did not move). Full six-family breakdown, real numbers per family → The quality panel below.六个独立证据家族中有四个在 buildGraph 上达成确证,每个都有其内联显示的理由——绝非单一混合分数。eligible="6497" 缩小到 ranked="524"(2-of-6 同意):这是该代码库自身函数的 8.1% 短名单,而非猜测(2026-08-23 重新推导——语料库增长,短名单份额未移动)。完整的六家族细分,每个家族的真实数字 → 下方的质量面板。

Full retrieval tables — including the MRR figures behind the router numbers above — in bench/ANSWERQUALITY.md and Measured.完整检索表格——包括上述路由器数字背后的 MRR 数据——在 bench/ANSWERQUALITY.md 和 Measured 中。

Three slides from the ripwire showcase deck: the head-to-head table, the ten-moments token table, and the quality-panel calibration

▶ The whole tool in 27 slides — every figure names the instrument that pins it
renders in your browser · pptx beside it · the numbers behind it
▶ 27 张幻灯片中的整个工具——每个数字都命名了固定它的工具 在浏览器中渲染 · 旁边的 pptx · 其背后的数字

What it answers · Quickstart · The quality panel · Benchmarks · Honesty contract · Agent setup · Docs它回答什么 · 快速入门 · 质量面板 · 基准测试 · 诚实契约 · 智能体设置 · 文档


What it answers它回答什么

Around the core sit 179 long flags advertised in --help, across seven families — plus an MCP server, so a coding agent can call any of them mid-task instead of grepping and reading whole files. Not sure which of them fits the task in front of you? ripwire . --help-task="<task in words>" recommends ONE executable command with the evidence behind the pick — advice only, it never runs the recommendation — and abstains honestly when the evidence is too thin to name a winner.核心周围有 179 个长标志在 --help 中广告,跨越七个家族——加上一个 MCP 服务器,所以编程智能体可以在任务中途调用它们中的任何一个,而不是 grep 和阅读整个文件。不确定哪一个适合你面前的任务?ripwire . --help-task="<task in words>" 推荐一个带有选择背后证据的可执行命令——仅建议,从不运行推荐——并在证据太薄无法命名赢家时诚实地弃权。

Which surface is the authority — --help vs docs/COMMANDS.md — and the four reflex verbs worth memorising哪个表面是权威——--help 对比 docs/COMMANDS.md——以及四个值得记忆的反射动词

./build/ripwire --help is generated from the binary's own flag table and is always the authority; docs/COMMANDS.md documents every one of the 145 documented flags — 94 of them with a real invocation and its recorded output (counts re-derived 2026-08-23; test/docscommandscheck.sh fails if that documented set and the binary's own flag table ever disagree). Each family below links there../build/ripwire --help 是从二进制文件自身的标志表生成的,始终是权威;docs/COMMANDS.md 记录了 145 个已记录标志中的每一个——其中 94 个带有真实调用及其记录的输出(计数于 2026-08-23 重新推导;如果该记录集和二进制文件自身的标志表不一致,test/docscommandscheck.sh 会失败)。下方的每个家族都在那里链接。

Four reflexes worth wiring into muscle memory: --from-trace=FILE for an error you have in hand, --edit-check=SYM right after an edit (did the contract change, and which callers are now provably incompatible), --merge-scout=REF1,REF2 before landing parallel branches, and --pack-task="…" for ranking, bodies, callers and tests in one budgeted bundle.四个值得编入肌肉记忆的反射:--from-trace=FILE 用于你手头的错误,--edit-check=SYM 在编辑后(契约是否改变,哪些调用者现在被证明不兼容),--merge-scout=REF1,REF2 在落地并行分支前,以及 --pack-task="…" 用于在一个预算包中排名、主体、调用者和测试。

Family The question Representative flags
understand a codebase cold "What is this repo, and what matters in it?" --for · --help-task · --tree · --lego · --exemplar · --recall · --top-k · --token-budget · --max-tokens
navigate / answer a question "Who calls this? Is it safe to change? Which tests?" --callers · --callees · --uses · --impact · --path · --connect · --affected · --situ · --test-gate · --grep
zoom the detail ladder "Show me more — but only where it pays." --detail · --pack-signatures · --outline · --expand · --compress
assess quality / structure "Where is the risk, and did I just add some?" --quality-panel · --hotspots · --clones · --metrics · --deps · --lint · --quality-delta · --dmm · --edit-check · --pr-context · --merge-scout
self-diagnosis "Is my setup actually working?" --doctor
security "Is this agent skill file safe to install?" --scan-skill · --scan-skills
knobs / modes shape, format, cache, budget --json · --format · --mcp

Quickstart快速入门

Prebuilt binary — macOS (arm64 / x86-64) and Linux (arm64 / x86-64, built for RHEL 8+; every release is smoke-tested on a RHEL 9 userland before it publishes). Downloads the latest GitHub Release, verifies its SHA-256, and installs to ~/.local/bin. From v0.2.2 the release tarball also ships the seventeen agent skills, and the installer stages them under ~/.local/share/ripwire/skills and activates them for every agent it detects (Claude Code, Codex), printing one line per agent saying what it did. An agent that is not installed is never given a skills directory, hooks are never registered without an explicit --hook, and RIPWIRE_NO_ACTIVATE=1 stages without activating for image builds. When no agent is detected the activation one-liner is printed instead:预构建二进制文件——macOS (arm64 / x86-64) 和 Linux (arm64 / x86-64,为 RHEL 8+ 构建;每个版本在发布前都在 RHEL 9 用户空间上进行烟雾测试)。下载最新的 GitHub Release,验证其 SHA-256,并安装到 ~/.local/bin。从 v0.2.2 开始,发布 tarball 还附带了十七个智能体技能,安装程序将它们暂存到 ~/.local/share/ripwire/skills 下,并为它检测到的每个智能体(Claude Code, Codex)激活它们,每智能体打印一行说明它做了什么。未安装的智能体从不被给予技能目录,钩子在没有显式 --hook 的情况下从不注册,RIPWIRE_NO_ACTIVATE=1 在构建镜像时暂存而不激活。当未检测到智能体时,打印激活单行命令:

RIPWIRE_REPO=redhat-et/ripwire bash -c "$(curl -fsSL https://raw.githubusercontent.com/redhat-et/ripwire/main/scripts/install.sh)"

Building it yourself needs CMake 3.24+ and a C++23 compiler, and nothing else installed first — every dependency is vendored in-tree, so the build completes with the network off.自己构建需要 CMake 3.24+ 和 C++23 编译器,不需要先安装其他任何东西——每个依赖项都在树内内置,所以构建在断网情况下完成。

git clone https://github.com/redhat-et/ripwire.git
cd ripwire
cmake -S . -B build && cmake --build build -j
./build/ripwire .          # the ranked map — start here on an unfamiliar repo
Why there is no download step — vendored grammars, the offline-build proof, the languages parsed, and putting it on PATH为什么没有下载步骤——内置语法、离线构建证明、解析的语言,以及将其放在 PATH 上

Or build from source. Requirements: CMake 3.24+ and a C++23 compiler — that means clang 16+ / AppleClang 15+ (Xcode 15) / gcc 13+ / MSVC 19.36+, and if your distro's CMake is older than 3.24, pip install cmake or brew install cmake gets a current one everywhere. Nothing else — tree-sitter's core, all 21 grammars and the test framework are vendored under third_party/deps, so there is no download step and no package manager to satisfy. Prove that with the network off: add -DFETCHCONTENT_FULLY_DISCONNECTED=ON and the build still completes.或者从源码构建。要求:CMake 3.24+ 和 C++23 编译器——这意味着 clang 16+ / AppleClang 15+ (Xcode 15) / gcc 13+ / MSVC 19.36+,如果你的发行版 CMake 早于 3.24,pip install cmake 或 brew install cmake 在任何地方都能得到最新的。没有其他要求——tree-sitter 的核心、所有 21 种语法和测试框架都内置在 third_party/deps 下,所以没有下载步骤,也没有需要满足的包管理器。在断网时证明这一点:添加 -DFETCHCONTENT_FULLY_DISCONNECTED=ON,构建仍然完成。

Two builds, two jobs — pick by what you are doing:两个构建,两个作业——根据你在做什么选择:

# building to USE it — the fast binary (Release implies LTO; scripts/pgobuild.sh adds PGO, what CI ships)
cmake -S . -B build-release -DCMAKE_BUILD_TYPE=Release && cmake --build build-release -j

# building to WORK ON it — plain configure, no build type (why that matters: the trap, under the fold below)
cmake -S . -B build && cmake --build build -j

Parses C/C++, Objective-C/C++, Python, TypeScript, JavaScript, Java, Ruby, PHP, Lua, Bash, Go, Rust, Swift, C# — plus JSON/TOML/YAML config keys, markdown sections, Metal, and CUDA (<<<>>> launches are call edges).解析 C/C++, Objective-C/C++, Python, TypeScript, JavaScript, Java, Ruby, PHP, Lua, Bash, Go, Rust, Swift, C#——加上 JSON/TOML/YAML 配置键、markdown 部分、Metal 和 CUDA(<<<>>> 启动是调用边缘)。

To put it on PATH, ./install.sh builds and atomically installs the binary plus the matching skills/ and hooks/ assets into a detected prefix (Homebrew's if present, ~/.local otherwise; override with RIPWIRE_INSTALL_PREFIX). Set RIPWIRE_ACTIVATE_CODEX=1 to also refresh Codex's skill links and advisory hooks from that same staged version; activation is otherwise explicit.要将其放在 PATH 上,./install.sh 构建并原子地将二进制文件加上匹配的 skills/ 和 hooks/ 资产安装到检测到的前缀中(如果存在 Homebrew 则为 Homebrew,否则为 ~/.local;用 RIPWIRE_INSTALL_PREFIX 覆盖)。设置 RIPWIRE_ACTIVATE_CODEX=1 以同时从该暂存版本刷新 Codex 的技能链接和咨询钩子;激活在其他情况下是显式的。

Wiring it into your agent takes one more minute — wrap prints the recipe for your client, it never edits your config:将其连接到你的智能体还需要一分钟——wrap 为你的客户端打印配方,它从不编辑你的配置:

ripwire wrap claude             # prints: claude mcp add ripwire -- ripwire --mcp
ripwire wrap --all              # detect every installed agent, print each one's recipe
skills/install.sh --codex       # Codex CLI: the task-shaped skills that say when to query — and when to stop

Four commands worth learning first:四个值得先学习的命令:

ripwire .                                          # the ranked map — start here
ripwire . --for="incremental cache invalidation"   # the task lens: what to touch, ranked
ripwire . --callers=someFunction                   # who calls it
ripwire . --test-gate                              # before you commit: which tests must run
CLI or MCP, the -DCMAKE_BUILD_TYPE=Release trap, and the honesty contract in one lineCLI 或 MCP,-DCMAKE_BUILD_TYPE=Release 陷阱,以及一行诚实契约

The CLI is the recommended baseline because it works in every shell-capable agent; the MCP server is optional, for agents whose workflow benefits from persistent tool registration. Full walkthrough, all six clients: Agent setup.CLI 是推荐的基准,因为它在每个 shell 兼容的智能体中都有效;MCP 服务器是可选的,用于工作流受益于持久工具注册的智能体。完整演练,所有六个客户端:智能体设置。

The trap, spelled out: never configure the dev tree (build/) with -DCMAKE_BUILD_TYPE=Release. Release defines NDEBUG, which compiles the degrade-path alerts out and blinds the gates that assert them — and every gate and bench number is measured against build/, so changing that tree's flavour silently moves all of them at once. Release belongs in its own tree (build-release/ above; ./install.sh builds its own build-install/ the same way). CI builds both flavours on purpose — see CONTRIBUTING.md.陷阱说明:永远不要配置开发树 (build/) 使用 -DCMAKE_BUILD_TYPE=Release。Release 定义了 NDEBUG,它将降级路径警报编译出去,并使断言它们的门控失明——每个门控和基准数字都是针对 build/ 测量的,所以改变该树的风味会同时静默移动所有数字。Release 属于它自己的树(上方的 build-release/;./install.sh 以同样方式构建自己的 build-install/)。CI 有意构建两种风味——见 CONTRIBUTING.md。

The honesty contract, in one line: every count ripwire cannot prove is a total ships labelled a floor, every truncation is disclosed where it happens, and a zero means none found — never none exists. Two runs over the same tree are byte-identical, and a warm run equals a cold one. That is a contract, gated on every pull request and every push to main, not a tendency. The full discipline — and the losses published next to the wins →诚实契约,一行:ripwire 无法证明的每个计数都是一个标记为下限的总数,每次截断都在发生的地方披露,零意味着没找到——绝不是不存在。对同一棵树的两次运行是字节相同的,热运行等于冷运行。这是一个契约,在每个拉取请求和每次推送到 main 时门控,而不是一种倾向。完整的纪律——以及在胜出旁边发布的损失 →


The quality panel质量面板

Six independent evidence families, ranked by how many of them agree — never one blended score. Pointed at this repository's 4,956 eligible functions, 2-of-6 agreement leaves 401 worth a second look: an 8.1% shortlist. Pooled over five corpora (n = 27,889) no two families correlate above +0.168, which is what makes agreement corroboration rather than one metric counted twice. What each family actually looks at — on this repository's own source, not a synthetic example:六个独立的证据族,按其共识程度排序——从不使用混合评分。针对本仓库的 4,956 个符合条件的函数,6 个中有 2 个达成共识(2-of-6 agreement)的函数有 401 个,值得二次审视:这是一个 8.1% 的精选列表。在五个语料库(n = 27,889)中汇总后,没有任何两个证据族的相关性高于 +0.168,这使得共识成为一种佐证,而不是同一指标的重复计算。以下是每个证据族在本仓库源码上的实际表现,而非合成示例:

Family Question Backing verb On this repo
structural shape: complexity, size, nesting and how much of the body is deep, params, local-variable count — absolute bars, not a ranking --metrics buildGraph (src/graph.h:462): ccx=698 loc=1244 nest=8 humps=30 deep=283 locals=114 — 114 local variables invisible to every quality lens until this session, because naming/size analysis has always stopped at a function's signature; locals= is a disclosed floor (locals_floor="1"), threaded through the same walk that already computes ccx/nest, at zero extra parsing cost
lexical identifier text: the 10 naming-* lint rules (short, wordy, case-mixed, uninformative, …) --lint, --naming-consistency, --lint --naming-locals see below — the one family with a fix, not just evidence
confusion syntactic idiom: the 7 atom-* rules (implicit predicates, nested ternaries, embedded ++/--, …) --lint corpus-wide finding counts, not a per-function claim to spotlight here
historical git change frequency — score = churn × cognitive complexity --hotspots src/main.cpp: churn=42 ccx=3387 score=142254 — top of --hotspots' ranking, and its own worst function (main, ccx=387) is where developers keep working and the code is hardest. One caveat the panel's own legend states and this table must too: churn is measured per file, so every symbol in a file carries that file's churn=/hrank= verbatim — this family is file evidence inherited by the row, never the row's own history
colocation (local reasoning) how much you must read that isn't in front of you --context-ratio computeQualityDelta (src/mcpverbs.h:2031), ~50 lines, 87.0% of its distinct references resolve outside its own file — by the tokens a reader must actually read, 99.6%. A refinement of Beck & Diehl's per-class congruence (FSE 2011); Martin's instability I = Ce/(Ca+Ce) is its cruder ancestor
state (unintended side effects) mutable state a change here can perturb, that --impact (who calls you) never asks about --nonlocal-state ensure_global_init (src/infra/profilePmc.h:288) reaches 3 distinct global/static cells through its own body and callees — a tiny, innocent-looking call site can still break state three hops away. Unsound by construction (no pointer aliasing, no indirect calls), so every count is a floor
How the six families are joined, the churn caveat, and the nest= profile deep-dive六个证据族是如何结合的、代码流失(churn)的注意事项,以及 nest= 配置文件的深度解析

--quality-panel joins six independent evidence families (structural shape, lexical naming, syntactic-confusion idioms, git churn history, cross-file colocation, and non-local mutable state) and ranks by the count of families agreeing, never a weighted composite — averaging correlated metrics and calling it several is the Maintainability Index's well-known failure mode. On this repository the panel measures 4,956 eligible functions and narrows them to 401 worth a second look at 2-of-6 agreement — an 8.1% shortlist, not a guess — and the largest correlation between any two families, pooled across five independent corpora (n = 27,889), is +0.168: the families really are measuring different things. The six-family table above shows what each finds on this repository's own source; the sections below are the parts that need more than a row.--quality-panel 结合了六个独立的证据族(结构形状、词法命名、句法混淆习惯用语、git 代码流失历史、跨文件共置和非局部可变状态),并按共识的证据族数量进行排序,从不使用加权综合——将相关指标平均后宣称是多个指标,这是“可维护性指数”(Maintainability Index)众所周知的失效模式。在本仓库中,该面板测量了 4,956 个符合条件的函数,并将其中 2-of-6 共识的 401 个函数筛选出来进行二次审视——这是一个 8.1% 的精选列表,而非猜测。在五个独立语料库(n = 27,889)中,任意两个证据族之间的最大相关性仅为 +0.168:这证明各证据族确实在测量不同的维度。上方的六族表格展示了每个证据族在本仓库源码上的发现;下方的章节则详细说明了需要更多篇幅解释的部分。

nest= is a max, so it cannot tell a long function from a tangled onenest= 是一个最大值,因此它无法区分长函数和纠缠复杂的函数

The structural family's nest= reports the single deepest line in a function. One line at depth 9 and a thousand lines at depth 9 produce the same number — which means a long blocked-sequential body (a run of shallow scoped steps, its max set by one inner loop nobody has to hold in their head) is indistinguishable from a tangled one that sustains depth for hundreds of lines. Every consumer of nest= inherited that blindness: the panel's structural family, --readability's rank, the ensemble join.结构证据族的 nest= 报告的是函数中单行最深的深度。深度为 9 的一行代码和一千行深度为 9 的代码会产生相同的数值——这意味着一个长且阻塞式的顺序主体(一系列浅层作用域步骤,其最大值由一个无需记忆的内部循环决定)与一个在数百行代码中维持深度的纠缠主体是无法区分的。nest= 的每个消费者都继承了这种盲点:面板的结构证据族、--readability 的排名以及集合连接。

--metrics now emits the profile beside the max — humps= (how many maximal regions reach the nesting bar, CodeScene's "bumpy road": a rise above the threshold then a fall, so repeated missing abstractions read differently from one deep tangle) and deep= (how many lines lie inside them, against the loc= already on the row). Both come from the same fused walk that already computes ccx/nest, at zero extra parsing cost; deep= is a disclosed floor (deep_floor="1"). Both are absent exactly when nest < the bar — not-deep, never a hidden 0. deep counts lines and humps counts regions, and two regions can share a line — a one-line if(c){x;}else{y;} at the bar is two regions on one line — so deep below humps is legal output rather than a defect. On this repository's own source:--metrics 现在会在最大值旁边输出配置文件——humps=(有多少个最大区域达到了嵌套阈值,即 CodeScene 的“颠簸路段”:上升超过阈值然后下降,因此重复缺失的抽象与一个深层的纠缠有不同的解读)和 deep=(有多少行代码位于其中,相对于行中的 loc=)。两者都来自已经计算 ccx/nest 的融合遍历,且零额外解析成本;deep= 是一个公开的下限(deep_floor="1")。当 nest < 阈值时,两者均不存在——即“不深”,绝非隐藏的 0。deep 计算行数,humps 计算区域,且两个区域可以共享一行——在阈值处的一行 if(c){x;}else{y;} 即为一行上的两个区域——因此 deep 小于 humps 是合法的输出,而非缺陷。在本仓库的源码上:

function loc nest humps deep deep/loc reading
ingest (src/ingest.cpp) 1632 8 25 467 29% genuinely tangled
buildGraph (src/graph.h) 1244 9 30 308 25% genuinely tangled
main (src/main.cpp) 1061 6 29 111 10% long, mostly shallow steps
dispatchMcpLine (src/mcp.h) 1099 7 22 102 9% a dispatch table, not a tangle
runDefaultMap (src/main.cpp) 650 4 7 15 2% blocked-sequential
ur_walkTree (src/ingest.cpp) 87 7 1 43 49% small and tangled

loc and nest alone rank main and dispatchMcpLine beside ingest and buildGraph; the profile separates them, and it promotes ur_walkTree — 87 lines, so no size bar fires, yet proportionally the densest thing in the table. This changes no ranking: humps > 0 is exactly nest >= bar, which is precisely when the nest bar already fired, so the family count and the panel's shortlist are untouched. It is strictly more evidence on rows that already appear — a reader can tell the two shapes apart without opening the file.仅凭 loc 和 nest 排名,main 和 dispatchMcpLine 会排在 ingest 和 buildGraph 旁边;配置文件将它们分离开来,并提升了 ur_walkTree——87 行,因此没有触发大小阈值,但在比例上却是表中密度最高的内容。这不会改变任何排名:humps > 0 恰好等同于 nest >= 阈值,这正是 nest 阈值已经触发的时候,因此证据族计数和面板的精选列表保持不变。这严格来说是在已经出现的行上提供了更多证据——读者无需打开文件即可区分两种形状。

The panel also carries one join, and it is deliberately not a seventh family: a row whose structural evidence includes deep= (a body that sustains depth at the nesting bar) and that no indexed test reaches is annotated join="deep+untested" — the pair where a refactor is most wanted and least safe, put side by side because both facts are already on the row. It changes nothing: not fam=, not of=, not the order, not which rows appear (counting it would be the structural family wearing a second hat). The root reports tested_scope= (symbols any indexed test reaches — the join's honest denominator) and deep_untested= (rows carrying the annotation across the whole row set); at tested_scope="0" no indexed test reaches anything here, so "untested" would be a fact about what was crawled rather than about the code, and the annotation is emitted on no row.该面板还包含一个连接,它特意不是第七个证据族:如果一行的结构证据包含 deep=(在嵌套阈值处维持深度的函数体)且没有任何索引测试覆盖到它,则会被标注为 join="deep+untested"——这是最需要重构且安全性最低的配对,将其并列是因为这两个事实已经在该行中体现。它不会改变任何东西:fam=、of=、顺序以及哪些行出现都不会改变(如果将其计入,就等于结构证据族戴了两顶帽子)。根节点报告 tested_scope=(任何索引测试能到达的符号——该连接的真实分母)和 deep_untested=(在整个行集中携带该标注的行);当 tested_scope="0" 时,没有任何索引测试能到达此处,因此“未测试”将是一个关于爬取范围的事实,而非关于代码的事实,此时该标注不会在任何行上输出。

Five lenses sit beside the six-family join — deliberately outside its vote. Each is out for a stated reason, not an oversight:在六族连接之外,还有五个透镜(lenses)——它们被特意排除在投票之外。每一个被排除都有明确的原因,而非疏忽:

Lens Asks Why beside the join On this repo
--field-affinity which struct fields are read together but declared far apart; each loop's access shape (index vs pointer-chase) its subject is a type, not a function — attributing a struct's finding to the functions touching it is a claim the lens never makes MainDispatch: 12 findings at separation cost 92.88; 1,374 loops classified, 5 genuine pointer-chases
cache-* lint rules + --with-profile cache-hostile access shapes (alloc-in-loop, p=p->next, a[b[i]], node containers, …), then which are measured hot rows are facts about sites, joined to per-scope hardware counters — not per-function evidence a family vote could count aggressive rules: 0 hits in shipping src/; 327 findings adversarially triaged → 0 fix-worthy; the one open refactor settled by measurement (5.2 ms)
--readability least-readable-first ordering (Halstead volume, Posnett sigmoid) the fitted score saturates past 20 lines — only the ordering is meaningful, and an ordering cannot vote in a count ordering only, never a grade
--naming-consistency off-convention names, each with a computed propose= the one lens that emits advice — a fix is not evidence, so it does not vote camelCase dominant at 93.0%; 136 names flagged with proposals
--lint --naming-locals the naming rules pointed at local variables inside already-flagged functions opt-in and unvalidated — stays outside any join until a real-corpus audit clears it (the withdrawn-rule lesson) +973 findings that were structurally invisible before
The depth on each lens — citations, caveats, and the withdrawn-rule note每个透镜的深度——引用、注意事项以及已撤回规则的说明

Two verbs sit beside the panel, not inside its six-family join — worth knowing the boundary rather than blurring it:有两个动词位于面板旁边,而不是在其六族连接内部——了解边界比模糊边界更有价值:

  • --field-affinity (cache-friendly co-access) is explicitly not a panel family, by unit: it measures which struct fields are read together but declared far apart, and its subject is a type, not a function — attributing a struct's finding to the functions that touch it would be a claim the lens itself never makes (docs/EVALS.md §9.9.2). MainDispatch (src/main.cpp:1335, the 144-byte struct threaded through nearly every verb) still carries 12 real findings against a separation cost of 92.88 — fields read together in the same call routinely cross cache-line boundaries. Chilimbi, Davidson & Larus's cache-conscious structure definition (PLDI 1999), validated on real hardware counters; the advice-not-transform posture (report a split, never auto-reorder a struct) follows Hundt, Mannarswamy & Chakrabarti (CGO 2006). This is a genuinely rare kind of tool: code review catches cache-unfriendly patterns constantly, but every adjacent tool that reasons about memory-access shape (Intel Advisor's pattern classifier, DMon, PerfLint) does it by running the program first — a two-round adversarial literature and patent search found no shipping tool and no published work that does this statically, before a line executes (tier: RARE BUT REAL, the full citation trail and hedged claim wording in docs/LINEAGE.md). The same verb now also classifies each loop's access shape — index/handle-based (predictable, the hardware prefetcher can hide the latency) vs. pointer-chase (data-dependent, no struct layout fixes an unhideable per-hop stall) — and, for genuine chases, checks whether the pointer you dereference to reach the next node sits next to the payload you're about to read, since that cache-line fetch is unavoidable and colocating there is a strictly higher-value fix than generic field reordering. On this repository: 1,374 loops classified, 5 genuine pointer-chases found in a codebase deliberately built handle-based rather than pointer-linked (guardrail G2) — the lens staying quiet on code written to avoid the problem is itself a check that it isn't firing at random. Ships entirely report-only: an A/B benchmark against a real 64 MB shuffled linked list measured a mostly-null result, so the ranking-affecting half of this feature is a provable no-op until a blind real-corpus validation session clears it — reported here at the same honesty level as everything else in this table, not oversold ahead of the evidence.--field-affinity(缓存友好的共同访问)明确不是面板证据族,按单元划分:它测量哪些结构体字段被一起读取但声明位置相距甚远,其主体是类型而非函数——将结构体的发现归因于触及它的函数,是该透镜本身从未做出的主张(docs/EVALS.md §9.9.2)。MainDispatch(src/main.cpp:1335,贯穿几乎每个动词的 144 字节结构体)在 92.88 的分离成本下仍有 12 个实际发现——在同一调用中一起读取的字段经常跨越缓存行边界。Chilimbi, Davidson & Larus 的缓存意识结构定义(PLDI 1999),已在实际硬件计数器上验证;其“建议而非转换”的立场(报告拆分,从不自动重排结构体)遵循 Hundt, Mannarswamy & Chakrabarti(CGO 2006)。这是一种真正罕见的工具:代码审查不断捕捉不友好的缓存模式,但所有关于内存访问形状进行推理的相邻工具(Intel Advisor 的模式分类器、DMon、PerfLint)都是通过先运行程序来完成的——两轮对抗性文献和专利搜索发现,没有任何现成的工具或已发表的作品能在代码执行前静态地做到这一点(层级:罕见但真实,完整的引用路径和对冲声明措辞见 docs/LINEAGE.md)。该动词现在还将每个循环的访问形状分类——基于索引/句柄(可预测,硬件预取器可以隐藏延迟)与指针追踪(数据依赖,没有任何结构布局能修复不可隐藏的每跳停顿)——对于真正的追踪,它会检查你为了到达下一个节点而解引用的指针是否位于你即将读取的有效载荷旁边,因为缓存行获取是不可避免的,在此处进行共置是比通用字段重排价值更高的修复。在本仓库上:1,374 个循环被分类,在故意构建为基于句柄而非指针链接的代码库中发现了 5 个真正的指针追踪(护栏 G2)——透镜在为避免该问题的代码上保持沉默,本身就是它没有随机触发的证明。完全以仅报告模式发布:针对真实的 64 MB 乱序链表进行的 A/B 基准测试得出了基本为零的结果,因此该功能的排名影响部分在盲测真实语料库验证通过之前被证明是空操作——在此处以与表中其他内容相同的诚实度报告,没有在证据面前过度推销。
  • The cache-* lint pack + --with-profile (cache-friendly access patterns — the other half of the locality story, shipped 2026-08-07/08) covers what --field-affinity deliberately does not: eight AST shapes practitioners agree hurt — node-based containers, vector<T*>/vector-of-indirect (the "matrix as vector of vectors"), heap allocation inside loops, p = p->next chase advances, a[b[i]] gather subscripts, by-value shared_ptr parameters, and existing manual prefetches flagged for re-measurement — loop-fenced by span algebra, C-family only, facts never verdicts. The honesty numbers, both directions: on this repository the aggressive rules fire only in benches and test fixtures, zero in shipping src/ (guardrail G2 holding is itself the check the rules aren't firing at random), and a 13-agent adversarial triage of all 327 findings confirmed zero as fix-worthy — every plausible refactor died on "win unmeasurable without a profile". That gap is exactly what --lint --with-profile=FILE closes: it joins a RIPWIRE_PROFILE build's own per-scope hardware counters (#PROF_TSV) onto findings, so a row carries heat_total_ms / heat_l1d_mpki from a real run — static shape × measured PMU weight, the two halves of SYZYGY's advice mode (Hundt, CGO 2006) finally in one command. Worked example: the one surviving refactor candidate (flattening the Louvain adjacency) was settled by its new PROFILE_SCOPE in a single measured run — 5.2 ms, 5.9% of the verb — a wasted afternoon prevented by a number (docs/CACHELINT.md holds the full catalog, the wave-2 specs, and the compiler-handled myths deliberately not checked).缓存 lint 包 + --with-profile(缓存友好的访问模式——局部性故事的另一半,2026-08-07/08 发布)涵盖了 --field-affinity 特意不做的部分:从业者公认有害的八种 AST 形状——基于节点的容器、vector<T*>/间接向量(“向量的矩阵”)、循环内的堆分配、p = p->next 追踪推进、a[b[i]] 收集下标、按值传递的 shared_ptr 参数,以及标记为需要重新测量的现有手动预取——由 span 代数进行循环围栏,仅限 C 家族,事实而非结论。诚实度数字,双向:在本仓库中,激进规则仅在基准测试和测试夹具中触发,在生产环境 src/ 中为零(护栏 G2 的保持本身就是规则未随机触发的检查),对所有 327 个发现进行的 13 代理对抗性分类确认没有一个是值得修复的——每一个貌似合理的重构都死在了“没有配置文件就无法衡量收益”上。这个差距正是 --lint --with-profile=FILE 所弥补的:它将 RIPWIRE_PROFILE 构建自身的每作用域硬件计数器(#PROF_TSV)连接到发现上,因此一行数据携带了来自真实运行的 heat_total_ms / heat_l1d_mpki——静态形状 × 测量的 PMU 权重,SYZYGY 建议模式(Hundt, CGO 2006)的两部分最终合二为一。工作示例:唯一幸存的重构候选者(扁平化 Louvain 邻接)通过其新的 PROFILE_SCOPE 在单次测量运行中得到解决——5.2 毫秒,占动词的 5.9%——一个被数字阻止的浪费下午(docs/CACHELINT.md 包含了完整目录、第二波规范以及编译器处理的故意未检查的神话)。
  • --readability is a sibling lens, not a panel family either — the one classic model in the tree with a published closed form: Halstead volume (Halstead, Elements of Software Science, 1977) and the Posnett/Hindle/Devanbu sigmoid fit (MSR 2011, doi:10.1145/1985441.1985454), fitted on snippets of 20 lines or fewer — past that the fitted score saturates and only the ordering stays meaningful, which is exactly how the verb is used: least-readable-first, never as a grade. Halstead's volume specifically (not the later, less-trusted difficulty/effort derivatives) is among the metrics shown to track measured cognitive load directly (Peitek, Apel, Parnin, Brechmann & Siegmund, ICSE 2021, doi:10.1109/ICSE43902.2021.00056) — --readability emits volume and stops there; difficulty and effort are computed nowhere in this tree.--readability 也是一个姊妹透镜,也不是面板证据族——树中唯一具有已发表闭式解的经典模型:Halstead 体积(Halstead, Elements of Software Science, 1977)和 Posnett/Hindle/Devanbu S 型拟合(MSR 2011, doi:10.1145/1985441.1985454),拟合于 20 行或更少的片段——超过此长度,拟合分数会饱和,只有排序仍然有意义,这正是该动词的使用方式:可读性最差者优先,绝不作为评分。Halstead 的体积(而非后来不被信任的难度/努力衍生指标)是少数被证明能直接追踪测量认知负荷的指标之一(Peitek, Apel, Parnin, Brechmann & Siegmund, ICSE 2021, doi:10.1109/ICSE43902.2021.00056)——--readability 输出体积并止步于此;难度和努力程度在本树中未计算。
  • --naming-consistency is the lexical family's one exception to "evidence, never advice": every other lens in this panel tells you WHAT is wrong, never a computed fix. Case-style consistency is the one property with a corpus-derivable answer — on this repository's src/, camelCase is the dominant convention at 1,677/1,803 (93.0%) agreement, and the verb flags 136 off-convention names with a mechanically recombined propose= value for each (no dictionary, no synonym judgment — see What it answers).--naming-consistency 是词法证据族中唯一一个“证据而非建议”的例外:面板中的每个其他透镜都告诉你哪里错了,从不计算修复方案。命名风格的一致性是唯一具有语料库可导出答案的属性——在本仓库的 src/ 中,camelCase 是主导约定,达成率为 1,677/1,803 (93.0%),该动词标记了 136 个不符合约定的名称,并为每个名称提供了一个机械重组的 propose= 值(无字典,无同义词判断——见“它回答什么”)。
  • --lint --naming-locals points those same naming rules at local variable names — the thing a human reviewer flags immediately in a sprawling function and no static tool measured until this session. Opt-in, off by default: on this repository, a plain --lint finds 2,225 findings; adding --naming-locals finds 3,198 — 973 findings that were structurally invisible a moment ago, scoped tightly (only inside functions already flagged large/complex, only locals nested two blocks deep for the short-name rule) so it doesn't just relabel every loop counter in the tree. Ships disabled by default on purpose: this repository's own history includes a naming rule that shipped on plausibility and was later measured to flag its best-named functions — see the withdrawn-rule note below — so a rule this new stays opt-in until a real-corpus audit clears it.--lint --naming-locals 将相同的命名规则指向局部变量名——这是人类审查员在庞大函数中立即标记出来,但在本次会话之前没有任何静态工具测量过的东西。可选,默认关闭:在本仓库中,普通的 --lint 会找到 2,225 个发现;添加 --naming-locals 会找到 3,198 个——即 973 个刚才在结构上不可见的发现,作用域限制极严(仅在已被标记为庞大/复杂的函数内部,仅针对短名称规则嵌套两层块深),因此它不会重新标记树中的每个循环计数器。故意默认禁用:本仓库自身的历史记录中包含一条基于合理性发布但后来被测量出标记了其最佳命名函数的命名规则——见下文的“已撤回规则说明”——因此一条如此新的规则在真实语料库审计通过前保持可选。

Full citation table, evidence tiers, and what got measured and withdrawn (a naming rule that flagged this repository's best-named functions, kept as the standing argument for measuring before shipping) → docs/LINEAGE.md.完整的引用表、证据层级,以及已测量并撤回的内容(一条标记了本仓库最佳命名函数的命名规则,作为发布前进行测量的有力论据保留)→ docs/LINEAGE.md。


Real runs真实运行

Four real invocations against this repository, each printed as the binary actually prints it: --callers (and why its count is a floor), the default ranked map (and what amb= admits), --test-gate (exit 4 while obligations remain), and --from-trace (feed it the error itself, not a paraphrase of one).针对本仓库的四次真实调用,每一条都按二进制文件实际打印的方式输出:--callers(以及为什么其计数是一个下限)、默认排名映射(以及 amb= 对解析器猜测的承认)、--test-gate(在义务剩余时以状态码 4 退出),以及 --from-trace(直接输入错误本身,而非其释义)。

How these excerpts were edited — minified output wrapped for reading, and exactly which numbers are elided这些摘录是如何编辑的——为阅读而换行的压缩输出,以及精确省略了哪些数字

Output is minified — one line, no whitespace between tags — so the excerpts below are wrapped for reading, and each one's leading legend comment is elided. Nothing else is edited, except that corpus-size numbers (file/symbol/edge counts, the ranked-map header's token/ambiguity tallies, PageRank k= values, and the test-gate example's script_gates_unmodelled= — a count of the script runners under test/, recursively) drift as this repository grows: the ranked map elides those specifically, and says so again at the point of use, and the test gate additionally trims its <u> rows down to 2 of the 25 the real run prints, behind a trailing ….输出经过压缩——单行,标签间无空格——因此下方的摘录为了阅读而进行了换行,且每条摘录开头的图例注释均已省略。除语料库大小数字(文件/符号/边计数、排名映射头部的 token/歧义统计、PageRank k= 值,以及测试门示例的 script_gates_unmodelled=——递归计算 test/ 下的脚本运行器数量)会随本仓库增长而漂移外,没有其他编辑:排名映射明确省略了这些数字,并在使用点再次说明,测试门额外将其 <u> 行从实际运行打印的 25 行缩减为 2 行,置于尾随的 … 之后。

--callers — a call graph built on the spot, and why count="6" ships labelled a floor--callers — 当场构建的调用图,以及为什么 count="6" 被标记为下限

Ten seconds, no index server, no embeddings, no API key — a parse and a call graph, built on the spot:十秒钟,无索引服务器,无嵌入,无 API 密钥——一次解析和一个当场构建的调用图:

$ ripwire . --callers=rankGraphTeleport
<callers of="rankGraphTeleport" defs="1" count="6" root="." hop_tested="0" hop_untested="6" counts_floor="1">
<s t="fn" n="runEval" p="src/eval.h:169"/>
<s t="fn" n="rankGraph" p="src/graph.h:2542"/>
<s t="fn" n="anchoredLexicalRank" p="src/graph.h:3091"/>
<s t="fn" n="churnRankedGraph" p="src/main.cpp:983"/>
<s t="fn" n="runDefaultMap" p="src/main.cpp:1098"/>
<s t="fn" n="getIndex" p="src/mcpindex.h:1104"/>
</callers>

counts_floor="1" is the point. Call edges are extracted from source text by name, so dynamic dispatch contributes no edge (a call through a function pointer or callback is an edge only when ONE function is bound to that variable in scope and the variable never escapes — its address taken or reference-bound — and a macro-generated call site — tagged role="macro" — only when its function-like #define is indexed): count="6" is a floor, and the element says so before you read a single row.counts_floor="1" 是关键点。调用边是按名称从源码文本中提取的,因此动态分派不贡献任何边(通过函数指针或回调的调用,仅当一个函数在作用域内绑定到该变量且该变量从不逃逸——即其地址被获取或引用绑定——以及宏生成的调用点——标记为 role="macro"——仅当其函数式 #define 被索引时,才是一条边):count="6" 是一个下限,元素在你阅读第一行之前就已经说明了这一点。

The default ranked map — --top-k=3, and what amb="2" admits about a resolver guess默认排名映射 — --top-k=3,以及 amb="2" 对解析器猜测的承认

The ranked map — the default run, capped to three symbols so it fits here:排名映射——默认运行,限制为三个符号以便在此显示:

$ ripwire . --top-k=3
<!-- files=… symbols=… edges=… shown=3 est_tokens=… ambiguous=… unresolved=…
     precise=… skipped_oversize=… order=important-first -->
<r est_tokens="435">
<f p="./src/infra/svector.h" layer="infra">
<s t="method" n="size" id="./src/infra/svector.h::svector::size" k="…"></s>
<s t="method" n="push_back" id="./src/infra/svector.h::svector::push_back" amb="2" k="…">
<c n="buf"/><c n="buf"/><c n="grow"/></s>
</f>
<f p="./src/scipoverlay.h">
<s t="method" n="empty" id="./src/scipoverlay.h::ScipOverlay::empty" k="…"></s>
</f>
</r>

files=/symbols=/edges= and the k= rank values are elided: this repository is the corpus here, so they move every time README.md itself gains or loses a line, which is not what the example demonstrates. The rest of the header measures the whole corpus, not the excerpt — the ambiguous= tally is the call-graph completeness gauge, and amb="2" on a row says two of that symbol's calls hit a name with several definitions and the resolver guessed. Read the source when which-target matters.files=/symbols=/edges= 和 k= 排名值已省略:本仓库是此处的语料库,因此每当 README.md 本身增加或减少一行时,它们就会变动,这并非示例所要演示的内容。头部的其余部分测量整个语料库,而非摘录——ambiguous= 统计是调用图完整性的衡量指标,某行上的 amb="2" 表示该符号的两次调用命中了具有多个定义的名称,且解析器进行了猜测。当需要确定目标时请阅读源码。

--test-gate — exit 4 while obligations remain, and why script_gates_unmodelled="332" stays nonzero on a clean clone--test-gate — 在义务剩余时以状态码 4 退出,以及为什么 script_gates_unmodelled="332" 在干净的克隆中保持非零

The test gate — --test-gate names the obligations and exits 4 while any remain. Captured with an uncommitted change in the tree: changed="1" and the rows below appear only because something was actually pending. A clean clone exits 0 with every changed/impacted/test count at zero — except script_gates_unmodelled=, which is structural (it counts script-to-binary test runners the call graph cannot see, not git status) and stays nonzero even then:测试门——--test-gate 命名了义务并在剩余任何义务时以状态码 4 退出。在树中有未提交更改时捕获:changed="1",下方的行出现仅因为确实有待处理事项。干净的克隆在 changed/impacted/test 计数均为零时以状态码 0 退出——除了 script_gates_unmodelled=,它是结构性的(它计算调用图无法看到的脚本到二进制的测试运行器,而非 git 状态),即使在那时也保持非零:

$ ripwire . --test-gate          # exit code: 4
<test-gate changed="1" impacted="80" tests="2" untested="76" shown_tests="2" tests_capped="0"
           shown_untested="25" untested_capped="1" script_gates_unmodelled="332" at="9cf0b16f3+dirty">
<t p="./test/adaptivecutshapefix/adaptive_cut_shape_test.cpp" run="bash test/adaptivecutshapecheck.sh"/>
<t p="./test/verify_radix.cpp"/>
<u sym="buildGraph" p="./src/graph.h" ccx="712"/>
<u sym="dispatchMcpLine" p="./src/mcp.h" ccx="428"/>
…
</test-gate>

A run= attribute appears only when a runner is derivable from real evidence — a test-dir script whose stem matches the harness, or whose text names it. No run= means not derivable, never a guessed suite command. script_gates_unmodelled="332" is the same discipline: script-to-binary is not a call edge, so those gates are invisible to this walk, and the number says so rather than letting tests="2" read as complete. The <u> rows are the untested blast radius: impacted symbols that no test in the corpus reaches.run= 属性仅在运行器可从真实证据导出时出现——即词干与测试工具匹配的测试目录脚本,或其文本中命名了该工具的脚本。没有 run= 意味着不可导出,绝非猜测的套件命令。script_gates_unmodelled="332" 遵循相同的纪律:脚本到二进制不是调用边,因此这些门对本次遍历是不可见的,数字说明了这一点,而不是让 tests="2" 被解读为完整。<u> 行是未经测试的爆炸半径:没有任何语料库中的测试能到达的受影响符号。

--from-trace — hand it the stack trace, sanitizer report or compiler error itself, not a paraphrase--from-trace — 直接输入堆栈跟踪、清理器报告或编译器错误本身,而非其释义

From an error, not a paraphrase of one — --from-trace takes a stack trace, sanitizer report or compiler error on stdin or from a file, maps its frames onto indexed symbols innermost-first, and returns the innermost in-corpus body with them:来自错误,而非错误的释义——--from-trace 从标准输入或文件中接收堆栈跟踪、清理器报告或编译器错误,将其帧映射到索引符号(最内层优先),并返回其中最内层的语料库内函数体:

./build/ripwire . --from-trace=asan_report.txt
cmake --build build 2>&1 | ./build/ripwire . --from-trace=-

What's new新内容

New (2026-08-30)新功能(2026-08-30) — each measured, dated, and re-derivable; the losses and caveats stated in place新功能(2026-08-30)——每一项均经过测量、注明日期并可重新导出;损失和注意事项已在原处说明
  • --slice-flow=back|fwd|both — cross-statement data-flow slicing (ARISE rung 2, arXiv:2605.03117). A bounded BFS from one variable over line-granular reaching-definition edges — backward to the statements whose values feed it, forward to the statements its value reaches — that stops at function boundaries, exactly as the paper's own slicer does. --slice-depth=1..32 bounds it (default 8, always disclosed as depth=); a bound that cuts a row says flow_truncated="1"; without the new flags the v1 output is byte-identical. Measured on the registered fix-commit protocol over this repository's own history (7 commits / 38 instances, cpp only — a thin corpus, reported as thin): flow rows lift function-level added-line recall 0.163 → 0.198, at a mean 4,993 output bytes — 25% of the 20,034-byte --expand whole-body baseline whose recall is 1.0 by construction. (bench/slice/run_slicerecall.py; protocol, per-instance ledger and caveats in docs/EVALS.md.)--slice-flow=back|fwd|both — 跨语句数据流切片(ARISE 梯级 2,arXiv:2605.03117)。从一个变量开始,在细粒度的到达定义边上进行有界 BFS——向后指向为其提供值的语句,向前指向其值到达的语句——并在函数边界处停止,正如该论文自身的切片器所做的那样。--slice-depth=1..32 对其进行限制(默认 8,始终作为 depth= 公开);截断行的限制表示 flow_truncated="1";没有新标志时,v1 输出与字节一致。在针对本仓库自身历史的注册修复提交协议上进行测量(7 次提交 / 38 个实例,仅 cpp——一个薄语料库,报告为薄):流切片行将函数级添加行召回率从 0.163 提升至 0.198,平均输出字节为 4,993 字节——仅为 20,034 字节的 --expand 全主体基准的 25%,其召回率按构造为 1.0。(bench/slice/run_slicerecall.py;协议、每个实例的分类账和注意事项见 docs/EVALS.md。)
  • The --slice v1 contract got its first measured numbers (registered 2026-08-28, no numbers until now): per-variable line-recall 0.726, hit-all rate 0.632, over-inclusion 3.77×. The misses were inspected one by one and are dominated by the measurement's own relevance oracle — a word-regex that matches short identifiers inside comments and string literals, occurrences the slicer correctly refuses to call variable uses — so 0.726 is a floor under a noisy oracle; no inspected instance showed a real occurrence the slice dropped.--slice v1 合约获得了其首次测量数字(2026-08-28 注册,此前无数字):每个变量的行召回率为 0.726,全命中率为 0.632,过度包含率为 3.77×。漏报项被逐一检查,主要由测量自身的关联预言机(一种匹配注释和字符串字面量中短标识符的词正则,切片器正确拒绝将其称为变量使用)主导——因此 0.726 是在嘈杂预言机下的下限;没有检查到的实例显示切片器遗漏了真实发生的情况。
  • --expand no longer hangs on minified bundles: the secret-redaction sweep was quadratic in LINE length. Invisible on ~100-byte source lines, fatal on a 2.9 KB-average-line minified bundle: one selector in babel's 2.1 MB / 768-line yarn bundle never completed (killed at 1,343.9 s of user CPU with an empty output file; 196.7 s is the only clean lower bound) and now answers in 0.46 s warm; the self-contained 20 KB single-line fixture went 23.02 s → 0.017 s (~1350×). A pure memoization, so an output no-op — 120/120 invocations byte-identical across 24 corpora × 5 verb shapes — gated on behaviour only (test/redactfixcheck.sh), with the timings a ledger row in bench/PROFILE.md, never a red-CI threshold.--expand 不再在压缩包上挂起:秘密编辑扫描在行长度上呈二次方增长。在 ~100 字节的源码行上不可见,但在 2.9 KB 平均行的压缩包上是致命的:babel 2.1 MB / 768 行 yarn 包中的一个选择器从未完成(在 1,343.9 秒用户 CPU 时间后被杀死,输出文件为空;196.7 秒是唯一干净的下限),现在在 0.46 秒内热启动完成;自包含的 20 KB 单行夹具从 23.02 秒降至 0.017 秒(~1350×)。纯粹的记忆化,因此输出无变化——120/120 次调用在 24 个语料库 × 5 种动词形状下字节一致——仅在行为上门控(test/redactfixcheck.sh),定时是 bench/PROFILE.md 中的分类账行,绝非红色 CI 阈值。
New (2026-08-23)新功能(2026-08-23) — each measured on this tree's binary, with the command that re-derives it新功能(2026-08-23)——每一项均在本树的二进制文件上测量,并附有可重新导出它的命令
  • --pattern — structural search written in CODE, not in node kinds. --pattern='foo($X, ...)' where $NAME binds one node, $_ binds nothing and ... is an ellipsis over siblings; comments are transparent, everything else is kind- and text-exact. Served across 13 grammar objects (11 languages), and it refuses rather than lying: a pattern no served grammar resolves, or that collapses to a bare token, exits 1 naming the served and unserved families — never hits=0. (./build/ripwire . --pattern='VERIFY($X)' on this repo: 101 hits over 625 eligible files, each row carrying its enclosing symbol; --pattern='$X' exits 1 with the refusal text.)--pattern — 用代码而非节点类型编写的结构化搜索。--pattern='foo($X, ...)' 其中 $NAME 绑定一个节点,$_ 绑定空,... 是兄弟节点的省略号;注释是透明的,其他所有内容都是类型和文本精确匹配。在 13 个语法对象(11 种语言)中提供,它拒绝而非撒谎:如果模式没有被任何语法解析,或者坍缩为裸 token,它会退出并返回 1,列出已服务和未服务的证据族——绝不会出现 hits=0。(./build/ripwire . --pattern='VERIFY($X)' 在本仓库:625 个符合条件的文件中有 101 次命中,每一行都携带其包含的符号;--pattern='$X' 以拒绝文本退出 1。)
  • --safe-delete=SYM — "can I delete this?" in ONE call. Composes the signals the tool already computes for a resolved symbol: 1-hop callers, the transitive blast radius, every read/write/ import/call site, how much of that radius any test reaches, and --dead-code's own shape — then reports risk= as a fact, never a go/no-go verdict. (--safe-delete=coversOrEquals: callers="2" impact_reaches="17" uses="2" radius_tested="0" radius_untested="17" dead_code_candidate="0" risk="untested-radius".)--safe-delete=SYM — 在一次调用中询问“我可以删除这个吗?”。组合工具已经为解析后的符号计算的信号:1 跳调用者、传递爆炸半径、每个读/写/导入/调用点、测试覆盖该半径的程度,以及 --dead-code 自身的形状——然后将 risk= 作为事实报告,绝非 go/no-go 结论。(--safe-delete=coversOrEquals: callers="2" impact_reaches="17" uses="2" radius_tested="0" radius_untested="17" dead_code_candidate="0" risk="untested-radius"。)
  • --impact grew a disclosed import tier. A class whose consumers #include or require the file that defines it used to look like it had no blast radius at all. importers= is now a second, weaker reach beside reaches= — with its own cap pair and <f via="import"> rows, and never summed into reaches=, because files and symbols are different units. (--impact=IngestResult on this repo: reaches="0" importers="70" shown_importers="40" importers_capped="1" — a symbol that reads as unreachable by calls and is included by 70 files.)--impact 增加了一个公开的导入层级。一个消费者 #include 或 require 定义它的文件的类,过去看起来好像根本没有爆炸半径。importers= 现在是 reaches= 旁边的第二个、较弱的覆盖范围——带有其自己的上限对和 <f via="import"> 行,并且从不计入 reaches=,因为文件和符号是不同的单位。(--impact=IngestResult 在本仓库:reaches="0" importers="70" shown_importers="40" importers_capped="1" ——一个在调用中显示为不可到达且被 70 个文件包含的符号。)
  • Conceptual --for queries serve a compact map instead of inline bodies. Bodies were 52.7% of every conceptual-query byte — the one class that missed the byte target — so the subtoken+body route now ships the ranked map plus one-hop <hops> edge context and no body CDATA, disclosed on the root as bundle="compact" bodies="0" reason="compact-route". Across the frozen 15-query class-B set that is 184,857 B → 95,256 B, −48.5%, with all 11 judged-decisive markers still present (better than either pre-existing lever's 10/11). --auto-bodies is a permanent opt-out, not a migration aid. (One pair on this repo, re-derived 2026-08-23: --for="incremental cache invalidation" 8,487 B compact vs 12,044 B with --auto-bodies, −29.5%; the 15-query total is docs/EVALS.md §5.)概念性 --for 查询现在提供紧凑映射而非内联主体。主体占每个概念查询字节的 52.7%——唯一未达到字节目标的类别——因此 subtoken+主体路径现在发布排名映射加上单跳 <hops> 边上下文,且无主体 CDATA,在根节点上披露为 bundle="compact" bodies="0" reason="compact-route"。在冻结的 15 个查询 B 类集合中,字节数从 184,857 B 降至 95,256 B,减少 48.5%,所有 11 个判定性标记仍然存在(优于任何预先存在的杠杆的 10/11)。--auto-bodies 是永久性的选择退出,而非迁移辅助。(本仓库上的一对,2026-08-23 重新导出:--for="incremental cache invalidation" 8,487 B 紧凑 vs 12,044 B 使用 --auto-bodies,减少 29.5%;15 个查询总计见 docs/EVALS.md §5。)
  • --pack-task orders callers by corroboration. A neighbour reached by several of the bundle's top anchors is more likely to be the thing you must touch than one reached by exactly one, so rows sort by shared= — the count of top-K anchors that reach them — omitted at 1 because that is what every 1-hop row satisfies by construction. (--pack-task="emit the minified xml map" puts escapeXml first at shared="4".)--pack-task 按共识对调用者进行排序。被包中多个顶级锚点到达的邻居,比被正好一个锚点到达的邻居更有可能是你必须触及的内容,因此行按 shared= 排序——即到达它们的 Top-K 锚点计数——在为 1 时省略,因为这是每个 1 跳行按构造满足的内容。(--pack-task="emit the minified xml map" 将 escapeXml 置于首位,shared="4"。)
  • --lint rolls up per rule, so a capped view stops hiding whole rules. Every rule gets a <rule name= count= shown_rows= rows_capped=/> row, and a rule whose registered languages match nothing in the corpus carries applicable="0" so its zero reads as structural inertness rather than a measurement. On this repository the default view shows 692 of 3,332 findings — and 14 of the 31 rules that fired contribute zero shown rows, 368 findings whose only evidence is their count=. (./build/ripwire . --lint, counted from the <rule> rows.)--lint 按规则汇总,因此上限视图不再隐藏整个规则。每条规则都会获得一行 <rule name= count= shown_rows= rows_capped=/>,且注册语言在语料库中无匹配的规则会携带 applicable="0",因此其零计数被解读为结构性惰性而非测量结果。在本仓库中,默认视图显示 3,332 个发现中的 692 个——触发的 31 条规则中有 14 条贡献了零显示行,368 个发现的唯一证据是它们的 count=。(./build/ripwire . --lint,从 <rule> 行计数。)
  • PHP and Lua joined the language line, with their floors stated rather than implied: PHP's dynamic dispatch ($fn(), call_user_func, __call) names its callee at run time and is a declared floor; a Lua corpus reports no inheritance edges, because metatable inheritance is a runtime call with no syntax to read.PHP 和 Lua 加入了语言行,并明确说明了它们的下限而非隐含:PHP 的动态分派($fn(), call_user_func, __call)在运行时命名其被调用者,是一个声明的下限;Lua 语料库报告没有继承边,因为元表继承是运行时调用,没有可读取的语法。
Earlier — New (2026-08-15)新功能(2026-08-15), kept with its own dates rather than overwritten更早之前 — 新功能(2026-08-15),保留其日期而非覆盖
  • --expand answers "show me this function" in one call, −47.3% tokens — an exact-name ask now skips the ranked-map preamble by default and the body arrives with its file's sibling symbols and imports inline (sibs=/inc=), so the follow-up "what else is in this file?" call never happens. (Re-derived 2026-08-15 fix-expand round: --expand=emitGrepReport — 47,252 B classic 200-row-map bundle vs 24,911 B today's exact-name default, on this repo; the figure moves as the corpus grows and is not itself CI-gated, so re-measure before citing it in a future round.)--expand 在一次调用中回答“向我展示这个函数”,减少 47.3% 的 token——精确名称询问现在默认跳过排名映射前导码,且主体随其文件的兄弟符号和导入内联到达(sibs=/inc=),因此后续“这个文件中还有什么?”的调用永远不会发生。(2026-08-15 fix-expand 轮次重新导出:--expand=emitGrepReport —— 在本仓库上,47,252 B 经典 200 行映射包 vs 24,911 B 今日精确名称默认值;该数字随语料库增长而移动,且本身未进行 CI 门控,因此在未来轮次引用前请重新测量。)
  • --grep groups, deduplicates, and speaks boolean — per-file grouping, identical-line collapse ("this exact guard appears at 6 call sites" is the finding), and --and=/--not=/--grep-scope=: a two-term ask returns the complete answer at −78% of the single-term dump. Default view now runs at ~clean-grep cost while naming the enclosing symbol for every hit.--grep 分组、去重并支持布尔值——按文件分组、相同行折叠(“这个精确的防护出现在 6 个调用点”是发现结果),以及 --and=/--not=/--grep-scope=:双项询问返回完整答案,仅为单项转储的 22%。默认视图现在以 ~clean-grep 的成本运行,同时为每次命中命名包含的符号。
  • C++ maps got materially truer: out-of-line definitions past one qualifier (Outer::Inner::method(){} — the house style of large C++ codebases) were silently invisible; on one 6,600-file production tree that was ~15% of qualified definitions. Now indexed at any depth.C++ 映射变得更加真实:超过一个限定符的行外定义(Outer::Inner::method(){} ——大型 C++ 代码库的风格)以前是隐形不可见的;在一个 6,600 文件的生产树中,这约占限定定义的 15%。现在在任何深度均可索引。
  • Compound --graph-query filters run ~25× faster via predicate pushdown — an exact algebraic identity, byte-identical output, gate-enforced.复合 --graph-query 过滤器通过谓词下推运行速度快约 25 倍 —— 一种精确的代数恒等式,字节一致的输出,由门控强制执行。

Measured测量结果

Every published number lives in docs/EVALS.md with the instrument that produced it, the corpus it ran on, and the in-tree file that pins it — alongside a counterexample section and a list of the claims this project deliberately does not publish. Read those first if you are here to check whether the tool is oversold.每个已发表的数字都存在于 docs/EVALS.md 中,附带产生它的仪器、运行它的语料库以及固定它的树内文件——旁边还有一个反例部分和本项目特意不发表的主张列表。如果你来这里是为了检查该工具是否被过度推销,请先阅读这些内容。

Against other tools与其他工具的对比

Round 4 (re-run in full 2026-08-08): 58.3% strict file@10 against 40.0% for the best competitor — a 1.46× margin, at a 0.31 s index. N = 60 paired instances, zero exclusions, one binary (the profile-guided release build that now ships), one evaluator, all arms re-run on the same day. Strict file@10 = all gold files inside the top 10.第 4 轮(2026-08-08 全面重新运行):58.3% 的严格 file@10,而最佳竞争对手为 40.0% —— 1.46 倍的差距,索引时间为 0.31 秒。N = 60 个配对实例,零排除,一个二进制文件(现已发布的配置文件引导发行版),一个评估器,所有分支在同一天重新运行。严格 file@10 = 所有黄金文件都在前 10 名内。

Arm strict file@10 any@10 index (median) query (median)
ripwire --for 58.3% 85.0% 0.31 s 0.108 s
codebase-memory-mcp 0.9.0 40.0% 63.3% 1.24 s 0.075 s
repowise 0.37.0 (MCP search_codebase, LLM-free wiki) 33.3% 53.3% 34.0 s¹ 1.159 s¹
graphify 0.9.34 (--code-only --no-cluster, keyless) 31.7% 46.7% 7.82 s 0.614 s
Aider repo-map 0.86.2 (ident-personalized) 20.0% 35.0% (inside query) 2.920 s
Aider repo-map 0.86.2 (no-personalization control) 10.0% 25.0% (inside query) 0.818 s
codeseek 0.1.31 (ident-mention convention arm) 15.0% 20.0% 3.37 s 0.040 s
codeseek 0.1.31 (raw issue text, keyless fallback) 0.0%² 0.0% 3.37 s 0.024 s
Round-4 method and the paired losses — one binary, one evaluator, what re-running cost us, and the three limits that travel with this table第 4 轮方法和配对损失 —— 一个二进制文件、一个评估器、重新运行的成本,以及伴随此表的三个限制

Round 4 (first run 2026-08-06; re-run in full 2026-08-08 on the profile-guided release build) — N = 60 paired instances, zero exclusions, one binary, one evaluator. Every competitor was re-run on the same day against the same ripwire binary and the same evaluator, so the arms are directly comparable to each other. Earlier rounds could not say that: r1 (2026-07-13/14) and r2 (2026-08-03) each scored a different subset against a different binary, which is why this page used to print two tables and ask the reader not to compare them. Strict file@10 = all gold files inside the top 10. Harness, per-instance JSONL, and a reproduction recipe: bench/headtohead/r4-2026-08-06/.第 4 轮(首次运行 2026-08-06;2026-08-08 在配置文件引导发行版上全面重新运行)—— N = 60 个配对实例,零排除,一个二进制文件,一个评估器。每个竞争对手都在同一天针对同一个 ripwire 二进制文件和同一个评估器进行了重新运行,因此各分支之间可以直接比较。早期的轮次无法做到这一点:r1 (2026-07-13/14) 和 r2 (2026-08-03) 每一轮都针对不同的二进制文件对不同的子集进行了评分,这就是为什么此页面过去打印两张表并要求读者不要比较它们的原因。严格 file@10 = 所有黄金文件都在前 10 名内。测试工具、每个实例的 JSONL 以及重现配方:bench/headtohead/r4-2026-08-06/。

Paired, ripwire's losses are 2 instances to codebase-memory-mcp, 2 to repowise, 1 each to graphify and aider; codeseek never beat it. Cold from nothing to an answer — parse, rank, reply, no cache — ripwire takes 0.213 s, against a ~34 s index-then-query for repowise, whose worst single index in this run was 352 s. That comparison is only possible because ripwire's own index was measured this round; r2 recorded competitor index walls and deliberately refused to tabulate them, since a one-sided cost table is not evidence.配对来看,ripwire 的损失是:2 个实例输给 codebase-memory-mcp,2 个输给 repowise,各 1 个输给 graphify 和 aider;codeseek 从未击败过它。从零开始到得到答案 —— 解析、排名、回复、无缓存 —— ripwire 需要 0.213 秒,而 repowise 需要 ~34 秒的索引加查询,其在此轮中最差的单次索引为 352 秒。这种比较只有在 ripwire 自身的索引在这一轮被测量时才有可能;r2 记录了竞争对手的索引墙,并特意拒绝进行制表,因为单方面的成本表不是证据。

What re-running cost us, stated because it is the reason to re-run at all. codebase-memory-mcp is the true runner-up at 40.0% — r1 credited it with 26.7%, and scoring it fairly against today's binary raised it. graphify rose 21.7% → 31.7% and aider 13.3% → 20.0% the same way. The margin over the best competitor is therefore 1.46×, not the 1.75× that two separately-dated tables implied; the old framing flattered us by comparing today's ripwire against year-old competitor runs.重新运行的成本,说明这一点是因为它是重新运行的理由。codebase-memory-mcp 是真正的亚军,为 40.0% —— r1 给它记了 26.7%,而将其与今天的二进制文件公平评分后提高了它。graphify 从 21.7% 上升到 31.7%,aider 从 13.3% 上升到 20.0%,方式相同。因此,相对于最佳竞争对手的差距是 1.46 倍,而不是两张不同日期表所暗示的 1.75 倍;旧的框架通过将今天的 ripwire 与一年前的竞争对手运行进行比较而美化了我们。

Three limits travel with this table. ¹ repowise's walls include a fresh MCP-server spawn per query; resident-server usage is faster. ² codeseek's raw row returned 0 results on 60/60 queries — its keyless fallback matches function names only, so that row measures a query-protocol boundary, not its embedder-backed shipping mode (unbenchmarked here). And the slice is Python-dominant — 107 of 134 gold files are .py — so this measures Python localization, not all twelve indexed languages. Vexp and CodeIndexer were excluded, not beaten: their free tiers (node/project/chunk caps) cannot run a fair 60-instance sweep. An independent adversarial pass attacked the r2 comparison's design, and its findings and dispositions ship with that report (VERIFIER.md); r1's and r2's tables remain in their own directories as the historical record.三个限制伴随此表。¹ repowise 的墙包括每次查询生成一个新的 MCP 服务器;驻留服务器的使用速度更快。² codeseek 的原始行在 60/60 次查询中返回 0 个结果 —— 其无密钥回退仅匹配函数名,因此该行测量的是查询协议边界,而非其基于嵌入的发布模式(此处未进行基准测试)。切片是 Python 主导的 —— 134 个黄金文件中 107 个是 .py —— 因此这测量的是 Python 本地化,而非所有十二种索引语言。Vexp 和 CodeIndexer 被排除,而非被击败:它们的免费层级(节点/项目/块上限)无法运行公平的 60 实例扫描。独立的对抗性通道攻击了 r2 比较的设计,其发现和处置随该报告发布(VERIFIER.md);r1 和 r2 的表作为历史记录保留在各自的目录中。

The open problem — multi-file gold: 21.4% strict against 78.6% any@10, and four pre-registered fixes rejected at ±0.00pp未决问题 —— 多文件黄金:21.4% 严格 vs 78.6% any@10,以及四个预注册的修复在 ±0.00pp 被拒绝

Multi-file gold is hard for every arm, including ours, and four attempts have failed to fix it. ripwire leads the stratum at 21.4% strict — but its own any@10 there is 78.6%: it finds a gold file and misses the siblings. If each gold file were an independent draw at the single-file rate (90.6%), multi-file would score 71.2%; it scores 21.4%, so the failures are strongly correlated. The mechanism is that a sibling is a file which changed because the primary changed — the primary carries the issue's vocabulary, the siblings carry the consequences. Four pre-registered rounds (r1_anchorhop, r1cpp_anchorhop, r4_siblift, r5_pooling) have now been rejected at ±0.00pp against it, each archived with its grid and its verdict under bench/locbench/results/.多文件黄金对每个分支来说都很困难,包括我们,且四次尝试均未能修复它。ripwire 在该层级以 21.4% 的严格率领先 —— 但其 any@10 为 78.6%:它找到了一个黄金文件,但漏掉了兄弟文件。如果每个黄金文件都是单文件率 (90.6%) 下的独立抽奖,多文件得分将为 71.2%;而它得分 21.4%,因此失败是强相关的。其机制是兄弟文件是因为主文件改变而改变的 —— 主文件承载问题的词汇,兄弟文件承载后果。四个预注册轮次(r1_anchorhop, r1cpp_anchorhop, r4_siblift, r5_pooling)现已在 ±0.00pp 被拒绝,每个都存档了其网格和结论,位于 bench/locbench/results/ 下。

Round 3 (2026-08-03) — headroom, the compression-layer competitor: 0 tokens saved on ripwire's output, and 5/12 losses published first第 3 轮(2026-08-03)—— 净空(headroom),压缩层竞争对手:ripwire 的输出节省了 0 个 token,且 5/12 的损失优先发布

Round three (2026-08-03): headroom — the compression-layer competitor. headroom (headroom-ai==0.33.0, 64k★) compresses context an agent already fetched; it retrieves nothing — so this round's instrument is tokens-to-correct-answer on 12 pre-registered mid-task questions (django @ pinned commit, five arms, one tokenizer), not file@k. ripwire won every measure the two tools share. headroom's default config passed every code chunk through byte-identical — its own protective guards fired throughout, netting −410 tokens on a 685,682-token workload (its own limitations page says "Code — Passthrough"; this run confirms it live) — and stacking it on ripwire's output added exactly 0 tokens of savings: the map is already past the density compression targets. As measured then, ripwire answered at 7.3% of the naive grep-and-read baseline's tokens (1.7% on the subset both arms fully answered), warm in ~0.14 s per verb. Those two figures were re-derived on 2026-08-23 and now read 5.0% and 5.2% — the block below. The losses in this round are ripwire's own, and they are published first: under the frozen no-human verb ladders it strictly satisfied only 5/12 questions vs the naive baseline's 11/12 — four ranking defects, one missing symbol kind, two harness artifacts, each bucketed with its fix disposition in the report. What the round does not show: headroom's home turf (JSON/log tool-output compression, provider-cache economics) was deliberately not measured — ripwire does not compete there. Provenance: docs/EVALS.md §2, full record + adversarial verification (which materially corrected the draft's arithmetic in headroom's favor) in bench/headtohead/r3-headroom-2026-08-03/.第三轮(2026-08-03):净空 —— 压缩层竞争对手。headroom (headroom-ai==0.33.0, 64k★) 压缩代理已经获取的上下文;它不检索任何内容 —— 因此这一轮的仪器是 12 个预注册的中途任务问题(django @ 固定提交,五个分支,一个分词器)上的“token 到正确答案”,而非 file@k。ripwire 在两个工具共享的每个度量上都获胜。headroom 的默认配置将每个代码块原样通过 —— 其自身的保护性防护在整个过程中触发,在 685,682 个 token 的工作负载上净亏损 -410 个 token(其自身的限制页面说“代码 —— 直通”;此运行实时确认了这一点)——且将其堆叠在 ripwire 的输出上节省了 0 个 token:映射已经超过了密度压缩目标。正如当时所测量的,ripwire 以 naive grep-and-read 基准 token 的 7.3% 进行回答(在两个分支都完全回答的子集上为 1.7%),在每个动词上热启动约 0.14 秒。这两个数字在 2026-08-23 重新导出,现在读作 5.0% 和 5.2% —— 下方的块。这一轮的损失是 ripwire 自身的,它们被优先发布:在冻结的无人类动词阶梯下,它严格满足了 5/12 的问题,而 naive 基准为 11/12 —— 四个排名缺陷、一个缺失符号类型、两个测试工具人工制品,每个都在报告中分类说明了修复处置。该轮次未显示的内容:headroom 的主场(JSON/日志工具输出压缩、提供者缓存经济学)特意未进行测量 —— ripwire 不在那里竞争。来源:docs/EVALS.md §2,完整记录 + 对抗性验证(实质上修正了草案中对 headroom 有利的算术)位于 bench/headtohead/r3-headroom-2026-08-03/。

Round 3, re-derived 2026-08-23 — one headline improved, the other got worse, and both are printed第 3 轮,2026-08-23 重新导出 —— 一个标题改善了,另一个变差了,两者都已打印

The 2026-08-03 round is frozen; this is the same instrument pointed at today's binary. Arms A (idealized grep-and-read) and C (ripwire's pre-registered verb ladders) were re-run from the committed harness.py, importing its metric functions unmodified — same questions.json, same frozen arms_spec.json ladders, same tiktoken cl100k_base counter, same corpus pin (django/django @ 70f39e46). The headroom arms (B/B′/D) were not re-run; they contribute nothing to the ripwire-vs-naive ratio, and the round's finding about them is a passthrough result that does not depend on ripwire's side.2026-08-03 轮次已冻结;这是针对今日二进制文件的相同仪器。分支 A(理想化的 grep-and-read)和 C(ripwire 的预注册动词阶梯)从提交的 harness.py 重新运行,未修改地导入其度量函数 —— 相同 questions.json,相同冻结的 arms_spec.json 阶梯,相同 tiktoken cl100k_base 计数器,相同语料库固定(django/django @ 70f39e46)。headroom 分支(B/B′/D)未重新运行;它们对 ripwire-vs-naive 比率没有任何贡献,且该轮次关于它们的发现是一个直通结果,不依赖于 ripwire 的一方。

The naive arm reproduced exactly — all 12 questions token-for-token, 685,682 t in total — which is what makes the comparison a measurement of ripwire's change and not of drift somewhere else. Satisfaction did not move either: 5/12 for ripwire, 11/12 for naive, and the both-satisfied set is the identical {q02, q03, q04, q05, q11}.naive 分支完全重现 —— 全部 12 个问题 token 对 token,总计 685,682 t —— 这使得比较成为对 ripwire 变化的测量,而非其他地方漂移的测量。满意度也没有移动:ripwire 为 5/12,naive 为 11/12,且两者都满足的集合是相同的 {q02, q03, q04, q05, q11}。

2026-08-03 2026-08-23
naive (arm A) total 685,682 t 685,682 t reproduced to the token
ripwire (arm C) total 50,138 t 33,948 t −32.3%
overall ripwire ÷ naive 7.3% 5.0% better
both-satisfied, naive 219,223 t 219,223 t same 5 questions
both-satisfied, ripwire 3,775 t 11,471 t +204%
both-satisfied ripwire ÷ naive 1.7% (58×) 5.2% (19×) worse
ripwire tokens spent on its own misses 92.5% 66.2%

Why they moved apart. The compact conceptual route made the seven questions ripwire misses dramatically cheaper — q07 13,198 → 4,416 t, q08 11,192 → 2,016 t, q01 11,974 → 3,045 t — which is what pulls the overall share down. On the five it answers, richer default bundles cost more: q05 522 → 6,736 t and q11 280 → 1,373 t dominate that column. The 58× figure was always the flattering framing of a 5-of-12 result, and the honest reading of the pair is that ripwire got much better at being wrong cheaply and somewhat more expensive at being right. Nothing about the four ranking defects, the missing symbol kind or the two harness artifacts in the original loss buckets has been re-adjudicated here — the satisfaction column is unchanged, so those losses stand.为什么它们分开了。紧凑概念路径使得 ripwire 漏掉的七个问题变得极其便宜 —— q07 13,198 → 4,416 t,q08 11,192 → 2,016 t,q01 11,974 → 3,045 t —— 这拉低了总体份额。在它回答的五个问题上,更丰富的默认包成本更高:q05 522 → 6,736 t 和 q11 280 → 1,373 t 主导了该列。58 倍的数字一直是 5/12 结果的美化框架,对这对数据的诚实解读是:ripwire 在廉价地出错方面变得更好,而在正确方面变得稍微昂贵了一点。四个排名缺陷、缺失符号类型或原始损失桶中的两个测试工具人工制品没有任何内容在此处经过重新裁决 —— 满意度列未变,因此那些损失依然存在。

LocBench held-out, N = 243 across 78 repositories. Strict file@10 60.9%, against 27.6% for the pre-routing baseline — a paired +33.33pp with a clustered-bootstrap 95% lower bound of +25.00pp, bought for +3.4% warm latency and −39.4% on the production token ceiling. More accurate and cheaper, which is why it shipped.LocBench 留出,N = 243,横跨 78 个仓库。严格 file@10 60.9%,相对于预路由基准的 27.6% —— 配对 +33.33pp,聚类引导 95% 下限为 +25.00pp,以 +3.4% 的热延迟和生产 token 上限 -39.4% 的代价换取。更准确且更便宜,这就是它发布的原因。

What it saves you, in tokens它为你节省了什么,以 token 计

Context is the budget an agent actually spends. Three measurements, each with the instrument that pins it:上下文是代理实际花费的预算。三次测量,每一项都附有固定它的仪器:

Where the saving comes from Measured Pinned by
--pack-signatures — body-elided declaration skeletons instead of full bodies 80.2% fewer element bytes at top-50 (84.5% at top-10, 80.6% at top-100) — re-derived 2026-08-30 test/showcasecapturecheck.sh, re-derived from this repo every run
Query-shape routing, on the production token ceiling −39.4% p50, while strict file@10 rose +33.33pp bench/locbench/, EVALS §3
A whole-question bundle against a naive agent read 96.0% fewer tokens (24.9×) — 14,758 against 367,192, tiktoken cl100k_base, six realistic questions bench/BENCHMARK.md — historical, private corpus, not reproducible from this tree
Read this before quoting those numbers — root-neutralised bytes, the private-corpus caveat, and the two verbs where the saving inverts在引用这些数字之前阅读此内容 —— 根中性化字节、私有语料库注意事项,以及节省反转的两个动词

Read the first row's methodology before quoting it: element bytes are counted root-neutralised, with the corpus-root prefix subtracted from both sides, because the root repeats inside every element, is charged in both forms, and is not what this verb elides. Quote the top-50 figure — the signature payload is top-50 whatever --top-k says, and top-10 is a ten-symbol sample that one one-line accessor can move several points. The gate fails if the documentation drifts more than 1.5 points from the binary.在引用第一行的方法论之前请阅读它:元素字节是按根中性化计算的,从两侧减去了语料库根前缀,因为根在每个元素内部重复,以两种形式收费,且不是该动词省略的内容。引用 top-50 数字 —— 无论 --top-k 说什么,签名有效载荷都是 top-50,而 top-10 是一个十符号样本,一个单行访问器可以移动几个点。如果文档与二进制文件漂移超过 1.5 个点,门控将失败。

And the third row's caveat is not small: it was measured 2026-06-20 on a large private C++ corpus, it is not publicly reproducible from this tree, and it proves cheaper and faster, not better outcomes.第三行的注意事项并不小:它是在 2026-06-20 在一个大型私有 C++ 语料库上测量的,不能从本树公开重现,它证明了更便宜和更快,而不是更好的结果。

The losses ship next to the wins. --grep's 2026-06 anti-headline (+19.7% / −11.2% vs raw grep) was re-derived 2026-08-15 after the emission overhaul: the un-tiered view — --grep-in=any, which was the default when this was measured — lands at −1.9% / +4.3% of a clean grep dump while carrying enclosing symbols and in-band honesty grep cannot give — one term either side of parity, which is not a headline in either direction — but an uncapped dump of that same un-tiered view remains token-negative (+150% / +214%), and this project still says so. (Span tiers landed 2026-08-19 and made the default a filtered view of the same scan; every byte number on this page is the un-tiered one, deliberately — the instrument may not move under a display change — so none of them describes today's default. See docs/EVALS.md §grep.) Nor is that the worst regime: on small-hit uncapped answers the fixed per-answer legend is not amortized over anything, and a gated set of twelve such queries on this repository runs +65.1% median, larger than plain grep on 12 of 12. When the agent knows a second term, --grep=A --and=B flips hard positive (−77.7% measured, complete both sides). --pack-signatures inverts on a short symbol: 303 bytes of signature-plus-doc-comment against a 158-byte body. The headline is a property of large result sets, and the full counterexample list is part of the contract, not an appendix — the four-fact grep re-derivation lives in docs/EVALS.md §5.损失与胜利并存。--grep 的 2026-06 反标题(+19.7% / −11.2% vs 原始 grep)在 2026-08-15 发射大修后重新导出:非分层视图 —— --grep-in=any,这是测量时的默认值 —— 落在 clean grep 转储的 −1.9% / +4.3%,同时携带了 grep 无法给出的包含符号和带内诚实度 —— 处于平价的一侧,在任何方向上都不是标题 —— 但同一非分层视图的未上限转储仍然是 token 负值的(+150% / +214%),本项目仍然这样说。(Span 层级于 2026-08-19 落地,使得默认值成为同一扫描的过滤视图;此页面上的每个字节数字都是特意未分层的 —— 仪器在显示变化下不得移动 —— 因此它们没有一个描述今天的默认值。见 docs/EVALS.md §grep。)这也不是最糟糕的情况:在小命中未上限的答案上,固定的每答案图例没有在任何东西上摊销,且本仓库上一组 12 个此类查询的门控集合运行中位数 +65.1%,在 12/12 上大于普通 grep。当代理知道第二个术语时,--grep=A --and=B 会大幅翻转为正(测量到 −77.7%,两侧完整)。--pack-signatures 在短符号上反转:303 字节的签名加文档注释 vs 158 字节的主体。标题是大结果集的一个属性,完整的反例列表是合同的一部分,而非附录 —— 四事实 grep 重新导出存在于 docs/EVALS.md §5。


Where its own cycles go — hardware counters, per scope它自身的周期去向哪里 —— 硬件计数器,按作用域

Every pipeline phase is bracketed by two hardware-counter reads, and the numbers say what wall-clock cannot. Parse and query retire 3.2–3.5 instructions per cycle; the graph phases stream at 32–35 L1D MPKI and still hold IPC above 3.1 (guardrail G2 doing its visible job); and a warm run replaces the dominant phase's 8.74 B instructions with a 52.3 M-instruction cache load, ≈167× fewer. Two opt-in builds go faster still — PGO by 14–25% cold — with byte-identical output on every one.每个流水线阶段都由两个硬件计数器读取所包围,数字说明了挂钟时间无法说明的内容。解析和查询每周期退休 3.2–3.5 条指令;图阶段以 32–35 L1D MPKI 流式传输,仍保持 IPC 高于 3.1(护栏 G2 正在执行其可见工作);热运行用 52.3 M 指令缓存加载替换了主导阶段的 8.74 B 指令,≈167 倍减少。两个可选构建运行得更快 —— PGO 冷启动快 14–25% —— 每一个的输出都是字节一致的。

How the self-profiler measures — kperf / perf_event_open, the per-scope counter table, and the three things it says that wall-clock cannot自分析器如何测量 —— kperf / perf_event_open,每作用域计数器表,以及它说的挂钟时间无法说的三件事

The self-profiler (-DRIPWIRE_PROFILE=ON; src/infra/profileScope.h + profilePmc.h) brackets every pipeline phase with two hardware-counter reads — kperf on Apple Silicon, a pinned perf_event_open group on Linux. Below: ripwire mapping its own public tree on an Apple M5 Pro, cold (--no-cache) except the last row. Counters are raw integers, never scaled; reproduce steps in bench/PROFILE.md (arming needs root; unprivileged runs print the same table with timing columns only — the honest degrade). The report renders on stderr; stdout stays the deterministic XML map, so redirects and | xmllint pipes behave the same in the profile flavour.该自分析器(-DRIPWIRE_PROFILE=ON;src/infra/profileScope.h + profilePmc.h)通过两次硬件计数器读取来界定每个流水线阶段——在 Apple Silicon 上使用 kperf,在 Linux 上使用固定的 perf_event_open 组。下图所示:ripwire 在 Apple M5 Pro 上映射其自身的公共树,除最后一行外均为冷启动(--no-cache)。计数器为原始整数,从不进行缩放;复现步骤见 bench/PROFILE.md(启用需要 root 权限;非特权运行仅打印包含时间列的相同表格——诚实的降级)。报告在 stderr 上渲染;stdout 保持为确定性的 XML 映射,因此重定向和 | xmllint 管道在分析模式下表现一致。

scope calls instructions IPC L1D MPKI wall
tree-sitter parse 803 8.74 B 3.52 4.0 731 ms
tags query exec + captures 803 8.65 B 3.22 3.0 635 ms
resolve refs + build CSR 1 54.6 M 3.27 35.4 3.6 ms
PageRank (power iteration) 1 13.7 M 3.17 32.4 0.93 ms
serialize ranked map 1 3.24 M 2.43 6.1 0.29 ms
warm run — loadCache (read + deserialize) 1 52.3 M 3.18 7.5 3.6 ms

Three things the counters say that wall-clock alone cannot. The parse/query phases are compute-dense, not stall-bound: 3.2–3.5 instructions retired per cycle at ~3–4 L1D misses per thousand. The graph phases stream hard — 32–35 L1D MPKI — yet hold IPC above 3.1, which is the DOD/SoA/CSR layout (G2) doing its visible job. And the auto-cache's whole story in two rows: a warm run replaces the dominant phase's 8.74 B instructions with a 52.3 M-instruction cache load, ≈167× fewer instructions. Caveats travel with the table: counters are per-thread and aggregated per scope, so rows must not be summed across scopes (a recursive site samples only its outermost frame); one machine, one corpus — re-run on yours. Backend contract is gated by test/pmccheck.sh; M5 Pro event names verified (the last-level alias resolves via PL2_CACHE_MISS_LD).计数器揭示了三个仅靠挂钟时间无法发现的事实。解析/查询阶段是计算密集型的,而非停顿受限的:每个周期退休 3.2–3.5 条指令,每千条指令 L1D 缺失约 3–4 次。图计算阶段流式传输压力大——32–35 L1D MPKI——但 IPC 仍保持在 3.1 以上,这是 DOD/SoA/CSR 布局(G2)发挥了其可见作用。自动缓存的完整故事仅需两行说明:热启动运行将主阶段的 87.4 亿条指令替换为 5.23 亿条指令的缓存加载,指令数减少了约 167 倍。表格附带注意事项:计数器是按线程且按作用域聚合的,因此行数不能跨作用域求和(递归站点仅采样其最外层框架);一台机器,一个语料库——请在您的机器上重新运行。后端契约由 test/pmccheck.sh 门控;M5 Pro 事件名称已验证(末级缓存别名通过 PL2_CACHE_MISS_LD 解析)。

The two opt-in faster builds — LTO on by default, PGO at 14–25% cold, and why the output stays byte-identical两个可选的更快构建方式——默认开启 LTO,冷启动时 PGO 提升 14–25%,以及为什么输出保持字节一致

Every number on this page is the DEFAULT build — and there is a faster one you can opt into. A clang optimization-remarks pass over src/ (-DRIPWIRE_OPT_REMARKS=ON; the whole triage is in docs/OPTREMARKS.md) found that the phases above spend their time calling tree-sitter's C API across a translation-unit boundary — 397 of 636 distinct inline/NoDefinition remarks in the hot TU name a ts_* accessor. Two build options answer that, both off by default:本页上的每个数字均为默认构建版本——您还可以选择更快的版本。对 src/ 进行的 clang 优化备注检查(-DRIPWIRE_OPT_REMARKS=ON;全部分类在 docs/OPTREMARKS.md 中)发现,上述阶段花费时间在翻译单元边界调用 tree-sitter 的 C API——在热点 TU 中 636 个不同的 inline/NoDefinition 备注里,有 397 个指向 ts_* 访问器。两个默认关闭的构建选项解决了这个问题:

build cold warm
-DRIPWIRE_LTO=OFF baseline baseline the fast edit loop, not the fast binary
default (cmake -S . -B build, LTO on) 1–6% faster 0–3% faster
scripts/pgobuild.sh (PGO on top of LTO) 14–25% faster (6–16% over the default) 5–10% faster the fastest binary this tree can produce

Measured by interleaved A/B (A,B,A,B,…, median and min, 9–31 runs per arm, repeated) on this repository and on a ~2000-file C++ tree that appears in no training run — the held-out corpus shows the same or larger gain, which is what rules out training on the benchmark. Output is byte-identical on all three builds and on both corpora, and the determinism gate passes on every tree; these options change how fast the answer arrives, never what it is. Cold gains 2–3× more than warm because cold is a branchy walk over tree-sitter's parse tree, while warm already runs in the cache-tuned CSR/SoA/B+tree structures G2 exists to produce. LTO is on by default — it costs link time and nothing else, and link time is not what this tool is optimized for. PGO needs a training run, so it stays a driven build (scripts/pgobuild.sh) rather than something a bare cmake --build does behind your back.通过交叉 A/B 测试(A,B,A,B,…,中位数和最小值,每个分支 9–31 次运行,重复)在本仓库和一个未出现在任何训练运行中的约 2000 个文件的 C++ 树上测量——留出的语料库显示出相同或更大的增益,这排除了在基准测试上进行训练的可能性。所有三个构建版本和两个语料库上的输出都是字节一致的,并且确定性门控在每棵树上都能通过;这些选项改变了获得结果的速度,而非结果本身。冷启动的增益比热启动高 2–3 倍,因为冷启动是对 tree-sitter 解析树的分支遍历,而热启动已经在 G2 旨在生成的缓存调优 CSR/SoA/B+tree 结构中运行。LTO 默认开启——它只消耗链接时间,而链接时间并不是该工具优化的重点。PGO 需要训练运行,因此它保持为驱动构建(scripts/pgobuild.sh),而不是 cmake --build 在后台自动执行的操作。

On a vPMU-less cloud VM the columns don't vanish — software counters, a G2 witness at zero page faults, and the 2.17 s subprocess they exposed在没有 vPMU 的云虚拟机上,列不会消失——软件计数器、零页面错误的 G2 见证,以及它们暴露出的 2.17 秒子进程

And on machines with no PMU at all — most cloud VMs and CI boxes — the counter columns no longer vanish. A kernel that refuses every hardware event (ENOENT; no vPMU is the common cloud case) still offers software counters, so the Linux backend's per-event graceful skip now extends to the group leader and falls through to two PERF_TYPE_SOFTWARE rows — task-clock (on-CPU ns) and page-faults — under their own column names, never as a stand-in for the hardware counts. Below, ripwire mapping its own tree, cold, on the 2-vCPU vPMU-less Intel Xeon VM this was validated live on:在完全没有 PMU 的机器上(大多数云虚拟机和 CI 盒子),计数器列不再消失。拒绝所有硬件事件的内核(ENOENT;云环境常见无 vPMU 情况)仍提供软件计数器,因此 Linux 后端的逐事件优雅跳过现在扩展到组领导者,并回落到两行 PERF_TYPE_SOFTWARE——task-clock(CPU 上纳秒数)和 page-faults——使用它们自己的列名,绝不作为硬件计数的替代品。下图所示,ripwire 在此验证过的 2-vCPU 无 vPMU Intel Xeon 虚拟机上,以冷启动方式映射其自身树:

scope calls wall task-clock (on-CPU) page-faults
tree-sitter parse 799 1,773 ms 1,134 ms 6.4 k
tags query exec + captures 799 1,084 ms 1,071 ms 6.7 k
doc post-pass (main-thread wait on the pool) 1 2,174 ms 0.50 ms 0
resolve refs + build CSR 1 12.32 ms 12.31 ms 7

Four things this buys that wall-clock alone cannot say. The wall−task-clock gap is off-CPU time: the parse phase's 36% gap is 2-vCPU oversubscription made visible (a pool parsing 799 files on two cores). The CSR row is a live cross-check: task-clock is the kernel's clock, the wall column is the profiler's own — two independent clocks agreeing to 0.05% on a single-threaded scope. (Short hot scopes diverge by the documented read-bracket overhead instead: the counter bracket encloses the tick bracket.) The page-faults column is a G2 witness: PageRank's power iteration retires with zero page faults and the CSR build with 7, against ~3,100 in the allocation-heavy model-build scopes — the no-allocation rule inside the ranked loop, watchable on a box with no PMU. And the doc post-pass row caught something real: 2.17 s of wall on 0.5 ms of CPU is work happening outside the process — with markitdown installed, the showcase PDF and PPTX are re-extracted by subprocess on every run, cache or no cache, which on this box is ~97% of a warm run's wall (2.05 s of 2.11 s); child CPU is invisible to every per-thread counter, and the wall-vs-task-clock gap is precisely the signature that flags it. (The extraction is already documented in-tree as a pure function of the file bytes — a cache candidate, now measured.) Only a kernel that offers nothing at all — perf_event_paranoid>=3, seccomp — still degrades to timing-only, and pmccheck's inactive arm now proves that was truly the case.这带来了四个仅靠挂钟时间无法说明的事实。挂钟时间与 task-clock 的差距是 CPU 外时间:解析阶段 36% 的差距是 2-vCPU 超额订阅的可视化(在一个池中在两个核心上解析 799 个文件)。CSR 行是一个实时交叉检查:task-clock 是内核时钟,挂钟列是分析器自己的——两个独立时钟在单线程作用域上达成 0.05% 的一致。(短热点作用域因记录的读取括号开销而产生偏差:计数器括号包围了滴答括号。)page-faults 列是 G2 的见证:PageRank 的幂迭代以零页面错误退休,CSR 构建为 7,而分配繁重的模型构建作用域约为 3,100——排名循环内的无分配规则,在没有 PMU 的盒子上可见。文档后处理行捕捉到了真实情况:0.5 毫秒 CPU 时间对应 2.17 秒挂钟时间,这是在进程外进行的工作——安装 markitdown 后,展示用的 PDF 和 PPTX 在每次运行时都会被子进程重新提取,无论是否有缓存,这在当前盒子上约占热启动挂钟时间的 97%(2.11 秒中的 2.05 秒);子进程 CPU 对每个线程的计数器都是不可见的,而挂钟时间与 task-clock 的差距正是其标志。(提取过程已在树内记录为文件字节的纯函数——一个缓存候选,现已测量。)只有什么都不提供的内核(perf_event_paranoid>=3,seccomp)才会降级为仅显示时间,而 pmccheck 的非活动分支现在证明了事实确实如此。

Standing on the whole field立足于整个领域

Almost none of the ideas here are new; the combination and the constraints are. Lessons folded from 36 repositories and 67 papers into one deterministic executable, alongside a labelled survey of 231 tools that folded nothing and are catalogued separately — the two sets are disjoint, so they add rather than nest. The row-by-row ledger, each with the lesson taken and where it lives, is docs/LINEAGE.md. Those three counts are derived from that document's own tables by test/readmedriftcheck.sh, which fails if this sentence and those tables disagree.这里的想法几乎都不是新的;组合和约束才是。从 36 个仓库和 67 篇论文中提炼出的经验汇总到一个确定性的可执行文件中,并附带一份包含 231 个未提炼任何内容且单独编目的工具的标记调查——这两组是不相交的,因此它们是相加而非嵌套的。逐行分类账,每一行都记录了吸取的经验及其位置,位于 docs/LINEAGE.md。那三个计数是由该文档自身的表格通过 test/readmedriftcheck.sh 导出的,如果本句与那些表格不一致,该测试将失败。

One of those papers measures the alternative architecture directly: an independent study found a planner that delegates exploration to a sub-agent in an isolated context window losing to search over a pre-built index — 65.2% vs 46.2% accuracy, at less than half the cost — with 41.8% of the delegated arm's failures happening silently at the planner→sub-agent hand-off (arXiv:2608.01507). A single process answering in one call has no hand-off to fail at.其中一篇论文直接测量了替代架构:一项独立研究发现,将探索委托给隔离上下文窗口中的子代理的规划器,在预构建索引上搜索时表现不佳——准确率分别为 65.2% 和 46.2%,成本不到一半——且委托分支中 41.8% 的失败发生在规划器到子代理的移交处(arXiv:2608.01507)。一个在一次调用中回答的单一进程没有移交失败的风险。


The honesty contract诚实契约

The differentiator is not a number, it is a discipline: a measurement you cannot check is a claim, and this tool ships the check.区别不在于数字,而在于准则:无法检查的测量只是主张,而该工具提供了检查。

What it misses, and what to run next它错过了什么,以及下一步该运行什么

A name-based call graph cannot see dynamic dispatch, a callback routed through a table, or a symbol that exists only after macro expansion. Every static tool has that horizon; the one that costs you a bug is the one that hides it. So the contract is not it sees everything — it is nothing it is unsure about reaches your agent unlabelled.基于名称的调用图无法看到动态分派、通过表路由的回调或仅在宏展开后才存在的符号。每个静态工具都有其视野局限;导致您出现 Bug 的那个工具就是隐藏它的那个。因此,契约不是它能看到一切——而是它不确定的内容绝不会未加标记地到达您的代理。

Measured against a compiler-grade oracle, its silent-miss count is zero. Of 68 answers scored against a scip-clang index, six were imperfect and four flagged themselves; the other two were right, and the oracle was the one that could not see the files. No imperfect answer arrived unmarked.与编译器级预言机相比,其静默缺失计数为零。在针对 scip-clang 索引评分的 68 个答案中,6 个不完美,4 个标记了自身;另外 2 个是正确的,而预言机无法看到这些文件。没有不完美的答案是未标记的。

When a mark says the cheap answer is not enough, escalate on purpose — never by guessing:当标记显示廉价答案不足以应付时,请有意升级——绝不要靠猜测:

  1. --expand=SYM — read the body it ranked, still a fraction of a whole-file read.--expand=SYM —— 读取它排名的主体,这仍然只是全文件读取的一小部分。
  2. --uses=SYM / --impact=SYM — every read, write and import site, and the transitive blast radius. --callers alone under-counts, and says so.--uses=SYM / --impact=SYM —— 每个读取、写入和导入站点,以及传递性的影响范围。仅 --callers 会低估计数,并会说明这一点。
  3. --scip=index.scip — hand it a compiler-grade index and precise edges replace the name-based guesses, tagged prov="scip". Missing or corrupt index degrades; it never fails.--scip=index.scip —— 提供编译器级索引,精确的边将取代基于名称的猜测,标记为 prov="scip"。缺失或损坏的索引会导致降级;它绝不会失败。
The six marks the output uses — amb=, ambiguous=, counts_floor=, unresolved=, external=, --skipped输出使用的六个标记——amb=, ambiguous=, counts_floor=, unresolved=, external=, --skipped

The map for this repository's own src/ grades itself in the header before a single answer (2026-08-10, at 4e245d7): files=109 symbols=3233 edges=10132 ambiguous=4768 unresolved=1097.本仓库自身 src/ 的映射在单个答案之前就在标题中进行了自我评分(2026-08-10,版本 4e245d7):files=109 symbols=3233 edges=10132 ambiguous=4768 unresolved=1097。

Read ambiguous= as a property of the indexed tree, not a score for the resolver. It counts call names that hit more than one definition, so it moves when the corpus gains same-named symbols — and it just did, visibly. On 2026-08-09 this number rose from 2991 to 4507. The cause was attributed by swapping one file back and re-measuring: src/infra/svector.h alone accounts for 4507 → 2741. The small-vector there grew a full container interface, so the tree now defines its own size, begin, end, push_back and data — the most-called names in any C++ corpus. Adding a container is a name collision by construction. Expect the number to climb again as that container replaces std::vector across the tree; a rise there means the map is disclosing more overloading, not resolving worse.将 ambiguous= 读取为索引树的属性,而非解析器的分数。它统计了命中多个定义的调用名称,因此当语料库增加同名符号时,它会变动——而刚才确实变动了。在 2026-08-09,该数字从 2991 上升至 4507。原因是通过换回一个文件并重新测量得出的:仅 src/infra/svector.h 就导致了 4507 → 2741 的变化。其中的小向量增加了一个完整的容器接口,因此树现在定义了自己的 size、begin、end、push_back 和 data——这是任何 C++ 语料库中调用最多的名称。添加容器在构建上就是名称冲突。预计随着该容器在整个树中替换 std::vector,这个数字会再次攀升;那里的上升意味着映射正在披露更多的重载,而不是解析得更差。

the output says read it as
amb="K" K of this symbol's calls hit an overloaded name — one target was chosen; read the source if which one matters
ambiguous=N the map's completeness gauge, one number, in the header
counts_floor="1" a floor, not a total — a zero means none found, never none exists
unresolved=N call sites recognized and deliberately not resolved — counted, never dropped in silence
external="1" no definition anywhere in the indexed tree — stdlib or third-party, not a miss
--skipped every file the index does not contain, itemized with its reason — oversize, excluded, unsupported-ext, a pruned vendor tree (pruned_dirs=, contents unknown, not zero) — plus the files it DOES contain but cannot vouch for: degraded-parse (tree-sitter error spans, with err_ratio=) and minified-suspect (ws_freq=)
How the zero was measured — the sweep, the two unflagged answers, and the 22.6% it over-hedges零是如何测量的——扫描、两个未标记的答案,以及它过度对冲的 22.6%

A 34-query sweep of this repository, 68 answers across --uses and --callers, scored against a scip-clang index (2026-08-09, the shipping binary). Six answers were imperfect; four carried a discriminating self-flag (amb=, defs>1, external="1"). The two unflagged were not misses: the oracle could not see those files — a Python file under bench/, an uncompiled file under test/ — and ripwire's answer was the correct one.对本仓库进行 34 次查询扫描,涵盖 --uses 和 --callers 的 68 个答案,针对 scip-clang 索引(2026-08-09,发布版本)进行评分。6 个答案不完美;4 个带有区分性的自我标记(amb=, defs>1, external="1")。那两个未标记的并非缺失:预言机无法看到这些文件——bench/ 下的一个 Python 文件,test/ 下的一个未编译文件——而 ripwire 的答案是正确的。

It errs the other way instead. 14 of 62 correct answers carried a caution flag they did not need — 22.6% over-hedging, up from 18.6% before this round's resolver fixes, because closing loss buckets added marks faster than it removed them. That bias is deliberate: a flag you did not need costs you one source read; a miss you were never told about costs you a bug.它反而犯了另一种错误。62 个正确答案中有 14 个带有它们不需要的警告标记——22.6% 的过度对冲,高于此轮解析器修复前的 18.6%,因为关闭损失桶添加标记的速度快于移除它们的速度。这种偏差是故意的:一个不需要的标记只会让您多读一次源码;而一个未被告知的缺失则会让您付出 Bug 的代价。

One corpus, 34 queries, and the oracle has blind spots of its own — the limits that travel with the number are listed with it. Receipt, per-query scores and reproduction: bench/headtohead/r9-2026-08-09/.一个语料库,34 次查询,预言机本身也有盲点——随数字而来的限制已与其一起列出。收据、按查询评分和复现:bench/headtohead/r9-2026-08-09/。

In the output在输出中

Three rules the output enforces on itself: a zero reads as none found, never none exists; every truncation says what it withheld and how to page it; and every count names its unit, because the units differ by verb.输出对自身强制执行三条规则:零读取为未找到,绝非不存在;每次截断都会说明它扣留了什么以及如何翻页;每个计数都命名了其单位,因为单位因动词而异。

The three rules in full — counts_floor="1", the shown_*/*_capped= paging vocabulary, and why two counts can disagree honestly三条规则详述——counts_floor="1",shown_*/*_capped= 翻页词汇表,以及为什么两个计数可以诚实地产生分歧
  • A zero is a measurement, not an absence. counts_floor="1" marks every count that name-based resolution cannot prove is a total. Read a zero as none found, never none exists.零是一种测量,而非缺失。counts_floor="1" 标记了每个基于名称的解析无法证明是总数的计数。将零读取为未找到,绝非不存在。
  • Truncation is disclosed where it happens. shown_*, *_capped= and the paging attributes say what was withheld and how to page it; the legend comment that leads each document defines the vocabulary in full, so the output explains itself without this README.截断在发生的地方被披露。shown_*, *_capped= 和翻页属性说明了扣留了什么以及如何翻页;引导每个文档的图例注释完整定义了词汇表,因此输出无需本 README 即可自解释。
  • Units are named, because they differ by verb. The callers count is distinct symbols, the impact count is a reach set, the uses count is call sites. The legend says which, so two numbers that look contradictory can be read as the different questions they answer.单位已命名,因为它们因动词而异。调用者(callers)计数是不同的符号,影响(impact)计数是到达集,使用(uses)计数是调用站点。图例说明了是哪一个,因此两个看起来矛盾的数字可以被解读为它们所回答的不同问题。

In the numbers在数字中

The evaluation labels were authored by reading the source and deciding which symbol is the on-task answer — never by transcribing the ranker's own output — so the eval is allowed to say the ranker is wrong, and it has. These are the results that say so, all in-tree, all published on purpose:评估标签是通过阅读源码并决定哪个符号是任务内答案而编写的——绝非转录排名器自身的输出——因此评估被允许指出排名器是错误的,而且它确实做到了。这些是说明这一点的结果,全部在树内,全部是有意发布的:

  • --grep costs more tokens than it saves, and --pack-signatures can make output bigger — both quantified next to the savings they qualify, because saying so is cheaper than being caught.--grep 消耗的 Token 比它节省的多,而 --pack-signatures 可能使输出变大——两者都在它们限定的节省量旁边进行了量化,因为说明这一点比被抓住要便宜。
  • The public C++ number is materially lower than the retired private one was. SFML: strict file@10 28.7%, any@10 41.7%, first-hit MRR 0.21 — measured at commit d411f3de4 (bench/cppbench/results/sfml_scoreboard.md). Until 2026-08-07 this bullet compared against a roughly-89%-any@10 private corpus that is no longer reproducible from this tree; that comparison is retired. The public number is the baseline going forward.公共 C++ 数字在实质上低于已退休的私有数字。SFML:严格 file@10 28.7%,any@10 41.7%,首次命中 MRR 0.21——在提交 d411f3de4 处测量(bench/cppbench/results/sfml_scoreboard.md)。在 2026-08-07 之前,此要点与一个约 89%-any@10 的私有语料库进行比较,该语料库已无法从本树复现;该比较已退休。公共数字是未来的基准。
  • PageRank is a bad co-change ranker — 3.8% recall@5 against 40.3% for plain lexical, and fusing the two made it worse. Relatedness is lexical; importance is structural; the tool uses different machinery for each because the measurement said so.PageRank 是一个糟糕的共同变更排名器——recall@5 为 3.8%,而纯词法为 40.3%,且融合两者使其变得更糟。相关性是词法的;重要性是结构的;该工具对两者使用不同的机制,因为测量结果就是这样。
  • Strict multi-file localization is hard and stays hard. Held-out LocBench: single-file gold 73.4%, multi-file 18.2%. Every corpus shows the same cliff.严格的多文件定位很难,而且一直很难。留出的 LocBench:单文件黄金标准 73.4%,多文件 18.2%。每个语料库都显示出同样的悬崖。

In the tests在测试中

test/regression.sh names 542 gate scripts and is the authoritative list; python3 test/pargates.py . ./build/ripwire -j 6 runs the same set in parallel. On top of them sit the contracts that do not fit a unit test: two runs byte-identical, warm output identical to cold, output that pipes clean through xmllint --noout, a sanitizer build with -fno-sanitize-recover=all, and a differential argv harness that runs a reference binary and the candidate over every argument vector and requires stdout, stderr and exit code to match on each.test/regression.sh 命名了 542 个门控脚本,是权威列表;python3 test/pargates.py . ./build/ripwire -j 6 并行运行同一集合。在它们之上是那些不适合单元测试的契约:两次运行字节一致,热启动输出与冷启动相同,输出可以通过 xmllint --noout 干净地管道传输,带有 -fno-sanitize-recover=all 的消毒剂构建,以及一个差分 argv 工具,它在每个参数向量上运行参考二进制文件和候选二进制文件,并要求 stdout、stderr 和退出代码在每次匹配。

The house rule behind all of it: write the gate before the code it measures. A ranking, a token estimate and a call graph all look plausible whether or not they are correct.这一切背后的家规:在编写它测量的代码之前先编写门控。排名、Token 估计和调用图无论是否正确,看起来都似是而非。


Set it up in your coding agent在您的编码代理中设置它

If your agent can run shell commands, it is already set up. The CLI is the primary interface: ripwire on PATH costs the agent nothing until the moment it runs a command — no server to register, no tool schemas riding in every request's context. The one step that matters is installing the skills (step 2 below), which teach the agent when to reach for which verb.如果您的代理可以运行 shell 命令,它就已经设置好了。CLI 是主要接口:PATH 上的 ripwire 在它运行命令的那一刻之前不会消耗代理任何资源——无需注册服务器,无需在每个请求的上下文中携带工具模式。重要的一步是安装技能(下文第 2 步),它教导代理何时使用哪个动词。

The MCP server is the optional second interface, for what a shell pipe can't give you: clients without shell access, lazy body handles (fetch a symbol's source only when actually needed), and the same span-addressed edit operations against an already-warm index. The CLI exposes those edits too, with the same staleness/ambiguity refusal and atomic-write contract:MCP 服务器是可选的第二个接口,用于 shell 管道无法提供的内容:没有 shell 访问权限的客户端、懒加载主体句柄(仅在真正需要时获取符号的源码),以及针对已热启动索引的相同跨度寻址编辑操作。CLI 也暴露了这些编辑,具有相同的陈旧/歧义拒绝和原子写入契约:

ripwire . --replace-symbol-body=SYM --edit-payload=definition.txt
printf '%s' "$BLOCK" | ripwire . --insert-before-symbol=SYM --edit-payload=-

That MCP convenience has a cost the CLI doesn't carry — the verb schemas sit in the agent's context every session — so register it when you want those verbs, not as a default.这种 MCP 便利性有一个 CLI 不具备的成本——动词模式在每次会话中都存在于代理的上下文中——因此在您想要这些动词时注册它,而不是作为默认设置。

1. (Optional) Register the MCP server1. (可选)注册 MCP 服务器

ripwire wrap <agent> prints the recipe for the agent you name. It prints; it never edits your config — you read the line, then run it.ripwire wrap <agent> 为您命名的代理打印配方。它只打印;它绝不会编辑您的配置——您阅读该行,然后运行它。

ripwire wrap claude      # MCP:      claude mcp add ripwire -- ripwire --mcp
ripwire wrap cursor      # MCP:      the mcpServers stanza for .cursor/mcp.json (or ~/.cursor/mcp.json)
ripwire wrap codex       # CLI-first: optional MCP restricted to audit/health verbs in Codex TOML
ripwire wrap windsurf    # MCP:      that client's stanza
ripwire wrap gemini      # MCP:      that client's stanza
ripwire wrap opencode    # CLI-1st:  the AGENTS.md wiring; its "mcp" stanza offered as the alternative
ripwire wrap aider       # no MCP:   a ranked map file, and the aider invocation that reads it
ripwire wrap --all       # detect every installed agent and emit each one's config

One stdio server, 30 verbs — 15 read, 12 flagship-reflex, 3 span-addressed edit — and a client that isn't one of the six above can be pointed at the same process by hand.一个 stdio 服务器,30 个动词——15 个读取,12 个旗舰反射,3 个跨度寻址编辑——并且不是上述六个之一的客户端可以通过手动指向同一进程。

What the 30 verbs are — lazy body handles, the edit verbs' safety contract, the pre-print skill scan, and the hand-written stanza for any other MCP client30 个动词是什么——懒加载主体句柄、编辑动词的安全契约、预打印技能扫描,以及任何其他 MCP 客户端的手写节

That registers one stdio server — ripwire --mcp — exposing 30 verbs: 15 read verbs, 12 flagship-reflex verbs, and 3 span-addressed edit verbs. Read verbs mirror the CLI (analyze, for, grep, cochange, fetch_body, lego, mentions, owners, memory_recall, situational_awareness, batch, …); find_symbol and find_referencing_symbols attach a stable handle instead of a body, so the agent fetches source only when it actually needs it. The edit verbs mirror the CLI flags and enforce the shared safety contract — staleness refusal, ambiguity refusal, mode preservation and atomic writes. Full reference: skills/ripwire-mcp/.这注册了一个 stdio 服务器——ripwire --mcp——暴露 30 个动词:15 个读取动词,12 个旗舰反射动词,和 3 个跨度寻址编辑动词。读取动词镜像 CLI(analyze, for, grep, cochange, fetch_body, lego, mentions, owners, memory_recall, situational_awareness, batch, …);find_symbol 和 find_referencing_symbols 附加一个稳定的句柄而不是主体,因此代理仅在真正需要时获取源码。编辑动词镜像 CLI 标志并强制执行共享的安全契约——陈旧拒绝、歧义拒绝、模式保留和原子写入。完整参考:skills/ripwire-mcp/。

Before printing, wrap security-scans ./skills and .agents/skills with the same engine as --scan-skills: a CRITICAL finding blocks the recipe, warnings print and continue.打印前,使用与 --scan-skills 相同的引擎对 ./skills 和 .agents/skills 进行安全扫描:CRITICAL 发现会阻止配方,警告会打印并继续。

If your client is not one of the six, the server is a plain stdio MCP process and every client that speaks MCP can be pointed at it by hand. The whole configuration is:如果您的客户端不是这六个之一,服务器是一个普通的 stdio MCP 进程,任何讲 MCP 的客户端都可以手动指向它。整个配置是:

{
  "mcpServers": {
    "ripwire": { "command": "ripwire", "args": ["--mcp"] }
  }
}

Use an absolute path in command if ripwire is not on the agent's PATH. For a client that wants a socket instead of stdio, ripwire --listen=HOST:PORT serves the same verbs.如果 ripwire 不在代理的 PATH 上,请在命令中使用绝对路径。对于想要套接字而不是 stdio 的客户端,ripwire --listen=HOST:PORT 提供相同的动词。

2. Install the skills2. 安装技能

skills/ ships eighteen task-shaped skills that tell an agent which verb answers the moment it is in — orienting cold, tracing a call, sizing a refactor, checking a diff, hunting a bug, writing tests, reviewing security. Without them an agent has 30 verbs and no map of when each applies; the skills name the moment each verb is for. Install as symlinks back into this repo, so edits here take effect immediately:skills/ 附带了 18 个任务形状的技能,告诉代理哪个动词在当前时刻回答——定向冷启动、追踪调用、调整重构大小、检查差异、狩猎 Bug、编写测试、审查安全性。没有它们,代理有 30 个动词,但没有每个动词何时适用的地图;技能命名了每个动词的适用时刻。安装为指向本仓库的符号链接,因此这里的编辑会立即生效:

skills/install.sh                 # → ~/.claude/skills
skills/install.sh --codex         # → ${AGENTS_HOME:-~/.agents}/skills (canonical Codex/agent path)
skills/install.sh --codex --hook  # → also install Codex's task router, CLI nudge + session primer
skills/install.sh --codex-legacy  # → ${CODEX_HOME:-~/.codex}/skills (older Codex installs)
skills/install.sh /some/path      # → an explicit destination
ripwire --scan-skills=skills      # read the security scanner's verdict first, if you would rather

The script's own header documents its other modes, including the opt-in advisory PreToolUse hook. wrap also prints a pasteable use-when blurb for your client's rules file (CLAUDE.md, AGENTS.md, .cursor/rules, …) and works from a prebuilt install with no checkout — from v0.2.2 it points at the installer's staged copy of the skills when the cwd is not a checkout.脚本自身的标题记录了其其他模式,包括可选的建议性 PreToolUse 钩子。wrap 还为您的客户端规则文件(CLAUDE.md, AGENTS.md, .cursor/rules, …)打印了一个可粘贴的使用时说明,并且可以在没有检出的预构建安装下工作——从 v0.2.2 开始,当 cwd 不是检出时,它指向安装程序的技能暂存副本。


Improve it with your agent用您的代理改进它

prompts/ holds eleven self-contained orchestrator prompts: the loops this project is built with, written so a coding agent can run them. They encode the workflow rather than describing it.prompts/ 包含 11 个独立的编排器提示:构建此项目的循环,编写方式使得编码代理可以运行它们。它们编码了工作流而不是描述它。

How to run one — build first, paste the file, and it writes a plan and stops for your go-ahead before anything runs如何运行一个——先构建,粘贴文件,它会编写一个计划并停止以等待您的批准,然后再运行任何内容

How to run one:如何运行一个:

  1. Build the tool first — most loops need a binary to measure against: cmake -S . -B build && cmake --build build -j先构建工具——大多数循环需要一个二进制文件来测量:cmake -S . -B build && cmake --build build -j
  2. Open your coding agent at the root of a ripwire checkout.在 ripwire 检出的根目录下打开您的编码代理。
  3. Paste the contents of one prompt file. It needs nothing else from that directory.粘贴一个提示文件的内容。它不需要该目录下的任何其他内容。
  4. It writes a plan and stops for your go-ahead. Nothing runs before you approve it — read the plan, cut what you disagree with, then say go.它会编写一个计划并停止以等待您的批准。在您批准之前,什么都不会运行——阅读计划,删掉您不同意的部分,然后说 go。
  5. The loop runs its own gates in the foreground and reports what it left green.循环在前台运行其自己的门控,并报告它留下了哪些绿色。

Three worth starting with:三个值得开始的:

Prompt What it produces
full-audit.md A severity-ranked audit across bugs, measured performance, verb-to-moment matching, token efficiency, and an ecosystem scan of papers and repos with real momentum.
dogfood-gaps.md A real task done using only ripwire for navigation, with every fallback to grep or a whole-file read logged as a product gap at the moment it happened.
capture-audit.md A fresh showcase capture read by parallel adversarial lenses, and the findings turned into family-wide gates.
The other seven — head-to-head, ranking-eval from your own sessions, per-language, onboarding, sibling sweep, command tour, showcase build其他七个——头对头、来自您自己会话的排名评估、按语言、入职、兄弟扫描、命令之旅、展示构建

The other seven — a paired head-to-head against a competitor, a ranking-eval loop that mines real retrieval misses from your own sessions, a per-language improvement pass, a zero-context onboarding study, a sibling sweep, a live command tour, a showcase build — are listed with their audiences in prompts/README.md. Each states its own scope and its honesty rules, and most name the gates they must leave green.其他七个——针对竞争对手的配对头对头、挖掘您自己会话中真实检索缺失的排名评估循环、按语言改进传递、零上下文入职研究、兄弟扫描、实时命令之旅、展示构建——已与其受众一起列在 prompts/README.md 中。每一个都声明了自己的作用域和诚实规则,大多数都命名了它们必须保持绿色的门控。


Languages语言

C, C++, Objective-C / Objective-C++, Metal (Metal Shading Language, .metal — indexed with the C++ grammar, since MSL is a C++14 dialect, so a dual-compile header's symbols resolve from both the GPU and CPU halves), CUDA (.cu/.cuh — indexed with the vendored tree-sitter-cuda grammar, so kernel<<<grid, block>>>( … ) launch sites are real call edges and --callers of a kernel names its host-side launchers; __constant__ module tables index as symbols even uninitialized — the cudaMemcpyToSymbol idiom — and SCREAMING_SNAKE __device__/__managed__ globals join them; dual-compile .cuh headers resolve from both halves), Python, TypeScript, JavaScript, Java, Ruby, PHP (.php/.phtml — classes, interfaces, traits, enums, functions, methods and constants; $o?->m() null-safe and A::m() static calls are edges; use directives are imports. Dynamic dispatch — $fn(), call_user_func, __call — names its callee at run time and is a stated floor, not a silence), Lua (all five spellings that define a function, including the M.f = function and table-constructor forms; function M:f() is a method. Metatable inheritance is a runtime call with no syntax to read, so a Lua corpus reports no inheritance edges — stated, not implied), Bash, Go, Rust, Swift, C#, JSON + TOML + YAML (config keys — a [tool.ruff.lint] table is one symbol under its full dotted name, and pyproject.toml/Cargo.toml/CI workflows become greppable), and Markdown (.md/.markdown — the DOC tier: every heading, ATX or setext, is a section symbol whose span runs to the next same-or-higher heading, so --for ranks the section, --expand serves the section body, --recall answers section-granular, and links/backtick mentions are doc→doc and doc→code edges). Twenty-one tree-sitter grammars, all vendored.C, C++, Objective-C / Objective-C++, Metal (Metal Shading Language, .metal —— 使用 C++ 语法索引,因为 MSL 是 C++14 方言,所以双编译头文件的符号从 GPU 和 CPU 两部分解析),CUDA (.cu/.cuh —— 使用供应商提供的 tree-sitter-cuda 语法索引,所以 kernel<<<grid, block>>>( … ) 启动站点是真实的调用边,内核的 --callers 命名其主机端启动器;__constant__ 模块表即使未初始化也索引为符号——cudaMemcpyToSymbol 惯用法——且 SCREAMING_SNAKE __device__/__managed__ 全局变量加入它们;双编译 .cuh 头文件从两部分解析),Python, TypeScript, JavaScript, Java, Ruby, PHP (.php/.phtml —— 类、接口、特征、枚举、函数、方法和常量;$o?->m() 空安全和 A::m() 静态调用是边;use 指令是导入。动态分派——$fn(), call_user_func, __call —— 在运行时命名其被调用者,是一个声明的底线,而不是静默),Lua(定义函数的所有五种拼写,包括 M.f = function 和表构造函数形式;function M:f() 是方法。元表继承是一个没有语法可读的运行时调用,因此 Lua 语料库不报告继承边——声明的,而非暗示的),Bash, Go, Rust, Swift, C#, JSON + TOML + YAML (配置键——[tool.ruff.lint] 表在其完整点分名称下是一个符号,且 pyproject.toml/Cargo.toml/CI 工作流变得可 grep),以及 Markdown (.md/.markdown —— DOC 层:每个标题,ATX 或 setext,都是一个节符号,其跨度运行到下一个相同或更高的标题,所以 --for 排名该节,--expand 服务于节主体,--recall 回答节粒度,链接/反引号提及是 doc→doc 和 doc→code 边)。21 个 tree-sitter 语法,全部由供应商提供。

Want another language? The pipeline is language-agnostic past the parse: a new language is a vendored tree-sitter grammar, its query file, and one row in the declarative extension → { grammar, queries } table (the "declarative constexpr tables" rule in CONTRIBUTING.md) — open an issue naming the grammar and the repo you'd run it on.想要另一种语言?流水线在解析之后是语言无关的:一种新语言是一个供应商提供的 tree-sitter 语法、其查询文件,以及声明式 extension → { grammar, queries } 表中的一行(CONTRIBUTING.md 中的“声明式 constexpr 表”规则)——打开一个 issue 命名语法和您将运行它的仓库。

Notebooks, HTML and CSV are indexed as documents for --recall and the doc↔code edges behind --mentions; Office and PDF join them through an optional bridge. Markdown graduated from that tier: it parses with its own vendored grammar, so its headings are symbols, not just document text.Notebooks, HTML 和 CSV 被索引为 --recall 和 --mentions 背后 doc↔code 边的文档;Office 和 PDF 通过可选桥接加入它们。Markdown 从该层毕业:它使用自己的供应商语法解析,所以其标题是符号,而不仅仅是文档文本。


Documentation文档

Need File
Every flag, with a real invocation and its recorded output docs/COMMANDS.md
The authoritative flag list, always current ./build/ripwire --help
Pipeline, data model, determinism contract, output-honesty contract docs/ARCHITECTURE.md
Every published number, its instrument, and what is not published docs/EVALS.md
Compiler optimization remarks: the triage, and the two opt-in faster builds docs/OPTREMARKS.md
The method, as something transferable docs/METHODOLOGY.md
Where every idea came from, and where each one lives in the code docs/LINEAGE.md
C++ house style, the G1–G5 guardrails, gate discipline, the submission checklist CONTRIBUTING.md
Orientation for a coding agent working on this repository CLAUDE.md / AGENTS.md
User-visible capabilities, behaviour changes, known limits CHANGELOG.md
Vendored dependencies and their licences THIRD_PARTY.md
The whole tool in 27 slides — the showcase deck present/ripwire-showcase.pdf (pptx, rebuilt by present/deck5_ripwire_build.js)

If a document disagrees with --help, the document is the bug.如果文档与 --help 不一致,文档就是 Bug。

Contributions are welcome — read CONTRIBUTING.md first, and CODE_OF_CONDUCT.md. Security reports: SECURITY.md.欢迎贡献——请先阅读 CONTRIBUTING.md 和 CODE_OF_CONDUCT.md。安全报告:SECURITY.md。


Licence许可证

Apache License 2.0 — see LICENSE for the full text.Apache License 2.0 —— 完整文本见 LICENSE。

Copyright 2026 David Brewster版权所有 2026 David Brewster

Vendored third-party code keeps its own licence; every dependency is enumerated with its terms in THIRD_PARTY.md.供应商提供的第三方代码保留其自己的许可证;每个依赖项及其条款都在 THIRD_PARTY.md 中列出。

About

The ripgrep of AI context: a zero-dependency C++23 CLI + MCP server giving coding agents a ranked, deterministic map of any repo, blast radius, tests-to-run and quality deltas. Signatures at 80% fewer bytes than bodies; ~5% of a grep-and-read pass's tokens.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

401 stars

Watchers

2 watching

Forks

Packages

No packages published