diff --git a/.ripwire_quality_acks b/.ripwire_quality_acks
index 3ba12823b..2b4856f35 100644
--- a/.ripwire_quality_acks
+++ b/.ripwire_quality_acks
@@ -627,6 +627,7 @@ ack duplication 5a94cb2859bf1601 71 now=71 was=0 prov=recon a probe TU deliberat
ack duplication 5ae632d0ded8f363 58 now=58 was=0 prov=recon facet=switch-name-table per-enumerator switches name every enumerator and carry no default: on purpose — that is what makes -Werror=switch a compile error at each one when an enumerator is appended; two such switches over one enum share the enumerator spelling by construction
ack duplication 5bfc60bf2eec4379 58 now=58 was=0 prov=recon readability-wave1 (clones.h scanCodeTokens extraction): normalizeTokens and objectKeys are both 'call a scanner, emplace_back each visit into a vector, return it' — the same 58-token visitor-to-vector adapter over two unrelated scanners in two different layers (the clone tokenizer in core vs the JSON top-level-key walker in the MCP layer). Neither can call the other; a shared generic adapter would be a cross-layer template earning six lines. Kept as written.
ack duplication 5c9174022e5a0734 44 DISCLOSE sinks: a reason-to-field switch is the shape every multi-reason sink shares; -Wswitch exhaustiveness over DisclosureWhy is the point (Diagnostics.h 4b)
+ack duplication 5c98961b8ec17a64 35 now=35 was=0 p=src/docparse.h:160 #155 (pr438 B2): inSortedTable is the span form of the table lookup isStrictlySortedTable's tables share; isMarkdownGrammarExtension is the same one-line binary_search over a different table, and merging them would need docparse.h to include externalnames.h for no gain
ack duplication 5e4956ffb34ce360 36 now=36 was=0 prov=recon M1: a 36-token shape coincidence, not duplication. isMcpProtocolVersionSupported walks a version list and mcpVerbDeclaresLegend walks a field list; both are the C++ spelling of 'is X in this list', over different tables, different types and different call sites. Folding them into one generic helper would couple the protocol handshake to the legend family for no shared meaning.
ack duplication 5f01b66132b916bd 44 DISCLOSE sinks: a reason-to-field switch is the shape every multi-reason sink shares; -Wswitch exhaustiveness over DisclosureWhy is the point (Diagnostics.h 4b)
ack duplication 5fad9d85c2552890 32 now=32 was=0 p=src/receiverevidence.h:142 lane FE-B (receiver evidence): lexical clone pairs, not shared logic — the per-language predicates (implicitReceiverLang, classNameReceiverLang, memberNeverReachesFreeFunction, isReceiverEvidenceKind, callableKind, classLike, isThisRoot) are one-line OR-lists over different enum sets that share only the shape with quality.h/model.h/slice.h predicates asking other questions; keyOf/typeKey build different keys into a reused buffer; classAt (innermost class span by byte) vs flipimpact innermostAtLine (by line, other table); impactViaColumn vs lintrules dependencyCapableMask share a bitmask idiom; the JS fixture encode|stringify is a deliberate twin (test/receiverevidencefix: same-named near misses); pargates.py is unchanged since cd87e30e (a regrouped pre-existing pair). The one real clone, the enclosing-function walk, was merged into innermostEnclosingFn instead of acked
diff --git a/changelog.d/155-kotlin-scope-functions.md b/changelog.d/155-kotlin-scope-functions.md
new file mode 100644
index 000000000..f6f2c2003
--- /dev/null
+++ b/changelog.d/155-kotlin-scope-functions.md
@@ -0,0 +1,18 @@
+### Fixed — Kotlin scope functions no longer bind Java methods (#438, thanks @llvm-x86)
+
+A Kotlin call with a trailing lambda to `let`, `run`, `with`, `apply` or `also` now stays off the Java
+method of the same name. Before this change, `s.run { }` bound `Job.run`, and `with( sb ) { }` bound
+`Builder.with`. Ripwire now reads the call as the stdlib scope function. It drops the Java candidates and
+keeps the Kotlin ones. A call with no Kotlin target reports `external=` with that proof.
+
+Calls without a trailing lambda keep their edges. `j.run()` still binds `Job.run`, and `b.with( "x" )` still
+binds `Builder.with`.
+
+Known floors:
+
+- A parenthesised lambda, such as `s.let( { } )`, is not a trailing lambda. Its edge is unchanged.
+- A Java method called from Kotlin with a trailing lambda is dropped when its name is a scope-function name.
+ The spelling alone does not tell the two apart.
+- A receiver of a Java type is not checked. A receiver whose type is an in-tree Kotlin class that defines the method
+ keeps its own binding (`t.run { }` on a `t: Task` binds `Task.run`).
+- A qualified `kotlin.run { }` can still bind an in-tree Kotlin `run`, hedged.
diff --git a/changelog.d/228-django-unittest-hooks.md b/changelog.d/228-django-unittest-hooks.md
new file mode 100644
index 000000000..0725d5011
--- /dev/null
+++ b/changelog.d/228-django-unittest-hooks.md
@@ -0,0 +1,21 @@
+### Fixed — Django and unittest hooks no longer read as dead code (#437, thanks @llvm-x86)
+
+Before: `--quality-delta` reported a Python hook as dead when no call in the tree named it. unittest and Django call
+`setUp`, `tearDown`, `setUpClass` and `setUpTestData` themselves. The runner calls each `test*` method. A closure inside a
+method that called `self.hook()` also lost the call. Each such method appeared as dead code.
+
+Now: the tool treats these names as called. It covers `setUpModule`, `tearDownModule`, `load_tests`, `runTest`, `asyncSetUp` and `asyncTearDown` too. The pytest xunit hooks `setup_module`, `teardown_module`,
+`setup_function`, `teardown_function`, `setup_class`, `teardown_class`, `setup_method` and `teardown_method` count as called too. A `test*`
+method (any name that starts with `test`) and an xunit hook count as called only in a test module: a path `isTestPath` accepts, or a Django `tests.py`. A closure
+that calls `self.` or `cls.` keeps the overrides of the method it calls live. A closure that binds `self` or `cls` as its own
+parameter does not.
+
+The HEAD snapshot scheme moves from 22 to 24. Old cached snapshots are not used.
+
+Not covered, still reported: pytest's conftest hooks such as `pytest_configure`. (`@pytest.fixture` functions are not reported as dead code here.)
+
+The hook names live in one table per framework (`kUnittestHooks`, `kXunitHooks`, `kUnittestModuleHooks` in `quality.h`), shared with `--dead-code` and `--safe-delete`, which now also skip `setUpTestData` and `runTest` in a TestCase subclass.
+
+Limit: the name check ignores types and scope. A method named `setUp`, `tearDown` or `load_tests` in application code is also treated as called. In a test module, any def named `test*` counts as called, nested defs and helper functions included. The tool errs toward live here.
+
+A closure that binds `self` or `cls` as its own parameter does not count, even for `def cb(self=self)`.
diff --git a/changelog.d/versions.md b/changelog.d/versions.md
index ed622a47e..254e403e1 100644
--- a/changelog.d/versions.md
+++ b/changelog.d/versions.md
@@ -1,10 +1,12 @@
### Changed — the versions this change moves, stated once
-`kParserVer` 206 → 226 (file tag 227): the Rust written-type receivers carried 202 (203) on their branch and the struct-field
+`kParserVer` 206 → 231 (file tag 232): the Rust written-type receivers carried 202 (203) on their branch and the struct-field
slot join 204 (205), and its fix rounds changed what 204 extracts, so a cache from that branch would replay the older slot
rows; the interface-dispatch records carried 210 and 212 on theirs; the JS/TS written-binding records carried 218 and the
-Python rebind-withholding records a 224 placeholder on theirs; 226 sits above every live branch and pull-request number
-(212 to 225). A cache written by 0.6.8 is re-parsed once. `kCacheVersion` 36 → 40: a Rust binding typed only through a trait
+Python rebind-withholding records a 224 placeholder on theirs; train 34 took 226; the Kotlin trailing-lambda capture (#155)
+carried a 228 placeholder and another branch holds 229, so 231 sits above every live branch and pull-request number. A cache
+written by 0.6.8 is re-parsed once. `kCacheVersion` 36 → 43: a Rust binding typed only through a trait
(`&dyn T`, `impl T`, a bound), a Rust `impl T for X` block and a JS/TS binding written after its declaration are new binding
-records, so a cache written before them is rejected and rebuilt (the branches that added them used 37, 38 and 39). The
-quality-snapshot scheme stays 22. The session legend dictionary is `dictv=8c941c6c17d27549 entries=932`.
+records, and a Kotlin call's trailing-lambda byte (#155) widens the reference record, so a cache written before them is
+rejected and rebuilt (the branches that added them used 37, 38, 39 and 41). The quality-snapshot scheme moves 22 → 24 (#228: Django and
+unittest hooks and closure self-dispatch change the dead set; old snapshots are not used; the branch used 23). The session legend dictionary is `dictv=8c941c6c17d27549 entries=932`.
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 582dd93c6..63995a1e4 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -258,6 +258,18 @@ triple-quoted string that ends in an escaped `$`). `test/kotlincheck.sh`
covers extraction, both bridge directions in flat and split layouts, the Java-edge invariant, the
bodyless-type collapse, hostile nesting, metrics and determinism.
+**Kotlin scope functions (#155).** A call with a trailing lambda to `let`, `run`, `with`, `apply` or `also`
+(`s.run { }`, `with( sb ) { }`, `xs.also { }`) is the stdlib inline function, so FE-A (`FalseEdgeRules`, `graph.h`)
+drops every Java candidate of that name and keeps the Kotlin ones; an emptied set is `external=` with that proof.
+The fact is `Reference::trailingLambda`, set by `kotlinTrailingLambda` (`ingest_metrics.h`); the names are
+`kKotlinScopeFunctionNames` (`externalnames.h`, regenerated by one `javap` command recorded there). A receiver rule
+that already picked a Kotlin member (`t.run { }` on a `t: Task` whose class defines `run`) keeps its proof; a pick
+holding a Java method is undone, so `s.run { }` is decided here. Stated floors: no receiver typing beyond that (a
+receiver of a Java type is not checked); a qualified `kotlin.run { }` can still bind an in-tree Kotlin `run` (hedged); no SAM conversion; a parenthesised lambda (`s.let( { } )`) is not trailing and
+keeps the ladder; and a Java method of one of these names called from Kotlin with a trailing lambda is dropped,
+because the spelling alone cannot tell the two apart. `test/kotlincheck.sh` §15 and `test/falseedgecheck.sh` arm J
+pin it.
+
**Clojure extraction.** The vendored Yogthos parser is a fork of Sogaiu's grammar. The grammar
rules match at the pinned revisions, while Yogthos' generated ABI-15 parser completed 4,930 of 4,933
diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md
index 376f62eb9..ee1492b30 100644
--- a/docs/COMMANDS.md
+++ b/docs/COMMANDS.md
@@ -9,7 +9,7 @@ python3 docs/docs_commands_build.py --bin build/ripwire
The flag surface below is read from `ripwire --help`, so it cannot disagree with the shipped
binary. `test/docscommandscheck.sh` fails if it ever does — in either direction.
-Sample output is lifted from a real recorded run (`docs/captures/COMMANDS_showcase_2026-10-25.md`), trimmed to the first few lines and
+Sample output is lifted from a real recorded run (`docs/captures/COMMANDS_showcase_2026-10-26.md`), trimmed to the first few lines and
scrubbed of local paths. It is illustrative, not a golden: run the command yourself for the
current shape.
@@ -70,7 +70,7 @@ _Same map, capped to the 5 highest-ranked symbols._
$ ./build/ripwire . --top-k=5
-
+
@@ -106,7 +106,7 @@ _The same capped map without its inventory tier: --top-k=5 leaves files out, so
$ ./build/ripwire . --top-k=5 --no-inventory
-
+
@@ -140,7 +140,7 @@ _SHAPE the map to fit ~1500 tokens (binary-search top-K)._
$ ./build/ripwire . --max-tokens=1500
-
+
@@ -215,13 +215,13 @@ _Name-shaped query: the router picks name-exact BM25 (header says which/why)._
```
$ ./build/ripwire . --for="rankGraphTeleport"
-
+
-
+
PageRank with an explicit teleport / personalization vector p (Σp = 1). The prior is name-quality-biased through biasPrior() so all rank modes share one weighting seam; the transition matrix (edgesinline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>&am … [line truncated: 31 more bytes on this line]
-#### The convergence disclosure contract
+#### The convergence disclosure contract
### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e`
@@ -252,14 +252,14 @@ _Restore the / sections the --for bundle collapses to a counted s
```
$ ./build/ripwire . --for="tree-sitter parse of a source file" --sections=lego,compose
-
+
inline bool topLevelEvidence( std::string_view source, const TSLanguage* language, const Predicate& predicate )
The crawl's per-file byte ceiling. A text file larger than this is skipped: at this size it is o…constexpr std::size_t kDefaultMaxFileBytes = 4u * 1024u * 1024u
-TSTree* parseTree( TSParser* parser, std::string_view src )
+TSTree* parseTree( TSParser* parser, std::string_view src )
Exercise every registered grammar and its embedded query, reporting loaded and expected totalsinline DoctorGrammarProbe doctorProbeGrammars()
... [21 more line(s); run it to see the whole thing]
@@ -279,13 +279,13 @@ _T3 opt-out: the signatures-only lens (no auto bodies, no bundle="auto" attribut
```
$ ./build/ripwire . --for="rankGraphTeleport" --signatures-only
-
+
-
+
PageRank with an explicit teleport / personalization vector p (Σp = 1). The prior is name-quality-biased through biasPrior() so all rank modes share one weighting seam; the transition matrix (edgesinline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>&am … [line truncated: 31 more bytes on this line]
-#### The convergence disclosure contract
+#### The convergence disclosure contract
### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e`
@@ -314,14 +314,14 @@ _Opt OUT of compact conceptual serving: restore the rank-first auto wal
```
$ ./build/ripwire . --for="tree-sitter parse of a source file" --auto-bodies
-
+
inline bool topLevelEvidence( std::string_view source, const TSLanguage* language, const Predicate& predicate )
The crawl's per-file byte ceiling. A text file larger than this is skipped: at this size it is o…constexpr std::size_t kDefaultMaxFileBytes = 4u * 1024u * 1024u
-TSTree* parseTree( TSParser* parser, std::string_view src )
+TSTree* parseTree( TSParser* parser, std::string_view src )
Exercise every registered grammar and its embedded query, reporting loaded and expected totalsinline DoctorGrammarProbe doctorProbeGrammars()
... [21 more line(s); run it to see the whole thing]
@@ -346,13 +346,13 @@ _Same query with routing forced OFF (plain subtoken+body BM25) — contrast with
```
$ ./build/ripwire . --for="rankGraphTeleport" --no-route
-
+
-
+
uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f )
-
+
PageRank with an explicit teleport / personalization vector p (Σp = 1). The prior is name-quali…inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f )
inline ChurnRanking churnRankedGraph( const MainDispatch& d )
@@ -378,14 +378,14 @@ _Cut the result at the relevance cliff (Adaptive-k) — on a flat ranking nothin
```
$ ./build/ripwire . --for="tree-sitter parse of a source file" --adaptive
-
+
inline bool topLevelEvidence( std::string_view source, const TSLanguage* language, const Predicate& predicate )
The crawl's per-file byte ceiling. A text file larger than this is skipped: at this size it is o…constexpr std::size_t kDefaultMaxFileBytes = 4u * 1024u * 1024u
-TSTree* parseTree( TSParser* parser, std::string_view src )
+TSTree* parseTree( TSParser* parser, std::string_view src )
Exercise every registered grammar and its embedded query, reporting loaded and expected totalsinline DoctorGrammarProbe doctorProbeGrammars()
... [21 more line(s); run it to see the whole thing]
@@ -409,7 +409,7 @@ _Same task with the anchor disabled — the contrast the flag exists for._
```
$ ./build/ripwire . --for="why does src/lexical.h chooseForRanker pick name-exact BM25" --no-mention-boost
-
@@ -439,14 +439,14 @@ _The same task with doc-mention surfacing OFF — the contrast the flag exists f
```
$ ./build/ripwire . --for="quality delta acks ledger rubber stamp" --no-doc-mention
-
+
L2 stale acks in the range form. A changed-files answer holds no whole target tree to check the …std::vector<rw::quality::StaleAck> refPairStaleAcks( const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const RefPairDelta& refs )
inline QualityDeltaOutcome computeQualityDelta( const std::string& root )
-inline std::string staleByKindValue( const std::vector<StaleAck>& staleAcks )
+inline std::string staleByKindValue( const std::vector<StaleAck>& staleAcks )
inline constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at
... [22 more line(s); run it to see the whole thing]
```
@@ -469,7 +469,7 @@ _Interface -> implementors view: every existing impl of the named interface; the
$ ./build/ripwire . --lego=Vehicle
-
+
@@ -500,7 +500,7 @@ _The repo's best-in-class instance to imitate before writing new code (picked by
$ ./build/ripwire . --exemplar="format byte sizes for humans"
-
+
/aux/kbcorpus --recall="field affinity cache line data layout which fields are read together" --top-k=3 --max-tokens=1200
ripwire recall — "field affinity cache line data layout which fields are read together" — 2 relevant of 2 document files, best-first — total=2 shown=1 capped=1 truncated=1 max_tokens=1200 share_bytes=2040 est_tokens=957
-━━ commands.md (relevance 10.053) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 588971 B; lines="3838-3842"; dropped_by_budget=163] [truncated: 1865 of 7738 bytes]
+━━ commands.md (relevance 10.117) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 589307 B; lines="3838-3842"; dropped_by_budget=163] [truncated: 1865 of 7738 bytes]
### `--field-affinity[=STRUCT]`
**Answers:** find fields that are read together but declared far apart — the cache-locality lens the CACHE-LOCALITY lens: which fields are READ TOGETHER but declared FAR APART.
@@ -623,7 +623,7 @@ _File-by-file orientation map (top symbols per file)._
```
$ ./build/ripwire . --tree
-
+
@@ -632,7 +632,7 @@ $ ./build/ripwire . --tree
-
+
@@ -727,7 +727,7 @@ _--no-stable outside --mcp: what the flag does (or says) when there is no stable
$ ./build/ripwire . --no-stable --top-k=3
-
+
@@ -761,7 +761,7 @@ $ ./build/ripwire . --around=rankGraphTeleport
-
+
@@ -813,18 +813,18 @@ _What SYM calls (1-hop out-edges)._
```
$ ./build/ripwire . --callees=rankGraphTeleport
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
```
@@ -848,10 +848,10 @@ _The resolvable use-sites (call/read/write/import/extends) with file:line; count
```
$ ./build/ripwire . --uses=rankGraphTeleport
-
+
-
-
+
+
@@ -882,13 +882,13 @@ _Composable node-set query: functions within 2 caller-hops of rankGraphTeleport.
```
$ ./build/ripwire . --graph-query='and(callers(name("rankGraphTeleport"),2),kind(all,fn))'
-
+
-
+
-
+
@@ -919,17 +919,17 @@ _Names referenced but never defined in-corpus (stdlib/third-party surface). The
```
$ ./build/ripwire . --external-surface
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
... [17 more line(s); run it to see the whole thing]
@@ -954,12 +954,12 @@ _Shortest directed call-path SRC -> DST. CHANGED: now reports from_p/to_p/from_d
```
$ ./build/ripwire . --path=main,rankGraphTeleport
-
+
-
+
```
@@ -976,10 +976,10 @@ _Minimal connecting subgraph over 3 symbols (finds shared-caller joins)._
```
$ ./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex
-
+
-
+
@@ -1086,7 +1086,7 @@ _Test files that transitively reach the changed file._
```
$ ./build/ripwire . --affected=src/graph.h
-
@@ -1143,7 +1143,7 @@ _Mid-task situational report for the current git diff — recorded against a CLE
$ ./build/ripwire . --situ
ripwire situational-awareness — 0 changed file(s), 0 symbols in them
root: .
-at: d3605fde7
+at: 0712a5182
(0 changed files — working tree is clean, nothing to analyze)
```
@@ -1162,18 +1162,18 @@ _The continuation packet for the NEXT session: disk truth (branch/sha
```
$ ./build/ripwire . --handoff
-
+
-
+
-
-
-
+
+
+
+
... [1 more line(s); run it to see the whole thing]
```
@@ -1197,7 +1197,7 @@ _Pre-PR gate on a CLEAN tree: no obligations, exit 0._
```
$ ./build/ripwire . --test-gate
-
```
@@ -1280,18 +1280,18 @@ _Boolean grep: hits where BOTH literals share the matched line (--grep-scope=lin
$ ./build/ripwire . --grep=DISCLOSE --and=cache
-
+
-
+
-
+
@@ -1524,7 +1524,7 @@ _Importance-weighted detail: FULL bodies for top-2, signatures for the rest._
```
$ ./build/ripwire . --for="pagerank power iteration" --detail=2
-
+
@@ -1559,7 +1559,7 @@ $ ./build/ripwire . --pack-signatures --top-k=10
-
+
@@ -1590,7 +1590,7 @@ $ ./build/ripwire . --outline=rankGraphTeleport --top-k=0
signature rows. est_tokens=: price as emitted (an upper bound under compact). root=: p= relative to it. -->
-
+
& p, float alpha = 0.85f )
{
PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" );
@@ -1621,7 +1621,7 @@ $ ./build/ripwire . --top-k=0 --expand=rankGraphTeleport
-
+
+
-
+
-
+
@@ -1794,7 +1794,7 @@ _File->file dependency graph (god-files, cycles)._
$ ./build/ripwire . --deps
-
+
@@ -1804,8 +1804,8 @@ $ ./build/ripwire . --deps
+
-
... [17 more line(s); run it to see the whole thing]
```
@@ -1830,16 +1830,16 @@ _Complexity x recent git churn (maintenance pain)._
$ ./build/ripwire . --hotspots
-
-
+
+
-
+
-
+
... [17 more line(s); run it to see the whole thing]
@@ -1858,7 +1858,7 @@ _Token-normalized duplicate bodies._
```
$ ./build/ripwire . --clones
-
+
@@ -1868,7 +1868,7 @@ $ ./build/ripwire . --clones
-
+
... [17 more line(s); run it to see the whole thing]
@@ -1889,10 +1889,10 @@ _Per-function size ranking, largest Halstead volume/token entropy/lines first
```
$ ./build/ripwire . --biggest-first --limit=8
-
-
+
+
-
+
@@ -1922,7 +1922,7 @@ _Per function, the non-local MUTABLE state it can reach (transitively), most wri
```
$ ./build/ripwire . --nonlocal-state --limit=8
-
|
|
@@ -1957,7 +1957,7 @@ _The family join: per function, which of four orthogonal evidence families fire,
```
$ ./build/ripwire . --ensemble --limit=8
-
@@ -1988,17 +1988,17 @@ _THE single wide-angle quality read: six families in one pass, an eligible/ranke
```
$ ./build/ripwire . --quality-panel
-
-
-
+
+
-
+
... [17 more line(s); run it to see the whole thing]
@@ -2025,13 +2025,13 @@ _The local-reasoning lens: to understand this symbol, how much must you know tha
```
$ ./build/ripwire . --context-ratio --limit=8
-
+
-
+
-
-
+
+
... [23 more line(s); run it to see the whole thing]
```
@@ -2056,8 +2056,8 @@ _Score the naming-* rules against this repo's own rename history: proxy=old/(old
```
$ ./build/ripwire . --naming-calibration
-
-
+
+
@@ -2091,10 +2091,10 @@ _The corpus's OWN case-convention vote per (language, kind) group; off-conventio
```
$ ./build/ripwire . --naming-consistency --limit=8
-
-
-
-
+
+
+
+
@@ -2128,7 +2128,7 @@ _The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/
```
$ ./build/ripwire . --lint --naming-locals
-
+
@@ -2163,7 +2163,7 @@ _Functions WITH a doc comment, most name-restating first: c_coeff (high = the co
```
$ ./build/ripwire . --comment-coherence --limit=8
-
+
@@ -2196,16 +2196,16 @@ _Files that change together in git (hidden coupling)._
```
$ ./build/ripwire . --cochange
-
-
+
+
-
-
-
-
+
+
+
+
... [22 more line(s); run it to see the whole thing]
```
@@ -2228,16 +2228,16 @@ _Only pairs whose co-change RECURS in 2+ sub-windows of the mined window (sub_wi
```
$ ./build/ripwire . --cochange --cochange-recur=2
-
+
+
-
-
-
-
+
+
+
... [22 more line(s); run it to see the whole thing]
```
@@ -2254,7 +2254,7 @@ _Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none
```
$ ./build/ripwire . --cochange --cochange-groups
-
+
@@ -2283,18 +2283,18 @@ _Hotspots scoped to RECENT churn (the regression lens)._
```
$ ./build/ripwire . --hotspots --since="2 weeks ago"
-
-
+
+
-
+
-
+
-
+
... [17 more line(s); run it to see the whole thing]
```
@@ -2321,7 +2321,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes
$ ./build/ripwire . --arch=test/archfix/rules.txt
-
@@ -2351,7 +2351,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes
$ ./build/ripwire . --arch=test/archfix/rules.txt
-
@@ -2377,7 +2377,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes
$ ./build/ripwire . --arch=test/archfix/rules.txt
-
@@ -2404,7 +2404,7 @@ _Built-in AST checks (c-cast, goto, unsafe-c-fn, ...)._
```
$ ./build/ripwire . --lint
-
+
@@ -2627,15 +2627,15 @@ _Cluster the call graph into cohesive modules._
```
$ ./build/ripwire . --communities
-
+
-
+
-
+
@@ -2658,7 +2658,7 @@ _Drill into ONE call-graph community by id — the drill= the --communities outp
```
$ ./build/ripwire . --community=0
-
```
@@ -2683,15 +2683,15 @@ _Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels
```
$ ./build/ripwire . --zoom
-
-
+
+
-
-
+
+
-
+
@@ -2720,15 +2720,15 @@ $ ./build/ripwire . --report
# ripwire architecture report
-3618 files · 31790 symbols · 29969 edges · 3610 modules (14921 call-graph isolated)
+3631 files · 31860 symbols · 30033 edges · 3620 modules (14942 call-graph isolated)
Root: `.`
-Call-graph isolate provenance: 3976 declaration, 2448 header, 3371 source, 5126 document; 0 connected Louvain singletons
+Call-graph isolate provenance: 3978 declaration, 2450 header, 3384 source, 5130 document; 0 connected Louvain singletons
-## Modules (call-graph clusters; showing 12 of 3610)
-- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1631 symbols
-- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 547 symbols
+## Modules (call-graph clusters; showing 12 of 3620)
+- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1630 symbols
+- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 548 symbols
- **src::DISCLOSE@infra/Diagnostics.h:616:43369 [read,compute,resolve]** — 335 symbols
... [17 more line(s); run it to see the whole thing]
```
@@ -2746,7 +2746,7 @@ _Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped._
```
$ ./build/ripwire . --seams
-
+
@@ -2777,15 +2777,15 @@ $ ./build/ripwire . --mermaid
%% ripwire --mermaid: module (directory) dependency graph — node = dir (symbol count), edge = inter-module calls (>= 3). Render at mermaid.live.
flowchart LR
subgraph sg0 ["src"]
- n102["src
9422"]
+ n102["src
9435"]
n103["src/infra
1301"]
end
subgraph sg1 ["test"]
- n104["test
5517"]
- n566["test/legochargefix
546"]
- n400["test/fixtures/recallpassage
314"]
- n956["test/slotjoinfix
175"]
- n798["test/ownerhopfix/py/pkg
158"]
+ n104["test
5523"]
+ n571["test/legochargefix
546"]
+ n405["test/fixtures/recallpassage
314"]
+ n962["test/slotjoinfix
175"]
+ n804["test/ownerhopfix/py/pkg
158"]
n342["test/expandmodefix
151"]
n344["test/expandsibsfix
149"]
... [17 more line(s); run it to see the whole thing]
@@ -2806,8 +2806,8 @@ _Bus-factor: recency-weighted author ownership per file._
```
$ ./build/ripwire . --owners
-
-
+
+
@@ -2837,7 +2837,7 @@ _Internal functions with no caller found in the index — a name-based graph rea
```
$ ./build/ripwire . --dead-code=src
-
+
```
@@ -2902,7 +2902,7 @@ _The same clean verdict with what it folded printed back: every stale acknowledg
```
$ ./build/ripwire . --quality-delta --show-stale
-
@@ -2931,7 +2931,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox
```
$ ./build/ripwire . --quality-delta
-
```
@@ -2956,7 +2956,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox
```
$ ./build/ripwire . --quality-delta
-
```
@@ -2981,7 +2981,7 @@ _A ref range run for two of the twelve kinds only: the named kinds' rows are exa
```
$ ./build/ripwire . --quality-delta=HEAD~1..HEAD --quality-kinds=complexity,dead-code
-
@@ -3074,7 +3074,7 @@ _OWNERSHIP partition for a shared tree: every regression here lives in src/infra
```
$ ./build/ripwire . --quality-delta --scope=src/graph.h
-
@@ -3104,10 +3104,10 @@ _Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree
```
$ ./build/ripwire . --edit-check=rankGraphTeleport
-
-
-
+
+
@@ -3158,12 +3158,12 @@ $ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payloa
{"n":"benchAdaptive","p":"bench/bench_radix_ab.cpp:157","l":[162]},
{"n":"radixSortNonNegativeFloatsDesc","p":"src/infra/sortutil.h:105","l":[114]},
{"n":"radixSortByScoreDescId","p":"src/infra/sortutil.h:120","l":[180]}],
-"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"},
+"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"},
{"p":"test/adaptivecutshapefix/adaptive_cut_shape_test.cpp","hops":2,"run":"bash test/adaptivecutshapecheck.sh"},
{"p":"test/includeprecise_unit.cpp","hops":2,"run":"bash test/includeprecisecheck.sh"},
{"p":"test/verify_csr.cpp","hops":2,"run":"bash test/a9disclosurecheck.sh"},
{"p":"test/rustimport_unit.cpp","hops":4,"run":"bash test/rustimportprecisecheck.sh"}],
-"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":782,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"}
+"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":782,"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"}
```
### `--insert-after-symbol=TARGET`
@@ -3179,12 +3179,12 @@ _Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 bec
```
$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=/aux/payload_note.h
{"applied":"insert_after_symbol","symbol":"lessByScoreDescId","file":"src/infra/sortutil.h","span":{"start":2375,"end":2463},"lines":{"start":56,"end":58},"replaced_bytes":0,"old_file_bytes":10824,"new_file_bytes":10912,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 652 more bytes on this line]
-"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"},
+"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"},
{"p":"test/adaptivecutshapefix/adaptive_cut_shape_test.cpp","hops":2,"run":"bash test/adaptivecutshapecheck.sh"},
{"p":"test/includeprecise_unit.cpp","hops":2,"run":"bash test/includeprecisecheck.sh"},
{"p":"test/verify_csr.cpp","hops":2,"run":"bash test/a9disclosurecheck.sh"},
{"p":"test/rustimport_unit.cpp","hops":4,"run":"bash test/rustimportprecisecheck.sh"}],
-"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":782,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"}
+"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":782,"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"}
```
**Caveats (stated by the binary):**
@@ -3230,12 +3230,12 @@ $ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payloa
{"n":"benchAdaptive","p":"bench/bench_radix_ab.cpp:157","l":[162]},
{"n":"radixSortNonNegativeFloatsDesc","p":"src/infra/sortutil.h:105","l":[114]},
{"n":"radixSortByScoreDescId","p":"src/infra/sortutil.h:120","l":[180]}],
-"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"},
+"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"},
{"p":"test/adaptivecutshapefix/adaptive_cut_shape_test.cpp","hops":2,"run":"bash test/adaptivecutshapecheck.sh"},
{"p":"test/includeprecise_unit.cpp","hops":2,"run":"bash test/includeprecisecheck.sh"},
{"p":"test/verify_csr.cpp","hops":2,"run":"bash test/a9disclosurecheck.sh"},
{"p":"test/rustimport_unit.cpp","hops":4,"run":"bash test/rustimportprecisecheck.sh"}],
-"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":782,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"}
+"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":782,"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"}
```
**Shaped by:** `--insert-after-symbol`
@@ -3294,11 +3294,11 @@ _The same plan committed: per-file locks, re-verify-before-write, atomic rename,
```
$ ./build/ripwire . --edit-plan=/aux/edit_plan.json --apply
-{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"applied":1,"atomic_files":1,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"mult … [line truncated: 528 more bytes on this line]
+{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"applied":1,"atomic_files":1,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"mult … [line truncated: 537 more bytes on this line]
{"n":"benchAdaptive","p":"bench/bench_radix_ab.cpp:157","l":[162]},
{"n":"radixSortNonNegativeFloatsDesc","p":"src/infra/sortutil.h:107","l":[116]},
{"n":"radixSortByScoreDescId","p":"src/infra/sortutil.h:122","l":[182]}],
-"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true}}]}
+"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true}}]}
```
**Shaped by:** `--edit-check`
@@ -3344,19 +3344,19 @@ _Bare --slice=SYM: the INVENTORY of sliceable locals (), so a calle
```
$ ./build/ripwire . --slice=rankGraphTeleport
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
... [3 more line(s); run it to see the whole thing]
```
@@ -3381,17 +3381,17 @@ _Forward flow: which statements the seed's value reaches, at the default depth b
```
$ ./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=fwd
-
-
+
+
-
+
teleport( pw.begin(), pw.end() );]]>
-
+
-
+
... [22 more line(s); run it to see the whole thing]
@@ -3435,10 +3435,10 @@ $ ./build/ripwire . --slice-depth=3
_Hold a LOCATION, not a name: the enclosing-definition chain at FILE:LINE (a compiler error, a diff hunk, a stack frame), outermost -> innermost._
```
-$ ./build/ripwire . --at=src/graph.h:11752
+$ ./build/ripwire . --at=src/graph.h:11811
-
-
+
+
```
@@ -3462,7 +3462,7 @@ _No-LLM review-evidence bundle for the working-tree diff (clean tree = empty)._
```
$ ./build/ripwire . --pr-context
-
```
@@ -3488,11 +3488,11 @@ _Pairwise cross-arm conflict sites + suggested landing order (any committish sha
```
$ ./build/ripwire . --merge-scout=HEAD~2,HEAD~1
-
-
+
+
-
+
@@ -3567,7 +3567,7 @@ _Which refs of the `lane/` ref family still hold divergent authored work vs HEAD
```
$ ./build/ripwire . --stray-content=lane/
-
+
[
@@ -3601,7 +3601,7 @@ _Select the genuinely-unmerged refs of the `lane/` ref family and feed them to m
```
$ ./build/ripwire . --stray-content=lane/ --plan
-
+
]
@@ -3637,20 +3637,20 @@ _Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract d
```
$ ./build/ripwire . --stray-content=lane/ --abi
-
-
-
+
+
+
-
-[
-
+
+
]
-[
-
+][
+
+
-... [2 more line(s); run it to see the whole thing]
+... [10 more line(s); run it to see the whole thing]
```
**Caveats (stated by the binary):**
@@ -3672,10 +3672,10 @@ _Which ref's tree defines or mentions SYM — HEAD first, then every local branc
```
$ ./build/ripwire . --whereis=rankGraphTeleport
-
-
-
-
+
+
+
+
... [14 more line(s); run it to see the whole thing]
@@ -3702,10 +3702,10 @@ _The same page with every t= line whole: the page above previews each line over
```
$ ./build/ripwire . --whereis=rankGraphTeleport --whereis-listing=all --whereis-full-text
-
-
-
-
+
+
+
... [24 more line(s); run it to see the whole thing]
@@ -3730,11 +3730,11 @@ _The whole hit list asked for by name: under the same 60-row cap HEAD's referenc
```
$ ./build/ripwire . --whereis=rankGraphTeleport --whereis-listing=all
-
-
+
+
-
-
+
+
... [23 more line(s); run it to see the whole thing]
@@ -3762,7 +3762,7 @@ _The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gat
$ ./build/ripwire . --flags
-
+
@@ -3843,7 +3843,7 @@ _The cache-locality lens over every aggregate: fields READ TOGETHER but declared
```
$ ./build/ripwire . --field-affinity
-
@@ -3878,7 +3878,7 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam
```
$ ./build/ripwire . --doc-drift
-
+
@@ -3912,7 +3912,7 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam
```
$ ./build/ripwire . --doc-drift
-
+
@@ -3945,8 +3945,8 @@ _Same report, with git history splitting stale mentions into deleted-by-commit v
```
$ ./build/ripwire . --doc-drift --with-history
-
-
+
+
@@ -3979,7 +3979,7 @@ _The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when
```
$ ./build/ripwire . --plan-lint=test/planlintfix/wave.md
-
+
@@ -4014,8 +4014,8 @@ $ ./build/ripwire . --from-trace=-
AddressSanitizer:DEADLYSIGNAL
=================================================================
==41337==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x000102f4a1c8 bp 0x00016d2f1a40 sp 0x00016d2f19e0 T0)
- #0 0x102f4a1c8 in rw::rankGraphTeleport(Graph const&, std::vector const&, float) src/graph.h:11752
- #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11793
+ #0 0x102f4a1c8 in rw::rankGraphTeleport(Graph const&, std::vector const&, float) src/graph.h:11811
+ #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11852
#2 0x102e11f30 in runDefaultMap(MainDispatch const&) src/main.cpp:1753
#3 0x102e01a44 in main src/main.cpp:4174
#4 0x1a2b3c0dc in start+0x9dc (dyld:arm64e+0x60dc)
@@ -4044,7 +4044,7 @@ _A command that exits 0: a minimal success record (exit, measured duration, disc
$ ./build/ripwire . --run-trace="true"
-
+
```
@@ -4204,7 +4204,7 @@ _Task lens + a compact Mermaid flowchart of the top anchors' 1-hop edges._
```
$ ./build/ripwire . --for="pagerank power iteration" --with-graph
-
+
@@ -4277,14 +4277,14 @@ _Environment self-check: binary staleness, grammars, cache dir, git, tracked-bin
```
$ ./build/ripwire . --doctor
-
-
+
-
-
+
+
-
-
+
@@ -4311,14 +4311,14 @@ _--doctor plus a LIVE integration inspection for one agent: PATH binary, install
```
$ ./build/ripwire . --doctor --agent=claude
-
-
+
-
-
+
+
-
-
+
@@ -4346,7 +4346,7 @@ $ ./build/ripwire . --skipped
-
@@ -4434,8 +4434,8 @@ _Rank by git change-frequency prior instead of PageRank._
$ ./build/ripwire . --rank-by=churn --top-k=5
-
-
+
+
]
@@ -4467,22 +4467,22 @@ a trailing slash is ignored; absolute paths and '..' are refused). The global block stays byte-identical, a second page follows it — n=/of= are its counts (of= IS the total, so the paging half carries no total=), capped="1" has_more="1" next_offset= offset= limit= page it, and next= replays THIS run's own corpus flags (--since/--exclude) so the page it names is a page of the same answer. The symbol map collapses to a disclosed stub — the map was not asked for and was not ranked at all, which is why the header carries no pr_iters=. merge_bombs_skipped= stays on the global block: it counts the window's skipped commits, not the directory's._
```
-$ ./build/ripwire . --rank-by=churn-decay --since=HEAD~4 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3
+$ ./build/ripwire . --rank-by=churn-decay --since=HEAD~2 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3
-
-
-
-
-
-
-
-
-
-
-
-
-... [18 more line(s); run it to see the whole thing]
+
+
+
+
+
+
+
+
+
+
+
+
+... [3 more line(s); run it to see the whole thing]
```
**Shaped by:** `--external-surface`, `--doctor`, `--legend`, `--max-memory`
@@ -4544,7 +4544,7 @@ _The same gating report under --legend=full — same rows, same exit 2; the defa
```
$ ./build/ripwire . --quality-delta --legend=full
-
@@ -4625,7 +4625,7 @@ _The family join: per function, which of four orthogonal evidence families fire,
```
$ ./build/ripwire . --ensemble --limit=8
-
@@ -4661,7 +4661,7 @@ _Drop matching paths (repeatable) before ranking._
$ ./build/ripwire . --exclude=present --exclude=bench --top-k=5
-
+
@@ -4692,8 +4692,8 @@ _Full map re-ranked with teleport toward git-changed files — clean tree, so ch
$ ./build/ripwire . --map-diff --top-k=5
-
-
+
+
@@ -4726,7 +4726,7 @@ _Explicit incremental cache at a path OUTSIDE the repo (first call writes it)._
$ ./build/ripwire . --cache=/aux/warm2.ripwirecache --top-k=3
-
+
@@ -4776,7 +4776,7 @@ _Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm co
$ ./build/ripwire . --no-cache --top-k=3
-
+
@@ -4807,7 +4807,7 @@ _Crawl paths the repo's own .gitignore covers (default honours it and discloses
$ ./build/ripwire . --no-ignore --top-k=3
-
+
@@ -4843,10 +4843,10 @@ _Skip files above a size bound before parsing (note the corpus shrink in the hea
$ ./build/ripwire . --max-file-size=8K --top-k=3
-
+
-
+
@@ -4923,7 +4923,7 @@ _Eval-only: a per-call-site census of WHICH mechanism resolved each call, and th
$ ./build/ripwire . --pin-census=/aux/pin_census.tsv --top-k=3
-
+
@@ -4978,9 +4978,9 @@ _--mcp-legend=inline: every answer of the stdio session carries its own legend (
$ ./build/ripwire '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"whereis","arguments":{"path":".","symbol":"rankGraphTeleport"}}}' '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"whereis","arguments":{"path":".","symbol":"computeOnePairOverlap"}}}' | ./build/ripwire --mcp --mcp-legend=inline
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-11-25","serverInfo":{"name":"ripwire","version":"1.0"},"capabilities":{"tools":{},"resources":{}},"instructions":"Map before reading files. Start a new task with explore; use from_trace for an error; use impact plus uses before changing a sym … [line truncated: 735 more bytes on this line]
{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [815 more display lines; full output is 26584 bytes on 1 raw line(s)]
+`````
+
+stderr:
+
+`````
+ripwire: cache : over its 2048 MiB budget — evicted 115 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept)
+`````
+
+## `./build/ripwire . --top-k=5`
+
+*Same map, capped to the 5 highest-ranked symbols.*
+
+**wall time: 1.98s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [67 more display lines; full output is 8280 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --top-k=5 --no-inventory`
+
+*The same capped map without its inventory tier: --top-k=5 leaves files out, so the default map appends (program entries, and the files the ranked rows left out) after its rows; --no-inventory drops that tier, and the ranked rows are the same.*
+
+**wall time: 3.23s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --top-k=0 --expand=rankGraphTeleport`
+
+*NEW since the last capture: --top-k=0 means PAYLOAD-ONLY — no ranked map rides along with the body you asked for.*
+
+**wall time: 1.39s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --token-budget=100`
+
+*GATE form: exit 3 if the map's own est_tokens exceeds the budget (over-budget failure shape).*
+
+**exit code: 3** — **wall time: 2.86s**
+
+`````
+
+
+`````
+
+stderr:
+
+`````
+ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100
+`````
+
+## `./build/ripwire . --for="incremental cache invalidation when a file content hash changes"`
+
+*The task lens: ranked signatures + quality metrics framed for the task.*
+
+**wall time: 7.14s**
+
+`````
+
+
+
+
+incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…constexpr std::uint32_t kCacheMagic = 0x4b505443
+
+and every file whose content hash differs is re-parsed — so a stale or foreign blob self-heals…constexpr std::uint32_t kHeadSnapCacheScheme = 1
+inline McpRebuildBaseline mcpRebuildBaseline( const McpIndex& ix, bool isIncrementalPass )
+inline void prewarmTagsQueries( const std::vector<std::string>& files, const HashMap<std::string, FileFacts>& cache, long long cacheWriteNs, IngestFile … [line truncated: 20 more bytes on this line]
+inline bool ingestCommitTree( const std::string& root, const std::string& sha, const std::vector<std::string>& excludes, std::size_t maxFileBytes, IngestResult& ou … [line truncated: 7 more bytes on this line]
+inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& imple … [line truncated: 62 more bytes on this line]
+inline std::string spanTierMemoPath( const std::string& diskPath )
+inline RawFacts runParsePool( IngestResult& result, const char* rootDir, std::string_view cacheFile, bool captureValueUses, HashMap<std::string, FileFacts>& cach … [line truncated: 98 more bytes on this line]
+
+persistent in-memory index (parse once, reuse across MCP calls) ---- The MCP server is long-live…struct McpIndex
+inline const McpIndex& getIndex( const std::string& root )
+inline std::uint64_t contentHash64( std::string_view s ) noexcept
+struct CacheEntry
+inline std::uint64_t blobChecksum( std::string_view s ) noexcept
+inline ContentIdIndex contentIdsBySym( const IngestResult& ing, const Graph& g, std::string_view root )
+inline std::vector<CacheWriteRow> buildCacheWritePlan( const std::vector<std::uint32_t>& orderIn, const std::vector<std::uint64_t>& pathHashes … [line truncated: 25 more bytes on this line]
+inline CachePathKeys buildCachePathKeys( const std::vector<std::string>& files, std::string_view rootDir )
+inline std::string reAbsolutize( std::string_view rel, std::string_view root )
+inline std::uint64_t indexContentHash( const std::vector<std::string>& files, const std::vector<long long>& fileMtime, const std::vector<std::uint64_t> … [line truncated: 25 more bytes on this line]
+inline std::string makeHandle( const std::string& canonId, const std::string& path, const std::string& name, std::uint64_t contentHash )
+struct IngestFileScan
+inline std::uint64_t byteHash( const char* data, std::size_t n ) noexcept
+inline void collectExtractPartials( const IngestFileScan& scan, IngestResult& result )
+void emitGrepHandleLegend( bool enabled )
+… [127 more display lines; full output is 20051 bytes on 8 raw line(s)]
+`````
+
+## `./build/ripwire . --for="rankGraphTeleport"`
+
+*Name-shaped query: the router picks name-exact BM25 (header says which/why).*
+
+**wall time: 6.06s**
+
+`````
+
+
+
+
+
+PageRank with an explicit teleport / personalization vector p (Σp = 1). The prior is name-quality-biased through biasPrior() so all rank modes share one weighting seam; the transition matrix (edgesinline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>&am … [line truncated: 31 more bytes on this line]
+#### The convergence disclosure contract
+### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+& p, float alpha = 0.85f )
+… [28 more display lines; full output is 5868 bytes on 29 raw line(s)]
+`````
+
+## `./build/ripwire . --for="rankGraphTeleport" --no-route`
+
+*Same query with routing forced OFF (plain subtoken+body BM25) — contrast with the routed run.*
+
+**wall time: 3.19s**
+
+`````
+
+
+
+
+
+uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f )
+
+PageRank with an explicit teleport / personalization vector p (Σp = 1). The prior is name-quali…inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f )
+inline ChurnRanking churnRankedGraph( const MainDispatch& d )
+
+L10 (2026-09-04): the old wording claimed "the same corpus ranked by pagerank orders differently…inline constexpr const char* kChurnRankLegend = "<!-- rank_by=churn: k= is PageRank re-run with the teleport BIASED by git CHANGE-FREQUENCY over window= " "(a c…
+struct RankedGraph
+inline std::vector<float> takeRank( RankedGraph ranked, RankDisclosure& disclosureOut )
+inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )
+inline std::vector<float> churnTeleportWorkspace( const std::vector<std::string>& rootDirs, const IngestResult& ing, const char* since = "18 months ago& … [line truncated: 20 more bytes on this line]
+inline ChurnRanking churnDecayRanking( const MainDispatch& d, const rw::SinceScope& sinceScope, bool isScoped, const char* verbLabel )
+inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false )
+PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> rank…
+inline std::vector<float> churnDecayTeleport( const std::string& root, const IngestResult& ing, const SinceScope* scope = nullptr, bool* outHasChurnEvidence = n…
+inline std::string didYouMean( const IngestResult& ing, std::string_view name )
+PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span< … [line truncated: 45 more bytes on this line]
+inline const McpIndex& getIndex( const std::string& root )
+inline std::vector<float> churnDecayTeleportWorkspace( const std::vector<std::string>& rootDirs, const IngestResult& ing, bool* outHasChurnEvidence = n … [line truncated: 12 more bytes on this line]
+struct DataSectionsCut
+### Fixed — `rank_by` over MCP no longer answers a different ranking than `--rank-by` on … [line truncated: 36 more bytes on this line]
+### 2. Gates for A
+inline std::vector<float> anchoredLexicalRank( const Graph& g, const std::vector<float>& lex )
+inline int runEval( const std::string& root, const IngestResult& ing, const Graph& g, const std::vector<char>& currentDiff )
+#### The convergence disclosure contract
+### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e`
+… [155 more display lines; full output is 24115 bytes on 72 raw line(s)]
+`````
+
+## `./build/ripwire . --for="rankGraphTeleport" --signatures-only`
+
+*T3 opt-out: the signatures-only lens (no auto bodies, no bundle="auto" attribute) — contrast with the terminal default above.*
+
+**wall time: 4.02s**
+
+`````
+
+
+
+
+
+PageRank with an explicit teleport / personalization vector p (Σp = 1). The prior is name-quality-biased through biasPrior() so all rank modes share one weighting seam; the transition matrix (edgesinline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>&am … [line truncated: 31 more bytes on this line]
+#### The convergence disclosure contract
+### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e`
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --for="tree-sitter parse of a source file" --adaptive`
+
+*Cut the result at the relevance cliff (Adaptive-k) — on a flat ranking nothing is cut and the header says so ([adaptive: kept N of N]).*
+
+**wall time: 3.70s**
+
+`````
+
+
+
+
+inline bool topLevelEvidence( std::string_view source, const TSLanguage* language, const Predicate& predicate )
+The crawl's per-file byte ceiling. A text file larger than this is skipped: at this size it is o…constexpr std::size_t kDefaultMaxFileBytes = 4u * 1024u * 1024u
+TSTree* parseTree( TSParser* parser, std::string_view src )
+
+Exercise every registered grammar and its embedded query, reporting loaded and expected totalsinline DoctorGrammarProbe doctorProbeGrammars()
+struct FileHealth
+constexpr std::array<LangEntry, 57> kLangTable =
+inline RevSide sliceAtRev( const std::string& root, const std::string& sha, const std::string& rel, const Symbol& sym, SliceFam fam, const ::TSLanguage* grammar… … [line truncated: 2 more bytes on this line]
+struct SliceScan
+enum class AstWalk : std::uint8_t
+inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept
+constexpr std::uint32_t kMaxKotlinStringNestDepth = 128u
+std::vector<LocalNameFact> collectGatedLocalNames( std::string_view defBytes, std::uint32_t defStartLine, Lang lang )
+inline ModuleScan scanModule( std::string_view source, std::string_view path )
+inline bool hasPhantomScopeSeparator( TSNode qualified ) noexcept
+bool jsonNestsTooDeep( std::string_view bytes ) noexcept
+inline bool hasMainGuard( std::string_view source )
+constexpr std::uint32_t kMaxYamlNestDepth = 64u
+SpanTierBatch spanTiersOfFiles( std::span<const std::string> diskPaths, bool useMemo )
+enum class DisclosureWhy : std::uint8_t
+inline SliceScan sliceScanDefinition( const std::string& src, const Symbol& sym, SliceFam fam, const ::TSLanguage* grammar, std::string_view varName )
+inline void runParseWorker( ParsePoolShared& sh, unsigned t )
+struct LintRule
+inline FileHealth measureHealthAdoptingMemberMacroReparse( TSParser* parser, Lang lang, std::string_view bytes, TreeGuard& tree, MemberMacroRepa … [line truncated: 19 more bytes on this line]
+inline std::string buildMemoryStopAttr( const IngestResult& ing, bool json )
+… [138 more display lines; full output is 19866 bytes on 44 raw line(s)]
+`````
+
+## `./build/ripwire . --for="why does src/lexical.h chooseForRanker pick name-exact BM25"`
+
+*Mention anchoring (default-on): a path and a Symbol literally named in the task get lifted; the header says what anchored.*
+
+**wall time: 3.26s**
+
+`````
+
+
+
+
+The name-exact ranker AS THE RETRIEVAL LENS SERVES IT: whole-name BM25 plus the definition-over-…inline std::vector<float> lexicalScoresNameExactRanked( const IngestResult& ing, std::string_view query, const std::vector<float>* symbolScoreMul )
+
+P11.12: the interpretive footer for --eval's ranker table, pulled into its own function so the 9…inline void printEvalRankerNote()
+inline int runEvalRetrieval( const IngestResult& ing, const Graph& g )
+
+calling agent knows to reformulate rather than trust the ranking. Calibrated empirically (2026-0…inline constexpr float kWeakLexicalScoreThreshold = 1.0f
+inline RouteChoice chooseForRanker( const IngestResult& ing, std::string_view query )
+inline std::string candidatesRootTag( std::size_t keep, std::size_t corpusCount, const CandidateProvenance& prov )
+inline std::vector<float> lexicalScoresNameExactTiered( const IngestResult& ing, std::string_view query, const std::vector<float>* symbolScoreMul )
+inline int runEvalMined( const std::string& root, const IngestResult& ing, const Graph& g, const std::string& path )
+struct NameCorpusStats
+inline int runEvalSkills( const std::string& root, const IngestResult& ing, const Graph& g, const std::string& labelsPath )
+inline bool hasIdentifierShape( std::string_view w ) noexcept
+struct LensRanking
+struct Bm25Params
+inline double bm25ImpactBound( double idf, double T, const Bm25Params& p ) noexcept
+inline int runEval( const std::string& root, const IngestResult& ing, const Graph& g, const std::vector<char>& currentDiff )
+rw::LensRanking computeLensRanking( const MainDispatch& d, std::string_view task, bool compactCandidate = false, bool fullDistribution = false ) // deep-tail: the file-grain tail rea … [line truncated: 65 more bytes on this line]
+inline constexpr int kLexWeightDoc = 2
+struct CandidateProvenance
+inline std::vector<float> lexicalScoresNameExact( const IngestResult& ing, std::string_view query )
+std::optional<int> runEvalViews( const MainDispatch& d )
+inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i )
+struct RecallSectionPick
+inline double binomialChoose( std::size_t n, std::size_t k )
+… [146 more display lines; full output is 21536 bytes on 18 raw line(s)]
+`````
+
+## `./build/ripwire . --for="why does src/lexical.h chooseForRanker pick name-exact BM25" --no-mention-boost`
+
+*Same task with the anchor disabled — the contrast the flag exists for.*
+
+**wall time: 4.14s**
+
+`````
+
+
+
+
+The name-exact ranker AS THE RETRIEVAL LENS SERVES IT: whole-name BM25 plus the definition-over-…inline std::vector<float> lexicalScoresNameExactRanked( const IngestResult& ing, std::string_view query, const std::vector<float>* symbolScoreMul )
+
+P11.12: the interpretive footer for --eval's ranker table, pulled into its own function so the 9…inline void printEvalRankerNote()
+inline int runEvalRetrieval( const IngestResult& ing, const Graph& g )
+
+calling agent knows to reformulate rather than trust the ranking. Calibrated empirically (2026-0…inline constexpr float kWeakLexicalScoreThreshold = 1.0f
+inline std::string candidatesRootTag( std::size_t keep, std::size_t corpusCount, const CandidateProvenance& prov )
+inline std::vector<float> lexicalScoresNameExactTiered( const IngestResult& ing, std::string_view query, const std::vector<float>* symbolScoreMul )
+inline int runEvalMined( const std::string& root, const IngestResult& ing, const Graph& g, const std::string& path )
+struct NameCorpusStats
+inline int runEvalSkills( const std::string& root, const IngestResult& ing, const Graph& g, const std::string& labelsPath )
+inline bool hasIdentifierShape( std::string_view w ) noexcept
+struct LensRanking
+struct Bm25Params
+inline RouteChoice chooseForRanker( const IngestResult& ing, std::string_view query )
+inline double bm25ImpactBound( double idf, double T, const Bm25Params& p ) noexcept
+inline int runEval( const std::string& root, const IngestResult& ing, const Graph& g, const std::vector<char>& currentDiff )
+rw::LensRanking computeLensRanking( const MainDispatch& d, std::string_view task, bool compactCandidate = false, bool fullDistribution = false ) // deep-tail: the file-grain tail rea … [line truncated: 65 more bytes on this line]
+inline constexpr int kLexWeightDoc = 2
+struct CandidateProvenance
+inline std::vector<float> lexicalScoresNameExact( const IngestResult& ing, std::string_view query )
+std::optional<int> runEvalViews( const MainDispatch& d )
+inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i )
+struct RecallSectionPick
+inline double binomialChoose( std::size_t n, std::size_t k )
+… [156 more display lines; full output is 21827 bytes on 18 raw line(s)]
+`````
+
+## `./build/ripwire . --lego=Vehicle`
+
+*Interface -> implementors view: every existing impl of the named interface; the method contract is extracted for the C-family/Java/TS/Python tiers — for a Rust trait (this fixture) it discloses caveat="not-extracted-for-lang" rather than an empty list.*
+
+**wall time: 1.30s**
+
+`````
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --exemplar="format byte sizes for humans"`
+
+*The repo's best-in-class instance to imitate before writing new code (picked by ROLE).*
+
+**wall time: 2.58s**
+
+`````
+
+
+
+
+
+`````
+
+## `./build/ripwire . --help-task="calls(runDefaultMap, rankGraphTeleport)"`
+
+*Deterministic enhanced help: a closed claim in the task is a structured shape, so the router recommends the ONE command that answers it (--verify) with the evidence behind the pick. Advice only — nothing executes.*
+
+**wall time: 2.10s**
+
+`````
+
+
+
+
+ripwire '.' --verify='calls(runDefaultMap, rankGraphTeleport)'
+
+
+`````
+
+## `./build/ripwire . --help-task="write a cheerful release announcement"`
+
+*The honest half of the contract: a task with no ripwire-shaped evidence ABSTAINS with zero commands rather than guessing.*
+
+**wall time: 2.94s**
+
+`````
+
+
+
+
+`````
+
+## `./build/ripwire . --recall="quality delta gating exit codes"`
+
+*Most relevant DOCS' full bodies (markdown only) — recall what is already written down.*
+
+**wall time: 1.28s**
+
+`````
+ripwire recall — "quality delta gating exit codes" — 122 relevant of 270 document files, best-first — total=122 shown=8 capped=1 truncated=6 generated_demoted=3 max_tokens=8000 share_bytes=2468 est_tokens=4165
+
+━━ README.md (relevance 8.093) ━━ [sections: 2 of 25 selected (60 in doc), section-granular; whole doc 222723 B; lines="2747-2759,2760-2767"; dropped_by_budget=23]
+#### 6.2 Exit codes
+
+This is the part to wire into a script.
+
+| Code | Meaning |
+| --- | --- |
+| 0 | The command completed. |
+| 1 | The command refused the request. A refusal names the reason on stderr. When `--callers`, `--callees`, `--uses`, `--impact` or `--path` refuse a selector that matches no indexed definition, they also print an answer on stdout: the verb's element with `found="0"` and the name to retry with. |
+| 2 | A policy gate fired: `--arch` found a layering violation, `--scan-skill` found a CRITICAL, `--quality-delta` found new debt. |
+| 3 | The output exceeded the token budget that you set. |
+| 4 | `--test-gate` found an open obligation. |
+| 5 | The memory guard stopped the run: over `--max-memory` (default 65% of the machine's memory) with no partial answer possible, or a verb other than the default map facing a partial index. One stderr line names the limit and the override. |
+
+#### 6.3 JSON output
+
+`--json` emits JSON instead of XML, with keys mirroring the XML attribute names one to one. It is an
+allow-list: the default map, `--for`, `--pack-task`, `--callers`, `--callees`, `--impact`,
+`--quality-delta`, `--test-gate`, `--metrics`, and `--plan-lanes`, which is JSON-native. Every other
+verb refuses on stderr with exit 1 rather than silently falling back to XML, so a verb added tomorrow
+refuses by default.
+
+
+
+━━ CHANGELOG.md (relevance 7.518) ━━ [sections: 1 of 109 selected (451 in doc), section-granular; whole doc 998064 B; lines="558-579"; dropped_by_budget=108] [truncated: 2264 of 3826 bytes]
+### Changed — `--quality-delta=A..B` answers the kinds it can under memory pressure, and exits 6 when that answer has no gating row (#387 follow-up)
+
+A tripped memory guard in the range form used to give exit 5 and nothing, so on a large repository a four-file change
+… [114 more lines, 10620 bytes total]
+`````
+
+## `./build/ripwire /aux/kbcorpus --recall="field affinity cache line data layout which fields are read together" --top-k=3 --max-tokens=1200`
+
+*The directory-as-knowledge-base pattern: --recall pointed at a 1353762-byte scratch dir of DUMPED TOOL OUTPUT (a git log, this repo's own generated command reference, --help text, an architecture doc, a fabricated JSON access log) instead of a source repo — no index to build, no daemon.*
+
+`````
+ripwire recall — "field affinity cache line data layout which fields are read together" — 2 relevant of 2 document files, best-first — total=2 shown=1 capped=1 truncated=1 max_tokens=1200 share_bytes=2040 est_tokens=957
+
+━━ commands.md (relevance 10.117) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 589307 B; lines="3838-3842"; dropped_by_budget=163] [truncated: 1865 of 7738 bytes]
+### `--field-affinity[=STRUCT]`
+
+**Answers:** find fields that are read together but declared far apart — the cache-locality lens the CACHE-LOCALITY lens: which fields are READ TOGETHER but declared FAR APART.
+
+Builds a static field CO-ACCESS affinity graph (one observation per indexed C-family function body) and diffs it against the DECLARED field order and 64-byte cache-line geometry, reusing --layout's LP64 offset model. Bare = every aggregate in the repo, ranked by separation cost; =STRUCT narrows the … [line truncated: 1355 more bytes on this line]
+
+(capped: 1 of 2 relevant document files omitted — raise --max-tokens/budget_tokens or narrow the query for 1 more (~2548-byte budget))
+`````
+
+stderr:
+
+`````
+ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pass --no-redact to disable
+`````
+
+## `./build/ripwire . --tree`
+
+*File-by-file orientation map (top symbols per file).*
+
+**wall time: 1.18s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [368 more display lines; full output is 11197 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --html=/aux/map2.html`
+
+*Self-contained HTML force-directed call graph.*
+
+**wall time: 5.02s**
+
+`````
+(empty)
+`````
+
+Artifact written:
+
+`````
+ 156034 /aux/map2.html
+`````
+
+## `./build/ripwire . --order=stable --top-k=5`
+
+*Stable (path/id) emit order — provider KV-cache hits across re-runs.*
+
+**wall time: 1.78s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [67 more display lines; full output is 8298 bytes on 1 raw line(s)]
+`````
+
+
+---
+
+# navigate / answer a question
+
+## `./build/ripwire . --around=rankGraphTeleport`
+
+*Ego graph around one symbol — depth 1 BY DEFAULT now (the root's depth= says so): ~6 KB where the 2-hop neighbourhood is ~64 KB on this repo.*
+
+**wall time: 1.17s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [164 more display lines; full output is 7789 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --around=rankGraphTeleport --around-depth=2`
+
+*The restoring knob: --around-depth=2 brings back the whole 2-hop neighbourhood (depth="2" on the root) — pay for it only when the 1-hop view was not enough.*
+
+**wall time: 1.27s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [1951 more display lines; full output is 53260 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --around=rankGraphTeleport --around-fanout=4`
+
+*The other knob: --around-fanout=4 keeps only the 4 strongest edges per node (default 32) — the same 1-hop depth, a quarter of the rows.*
+
+**wall time: 1.28s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --callers=rankGraphTeleport`
+
+*Who calls SYM (1-hop in-edges).*
+
+**wall time: 1.30s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --callers=rankGraphTeleport --legend=full`
+
+*The same rows under --legend=full: the default is the compact dialect (one compact comment plus schema="ripwire.callers/v1" on the root), and --legend=full restores the prose legend — every row byte and every completeness attribute (counts_floor=, graph_ambiguous=, next=) identical, ~3 KB more legend. Works on EVERY XML verb.*
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --callers=DoesNotExist`
+
+*Unknown-symbol REFUSAL shape (exit 1) with a did-you-mean from real edit distance.*
+
+**exit code: 1** — **wall time: 4.17s**
+
+`````
+
+
+`````
+
+stderr:
+
+`````
+ripwire: --callers symbol not found: DoesNotExist
+`````
+
+## `./build/ripwire . --callees=rankGraphTeleport`
+
+*What SYM calls (1-hop out-edges).*
+
+**wall time: 1.37s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --uses=rankGraphTeleport`
+
+*The resolvable use-sites (call/read/write/import/extends) with file:line; count= is a floor.*
+
+**wall time: 1.59s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --graph-query='and(callers(name("rankGraphTeleport"),2),kind(all,fn))'`
+
+*Composable node-set query: functions within 2 caller-hops of rankGraphTeleport.*
+
+**wall time: 1.60s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [28 more display lines; full output is 3650 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --external-surface`
+
+*Names referenced but never defined in-corpus (stdlib/third-party surface). The root carries names/shown/capped; the default is a 100-row window now, so total= and a pasteable next= join them when it bites (the explicit --limit form carries the same quintet). The sh BUILTINS (cd/echo/set…) are dropped and COUNTED as builtins_excluded= — grep/sed/git stay, they ARE the surface.*
+
+**wall time: 1.28s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [73 more display lines; full output is 5604 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --external-surface --include-builtins`
+
+*The restoring knob: --include-builtins keeps the shell builtins in the same 100-row window (they now compete for rows, so the window's tail differs).*
+
+**wall time: 1.35s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [73 more display lines; full output is 5478 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --path=main,rankGraphTeleport`
+
+*Shortest directed call-path SRC -> DST. CHANGED: now reports from_p/to_p/from_defs and resolves the right `main` (was reachable="0").*
+
+**wall time: 1.34s**
+
+`````
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex`
+
+*Minimal connecting subgraph over 3 symbols (finds shared-caller joins).*
+
+**wall time: 1.71s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --impact=rankGraphTeleport`
+
+*Transitive blast radius — everything that reaches SYM. NOW carries shown/capped.*
+
+**wall time: 2.03s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+… [70 more display lines; full output is 6868 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --mentions=rankGraphTeleport`
+
+*Markdown docs that name SYM in a backtick (doc<->code edges).*
+
+**wall time: 1.52s**
+
+`````
+
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --affected=src/graph.h`
+
+*Test files that transitively reach the changed file.*
+
+**wall time: 1.96s**
+
+`````
+
+
+
+
+
+
+
+
+
+`````
+
+## `./build/ripwire . --situ`
+
+*Mid-task situational report for the current git diff — recorded against a CLEAN tree (contrast with the sandbox run below).*
+
+**wall time: 2.91s**
+
+`````
+ripwire situational-awareness — 0 changed file(s), 0 symbols in them
+root: .
+at: 0712a5182
+ (0 changed files — working tree is clean, nothing to analyze)
+`````
+
+## `./build/ripwire . --test-gate`
+
+*Pre-PR gate on a CLEAN tree: no obligations, exit 0.*
+
+**wall time: 5.28s**
+
+`````
+
+
+`````
+
+## `./build/ripwire . --grep=DISCLOSE`
+
+*Literal trigram-indexed search. Each hit carries its MATCHED line as the element's own CDATA (the wrapper is gone), plus shown/capped/hits_capped and a pasteable next= on the root.*
+
+**wall time: 1.39s**
+
+`````
+
+if data.get( "schema" ) != SCHEMA: raise SystemExit( f"{path}: unexpected schema {data.get('schema')!r} (expecte
+if not str( data.get( "tasks_lock_content_sha256", "" ) ).startswith( "questions:" ): train_repos = select_tasks
+if train_repos: raise SystemExit( f"{path}: records from repo(s) that re-derive to LocBench
+if base and ctx and base["status"] == "ok" and ctx["status"] == "ok": paired.append( ( instance_id, base["re
+if not repos: return 0.0, []
+if base["localization_hit"] is None or ctx["localization_hit"] is None: return 0.0
+if bv: ratios.append( cv / bv - 1 )
+if not ratios: return None, None
+if rw is None or native is None: return None
+if not paired: out["note"] = "zero complete paired (baseline,ripwire_cli) runs — nothing to analyze yet"
+if contaminated: print( f" ** {contaminated} baseline run(s) invoked ripwire despite the no-ripwire contract "
+if "note" in out: print( f" {out['note']}" ); return
+if out["n_pairs"] != 27: failures.append( f"expected 27 paired runs, got {out['n_pairs']}" )
+if out["n_incomplete"] != 2: failures.append( f"expected 2 incomplete pairs (the orphan + the contaminated-basel
+if out["n_repos"] != 3: failures.append( f"expected 3 repos, got {out['n_repos']}" )
+if out.get( "n_contaminated_baseline" ) != 1: failures.append( f"expected exactly 1 contaminated baseline run co
+if not ( out["resolved_delta_mean"] > 0 ): failures.append( "expected a positive resolved-rate delta" )
+if not ( out["resolved_delta_bootstrap_95_lower"] > 0 ): failures.append( "expected a POSITIVE bootstrap 95% low
+if out["tokens_out_ratio_p50"] is None or abs( out["tokens_out_ratio_p50"] - 0.08 ) > 1e-6: failures.append( f"e
+if out.get( "n_resolved_pairs" ) != 27: failures.append( f"expected all 27 pairs resolution-scored, got {out.get
+if out.get( "substitution_rate_baseline" ) != 0.0: failures.append( f"expected baseline substitution rate 0.0 (n
+if out.get( "substitution_rate_ripwire" ) is None or abs( out["substitution_rate_ripwire"] - 0.75 ) > 1e-9: fail
+if out.get( "n_substitution_ripwire" ) != 27: failures.append( f"expected 27 substitution-scored ripwire runs, g
+if out3.get( "substitution_rate_ripwire" ) is not None or out3.get( "n_substitution_ripwire" ) != 0: failures.ap
+if out2["n_pairs"] != 27: failures.append( f"evaluator-none: expected 27 pairs, got {out2['n_pairs']}" )
+if out2["n_resolved_pairs"] != 0: failures.append( f"evaluator-none: expected 0 resolution-scored pairs, got {ou
+if out2["resolved_delta_mean"] is not None or out2["resolved_delta_bootstrap_95_lower"] is not None: failures.ap
+if out2["tokens_out_ratio_p50"] is None or abs( out2["tokens_out_ratio_p50"] - 0.08 ) > 1e-6: failures.append( "
+… [73 more display lines; full output is 16956 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --match='(if_statement) @i'`
+
+*The same shape query WITH an explicit capture — identical hits, no auto_captured= attribute.*
+
+**wall time: 2.10s**
+
+`````
+
+if data.get( "schema" ) != SCHEMA: raise SystemExit( f"{path}: unexpected schema {data.get('schema')!r} (expecte
+if not str( data.get( "tasks_lock_content_sha256", "" ) ).startswith( "questions:" ): train_repos = select_tasks
+if train_repos: raise SystemExit( f"{path}: records from repo(s) that re-derive to LocBench
+if base and ctx and base["status"] == "ok" and ctx["status"] == "ok": paired.append( ( instance_id, base["re
+if not repos: return 0.0, []
+if base["localization_hit"] is None or ctx["localization_hit"] is None: return 0.0
+if bv: ratios.append( cv / bv - 1 )
+if not ratios: return None, None
+if rw is None or native is None: return None
+if not paired: out["note"] = "zero complete paired (baseline,ripwire_cli) runs — nothing to analyze yet"
+if contaminated: print( f" ** {contaminated} baseline run(s) invoked ripwire despite the no-ripwire contract "
+if "note" in out: print( f" {out['note']}" ); return
+if out["n_pairs"] != 27: failures.append( f"expected 27 paired runs, got {out['n_pairs']}" )
+if out["n_incomplete"] != 2: failures.append( f"expected 2 incomplete pairs (the orphan + the contaminated-basel
+if out["n_repos"] != 3: failures.append( f"expected 3 repos, got {out['n_repos']}" )
+if out.get( "n_contaminated_baseline" ) != 1: failures.append( f"expected exactly 1 contaminated baseline run co
+if not ( out["resolved_delta_mean"] > 0 ): failures.append( "expected a positive resolved-rate delta" )
+if not ( out["resolved_delta_bootstrap_95_lower"] > 0 ): failures.append( "expected a POSITIVE bootstrap 95% low
+if out["tokens_out_ratio_p50"] is None or abs( out["tokens_out_ratio_p50"] - 0.08 ) > 1e-6: failures.append( f"e
+if out.get( "n_resolved_pairs" ) != 27: failures.append( f"expected all 27 pairs resolution-scored, got {out.get
+if out.get( "substitution_rate_baseline" ) != 0.0: failures.append( f"expected baseline substitution rate 0.0 (n
+if out.get( "substitution_rate_ripwire" ) is None or abs( out["substitution_rate_ripwire"] - 0.75 ) > 1e-9: fail
+if out.get( "n_substitution_ripwire" ) != 27: failures.append( f"expected 27 substitution-scored ripwire runs, g
+if out3.get( "substitution_rate_ripwire" ) is not None or out3.get( "n_substitution_ripwire" ) != 0: failures.ap
+if out2["n_pairs"] != 27: failures.append( f"evaluator-none: expected 27 pairs, got {out2['n_pairs']}" )
+if out2["n_resolved_pairs"] != 0: failures.append( f"evaluator-none: expected 0 resolution-scored pairs, got {ou
+if out2["resolved_delta_mean"] is not None or out2["resolved_delta_bootstrap_95_lower"] is not None: failures.ap
+if out2["tokens_out_ratio_p50"] is None or abs( out2["tokens_out_ratio_p50"] - 0.08 ) > 1e-6: failures.append( "
+… [73 more display lines; full output is 16840 bytes on 1 raw line(s)]
+`````
+
+## `./build/ripwire . --query="teleport pagerank" --top-k=5`
+
+*Raw BM25 ranking (debug lens; --for is the real verb).*
+
+**wall time: 2.32s**
+
+`````
+
+
+
+
+
+