From 9053923f45514703e0f0ba1fa109c9b3703afed4 Mon Sep 17 00:00:00 2001 From: liziye627-design <232619260+liziye627-design@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:44:42 +0800 Subject: [PATCH 01/21] test(type3clonecheck): rename p2ok to ok so G1 checks it; add write guard and return 0 (#305) --- test/type3clonecheck.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/type3clonecheck.sh b/test/type3clonecheck.sh index 8234ba1e6..8b0bc6291 100755 --- a/test/type3clonecheck.sh +++ b/test/type3clonecheck.sh @@ -89,7 +89,7 @@ BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" [ -x "$BIN" ] || { echo " FAIL PART 2 needs a ripwire binary at $BIN (build first, or set RIPWIRE_BIN)"; exit 2; } p2fail=0 -p2ok(){ printf ' PASS %s\n' "$*"; } +ok(){ printf ' PASS %s\n' "$*" || { p2fail=1; printf ' FAIL could not write the PASS line for: %s\n' "$*"; }; return 0; } p2no(){ printf ' FAIL %s\n' "$*"; p2fail=1; } echo "type3clonecheck: PART 2 (grouping + duplication %) BIN=$BIN" @@ -144,21 +144,21 @@ N="$( cl "$W2/noclone" )" # first. If the detector found no near-miss pairs in grp/, the grouping arms would pass vacuously. t3="$( attr type3 "$G" )" [ "${t3:-0}" -ge 3 ] \ - && p2ok "guard: grp/ yields $t3 Type-3 PAIRS (the grouping arms have something to group)" \ + && ok "guard: grp/ yields $t3 Type-3 PAIRS (the grouping arms have something to group)" \ || p2no "guard: grp/ yielded type3=${t3:-none} — expected >= 3 pairs; the grouping arms would be inert" # ── arm F: every emitted group row carries a gid= ──────────────────────────────────────────────────── rows="$( printf '%s' "$G" | grep -oE ']*>' | wc -l | tr -d ' ' )" gids="$( printf '%s' "$G" | grep -oE ']*>' | grep -cE 'gid="[0-9]+"' | tr -d ' ' )" [ "$rows" -gt 0 ] && [ "$rows" = "$gids" ] \ - && p2ok "arm F: all $rows group rows carry gid=" \ + && ok "arm F: all $rows group rows carry gid=" \ || p2no "arm F: $gids of $rows group rows carry gid=" # ── arm G: UNION-FIND — three mutually-similar bodies collapse to ONE group id, not three ──────────── distinct="$( printf '%s' "$G" | grep -oE 'gid="[0-9]+"' | sort -u | wc -l | tr -d ' ' )" cg="$( attr clone_groups "$G" )" if [ "$distinct" = 1 ] && [ "$cg" = 1 ]; then - p2ok "arm G: $t3 pairs over three mutual near-copies collapse to ONE component (clone_groups=1, 1 distinct gid)" + ok "arm G: $t3 pairs over three mutual near-copies collapse to ONE component (clone_groups=1, 1 distinct gid)" else p2no "arm G: expected 1 component, got clone_groups=${cg:-absent} with $distinct distinct gid values over $t3 pairs" fi @@ -172,24 +172,24 @@ cp "$W2/dupexact/two.py" "$W2/two/pairA.py" T="$( cl "$W2/two" )" cg2="$( attr clone_groups "$T" )" [ "$cg2" = 2 ] \ - && p2ok "arm G-mut: two independent clone relations report clone_groups=2 (grouping discriminates)" \ + && ok "arm G-mut: two independent clone relations report clone_groups=2 (grouping discriminates)" \ || p2no "arm G-mut: two independent clone relations reported clone_groups=${cg2:-absent}, expected 2" # ── arm H: the duplication percentage, computed by hand on dupexact/ ───────────────────────────────── dl="$( attr dup_loc "$D" )"; tl="$( attr total_loc "$D" )"; dp="$( attr dup_pct "$D" )" if [ -n "$dl" ] && [ -n "$tl" ] && [ "${tl:-0}" -gt 0 ] && [ "$(( dl * 2 ))" = "$tl" ]; then - p2ok "arm H1: two identical equal-LOC bodies ⇒ dup_loc($dl) is exactly half of total_loc($tl)" + ok "arm H1: two identical equal-LOC bodies ⇒ dup_loc($dl) is exactly half of total_loc($tl)" else p2no "arm H1: dup_loc=${dl:-absent} total_loc=${tl:-absent} — expected dup_loc*2 == total_loc" fi [ "$dp" = "50.0" ] \ - && p2ok "arm H2: dup_pct=50.0 on the hand-computed corpus" \ + && ok "arm H2: dup_pct=50.0 on the hand-computed corpus" \ || p2no "arm H2: dup_pct=${dp:-absent}, expected 50.0" # ── arm I: a corpus with no clones reports a REAL zero (none found), not an absent attribute ───────── ndl="$( attr dup_loc "$N" )"; ndp="$( attr dup_pct "$N" )"; ncg="$( attr clone_groups "$N" )" if [ "$ndl" = 0 ] && [ "$ndp" = "0.0" ] && [ "$ncg" = 0 ]; then - p2ok "arm I: a clone-free corpus reports dup_loc=0 dup_pct=0.0 clone_groups=0 (none found, stated)" + ok "arm I: a clone-free corpus reports dup_loc=0 dup_pct=0.0 clone_groups=0 (none found, stated)" else p2no "arm I: clone-free corpus reported dup_loc=${ndl:-absent} dup_pct=${ndp:-absent} clone_groups=${ncg:-absent}" fi @@ -204,10 +204,10 @@ fi if printf '%s' "$G" | grep -qE ']*(counts_floor|type3_capped)='; then p2no "arm J1: counts_floor=/type3_capped= on a run whose Type-3 pair cap did NOT fire — a floor claim with nothing dropped" else - p2ok "arm J1: no counts_floor=/type3_capped= when the pair cap did not fire (the counts are not floors on this run)" + ok "arm J1: no counts_floor=/type3_capped= when the pair cap did not fire (the counts are not floors on this run)" fi printf '%s' "$G" | grep -q 'dup_pct=duplicated-LOC' \ - && p2ok "arm J2: the legend DEFINES dup_pct (numerator, denominator and the per-group counting rule)" \ + && ok "arm J2: the legend DEFINES dup_pct (numerator, denominator and the per-group counting rule)" \ || p2no "arm J2: the legend does not define dup_pct" # ── arm K: determinism + well-formedness of the extended output ────────────────────────────────────── @@ -215,12 +215,12 @@ G2="$( cl "$W2/grp" )" if [ -z "$G" ]; then p2no "arm K1: EMPTY --clones output — vacuously identical, not deterministic" elif [ "$G" = "$G2" ]; then - p2ok "arm K1: two --clones runs byte-identical (determinism)" + ok "arm K1: two --clones runs byte-identical (determinism)" else p2no "arm K1: two --clones runs DIFFER" fi if command -v xmllint >/dev/null 2>&1; then - printf '%s' "$G" | xmllint --noout - 2>"$W2/xl" && p2ok "arm K2: extended --clones output is well-formed XML" \ + printf '%s' "$G" | xmllint --noout - 2>"$W2/xl" && ok "arm K2: extended --clones output is well-formed XML" \ || { p2no "arm K2: xmllint rejected the extended output"; sed 's/^/ /' "$W2/xl" | head -3; } else p2no "arm K2: xmllint missing — cannot verify well-formedness (install libxml2-utils)" From 84fe66c84428a340dc7934ace644c724d2e45e95 Mon Sep 17 00:00:00 2001 From: llvm-x86 Date: Sun, 25 Oct 2026 11:12:48 -0500 Subject: [PATCH 02/21] fix(quality): keep Django and unittest hooks out of the dead-code list (#228) Framework hooks (setUp, tearDown, setUpClass, tearDownClass, setUpTestData, setUpModule, tearDownModule, load_tests) and test* methods in test modules are live. Closures that call self. or cls. keep the overrides of their class live. kQSnapCacheScheme moves from 22 to 23. The tripwire pin follows. Co-Authored-By: Claude --- changelog.d/228-django-unittest-hooks.md | 16 +++ changelog.d/versions.md | 2 +- src/langfacts.h | 6 +- src/quality.h | 154 ++++++++++++++++++----- test/qschemetrip.hash | 2 +- test/qschemetripcheck.sh | 2 + test/qualitycheck.sh | 139 ++++++++++++++++++++ 7 files changed, 290 insertions(+), 31 deletions(-) create mode 100644 changelog.d/228-django-unittest-hooks.md diff --git a/changelog.d/228-django-unittest-hooks.md b/changelog.d/228-django-unittest-hooks.md new file mode 100644 index 000000000..05c75fd97 --- /dev/null +++ b/changelog.d/228-django-unittest-hooks.md @@ -0,0 +1,16 @@ +### Fixed — Django and unittest hooks no longer read as dead code + +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. A `test*` +method (any name that starts with `test`) counts 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 23. Old cached snapshots are not used. + +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 da0136758..c0554e5b9 100644 --- a/changelog.d/versions.md +++ b/changelog.d/versions.md @@ -7,4 +7,4 @@ Python rebind-withholding records a 224 placeholder on theirs; 226 sits above ev (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 (`&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=2259c5025ac90271 entries=930`. +quality-snapshot scheme moves 22 → 23 (#228: Django and unittest hooks and closure self-dispatch change the dead set; old snapshots are not used). The session legend dictionary is `dictv=2259c5025ac90271 entries=930`. diff --git a/src/langfacts.h b/src/langfacts.h index bd9713a39..2426da3c7 100644 --- a/src/langfacts.h +++ b/src/langfacts.h @@ -116,6 +116,10 @@ struct LangFacts /// open too (ifacedispatch.h). A Kotlin-only tree is unchanged. bool samFromJavaLambdas = false; + /// Python: unittest and Django call setUp, tearDown and the other test-framework hooks themselves, and a closure inside a method + /// can call `self.hook()` for its host (quality.h pythonFrameworkInvokedSymbol, pythonReceiverScope; the dead-code set reads both). + bool frameworkEntryHooks = false; + /// Kotlin: an `interface` is a class_declaration like a class (queries/kotlin/tags.scm: "both land here as @definition.class"), /// so the symbol's kind cannot tell the two apart; shared code that needs an interface (ifacedispatch.h's lambda test) reads a /// class of such a language as a possible one. @@ -182,7 +186,7 @@ inline constexpr std::array kJavaObjectMethods = { "equals" inline constexpr std::array kLangFacts = { { { .lang = Lang::Cpp, .defectShapeNeedsMacroSet = true, .noNestedNamedFunctions = true, .memberSeparator = "::", .transitiveIncludes = true }, - { .lang = Lang::Python, .baseImportEvidence = BaseImportEvidence::PythonImport }, + { .lang = Lang::Python, .frameworkEntryHooks = true, .baseImportEvidence = BaseImportEvidence::PythonImport }, { .lang = Lang::TypeScript, .overloadSignatures = true, .structuralTyping = true, .importBoundConstruction = true, .baseImportEvidence = BaseImportEvidence::JsImport, .writtenBindingUndecided = true }, { .lang = Lang::Go, .structuralTyping = true }, diff --git a/src/quality.h b/src/quality.h index 9c45885c6..4356b96c4 100644 --- a/src/quality.h +++ b/src/quality.h @@ -818,6 +818,33 @@ inline bool languageInvokedSymbol( const Symbol& s ) noexcept return false; } +// Python test-framework entry points (#228). unittest and Django's TestCase call setUp/tearDown/setUpClass/ +// tearDownClass/setUpTestData around tests, setUpModule/tearDownModule/load_tests around a module, runTest/asyncSetUp/asyncTearDown, and run every +// test* method as a test. Pytest runs test_* too. No call in the indexed tree names them, so zero in-edges says +// nothing. Name-level, like the dunder rule in languageInvokedSymbol: errs toward live. The test* clause also +// needs a test module (isTestPath, or Django's tests.py), so a helper named testSomething in application code +// still reads as dead. +inline bool pythonFrameworkInvokedSymbol( const Symbol& s, std::string_view p ) noexcept +{ + if( !langFacts( s.lang ).frameworkEntryHooks || ( s.kind != SymKind::Method && s.kind != SymKind::Function ) ) + { + return false; + } + const std::string_view n = s.name; + if( n == "setUp" || n == "tearDown" || n == "setUpClass" || n == "tearDownClass" || n == "setUpTestData" + || n == "setUpModule" || n == "tearDownModule" || n == "load_tests" || n == "runTest" || n == "asyncSetUp" || n == "asyncTearDown" ) + { + return true; + } + if( n.substr( 0, 4 ) != "test" ) + { + return false; + } + const std::size_t sl = p.rfind( '/' ); + const std::string_view fn = sl == std::string_view::npos ? p : p.substr( sl + 1 ); + return isTestPath( p ) || fn == "tests.py"; +} + // A "dead deletion-candidate": has a body, no caller in the indexed tree, not invoked from file scope, not // invoked by the LANGUAGE itself (languageInvokedSymbol, above), not a test fixture, not produced by a // registered self-registering macro. A SIMPLE, @@ -865,6 +892,10 @@ inline bool isDeadCandidate( const IngestResult& ing, const Graph& g, NodeId i, return false; // Q-DIAL-2: the LANGUAGE calls it — see languageInvokedSymbol (this replaced a blanket header exclusion) } const std::string_view p = rootRelPath( ing, s.fileId ); // #228: a directory above the root never decides this + if( pythonFrameworkInvokedSymbol( s, p ) ) + { + return false; // #228: unittest/Django/pytest call this by protocol (see pythonFrameworkInvokedSymbol) + } if( isFixturePath( p ) ) { return false; // fixtures are dead by design (noise rules) @@ -1204,8 +1235,29 @@ inline void forEachSymbolBody( const IngestResult& ing, Fn&& visit ) } } -// Direct Python class members only; module-level and nested functions have no class owner. -inline std::vector pythonMethodOwners( const IngestResult& ing ) +// Direct Python class members get an owner: the enclosing class. A def nested inside a method gets a host: the +// nearest enclosing method, whose self/cls it reads as a free variable. Module-level functions have neither. +struct PythonScopes +{ + std::vector owner; + std::vector host; +}; + +// Records one definition's enclosing scope: a class makes it a direct member; a method, or a closure in one, makes +// the nearest method its host. +inline void pythonRecordParent( PythonScopes& scopes, const IngestResult& ing, NodeId id, NodeId parent ) noexcept +{ + if( ing.symbols[parent].kind != SymKind::Class ) + { + scopes.host[id] = scopes.owner[parent] != kNoNode ? parent : scopes.host[parent]; + } + else if( ing.symbols[id].kind != SymKind::Class ) + { + scopes.owner[id] = parent; + } +} + +inline PythonScopes pythonMethodOwners( const IngestResult& ing ) { const bool hasClasses = std::any_of( ing.symbols.begin(), ing.symbols.end(), []( const Symbol& s ) { @@ -1215,7 +1267,9 @@ inline std::vector pythonMethodOwners( const IngestResult& ing ) { return {}; } - std::vector owner( ing.symbols.size(), kNoNode ); + PythonScopes scopes; + scopes.owner.assign( ing.symbols.size(), kNoNode ); + scopes.host.assign( ing.symbols.size(), kNoNode ); SymbolsByFile byFile = symbolsByFileInIdOrder( ing, []( const Symbol& s ) { return s.lang == Lang::Python && ( s.kind == SymKind::Class || s.kind == SymKind::Function || s.kind == SymKind::Method ); @@ -1240,50 +1294,85 @@ inline std::vector pythonMethodOwners( const IngestResult& ing ) { parents.pop_back(); } - if( s.kind != SymKind::Class && !parents.empty() && ing.symbols[parents.back()].kind == SymKind::Class ) + if( !parents.empty() ) { - owner[id] = parents.back(); + pythonRecordParent( scopes, ing, id, parents.back() ); } parents.push_back( id ); } } - return owner; + return scopes; } -// Python VarDecl bindings are parameter names in source order (emitBindings); the first one -// identifies the conventional receiver. Reuse those AST facts, including commented/typed parameters. -// A non-receiver first parameter is marked 3 so a later parameter named cls cannot replace it. -inline std::vector pythonReceiverParameters( const IngestResult& ing ) +// The conventional receiver of each Python def and the receiver names it binds as parameters. Parameters are +// VarDecl bindings in source order (emitBindings). kind: 1 self, 2 cls, 3 a first parameter that is neither, 0 none; +// the first parameter decides it, so a later parameter named cls cannot replace it. bound: bit 1 self, bit 2 cls, +// wherever the name sits in the list. +struct PythonReceivers { - std::vector receiver( ing.symbols.size(), 0 ); + std::vector kind; + std::vector bound; +}; + +inline PythonReceivers pythonReceiverParameters( const IngestResult& ing ) +{ + PythonReceivers receivers; + receivers.kind.assign( ing.symbols.size(), 0 ); + receivers.bound.assign( ing.symbols.size(), 0 ); for( const Binding& b : ing.bindings ) { - if( b.fromSymbol >= receiver.size() || ing.symbols[b.fromSymbol].lang != Lang::Python - || b.kind != LocalBindKind::VarDecl || b.spanStart != 0 || b.spanEnd != 0 || receiver[b.fromSymbol] != 0 ) + if( b.fromSymbol >= receivers.kind.size() || !langFacts( ing.symbols[b.fromSymbol].lang ).frameworkEntryHooks + || b.kind != LocalBindKind::VarDecl || b.spanStart != 0 || b.spanEnd != 0 ) { continue; } - receiver[b.fromSymbol] = b.var == "self" ? 1 : b.var == "cls" ? 2 : 3; + const std::uint8_t name = b.var == "self" ? 1 : b.var == "cls" ? 2 : 0; + receivers.bound[ b.fromSymbol ] |= name; + if( receivers.kind[ b.fromSymbol ] == 0 ) + { + receivers.kind[ b.fromSymbol ] = name != 0 ? name : 3; + } } - return receiver; + return receivers; } -// Deduplicate receiver-call evidence before walking inheritance; repeated call sites have the same -// possible targets. Views borrow the ingested reference names for this one snapshot computation. +// The method whose receiver a self./cls. call reads, or kNoNode. A method reads its own receiver. A closure nested +// in a method reads the enclosing method's, unless the closure binds that receiver name itself. The method's receiver +// must be the conventional one: self for ThisObj, cls for the NamedVar cls. +inline NodeId pythonReceiverScope( const PythonScopes& scopes, const PythonReceivers& receivers, const Reference& r ) noexcept +{ + const std::uint8_t want = r.recv == RecvKind::ThisObj ? 1 : 2; + NodeId scope = kNoNode; + if( scopes.owner[ r.fromSymbol ] != kNoNode ) + { + scope = r.fromSymbol; + } + else if( scopes.host[ r.fromSymbol ] != kNoNode && ( receivers.bound[ r.fromSymbol ] & want ) == 0 ) + { + scope = scopes.host[ r.fromSymbol ]; + } + return scope != kNoNode && receivers.kind[ scope ] == want ? scope : kNoNode; +} + +// Deduplicate receiver-call evidence before walking inheritance; repeated call sites have the same possible targets. +// Views borrow the ingested reference names for this one snapshot computation. inline std::vector> pythonDispatchRequests( const IngestResult& ing, - std::span owner, std::span receiver ) + const PythonScopes& scopes, const PythonReceivers& receivers ) { std::vector> requests; for( const Reference& r : ing.references ) { - if( r.lang != Lang::Python || r.role != RefRole::Call || r.fromSymbol >= owner.size() - || owner[r.fromSymbol] == kNoNode || !r.qualifier.empty() - || !( ( r.recv == RecvKind::ThisObj && receiver[r.fromSymbol] == 1 ) - || ( r.recv == RecvKind::NamedVar && r.recvVar == "cls" && receiver[r.fromSymbol] == 2 ) ) ) + const bool selfOrCls = r.recv == RecvKind::ThisObj || ( r.recv == RecvKind::NamedVar && r.recvVar == "cls" ); + if( !langFacts( r.lang ).frameworkEntryHooks || r.role != RefRole::Call || r.fromSymbol >= scopes.owner.size() + || !r.qualifier.empty() || !selfOrCls ) { continue; } - requests.emplace_back( owner[r.fromSymbol], r.calleeName ); + const NodeId scope = pythonReceiverScope( scopes, receivers, r ); + if( scope != kNoNode ) + { + requests.emplace_back( scopes.owner[ scope ], r.calleeName ); + } } std::sort( requests.begin(), requests.end(), []( const auto& a, const auto& b ) { @@ -1311,11 +1400,12 @@ inline std::vector pythonDispatchClasses( const Graph& g, NodeId base ) // This is conservative liveness, not a model of Python's MRO, descriptors, or monkey-patching. inline std::vector pythonDispatchedMethodIds( const IngestResult& ing, const Graph& g ) { - const std::vector owner = pythonMethodOwners( ing ); - if( owner.empty() ) + const PythonScopes scopes = pythonMethodOwners( ing ); + if( scopes.owner.empty() ) { return {}; } + const std::vector& owner = scopes.owner; HashMap> methods; methods.reserve( 32 ); for( NodeId i = 0; i < owner.size(); ++i ) @@ -1325,9 +1415,9 @@ inline std::vector pythonDispatchedMethodIds( const IngestResult& ing, c methods[ owner[i] ].push_back( i ); } } - const std::vector receiver = pythonReceiverParameters( ing ); + const PythonReceivers receivers = pythonReceiverParameters( ing ); std::vector result; - for( const auto& [ base, name ] : pythonDispatchRequests( ing, owner, receiver ) ) + for( const auto& [ base, name ] : pythonDispatchRequests( ing, scopes, receivers ) ) { for( NodeId id : pythonDispatchClasses( g, base ) ) { @@ -3520,6 +3610,9 @@ inline void evictOldHeadSnapCaches( const std::string& dir, const std::string& r // pythonDispatchClasses (quality.h) — downward-only inheritance reachability // pythonDispatchedMethodIds (quality.h) — Python inherited receiver-call evidence for the dead set // isDeadCandidate (quality.h) — the dead-set predicate itself +// pythonFrameworkInvokedSymbol (quality.h) — the framework-hook exemption isDeadCandidate calls into (#228) +// pythonRecordParent (quality.h) — fills the closure host and owner that pythonReceiverScope reads (#228) +// pythonReceiverScope (quality.h) — which method a self./cls. call in a closure belongs to (#228) // isFixturePath (quality.h) — a fixture-path exemption isDeadCandidate calls into // isTestScriptPath (quality.h) — the test-script exemption isDeadCandidate calls into (the exact // helper B10.1a added without a bump — the finding this guards) @@ -3657,7 +3750,12 @@ inline void evictOldHeadSnapCaches( const std::string& dir, const std::string& r // the standard-member gate gained a Rust row (graph.h kStdMemberNames), so a Rust definition a DECLINED call could have meant is // no dead candidate (Graph::gateDeclinedTarget), as v15 did for the builtin-method gate. No extraction change: kParserVer and its // mirror stay. The producer identity already keeps this build's blobs apart; bumped 21 -> 22 so the history above stays complete. -constexpr std::uint32_t kQSnapCacheScheme = 22; +// v23 (2026-10-24, #228: Django/unittest hooks and closure dispatch) — no blob shape change; the dead SET's inputs moved. +// isDeadCandidate exempts Python framework entry points (pythonFrameworkInvokedSymbol: setUp, tearDown, setUpClass, +// tearDownClass, setUpTestData, setUpModule, tearDownModule, load_tests, and test* methods in test modules), and +// pythonDispatchedMethodIds keeps a self./cls. call inside a closure nested in a method live: the overrides of the called name on that method's class and its subclasses. +// The producer identity already keeps this build's blobs apart; bumped 22 -> 23 so the history above stays complete. +constexpr std::uint32_t kQSnapCacheScheme = 23; constexpr char kQSnapMagic[4] = { 'Q', 'S', 'N', 'P' }; // The qsnap EXCLUDES-config key folds the qsnap SCHEME (independent of the ingest cache's kHeadSnapCacheScheme) diff --git a/test/qschemetrip.hash b/test/qschemetrip.hash index 1db263ca9..eff1e2d0e 100644 --- a/test/qschemetrip.hash +++ b/test/qschemetrip.hash @@ -1 +1 @@ -ec5455c6c9bcf87e8a617d937aa6fc94c039111cd7ae573b813e059b451ca188 +e051955190a03bb5e87b5236fd2b31e2becdf89a8f395706057ee2c60661da9d diff --git a/test/qschemetripcheck.sh b/test/qschemetripcheck.sh index 9afaaf79d..e6f34481e 100755 --- a/test/qschemetripcheck.sh +++ b/test/qschemetripcheck.sh @@ -34,6 +34,8 @@ SRC="$ROOT/src/quality.h" ING="$ROOT/src/ingest_cache.h" # extraction-identity constants moved here (2026-08-29 ingest.cpp section split); the hashed CONCAT label keeps its historical spelling so the pin holds PIN="$ROOT/test/qschemetrip.hash" # RE-PIN LOG (the pin is a bare hash, so its justification has to live here). +# 2026-10-24, #228 (Django/unittest hooks, closure self-dispatch): RE-PINNED with UPDATE_GOLDEN=1 after isDeadCandidate gained +# pythonFrameworkInvokedSymbol and pythonMethodOwners / pythonDispatchRequests gained the closure host. kQSnapCacheScheme 22 -> 23. # 2026-10-24, train 34 (lean2b, fc2-lego-extparent, honest-lex, ind4b-k5-tighten-k5c, hop1, fc3-js-rebind merged onto main # 7abad955): RE-DERIVED ONCE with UPDATE_GOLDEN=1 on the merged tree (3e88ca157f…36842 -> ec5455c6c9…ca188). Watched text: # kParserVer 224 -> 226 (rich file tag 227; above main / #432 224 / 225, lane ind4b's placeholder 224, lane ind5-glob-imports diff --git a/test/qualitycheck.sh b/test/qualitycheck.sh index b9b011701..c9c99af34 100755 --- a/test/qualitycheck.sh +++ b/test/qualitycheck.sh @@ -463,6 +463,145 @@ else no "Python inherited self/cls hooks were classified dead or the orphan was hidden" fi +# Python test-framework hooks (#228): unittest and Django call setUp/tearDown/setUpClass/setUpTestData and +# test_* methods by protocol, so the call graph never sees them. Closures inside a method reach the method's +# self/cls as a free variable. Both must stay live. The orphans are the sensitivity control: the arm must +# still see real dead code in the same tree. +if python3 - "$BIN" "$WORK/django-hooks" <<'PYHOOKS' +import pathlib +import subprocess +import sys +import xml.etree.ElementTree as ET + +binary, directory = sys.argv[1:] +root = pathlib.Path(directory) +root.mkdir() + +def git(*args): + return subprocess.run(["git", "-c", "user.name=Fixture", "-c", "user.email=fixture@example.invalid", + "-c", "core.hooksPath=/dev/null", *args], cwd=root, + check=True, capture_output=True, text=True) + +def run(*args): + return subprocess.run([binary, ".", *args, "--no-cache"], cwd=root, text=True, capture_output=True) + +def dead_rows(result): + assert result.returncode in (0, 2), result.stderr + return sorted(row.attrib["sym"] for row in ET.fromstring(result.stdout).findall("r") + if row.attrib["kind"] == "dead-code") + +(root / "app.py").write_text("def main():\n return 0\n") +git("init", "-q") +git("add", ".") +git("commit", "-qm", "application only") + +(root / "tests").mkdir() +(root / "tests/__init__.py").write_text("") +(root / "tests/base_case.py").write_text("""from django.test import TestCase + + +class BaseCase(TestCase): + @classmethod + def setUpTestData(cls): + def inner(): + return cls.make_shared() + cls.shared = inner() + + @classmethod + def make_shared(cls): + return 1 + + @classmethod + def setUpClass(cls): + super().setUpClass() + + def setUp(self): + self.value = self.make_value() + + def make_value(self): + return 2 + + def tearDown(self): + pass + + def test_thing(self): + self.run_closure() + return self.value + + def testCamel(self): + return 3 + + def run_closure(self): + def inner(): + return self.closure_hook() + return inner() + + def closure_hook(self): + return 4 + + def never_called(self): + return 5 + + +def unused_helper(): + return 6 +""") +(root / "tests/test_fw.py").write_text("""from tests.base_case import BaseCase + + +class FwCase(BaseCase): + @classmethod + def make_shared(cls): + return 9 + + def setUp(self): + super().setUp() + + def make_value(self): + return 7 + + def closure_hook(self): + return 8 +""") +(root / "checks").mkdir() +(root / "checks/tests.py").write_text("""from django.test import TestCase + + +class ChecksTests(TestCase): + def setUp(self): + self.ready = True + + def test_one(self): + return self.ready + + def testlower(self): + return 1 + + def runTest(self): + return 2 + + async def asyncSetUp(self): + return 3 + + async def asyncTearDown(self): + return 4 +""") +git("add", ".") +git("commit", "-qm", "django hooks") + +# Framework hooks, the closure dispatch, and the subclass overrides must not be dead. The two orphans +# (never_called, unused_helper) are the control: the arm must still see real dead code in this shape. +rows = dead_rows(run("--quality-delta=HEAD~1..HEAD")) +expected = sorted(["tests/base_case.py::BaseCase::never_called", "unused_helper"]) +assert rows == expected, rows +print("django hooks and closure dispatch stay live; the two orphans gate") +PYHOOKS +then + ok "Django/unittest hooks (setUp, setUpTestData, test_*) and closure self-dispatch are not dead" +else + no "Django/unittest hooks or closure self-dispatch classified dead (#228)" +fi + # ── (U) THE UNCHANGED-TREE INVARIANT — a no-op diff must never gate (issue #228, part 1) ────────────────── # # THE CONTRACT: a working tree whose TRACKED files are identical to HEAD reports regressions="0" gating="0" From 3d70c98482f5ea5fff794c52c0134dd31effebb4 Mon Sep 17 00:00:00 2001 From: llvm-x86 Date: Sat, 24 Oct 2026 17:10:20 -0500 Subject: [PATCH 03/21] fix(kotlin): a trailing-lambda scope function never binds a Java method (#155) A Kotlin call to run, let, apply, also or with that has a trailing lambda is the stdlib scope function. FE-A now drops the non-Kotlin candidates for it. An emptied set lands as external= with proof. One new u8 on the call record carries the trailing-lambda fact. kParserVer 228 and kCacheVersion 41 are placeholders above every live value. The qschemetrip re-pin is the next commit. Co-Authored-By: Claude --- changelog.d/155-kotlin-scope-functions.md | 16 + docs/ARCHITECTURE.md | 11 + docs/COMMANDS.md | 809 +- docs/captures/COMMANDS_showcase_2026-10-25.md | 7626 +++++++++++++++++ src/externalnames.h | 20 + src/graph.h | 49 +- src/ingest_cache.h | 16 +- src/ingest_metrics.h | 29 + src/ingest_model.h | 1 + src/ingest_sidecap.h | 4 + src/langfacts.h | 7 +- src/model.h | 4 + src/quality.h | 6 +- test/cachefuzzcheck.sh | 2 +- test/falseedgecheck.sh | 26 +- test/falseedgefix/README.md | 4 + test/falseedgefix/kt/java/jobs/Job.java | 7 + test/falseedgefix/kt/java/lib/Builder.java | 8 + test/falseedgefix/kt/kt/Dispatch.kt | 1 + test/falseedgefix/kt/kt/Scopes.kt | 9 + test/falseedgefix/kt/kt/Use.kt | 7 + test/falseedgefix/ktown/java/jobs/Job.java | 7 + test/falseedgefix/ktown/kt/Task.kt | 11 + test/kotlincheck.sh | 234 + test/pyimportprecisecheck.sh | 4 +- test/qschemetrip.hash | 2 +- 26 files changed, 8472 insertions(+), 448 deletions(-) create mode 100644 changelog.d/155-kotlin-scope-functions.md create mode 100644 docs/captures/COMMANDS_showcase_2026-10-25.md create mode 100644 test/falseedgefix/kt/java/jobs/Job.java create mode 100644 test/falseedgefix/kt/java/lib/Builder.java create mode 100644 test/falseedgefix/kt/kt/Dispatch.kt create mode 100644 test/falseedgefix/kt/kt/Scopes.kt create mode 100644 test/falseedgefix/kt/kt/Use.kt create mode 100644 test/falseedgefix/ktown/java/jobs/Job.java create mode 100644 test/falseedgefix/ktown/kt/Task.kt diff --git a/changelog.d/155-kotlin-scope-functions.md b/changelog.d/155-kotlin-scope-functions.md new file mode 100644 index 000000000..05815240e --- /dev/null +++ b/changelog.d/155-kotlin-scope-functions.md @@ -0,0 +1,16 @@ +### Fixed — Kotlin scope functions no longer bind Java methods + +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. +- Receiver types are not checked. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a7aa2b8c7..4d3f74f65 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -258,6 +258,17 @@ 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). The arm runs +ahead of the receiver gate, so `s.run { }` is decided. Stated floors: no receiver typing (a Kotlin receiver of an +unrelated Java type is not checked); 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 84e4711cd..9562f617c 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-24.md`), trimmed to the first few lines and +Sample output is lifted from a real recorded run (`docs/captures/COMMANDS_showcase_2026-10-25.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,14 +70,14 @@ _Same map, capped to the 5 highest-ranked symbols._ $ ./build/ripwire . --top-k=5 - + - + - + @@ -106,14 +106,14 @@ _The same capped map without its inventory tier: --top-k=5 leaves files out, so $ ./build/ripwire . --top-k=5 --no-inventory - + - + - + @@ -140,10 +140,10 @@ _SHAPE the map to fit ~1500 tokens (binary-search top-K)._ $ ./build/ripwire . --max-tokens=1500 - + - + @@ -211,17 +211,17 @@ STOPS WHEN COMPLETE: the ranked head (: the relevance floor within **Try it** -_Name-shaped query: the router picks name-exact BM25 (header says which/why)._ +_Name-shaped query: the router picks name-exact BM25 (header says which.hy)._ ``` $ ./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=952 +$ ./build/ripwire ./build/sc/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.880) ━━ [sections: 1 of 165 selected (192 in doc), section-granular; whole doc 594792 B; lines="555-580"; dropped_by_budget=164] [truncated: 1854 of 4256 bytes] -#### Pattern: a directory of dumped tool output as a knowledge base +━━ commands.md (relevance 10.054) ━━ [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] +### `--field-affinity[=STRUCT]` -**Answers:** can `--recall` serve as a zero-setup knowledge base over dumped tool output — a -`git log`, an API response dump, a fetched doc, ` --help` text — sitting in a scratch -directory, instead of a source repo? +**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. -Yes, unmodified. `--recall` never distinguishes "a codebase" from any other directory it can -walk: point it at the scratch dir and query it. No index to build, no daemon, no mutable store -between runs — the whole cost is one cold parse. Two conditions decide whether it works at all, -and both are yours, because the file you write is the only thing that sets them: +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] -... [17 more line(s); run it to see the whole thing] +(capped: 1 of 2 relevant document files omitted — raise --max-tokens/budget_tokens or narrow the query for 1 more (~2548-byte budget)) ``` ### `--tree` @@ -628,7 +623,7 @@ _File-by-file orientation map (top symbols per file)._ ``` $ ./build/ripwire . --tree - + @@ -637,7 +632,7 @@ $ ./build/ripwire . --tree - + @@ -662,7 +657,7 @@ A navigation or report verb answers instead of the map, so --html beside one ref _Self-contained HTML force-directed call graph._ ``` -$ ./build/ripwire . --html=/aux/map2.html +$ ./build/ripwire . --html=./build/sc/aux/map2.html (empty) ``` @@ -683,7 +678,7 @@ the flag only sets the initial mode _The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector)._ ``` -$ ./build/ripwire . --html=/aux/map2.html --color-by=community +$ ./build/ripwire . --html=./build/sc/aux/map2.html --color-by=community (empty) ``` @@ -732,14 +727,14 @@ _--no-stable outside --mcp: what the flag does (or says) when there is no stable $ ./build/ripwire . --no-stable --top-k=3 - + - + - + @@ -766,7 +761,7 @@ $ ./build/ripwire . --around=rankGraphTeleport - + @@ -818,18 +813,18 @@ _What SYM calls (1-hop out-edges)._ ``` $ ./build/ripwire . --callees=rankGraphTeleport - - + + - - - - - - + + + + + + ``` @@ -848,15 +843,15 @@ external="1" if SYM has no in-corpus def. file:name or a "::" spelling narrows d **Try it** -_The resolvable use-sites (call/read/write/import/extends) with file:line; count= is a floor._ +_The resolvable use-sites (call/read.rite/import/extends) with file:line; count= is a floor._ ``` $ ./build/ripwire . --uses=rankGraphTeleport - + - - + + @@ -887,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))' - + - + - + @@ -924,12 +919,12 @@ _Names referenced but never defined in-corpus (stdlib/third-party surface). The ``` $ ./build/ripwire . --external-surface - - - - - - + + + + + + @@ -959,12 +954,12 @@ _Shortest directed call-path SRC -> DST. CHANGED: now reports from_p/to_p/from_d ``` $ ./build/ripwire . --path=main,rankGraphTeleport - + - + ``` @@ -981,10 +976,10 @@ _Minimal connecting subgraph over 3 symbols (finds shared-caller joins)._ ``` $ ./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex - + - + @@ -1091,7 +1086,7 @@ _Test files that transitively reach the changed file._ ``` $ ./build/ripwire . --affected=src/graph.h - @@ -1148,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: c97f6f91c +at: e47df2266 (0 changed files — working tree is clean, nothing to analyze) ``` @@ -1166,21 +1161,17 @@ _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] + ``` **Caveats (stated by the binary):** @@ -1202,7 +1193,7 @@ _Pre-PR gate on a CLEAN tree: no obligations, exit 0._ ``` $ ./build/ripwire . --test-gate - ``` @@ -1227,7 +1218,7 @@ _Literal trigram-indexed search. Each hit carries its MATCHED line as the $ ./build/ripwire . --grep=DISCLOSE - + - + - + @@ -1529,7 +1520,7 @@ _Importance-weighted detail: FULL bodies for top-2, signatures for the rest._ ``` $ ./build/ripwire . --for="pagerank power iteration" --detail=2 - + @@ -1564,14 +1555,14 @@ $ ./build/ripwire . --pack-signatures --top-k=10 - + - + - + ... [17 more line(s); run it to see the whole thing] @@ -1595,7 +1586,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)" ); @@ -1626,7 +1617,7 @@ $ ./build/ripwire . --top-k=0 --expand=rankGraphTeleport - + of ; resolved callees. window: shown= total= capped= (capped=1 cut). sibs_capped=/inc_capped=: 1 = cut. est_tokens=: price as emitted (an upper bound under compact). root=: p= relative to it. : that callee matched by name alone (receiver unproven); it does NOT mean the edge is fal … [line truncated: 443 more bytes on this line] -: that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> - + - + - + @@ -1798,9 +1789,9 @@ _File->file dependency graph (god-files, cycles)._ ``` $ ./build/ripwire . --deps - - - + + + @@ -1835,10 +1826,10 @@ _Complexity x recent git churn (maintenance pain)._ $ ./build/ripwire . --hotspots - - + + - + @@ -1863,17 +1854,17 @@ _Token-normalized duplicate bodies._ ``` $ ./build/ripwire . --clones - + - + - + ... [17 more line(s); run it to see the whole thing] @@ -1894,8 +1885,8 @@ _Per-function size ranking, largest Halstead volume/token entropy/lines first ``` $ ./build/ripwire . --biggest-first --limit=8 - - + + @@ -1927,7 +1918,7 @@ _Per function, the non-local MUTABLE state it can reach (transitively), most wri ``` $ ./build/ripwire . --nonlocal-state --limit=8 - @@ -1962,7 +1953,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -1993,17 +1984,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] @@ -2030,13 +2021,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] ``` @@ -2061,7 +2052,7 @@ _Score the naming-* rules against this repo's own rename history: proxy=old/(old ``` $ ./build/ripwire . --naming-calibration - + @@ -2096,9 +2087,9 @@ _The corpus's OWN case-convention vote per (language, kind) group; off-conventio ``` $ ./build/ripwire . --naming-consistency --limit=8 - - - + + + @@ -2133,7 +2124,7 @@ _The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/ ``` $ ./build/ripwire . --lint --naming-locals - + @@ -2168,7 +2159,7 @@ _Functions WITH a doc comment, most name-restating first: c_coeff (high = the co ``` $ ./build/ripwire . --comment-coherence --limit=8 - + @@ -2201,16 +2192,16 @@ _Files that change together in git (hidden coupling)._ ``` $ ./build/ripwire . --cochange - - - + + - - + + - - + + + ... [22 more line(s); run it to see the whole thing] ``` @@ -2233,16 +2224,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] ``` @@ -2259,7 +2250,7 @@ _Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none ``` $ ./build/ripwire . --cochange --cochange-groups - + @@ -2288,19 +2279,19 @@ _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] ``` @@ -2326,11 +2317,11 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - - + @@ -2356,11 +2347,11 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - - + @@ -2382,11 +2373,11 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - - + @@ -2409,7 +2400,7 @@ _Built-in AST checks (c-cast, goto, unsafe-c-fn, ...)._ ``` $ ./build/ripwire . --lint - + @@ -2448,7 +2439,7 @@ $ ./build/ripwire . --lint-catalog a C-style cast — cppcoreguidelines-pro-type-cstyle-cast prefers the explicit static_cast/const_cast/reinterpret_cast a goto statement — cppcoreguidelines-avoid-goto -a do/while loop shape (on Swift, its do/catch block shares the same grammar node and also matches) +a do.hile loop shape (on Swift, its do/catch block shares the same grammar node and also matches) a call to an unbounded C string function (strcpy/strcat/sprintf/gets) a call to a broken hash or cipher (MD5/SHA1/MD4/RC4) a doubly-parenthesized expression — readability-redundant-parentheses @@ -2632,15 +2623,15 @@ _Cluster the call graph into cohesive modules._ ``` $ ./build/ripwire . --communities - + - + - + @@ -2663,7 +2654,7 @@ _Drill into ONE call-graph community by id — the drill= the --communities outp ``` $ ./build/ripwire . --community=0 - ``` @@ -2688,15 +2679,15 @@ _Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels ``` $ ./build/ripwire . --zoom - - + + - - + + - + @@ -2725,15 +2716,15 @@ $ ./build/ripwire . --report # ripwire architecture report -3589 files · 31640 symbols · 29882 edges · 3588 modules (14830 call-graph isolated) +3607 files · 31702 symbols · 29921 edges · 3598 modules (14863 call-graph isolated) Root: `.` -Call-graph isolate provenance: 3951 declaration, 2444 header, 3330 source, 5105 document; 0 connected Louvain singletons +Call-graph isolate provenance: 3961 declaration, 2444 header, 3343 source, 5115 document; 0 connected Louvain singletons -## Modules (call-graph clusters; showing 12 of 3588) -- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1617 symbols -- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 547 symbols +## Modules (call-graph clusters; showing 12 of 3598) +- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1618 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] ``` @@ -2751,7 +2742,7 @@ _Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped._ ``` $ ./build/ripwire . --seams - + @@ -2782,15 +2773,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
9384"] + n102["src
9389"] n103["src/infra
1301"] end subgraph sg1 ["test"] - n104["test
5501"] - n559["test/legochargefix
546"] - n400["test/fixtures/recallpassage
314"] - n944["test/slotjoinfix
175"] - n786["test/ownerhopfix/py/pkg
158"] + n104["test
5507"] + n568["test/legochargefix
546"] + n405["test/fixtures/recallpassage
314"] + n953["test/slotjoinfix
175"] + n795["test/ownerhopfix/py/pkg
158"] n342["test/expandmodefix
151"] n344["test/expandsibsfix
149"] ... [17 more line(s); run it to see the whole thing] @@ -2811,13 +2802,13 @@ _Bus-factor: recency-weighted author ownership per file._ ``` $ ./build/ripwire . --owners - - + + - - - + + + @@ -2842,7 +2833,7 @@ _Internal functions with no caller found in the index — a name-based graph rea ``` $ ./build/ripwire . --dead-code=src - + ``` @@ -2906,8 +2897,8 @@ _The same clean verdict with what it folded printed back: every stale acknowledg ``` $ ./build/ripwire . --quality-delta --show-stale - -, acked. value-ref-excluded=N: internal functions kept off because a table, field or argument in another function or at file scope holds them (matched by name, not a proven call); a floor. at=: commit+dirty+shallow. stale=N: ack ledger rows whose target no longer applies (sa rows); never gating. preexisting-worse=N: regressions on symbols that existed at baseline; they gate when major. new-symbol=N: findings on NEW code; new-symbol rows never gate, except defect-shape format-arity. register-macro-excluded=N: symbols kept out of dead-code as self-registering test/bench macros; a floor. declined-call-excluded=N: symbols kept out of dead-code only because a declined call may mean them; a floor. api-new-surface=N: new PUBLIC symbols; a count, never gates, not in regressions=. renames=/rename_window_commits=: git rename pairs read over that many commits, to re-file baseline and acks. acked_by_rename=/acked_by_content=: acked= suppressions matched via git renames / an equal body hash. renames_window_truncated=1: history is deeper than the rename window, older renames unread. acked=N: findings suppressed by the ack ledger, listed as sa rows; never gating. sa key=.hy=: the stale ack's ledger hash / target-gone (names nothing now) or finding-gone (no longer fires). head_basis=identity: the floor is this tree's own snapshot; archived-index-hidden: refused, a tracked path is skip-worktree/assume-unchanged; absent: the archived HEAD tree. --> + @@ -2936,7 +2927,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2961,7 +2952,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2986,7 +2977,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 -

@@ -3078,8 +3069,8 @@ _OWNERSHIP partition for a shared tree: every regression here lives in src/infra ``` $ ./build/ripwire . --quality-delta --scope=src/graph.h - -, acked. value-ref-excluded=N: internal functions kept off because a table, field or argument in another function or at file scope holds them (matched by name, not a proven call); a floor. at=: commit+dirty+shallow. stale=N: ack ledger rows whose target no longer applies (sa rows); never gating. preexisting-worse=N: regressions on symbols that existed at baseline; they gate when major. new-symbol=N: findings on NEW code; new-symbol rows never gate, except defect-shape format-arity. register-macro-excluded=N: symbols kept out of dead-code as self-registering test/bench macros; a floor. declined-call-excluded=N: symbols kept out of dead-code only because a declined call may mean them; a floor. api-new-surface=N: new PUBLIC symbols; a count, never gates, not in regressions=. renames=/rename_window_commits=: git rename pairs read over that many commits, to re-file baseline and acks. acked_by_rename=/acked_by_content=: acked= suppressions matched via git renames / an equal body hash. renames_window_truncated=1: history is deeper than the rename window, older renames unread. r surface=: the api-surface tier, new-symbol or contract-change. acked=N: findings suppressed by the ack ledger, listed as sa rows; never gating. r sev=minor: a small numeric delta, counted in minor=, never gating (absent: major). r origin=new-symbol: a finding on NEW code (absent: preexisting-worse). sa key=.hy=: the stale ack's ledger hash / target-gone (names nothing now) or finding-gone (no longer fires). r members=/tokens=: a duplication row's clone group (member ids) / their shared normalized-token count. --> + @@ -3109,10 +3100,10 @@ _Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree ``` $ ./build/ripwire . --edit-check=rankGraphTeleport - - - + + @@ -3139,7 +3130,7 @@ disclosed as trailing_newline_folded=true; a second one, a deliberate blank line _An unknown TARGET refuses and leaves every file byte-identical._ ``` -$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=/aux/payload_note.h +$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc/aux/payload_note.h (empty) ``` @@ -3158,17 +3149,17 @@ $ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=/ _Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured)._ ``` -$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=/aux/payload_note.h --edit-target-file=src/infra/sortutil.h +$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=./build/sc/aux/payload_note.h --edit-target-file=src/infra/sortutil.h {"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] {"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":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"graph_ambiguous":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2925,"graph_unresolved":15128,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ``` ### `--insert-after-symbol=TARGET` @@ -3182,14 +3173,14 @@ Both inserts PAD the block (newlines only, never removed) so it is separated fro _Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call._ ``` -$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=/aux/payload_note.h +$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/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":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"graph_ambiguous":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} +"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ``` **Caveats (stated by the binary):** @@ -3209,7 +3200,7 @@ empty payloads refuse, never imply deletion _An unknown TARGET refuses and leaves every file byte-identical._ ``` -$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=/aux/payload_note.h +$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc/aux/payload_note.h (empty) ``` @@ -3230,17 +3221,17 @@ RELATIVE (matched against the indexed spelling) or ABSOLUTE (matched against the _Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured)._ ``` -$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=/aux/payload_note.h --edit-target-file=src/infra/sortutil.h +$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=./build/sc/aux/payload_note.h --edit-target-file=src/infra/sortutil.h {"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] {"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":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"graph_ambiguous":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2925,"graph_unresolved":15128,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ``` **Shaped by:** `--insert-after-symbol` @@ -3262,7 +3253,7 @@ pass this when you are about to edit again immediately). The MCP spelling is pos _The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr._ ``` -$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=/aux/payload_note.h --no-post-check +$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h --no-post-check {"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] ``` @@ -3283,7 +3274,7 @@ op is one of replace_symbol_body, insert_before_symbol, insert_after_symbol each _Neither --dry-run nor --apply: the mode is explicit, so this refuses._ ``` -$ ./build/ripwire . --edit-plan=/aux/edit_plan.json +$ ./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json (empty) ``` @@ -3298,12 +3289,12 @@ exactly one of the two is required the plan's explicit mode: --dry-run preflight _The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure._ ``` -$ ./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":2925,"graph_unresolved":15128,"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] +$ ./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json --apply +{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15150,"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: 466 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":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true}}]} +"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true}}]} ``` **Shaped by:** `--edit-check` @@ -3349,19 +3340,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] ``` @@ -3386,17 +3377,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] @@ -3440,10 +3431,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:11751 +$ ./build/ripwire . --at=src/graph.h:11793 - - + + ``` @@ -3467,7 +3458,7 @@ _No-LLM review-evidence bundle for the working-tree diff (clean tree = empty)._ ``` $ ./build/ripwire . --pr-context - ``` @@ -3493,11 +3484,11 @@ _Pairwise cross-arm conflict sites + suggested landing order (any committish sha ``` $ ./build/ripwire . --merge-scout=HEAD~2,HEAD~1 - - + + - + @@ -3547,7 +3538,7 @@ Each line is ranked on its own — no community carve, no bin packing — so the _NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode)._ ``` -$ ./build/ripwire . --plan-lanes --brief=/aux/lanes_brief.txt +$ ./build/ripwire . --plan-lanes --brief=./build/sc/aux/lanes_brief.txt add a --since filter to the doc-drift verb add the CLI parse arm and help text for the new filter write regression tests for the new filter @@ -3567,22 +3558,13 @@ Per local ref (SUBSTR filters ref names): the lines its own divergent work AUTHO **Try it** -_Which refs of the `lane/` ref family still hold divergent authored work vs HEAD, with verdicts._ +_Which refs of the one branch `b155` (no ref family left to select on this checkout) still hold divergent authored work vs HEAD, with verdicts._ ``` -$ ./build/ripwire . --stray-content=lane/ - - - - - - - - - - - -... [20 more line(s); run it to see the whole thing] +$ ./build/ripwire . --stray-content=b155 + + + ``` **Shaped by:** `--plan`, `--abi`, `--whereis`, `--limit`, `--eval-stray` @@ -3601,25 +3583,13 @@ $ ./build/ripwire . --stray-content=lane/ **Try it** -_Select the genuinely-unmerged refs of the `lane/` ref family and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root)._ +_Select the genuinely-unmerged refs of the one branch `b155` (no ref family left to select on this checkout) and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root)._ ``` -$ ./build/ripwire . --stray-content=lane/ --plan +$ ./build/ripwire . --stray-content=b155 --plan - - - - - - - - - - - - - -... [17 more line(s); run it to see the whole thing] + + ``` **Shaped by:** `--stray-content`, `--legend`, `--json` @@ -3637,25 +3607,13 @@ SCOPE is what each ref AUTHORED — the paths `git diff base..tip` reports again **Try it** -_Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all._ +_Cross-branch ABI-break gate over the one branch `b155` (no ref family left to select on this checkout): struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all._ ``` -$ ./build/ripwire . --stray-content=lane/ --abi +$ ./build/ripwire . --stray-content=b155 --abi - - - - - - - - - - - - -... [2 more line(s); run it to see the whole thing] + + ``` **Caveats (stated by the binary):** @@ -3676,14 +3634,11 @@ _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] + + + + +<.hereis> ``` **Shaped by:** `--whereis-full-text`, `--whereis-listing`, `--with-history`, `--limit` @@ -3706,13 +3661,13 @@ _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 - - - - + + + + - + + - + -... [23 more line(s); run it to see the whole thing] +... [24 more line(s); run it to see the whole thing] ``` **Shaped by:** `--whereis` @@ -3767,8 +3721,8 @@ _The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gat $ ./build/ripwire . --flags - - + + @@ -3848,7 +3802,7 @@ _The cache-locality lens over every aggregate: fields READ TOGETHER but declared ``` $ ./build/ripwire . --field-affinity - @@ -3882,8 +3836,8 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - - + + @@ -3916,8 +3870,8 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - - + + @@ -3949,9 +3903,9 @@ _Same report, with git history splitting stale mentions into deleted-by-commit v ``` $ ./build/ripwire . --doc-drift --with-history - - - + + + @@ -3982,9 +3936,9 @@ FILE is read directly (like --from-trace's FILE, not through the crawled index), _The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates._ ``` -$ ./build/ripwire . --plan-lint=test/planlintfix/wave.md +$ ./build/ripwire . --plan-lint=test/planlintfix.ave.md - + @@ -4019,8 +3973,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:11751 - #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11792 + #0 0x102f4a1c8 in rw::rankGraphTeleport(Graph const&, std::vector const&, float) src/graph.h:11793 + #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11834 #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) @@ -4049,7 +4003,7 @@ _A command that exits 0: a minimal success record (exit, measured duration, disc $ ./build/ripwire . --run-trace="true" - + ``` @@ -4151,7 +4105,7 @@ $ ./build/ripwire . --pack-task="add a new output format flag to the CLI" Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept - + claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of its newlineinline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) ... [17 more line(s); run it to see the whole thing] ``` @@ -4184,9 +4138,9 @@ $ ./build/ripwire . --pack-task="add a new output format flag to the CLI" --part Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept - + claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of…inline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) - + ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION doe…inline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, const std::string_view executablePath, const WrapListing& listing ) noexcept ... [19 more line(s); run it to see the whole thing] ``` @@ -4209,7 +4163,7 @@ _Task lens + a compact Mermaid flowchart of the top anchors' 1-hop edges._ ``` $ ./build/ripwire . --for="pagerank power iteration" --with-graph - + @@ -4234,7 +4188,7 @@ feeds a CodeCharta 3D city _Per-file metrics as CodeCharta cc.json._ ``` -$ ./build/ripwire . --export=cc.json:/aux/ripwire2.cc.json +$ ./build/ripwire . --export=cc.json:./build/sc/aux/ripwire2.cc.json (empty) ``` @@ -4251,7 +4205,7 @@ caps at 16 (over-cap = capped=1). THE SAME `verb:arg` line is accepted by the MC _One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped ._ ``` -$ ./build/ripwire . --batch=/aux/batch2.txt +$ ./build/ripwire . --batch=./build/sc/aux/batch2.txt for:incremental cache invalidation callers:rankGraphTeleport grep:DISCLOSE @@ -4281,15 +4235,15 @@ _Environment self-check: binary staleness, grammars, cache dir, git, tracked-bin ``` $ ./build/ripwire . --doctor - - - + - - + + - - + @@ -4315,20 +4269,19 @@ _--doctor plus a LIVE integration inspection for one agent: PATH binary, install ``` $ ./build/ripwire . --doctor --agent=claude - - - + - - + + - - + - - -... [2 more line(s); run it to see the whole thing] + +... [3 more line(s); run it to see the whole thing] ``` **Caveats (stated by the binary):** @@ -4351,7 +4304,7 @@ $ ./build/ripwire . --skipped - @@ -4439,8 +4392,8 @@ _Rank by git change-frequency prior instead of PageRank._ $ ./build/ripwire . --rank-by=churn --top-k=5 - - + + @@ -4472,22 +4425,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~6 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3 +$ ./build/ripwire . --rank-by=churn-decay --since=HEAD~5 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3 - - - - - - - - - - - - -... [17 more line(s); run it to see the whole thing] + + + + + + + + + + + + +... [8 more line(s); run it to see the whole thing] ``` **Shaped by:** `--external-surface`, `--doctor`, `--legend`, `--max-memory` @@ -4549,7 +4502,7 @@ _The same gating report under --legend=full — same rows, same exit 2; the defa ``` $ ./build/ripwire . --quality-delta --legend=full - @@ -4629,7 +4582,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -4665,7 +4618,7 @@ _Drop matching paths (repeatable) before ranking._ $ ./build/ripwire . --exclude=present --exclude=bench --top-k=5 - + @@ -4676,7 +4629,7 @@ $ ./build/ripwire . --exclude=present --exclude=bench --top-k=5 - + ... [17 more line(s); run it to see the whole thing] ``` @@ -4696,14 +4649,14 @@ _Full map re-ranked with teleport toward git-changed files — clean tree, so ch $ ./build/ripwire . --map-diff --top-k=5 - - + + - + - + @@ -4727,17 +4680,17 @@ $ ./build/ripwire . --map-diff --top-k=5 _Explicit incremental cache at a path OUTSIDE the repo (first call writes it)._ ``` -$ ./build/ripwire . --cache=/aux/warm2.ripwirecache --top-k=3 +$ ./build/ripwire . --cache=./build/sc/aux.arm2.ripwirecache --top-k=3 - + - + - + @@ -4758,7 +4711,7 @@ Writes BOTH families — BASE.lean.ripwirecache (map/ nav/--pr-context) and BASE _CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout._ ``` -$ ./build/ripwire . --index-out=/aux/ci_index +$ ./build/ripwire . --index-out=./build/sc/aux/ci_index (empty) ``` @@ -4780,14 +4733,14 @@ _Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm co $ ./build/ripwire . --no-cache --top-k=3 - + - + - + @@ -4811,14 +4764,14 @@ _Crawl paths the repo's own .gitignore covers (default honours it and discloses $ ./build/ripwire . --no-ignore --top-k=3 - + - + - + @@ -4847,13 +4800,13 @@ _Skip files above a size bound before parsing (note the corpus shrink in the hea $ ./build/ripwire . --max-file-size=8K --top-k=3 - + - + @@ -4924,17 +4877,17 @@ Under --scip it also writes the index's covered sites, so a precision join needs _Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target._ ``` -$ ./build/ripwire . --pin-census=/aux/pin_census.tsv --top-k=3 +$ ./build/ripwire . --pin-census=./build/sc/aux/pin_census.tsv --top-k=3 - + - + - + @@ -4957,7 +4910,7 @@ $ ./build/ripwire '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jso {"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: 738 more bytes on this line] {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"analyze","description":"Architecture map for a directory: signatures and the call graph for the top symbols. Use when landing cold in a repo or subdir, before reading files; for a task-scoped inventory use 'for', for one symbol's neighborhood find_ … [line truncated: 742 more bytes on this line] {"name":"rank_by","description":"The SAME architecture map 'analyze' serves, ranked by a different signal instead of plain PageRank. rank_by = pagerank (default, omit it — the CLI's own unbiased --rank-by=pagerank; 'analyze' can rank differently on a tree with uncommitted changes, where it biases … [line truncated: 1077 more bytes on this line] -{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read/write/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] +{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read.rite/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] ... [30 more line(s); run it to see the whole thing] ``` @@ -4981,10 +4934,10 @@ _--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":" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [735 more display lines; full output is 23597 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --top-k=5` + +*Same map, capped to the 5 highest-ranked symbols.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [67 more display lines; full output is 8256 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.* + +````` + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./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.* + +````` + + + + + + + + + + +````` + +## `./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** + +````` + + +````` + +stderr: + +````` +ripwire: --token-budget exceeded: withheld_est_tokens=9507 > 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: 2.48s** + +````` + + + + +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.hy).* + +**wall time: 1.39s** + +````` + + + + + +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: 1.38s** + +````` + + + + + +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: 1.39s** + +````` + + + + + +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: 1.49s** + +````` + + + + +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…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 19980 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: 1.46s** + +````` + + + + +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 ) +inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) +std::optional<int> runEvalViews( const MainDispatch& d ) +struct RecallSectionPick +inline double binomialChoose( std::size_t n, std::size_t k ) +… [146 more display lines; full output is 21540 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: 1.46s** + +````` + + + + +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 ) +inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) +std::optional<int> runEvalViews( const MainDispatch& d ) +struct RecallSectionPick +inline double binomialChoose( std::size_t n, std::size_t k ) +… [155 more display lines; full output is 21617 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.* + +````` + + + + + + + + + +````` + +## `./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: 1.32s** + +````` + + + + + +````` + +## `./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.* + +````` + + + + +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.* + +````` + + + + +````` + +## `./build/ripwire . --recall="quality delta gating exit codes"` + +*Most relevant DOCS' full bodies (markdown only) — recall what is already written down.* + +````` +ripwire recall — "quality delta gating exit codes" — 121 relevant of 265 document files, best-first — total=121 shown=8 capped=1 truncated=6 generated_demoted=3 max_tokens=8000 share_bytes=2468 est_tokens=4165 + +━━ README.md (relevance 8.095) ━━ [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.525) ━━ [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 ./build/sc/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 1347635-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.054) ━━ [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] +### `--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: + +````` +[math degraded] ingest: the git ignore probe exited non-zero — full walk (ingest_crawl.h:1481, rw::{anonymous}::GitIgnoreSet rw::{anonymous}::parseGitIgnoreProbe(const GitIgnoreProbeRaw&) — logged once per site) +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).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [368 more display lines; full output is 11197 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --html=./build/sc/aux/map2.html` + +*Self-contained HTML force-directed call graph.* + +**wall time: 1.55s** + +````` +(empty) +````` + +Artifact written: + +````` +155999 ./build/sc/aux/map2.html +````` + +## `./build/ripwire . --order=stable --top-k=5` + +*Stable (path/id) emit order — provider KV-cache hits across re-runs.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [67 more display lines; full output is 8274 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.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [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.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [1948 more display lines; full output is 53189 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.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --callers=rankGraphTeleport` + +*Who calls SYM (1-hop in-edges).* + +````` + + + + + + + + + + +````` + +## `./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** + +````` + + +````` + +stderr: + +````` +ripwire: --callers symbol not found: DoesNotExist +````` + +## `./build/ripwire . --callees=rankGraphTeleport` + +*What SYM calls (1-hop out-edges).* + +````` + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --uses=rankGraphTeleport` + +*The resolvable use-sites (call/read.rite/import/extends) with file:line; count= is a floor.* + +**wall time: 1.32s** + +````` + + + + + + + + + + + + +````` + +## `./build/ripwire . --graph-query='and(callers(name("rankGraphTeleport"),2),kind(all,fn))'` + +*Composable node-set query: functions within 2 caller-hops of rankGraphTeleport.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [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.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [73 more display lines; full output is 5600 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).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [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").* + +````` + + + + + + + + +````` + +## `./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex` + +*Minimal connecting subgraph over 3 symbols (finds shared-caller joins).* + +````` + + + + + + + + + + +````` + +## `./build/ripwire . --impact=rankGraphTeleport` + +*Transitive blast radius — everything that reaches SYM. NOW carries shown/capped.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [69 more display lines; full output is 6423 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --mentions=rankGraphTeleport` + +*Markdown docs that name SYM in a backtick (doc<->code edges).* + +````` + + + + + + + + + + +````` + +## `./build/ripwire . --affected=src/graph.h` + +*Test files that transitively reach the changed file.* + +````` + + + + + + + + + +````` + +## `./build/ripwire . --situ` + +*Mid-task situational report for the current git diff — recorded against a CLEAN tree (contrast with the sandbox run below).* + +````` +ripwire situational-awareness — 0 changed file(s), 0 symbols in them +root: . +at: e47df2266 + (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: 2.16s** + +````` + + +````` + +## `./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.* + +````` + +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: 1.17s** + +````` + +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).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [21 more display lines; full output is 3219 bytes on 1 raw line(s)] +````` + + +--- + +# zoom the detail ladder + +## `./build/ripwire . --for="pagerank power iteration" --detail=2` + +*Importance-weighted detail: FULL bodies for top-2, signatures for the rest.* + +**wall time: 1.45s** + +````` + + + + + +NodeId order. Renumbering an otherwise-identical graph (the exact "same probe file, different so…inline constexpr float kScoreTieAbsEps = 1e-6f + +Render one form of the disclosure. Empty string whenever there is nothing to say — no power it…inline std::string renderDisclosure( const RankDisclosure& d, DiscloseAs as ) + +The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] +inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) +struct RankedGraph +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… +inline std::uint32_t sliceRdIterationCeiling() noexcept +struct PageRankRun + +What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window +inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept +inline std::string powerShellSingleQuote( std::string_view s ) noexcept +inline std::string path_prepend_hint( std::string_view dir ) +HOT_FILES = ( "src/pagerank.cpp", # the power-iteration loop — G2's no-allocation scope "src/infra/radixSort.h", # LSD radix entry points "src/infra/radixSort.inl", # the counting … [line truncated: 76 more bytes on this line] +handle_t leftmost_leaf() const +inline void discloseUniformChurnFallback( bool hasChurnEvidence, bool stubbed, const char* verbLabel, const std::string& windowStamp ) +inline std::string doctorPathPrependLine( const std::string& selfPath ) +inline std::string doctorWhichRipwire( rw::os::stat_t& st ) +std::uint32_t testIterationCeiling() noexcept +inline const char* rankByLegendFor( const char* label ) noexcept +… [156 more display lines; full output is 22215 bytes on 72 raw line(s)] +````` + +## `./build/ripwire . --pack-signatures --top-k=10` + +*Body-elided decl skeletons — recounted on this corpus. Measured as element bytes: the signature+doc elements --pack-signatures emits, against the SAME symbols' full bodies from --expand, with the CORPUS-ROOT PREFIX SUBTRACTED FROM BOTH SIDES. That subtraction is the whole methodology and the figure is meaningless without it: the root repeats inside every element's id= and p=, it is not what this verb elides, and counting it makes the headline a function of how deep the checkout happens to sit on disk — on one corpus, three spellings of the same root read 18.6 points apart before the subtraction and agree exactly after it. Root-neutralised on THIS repo: 88.8% fewer bytes at top-10, 86.2% at top-50, 87.4% at top-100 (re-derived 2026-10-10 when the C++ standard-member gate stopped std::vector/std::string calls such as out.push_back() and s.empty() from binding to in-tree namesakes by name: the ranked top-10/50 lost one-line container accessors (svector::push_back, WidePath::c_str, every empty) and gained one-line forwarding helpers and macros (kindIs, ASSUME, formatTo, emitTo) whose signature is nearly the whole body, so less of the set is elidable, from 92.7/88.7/87.6; before that, re-derived 2026-09-20 when the native Windows port landed: src/infra/os_win32.cpp and os_win32_logic.h are ~3,900 lines of new, heavily commented infra that the ranked top-10/50/100 now reach, and their bodies are this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new, from top-50 87.1. Measured by test/showcasecapturecheck.sh's own recount arm on the combined tree, which is the gate that would otherwise report the drift; before that, re-derived 2026-09-17 at the self-check macro vocabulary rename: VERIFY/VERIFY_TEXT/VERIFY_DEBUG_ONLY/VERIFY_NOT_REACHED/VERIFY_SAME_THREAD/VERIFY_NO_ALIAS*/DYNMAP_VERIFY/DEGRADED_PATH_ALERT renamed to ASSUME/EXPECTS/ENSURES/DASSERT/UNREACHABLE/ASSUME_SAME_THREAD*/ASSUME_NO_ALIAS*/DYNMAP_ASSUME/DISCLOSE (plus new VALIDATE sites) across 839 identifier renames in 179 files, and a hand-written Diagnostics.h/diagnostics.cpp replacing the old ones outright: this moves both WHICH symbols the ranked top-10/50/100 hold and how large their bodies are, from top-50 85.2. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-12 when the rows dropped the path-repeating id= for the short sc= scope: the signature side shrank, the bodies did not; before that, 89.5% / 81.8% / 84.3% re-derived 2026-09-10 at the sibs= cap raise: kMaxExpandSibs went 8 -> 100, so --expand's bodies now carry the file context the old cap hid — 89.3% of all sibling names — and the body side is this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new. Measured on a fixed tree with the top-50 membership and the signature side unchanged: top-50 from 71.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-09 at the printf-family -> std::print conversion: converting ~1,500 emitter call sites to rw::emitTo/emitRaw/formatTo across 93 files changes how large the ranked symbols' BODIES are, and the body side is this ratio's denominator — top-50 from 72.3. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-08 at the confident-zero round, issues #62/#63/#66: that change adds symbols to src/graphlegend.h and the new src/preprocdead.h and re-homes two long comment blocks from call sites onto the helpers they explain, which moves both WHICH symbols the ranked top-50 holds and how large their bodies are — top-50 from 74.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-06 at the stranger-audit fix round: the doctor, cache-sweep and html-provenance bodies grew this corpus's BODY side, moving top-50 from 75.6 — a real re-derivation, not a tolerance edit; before that, re-derived 2026-09-05 at the capture-audit close: lane L7's P16 caps --expand's sibs= at 8 names, which SHRINKS the body side of this ratio and moved the figure down from 84.5/80.2/80.6 — the V1 2026-08-15 re-center, when sibs=/inc= first grew the body side from 70.0/61.0/63.8, in reverse; both were real re-derivations, not tolerance edits). top-50 is the number to quote, because the sigs payload is top-50 regardless of --top-k and is therefore what THIS command emits. A single small/trivial body can still invert it (signature+doc bigger than the body), like the --format=columnar sibling below. test/showcasecapturecheck.sh (C) re-derives all three from this repo every run, in the same quantity, and fails if the caption and the recount drift apart.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [148 more display lines; full output is 14953 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --outline=rankGraphTeleport --top-k=0` + +*Control-flow skeleton of one symbol, payload-only via the new --top-k=0.* + +````` + + + + +& p, float alpha = 0.85f ) +{ + PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); + const std::vector pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + ... + } + std::vector r( N, 0.f ); + std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); + return { std::move( r ), run.iterationCount, run.hasConverged }; +} +]]> +````` + +## `./build/ripwire . --outline=rankGraphTeleport:1-10 --top-k=0` + +*CHANGED: a line range on --outline is now STRIPPED with a stderr note (it used to refuse).* + +````` + + + + +& p, float alpha = 0.85f ) +{ + PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); + const std::vector pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + ... + } + std::vector r( N, 0.f ); + std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); + return { std::move( r ), run.iterationCount, run.hasConverged }; +} +]]> +````` + +stderr: + +````` +ripwire: --outline=rankGraphTeleport:1-10: --outline has no line-range form — outlining the whole symbol (use --expand=rankGraphTeleport:1-10 for a body slice) +````` + +## `./build/ripwire . --expand=rankGraphTeleport --top-k=0` + +*Full body + inline callee signatures.* + +````` + + + + +: files the ranked rows show / do not (sum = files=), each named or counted below. : a program entry by its language's convention (C/Go/Rust main, Java/C# static main, a script main its module scope calls, __main__.py), callees as c rows; manifest entries not read. : n= unshown files under dir p=; f= names its code files, the rest (tests, docs, config, test/doc/example dirs) counted. declined=K: K call sites without edges, including inert Elixir quote sites after unquote/unquote_splicing re-entry. external=K: K calls proven outside the tree, no edge. locality_pinned=K: K calls pinned by locality alone (a guess). extent_suspect_syms=K: K defs failed containment, corpus-wide. macro_blanked_files=K: K files indexed from a macro-blanked re-parse. prov=scip|binding|import|split|final-segment: how that edge bound (absent: one unique name); split = one arm of an amb= pick; final-segment = a qualified type matched by last name only. files=/symbols=: files and symbols indexed; edges= distinct call edges; shown= symbols printed, a merged row counting each def; ambiguous= calls split over several defs, corpus-wide; unresolved= calls with in-tree evidence and no edge (every def language-filtered or unreachable, or binding refused); order= rows by rank (important-first, important-last; (auto:fill) = flipped past a size threshold) or by path (stable). skipped_oversize=K: K files over a size ceiling, not indexed. unindexed=ext:N: N text files of that extension no grammar reads (6 extensions at most). unindexed_exts=E: E such extensions in all, the list cut. : a non-test row an indexed test transitively reaches (absent otherwise, never 0). : that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [97 more display lines; full output is 10931 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --deps` + +*File->file dependency graph (god-files, cycles).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [899 more display lines; full output is 24018 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --hotspots` + +*Complexity x recent git churn (maintenance pain).* + +**wall time: 1.50s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [14 more display lines; full output is 5767 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --clones` + +*Token-normalized duplicate bodies.* + +**wall time: 2.99s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [308 more display lines; full output is 16222 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --cochange` + +*Files that change together in git (hidden coupling).* + +**wall time: 1.43s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --hotspots --since="2 weeks ago"` + +*Hotspots scoped to RECENT churn (the regression lens).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [13 more display lines; full output is 5128 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --arch=test/archfix/rules.txt` + +*Enforce layering rules (exit 2 on violation) — run against the repo's own test fixture rules.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [1038 more display lines; full output is 153440 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint` + +*Built-in AST checks (c-cast, goto, unsafe-c-fn, ...).* + +**wall time: 2.44s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [685 more display lines; full output is 70581 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint-rules=test/lintrulesfix/rules` + +*User lint rules (YAML, ast-grep style) from a directory.* + +**wall time: 1.04s** + +````` + + + + +use LOG() instead of printf +use LOG() instead of printf +use LOG() instead of printf +use LOG() instead of printf +use LOG() instead of printf + +````` + +stderr: + +````` +ripwire: lint-rules: test/lintrulesfix/rules/malformed.yaml:5: expected 'key: value' — file skipped +[math degraded] lint-rules: malformed rule file skipped (lintrules.h:399, rw::parseLintRuleFile(const std::string&, std::string_view, std::vector&):: — logged once per site) +ripwire: AST query did not compile for any grammar: (this_is_not_a_real_node @x @@@ ((( ) +````` + +## `./build/ripwire . --lint --with-profile=report.txt` + +*Join MEASURED heat onto --lint findings — runs in a tiny fabricated demo corpus (one cache-pointer-chase-loop finding under a PROFILE_SCOPE site) because a real report needs a RIPWIRE_PROFILE build; the finding inside the profiled scope gains heat_* columns from the report's #PROF_TSV row.* + +Input file: + +````` +#PROF_TSV_BEGIN one row per scope, aggregated across threads; counters are RAW integers +scope file line calls total_ms l1d_mpki +walk: chase pass x.cpp 9 12 48.500 7.250 +#PROF_TSV_END +````` + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [13 more display lines; full output is 3428 bytes on 1 raw line(s)] +````` + +stderr: + +````` +[math degraded] ingest: the git ignore probe exited non-zero — full walk (ingest_crawl.h:1481, rw::{anonymous}::GitIgnoreSet rw::{anonymous}::parseGitIgnoreProbe(const GitIgnoreProbeRaw&) — logged once per site) +````` + +The joined finding — past the display cut above, extracted so the join is visible: + +````` +p = p->next +````` + +## `./build/ripwire . --communities` + +*Cluster the call graph into cohesive modules.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [189 more display lines; full output is 16860 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --zoom` + +*Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels_shown="2" of levels= BY DEFAULT over the 40 largest top modules (~8 KB, where the whole tree is ~220 KB); a module AT the cut carries children=.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [135 more display lines; full output is 7291 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --zoom --zoom-levels=3` + +*The restoring knob: --zoom-levels=N prints N levels (0 = the whole tree); here three, ~11 KB.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [271 more display lines; full output is 12259 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --report` + +*Architecture summary (modules, god-files, cycles) as markdown.* + +````` + + +# ripwire architecture report + +3607 files · 31702 symbols · 29921 edges · 3598 modules (14863 call-graph isolated) + +Root: `.` + +Call-graph isolate provenance: 3961 declaration, 2444 header, 3343 source, 5115 document; 0 connected Louvain singletons + +## Modules (call-graph clusters; showing 12 of 3598) +- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1618 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 +- **docs::`--top-k=N`@COMMANDS.md:59:9077 [pack,allow,insert]** — 181 symbols +- **test/ownerhopfix/py/pkg::big_handler_001@broadcast.py:3:72** — 106 symbols +- **src::buf@infra/svector.h:125:8942 [insert,find,push]** — 91 symbols +- **src/infra::fail@os_win32.cpp:63:2553 [open,get,close]** — 89 symbols +- **test::no@estchargecheck.sh:52:4108 [skip,set]** — 63 symbols +- **src::child@ingest_valuerefs.h:656:33874 [emit,resolve,open]** — 62 symbols +- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 55 symbols +- **src::sliceKindIs@slice.h:368:24239 [match,collect,push]** — 48 symbols +- **src/infra::DYNMAP_ASSUME@dynamic_map.hpp:90:4411 [insert,erase,find]** — 44 symbols + +## God files (most depended-on; showing 10 of 228) +- `src/model.h` — 103 dependents +- `src/infra/emit.h` — 87 dependents +- `src/infra/Diagnostics.h` — 65 dependents +- `src/graph.h` — 46 dependents +- `src/serialize.h` — 45 dependents +… [35 more lines, 3956 bytes total] +````` + +## `./build/ripwire . --seams` + +*Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [57 more display lines; full output is 9051 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --mermaid` + +*Module (directory) dependency graph as a Mermaid diagram.* + +````` +%% 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
9389"] + n103["src/infra
1301"] + end + subgraph sg1 ["test"] + n104["test
5507"] + n568["test/legochargefix
546"] + n405["test/fixtures/recallpassage
314"] + n953["test/slotjoinfix
175"] + n795["test/ownerhopfix/py/pkg
158"] + n342["test/expandmodefix
151"] + n344["test/expandsibsfix
149"] + n936["test/rubyschemafix
99"] + n424["test/forbodyfoldfix/py
98"] + n918["test/rubyattrsfix
85"] + n731["test/lib
81"] + end + n74["docs
858"] + n2[".github
625"] + n0["(root)
606"] + subgraph sg5 ["bench"] + n4["bench
545"] + n5["bench/agentloop
331"] + n49["bench/locbench/results/r5_pooling
237"] + n50["bench/locbench/results/r6_expansion
187"] + n59["bench/recalleval
113"] + n43["bench/locbench
107"] + n38["bench/headtohead/r3-headroom-2026-08-03
102"] +… [20 more lines, 1592 bytes total] +````` + +## `./build/ripwire . --owners` + +*Bus-factor: recency-weighted author ownership per file.* + +**wall time: 1.42s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [971 more display lines; full output is 106097 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --dead-code=src` + +*Internal functions with no caller found in the index — a name-based graph reading, not a confidence score. NOTE the filter is a path-COMPONENT match: 'src' matches any .../src/... segment; use ./src to pin the root directory.* + +````` + + + + +````` + +## `./build/ripwire . --exercises=test/regression.sh` + +*Which symbols a TEST FILE exercises — the reverse direction of --affected.* + +````` + + + +````` + +## `./build/ripwire . --community=0` + +*Drill into ONE call-graph community by id — the drill= the --communities output itself advertises.* + +````` + + + +````` + +## `./build/ripwire . --quality-delta` + +*On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox section below.* + +**wall time: 16.12s** + +````` + + +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +````` + +## `./build/ripwire . --quality-delta --show-stale` + +*The same clean verdict with what it folded printed back: every stale acknowledgement as an row and the full header. The regression-free answer above keeps only stale= and stale_by_kind= (and stale_next= names this call), and folds only when that saves a quarter of the bytes. Refused without --quality-delta.* + +**wall time: 12.74s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [140 more display lines; full output is 16170 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +````` + +## `./build/ripwire . --edit-check=rankGraphTeleport` + +*Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree).* + +**wall time: 8.44s** + +````` + + + + + + + + + +````` + +## `./build/ripwire . --pr-context` + +*No-LLM review-evidence bundle for the working-tree diff (clean tree = empty).* + +````` + + + +````` + +## `./build/ripwire . --pr-context=HEAD~1` + +*The BASEREF form: diffed against merge-base(BASEREF, HEAD), never the ref tip — here the previous commit on the current line (a ref with NO merge base falls back to a disclosed two-dot diff: anchor="ref-tip-two-dot").* + +**wall time: 2.14s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [21 more display lines; full output is 5229 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --merge-scout=HEAD~2,HEAD~1` + +*Pairwise cross-arm conflict sites + suggested landing order (any committish sharing a merge base with HEAD works as an arm; one that does not is reported ok="0", never compared).* + +**wall time: 7.56s** + +````` + + + + + + + + + + + +````` + +## `./build/ripwire . --stray-content=b155` + +*Which refs of the one branch `b155` (no ref family left to select on this checkout) still hold divergent authored work vs HEAD, with verdicts.* + +````` + + + +````` + +## `./build/ripwire . --stray-content=no-such-ref` + +*A second selection, `no-such-ref`, which no local ref carries, so the verb REFUSES (exit 1), picked at capture time from the refs this checkout really has and never the selection above: merged refs are OMITTED from the rows and counted in merged=; refs sharing no merge base with HEAD (a shallow clone, or a pre-rewrite history) land in unknown= with ok="0" — the counters always reconcile against refs=.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --stray-content=no-such-ref matches no local ref — a zero here would be a failure, not a measurement + (the filter is a substring match against refs/heads names; run bare --stray-content to list them, e.g. --stray-content=feat/) +````` + +## `./build/ripwire . --stray-content=b155 --plan` + +*Select the genuinely-unmerged refs of the one branch `b155` (no ref family left to select on this checkout) and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root).* + +````` + + + +````` + +## `./build/ripwire . --stray-content=zzzz-no-such-ref --plan` + +*A --plan filter that selects NO ref REFUSES (exit 1) naming the substring — before the wave-3 close this fell through to the '>512 refs match' sentence, and --abi under the same filter answered an empty measurement at exit 0.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zero here would be a failure, not a measurement + (the filter is a substring match against refs/heads names; run bare --stray-content to list them, e.g. --stray-content=feat/) +````` + +## `./build/ripwire . --stray-content=b155 --abi` + +*Cross-branch ABI-break gate over the one branch `b155` (no ref family left to select on this checkout): struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all.* + +````` + + + +````` + +## `./build/ripwire . --whereis=rankGraphTeleport` + +*Which ref's tree defines or mentions SYM — HEAD first, then every local branch. The default lists the kind="def" rows (here the first 60, most on branches, each carrying tip= and date=) and counts the references in : on this symbol HEAD's references would fill the 60-row cap before the branch definitions arrive, so the whole list (below) shows fewer definitions, and the default serves the page that shows more of them, whatever its bytes.* + +**wall time: 1.23s** + +````` + + + + +<.hereis> +````` + +## `./build/ripwire . --whereis=rankGraphTeleport --whereis-listing=all` + +*The whole hit list asked for by name: under the same 60-row cap HEAD's references fill the list, so it shows far fewer definitions (here HEAD's one) than the default above (here 60). The default serves the all page only when it shows the same definitions as the defs page in strictly fewer bytes (a tie serves it too).* + +**wall time: 1.25s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [35 more display lines; full output is 12690 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --quality-delta=HEAD~1..HEAD --quality-kinds=complexity,dead-code` + +*A ref range run for two of the twelve kinds only: the named kinds' rows are exactly their rows in the full answer, the header names the others (kinds_skipped=, skipped_why="selector"), and a pass no named kind needs does not run. The replay a memory-stopped range answer hands back (kinds_next=) is this flag. Refused without --quality-delta=A..B.* + +**wall time: 7.61s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [34 more display lines; full output is 13667 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --whereis=computeOnePairOverlap --with-history` + +*Same, plus a git-history row (never / removed-by-commit) for names no tree carries.* + +**wall time: 11.54s** + +````` + + + + + +<.hereis> +````` + +## `./build/ripwire . --flags` + +*The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gates from comments/heredocs, so the count only reflects real ifndef/define, CMake option(), and getenv gates.* + +**wall time: 1.18s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [400 more display lines; full output is 24541 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --flags --flip=RIPWIRE_ASAN` + +*Blast radius of turning ONE gate on: live code, symbols, transitive reach, covering tests.* + +**wall time: 1.16s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --flags --flip=RIPWIRE_ASA` + +*Unknown-gate refusal (exit 1) with a did-you-mean from a real edit distance (one character off RIPWIRE_ASAN).* + +**exit code: 1** — **wall time: 1.12s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --flip: no gate named 'RIPWIRE_ASA' in . (did you mean 'RIPWIRE_ASAN'?) +ripwire: run `ripwire . --flags` for the gate table +````` + +## `./build/ripwire . --plan-lanes=3 --task="add a --since filter to the doc-drift verb and cover it with tests"` + +*NEW VERB: pre-hoc lane plan — which of 3 parallel worktrees would COLLIDE, before a line is written. JSON on stdout.* + +**wall time: 1.52s** + +````` +{"v":1,"verb":"plan-lanes","at":"e47df2266","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3607,"symbols":31702,"edges":299 … [line truncated: 338 more bytes on this line] +"symbols":[{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","l":286,"id":"./src/docdrift.h::DriftResult::DriftResult"}, +{"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","l":2441,"id":"./src/docdrift.h::docdrift::computeDocDrift"}, +{"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","l":2739,"id":"./src/docdrift.h::docdrift::kDocDriftLegend"}, +{"p":"./src/docdrift.h","n":"writeDocDriftPage","scope":"docdrift","l":2909,"id":"./src/docdrift.h::docdrift::writeDocDriftPage"}, +{"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","l":655,"id":"./src/mcpverbs.h::rw::docDriftText"}, +{"p":"./src/verbs_change.h","n":"runDocDrift","scope":"","l":1678,"id":null}]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb and cover it with tests","claims":{"symbols":[{"p":"./src/verbs_change.h","n":"runAbiCheck","scope":"","key":"183da9aaf74a4a92","id":null,"id_addr … [line truncated: 113 more bytes on this line] +{"p":"./src/editcheck.h","n":"editCheckPriceRoot","scope":"rw","key":"33219bb04158a6a8","id":"./src/editcheck.h::rw::editCheckPriceRoot","id_addressable":true,"id_collides_with":0,"l":1202,"ord":0,"overloads":1,"amb":0,"cx":8,"ccx":10,"churn":57,"tested":0}, +{"p":"./src/docdrift.h","n":"writeGateability","scope":"docdrift","key":"42c456dfb55faee4","id":"./src/docdrift.h::docdrift::writeGateability","id_addressable":true,"id_collides_with":0,"l":2685,"ord":0,"overloads":1,"amb":2,"cx":6,"ccx":6,"churn":36,"tested":0}, +{"p":"./src/darkflags.h","n":"writeFlags","scope":"darkflags","key":"5c2c4a2b311b8dba","id":"./src/darkflags.h::darkflags::writeFlags","id_addressable":true,"id_collides_with":0,"l":1298,"ord":0,"overloads":1,"amb":1,"cx":8,"ccx":8,"churn":32,"tested":0}, +{"p":"./src/docdrift.h","n":"docDriftNextAttr","scope":"docdrift","key":"7723ed789a1c9c09","id":"./src/docdrift.h::docdrift::docDriftNextAttr","id_addressable":true,"id_collides_with":0,"l":2864,"ord":0,"overloads":1,"amb":0,"cx":6,"ccx":5,"churn":36,"tested":0}, +{"p":"./src/docdrift.h","n":"recordWeakDisclosures","scope":"docdrift","key":"972779210e49c0cf","id":"./src/docdrift.h::docdrift::recordWeakDisclosures","id_addressable":true,"id_collides_with":0,"l":2430,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":1,"churn":36,"tested":0}, +{"p":"./src/testmap.h","n":"scriptGatesUnmodelledCount","scope":"rw","key":"98c4487e2e9e08bc","id":"./src/testmap.h::rw::scriptGatesUnmodelledCount","id_addressable":true,"id_collides_with":0,"l":1793,"ord":0,"overloads":1,"amb":0,"cx":4,"ccx":4,"churn":61,"tested":0}, +{"p":"./src/main.cpp","n":"scanReportVerbPrecedence","scope":"","key":"9ab981e987e8108e","id":null,"id_addressable":false,"id_collides_with":0,"l":3031,"ord":0,"overloads":1,"amb":0,"cx":8,"ccx":11,"churn":453,"tested":0}, +{"p":"./src/pageview.h","n":"secondaryCutAttrs","scope":"rw","key":"a10ea8d3bdca1dfb","id":"./src/pageview.h::rw::secondaryCutAttrs","id_addressable":true,"id_collides_with":0,"l":399,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":28,"tested":0}, +{"p":"./src/main.cpp","n":"emitNoteAddUnprovenDefs","scope":"","key":"a950332ccfce6b8d","id":null,"id_addressable":false,"id_collides_with":0,"l":691,"ord":0,"overloads":1,"amb":1,"cx":2,"ccx":1,"churn":453,"tested":0}, +{"p":"./src/docdrift.h","n":"sortDocsByLiveDrift","scope":"docdrift","key":"d5de682411b9a9a9","id":"./src/docdrift.h::docdrift::sortDocsByLiveDrift","id_addressable":true,"id_collides_with":0,"l":2390,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":2,"churn":36,"tested":0}, +{"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5838,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":459,"tested":0}], +"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":55}, +{"p":"./src/docdrift.h","symbols":4,"churn":36,"ccx":14,"hotspot_rank":38}, +{"p":"./src/editcheck.h","symbols":1,"churn":57,"ccx":10,"hotspot_rank":42}, +{"p":"./src/main.cpp","symbols":2,"churn":453,"ccx":12,"hotspot_rank":5}, +{"p":"./src/mcpverbs.h","symbols":1,"churn":459,"ccx":2,"hotspot_rank":4}, +{"p":"./src/pageview.h","symbols":1,"churn":28,"ccx":2,"hotspot_rank":129}, +{"p":"./src/testmap.h","symbols":1,"churn":61,"ccx":4,"hotspot_rank":33}, +{"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":9,"hotspot_rank":25}]},"blast_radius":{"reaches":47,"files_total":16,"capped":false,"files":["./src/darkflags.h","./src/docdrift.h","./src/editcheck.h","./src/editplan.h","./src/editpreview.h","./src/flipimpact.h","./src/main.cpp","./src/mcp.h … [line truncated: 182 more bytes on this line] +"tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":47,"module_span":1,"notes":[], +"execution":{"policy":"codex-lane/v1","model":"gpt-5.6-terra","reasoning":"high","rule":"moderate-cross-module","basis":"structural-only","signals":{"claims":12,"files":8,"module_span":1,"max_ccx":11,"sum_ccx":61,"ambiguous_calls":6,"blast_reaches":47,"contract_touches":0,"conflicts":0,"untested":47 … [line truncated: 142 more bytes on this line] +{"id":"lane-1","task":"add a --since filter to the doc-drift verb and cover it with tests","claims":{"symbols":[{"p":"./src/gitmine.h","n":"gitWindowBoundarySha","scope":"rw","key":"18627516699d7062","id":"./src/gitmine.h::rw::gitWindowBoundarySha","id_addressable":true,"id_collides_with":0,"l":1674 … [line truncated: 69 more bytes on this line] +{"p":"./src/cli.h","n":"kViewFlags","scope":"rw","key":"2a2f2487082cc6d8","id":"./src/cli.h::rw::kViewFlags","id_addressable":true,"id_collides_with":0,"l":3327,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +… [69 more display lines; full output is 20481 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --plan-lanes --brief=./build/sc/aux/lanes_brief.txt` + +*NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode).* + +**wall time: 1.62s** + +Input file: + +````` +add a --since filter to the doc-drift verb +add the CLI parse arm and help text for the new filter +write regression tests for the new filter +````` + +````` +{"v":1,"verb":"plan-lanes","at":"e47df2266","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3607,"symbols":31702,"edges":29921,"ambiguous":2932,"unresolved":15150},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] +"symbols":[]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb","claims":{"symbols":[{"p":"./src/docdrift.h","n":"recordUnchecked","scope":"docdrift","key":"12641dab14abc8fd","id":"./src/docdrift.h::docdrift::recordUnchecked","id_addressable":true,"id_collides_with":0,"l":2 … [line truncated: 72 more bytes on this line] +{"p":"./src/docdrift.h","n":"sortWeakGroupsByPath","scope":"docdrift","key":"1944ba506280ff80","id":"./src/docdrift.h::docdrift::sortWeakGroupsByPath","id_addressable":true,"id_collides_with":0,"l":2401,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":36,"tested":0}, +{"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","key":"1fa68e8d93c05a59","id":"./src/mcpverbs.h::rw::docDriftText","id_addressable":true,"id_collides_with":0,"l":655,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":459,"tested":0}, +{"p":"./src/cli.h","n":"kViewFlags","scope":"rw","key":"2a2f2487082cc6d8","id":"./src/cli.h::rw::kViewFlags","id_addressable":true,"id_collides_with":0,"l":3327,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +{"p":"./src/recall.h","n":"docFileMask","scope":"rw","key":"3149a219f599664c","id":"./src/recall.h::rw::docFileMask","id_addressable":true,"id_collides_with":0,"l":110,"ord":0,"overloads":1,"amb":0,"cx":4,"ccx":4,"churn":27,"tested":0}, +{"p":"./src/docdrift.h","n":"writeDocDriftPage","scope":"docdrift","key":"380b7de5df1cfd73","id":"./src/docdrift.h::docdrift::writeDocDriftPage","id_addressable":true,"id_collides_with":0,"l":2909,"ord":0,"overloads":1,"amb":10,"cx":14,"ccx":15,"churn":36,"tested":0}, +{"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","key":"3b19cc3d8996c3b2","id":"./src/docdrift.h::docdrift::computeDocDrift","id_addressable":true,"id_collides_with":0,"l":2441,"ord":0,"overloads":1,"amb":1,"cx":26,"ccx":38,"churn":36,"tested":0}, +{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","key":"422ab39546b6e0bd","id":"./src/docdrift.h::DriftResult::DriftResult","id_addressable":true,"id_collides_with":0,"l":286,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":36,"tested":0}, +{"p":"./src/verbs_change.h","n":"runDocDrift","scope":"","key":"904831e5c0f66b39","id":null,"id_addressable":false,"id_collides_with":0,"l":1678,"ord":0,"overloads":1,"amb":1,"cx":5,"ccx":4,"churn":82,"tested":0}, +{"p":"./src/ensemble.h","n":"kEnsembleChurnSince","scope":"ensemble","key":"a34fc78c05bf56a8","id":"./src/ensemble.h::ensemble::kEnsembleChurnSince","id_addressable":true,"id_collides_with":0,"l":120,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":23,"tested":0}, +{"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5838,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":459,"tested":0}, +{"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","key":"ff2ba74637bbbebf","id":"./src/docdrift.h::docdrift::kDocDriftLegend","id_addressable":true,"id_collides_with":0,"l":2739,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":36,"tested":0}], +"files":[{"p":"./src/cli.h","symbols":1,"churn":511,"ccx":0,"hotspot_rank":6}, +{"p":"./src/docdrift.h","symbols":6,"churn":36,"ccx":54,"hotspot_rank":38}, +{"p":"./src/ensemble.h","symbols":1,"churn":23,"ccx":0,"hotspot_rank":105}, +{"p":"./src/mcpverbs.h","symbols":2,"churn":459,"ccx":2,"hotspot_rank":4}, +{"p":"./src/recall.h","symbols":1,"churn":27,"ccx":4,"hotspot_rank":64}, +{"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":4,"hotspot_rank":25}], +"symbols_total":3458,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], +"tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":13,"module_span":6,"notes":[], +"execution":{"policy":"codex-lane/v1","model":"gpt-5.6-sol","reasoning":"xhigh","rule":"wide-contract-work","basis":"structural-only","signals":{"claims":12,"files":6,"module_span":6,"max_ccx":38,"sum_ccx":64,"ambiguous_calls":12,"blast_reaches":13,"contract_touches":1,"conflicts":0,"untested":13,"t … [line truncated: 139 more bytes on this line] +{"id":"lane-1","task":"add the CLI parse arm and help text for the new filter","claims":{"symbols":[{"p":"./scripts/optremarks.py","n":"main","scope":"","key":"01b3b880f77d1512","id":null,"id_addressable":false,"id_collides_with":133,"l":279,"ord":0,"overloads":1,"amb":0,"cx":23,"ccx":31,"churn":14, … [line truncated: 12 more bytes on this line] +{"p":"./src/cli.h","n":"HelpLine","scope":"rw","key":"1489844dbc310b82","id":"./src/cli.h::rw::HelpLine","id_addressable":true,"id_collides_with":0,"l":2948,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +{"p":"./src/cli.h","n":"HelpFilter","scope":"HelpFilter","key":"3103a5e8bfc33d38","id":"./src/cli.h::HelpFilter::HelpFilter","id_addressable":true,"id_collides_with":0,"l":3027,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":133,"l":865,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":17,"tested":0}, +{"p":"./src/mcprefusal.h","n":"kMcpValueFields","scope":"rw::mcprefuse","key":"4a7106e488a2aa80","id":"./src/mcprefusal.h::rw::mcprefuse::kMcpValueFields","id_addressable":true,"id_collides_with":0,"l":304,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":49,"tested":0}, +{"p":"./src/cli.h","n":"serveHelpSelector","scope":"rw","key":"4b247ee064fc4e94","id":"./src/cli.h::rw::serveHelpSelector","id_addressable":true,"id_collides_with":0,"l":3092,"ord":0,"overloads":1,"amb":1,"cx":4,"ccx":3,"churn":511,"tested":0}, +{"p":"./src/query.h","n":"tryParsePredicateOnAll","scope":"query","key":"786acc4dbfec612b","id":"./src/query.h::query::tryParsePredicateOnAll","id_addressable":false,"id_collides_with":1,"l":113,"ord":0,"overloads":2,"amb":0,"cx":1,"ccx":0,"churn":20,"tested":0}, +{"p":"./src/cli.h","n":"printUsageTier","scope":"rw","key":"82b7af67acdca479","id":"./src/cli.h::rw::printUsageTier","id_addressable":true,"id_collides_with":0,"l":3078,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":1,"churn":511,"tested":0}, +… [60 more display lines; full output is 18606 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --plan-lanes=99 --task=x` + +*Out-of-range refusal shape for the lane count.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out) +````` + +## `./build/ripwire . --layout=Symbol` + +*CPU/GPU contract view of one struct: computed offsets/sizes/padding + mirror check.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --layout=Lang` + +*The honest refusal (exit 1): Lang is an `enum class`, not a struct — no offsets are fabricated.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped enum's underlying type is not a byte layout) +````` + +## `./build/ripwire . --doc-drift` + +*Which of this repo's doc claims are now false. CHANGED: row attribute at= renamed to tgt= (at= is now only the root sha stamp).* + +````` + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + +… [228 more display lines; full output is 23906 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --doc-drift --gateability` + +*The finishable to-do list: docs whose LIVE failing anchors a date-stamp would reclassify.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [255 more display lines; full output is 25161 bytes on 1 raw line(s)] +````` + +Tail of the same output — the `` section: + +````` + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --doc-drift --with-history` + +*Same report, with git history splitting stale mentions into deleted-by-commit vs never-existed.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [208 more display lines; full output is 23885 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --from-trace=-` + +*Map a pasted stack trace onto indexed symbols. CHANGED: in_corpus= now reports the real count (was 0).* + +Input file: + +````` +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:11793 + #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11834 + #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) +==41337==ABORTING +````` + +````` + + + + + + + + + + + +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] + +uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f ) +int runDefaultMap( const MainDispatch& d ) +int main( int argc, char** argv ) + + + +& p, float alpha = 0.85f ) +{ + PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); + const std::vector pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + double teleportMass = 0.0; +… [18 more display lines; full output is 4915 bytes on 29 raw line(s)] +````` + +## `./build/ripwire . --notes` + +*List all field notes (write-side memory) — the committed .ripwire_notes at the repo root, each with the sha/branch it was recorded at.* + +````` + + + + + + + + + + + gate scripts' claim (~line 1305) is NOT enforced — the derived-vs-stated sibling loop here covers docs/EVALS.md only. It drifted 407→451 unnoticed (fixed 2026-08-23). To close: grep both files ('file:line:' parsing) in the gateCountClaims arm.]]> + + + + +````` + +## `./build/ripwire . --pack-task="add a new output format flag to the CLI"` + +*ONE budget-shared bundle: ranking + top bodies + caller sigs + notes + tests_to_run. CHANGED: rows now carry n=/id=.* + +````` + + + + +Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept + +claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of its newlineinline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) + +ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION does not vary by agent — only the MCP alternative does. Before this there were four near-identical CLI-fiinline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, c … [line truncated: 83 more bytes on this line] + +mcp-tools pass-through. Written into the server command only where its argument shape is known to be one more plain argument: the JSON args arrays (cursor.indsurf/gemini), opencode's command arrayinline bool wrapWritesToolsArg( const AgentTarget& row ) noexcept + +L8 (train 29): the NEXT PAGE of a callers listing — the CLI --callers root's next=, find_referencing_symbols' next and find_symbol's calledBy_next all name this one call, so the three cannot spell tinline std::string callHierarchyPageNext( bool wantCallers, std::string_vi … [line truncated: 98 more bytes on this line] +inline std::string classNewGroupXml( const IngestResult& ing, std::span<const ClassNewRow> rows, std::string_view rootPrefix, EscapeFn ex ) + + + + + + + + + +… [67 more display lines; full output is 12092 bytes on 59 raw line(s)] +````` + +## `./build/ripwire . --pack-task="add a new output format flag to the CLI" --partition=3` + +*Fan-out form: one shared core + 3 per-agent slices carved along call-graph communities.* + +````` + wraps a ; bundle role=core|partition i= symbols= modules= bytes= tokens=: one agent's ctx, symbols= ids assigned, bytes= its size; tokens= = est_tokens= = bytes/2.36 (flat, the densest rate; the inner ctx est_tokens= is language-weighted). Inner ctx task= root= budget_tokens= dropped_positive=: the task, p= base, the slice's token target, ranked candidates its budget cut. of_top=: rows ranked (far) / bodies (callers); s rel=caller|callee shared=: 1-hop edge, bodies reached (absent at 1). window: shown= total= capped= (capped=1 cut). run_unknown=1: no runner derivable (a guess would be worse). est_tokens=: price as emitted (an upper bound under compact). : rank N in this ranking, rows in r= order. : cyclomatic/cognitive complexity. : N callers in the index (absent: not measured). route=: the ranker: name-exact(X) = the task names symbol X (anchors: its evidence), subtoken+body = conceptual BM25 (:broad = 1-2 plain words, plain rg may also win; :declined(...) = a name hit refused as a common name). sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. next=: the one pasteable follow-up. pure=1: const/constexpr signature (Swift: non-mutating) and no transitive side effect found; a hint. partitions=/requested=: partitions carved / asked for. modules=/split=: call-graph groups found / cuts forced to split one. core_symbols=/surface=: ids in the shared core / core plus the assignable remainder. budget_per_agent_tokens=: one agent's budget, core_budget_tokens= plus partition_budget_tokens=. total_bytes=N: bytes of all bundles together. overlap_mean=/overlap_max=: pairwise Jaccard over the ids partitions name, before trimming. shared_symbols=/union_symbols=: ids two or more partitions name / ids any partition names. core_overlap=: share of the core surface a partition reaches anyway. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. --> + + + + + +Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept + +claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of…inline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) + +ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION doe…inline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, const std::string_view executablePath, const WrapListing& listing ) noexcept + +mcp-tools pass-through. Written into the server command only where its argument shape is known t…inline bool wrapWritesToolsArg( const AgentTarget& row ) noexcept + + + + + +inline bool printUsageTier( std::FILE* out, HelpTier tier, std::string_view want ) noexcept + + + + + + + + +NodeId order. Renumbering an otherwise-identical graph (the exact "same probe file, different so…inline constexpr float kScoreTieAbsEps = 1e-6f + +Render one form of the disclosure. Empty string whenever there is nothing to say — no power it…inline std::string renderDisclosure( const RankDisclosure& d, DiscloseAs as ) + +The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] +inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) +struct RankedGraph +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… +inline std::uint32_t sliceRdIterationCeiling() noexcept +struct PageRankRun + +What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window +inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept +inline std::string powerShellSingleQuote( std::string_view s ) noexcept +inline std::string path_prepend_hint( std::string_view dir ) +HOT_FILES = ( "src/pagerank.cpp", # the power-iteration loop — G2's no-allocation scope "src/infra/radixSort.h", # LSD radix entry points "src/infra/radixSort.inl", # the counting … [line truncated: 76 more bytes on this line] +handle_t leftmost_leaf() const +inline void discloseUniformChurnFallback( bool hasChurnEvidence, bool stubbed, const char* verbLabel, const std::string& windowStamp ) +inline std::string doctorPathPrependLine( const std::string& selfPath ) +inline std::string doctorWhichRipwire( rw::os::stat_t& st ) +std::uint32_t testIterationCeiling() noexcept +inline const char* rankByLegendFor( const char* label ) noexcept +… [124 more display lines; full output is 19081 bytes on 10 raw line(s)] +````` + +## `./build/ripwire . --export=cc.json:./build/sc/aux/ripwire2.cc.json` + +*Per-file metrics as CodeCharta cc.json.* + +**wall time: 1.47s** + +````` +(empty) +````` + +Artifact written: + +````` +559268 ./build/sc/aux/ripwire2.cc.json +{"projectName":"project","apiVersion":"1.3","attributeDescriptors":{"loc":{"title":"Lines of Code","description":"Physical line count","direction":-1},"symbols":{"title":"Symbols","description":"Definitions in the file","direction":-1},"cx":{"title":"Cyclomatic Complexity","description":"Sum of per-symbol cyclomatic complexity","direction":-1},"cognitive_cx":{"title":"Cognitive Complexity","descri +````` + +## `./build/ripwire . --batch=./build/sc/aux/batch2.txt` + +*One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped .* + +**wall time: 2.60s** + +Input file: + +````` +for:incremental cache invalidation +callers:rankGraphTeleport +grep:DISCLOSE +lego:Vehicle +````` + +````` + + + + + + + + + +incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…constexpr std::uint32_t kCacheMagic = 0x4b505443 + +Composed exactly the way every OTHER blob family is (quality.h): one fixed-width identity hex pe…inline std::string spanTierMemoPath( const std::string& diskPath ) + +Ingest the tree at `sha`, materialized out of `root`'s object store. The HEAD side reuses the SA…inline bool ingestCommitTree( const std::string& root, const std::string& sha, const std::vector<std::string>& excludes, std::size_t maxFileBytes, IngestResult&… … [line truncated: 4 more bytes on this line] + +P1-15 — the `_reingest` envelope field for a response whose handling ran an INCREMENTAL pass, …inline bool mcpRefreshedThisRequest( std::uint64_t passesAtEntry ) +struct FileHealth +inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::ve … [line truncated: 8 more bytes on this line] +inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… +inline RawFacts runParsePool( IngestResult& result, const char* rootDir, std::string_view cacheFile, bool captureValueUses, HashMap<std::string, FileFacts>& cache, const CacheLoadStats& cac … [line truncated: 66 more bytes on this line] +inline McpRebuildBaseline mcpRebuildBaseline( const McpIndex& ix, bool isIncrementalPass ) +inline const McpIndex& getIndex( const std::string& root ) +inline std::string mcpFreshFields( std::uint64_t passesAtEntry ) +struct McpIndex +inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) +IngestResult ingest( const char* rootDir, const std::vector<std::string>& excludeSubstr, std::string_view cacheFile, std::size_t maxFileBytes, bool captureValueUses, std::string_view excludeLabel, bool … [line truncated: 37 more bytes on this line] +const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) +static bool cachePathIsDirectory( const std::string& cachePath ) +inline std::string oracleCachePath( const std::string& root, const std::string& headSha ) +HashMap<const TSLanguage*, TSQuery*>& compiledQueryCache() +… [107 more display lines; full output is 51596 bytes on 1 raw line(s)] +````` + + +--- + +# self-diagnosis + +## `./build/ripwire . --doctor` + +*Environment self-check: binary staleness, grammars, cache dir, git, tracked-binary staleness — exit 1 when any check fails (here: the PATH install is older than ./build).* + +**exit code: 1** — **wall time: 1.55s** + +````` + + + + + + + + + + +````` + +stderr: + +````` +ripwire --doctor: no ripwire resolves from PATH. To put this binary's directory first (for this shell; put the same line in your shell rc file), paste this line: +export PATH='./build':"$PATH" +````` + + +--- + +# security + +## `./build/ripwire --scan-skill=skills/ripwire-orient/SKILL.md` + +*Scan a single skill file for injection/exfiltration patterns before installing.* + +````` + + + +````` + +stderr: + +````` +ripwire scan: 0 finding(s) in skills/ripwire-orient/SKILL.md +````` + +## `./build/ripwire --scan-skills=skills` + +*Scan a whole skills directory (exit 2 = CRITICAL, 1 = WARN). Explicit-DIR form only.* + +````` + + + +````` + +stderr: + +````` +ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s) skipped, 0 denylisted subtree(s) not descended) +````` + + +--- + +# knobs / modes + +## `./build/ripwire . --rank-by=churn --top-k=5` + +*Rank by git change-frequency prior instead of PageRank.* + +**wall time: 1.50s** + +````` + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --rank-by=churn-decay --since=HEAD~5 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3` + +*Scope the recent-changes answer to ONE directory. 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=bogus --top-k=5` + +*An unknown value REFUSES (exit 1), NAMED, with the supported set listed.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf|churn|churn-decay) +````` + +## `./build/ripwire . --callers=rankGraphTeleport --format=columnar` + +*Columnar output: paths table + parallel arrays, ~15-60% fewer tokens on MANY-row lists — small results can be LARGER (the columnar legend is a fixed cost).* + +````` + + +0=src/mcpindex.h 1=src/graph.h 2=src/eval.h 3=src/main.cpp + +0,1,1,2,3,3,3 +getIndex,rankGraph,anchoredLexicalRank,runEval,churnDecayRanking,churnRankedGraph,runDefaultMap +1184,11832,12478,171,1425,1464,1751 +fn,fn,fn,fn,fn,fn,fn +0,0,0,0,0,0,0 +src/mcpindex.h:1288,src/graph.h:11835,src/graph.h:12529,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 + + +````` + +## `./build/ripwire . --for="cache invalidation" --format=candidates --top-k=5` + +*Flat top-K export for an external reranker.* + +**wall time: 1.35s** + +````` + + + +inline std::string spanTierMemoPath( const std::string& diskPath ) + + +inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::vector<NodeId>& surfaceIds ) + + +### See the map — not just the numbers + + +inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) + + +const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) + + +````` + +## `./build/ripwire . --callers=rankGraphTeleport --format=bogus` + +*An unknown --format value REFUSES (exit 1), named, with the supported set listed.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --format: unknown value 'bogus' (supported: xml|columnar|rows|candidates) +````` + +## `./build/ripwire . --callers=rankGraphTeleport --json` + +*Machine-parseable JSON, same content, keys mirror the XML attrs.* + +````` +{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, +{"t":"fn","n":"rankGraph","p":"src/graph.h:11832","sites_at":["src/graph.h:11835"]}, +{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12478","sites_at":["src/graph.h:12529"]}, +{"t":"fn","n":"runEval","p":"src/eval.h:171","sites_at":["src/eval.h:328"]}, +{"t":"fn","n":"churnDecayRanking","p":"src/main.cpp:1425","sites_at":["src/main.cpp:1439"]}, +{"t":"fn","n":"churnRankedGraph","p":"src/main.cpp:1464","sites_at":["src/main.cpp:1478","src/main.cpp:1479","src/main.cpp:1493"]}, +{"t":"fn","n":"runDefaultMap","p":"src/main.cpp:1751","sites_at":["src/main.cpp:1871"]}]} +````` + +## `./build/ripwire . --hotspots --json` + +*JSON refusal shape: an unsupported verb refuses loudly instead of silently falling back to XML.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --json is not yet supported for --hotspots — supported: the default map, --for, --pack-task, --callers/--callees, --impact, --quality-delta, --test-gate, --metrics, and --plan-lanes which is JSON-native (e.g. ripwire

--callers=SYM --json) +````` + +## `./build/ripwire . --hotspots --limit=3 --offset=3` + +*Pagination: 3 items, skipping the first 3 (deterministic seams).* + +**wall time: 1.44s** + +````` + + + + + + + +````` + +## `./build/ripwire . --ignore-tests --top-k=5` + +*Drop test paths from the corpus before ranking.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [67 more display lines; full output is 8115 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --exclude=present --exclude=bench --top-k=5` + +*Drop matching paths (repeatable) before ranking.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [65 more display lines; full output is 8095 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --map-diff --top-k=5` + +*Full map re-ranked with teleport toward git-changed files — clean tree, so changed=0 and it degrades to the plain map.* + +````` + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --no-cache --top-k=3` + +*Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm cost.* + +**wall time: 1.64s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --cache=./build/sc/aux.arm2.ripwirecache --top-k=3` + +*Explicit incremental cache at a path OUTSIDE the repo (first call writes it).* + +**wall time: 1.68s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] +````` + +Artifact written: + +````` +28654855 ./build/sc/aux.arm2.ripwirecache +````` + +## `./build/ripwire . --max-file-size=8K --top-k=3` + +*Skip files above a size bound before parsing (note the corpus shrink in the header).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [18 more display lines; full output is 4246 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --scip=does_not_exist.scip --callers=rankGraphTeleport` + +*SCIP overlay with a missing index REFUSES (exit 1) naming the file — never silently serves the name-based map you named a precision index to improve on (it used to degrade in silence).* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather than serving the name-based map you named a precision index to improve on (generate one with scip-clang/scip-python, or drop --scip) +````` + +## `./build/ripwire src test --top-k=5` + +*Multi-root workspace: ONE merged graph over two roots, paths labeled /.* + +**wall time: 1.83s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --eval` + +*Self-eval: co-change recall vs BM25.* + +**wall time: 18.51s** + +````` +ripwire --eval (co-change recovery, averaged over 80 historical commits) + ranker recall@5 recall@10 recall@20 + ripwire 4.7% 6.4% 16.6% + BM25 9.3% 14.1% 16.6% + BM25sub 10.8% 21.2% 27.7% + BM25body 15.3% 21.0% 30.4% + fused 11.8% 13.3% 24.8% + anchored 15.3% 21.3% 30.7% + same-dir 0.9% 4.6% 8.4% + random 0.1% 0.3% 0.6% <- floor (random ranking over F=3607 files) + note: `ripwire` here is the DEFAULT MAP's structural-only PageRank (importance, not + relatedness) — it is NOT what a --for/--query retrieval call ranks with. BM25 / + BM25sub / BM25body are QUERY-TIME lexical rankers (whole-name / subtoken / + subtoken+body); fused = RRF(ripwire, BM25sub); anchored = BM25body + anchored PPR + expansion (--for --anchor, EXPERIMENTAL). The SHIPPED default for --for/--query is + the subtoken+body lexical family (routed to name-exact only for an identifier-shaped + query — lexical.h chooseForRanker), so a gap between the ripwire and BM25* rows here + is structural-importance-vs-lexical-relatedness on a co-change task, not the shipped + retrieval path losing to an alternative it was never running. +````` + +## `./build/ripwire . --eval-retrieval` + +*Known-item retrieval eval: MRR + recall@k per ranker per query mode.* + +**wall time: 187.37s** + +````` +ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-corpus by construction) + sample: population=7974 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population + (smallest fnv1a64(scope::name) over the population, cut on the key so an identity is never split; + path- and order-independent, but a corpus this size is NOT graded exhaustively — say so when citing it) + ingest: lex=rich (persisted subtoken stats; no per-query corpus re-tokenize) + ranker query-mode MRR recall@1 recall@5 recall@10 + subtoken name 0.680 54.5% 84.8% 90.0% + subtoken doc-phrase 0.903 88.3% 92.2% 93.4% + name-exact name 0.898 82.2% 95.8% 97.4% + name-exact doc-phrase 0.013 0.5% 1.8% 2.6% + anchored name 0.687 56.1% 84.1% 88.7% + anchored doc-phrase 0.899 87.5% 92.2% 92.9% + routed name 0.899 82.4% 96.0% 97.6% + routed doc-phrase 0.902 88.2% 92.0% 93.2% + note: routing chose name-exact on 3989/4000 NAME queries (a NAME query is always identifier-shaped); + the confidence gate routes doc-phrase queries to name-exact ONLY when EVERY content word names a symbol + (or an explicit camel/snake token appears) AND every matched name is specific enough to anchor on — + a common name (many definitions, or a subtoken carried by many symbol names) declines the route — so + conceptual prose falls back to subtoken+body; routed tracks the better ranker on BOTH modes + (routed==name-exact on name, ~=subtoken+body on doc-phrase). +````` + +## `./build/ripwire . --eval-stray=./build/sc/aux/stray_labels2.tsv` + +*Labelled verdict-accuracy eval for --stray-content — three labels over REAL local refs (names resolved at capture time); exit 3 when accuracy is under the floor. Read got= against v= in the stray-content run: a ref the verb could not analyse (unknown) must never be credited as a merged hit.* + +**exit code: 1** + +Input file: + +````` +# refverdict labels for --eval-stray (the first three local branches, resolved at capture time; a missing branch is padded with a nonexistent name on purpose) +b155 merged +no-such-ref-1 unmerged +no-such-ref-2 merged +````` + +````` +(empty) +````` + +stderr: + +````` +ripwire: --eval-stray: 2 labelled ref(s) do not exist in . -- not merged, just absent: no-such-ref-1, no-such-ref-2 (fix the labels file or add the ref) +````` + +## `./build/ripwire skills --eval-skills=./build/sc/aux/skills_labels2.tsv` + +*Labelled skill-ROUTING eval over the repo's own skills/ directory (4 hand-labelled prompts).* + +Input file: + +````` +orient in an unfamiliar codebase fast ripwire-orient judged +who calls this function and what is the blast radius ripwire-navigate judged +plan parallel worktrees so the lanes do not collide ripwire-change-check judged +what is the weather in Paris none neg +````` + +````` +ripwire --eval-skills (skill routing over K=16 candidate skills [ripwire-router excluded]; 3 positive + 1 negative prompts; corpus './build/sc/aux/skills_labels2.tsv'; split test=4 dev=0) + arm hit@1 hit@2 mrr sep-auc fire/abstain@ORACLE-th (upper bound) + overlap 66.7% 66.7% 0.689 0.000 50.0% (th=-1.000) + name 33.3% 66.7% 0.537 0.667 50.0% (th=0.000) + bm25-desc 66.7% 66.7% 0.689 0.667 75.0% (th=2.865) + bm25-full 33.3% 66.7% 0.611 1.000 50.0% (th=0.426) + for-routed 33.3% 33.3% 0.556 1.000 50.0% (th=0.663) + random 6.2% 12.5% 0.211 0.500 <- floor (uniform-random ranking; auc 0.5 by definition) + provenance hit@1 (bm25-desc): router 0/0, desc 0/0, judged 2/3 (desc rows quote the descriptions - expect them easiest; judged is the honest number) + judged-only hit@1 per arm: overlap 2/3, name 1/3, bm25-desc 2/3, bm25-full 1/3, for-routed 1/3 + router-magnet: with ripwire-router ADMITTED as a candidate it takes top-1 on 1/3 positive prompts (bm25-desc arm) - why it is excluded above + per-skill (bm25-desc): name / permitted-rows / won / pos-fires / false-fires / neg-fires + ripwire-before-you-build 0 0 1 1 0 + ripwire-change-check 1 0 0 0 0 + ripwire-find-bug 0 0 0 0 0 + ripwire-fresh-eyes 0 0 0 0 1 + ripwire-graph-query 0 0 0 0 0 + ripwire-handoff 0 0 0 0 0 + ripwire-layers 0 0 0 0 0 + ripwire-mcp 0 0 0 0 0 + ripwire-navigate 1 1 1 0 0 + ripwire-opt-remarks 0 0 0 0 0 + ripwire-orient 1 1 1 0 0 + ripwire-perf-target 0 0 0 0 0 + ripwire-quality-bar 0 0 0 0 0 + ripwire-reuse-first 0 0 0 0 0 + ripwire-security-scan 0 0 0 0 0 + ripwire-write-tests 0 0 0 0 0 + misses (overlap): + line 3 want=ripwire-change-check got=ripwire-before-you-build "plan parallel worktrees so the lanes do not collide" +… [19 more lines, 3602 bytes total] +````` + +## `./build/ripwire wrap claude` + +*Print the recipe to wire ripwire into Claude Code as an MCP server.* + +````` +# ripwire -> Claude Code (CLI-first) +# NOTE: nothing on PATH is named ripwire right now, so the command below is this binary's absolute path; +# put its directory on PATH (the installer printed the export line) and the bare word works too. +# RECOMMENDED — this agent can run shell commands, so call the CLI directly. It costs +# nothing until you invoke it, and it reads CLAUDE.md, so the paste block below IS the wiring: +./build/ripwire . --for="" +# +# ...every follow-up call answers with the compact legend by default (terse definitions of only the +# attributes the answer carries; the payload is byte-identical either way). Add --legend=full when a +# definition's reasoning is needed -- `ripwire --help` carries the measured saving (one place, +# gate-held) -- this line does not repeat it, because two copies of a number is one that goes stale: +# ripwire . --callers=SYM --legend=full +# +# ALTERNATIVE — register the MCP server instead, for a warm index across calls: +claude mcp add ripwire -- ./build/ripwire --mcp +# verbs the agent can then call mid-task (33 total): +# read: analyze, rank_by, find_symbol, find_referencing_symbols, grep, cochange, memory_recall, situational_awareness, mentions, for, lego, owners, fetch_body, batch, flags, doc_drift, slice +# flagship reflex: exemplar, quality_delta, quality_baseline, impact, uses, affected, path_between, connect, explore, from_trace, edit_check, whereis, stray_content +# edit: replace_symbol_body, insert_before_symbol, insert_after_symbol +bash skills/install.sh # deploy to ${CLAUDE_CONFIG_DIR:-~/.claude}/skills (drift-gated) +bash skills/install.sh --hook # RECOMMENDED: advisory Read/Grep -> ripwire CLI nudge + session primer (opt-in, never blocks) +# +# context wiring — a binary on PATH is invisible to an agent until its rules file says when +# to reach for it. Paste the block below into CLAUDE.md: +# --- paste into CLAUDE.md --- +## ripwire — deterministic codebase maps (on PATH as `ripwire`) +Reach for it BEFORE blind grep + whole-file reads. First call ~1s cold; after that warm, ~0.1s. +- Orient on a task: `ripwire --for=""` — ranked, quality-annotated + signatures. Paste symbol/file names from the issue verbatim; named mentions get anchored. +- One task: `--pack-task="" --legend=compact`; before parallel agents: `--plan-lanes=N --task=""`, then read `lanes[].execution`. +… [16 more lines, 4284 bytes total] +````` + +## `./build/ripwire --version` + +*Version + short build info.* + +````` +ripwire 0.6.8 (dev, GNU 14.2.0, emit=std::print, built_from=f3f773982) +````` + + +--- + +# navigate — seeds, claims, slices, shapes + +## `./build/ripwire . --at=src/graph.h:11793` + +*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 . --callers=@src/graph.h:11793` + +*The same seed in a SELECTOR position: @FILE:LINE resolves to the innermost enclosing definition, then --callers runs on it.* + +````` + + + + + + + + + + +````` + +## `./build/ripwire . --at=src/graph.h:999999` + +*A seed past the end of the file — the refusal shape for a faulted location.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16149 lines — the seed asked for line 999999) +````` + +## `./build/ripwire . --verify="calls(runDefaultMap, rankGraphTeleport)"` + +*VERIFY a closed claim in one call: three-valued verdict (confirmed / refuted / not-established) with the evidence rows inline.* + +**wall time: 1.28s** + +````` + + + + + +````` + +## `./build/ripwire . --verify="unused(rankGraphTeleport)"` + +*A claim that is FALSE — the refuted shape, with the references that refute it.* + +**wall time: 1.24s** + +````` + + + + + + + + + + + + +````` + +## `./build/ripwire . --verify="contains(src/graph.h, \"no such literal anywhere\")"` + +*A literal-scan absence: refuted only with complete= evidence, never on a partial scan.* + +**wall time: 1.25s** + +````` + + + +````` + +## `./build/ripwire . --verify="frobnicate(x)"` + +*An unparseable claim — the refusal names the accepted shapes.* + +**exit code: 1** — **wall time: 1.28s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. The claim language is CLOSED; the shapes are: calls(A, B) does A transitively call B · uses(SYM) is SYM referenced anywhere · unused(SYM) is SYM referenced nowhere · contains(FILE, "LITERAL") do FILE's bytes contain t … [line truncated: 218 more bytes on this line] +````` + +## `./build/ripwire . --slice=rankGraphTeleport` + +*Bare --slice=SYM: the INVENTORY of sliceable locals (), so a caller can pick VAR.* + +````` + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport` + +*Intra-procedural def-use slice of ONE variable: one row per line touching it, k=def|use|both, reaching definitions flow-sensitive (reach=cfg).* + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=back --slice-depth=3` + +*TRANSITIVE backward value-flow from the seed variable, bounded BFS (depth= disclosed; a cut frontier says flow_truncated=1).* + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + + pw = biasPrior( g, p );]]> + + +& p, float alpha = 0.85f )]]> + + +& p, float alpha = 0.85f )]]> + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=fwd` + +*Forward flow: which statements the seed's value reaches, at the default depth bound.* + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + + + + + + + + + + + + + + 0.0 )]]> + + + + + + + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:nosuchvar` + +*A variable the definition does not bind — the refusal shape, naming the inventory.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --slice: no occurrence of 'nosuchvar' in rankGraphTeleport — sliceable locals: alpha, g, p, pw, N, teleport, rankDouble, run, teleportMass, value, inverseMass, r (bare --slice=rankGraphTeleport lists them with first-def lines) +````` + +## `./build/ripwire . --slice-depth=3` + +*--slice-depth without --slice-flow is refused loudly rather than silently ignored.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire --slice=parseArgs:argIndex --slice-flow=fwd --slice-depth=4) +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport --legend=compact` + +*The compact legend posture: rows byte-identical, a versioned schema id replaces the repeated explanatory prose — for a many-small-calls loop.* + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + +````` + +## `./build/ripwire . --pattern='rankGraphTeleport($A, $B, $C)'` + +*Structural search written in CODE: $NAME binds one node; grammars=/shapes= disclose what the pattern became per grammar (a 3-argument call shape — the 2-argument spelling has no call site in this repo and correctly reports hits=0).* + +**wall time: 1.36s** + +````` + +rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) + +````` + +## `./build/ripwire . --pattern='DISCLOSE(...)'` + +*The ellipsis form over a macro-shaped call site; unsupported= names the families this verb does not serve.* + +**wall time: 1.39s** + +````` + +DISCLOSE( result, AbiResult::DisclosureWhy::NoMergeBase, "abi: no merge-base for a ref (unrelated history?) — that ref +DISCLOSE( Diagnostics::answerRefused, "--arch exits 1 with path:line and the reason on stderr; no report is printed", +DISCLOSE( baseline, ArchBaselineRead::DisclosureWhy::SymlinkRefused, "arch: refusing to read the arch baseline sidecar t +DISCLOSE( Diagnostics::answerRefused, "--baseline exits 1: pathguard names the refused link on stderr and the verb says +DISCLOSE( ex, Exclusions::DisclosureWhy::ForHeaderSaturated, "atoms: the for-header exclusion stream spent its whole bud +DISCLOSE( ex, Exclusions::DisclosureWhy::StmtCrementSaturated, "atoms: the statement-crement exclusion stream spent its +DISCLOSE( ex, Exclusions::DisclosureWhy::StmtAssignSaturated, "atoms: the statement-assign exclusion stream spent its wh +DISCLOSE( ex, Exclusions::DisclosureWhy::InnerCommaSaturated, "atoms: the inner-comma exclusion stream spent its whole b +DISCLOSE( st, Type3Stats::DisclosureWhy::PairCapHit, "clones: Type-3 pair cap hit — first N compared (both-gate-surviv +DISCLOSE( scan, CommentCoherenceScan::DisclosureWhy::UnreadableFile, "comment-coherence: an indexed file could not be re +DISCLOSE( st, StreamBlobStats::DisclosureWhy::ListUnwritable, "crossref: cannot write the blob-batch list — cross-bran +DISCLOSE( st, StreamBlobStats::DisclosureWhy::BatchNotStarted, "crossref: git cat-file --batch failed to start — cross +DISCLOSE( st, StreamBlobStats::DisclosureWhy::StreamEndedMidBlob, "crossref: git cat-file stream e +DISCLOSE( dropSink, RefEnumeration::DisclosureWhy::TipNotObjectName, "crossref: for-each-ref yielded a ref whose tip is +DISCLOSE( "crossref: refusing a diff whose revision arguments are not resolved object names" ) +DISCLOSE( sweep, ParallelSweep::DisclosureWhy::WorkerThrew, "crossref: a git worker threw — this shard of the sweep is +DISCLOSE( stats, StreamBlobStats::DisclosureWhy::BatchNotStarted, "crossref: a blob-stream slice was never read — comp +DISCLOSE( plumb, RefPlumbing::DisclosureWhy::RevisionNotObjectName, "crossref: ref tip or HEAD is not a resolved object +DISCLOSE( plumb, RefPlumbing::DisclosureWhy::MergeBaseNotObjectName, "crossref: merge-base returned something that is no +DISCLOSE( plumb, RefPlumbing::DisclosureWhy::NoMergeBase, "crossref: no merge-base for ref (shallow clone or unrelated h +DISCLOSE( "crossref: refusing to list a tree whose revision argument is not a resolved object name" ) +DISCLOSE( "whereis: the index's def sites match no HEAD row (working tree drifted from HEAD?) — keeping the lexical la +DISCLOSE( reads[ k ], BranchBlobReadBack::DisclosureWhy::NotReadBackWhole, "whereis: a blob the pa +DISCLOSE( scan, WorktreeScan::DisclosureWhy::ListingFailed, "whereis: git could not list the working tree's changes — +DISCLOSE( scan, WorktreeScan::DisclosureWhy::OverPathCap, "whereis: more changed paths than the overlay reads — the re +DISCLOSE( scan, WorktreeScan::DisclosureWhy::CopyUnread, "whereis: a changed path could not be read from the working tre +DISCLOSE( Diagnostics::answerUnchanged, "lsTree lists the same rows per ref: only slower", "crossref: +DISCLOSE( out, CMakeScan::DisclosureWhy::SymlinkEscapesRoot, "flags: a CMake file's symlink target leaves the root — f +… [73 more display lines; full output is 17778 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --pattern='x'` + +*A pattern that collapses to a bare token is REFUSED — never reported as hits=0.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --pattern: this pattern collapses to a single bare token, which is a TEXT search, not a structural one — a clean parse is not enough (a bare word parses fine in most grammars and means nothing structural). Give it a shape (foo($X), $A + $B, if ($C) { ... }) or use the grep flag for litera … [line truncated: 176 more bytes on this line] +````` + +## `./build/ripwire . --grep=DISCLOSE --and=cache` + +*Boolean grep: hits where BOTH literals share the matched line (--grep-scope=line is the default).* + +````` + + + +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…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 19865 bytes on 44 raw line(s)] +````` + +## `./build/ripwire . --for="tree-sitter parse of a source file" --sections=lego,compose` + +*Restore the / sections the --for bundle collapses to a counted stub by default (this is the stub's own next= spelling).* + +**wall time: 1.46s** + +````` + + + + +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…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 ) +… [149 more display lines; full output is 20198 bytes on 44 raw line(s)] +````` + +## `./build/ripwire . --for="tree-sitter parse of a source file" --auto-bodies` + +*Opt OUT of compact conceptual serving: restore the rank-first auto walk (bundle="auto").* + +**wall time: 1.44s** + +````` + + + + +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…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 ) +… [134 more display lines; full output is 20417 bytes on 55 raw line(s)] +````` + +## `./build/ripwire . --for="quality delta acks ledger rubber stamp"` + +*Doc-mention surfacing (default ON): a markdown doc naming a top-resolved symbol in a backtick rides in below that symbol — the legend's [doc mentions: …] clause says it fired.* + +**wall time: 1.42s** + +````` + + + + + +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 constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at +inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) +inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… +inline const char* kNotesFile = ".ripwire_notes" +inline void writePlanLint( std::FILE* out, const LintResult& res ) + +The REF-PAIR floor's comparison, once loadRefPairDelta has both sides: the base snapshot is the …void refPairBasis( const rw::Config& cfg, const std::string& root, RefPairDelta& refs, DeltaBasis& out ) +std::optional<int> refuseForeignAckSelection( const rw::Config& cfg, const rw::quality::Scope& scope, const std::vector<rw::quality::Regression>& outOf … [line truncated: 16 more bytes on this line] +std::optional<int> runQualityDelta( const MainDispatch& d ) +struct DeltaBasis +int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] +inline const char* kAcksFile = ".ripwire_quality_acks" +DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) +struct IdentityHealing +inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline std::string qualityAcksPath( const std::string& root ) +struct QualityDeltaOutcome +std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) +… [193 more display lines; full output is 22980 bytes on 45 raw line(s)] +````` + +## `./build/ripwire . --for="quality delta acks ledger rubber stamp" --no-doc-mention` + +*The same task with doc-mention surfacing OFF — the contrast the flag exists for (no [doc mentions] clause, one fewer row).* + +**wall time: 1.48s** + +````` + + + + + +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 constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at +inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) +inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… +inline const char* kNotesFile = ".ripwire_notes" +inline void writePlanLint( std::FILE* out, const LintResult& res ) + +The REF-PAIR floor's comparison, once loadRefPairDelta has both sides: the base snapshot is the …void refPairBasis( const rw::Config& cfg, const std::string& root, RefPairDelta& refs, DeltaBasis& out ) +std::optional<int> refuseForeignAckSelection( const rw::Config& cfg, const rw::quality::Scope& scope, const std::vector<rw::quality::Regression>& outOf … [line truncated: 16 more bytes on this line] +std::optional<int> runQualityDelta( const MainDispatch& d ) +struct DeltaBasis +int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] +inline const char* kAcksFile = ".ripwire_quality_acks" +DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) +struct IdentityHealing +inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline std::string qualityAcksPath( const std::string& root ) +struct QualityDeltaOutcome +std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) +… [193 more display lines; full output is 22799 bytes on 45 raw line(s)] +````` + +## `./build/ripwire . --safe-delete=rankGraphTeleport` + +*"Can I delete this?" — callers + transitive impact + every use site + how much of the radius is tested, composed in ONE call; risk= names what was found, never a verdict.* + +````` + + + + + + + + + +````` + +## `./build/ripwire . --safe-delete=DoesNotExist` + +*Unknown-symbol refusal shape for --safe-delete.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --safe-delete symbol not found: DoesNotExist +````` + +## `./build/ripwire . --handoff` + +*The continuation packet for the NEXT session: disk truth (branch/sha, changed symbols, blast radius, tests) + labeled suggestions. Recorded against a CLEAN tree.* + +**wall time: 1.53s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [441 more display lines; full output is 46965 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --no-ignore --top-k=3` + +*Crawl paths the repo's own .gitignore covers (default honours it and discloses ignored_files=/ignored_dirs= only when it dropped anything — this repo's crawl drops nothing, so the header is identical to the default map's; --skipped's ignore_mode= says which rule applied).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --no-stable --top-k=3` + +*--no-stable outside --mcp: what the flag does (or says) when there is no stable-by-default ordering to opt out of.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable ordering the server turns on) — it changed nothing here; the CLI map orders important-first unless you pass --order=stable +````` + +## `./build/ripwire . --run-trace="cat ./build/sc/aux/asan_trace_now.txt; exit 1"` + +*EXEC-MODE --from-trace: run a command, and on a non-zero exit map its captured output onto indexed symbols in the same call — the whole fix-loop entry. ripwire exits 4 here because the wrapped command failed, which is the signal, not an incident.* + +**exit code: 4** + +````` + + + + + + const&, float) src/graph.h:11793 + #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11834 + #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)]]> pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + double teleportMass = 0.0; + for( const double value : teleport ) + { + teleportMass += value; + } + if( teleportMass > 0.0 ) + { + const double inverseMass = 1.0 / teleportMass; + for( double& value : teleport ) + { + value *= inverseMass; + } + } + run = pageRankDouble( g.inEdges, g.wOutDeg, teleport, rankDouble, PageRankConfig{ .alpha = double( alpha ) } ); + } + std::vector r( N, 0.f ); + std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); + return { std::move( r ), run.iterationCount, run.hasConverged }; +}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] +````` + +## `./build/ripwire . --run-trace="true"` + +*A command that exits 0: a minimal success record (exit, measured duration, disclosed output tail) and NO bundle — nothing failed, nothing to map.* + +````` + + + + +````` + +## `./build/ripwire . --run-trace="sleep 30" --run-timeout=2` + +*A command still running at the cap: its process group is killed and the run reports timed_out=1 — an honest timeout, never an empty success.* + +**exit code: 4** — **wall time: 2.83s** + +````` + + + + +````` + +stderr: + +````` +ripwire: --run-trace: TIMEOUT — the command exceeded the 2 s cap; its process group was killed +````` + +## `./build/ripwire . --run-timeout=5` + +*--run-timeout alone is refused loudly (it only modifies --run-trace).* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwire --run-trace="make -j" --run-timeout=60) +````` + + +--- + +# assess quality — the wider lens family + +## `./build/ripwire . --quality-panel` + +*THE single wide-angle quality read: six families in one pass, an eligible/ranked shortlist rather than a firehose.* + +**wall time: 4.84s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [188 more display lines; full output is 15675 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --biggest-first --limit=8` + +*Per-function size ranking, largest Halstead volume/token entropy/lines first — a size proxy, not a readability order (withdrawn, docs/EVALS.md §8) — a RANKING lens, not a grade.* + +**wall time: 1.15s** + +````` + + + + + + + + + + + +````` + +## `./build/ripwire . --comment-coherence --limit=8` + +*Functions WITH a doc comment, most name-restating first: c_coeff (high = the comment repeats the name) and cic (Jaccard of comment vs identifier vocabulary), both reported, never collapsed.* + +**wall time: 1.14s** + +````` + + + + + + + + + + + +````` + +## `./build/ripwire . --context-ratio --limit=8` + +*The local-reasoning lens: to understand this symbol, how much must you know that is NOT in front of you (ent_ratio= edge share, read_ratio= token-weighted).* + +**wall time: 1.38s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [21 more display lines; full output is 11151 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --nonlocal-state --limit=8` + +*Per function, the non-local MUTABLE state it can reach (transitively), most writes first — unsound by construction, and the legend says where.* + +**wall time: 3.29s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [41 more display lines; full output is 7601 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --ensemble --limit=8` + +*The family join: per function, which of four orthogonal evidence families fire, ranked by how many agree.* + +**wall time: 2.33s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [36 more display lines; full output is 7488 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --field-affinity` + +*The cache-locality lens over every aggregate: fields READ TOGETHER but declared FAR APART (split-line / straddle findings, Chilimbi separation weight) — advice only, never a rewrite.* + +**wall time: 1.52s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [510 more display lines; full output is 45635 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --field-affinity=Symbol` + +*The same lens narrowed to ONE struct — the one --layout=Symbol shows the offsets for.* + +**wall time: 1.54s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --naming-consistency --limit=8` + +*The corpus's OWN case-convention vote per (language, kind) group; off-convention names get a mechanical propose= (a suggestion, never a blind rename).* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [13 more display lines; full output is 4430 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --naming-calibration` + +*Score the naming-* rules against this repo's own rename history: proxy=old/(old+new) per rule, 0.50 = chance; read pairs= (sample size) first.* + +**wall time: 11.13s** + +````` + + + + + + + + + + + +

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+… [154 more display lines; full output is 16060 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint --naming-locals` + +*The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/C++ only, only inside functions already past a size/complexity gate.* + +**wall time: 3.17s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [641 more display lines; full output is 72667 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint-catalog` + +*The built-in rule registry — one row per rule with sev=/category=/rationale/lang=/since=; no corpus needed.* + +````` + + +a C-style cast — cppcoreguidelines-pro-type-cstyle-cast prefers the explicit static_cast/const_cast/reinterpret_cast +a goto statement — cppcoreguidelines-avoid-goto +a do.hile loop shape (on Swift, its do/catch block shares the same grammar node and also matches) +a call to an unbounded C string function (strcpy/strcat/sprintf/gets) +a call to a broken hash or cipher (MD5/SHA1/MD4/RC4) +a doubly-parenthesized expression — readability-redundant-parentheses +an if-body that is just `;` — bugprone-suspicious-semicolon +a C-style typedef struct/union where `using` is preferred +a non-trivial numeric literal inside a function body, outside a const/constexpr init +a catch block with an empty body +x = x — almost always a copy-paste bug +a function body over 80 lines +brace nesting depth over 4 inside a function body +a bare `return;` mixed with a value-returning return in the same function +a statement after an unconditional return/break/continue/throw/raise in the same block +a 1-2 letter Function/Method/Var name — visible far beyond any tiny scope [Beniamini/Hofmeister] +more than 5 split tokens in one name [Butler; AlSuhaibani] +foo1/foo2/... digit-suffix siblings sharing a base name in one scope [Butler] +internal consecutive underscores, or a C-family reserved __x/_X form [Butler] +snake_case and camelCase mixed inside one name [Butler] +an is/has/can/should.as-prefixed name whose KNOWN return type is not bool-like [LAPD A2] +a set-prefixed name whose KNOWN return type is not void-like [LAPD A3] +a co-visible pair within edit distance <=2, reordered tokens, or a bare/digit-suffixed twin [Namesake] +every split subtoken is corpus-ubiquitous (BM25 idf) on a body past the size floor — fires only at the low end [Sparck Jones 1972] +the comma operator inside an expression (never a for-header comma) [Gopstein FSE 2017] +++/-- evaluated inside a larger expression (never a whole statement) [Gopstein FSE 2017] +an assignment whose VALUE is consumed (a condition, an argument, ...) [Gopstein FSE 2017] +a conditional expression inside a conditional expression [Gopstein FSE 2017] +… [12 more display lines; full output is 7800 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --legend-dict` + +*The session legend dictionary the MCP server serves as ripwire://legend-dict/full — one definition per line, headed by its dictv= version; no corpus needed. =roster lists the completeness attributes it defines.* + +````` +ripwire legend dictionary ripwire.dict/v1 dictv=2259c5025ac90271 entries=930 +: the answer's rows come first; its root keeps only task= changed= from= to=, and this LAST child carries every other root attribute unchanged (schema= included); legend="ref": a definition is sent once per session (this dictionary's core, or the first answer that ne … [line truncated: 83 more bytes on this line] +schema=ripwire.KEY/v1: the line ripwire.KEY/v1 below reads the answer's rows +window: shown= total= capped= has_more= next_offset= offset= limit= page a list (capped=1 cut; next_offset= pastes as offset=) +X_capped= (any attribute ending _capped): 1 = cut +under ref, est_tokens= and over_ceiling= price the answer with its inline legend: an upper bound +under ref, a group of n <= 8 runner-less rows prints as its n single rows, each run_unknown=1 +ripwire.map/v1 : ranked symbol map: groups rows (k= rank), resolved callees; the header comment is data +ripwire.map-diff/v1 : the ranked map anchored at at=: what the diff touched, the map's row vocabulary +ripwire.metrics/v1 : the ranked map with per-symbol metrics: in/out, cx/ccx, loc, params, nest, humps/deep, locals, cbo, amp, tested, ev +ripwire.around/v1 : call neighbourhood of of=: depth= hops, fanout= kept per hop; absent rows lie outside that boundary +ripwire.query/v1 : lexical-rank map for the query term, the map's row vocabulary +ripwire.pack-signatures/v1 : the ranked map plus signature rows +ripwire.pack-top-n/v1 : the ranked map plus bodies of the top-N symbols +ripwire.skipped/v1 : why the index lacks a file ; indexed but unvouched ; census +ripwire.notes/v1 : field notes by target: holds ; the kept count comment: notes= rows, targets= rows, dangling= targets matching nothing indexed (listed, surfaced nowhere) +ripwire.lego/v1 : ONE interface/base type: , its method contract, every implementor +ripwire.expand/v1 : full bodies: of ; resolved callees +ripwire.expand-file/v1 : the file's own text: ; per scoped symbol; full id = p::sc::n +ripwire.candidate-page/v1 : budgeted-bundle candidate page: a resumable window over the ranked candidate set the bundle cuts, for task= under budget_tokens=, one tier per page, ranks global across pages +ripwire.pack-task/v1 : one-call task bundle for task= under budget_tokens=: ranking, ranked but over 1 hop out (of_top= ranked rows) > with callees > 1-hop from the bodies (o … [line truncated: 105 more bytes on this line] +ripwire.from-trace/v1 : trace frames mapped to indexed symbols, innermost first; the innermost in-corpus body included +ripwire.exemplar/v1 : the best-in-class instance of kind= for the task, chosen by role: , to imitate +ripwire.pack-task/v1 : N minimally overlapping agent bundles carved along call-graph communities plus one shared core; each wraps a ; bundle role=core|partition i= symbols= modules= bytes= tokens=: one agent's ctx, symbols= ids assigned, bytes= its size; tokens= = est_t … [line truncated: 345 more bytes on this line] +ripwire.callers/v1 : 1-hop CALLERS of of= (defs= matched, count= distinct symbols): ; hop_tested=/hop_untested= +ripwire.callees/v1 : 1-hop CALLEES of of= (defs= matched, count= distinct symbols): +ripwire.uses/v1 : resolvable use-sites of of=: +ripwire.impact/v1 : transitive blast radius of of=: reach set, importers; defs= matched, reaches= their transitive callers, radius_tested= non-tests an indexed test reaches, radius_untested= the rest; importers= files that #include/import a def's file +ripwire.path/v1 : one DIRECTED call path from= to to=, each a hop; reachable=0 hops=0 when none +ripwire.connect/v1 : minimal joining subgraph: groups, terminals, joins, edges, +… [901 more display lines; full output is 97483 bytes on 931 raw line(s)] +````` + +## `./build/ripwire . --lint --lint-select=cache-` + +*Run ONLY one rule family; the root carries selected="K of N" so a filtered zero is never confusable with an unfiltered one.* + +**wall time: 2.43s** + +````` + + + + + + + + + + +vector<std::vector<double>> +nodes[ perm[i] ] +nodes[ perm[ i + 1 ] ] +p = p->next +map +byName[ symN[i] ] +vector<std::vector<std::vector<std::uint32_t>>> +vector<std::vector<std::uint32_t>> +m[ symN[id] ] +vector<std::vector<double>> +m[ in.keys[ i ] ] +map +vector<std::vector<std::vector<std::uint32_t>>> +vector<std::vector<std::uint32_t>> +m[ symN[id] ] +map +m[ g_pool[ g_keyOf[i] ] ] +g_pool[ g_readOf[i] ] +g_pool[ g_readOf[i] ] +m[ g_pool[i] ] +… [607 more display lines; full output is 73533 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint --lint-ignore=naming-,cache-` + +*DROP two families, applied after selection; the raw select=/ignore= you passed rides on the root.* + +**wall time: 2.38s** + +````` + + + + + + + + + + + + + + + + + + + + + + + +0.5 +1023u +main (90 lines) +20 +delta < 0.02 && delta > -0.02 +0.02 +… [724 more display lines; full output is 66341 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint --lint-select=goto --lint-max-per-rule=4` + +*A rule that spends its own match budget (here 4, set BELOW the default 5000 so the floor shows on this repo): goto carries count_capped="1", its count= is a FLOOR, and the root names the call that counts the rest — findings_next= re-runs only the floored rules under a 10x budget.* + +**wall time: 2.43s** + +````` + + + +goto done; +goto epilogue; +goto epilogue; +goto epilogue; + +````` + +## `./build/ripwire . --lint --lint-select=goto --lint-max-per-rule=40` + +*Pasting that findings_next=: the same rule under a 10x budget counts its true total — no count_capped=, no findings_next=.* + +**wall time: 2.42s** + +````` + + + +goto done; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto error; +goto error; +goto error; +goto done; +goto done; + +````` + +## `./build/ripwire . --lint --lint-select=cach-` + +*An unresolvable PREFIX refuses (exit 1) with a did-you-mean from a real edit distance (one character off cache-).* + +**exit code: 1** — **wall time: 2.46s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --lint-select: 'cach-' matches no rule or family (did you mean 'cache-'?) — see --lint-catalog for the full registry +````` + +## `./build/ripwire . --lint --lint-select=nosuchfamily` + +*A PREFIX with no near miss at all: the refusal points at --lint-catalog instead of guessing.* + +**exit code: 1** — **wall time: 2.42s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint-catalog for the full registry +````` + +## `./build/ripwire . --lint --sarif` + +*The SAME findings as SARIF 2.1.0 (what github/codeql-action/upload-sarif consumes) — pure re-serialization, results count == the native run's.* + +**wall time: 2.50s** + +````` +{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"name":"ripwire","rules":[{"id":"c-style-cast","shortDescription":{"text":"c-style-cast"},"properties":{"builtin":true,"capped":false,"applicable": … [line truncated: 7 more bytes on this line] +{"id":"goto","shortDescription":{"text":"goto"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"do-while","shortDescription":{"text":"do-while"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"unsafe-c-fn","shortDescription":{"text":"unsafe-c-fn"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"weak-crypto","shortDescription":{"text":"weak-crypto"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"redundant-parens","shortDescription":{"text":"redundant-parens"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"suspicious-semicolon","shortDescription":{"text":"suspicious-semicolon"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"typedef-over-using","shortDescription":{"text":"typedef-over-using"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"magic-number","shortDescription":{"text":"magic-number"},"properties":{"builtin":true,"capped":true,"applicable":true}}, +{"id":"empty-catch","shortDescription":{"text":"empty-catch"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"self-assign","shortDescription":{"text":"self-assign"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"large-function","shortDescription":{"text":"large-function"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"deep-nesting","shortDescription":{"text":"deep-nesting"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"inconsistent-return","shortDescription":{"text":"inconsistent-return"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"unreachable-code","shortDescription":{"text":"unreachable-code"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-short","shortDescription":{"text":"naming-short"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-wordy","shortDescription":{"text":"naming-wordy"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-series","shortDescription":{"text":"naming-series"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-underscore","shortDescription":{"text":"naming-underscore"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-case","shortDescription":{"text":"naming-case"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-predicate","shortDescription":{"text":"naming-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-setter","shortDescription":{"text":"naming-setter"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-confusable","shortDescription":{"text":"naming-confusable"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-uninformative","shortDescription":{"text":"naming-uninformative"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-comma-operator","shortDescription":{"text":"atom-comma-operator"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-embedded-crement","shortDescription":{"text":"atom-embedded-crement"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-assign-as-value","shortDescription":{"text":"atom-assign-as-value"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-nested-ternary","shortDescription":{"text":"atom-nested-ternary"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-implicit-predicate","shortDescription":{"text":"atom-implicit-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-octal-literal","shortDescription":{"text":"atom-octal-literal"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +… [13397 more display lines; full output is 1896280 bytes on 1 raw line(s)] +````` + +Parsed summary of the same SARIF (past the display cut): + +````` +sarif 2.1.0 rules= 39 results= 6694 +````` + +## `./build/ripwire . --lint --sarif --limit=5` + +*SARIF is always the FULL result set: paging alongside it refuses loudly.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M +````` + +## `./build/ripwire . --dmm` + +*The Delta Maintainability Model scalar for the WORKING TREE vs HEAD — recorded against a CLEAN tree (the sandbox section shows a real delta). UNAVAILABLE is a stated reason, never 0 or 1.* + +**wall time: 3.44s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --dmm=HEAD` + +*The per-commit scalar: HEAD vs its first parent, with the three separately actionable sub-scores.* + +**wall time: 6.95s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --dmm=HEAD~3..HEAD` + +*The range form: tree HEAD vs tree HEAD~3.* + +**wall time: 6.88s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --cochange --cochange-groups` + +*Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none of which it depends on" — a greedy cover, disclosed as greedy.* + +**wall time: 1.51s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [847 more display lines; full output is 56290 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --cochange --cochange-recur=2` + +*Only pairs whose co-change RECURS in 2+ sub-windows of the mined window (sub_windows= is the denominator) — a one-off sprint stops reading like a structural defect.* + +**wall time: 1.48s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --html=./build/sc/aux/map2.html --color-by=community` + +*The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector).* + +**wall time: 1.51s** + +````` +(empty) +````` + +Artifact written: + +````` +156004 ./build/sc/aux/map2.html +````` + +## `./build/ripwire . --index-out=./build/sc/aux/ci_index` + +*CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout.* + +**wall time: 3.33s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --index-out wrote ./build/sc/aux/ci_index.lean.ripwirecache (28654855 bytes, lean family) +ripwire: --index-out wrote ./build/sc/aux/ci_index.rich.ripwirecache (58741710 bytes, rich family) +````` + +Artifact written: + +````` +28654855 ./build/sc/aux/ci_index.lean.ripwirecache +58741710 ./build/sc/aux/ci_index.rich.ripwirecache +87396565 total +````` + +## `./build/ripwire . --cache=./build/sc/aux/ci_index.lean.ripwirecache --top-k=3` + +*Consume the lean artifact in a PR job: restore-equivalence, never blob-byte-identity.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --pin-census=./build/sc/aux/pin_census.tsv --top-k=3` + +*Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target.* + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] +````` + +Artifact written: + +````` +# ripwire pin-census v3 C=kind\tmech\tpre\tpost\tflags\tcaller_id\tcallee\ttargets(|-sep)\tline +# v3 field escape: every id and callee field is escaped, so no separator occurs inside one. A backslash is +# written \\, TAB \t, LF \n, CR \r, every other control byte 0x00-0x1f and the targets separator | as \xHH +# (lowercase hex). Split lines on LF, fields on TAB and targets on |, THEN decode. Columns are unchanged +# from v2 and an id without those bytes is spelled exactly as in v2; a C++ out-of-line template member +# whose template-argument list spans lines keeps its line break as \n instead of splitting the row. +# line is the 1-based call-site line in the caller's file (v2, appended LAST so v1 readers are unchanged): +# the key a SCIP occurrence joins on, so a coverage loss can be classified per site instead of guessed. +129064 ./build/sc/aux/pin_census.tsv +````` + +## `./build/ripwire . --plan-lint=test/planlintfix.ave.md` + +*The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates.* + +**exit code: 2** + +````` + + + + + + + + + + + + + +````` + +## `./build/ripwire . --plan-lint=test/planlintfix.ave_ledger.md` + +*The ledger-shaped fixture through the same check (exit 2: one gating card).* + +**exit code: 2** + +````` + + + + + + + +````` + +## `./build/ripwire . --doctor --agent=claude` + +*--doctor plus a LIVE integration inspection for one agent: PATH binary, installed-skill manifest parity, hook executability, MCP wiring — read-only, fixed repair commands, never config contents; exit 1 when any check fails.* + +**exit code: 1** — **wall time: 1.63s** + +````` + + + + + + + + + + + + + +````` + +stderr: + +````` +ripwire --doctor: no ripwire resolves from PATH. To put this binary's directory first (for this shell; put the same line in your shell rc file), paste this line: +export PATH='./build':"$PATH" +````` + +## `./build/ripwire . --doctor --agent=nosuch` + +*Other --agent values refuse.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: unsupported --agent value 'nosuch' (supported: codex, claude) +````` + + +--- + +# the dirty-tree verbs (throwaway clone, NOT the read-only repo) + +Everything below runs with `cwd` = the throwaway clone at `./build/sc/dirty` (`git clone --local` of this repo, then one deliberate regression in `src/infra/sortutil.h`). The read-only repo is never touched. The binary is the same `build/ripwire`, addressed absolutely. + +## `./build/ripwire . --situ` + +*Situational report for a real diff: blast radius + tests + co-change + forgotten co-change partners.* + +**wall time: 4.68s** + +````` +ripwire situational-awareness — 1 changed file(s), 13 symbols in them +root: . +at: e47df2266+dirty + change_set: granularity=file changed_symbols=13 file_symbols=13 files_narrowed=0 files_file_granular=1 diff_hunks=7 diff_hunks_located=6 diff_hunks_unlocated=1 — seeds = symbols a diff -U0-vs-HEAD hunk overlaps (function/method body spans only); an unlocated hunk (module-level, deletion, rename) … [line truncated: 34 more bytes on this line] + [1] blast radius: 246 symbols across 58 files transitively depend on these changes (showing 8 of 58 files — shown=8 total=58 capped=1 prcontext_cap=20 (--pr-context's own per-file list is cut at 20 too); next: --situ --limit=58) + counts_floor=1 graph_ambiguous=2932 graph_unresolved=15150 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] + src/mcpverbs.h (33 dependent symbols) + src/quality.h (15 dependent symbols) + src/verbs_quality.h (14 dependent symbols) + src/verbs_for.h (13 dependent symbols) + src/editcheck.h (9 dependent symbols) + src/resolve.h (9 dependent symbols) + src/verbs_navigate.h (9 dependent symbols) + src/graph.h (8 dependent symbols) + [2] tests to run (5) order=evidence: [changed] you edited it, [partner] named after a changed file, then hops asc (1 = direct); "(n): a, b" = n runner-less files sharing that evidence; a (run: …) is relative to root: + test/verify_radix.cpp [hops=1] (run: bash test/greptiercheck.sh) + test/adaptivecutshapefix/adaptive_cut_shape_test.cpp [hops=2] (run: bash test/adaptivecutshapecheck.sh) + test/includeprecise_unit.cpp [hops=2] (run: bash test/includeprecisecheck.sh) + test/verify_csr.cpp [hops=2] (run: bash test/a9disclosurecheck.sh) + test/rustimport_unit.cpp [hops=4] (run: bash test/rustimportprecisecheck.sh) + script_gates_unmodelled=779 — test/*.sh gates never appear above: script-to-binary edges are not call edges (a path count) + [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5240": + (none — 5240 commits were mined and none co-edited a file outside your diff) + next: --test-gate +````` + +## `./build/ripwire . --test-gate` + +*The pre-PR gate with real obligations — exit 4 when tests-to-run or untested blast radius is non-empty.* + +**exit code: 4** — **wall time: 4.31s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --quality-delta` + +*Every row carries p="file:line", the gating rows are marked gating="1" and now bar= (the threshold each numeric row is judged against), and the exit-2 refusal prints a naming line on stderr; a gating row carries a pasteable next=.* + +**exit code: 2** — **wall time: 21.23s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [149 more display lines; full output is 18050 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) +````` + +## `./build/ripwire . --quality-delta --legend=full` + +*The same gating report under --legend=full — same rows, same exit 2; the default compact comment (schema="ripwire.quality-delta/v1", the shape an agent's edit loop should run) becomes ~4 KB of prose legend.* + +**exit code: 2** — **wall time: 10.88s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [149 more display lines; full output is 23042 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) +````` + +## `./build/ripwire . --quality-delta --json` + +*The same findings as JSON (one of the CI/scripting verbs --json supports) — same exit 2 as the XML form.* + +**exit code: 2** — **wall time: 10.84s** + +````` +{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"e47df2266+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] +{"kind":"complexity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":67,"p":"src/infra/sortutil.h:49","gating":true}, +{"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy","p":"src/infra/sortutil.h:119","origin":"new-symbol"}, +{"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","p":"src/infra/sortutil.h:129","origin":"new-symbol"}, +{"kind":"duplication","members":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey","tokens":59,"p":"src/infra/sortutil.h:119","gating":true}, +{"kind":"nesting","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":6,"p":"src/infra/sortutil.h:49","gating":true}, +{"kind":"new-clone-of-reused-helper","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey","was":0,"now":4,"p":"src/infra/sortutil.h:119","gating":true}, +{"kind":"params","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","was":0,"now":8,"p":"src/infra/sortutil.h:129","origin":"new-symbol"}, +{"kind":"verbosity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":8,"now":47,"p":"src/infra/sortutil.h:49","sev":"minor"}], +"sa":[{"kind":"api-surface","key":"085e3d408c2c4a35","why":"target-gone"}, +{"kind":"api-surface","key":"155d74d341a49f3c","why":"target-gone"}, +{"kind":"api-surface","key":"1a15386c2d1e47af","why":"target-gone"}, +{"kind":"api-surface","key":"298e798c7f075715","why":"target-gone"}, +{"kind":"api-surface","key":"56acdf9b5c314a14","why":"target-gone"}, +{"kind":"api-surface","key":"5a07390012b46e06","why":"target-gone"}, +{"kind":"api-surface","key":"6eef859578c8c376","why":"target-gone"}, +{"kind":"api-surface","key":"6f2394762f82a855","why":"target-gone"}, +{"kind":"api-surface","key":"7f2c3eefdf6e512e","why":"target-gone"}, +{"kind":"api-surface","key":"802e513731103806","why":"target-gone"}, +{"kind":"api-surface","key":"b6a24afef32a68a8","why":"target-gone"}, +{"kind":"api-surface","key":"c923e661c197b265","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"1926b0d9e94541a0","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"1d3814ba687a4aef","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"1db76028879244ef","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"25c9f0504fd376a4","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"36e39c7ab0fc1686","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"4bce64bd920de0c3","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"61f0e361ef7dee27","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"79625906f9f71ad0","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"8ecb190954dce18a","why":"target-gone"}, +… [146 more display lines; full output is 16644 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) +````` + +## `./build/ripwire . --quality-delta --quality-ack --ack-only=zzznope` + +*NEW FLAG: --ack-only matching nothing REFUSES rather than falling back to acking everything.* + +**exit code: 1** — **wall time: 6.53s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: ack provenance backfill — 0 clone row(s) reconstructed from the current tree, 213 re-derived, 21 left UNVERIFIED (their group was not found here — a floor, not proof it is gone), 56 left legacy (member set not found cloning here — a floor, not proof it is gone), 1311 ineligible (no cu … [line truncated: 200 more bytes on this line] +ripwire: --ack-only=zzznope matched none of the 9 finding(s) — nothing written +````` + +## `./build/ripwire . --quality-delta --quality-ack --ack-only=api-surface` + +*NEW FLAG: ack only the api-surface findings — a per-finding ratchet instead of a rubber stamp.* + +**wall time: 6.54s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: ack provenance backfill — 0 clone row(s) reconstructed from the current tree, 213 re-derived, 21 left UNVERIFIED (their group was not found here — a floor, not proof it is gone), 56 left legacy (member set not found cloning here — a floor, not proof it is gone), 1311 ineligible (no cu … [line truncated: 200 more bytes on this line] +ripwire: acknowledged 1 of 9 finding(s) (8 left UNACKED by --ack-only, 0 already acked) → ./.ripwire_quality_acks +````` + +## `./build/ripwire . --quality-delta` + +*Re-run after the partial ack: acked=3, the rest still gate (exit 2).* + +**exit code: 2** — **wall time: 10.68s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [148 more display lines; full output is 17753 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 4 preexisting-worse major finding(s); first: complexity src/infra/sortutil.h::rw::sortutil::lessByScoreDescId at src/infra/sortutil.h:49 (was=1 now=67) +````` + +## `./build/ripwire . --ack-only=gating` + +*--ack-only WITHOUT --quality-ack REFUSES loudly (exit 1, the pairing named) — it used to be silently ignored.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire

--quality-delta --ack-only=contract-change --quality-ack="reason") +````` + +## `./build/ripwire . --edit-check=nonNegativeFloatDescKey` + +*A real contract-change: was=1 now=2 params, with the call sites that are now provably incompatible, and a pasteable next= (--uses=SYM) on the root.* + +**wall time: 1.60s** + +````` + + + + + + +````` + +## `./build/ripwire . --edit-check=nonNegativeFloatDescKey --legend=full` + +*The same verdict under --legend=full: the default's one compact comment (the post-edit reflex at its cheapest) becomes ~5.7 KB of prose legend, every row identical.* + +**wall time: 1.60s** + +````` + + + + + + +````` + +## `./build/ripwire . --pr-context` + +*The review-evidence bundle with an actual changed file.* + +**wall time: 3.59s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [80 more display lines; full output is 8063 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --map-diff --top-k=5` + +*The map re-ranked with a teleport toward the changed file (changed=1 here, not 0).* + +**wall time: 2.33s** + +````` + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --clones` + +*The duplicated helper the sandbox edit introduced shows up as a clone group.* + +**wall time: 3.01s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [308 more display lines; full output is 16222 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --stray-content=zz-orphan` + +*CHANGED: a ref with NO merge base with HEAD now reports v="unknown" ok="0" in its own bucket — the absence of an answer, never a claim it is merged. (The sandbox carries a deliberately parentless branch built with `git commit-tree`; a shallow CI clone puts every ref here.)* + +**wall time: 1.59s** + +````` + + + +````` + +## `./build/ripwire . --stray-content=zz-orphan --plan` + +*CHANGED: --plan surfaces those same refs as an row rather than silently dropping them.* + +**wall time: 2.38s** + +````` + + + +````` + +## `./build/ripwire . --dmm` + +*The DMM scalar on a REAL delta: the sandbox edit grew one unit past the nesting/complexity thresholds and added an 8-parameter one, so dmm is low and the three sub-scores say which property moved.* + +**wall time: 4.22s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --quality-delta --scope=src/graph.h` + +*OWNERSHIP partition for a shared tree: every regression here lives in src/infra/, so under a scope naming src/graph.h they ALL print under with a do-not-ack banner and never gate — scoped-out-gating= says how many would have.* + +**wall time: 10.76s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [151 more display lines; full output is 18020 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +````` + +## `./build/ripwire . --quality-delta --quality-ack --scope=src/graph.h --ack-only=api-surface` + +*The rubber-stamp guard: an --ack-only that names an OUT-OF-SCOPE row refuses (exit 1) and writes nothing.* + +**exit code: 1** — **wall time: 6.40s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=src/graph.h — refusing, and writing nothing at all: + api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 + those rows belong to whoever is editing those paths. Acking them here writes their debt into a committed ledger under YOUR + reason string, which is how a per-finding ratchet becomes a rubber stamp. Narrow the pattern, or widen the scope if they really are yours. +````` + +## `./build/ripwire . --handoff` + +*The continuation packet with a REAL diff: verified changed symbols + blast radius + tests-to-run, then the heuristic rows.* + +**wall time: 3.79s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --note-add="lessByScoreDescId: keep this branch-free — it sits inside the PageRank sort comparator"` + +*Pin a field note (write-side memory) to a symbol; committed to .ripwire_notes in the sandbox. The BARE name is resolved through the same resolver the read verbs use and stored as the canonical id — the rewrite is echoed on stderr, because a silent one is not a disclosure.* + +````` +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 keep this branch-free — it sits inside the PageRank sort comparator e47df22661f8b88439e96dd63cf7ca25c0525ebe b155 +````` + +stderr: + +````` +ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why +ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sortutil.h::rw::sortutil::lessByScoreDescId' — that is the id --for/--expand key notes by +````` + +## `./build/ripwire . --notes` + +*The note is listed under the canonical id, dangling="0" — i.e. it will actually surface. (Before the H1 fix the bare name was stored verbatim and read dangling="1": recorded, and surfaced nowhere.)* + +````` + + + + + + + + + + + + + + + + gate scripts' claim (~line 1305) is NOT enforced — the derived-vs-stated sibling loop here covers docs/EVALS.md only. It drifted 407→451 unnoticed (fixed 2026-08-23). To close: grep both files ('file:line:' parsing) in the gateCountClaims arm.]]> + + + + +````` + +## `./build/ripwire . --note-add="gitOneLine: which one?"` + +*Two definitions carry this name, so the write REFUSES rather than pick one: a note keys ONE canonical id, and an ambiguous selector is refused, never silently narrowed. Every candidate is named, with a runnable retry.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why +ripwire: --note-add: target 'gitOneLine' is ambiguous — it matches 2 definitions in 2 distinct contracts, and a note keys ONE canonical id (it would surface on one of them and look absent on the rest). Qualify one: ./src/handoff.h:gitOneLine, ./src/quality.h:gitOneLine — e.g. --note-add="./src/h … [line truncated: 33 more bytes on this line] +````` + +## `./build/ripwire . --note-add="lessByScoreDescIdd: typo"` + +*A name that resolves to nothing is refused with the read verbs' own did-you-mean — never written as a dead note.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why +ripwire: --note-add: target not found: lessByScoreDescIdd (did you mean 'lessByScoreDescId'?) — a note keys the canonical id a read verb resolves; to note a FILE instead, pass a path (one with a '/' or an extension), which may name a file that does not exist yet +````` + +## `./build/ripwire . --note-add="src/infra/sortutil.h::rw::sortutil::lessByScoreDescId: chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort"` + +*The same symbol addressed by its CANONICAL id: already canonical, so nothing is rewritten and both notes land on ONE target.* + +````` +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort e47df22661f8b88439e96dd63cf7ca25c0525ebe b155 +````` + +## `./build/ripwire . --expand=lessByScoreDescId --top-k=0` + +*Both notes riding along with the symbol's body — the elements follow the body, past the display cut, so they are extracted below.* + +````` + + + + + + + + + + + + + +````` + +## `./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h` + +*Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call.* + +**wall time: 4.63s** + +````` +{"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":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} +````` + +stderr: + +````` +ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: bash test/greptiercheck.sh +````` + +## `./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h --no-post-check` + +*The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr.* + +**wall time: 2.19s** + +````` +{"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] +````` + +stderr: + +````` +ripwire edit: applied atomically; receipt carries region, blob_sha (post-check skipped); next: --edit-check=src/infra/sortutil.h:lessByScoreDescId +````` + +## `./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=./build/sc/aux/payload_note.h --edit-target-file=src/infra/sortutil.h` + +*Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured).* + +**wall time: 5.07s** + +````` +{"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] +{"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":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} +````` + +stderr: + +````` +ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: --uses=src/infra/sortutil.h:nonNegativeFloatDescKey +````` + +## `./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc/aux/payload_note.h` + +*An unknown TARGET refuses and leaves every file byte-identical.* + +**exit code: 1** — **wall time: 2.15s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --replace-symbol-body: symbol 'DoesNotExist' not found +````` + +## `./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json --dry-run` + +*A versioned multi-edit TRANSACTION preflighted without writing: the receipt shows what each op would read and touch.* + +**wall time: 2.20s** + +Input file: + +````` +{ + "version": 1, + "edits": [ + { + "op": "insert_before_symbol", + "target": "nonNegativeFloatDescKey", + "payload": "plan_note.h" + } + ] +} +````` + +````` +{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 282 more bytes on this line] +````` + +## `./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json --apply` + +*The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure.* + +**wall time: 4.65s** + +````` +{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15150,"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: 466 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":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true}}]} +````` + +## `./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json` + +*Neither --dry-run nor --apply: the mode is explicit, so this refuses.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --edit-plan requires exactly one of --dry-run or --apply +````` + +## `./build/ripwire . --quality-delta` + +*After the agent's edits: the complexity/nesting rows on lessByScoreDescId are gone (the replace undid them), the rest still gate (exit 2).* + +**exit code: 2** — **wall time: 11.11s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [145 more display lines; full output is 17117 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 2 preexisting-worse major finding(s); first: duplication src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:88 (was=0 now=59) +````` + +## `./build/ripwire . --quality-baseline` + +*REFUSES, exit 1: this sandbox tree is already regressed, and pinning here would swallow that debt into the floor so every later delta read clean. It names how many gating findings it would absorb, the first of them, and the way forward.* + +**exit code: 1** — **wall time: 6.47s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --quality-baseline: this tree already holds 2 gating finding(s) against HEAD — pinning here would absorb + them into the floor, and every later --quality-delta would read clean. First: duplication src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey (was=0 now=59) + Commit the tree first, or pass --allow-dirty to pin anyway (the sidecar then records the 2 absorbed, and every + report against it carries baseline_absorbed="2"). +````` + +## `./build/ripwire . --quality-baseline --allow-dirty` + +*The consent form: pin anyway. The sidecar is stamped with the dirty pin and the absorbed count, so the fact outlives the process that knew it.* + +**wall time: 10.05s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --quality-baseline --allow-dirty: pinned with 2 gating finding(s) ABSORBED into the floor (stamped in the sidecar; every --quality-delta against it carries baseline_absorbed="2") +ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30766 per-symbol rows, 31704 indexed symbols total) +````` + +Artifact written: + +````` +5208125 .ripwire_quality_baseline +# ripwire quality baseline v6 — regenerate with --quality-baseline; do not hand-edit +producer 95a5aa40644062cd8ddb0c7725ac755d112333f011e507d1c703684c2d334646 +head e47df22661f8b88439e96dd63cf7ca25c0525ebe +dirty 1 +absorbed 2 +ccx 67c15011ee8b 0 +ccx d19d7c13cbc7 2 +ccx 1f7edbff929e5 10 +ccx 6a732f6699b +````` + +## `./build/ripwire . --quality-delta` + +*Against that sidecar the same tree reads regressions=0 — but baseline_absorbed= is on the root, so this green means clean SINCE THE PIN, never clean. A baseline is a floor YOU chose, and it belongs BEFORE the change.* + +**wall time: 10.86s** + +````` + + +````` + + +--- + +# the MCP dialect — the same verbs over stdio JSON-RPC (one-shot exchange, not a persistent server) + +## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ./build/ripwire --mcp` + +*initialize + tools/list: the manifest an agent host loads at session start — every verb's name, description and input schema.* + +````` +{"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: 738 more bytes on this line] +{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"analyze","description":"Architecture map for a directory: signatures and the call graph for the top symbols. Use when landing cold in a repo or subdir, before reading files; for a task-scoped inventory use 'for', for one symbol's neighborhood find_ … [line truncated: 742 more bytes on this line] +{"name":"rank_by","description":"The SAME architecture map 'analyze' serves, ranked by a different signal instead of plain PageRank. rank_by = pagerank (default, omit it — the CLI's own unbiased --rank-by=pagerank; 'analyze' can rank differently on a tree with uncommitted changes, where it biases … [line truncated: 1077 more bytes on this line] +{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read.rite/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] +{"name":"find_referencing_symbols","description":"Direct (1-hop) callers of a symbol, each with a fetch_body handle. For the full transitive blast radius use 'impact', for read.rite/import sites 'uses'. JSON {symbol, calledBy, defs, count, hop_tested, hop_untested, declined_calls, counts_floor}; ca … [line truncated: 945 more bytes on this line] +{"name":"grep","description":"Trigram literal search; each hit annotated with its enclosing symbol (which function/class it is in). Hits carry text; enclosing rows a fetch_body handle. pattern = the literal; in=any lifts the span tiering (default: tightest non-empty tier; rest rides as suppressed_co … [line truncated: 837 more bytes on this line] +{"name":"cochange","description":"Files that historically change together with this file — the co-edit partners. Fowler's Shotgun Surgery as change coupling. dep_capable=false means neither side could carry one (sh/md/json/binary), so surprising is undefined rather than informative. file = the fil … [line truncated: 700 more bytes on this line] +{"name":"memory_recall","description":"Most relevant memory notes / docs for a task, full text — the few that matter, not the whole corpus. path = docs/memory dir; task = what you're working on; top_k = docs to return, 1..1000 (default 8), refused outside that band, never clamped; budget_tokens = … [line truncated: 790 more bytes on this line] +{"name":"situational_awareness","description":"The 5 things to know about a diff, as JSON: blast_radius, tests_to_run, forgotten (usual co-change partners missing from this diff), hotspot_alert, modules_touched. forgotten = the Shotgun Surgery check. diff/files optional — defaults to 'git diff HEA … [line truncated: 1297 more bytes on this line] +{"name":"mentions","description":"Docs (markdown plans/designs) that name a code symbol in a backtick. symbol = the code symbol name; limit/offset page the files. An @FILE:LINE line-seed rebinds to the innermost definition enclosing that line and answers for it, disclosing the rebound name as 'sym' … [line truncated: 625 more bytes on this line] +{"name":"for","description":"Task-lens ranked, signatures-only inventory of the building blocks most relevant to a task (cx=complexity, in=reuse-count). task = the task in plain words; budget_tokens = an optional soft row target (the CLI --for --token-budget). The header carries route= (which ranker … [line truncated: 1061 more bytes on this line] +{"name":"lego","description":"Interface-to-impls view for ONE named interface/base: its method contract plus EVERY implementor (own-language only), each with file path. Use when implementing against a KNOWN interface (contrast 'for', which sprays top interfaces for a task). type = interface/base nam … [line truncated: 841 more bytes on this line] +{"name":"owners","description":"Bus-factor: recency-weighted (6-month half-life) author ownership per file. symbol = optional, restricts to the file that defines it; limit/offset page the rows. at= is the commit these numbers were computed at (+dirty = the working tree differed). An @FILE:LINE line- … [line truncated: 879 more bytes on this line] +{"name":"replace_symbol_body","description":"Replace a symbol's ENTIRE definition (signature through closing brace) with new_body — splices over the full def span, preserving every byte outside it verbatim; new_body must be a complete, well-formed definition. One trailing newline folds (trailing_n … [line truncated: 1323 more bytes on this line] +{"name":"insert_before_symbol","description":"Insert text immediately BEFORE a symbol's definition (its first byte); padded to the file's own blank-line seam (separator_padded=N). Same refusal contract as replace_symbol_body (not found / ambiguous / stale index / symlink / concurrent write, file unc … [line truncated: 877 more bytes on this line] +{"name":"insert_after_symbol","description":"Insert text immediately AFTER a symbol's definition (past its final byte, which is preserved exactly); padded to the file's own blank-line seam (separator_padded=N); one trailing newline folds (trailing_newline_folded). Same refusal contract as replace_sy … [line truncated: 878 more bytes on this line] +{"name":"fetch_body","description":"Full (or partial-range) source of a symbol's definition, addressed by the stable `handle` a read verb attached to it (bodies on request, not by default). start_line/end_line are optional, 1-based, INCLUSIVE and BODY-RELATIVE (line 1 = the def's first line), clampe … [line truncated: 1049 more bytes on this line] +{"name":"exemplar","description":"BEFORE writing a function / method / class / struct / interface / variable, get the repo's single best-in-class instance of that kind to imitate — signature AND full body. chosen by ROLE, NEVER by text similarity to your task: candidates are first filtered to cogn … [line truncated: 1375 more bytes on this line] +{"name":"quality_delta","description":"Your PR self-check, run every time you think a change is DONE — pairs with the CLI-only --test-gate (names the tests to run + the untested blast radius; not MCP-exposed) to form the two-step pre-PR gate. Reports ONLY what your working tree made WORSE vs basel … [line truncated: 862 more bytes on this line] +{"name":"quality_baseline","description":"PIN the quality floor: writes .ripwire_quality_baseline stamped with the current git HEAD sha, snapshotting complexity / duplication / dead-code / API surface. Call once at the start of non-trivial work, then quality_delta compares against this pinned floor … [line truncated: 445 more bytes on this line] +{"name":"impact","description":"IS IT SAFE TO CHANGE X? — the TRANSITIVE blast radius of a symbol via calls, nearest first (d= hop depth), then PageRank. Use before modifying or deleting a symbol; it beats find_referencing_symbols (direct callers only), and 'uses' catches the read.rite/import sit … [line truncated: 1325 more bytes on this line] +{"name":"uses","description":"The STATICALLY RESOLVABLE use-sites of a symbol, not just calls: role (call | read | write | import | extends), file:line, and enclosing symbol. Use to see the footprint before renaming or changing a name — find_referencing_symbols and impact follow only calls. extern … [line truncated: 1146 more bytes on this line] +{"name":"affected","description":"WHICH TESTS TO RUN for a change — test files that transitively reach the changed files/symbols, ranked by evidence (edited > partner-named > hop distance). files = changed files and/or symbols, comma-separated: each item is tried as an indexed PATH pattern first, … [line truncated: 1238 more bytes on this line] +{"name":"path_between","description":"Does A REACH B, and HOW? — the shortest directed CALL path between two symbols, hop-by-hop. reachable=\"0\" hops=\"0\" is a valid 'not reachable' answer — call edges are name-based, so a missing dynamic/callback edge can hide a real path. Named path_between … [line truncated: 709 more bytes on this line] +{"name":"connect","description":"When a task touches 2..16 named symbols, returns the minimal subgraph RELATING them - terminals, the fewest joining intermediaries (with signatures), and call edges in true direction - finding the shared-caller joins a directed path_between cannot; unrelated symbols … [line truncated: 950 more bytes on this line] +{"name":"explore","description":"ONE-call task orientation: the routed+anchored ranking, full bodies of the top hits, their 1-hop callers, field notes, and tests_to_run — ALL under one deterministic byte budget, in a fixed section order (ranking > bodies > callers > notes > tests) that degrades gr … [line truncated: 2135 more bytes on this line] +{"name":"from_trace","description":"Paste a stack trace / sanitizer report / compiler error and get it mapped onto indexed symbols, ranked INNERMOST-first: the parsed frame map, the ranked suspects' signatures, and the innermost in-corpus symbol's FULL body. Out-of-corpus frames are listed a … [line truncated: 1233 more bytes on this line] +{"name":"edit_check","description":"Just edited a symbol? Did its CONTRACT (param count + publicness) change vs git HEAD, and which 1-hop callers are NOW INCOMPATIBLE with the new arity by fixed-arity evidence (not a guess — every folded definition disagrees)? This is call sites worth OPENING, not … [line truncated: 1908 more bytes on this line] +{"name":"whereis","description":"WHERE DOES THIS CONTENT LIVE? Which branch's tree defines or mentions a symbol, HEAD first, with on-head=0 naming the case this verb exists for: content that lives only on a branch (a finished fix stranded on 1 of 30 refs). Each distinct blob is read once (content-ad … [line truncated: 1475 more bytes on this line] +{"name":"stray_content","description":"Per branch: the lines its own divergent work AUTHORED (vs its merge-base with HEAD) that the live line does NOT have. Four verdicts (unmerged+superseded+merged+unknown=refs): v=unmerged is genuinely absent; v=superseded means the live line re-implemented the wo … [line truncated: 1123 more bytes on this line] +{"name":"flags","description":"WHAT IS BUILT BUT DARK here — the answer to 'why don't I see feature X?'. Harvests all three gate patterns (ifndef/define header gates, CMake option(), getenv reads) with each gate's kind, DEFAULT, the size of the code it guards, and its read sites. When a name is bo … [line truncated: 1434 more bytes on this line] +{"name":"doc_drift","description":"WHICH OF THIS REPO'S DOC CLAIMS ARE NOW FALSE. Verifies the CHECKABLE anchors in every markdown file against the live index and returns ONLY the ones that no longer hold: file:line refs (missing-file / past-eof / line-moved), backticked symbol mentions (undefined), … [line truncated: 1167 more bytes on this line] +{"name":"slice","description":"WHERE IS THIS VARIABLE DEFINED AND USED inside one function — NAME-BASED intra-procedural def-use rows of one variable inside ONE uniquely-resolved definition (the ARISE slicer, arXiv:2605.03117). symbol alone lists the sliceable locals to pick from; add var (or spel … [line truncated: 1722 more bytes on this line] +{"name":"batch","description":"ONE-TURN CONTEXT SWEEP: answer up to 16 heterogeneous READ sub-queries in a single call (the deterministic $0 counterpart of a parallel-search agent). queries = array over the SAME path, in EITHER grammar: {verb, ...args} objects, or the CLI --batch file's own \"verb:a … [line truncated: 2040 more bytes on this line] +````` + +The manifest, summarised (name / description bytes / required args) — what the host pays in context every session: + +````` +tools= 33 manifest_bytes= 47445 (~tokens at 4 bytes/token: 11861 ) +explore desc_bytes= 1340 schema_bytes= 958 required=['task'] +batch desc_bytes= 1235 schema_bytes= 962 required=['queries'] +edit_check desc_bytes= 1180 schema_bytes= 889 required=['symbol'] +slice desc_bytes= 953 schema_bytes= 932 required=['symbol'] +whereis desc_bytes= 701 schema_bytes= 941 required=['symbol'] +flags desc_bytes= 881 schema_bytes= 720 required=[] +exemplar desc_bytes= 954 schema_bytes= 591 required=[] +replace_symbol_body desc_bytes= 865 schema_bytes= 610 required=['symbol', 'new_body'] +impact desc_bytes= 821 schema_bytes= 666 required=['symbol'] +situational_awareness desc_bytes= 865 schema_bytes= 581 required=[] +affected desc_bytes= 790 schema_bytes= 610 required=['files'] +from_trace desc_bytes= 836 schema_bytes= 559 required=['trace'] +find_symbol desc_bytes= 752 schema_bytes= 590 required=['symbol'] +doc_drift desc_bytes= 728 schema_bytes= 604 required=[] +uses desc_bytes= 626 schema_bytes= 682 required=['symbol'] +stray_content desc_bytes= 678 schema_bytes= 604 required=[] +rank_by desc_bytes= 758 schema_bytes= 481 required=[] +for desc_bytes= 453 schema_bytes= 777 required=['task'] +fetch_body desc_bytes= 623 schema_bytes= 588 required=['handle'] +connect desc_bytes= 535 schema_bytes= 580 required=['symbols'] +find_referencing_symbols desc_bytes= 505 schema_bytes= 590 required=['symbol'] +insert_after_symbol desc_bytes= 458 schema_bytes= 577 required=['symbol', 'text'] +insert_before_symbol desc_bytes= 455 schema_bytes= 578 required=['symbol', 'text'] +owners desc_bytes= 425 schema_bytes= 625 required=[] +quality_delta desc_bytes= 742 schema_bytes= 279 required=[] +lego desc_bytes= 360 schema_bytes= 651 required=['type'] +grep desc_bytes= 445 schema_bytes= 562 required=['pattern'] +memory_recall desc_bytes= 447 schema_bytes= 500 required=['task'] +path_between desc_bytes= 357 schema_bytes= 506 required=['from', 'to'] +cochange desc_bytes= 388 schema_bytes= 476 required=['file'] +analyze desc_bytes= 546 schema_bytes= 318 required=[] +mentions desc_bytes= 305 schema_bytes= 486 required=['symbol'] +quality_baseline desc_bytes= 407 schema_bytes= 193 required=[] +````` + +## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ./build/ripwire --mcp --mcp-tools=core` + +*--mcp-tools=core: the server lists only the core profile's tools (explore, batch, from_trace, impact, uses, fetch_body, edit_check, quality_delta), so a host that loads every schema at session start pays only for those.* + +````` +{"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: 955 more bytes on this line] +{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"fetch_body","description":"Full (or partial-range) source of a symbol's definition, addressed by the stable `handle` a read verb attached to it (bodies on request, not by default). start_line/end_line are optional, 1-based, INCLUSIVE and BODY-RELAT … [line truncated: 1092 more bytes on this line] +{"name":"quality_delta","description":"Your PR self-check, run every time you think a change is DONE — pairs with the CLI-only --test-gate (names the tests to run + the untested blast radius; not MCP-exposed) to form the two-step pre-PR gate. Reports ONLY what your working tree made WORSE vs basel … [line truncated: 862 more bytes on this line] +{"name":"impact","description":"IS IT SAFE TO CHANGE X? — the TRANSITIVE blast radius of a symbol via calls, nearest first (d= hop depth), then PageRank. Use before modifying or deleting a symbol; it beats find_referencing_symbols (direct callers only), and 'uses' catches the read.rite/import sit … [line truncated: 1325 more bytes on this line] +{"name":"uses","description":"The STATICALLY RESOLVABLE use-sites of a symbol, not just calls: role (call | read | write | import | extends), file:line, and enclosing symbol. Use to see the footprint before renaming or changing a name — find_referencing_symbols and impact follow only calls. extern … [line truncated: 1146 more bytes on this line] +{"name":"explore","description":"ONE-call task orientation: the routed+anchored ranking, full bodies of the top hits, their 1-hop callers, field notes, and tests_to_run — ALL under one deterministic byte budget, in a fixed section order (ranking > bodies > callers > notes > tests) that degrades gr … [line truncated: 2135 more bytes on this line] +{"name":"from_trace","description":"Paste a stack trace / sanitizer report / compiler error and get it mapped onto indexed symbols, ranked INNERMOST-first: the parsed frame map, the ranked suspects' signatures, and the innermost in-corpus symbol's FULL body. Out-of-corpus frames are listed a … [line truncated: 1233 more bytes on this line] +{"name":"edit_check","description":"Just edited a symbol? Did its CONTRACT (param count + publicness) change vs git HEAD, and which 1-hop callers are NOW INCOMPATIBLE with the new arity by fixed-arity evidence (not a guess — every folded definition disagrees)? This is call sites worth OPENING, not … [line truncated: 1908 more bytes on this line] +{"name":"batch","description":"ONE-TURN CONTEXT SWEEP: answer up to 16 heterogeneous READ sub-queries in a single call (the deterministic $0 counterpart of a parallel-search agent). queries = array over the SAME path, in EITHER grammar: {verb, ...args} objects, or the CLI --batch file's own \"verb:a … [line truncated: 2040 more bytes on this line] +````` + +The core manifest, summarised (name / description bytes / required args): + +````` +tools= 8 manifest_bytes= 14186 (~tokens at 4 bytes/token: 3546 ) +explore desc_bytes= 1340 schema_bytes= 958 required=['task'] +batch desc_bytes= 1235 schema_bytes= 962 required=['queries'] +edit_check desc_bytes= 1180 schema_bytes= 889 required=['symbol'] +impact desc_bytes= 821 schema_bytes= 666 required=['symbol'] +from_trace desc_bytes= 836 schema_bytes= 559 required=['trace'] +uses desc_bytes= 626 schema_bytes= 682 required=['symbol'] +fetch_body desc_bytes= 623 schema_bytes= 588 required=['handle'] +quality_delta desc_bytes= 742 schema_bytes= 279 required=[] +````` + +## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"for","arguments":{"path":".","task":"pagerank power iteration"}}}' | ./build/ripwire --mcp` + +*MCP `for`: always bundle=sigs (never the CLI's compact route), the same ranked signatures as --for.* + +**wall time: 1.45s** + +````` +{"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: 738 more bytes on this line] +{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":". window: shown= capped= (capped=1 cut). at=: commit+dirty+shallow. next= … [line truncated: 1194 more bytes on this line] +"_index":"[index: files=3607 symbols=31702 hash=1d175297]","_fresh":"ok"}} +{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":" - + - + - + @@ -106,14 +106,14 @@ _The same capped map without its inventory tier: --top-k=5 leaves files out, so $ ./build/ripwire . --top-k=5 --no-inventory - + - + - + @@ -140,10 +140,10 @@ _SHAPE the map to fit ~1500 tokens (binary-search top-K)._ $ ./build/ripwire . --max-tokens=1500 - + - + @@ -211,17 +211,17 @@ STOPS WHEN COMPLETE: the ranked head (: the relevance floor within **Try it** -_Name-shaped query: the router picks name-exact BM25 (header says which.hy)._ +_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=952 -━━ commands.md (relevance 10.054) ━━ [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] -### `--field-affinity[=STRUCT]` +━━ commands.md (relevance 10.880) ━━ [sections: 1 of 165 selected (192 in doc), section-granular; whole doc 594792 B; lines="555-580"; dropped_by_budget=164] [truncated: 1854 of 4256 bytes] +#### Pattern: a directory of dumped tool output as a knowledge base -**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. +**Answers:** can `--recall` serve as a zero-setup knowledge base over dumped tool output — a +`git log`, an API response dump, a fetched doc, ` --help` text — sitting in a scratch +directory, instead of a source repo? -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] +Yes, unmodified. `--recall` never distinguishes "a codebase" from any other directory it can +walk: point it at the scratch dir and query it. No index to build, no daemon, no mutable store +between runs — the whole cost is one cold parse. Two conditions decide whether it works at all, +and both are yours, because the file you write is the only thing that sets them: -(capped: 1 of 2 relevant document files omitted — raise --max-tokens/budget_tokens or narrow the query for 1 more (~2548-byte budget)) +... [17 more line(s); run it to see the whole thing] ``` ### `--tree` @@ -623,7 +628,7 @@ _File-by-file orientation map (top symbols per file)._ ``` $ ./build/ripwire . --tree - + @@ -632,7 +637,7 @@ $ ./build/ripwire . --tree - + @@ -657,7 +662,7 @@ A navigation or report verb answers instead of the map, so --html beside one ref _Self-contained HTML force-directed call graph._ ``` -$ ./build/ripwire . --html=./build/sc/aux/map2.html +$ ./build/ripwire . --html=/aux/map2.html (empty) ``` @@ -678,7 +683,7 @@ the flag only sets the initial mode _The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector)._ ``` -$ ./build/ripwire . --html=./build/sc/aux/map2.html --color-by=community +$ ./build/ripwire . --html=/aux/map2.html --color-by=community (empty) ``` @@ -727,14 +732,14 @@ _--no-stable outside --mcp: what the flag does (or says) when there is no stable $ ./build/ripwire . --no-stable --top-k=3 - + - + - + @@ -761,7 +766,7 @@ $ ./build/ripwire . --around=rankGraphTeleport - + @@ -813,18 +818,18 @@ _What SYM calls (1-hop out-edges)._ ``` $ ./build/ripwire . --callees=rankGraphTeleport - - + + - - - - - - + + + + + + ``` @@ -843,15 +848,15 @@ external="1" if SYM has no in-corpus def. file:name or a "::" spelling narrows d **Try it** -_The resolvable use-sites (call/read.rite/import/extends) with file:line; count= is a floor._ +_The resolvable use-sites (call/read/write/import/extends) with file:line; count= is a floor._ ``` $ ./build/ripwire . --uses=rankGraphTeleport - + - - + + @@ -882,13 +887,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,12 +924,12 @@ _Names referenced but never defined in-corpus (stdlib/third-party surface). The ``` $ ./build/ripwire . --external-surface - - - - - - + + + + + + @@ -954,12 +959,12 @@ _Shortest directed call-path SRC -> DST. CHANGED: now reports from_p/to_p/from_d ``` $ ./build/ripwire . --path=main,rankGraphTeleport - + - + ``` @@ -976,10 +981,10 @@ _Minimal connecting subgraph over 3 symbols (finds shared-caller joins)._ ``` $ ./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex - + - + @@ -1086,7 +1091,7 @@ _Test files that transitively reach the changed file._ ``` $ ./build/ripwire . --affected=src/graph.h - @@ -1143,7 +1148,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: e47df2266 +at: c97f6f91c (0 changed files — working tree is clean, nothing to analyze) ``` @@ -1161,17 +1166,21 @@ _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] ``` **Caveats (stated by the binary):** @@ -1193,7 +1202,7 @@ _Pre-PR gate on a CLEAN tree: no obligations, exit 0._ ``` $ ./build/ripwire . --test-gate - ``` @@ -1218,7 +1227,7 @@ _Literal trigram-indexed search. Each hit carries its MATCHED line as the $ ./build/ripwire . --grep=DISCLOSE - + - + - + @@ -1520,7 +1529,7 @@ _Importance-weighted detail: FULL bodies for top-2, signatures for the rest._ ``` $ ./build/ripwire . --for="pagerank power iteration" --detail=2 - + @@ -1555,14 +1564,14 @@ $ ./build/ripwire . --pack-signatures --top-k=10 - + - + - + ... [17 more line(s); run it to see the whole thing] @@ -1586,7 +1595,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)" ); @@ -1617,7 +1626,7 @@ $ ./build/ripwire . --top-k=0 --expand=rankGraphTeleport - + of ; resolved callees. window: shown= total= capped= (capped=1 cut). sibs_capped=/inc_capped=: 1 = cut. est_tokens=: price as emitted (an upper bound under compact). root=: p= relative to it. : that callee matched by name alone (receiver unproven); it does NOT mean the edge is fal … [line truncated: 443 more bytes on this line] -: that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> - + - + - + @@ -1789,9 +1798,9 @@ _File->file dependency graph (god-files, cycles)._ ``` $ ./build/ripwire . --deps - - - + + + @@ -1826,10 +1835,10 @@ _Complexity x recent git churn (maintenance pain)._ $ ./build/ripwire . --hotspots - - + + - + @@ -1854,17 +1863,17 @@ _Token-normalized duplicate bodies._ ``` $ ./build/ripwire . --clones - + - + - + ... [17 more line(s); run it to see the whole thing] @@ -1885,8 +1894,8 @@ _Per-function size ranking, largest Halstead volume/token entropy/lines first ``` $ ./build/ripwire . --biggest-first --limit=8 - - + + @@ -1918,7 +1927,7 @@ _Per function, the non-local MUTABLE state it can reach (transitively), most wri ``` $ ./build/ripwire . --nonlocal-state --limit=8 - @@ -1953,7 +1962,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -1984,17 +1993,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] @@ -2021,13 +2030,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] ``` @@ -2052,7 +2061,7 @@ _Score the naming-* rules against this repo's own rename history: proxy=old/(old ``` $ ./build/ripwire . --naming-calibration - + @@ -2087,9 +2096,9 @@ _The corpus's OWN case-convention vote per (language, kind) group; off-conventio ``` $ ./build/ripwire . --naming-consistency --limit=8 - - - + + + @@ -2124,7 +2133,7 @@ _The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/ ``` $ ./build/ripwire . --lint --naming-locals - + @@ -2159,7 +2168,7 @@ _Functions WITH a doc comment, most name-restating first: c_coeff (high = the co ``` $ ./build/ripwire . --comment-coherence --limit=8 - + @@ -2192,16 +2201,16 @@ _Files that change together in git (hidden coupling)._ ``` $ ./build/ripwire . --cochange - - + + + - - + + - - - + + ... [22 more line(s); run it to see the whole thing] ``` @@ -2224,16 +2233,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] ``` @@ -2250,7 +2259,7 @@ _Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none ``` $ ./build/ripwire . --cochange --cochange-groups - + @@ -2279,19 +2288,19 @@ _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] ``` @@ -2317,11 +2326,11 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - - + @@ -2347,11 +2356,11 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - - + @@ -2373,11 +2382,11 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - - + @@ -2400,7 +2409,7 @@ _Built-in AST checks (c-cast, goto, unsafe-c-fn, ...)._ ``` $ ./build/ripwire . --lint - + @@ -2439,7 +2448,7 @@ $ ./build/ripwire . --lint-catalog a C-style cast — cppcoreguidelines-pro-type-cstyle-cast prefers the explicit static_cast/const_cast/reinterpret_cast a goto statement — cppcoreguidelines-avoid-goto -a do.hile loop shape (on Swift, its do/catch block shares the same grammar node and also matches) +a do/while loop shape (on Swift, its do/catch block shares the same grammar node and also matches) a call to an unbounded C string function (strcpy/strcat/sprintf/gets) a call to a broken hash or cipher (MD5/SHA1/MD4/RC4) a doubly-parenthesized expression — readability-redundant-parentheses @@ -2623,15 +2632,15 @@ _Cluster the call graph into cohesive modules._ ``` $ ./build/ripwire . --communities - + - + - + @@ -2654,7 +2663,7 @@ _Drill into ONE call-graph community by id — the drill= the --communities outp ``` $ ./build/ripwire . --community=0 - ``` @@ -2679,15 +2688,15 @@ _Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels ``` $ ./build/ripwire . --zoom - - + + - - + + - + @@ -2716,15 +2725,15 @@ $ ./build/ripwire . --report # ripwire architecture report -3607 files · 31702 symbols · 29921 edges · 3598 modules (14863 call-graph isolated) +3589 files · 31640 symbols · 29882 edges · 3588 modules (14830 call-graph isolated) Root: `.` -Call-graph isolate provenance: 3961 declaration, 2444 header, 3343 source, 5115 document; 0 connected Louvain singletons +Call-graph isolate provenance: 3951 declaration, 2444 header, 3330 source, 5105 document; 0 connected Louvain singletons -## Modules (call-graph clusters; showing 12 of 3598) -- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1618 symbols -- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 548 symbols +## Modules (call-graph clusters; showing 12 of 3588) +- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1617 symbols +- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 547 symbols - **src::DISCLOSE@infra/Diagnostics.h:616:43369 [read,compute,resolve]** — 335 symbols ... [17 more line(s); run it to see the whole thing] ``` @@ -2742,7 +2751,7 @@ _Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped._ ``` $ ./build/ripwire . --seams - + @@ -2773,15 +2782,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
9389"] + n102["src
9384"] n103["src/infra
1301"] end subgraph sg1 ["test"] - n104["test
5507"] - n568["test/legochargefix
546"] - n405["test/fixtures/recallpassage
314"] - n953["test/slotjoinfix
175"] - n795["test/ownerhopfix/py/pkg
158"] + n104["test
5501"] + n559["test/legochargefix
546"] + n400["test/fixtures/recallpassage
314"] + n944["test/slotjoinfix
175"] + n786["test/ownerhopfix/py/pkg
158"] n342["test/expandmodefix
151"] n344["test/expandsibsfix
149"] ... [17 more line(s); run it to see the whole thing] @@ -2802,13 +2811,13 @@ _Bus-factor: recency-weighted author ownership per file._ ``` $ ./build/ripwire . --owners - - + + - - - + + + @@ -2833,7 +2842,7 @@ _Internal functions with no caller found in the index — a name-based graph rea ``` $ ./build/ripwire . --dead-code=src - + ``` @@ -2897,8 +2906,8 @@ _The same clean verdict with what it folded printed back: every stale acknowledg ``` $ ./build/ripwire . --quality-delta --show-stale - -, acked. value-ref-excluded=N: internal functions kept off because a table, field or argument in another function or at file scope holds them (matched by name, not a proven call); a floor. at=: commit+dirty+shallow. stale=N: ack ledger rows whose target no longer applies (sa rows); never gating. preexisting-worse=N: regressions on symbols that existed at baseline; they gate when major. new-symbol=N: findings on NEW code; new-symbol rows never gate, except defect-shape format-arity. register-macro-excluded=N: symbols kept out of dead-code as self-registering test/bench macros; a floor. declined-call-excluded=N: symbols kept out of dead-code only because a declined call may mean them; a floor. api-new-surface=N: new PUBLIC symbols; a count, never gates, not in regressions=. renames=/rename_window_commits=: git rename pairs read over that many commits, to re-file baseline and acks. acked_by_rename=/acked_by_content=: acked= suppressions matched via git renames / an equal body hash. renames_window_truncated=1: history is deeper than the rename window, older renames unread. acked=N: findings suppressed by the ack ledger, listed as sa rows; never gating. sa key=/why=: the stale ack's ledger hash / target-gone (names nothing now) or finding-gone (no longer fires). head_basis=identity: the floor is this tree's own snapshot; archived-index-hidden: refused, a tracked path is skip-worktree/assume-unchanged; absent: the archived HEAD tree. --> + @@ -2927,7 +2936,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2952,7 +2961,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2977,7 +2986,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 -

--callers=SYM --json) -````` - -## `./build/ripwire . --hotspots --limit=3 --offset=3` - -*Pagination: 3 items, skipping the first 3 (deterministic seams).* - -**wall time: 1.44s** - -````` - - - - - - - -````` - -## `./build/ripwire . --ignore-tests --top-k=5` - -*Drop test paths from the corpus before ranking.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [67 more display lines; full output is 8115 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --exclude=present --exclude=bench --top-k=5` - -*Drop matching paths (repeatable) before ranking.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [65 more display lines; full output is 8095 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --map-diff --top-k=5` - -*Full map re-ranked with teleport toward git-changed files — clean tree, so changed=0 and it degrades to the plain map.* - -````` - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --no-cache --top-k=3` - -*Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm cost.* - -**wall time: 1.64s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --cache=./build/sc/aux.arm2.ripwirecache --top-k=3` - -*Explicit incremental cache at a path OUTSIDE the repo (first call writes it).* - -**wall time: 1.68s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] -````` - -Artifact written: - -````` -28654855 ./build/sc/aux.arm2.ripwirecache -````` - -## `./build/ripwire . --max-file-size=8K --top-k=3` - -*Skip files above a size bound before parsing (note the corpus shrink in the header).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [18 more display lines; full output is 4246 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --scip=does_not_exist.scip --callers=rankGraphTeleport` - -*SCIP overlay with a missing index REFUSES (exit 1) naming the file — never silently serves the name-based map you named a precision index to improve on (it used to degrade in silence).* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather than serving the name-based map you named a precision index to improve on (generate one with scip-clang/scip-python, or drop --scip) -````` - -## `./build/ripwire src test --top-k=5` - -*Multi-root workspace: ONE merged graph over two roots, paths labeled /.* - -**wall time: 1.83s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --eval` - -*Self-eval: co-change recall vs BM25.* - -**wall time: 18.51s** - -````` -ripwire --eval (co-change recovery, averaged over 80 historical commits) - ranker recall@5 recall@10 recall@20 - ripwire 4.7% 6.4% 16.6% - BM25 9.3% 14.1% 16.6% - BM25sub 10.8% 21.2% 27.7% - BM25body 15.3% 21.0% 30.4% - fused 11.8% 13.3% 24.8% - anchored 15.3% 21.3% 30.7% - same-dir 0.9% 4.6% 8.4% - random 0.1% 0.3% 0.6% <- floor (random ranking over F=3607 files) - note: `ripwire` here is the DEFAULT MAP's structural-only PageRank (importance, not - relatedness) — it is NOT what a --for/--query retrieval call ranks with. BM25 / - BM25sub / BM25body are QUERY-TIME lexical rankers (whole-name / subtoken / - subtoken+body); fused = RRF(ripwire, BM25sub); anchored = BM25body + anchored PPR - expansion (--for --anchor, EXPERIMENTAL). The SHIPPED default for --for/--query is - the subtoken+body lexical family (routed to name-exact only for an identifier-shaped - query — lexical.h chooseForRanker), so a gap between the ripwire and BM25* rows here - is structural-importance-vs-lexical-relatedness on a co-change task, not the shipped - retrieval path losing to an alternative it was never running. -````` - -## `./build/ripwire . --eval-retrieval` - -*Known-item retrieval eval: MRR + recall@k per ranker per query mode.* - -**wall time: 187.37s** - -````` -ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-corpus by construction) - sample: population=7974 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population - (smallest fnv1a64(scope::name) over the population, cut on the key so an identity is never split; - path- and order-independent, but a corpus this size is NOT graded exhaustively — say so when citing it) - ingest: lex=rich (persisted subtoken stats; no per-query corpus re-tokenize) - ranker query-mode MRR recall@1 recall@5 recall@10 - subtoken name 0.680 54.5% 84.8% 90.0% - subtoken doc-phrase 0.903 88.3% 92.2% 93.4% - name-exact name 0.898 82.2% 95.8% 97.4% - name-exact doc-phrase 0.013 0.5% 1.8% 2.6% - anchored name 0.687 56.1% 84.1% 88.7% - anchored doc-phrase 0.899 87.5% 92.2% 92.9% - routed name 0.899 82.4% 96.0% 97.6% - routed doc-phrase 0.902 88.2% 92.0% 93.2% - note: routing chose name-exact on 3989/4000 NAME queries (a NAME query is always identifier-shaped); - the confidence gate routes doc-phrase queries to name-exact ONLY when EVERY content word names a symbol - (or an explicit camel/snake token appears) AND every matched name is specific enough to anchor on — - a common name (many definitions, or a subtoken carried by many symbol names) declines the route — so - conceptual prose falls back to subtoken+body; routed tracks the better ranker on BOTH modes - (routed==name-exact on name, ~=subtoken+body on doc-phrase). -````` - -## `./build/ripwire . --eval-stray=./build/sc/aux/stray_labels2.tsv` - -*Labelled verdict-accuracy eval for --stray-content — three labels over REAL local refs (names resolved at capture time); exit 3 when accuracy is under the floor. Read got= against v= in the stray-content run: a ref the verb could not analyse (unknown) must never be credited as a merged hit.* - -**exit code: 1** - -Input file: - -````` -# refverdict labels for --eval-stray (the first three local branches, resolved at capture time; a missing branch is padded with a nonexistent name on purpose) -b155 merged -no-such-ref-1 unmerged -no-such-ref-2 merged -````` - -````` -(empty) -````` - -stderr: - -````` -ripwire: --eval-stray: 2 labelled ref(s) do not exist in . -- not merged, just absent: no-such-ref-1, no-such-ref-2 (fix the labels file or add the ref) -````` - -## `./build/ripwire skills --eval-skills=./build/sc/aux/skills_labels2.tsv` - -*Labelled skill-ROUTING eval over the repo's own skills/ directory (4 hand-labelled prompts).* - -Input file: - -````` -orient in an unfamiliar codebase fast ripwire-orient judged -who calls this function and what is the blast radius ripwire-navigate judged -plan parallel worktrees so the lanes do not collide ripwire-change-check judged -what is the weather in Paris none neg -````` - -````` -ripwire --eval-skills (skill routing over K=16 candidate skills [ripwire-router excluded]; 3 positive + 1 negative prompts; corpus './build/sc/aux/skills_labels2.tsv'; split test=4 dev=0) - arm hit@1 hit@2 mrr sep-auc fire/abstain@ORACLE-th (upper bound) - overlap 66.7% 66.7% 0.689 0.000 50.0% (th=-1.000) - name 33.3% 66.7% 0.537 0.667 50.0% (th=0.000) - bm25-desc 66.7% 66.7% 0.689 0.667 75.0% (th=2.865) - bm25-full 33.3% 66.7% 0.611 1.000 50.0% (th=0.426) - for-routed 33.3% 33.3% 0.556 1.000 50.0% (th=0.663) - random 6.2% 12.5% 0.211 0.500 <- floor (uniform-random ranking; auc 0.5 by definition) - provenance hit@1 (bm25-desc): router 0/0, desc 0/0, judged 2/3 (desc rows quote the descriptions - expect them easiest; judged is the honest number) - judged-only hit@1 per arm: overlap 2/3, name 1/3, bm25-desc 2/3, bm25-full 1/3, for-routed 1/3 - router-magnet: with ripwire-router ADMITTED as a candidate it takes top-1 on 1/3 positive prompts (bm25-desc arm) - why it is excluded above - per-skill (bm25-desc): name / permitted-rows / won / pos-fires / false-fires / neg-fires - ripwire-before-you-build 0 0 1 1 0 - ripwire-change-check 1 0 0 0 0 - ripwire-find-bug 0 0 0 0 0 - ripwire-fresh-eyes 0 0 0 0 1 - ripwire-graph-query 0 0 0 0 0 - ripwire-handoff 0 0 0 0 0 - ripwire-layers 0 0 0 0 0 - ripwire-mcp 0 0 0 0 0 - ripwire-navigate 1 1 1 0 0 - ripwire-opt-remarks 0 0 0 0 0 - ripwire-orient 1 1 1 0 0 - ripwire-perf-target 0 0 0 0 0 - ripwire-quality-bar 0 0 0 0 0 - ripwire-reuse-first 0 0 0 0 0 - ripwire-security-scan 0 0 0 0 0 - ripwire-write-tests 0 0 0 0 0 - misses (overlap): - line 3 want=ripwire-change-check got=ripwire-before-you-build "plan parallel worktrees so the lanes do not collide" -… [19 more lines, 3602 bytes total] -````` - -## `./build/ripwire wrap claude` - -*Print the recipe to wire ripwire into Claude Code as an MCP server.* - -````` -# ripwire -> Claude Code (CLI-first) -# NOTE: nothing on PATH is named ripwire right now, so the command below is this binary's absolute path; -# put its directory on PATH (the installer printed the export line) and the bare word works too. -# RECOMMENDED — this agent can run shell commands, so call the CLI directly. It costs -# nothing until you invoke it, and it reads CLAUDE.md, so the paste block below IS the wiring: -./build/ripwire . --for="" -# -# ...every follow-up call answers with the compact legend by default (terse definitions of only the -# attributes the answer carries; the payload is byte-identical either way). Add --legend=full when a -# definition's reasoning is needed -- `ripwire --help` carries the measured saving (one place, -# gate-held) -- this line does not repeat it, because two copies of a number is one that goes stale: -# ripwire . --callers=SYM --legend=full -# -# ALTERNATIVE — register the MCP server instead, for a warm index across calls: -claude mcp add ripwire -- ./build/ripwire --mcp -# verbs the agent can then call mid-task (33 total): -# read: analyze, rank_by, find_symbol, find_referencing_symbols, grep, cochange, memory_recall, situational_awareness, mentions, for, lego, owners, fetch_body, batch, flags, doc_drift, slice -# flagship reflex: exemplar, quality_delta, quality_baseline, impact, uses, affected, path_between, connect, explore, from_trace, edit_check, whereis, stray_content -# edit: replace_symbol_body, insert_before_symbol, insert_after_symbol -bash skills/install.sh # deploy to ${CLAUDE_CONFIG_DIR:-~/.claude}/skills (drift-gated) -bash skills/install.sh --hook # RECOMMENDED: advisory Read/Grep -> ripwire CLI nudge + session primer (opt-in, never blocks) -# -# context wiring — a binary on PATH is invisible to an agent until its rules file says when -# to reach for it. Paste the block below into CLAUDE.md: -# --- paste into CLAUDE.md --- -## ripwire — deterministic codebase maps (on PATH as `ripwire`) -Reach for it BEFORE blind grep + whole-file reads. First call ~1s cold; after that warm, ~0.1s. -- Orient on a task: `ripwire --for=""` — ranked, quality-annotated - signatures. Paste symbol/file names from the issue verbatim; named mentions get anchored. -- One task: `--pack-task="" --legend=compact`; before parallel agents: `--plan-lanes=N --task=""`, then read `lanes[].execution`. -… [16 more lines, 4284 bytes total] -````` - -## `./build/ripwire --version` - -*Version + short build info.* - -````` -ripwire 0.6.8 (dev, GNU 14.2.0, emit=std::print, built_from=f3f773982) -````` - - ---- - -# navigate — seeds, claims, slices, shapes - -## `./build/ripwire . --at=src/graph.h:11793` - -*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 . --callers=@src/graph.h:11793` - -*The same seed in a SELECTOR position: @FILE:LINE resolves to the innermost enclosing definition, then --callers runs on it.* - -````` - - - - - - - - - - -````` - -## `./build/ripwire . --at=src/graph.h:999999` - -*A seed past the end of the file — the refusal shape for a faulted location.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16149 lines — the seed asked for line 999999) -````` - -## `./build/ripwire . --verify="calls(runDefaultMap, rankGraphTeleport)"` - -*VERIFY a closed claim in one call: three-valued verdict (confirmed / refuted / not-established) with the evidence rows inline.* - -**wall time: 1.28s** - -````` - - - - - -````` - -## `./build/ripwire . --verify="unused(rankGraphTeleport)"` - -*A claim that is FALSE — the refuted shape, with the references that refute it.* - -**wall time: 1.24s** - -````` - - - - - - - - - - - - -````` - -## `./build/ripwire . --verify="contains(src/graph.h, \"no such literal anywhere\")"` - -*A literal-scan absence: refuted only with complete= evidence, never on a partial scan.* - -**wall time: 1.25s** - -````` - - - -````` - -## `./build/ripwire . --verify="frobnicate(x)"` - -*An unparseable claim — the refusal names the accepted shapes.* - -**exit code: 1** — **wall time: 1.28s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. The claim language is CLOSED; the shapes are: calls(A, B) does A transitively call B · uses(SYM) is SYM referenced anywhere · unused(SYM) is SYM referenced nowhere · contains(FILE, "LITERAL") do FILE's bytes contain t … [line truncated: 218 more bytes on this line] -````` - -## `./build/ripwire . --slice=rankGraphTeleport` - -*Bare --slice=SYM: the INVENTORY of sliceable locals (), so a caller can pick VAR.* - -````` - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --slice=rankGraphTeleport:teleport` - -*Intra-procedural def-use slice of ONE variable: one row per line touching it, k=def|use|both, reaching definitions flow-sensitive (reach=cfg).* - -````` - - - - - - - teleport( pw.begin(), pw.end() );]]> - - - - - - - - -````` - -## `./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=back --slice-depth=3` - -*TRANSITIVE backward value-flow from the seed variable, bounded BFS (depth= disclosed; a cut frontier says flow_truncated=1).* - -````` - - - - - - - teleport( pw.begin(), pw.end() );]]> - - - - - - - - - pw = biasPrior( g, p );]]> - - -& p, float alpha = 0.85f )]]> - - -& p, float alpha = 0.85f )]]> - - -````` - -## `./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=fwd` - -*Forward flow: which statements the seed's value reaches, at the default depth bound.* - -````` - - - - - - - teleport( pw.begin(), pw.end() );]]> - - - - - - - - - - - - - - - - - - - - - 0.0 )]]> - - - - - - - - -````` - -## `./build/ripwire . --slice=rankGraphTeleport:nosuchvar` - -*A variable the definition does not bind — the refusal shape, naming the inventory.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --slice: no occurrence of 'nosuchvar' in rankGraphTeleport — sliceable locals: alpha, g, p, pw, N, teleport, rankDouble, run, teleportMass, value, inverseMass, r (bare --slice=rankGraphTeleport lists them with first-def lines) -````` - -## `./build/ripwire . --slice-depth=3` - -*--slice-depth without --slice-flow is refused loudly rather than silently ignored.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire --slice=parseArgs:argIndex --slice-flow=fwd --slice-depth=4) -````` - -## `./build/ripwire . --slice=rankGraphTeleport:teleport --legend=compact` - -*The compact legend posture: rows byte-identical, a versioned schema id replaces the repeated explanatory prose — for a many-small-calls loop.* - -````` - - - - - - - teleport( pw.begin(), pw.end() );]]> - - - - - - - - -````` - -## `./build/ripwire . --pattern='rankGraphTeleport($A, $B, $C)'` - -*Structural search written in CODE: $NAME binds one node; grammars=/shapes= disclose what the pattern became per grammar (a 3-argument call shape — the 2-argument spelling has no call site in this repo and correctly reports hits=0).* - -**wall time: 1.36s** - -````` - -rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) - -````` - -## `./build/ripwire . --pattern='DISCLOSE(...)'` - -*The ellipsis form over a macro-shaped call site; unsupported= names the families this verb does not serve.* - -**wall time: 1.39s** - -````` - -DISCLOSE( result, AbiResult::DisclosureWhy::NoMergeBase, "abi: no merge-base for a ref (unrelated history?) — that ref -DISCLOSE( Diagnostics::answerRefused, "--arch exits 1 with path:line and the reason on stderr; no report is printed", -DISCLOSE( baseline, ArchBaselineRead::DisclosureWhy::SymlinkRefused, "arch: refusing to read the arch baseline sidecar t -DISCLOSE( Diagnostics::answerRefused, "--baseline exits 1: pathguard names the refused link on stderr and the verb says -DISCLOSE( ex, Exclusions::DisclosureWhy::ForHeaderSaturated, "atoms: the for-header exclusion stream spent its whole bud -DISCLOSE( ex, Exclusions::DisclosureWhy::StmtCrementSaturated, "atoms: the statement-crement exclusion stream spent its -DISCLOSE( ex, Exclusions::DisclosureWhy::StmtAssignSaturated, "atoms: the statement-assign exclusion stream spent its wh -DISCLOSE( ex, Exclusions::DisclosureWhy::InnerCommaSaturated, "atoms: the inner-comma exclusion stream spent its whole b -DISCLOSE( st, Type3Stats::DisclosureWhy::PairCapHit, "clones: Type-3 pair cap hit — first N compared (both-gate-surviv -DISCLOSE( scan, CommentCoherenceScan::DisclosureWhy::UnreadableFile, "comment-coherence: an indexed file could not be re -DISCLOSE( st, StreamBlobStats::DisclosureWhy::ListUnwritable, "crossref: cannot write the blob-batch list — cross-bran -DISCLOSE( st, StreamBlobStats::DisclosureWhy::BatchNotStarted, "crossref: git cat-file --batch failed to start — cross -DISCLOSE( st, StreamBlobStats::DisclosureWhy::StreamEndedMidBlob, "crossref: git cat-file stream e -DISCLOSE( dropSink, RefEnumeration::DisclosureWhy::TipNotObjectName, "crossref: for-each-ref yielded a ref whose tip is -DISCLOSE( "crossref: refusing a diff whose revision arguments are not resolved object names" ) -DISCLOSE( sweep, ParallelSweep::DisclosureWhy::WorkerThrew, "crossref: a git worker threw — this shard of the sweep is -DISCLOSE( stats, StreamBlobStats::DisclosureWhy::BatchNotStarted, "crossref: a blob-stream slice was never read — comp -DISCLOSE( plumb, RefPlumbing::DisclosureWhy::RevisionNotObjectName, "crossref: ref tip or HEAD is not a resolved object -DISCLOSE( plumb, RefPlumbing::DisclosureWhy::MergeBaseNotObjectName, "crossref: merge-base returned something that is no -DISCLOSE( plumb, RefPlumbing::DisclosureWhy::NoMergeBase, "crossref: no merge-base for ref (shallow clone or unrelated h -DISCLOSE( "crossref: refusing to list a tree whose revision argument is not a resolved object name" ) -DISCLOSE( "whereis: the index's def sites match no HEAD row (working tree drifted from HEAD?) — keeping the lexical la -DISCLOSE( reads[ k ], BranchBlobReadBack::DisclosureWhy::NotReadBackWhole, "whereis: a blob the pa -DISCLOSE( scan, WorktreeScan::DisclosureWhy::ListingFailed, "whereis: git could not list the working tree's changes — -DISCLOSE( scan, WorktreeScan::DisclosureWhy::OverPathCap, "whereis: more changed paths than the overlay reads — the re -DISCLOSE( scan, WorktreeScan::DisclosureWhy::CopyUnread, "whereis: a changed path could not be read from the working tre -DISCLOSE( Diagnostics::answerUnchanged, "lsTree lists the same rows per ref: only slower", "crossref: -DISCLOSE( out, CMakeScan::DisclosureWhy::SymlinkEscapesRoot, "flags: a CMake file's symlink target leaves the root — f -… [73 more display lines; full output is 17778 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --pattern='x'` - -*A pattern that collapses to a bare token is REFUSED — never reported as hits=0.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --pattern: this pattern collapses to a single bare token, which is a TEXT search, not a structural one — a clean parse is not enough (a bare word parses fine in most grammars and means nothing structural). Give it a shape (foo($X), $A + $B, if ($C) { ... }) or use the grep flag for litera … [line truncated: 176 more bytes on this line] -````` - -## `./build/ripwire . --grep=DISCLOSE --and=cache` - -*Boolean grep: hits where BOTH literals share the matched line (--grep-scope=line is the default).* - -````` - - - -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…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 19865 bytes on 44 raw line(s)] -````` - -## `./build/ripwire . --for="tree-sitter parse of a source file" --sections=lego,compose` - -*Restore the / sections the --for bundle collapses to a counted stub by default (this is the stub's own next= spelling).* - -**wall time: 1.46s** - -````` - - - - -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…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 ) -… [149 more display lines; full output is 20198 bytes on 44 raw line(s)] -````` - -## `./build/ripwire . --for="tree-sitter parse of a source file" --auto-bodies` - -*Opt OUT of compact conceptual serving: restore the rank-first auto walk (bundle="auto").* - -**wall time: 1.44s** - -````` - - - - -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…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 ) -… [134 more display lines; full output is 20417 bytes on 55 raw line(s)] -````` - -## `./build/ripwire . --for="quality delta acks ledger rubber stamp"` - -*Doc-mention surfacing (default ON): a markdown doc naming a top-resolved symbol in a backtick rides in below that symbol — the legend's [doc mentions: …] clause says it fired.* - -**wall time: 1.42s** - -````` - - - - - -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 constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at -inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) -inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… -inline const char* kNotesFile = ".ripwire_notes" -inline void writePlanLint( std::FILE* out, const LintResult& res ) - -The REF-PAIR floor's comparison, once loadRefPairDelta has both sides: the base snapshot is the …void refPairBasis( const rw::Config& cfg, const std::string& root, RefPairDelta& refs, DeltaBasis& out ) -std::optional<int> refuseForeignAckSelection( const rw::Config& cfg, const rw::quality::Scope& scope, const std::vector<rw::quality::Regression>& outOf … [line truncated: 16 more bytes on this line] -std::optional<int> runQualityDelta( const MainDispatch& d ) -struct DeltaBasis -int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] -inline const char* kAcksFile = ".ripwire_quality_acks" -DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) -struct IdentityHealing -inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) -inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) -inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) -inline std::string qualityAcksPath( const std::string& root ) -struct QualityDeltaOutcome -std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) -inline bool atomicWriteFile( const std::string& path, const std::string& blob ) -inline std::string gitHeadSha( const std::string& root ) -… [193 more display lines; full output is 22980 bytes on 45 raw line(s)] -````` - -## `./build/ripwire . --for="quality delta acks ledger rubber stamp" --no-doc-mention` - -*The same task with doc-mention surfacing OFF — the contrast the flag exists for (no [doc mentions] clause, one fewer row).* - -**wall time: 1.48s** - -````` - - - - - -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 constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at -inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) -inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… -inline const char* kNotesFile = ".ripwire_notes" -inline void writePlanLint( std::FILE* out, const LintResult& res ) - -The REF-PAIR floor's comparison, once loadRefPairDelta has both sides: the base snapshot is the …void refPairBasis( const rw::Config& cfg, const std::string& root, RefPairDelta& refs, DeltaBasis& out ) -std::optional<int> refuseForeignAckSelection( const rw::Config& cfg, const rw::quality::Scope& scope, const std::vector<rw::quality::Regression>& outOf … [line truncated: 16 more bytes on this line] -std::optional<int> runQualityDelta( const MainDispatch& d ) -struct DeltaBasis -int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] -inline const char* kAcksFile = ".ripwire_quality_acks" -DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) -struct IdentityHealing -inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) -inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) -inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) -inline std::string qualityAcksPath( const std::string& root ) -struct QualityDeltaOutcome -std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) -inline bool atomicWriteFile( const std::string& path, const std::string& blob ) -inline std::string gitHeadSha( const std::string& root ) -… [193 more display lines; full output is 22799 bytes on 45 raw line(s)] -````` - -## `./build/ripwire . --safe-delete=rankGraphTeleport` - -*"Can I delete this?" — callers + transitive impact + every use site + how much of the radius is tested, composed in ONE call; risk= names what was found, never a verdict.* - -````` - - - - - - - - - -````` - -## `./build/ripwire . --safe-delete=DoesNotExist` - -*Unknown-symbol refusal shape for --safe-delete.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --safe-delete symbol not found: DoesNotExist -````` - -## `./build/ripwire . --handoff` - -*The continuation packet for the NEXT session: disk truth (branch/sha, changed symbols, blast radius, tests) + labeled suggestions. Recorded against a CLEAN tree.* - -**wall time: 1.53s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [441 more display lines; full output is 46965 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --no-ignore --top-k=3` - -*Crawl paths the repo's own .gitignore covers (default honours it and discloses ignored_files=/ignored_dirs= only when it dropped anything — this repo's crawl drops nothing, so the header is identical to the default map's; --skipped's ignore_mode= says which rule applied).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --no-stable --top-k=3` - -*--no-stable outside --mcp: what the flag does (or says) when there is no stable-by-default ordering to opt out of.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable ordering the server turns on) — it changed nothing here; the CLI map orders important-first unless you pass --order=stable -````` - -## `./build/ripwire . --run-trace="cat ./build/sc/aux/asan_trace_now.txt; exit 1"` - -*EXEC-MODE --from-trace: run a command, and on a non-zero exit map its captured output onto indexed symbols in the same call — the whole fix-loop entry. ripwire exits 4 here because the wrapped command failed, which is the signal, not an incident.* - -**exit code: 4** - -````` - - - - - - const&, float) src/graph.h:11793 - #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11834 - #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)]]> pw = biasPrior( g, p ); - const std::size_t N = pw.size(); - std::vector teleport( pw.begin(), pw.end() ); - std::vector rankDouble( N, 0.0 ); - PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun - if( N ) - { - double teleportMass = 0.0; - for( const double value : teleport ) - { - teleportMass += value; - } - if( teleportMass > 0.0 ) - { - const double inverseMass = 1.0 / teleportMass; - for( double& value : teleport ) - { - value *= inverseMass; - } - } - run = pageRankDouble( g.inEdges, g.wOutDeg, teleport, rankDouble, PageRankConfig{ .alpha = double( alpha ) } ); - } - std::vector r( N, 0.f ); - std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); - return { std::move( r ), run.iterationCount, run.hasConverged }; -}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] -````` - -## `./build/ripwire . --run-trace="true"` - -*A command that exits 0: a minimal success record (exit, measured duration, disclosed output tail) and NO bundle — nothing failed, nothing to map.* - -````` - - - - -````` - -## `./build/ripwire . --run-trace="sleep 30" --run-timeout=2` - -*A command still running at the cap: its process group is killed and the run reports timed_out=1 — an honest timeout, never an empty success.* - -**exit code: 4** — **wall time: 2.83s** - -````` - - - - -````` - -stderr: - -````` -ripwire: --run-trace: TIMEOUT — the command exceeded the 2 s cap; its process group was killed -````` - -## `./build/ripwire . --run-timeout=5` - -*--run-timeout alone is refused loudly (it only modifies --run-trace).* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwire --run-trace="make -j" --run-timeout=60) -````` - - ---- - -# assess quality — the wider lens family - -## `./build/ripwire . --quality-panel` - -*THE single wide-angle quality read: six families in one pass, an eligible/ranked shortlist rather than a firehose.* - -**wall time: 4.84s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [188 more display lines; full output is 15675 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --biggest-first --limit=8` - -*Per-function size ranking, largest Halstead volume/token entropy/lines first — a size proxy, not a readability order (withdrawn, docs/EVALS.md §8) — a RANKING lens, not a grade.* - -**wall time: 1.15s** - -````` - - - - - - - - - - - -````` - -## `./build/ripwire . --comment-coherence --limit=8` - -*Functions WITH a doc comment, most name-restating first: c_coeff (high = the comment repeats the name) and cic (Jaccard of comment vs identifier vocabulary), both reported, never collapsed.* - -**wall time: 1.14s** - -````` - - - - - - - - - - - -````` - -## `./build/ripwire . --context-ratio --limit=8` - -*The local-reasoning lens: to understand this symbol, how much must you know that is NOT in front of you (ent_ratio= edge share, read_ratio= token-weighted).* - -**wall time: 1.38s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [21 more display lines; full output is 11151 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --nonlocal-state --limit=8` - -*Per function, the non-local MUTABLE state it can reach (transitively), most writes first — unsound by construction, and the legend says where.* - -**wall time: 3.29s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [41 more display lines; full output is 7601 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --ensemble --limit=8` - -*The family join: per function, which of four orthogonal evidence families fire, ranked by how many agree.* - -**wall time: 2.33s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [36 more display lines; full output is 7488 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --field-affinity` - -*The cache-locality lens over every aggregate: fields READ TOGETHER but declared FAR APART (split-line / straddle findings, Chilimbi separation weight) — advice only, never a rewrite.* - -**wall time: 1.52s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [510 more display lines; full output is 45635 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --field-affinity=Symbol` - -*The same lens narrowed to ONE struct — the one --layout=Symbol shows the offsets for.* - -**wall time: 1.54s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --naming-consistency --limit=8` - -*The corpus's OWN case-convention vote per (language, kind) group; off-convention names get a mechanical propose= (a suggestion, never a blind rename).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [13 more display lines; full output is 4430 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --naming-calibration` - -*Score the naming-* rules against this repo's own rename history: proxy=old/(old+new) per rule, 0.50 = chance; read pairs= (sample size) first.* - -**wall time: 11.13s** - -````` - - - - - - - - - - - -

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-… [154 more display lines; full output is 16060 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --lint --naming-locals` - -*The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/C++ only, only inside functions already past a size/complexity gate.* - -**wall time: 3.17s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [641 more display lines; full output is 72667 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --lint-catalog` - -*The built-in rule registry — one row per rule with sev=/category=/rationale/lang=/since=; no corpus needed.* - -````` - - -a C-style cast — cppcoreguidelines-pro-type-cstyle-cast prefers the explicit static_cast/const_cast/reinterpret_cast -a goto statement — cppcoreguidelines-avoid-goto -a do.hile loop shape (on Swift, its do/catch block shares the same grammar node and also matches) -a call to an unbounded C string function (strcpy/strcat/sprintf/gets) -a call to a broken hash or cipher (MD5/SHA1/MD4/RC4) -a doubly-parenthesized expression — readability-redundant-parentheses -an if-body that is just `;` — bugprone-suspicious-semicolon -a C-style typedef struct/union where `using` is preferred -a non-trivial numeric literal inside a function body, outside a const/constexpr init -a catch block with an empty body -x = x — almost always a copy-paste bug -a function body over 80 lines -brace nesting depth over 4 inside a function body -a bare `return;` mixed with a value-returning return in the same function -a statement after an unconditional return/break/continue/throw/raise in the same block -a 1-2 letter Function/Method/Var name — visible far beyond any tiny scope [Beniamini/Hofmeister] -more than 5 split tokens in one name [Butler; AlSuhaibani] -foo1/foo2/... digit-suffix siblings sharing a base name in one scope [Butler] -internal consecutive underscores, or a C-family reserved __x/_X form [Butler] -snake_case and camelCase mixed inside one name [Butler] -an is/has/can/should.as-prefixed name whose KNOWN return type is not bool-like [LAPD A2] -a set-prefixed name whose KNOWN return type is not void-like [LAPD A3] -a co-visible pair within edit distance <=2, reordered tokens, or a bare/digit-suffixed twin [Namesake] -every split subtoken is corpus-ubiquitous (BM25 idf) on a body past the size floor — fires only at the low end [Sparck Jones 1972] -the comma operator inside an expression (never a for-header comma) [Gopstein FSE 2017] -++/-- evaluated inside a larger expression (never a whole statement) [Gopstein FSE 2017] -an assignment whose VALUE is consumed (a condition, an argument, ...) [Gopstein FSE 2017] -a conditional expression inside a conditional expression [Gopstein FSE 2017] -… [12 more display lines; full output is 7800 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --legend-dict` - -*The session legend dictionary the MCP server serves as ripwire://legend-dict/full — one definition per line, headed by its dictv= version; no corpus needed. =roster lists the completeness attributes it defines.* - -````` -ripwire legend dictionary ripwire.dict/v1 dictv=2259c5025ac90271 entries=930 -: the answer's rows come first; its root keeps only task= changed= from= to=, and this LAST child carries every other root attribute unchanged (schema= included); legend="ref": a definition is sent once per session (this dictionary's core, or the first answer that ne … [line truncated: 83 more bytes on this line] -schema=ripwire.KEY/v1: the line ripwire.KEY/v1 below reads the answer's rows -window: shown= total= capped= has_more= next_offset= offset= limit= page a list (capped=1 cut; next_offset= pastes as offset=) -X_capped= (any attribute ending _capped): 1 = cut -under ref, est_tokens= and over_ceiling= price the answer with its inline legend: an upper bound -under ref, a group of n <= 8 runner-less rows prints as its n single rows, each run_unknown=1 -ripwire.map/v1 : ranked symbol map: groups rows (k= rank), resolved callees; the header comment is data -ripwire.map-diff/v1 : the ranked map anchored at at=: what the diff touched, the map's row vocabulary -ripwire.metrics/v1 : the ranked map with per-symbol metrics: in/out, cx/ccx, loc, params, nest, humps/deep, locals, cbo, amp, tested, ev -ripwire.around/v1 : call neighbourhood of of=: depth= hops, fanout= kept per hop; absent rows lie outside that boundary -ripwire.query/v1 : lexical-rank map for the query term, the map's row vocabulary -ripwire.pack-signatures/v1 : the ranked map plus signature rows -ripwire.pack-top-n/v1 : the ranked map plus bodies of the top-N symbols -ripwire.skipped/v1 : why the index lacks a file ; indexed but unvouched ; census -ripwire.notes/v1 : field notes by target: holds ; the kept count comment: notes= rows, targets= rows, dangling= targets matching nothing indexed (listed, surfaced nowhere) -ripwire.lego/v1 : ONE interface/base type: , its method contract, every implementor -ripwire.expand/v1 : full bodies: of ; resolved callees -ripwire.expand-file/v1 : the file's own text: ; per scoped symbol; full id = p::sc::n -ripwire.candidate-page/v1 : budgeted-bundle candidate page: a resumable window over the ranked candidate set the bundle cuts, for task= under budget_tokens=, one tier per page, ranks global across pages -ripwire.pack-task/v1 : one-call task bundle for task= under budget_tokens=: ranking, ranked but over 1 hop out (of_top= ranked rows) > with callees > 1-hop from the bodies (o … [line truncated: 105 more bytes on this line] -ripwire.from-trace/v1 : trace frames mapped to indexed symbols, innermost first; the innermost in-corpus body included -ripwire.exemplar/v1 : the best-in-class instance of kind= for the task, chosen by role: , to imitate -ripwire.pack-task/v1 : N minimally overlapping agent bundles carved along call-graph communities plus one shared core; each wraps a ; bundle role=core|partition i= symbols= modules= bytes= tokens=: one agent's ctx, symbols= ids assigned, bytes= its size; tokens= = est_t … [line truncated: 345 more bytes on this line] -ripwire.callers/v1 : 1-hop CALLERS of of= (defs= matched, count= distinct symbols): ; hop_tested=/hop_untested= -ripwire.callees/v1 : 1-hop CALLEES of of= (defs= matched, count= distinct symbols): -ripwire.uses/v1 : resolvable use-sites of of=: -ripwire.impact/v1 : transitive blast radius of of=: reach set, importers; defs= matched, reaches= their transitive callers, radius_tested= non-tests an indexed test reaches, radius_untested= the rest; importers= files that #include/import a def's file -ripwire.path/v1 : one DIRECTED call path from= to to=, each a hop; reachable=0 hops=0 when none -ripwire.connect/v1 : minimal joining subgraph: groups, terminals, joins, edges, -… [901 more display lines; full output is 97483 bytes on 931 raw line(s)] -````` - -## `./build/ripwire . --lint --lint-select=cache-` - -*Run ONLY one rule family; the root carries selected="K of N" so a filtered zero is never confusable with an unfiltered one.* - -**wall time: 2.43s** - -````` - - - - - - - - - - -vector<std::vector<double>> -nodes[ perm[i] ] -nodes[ perm[ i + 1 ] ] -p = p->next -map -byName[ symN[i] ] -vector<std::vector<std::vector<std::uint32_t>>> -vector<std::vector<std::uint32_t>> -m[ symN[id] ] -vector<std::vector<double>> -m[ in.keys[ i ] ] -map -vector<std::vector<std::vector<std::uint32_t>>> -vector<std::vector<std::uint32_t>> -m[ symN[id] ] -map -m[ g_pool[ g_keyOf[i] ] ] -g_pool[ g_readOf[i] ] -g_pool[ g_readOf[i] ] -m[ g_pool[i] ] -… [607 more display lines; full output is 73533 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --lint --lint-ignore=naming-,cache-` - -*DROP two families, applied after selection; the raw select=/ignore= you passed rides on the root.* - -**wall time: 2.38s** - -````` - - - - - - - - - - - - - - - - - - - - - - - -0.5 -1023u -main (90 lines) -20 -delta < 0.02 && delta > -0.02 -0.02 -… [724 more display lines; full output is 66341 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --lint --lint-select=goto --lint-max-per-rule=4` - -*A rule that spends its own match budget (here 4, set BELOW the default 5000 so the floor shows on this repo): goto carries count_capped="1", its count= is a FLOOR, and the root names the call that counts the rest — findings_next= re-runs only the floored rules under a 10x budget.* - -**wall time: 2.43s** - -````` - - - -goto done; -goto epilogue; -goto epilogue; -goto epilogue; - -````` - -## `./build/ripwire . --lint --lint-select=goto --lint-max-per-rule=40` - -*Pasting that findings_next=: the same rule under a 10x budget counts its true total — no count_capped=, no findings_next=.* - -**wall time: 2.42s** - -````` - - - -goto done; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto epilogue; -goto error; -goto error; -goto error; -goto done; -goto done; - -````` - -## `./build/ripwire . --lint --lint-select=cach-` - -*An unresolvable PREFIX refuses (exit 1) with a did-you-mean from a real edit distance (one character off cache-).* - -**exit code: 1** — **wall time: 2.46s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --lint-select: 'cach-' matches no rule or family (did you mean 'cache-'?) — see --lint-catalog for the full registry -````` - -## `./build/ripwire . --lint --lint-select=nosuchfamily` - -*A PREFIX with no near miss at all: the refusal points at --lint-catalog instead of guessing.* - -**exit code: 1** — **wall time: 2.42s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint-catalog for the full registry -````` - -## `./build/ripwire . --lint --sarif` - -*The SAME findings as SARIF 2.1.0 (what github/codeql-action/upload-sarif consumes) — pure re-serialization, results count == the native run's.* - -**wall time: 2.50s** - -````` -{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"name":"ripwire","rules":[{"id":"c-style-cast","shortDescription":{"text":"c-style-cast"},"properties":{"builtin":true,"capped":false,"applicable": … [line truncated: 7 more bytes on this line] -{"id":"goto","shortDescription":{"text":"goto"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"do-while","shortDescription":{"text":"do-while"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"unsafe-c-fn","shortDescription":{"text":"unsafe-c-fn"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"weak-crypto","shortDescription":{"text":"weak-crypto"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"redundant-parens","shortDescription":{"text":"redundant-parens"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"suspicious-semicolon","shortDescription":{"text":"suspicious-semicolon"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"typedef-over-using","shortDescription":{"text":"typedef-over-using"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"magic-number","shortDescription":{"text":"magic-number"},"properties":{"builtin":true,"capped":true,"applicable":true}}, -{"id":"empty-catch","shortDescription":{"text":"empty-catch"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"self-assign","shortDescription":{"text":"self-assign"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"large-function","shortDescription":{"text":"large-function"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"deep-nesting","shortDescription":{"text":"deep-nesting"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"inconsistent-return","shortDescription":{"text":"inconsistent-return"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"unreachable-code","shortDescription":{"text":"unreachable-code"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-short","shortDescription":{"text":"naming-short"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-wordy","shortDescription":{"text":"naming-wordy"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-series","shortDescription":{"text":"naming-series"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-underscore","shortDescription":{"text":"naming-underscore"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-case","shortDescription":{"text":"naming-case"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-predicate","shortDescription":{"text":"naming-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-setter","shortDescription":{"text":"naming-setter"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-confusable","shortDescription":{"text":"naming-confusable"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"naming-uninformative","shortDescription":{"text":"naming-uninformative"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"atom-comma-operator","shortDescription":{"text":"atom-comma-operator"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"atom-embedded-crement","shortDescription":{"text":"atom-embedded-crement"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"atom-assign-as-value","shortDescription":{"text":"atom-assign-as-value"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"atom-nested-ternary","shortDescription":{"text":"atom-nested-ternary"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"atom-implicit-predicate","shortDescription":{"text":"atom-implicit-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -{"id":"atom-octal-literal","shortDescription":{"text":"atom-octal-literal"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -… [13397 more display lines; full output is 1896280 bytes on 1 raw line(s)] -````` - -Parsed summary of the same SARIF (past the display cut): - -````` -sarif 2.1.0 rules= 39 results= 6694 -````` - -## `./build/ripwire . --lint --sarif --limit=5` - -*SARIF is always the FULL result set: paging alongside it refuses loudly.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M -````` - -## `./build/ripwire . --dmm` - -*The Delta Maintainability Model scalar for the WORKING TREE vs HEAD — recorded against a CLEAN tree (the sandbox section shows a real delta). UNAVAILABLE is a stated reason, never 0 or 1.* - -**wall time: 3.44s** - -````` - - -

-

- -````` - -## `./build/ripwire . --dmm=HEAD` - -*The per-commit scalar: HEAD vs its first parent, with the three separately actionable sub-scores.* - -**wall time: 6.95s** - -````` - - -

-

- -````` - -## `./build/ripwire . --dmm=HEAD~3..HEAD` - -*The range form: tree HEAD vs tree HEAD~3.* - -**wall time: 6.88s** - -````` - - -

-

- -````` - -## `./build/ripwire . --cochange --cochange-groups` - -*Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none of which it depends on" — a greedy cover, disclosed as greedy.* - -**wall time: 1.51s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [847 more display lines; full output is 56290 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --cochange --cochange-recur=2` - -*Only pairs whose co-change RECURS in 2+ sub-windows of the mined window (sub_windows= is the denominator) — a one-off sprint stops reading like a structural defect.* - -**wall time: 1.48s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --html=./build/sc/aux/map2.html --color-by=community` - -*The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector).* - -**wall time: 1.51s** - -````` -(empty) -````` - -Artifact written: - -````` -156004 ./build/sc/aux/map2.html -````` - -## `./build/ripwire . --index-out=./build/sc/aux/ci_index` - -*CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout.* - -**wall time: 3.33s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --index-out wrote ./build/sc/aux/ci_index.lean.ripwirecache (28654855 bytes, lean family) -ripwire: --index-out wrote ./build/sc/aux/ci_index.rich.ripwirecache (58741710 bytes, rich family) -````` - -Artifact written: - -````` -28654855 ./build/sc/aux/ci_index.lean.ripwirecache -58741710 ./build/sc/aux/ci_index.rich.ripwirecache -87396565 total -````` - -## `./build/ripwire . --cache=./build/sc/aux/ci_index.lean.ripwirecache --top-k=3` - -*Consume the lean artifact in a PR job: restore-equivalence, never blob-byte-identity.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --pin-census=./build/sc/aux/pin_census.tsv --top-k=3` - -*Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [63 more display lines; full output is 8117 bytes on 1 raw line(s)] -````` - -Artifact written: - -````` -# ripwire pin-census v3 C=kind\tmech\tpre\tpost\tflags\tcaller_id\tcallee\ttargets(|-sep)\tline -# v3 field escape: every id and callee field is escaped, so no separator occurs inside one. A backslash is -# written \\, TAB \t, LF \n, CR \r, every other control byte 0x00-0x1f and the targets separator | as \xHH -# (lowercase hex). Split lines on LF, fields on TAB and targets on |, THEN decode. Columns are unchanged -# from v2 and an id without those bytes is spelled exactly as in v2; a C++ out-of-line template member -# whose template-argument list spans lines keeps its line break as \n instead of splitting the row. -# line is the 1-based call-site line in the caller's file (v2, appended LAST so v1 readers are unchanged): -# the key a SCIP occurrence joins on, so a coverage loss can be classified per site instead of guessed. -129064 ./build/sc/aux/pin_census.tsv -````` - -## `./build/ripwire . --plan-lint=test/planlintfix.ave.md` - -*The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates.* - -**exit code: 2** - -````` - - - - - - - - - - - - - -````` - -## `./build/ripwire . --plan-lint=test/planlintfix.ave_ledger.md` - -*The ledger-shaped fixture through the same check (exit 2: one gating card).* - -**exit code: 2** - -````` - - - - - - - -````` - -## `./build/ripwire . --doctor --agent=claude` - -*--doctor plus a LIVE integration inspection for one agent: PATH binary, installed-skill manifest parity, hook executability, MCP wiring — read-only, fixed repair commands, never config contents; exit 1 when any check fails.* - -**exit code: 1** — **wall time: 1.63s** - -````` - - - - - - - - - - - - - -````` - -stderr: - -````` -ripwire --doctor: no ripwire resolves from PATH. To put this binary's directory first (for this shell; put the same line in your shell rc file), paste this line: -export PATH='./build':"$PATH" -````` - -## `./build/ripwire . --doctor --agent=nosuch` - -*Other --agent values refuse.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: unsupported --agent value 'nosuch' (supported: codex, claude) -````` - - ---- - -# the dirty-tree verbs (throwaway clone, NOT the read-only repo) - -Everything below runs with `cwd` = the throwaway clone at `./build/sc/dirty` (`git clone --local` of this repo, then one deliberate regression in `src/infra/sortutil.h`). The read-only repo is never touched. The binary is the same `build/ripwire`, addressed absolutely. - -## `./build/ripwire . --situ` - -*Situational report for a real diff: blast radius + tests + co-change + forgotten co-change partners.* - -**wall time: 4.68s** - -````` -ripwire situational-awareness — 1 changed file(s), 13 symbols in them -root: . -at: e47df2266+dirty - change_set: granularity=file changed_symbols=13 file_symbols=13 files_narrowed=0 files_file_granular=1 diff_hunks=7 diff_hunks_located=6 diff_hunks_unlocated=1 — seeds = symbols a diff -U0-vs-HEAD hunk overlaps (function/method body spans only); an unlocated hunk (module-level, deletion, rename) … [line truncated: 34 more bytes on this line] - [1] blast radius: 246 symbols across 58 files transitively depend on these changes (showing 8 of 58 files — shown=8 total=58 capped=1 prcontext_cap=20 (--pr-context's own per-file list is cut at 20 too); next: --situ --limit=58) - counts_floor=1 graph_ambiguous=2932 graph_unresolved=15150 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] - src/mcpverbs.h (33 dependent symbols) - src/quality.h (15 dependent symbols) - src/verbs_quality.h (14 dependent symbols) - src/verbs_for.h (13 dependent symbols) - src/editcheck.h (9 dependent symbols) - src/resolve.h (9 dependent symbols) - src/verbs_navigate.h (9 dependent symbols) - src/graph.h (8 dependent symbols) - [2] tests to run (5) order=evidence: [changed] you edited it, [partner] named after a changed file, then hops asc (1 = direct); "(n): a, b" = n runner-less files sharing that evidence; a (run: …) is relative to root: - test/verify_radix.cpp [hops=1] (run: bash test/greptiercheck.sh) - test/adaptivecutshapefix/adaptive_cut_shape_test.cpp [hops=2] (run: bash test/adaptivecutshapecheck.sh) - test/includeprecise_unit.cpp [hops=2] (run: bash test/includeprecisecheck.sh) - test/verify_csr.cpp [hops=2] (run: bash test/a9disclosurecheck.sh) - test/rustimport_unit.cpp [hops=4] (run: bash test/rustimportprecisecheck.sh) - script_gates_unmodelled=779 — test/*.sh gates never appear above: script-to-binary edges are not call edges (a path count) - [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5240": - (none — 5240 commits were mined and none co-edited a file outside your diff) - next: --test-gate -````` - -## `./build/ripwire . --test-gate` - -*The pre-PR gate with real obligations — exit 4 when tests-to-run or untested blast radius is non-empty.* - -**exit code: 4** — **wall time: 4.31s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --quality-delta` - -*Every row carries p="file:line", the gating rows are marked gating="1" and now bar= (the threshold each numeric row is judged against), and the exit-2 refusal prints a naming line on stderr; a gating row carries a pasteable next=.* - -**exit code: 2** — **wall time: 21.23s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [149 more display lines; full output is 18050 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) -````` - -## `./build/ripwire . --quality-delta --legend=full` - -*The same gating report under --legend=full — same rows, same exit 2; the default compact comment (schema="ripwire.quality-delta/v1", the shape an agent's edit loop should run) becomes ~4 KB of prose legend.* - -**exit code: 2** — **wall time: 10.88s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [149 more display lines; full output is 23042 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) -````` - -## `./build/ripwire . --quality-delta --json` - -*The same findings as JSON (one of the CI/scripting verbs --json supports) — same exit 2 as the XML form.* - -**exit code: 2** — **wall time: 10.84s** - -````` -{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"e47df2266+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] -{"kind":"complexity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":67,"p":"src/infra/sortutil.h:49","gating":true}, -{"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy","p":"src/infra/sortutil.h:119","origin":"new-symbol"}, -{"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","p":"src/infra/sortutil.h:129","origin":"new-symbol"}, -{"kind":"duplication","members":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey","tokens":59,"p":"src/infra/sortutil.h:119","gating":true}, -{"kind":"nesting","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":6,"p":"src/infra/sortutil.h:49","gating":true}, -{"kind":"new-clone-of-reused-helper","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey","was":0,"now":4,"p":"src/infra/sortutil.h:119","gating":true}, -{"kind":"params","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","was":0,"now":8,"p":"src/infra/sortutil.h:129","origin":"new-symbol"}, -{"kind":"verbosity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":8,"now":47,"p":"src/infra/sortutil.h:49","sev":"minor"}], -"sa":[{"kind":"api-surface","key":"085e3d408c2c4a35","why":"target-gone"}, -{"kind":"api-surface","key":"155d74d341a49f3c","why":"target-gone"}, -{"kind":"api-surface","key":"1a15386c2d1e47af","why":"target-gone"}, -{"kind":"api-surface","key":"298e798c7f075715","why":"target-gone"}, -{"kind":"api-surface","key":"56acdf9b5c314a14","why":"target-gone"}, -{"kind":"api-surface","key":"5a07390012b46e06","why":"target-gone"}, -{"kind":"api-surface","key":"6eef859578c8c376","why":"target-gone"}, -{"kind":"api-surface","key":"6f2394762f82a855","why":"target-gone"}, -{"kind":"api-surface","key":"7f2c3eefdf6e512e","why":"target-gone"}, -{"kind":"api-surface","key":"802e513731103806","why":"target-gone"}, -{"kind":"api-surface","key":"b6a24afef32a68a8","why":"target-gone"}, -{"kind":"api-surface","key":"c923e661c197b265","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"1926b0d9e94541a0","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"1d3814ba687a4aef","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"1db76028879244ef","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"25c9f0504fd376a4","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"36e39c7ab0fc1686","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"4bce64bd920de0c3","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"61f0e361ef7dee27","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"79625906f9f71ad0","why":"target-gone"}, -{"kind":"api-surface:new-symbol","key":"8ecb190954dce18a","why":"target-gone"}, -… [146 more display lines; full output is 16644 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) -````` - -## `./build/ripwire . --quality-delta --quality-ack --ack-only=zzznope` - -*NEW FLAG: --ack-only matching nothing REFUSES rather than falling back to acking everything.* - -**exit code: 1** — **wall time: 6.53s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: ack provenance backfill — 0 clone row(s) reconstructed from the current tree, 213 re-derived, 21 left UNVERIFIED (their group was not found here — a floor, not proof it is gone), 56 left legacy (member set not found cloning here — a floor, not proof it is gone), 1311 ineligible (no cu … [line truncated: 200 more bytes on this line] -ripwire: --ack-only=zzznope matched none of the 9 finding(s) — nothing written -````` - -## `./build/ripwire . --quality-delta --quality-ack --ack-only=api-surface` - -*NEW FLAG: ack only the api-surface findings — a per-finding ratchet instead of a rubber stamp.* - -**wall time: 6.54s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: ack provenance backfill — 0 clone row(s) reconstructed from the current tree, 213 re-derived, 21 left UNVERIFIED (their group was not found here — a floor, not proof it is gone), 56 left legacy (member set not found cloning here — a floor, not proof it is gone), 1311 ineligible (no cu … [line truncated: 200 more bytes on this line] -ripwire: acknowledged 1 of 9 finding(s) (8 left UNACKED by --ack-only, 0 already acked) → ./.ripwire_quality_acks -````` - -## `./build/ripwire . --quality-delta` - -*Re-run after the partial ack: acked=3, the rest still gate (exit 2).* - -**exit code: 2** — **wall time: 10.68s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [148 more display lines; full output is 17753 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: --quality-delta gating: 4 preexisting-worse major finding(s); first: complexity src/infra/sortutil.h::rw::sortutil::lessByScoreDescId at src/infra/sortutil.h:49 (was=1 now=67) -````` - -## `./build/ripwire . --ack-only=gating` - -*--ack-only WITHOUT --quality-ack REFUSES loudly (exit 1, the pairing named) — it used to be silently ignored.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire

--quality-delta --ack-only=contract-change --quality-ack="reason") -````` - -## `./build/ripwire . --edit-check=nonNegativeFloatDescKey` - -*A real contract-change: was=1 now=2 params, with the call sites that are now provably incompatible, and a pasteable next= (--uses=SYM) on the root.* - -**wall time: 1.60s** - -````` - - - - - - -````` - -## `./build/ripwire . --edit-check=nonNegativeFloatDescKey --legend=full` - -*The same verdict under --legend=full: the default's one compact comment (the post-edit reflex at its cheapest) becomes ~5.7 KB of prose legend, every row identical.* - -**wall time: 1.60s** - -````` - - - - - - -````` - -## `./build/ripwire . --pr-context` - -*The review-evidence bundle with an actual changed file.* - -**wall time: 3.59s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [80 more display lines; full output is 8063 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --map-diff --top-k=5` - -*The map re-ranked with a teleport toward the changed file (changed=1 here, not 0).* - -**wall time: 2.33s** - -````` - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --clones` - -*The duplicated helper the sandbox edit introduced shows up as a clone group.* - -**wall time: 3.01s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [308 more display lines; full output is 16222 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --stray-content=zz-orphan` - -*CHANGED: a ref with NO merge base with HEAD now reports v="unknown" ok="0" in its own bucket — the absence of an answer, never a claim it is merged. (The sandbox carries a deliberately parentless branch built with `git commit-tree`; a shallow CI clone puts every ref here.)* - -**wall time: 1.59s** - -````` - - - -````` - -## `./build/ripwire . --stray-content=zz-orphan --plan` - -*CHANGED: --plan surfaces those same refs as an row rather than silently dropping them.* - -**wall time: 2.38s** - -````` - - - -````` - -## `./build/ripwire . --dmm` - -*The DMM scalar on a REAL delta: the sandbox edit grew one unit past the nesting/complexity thresholds and added an 8-parameter one, so dmm is low and the three sub-scores say which property moved.* - -**wall time: 4.22s** - -````` - - -

-

- -````` - -## `./build/ripwire . --quality-delta --scope=src/graph.h` - -*OWNERSHIP partition for a shared tree: every regression here lives in src/infra/, so under a scope naming src/graph.h they ALL print under with a do-not-ack banner and never gate — scoped-out-gating= says how many would have.* - -**wall time: 10.76s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [151 more display lines; full output is 18020 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -````` - -## `./build/ripwire . --quality-delta --quality-ack --scope=src/graph.h --ack-only=api-surface` - -*The rubber-stamp guard: an --ack-only that names an OUT-OF-SCOPE row refuses (exit 1) and writes nothing.* - -**exit code: 1** — **wall time: 6.40s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=src/graph.h — refusing, and writing nothing at all: - api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 - those rows belong to whoever is editing those paths. Acking them here writes their debt into a committed ledger under YOUR - reason string, which is how a per-finding ratchet becomes a rubber stamp. Narrow the pattern, or widen the scope if they really are yours. -````` - -## `./build/ripwire . --handoff` - -*The continuation packet with a REAL diff: verified changed symbols + blast radius + tests-to-run, then the heuristic rows.* - -**wall time: 3.79s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --note-add="lessByScoreDescId: keep this branch-free — it sits inside the PageRank sort comparator"` - -*Pin a field note (write-side memory) to a symbol; committed to .ripwire_notes in the sandbox. The BARE name is resolved through the same resolver the read verbs use and stored as the canonical id — the rewrite is echoed on stderr, because a silent one is not a disclosure.* - -````` -src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 keep this branch-free — it sits inside the PageRank sort comparator e47df22661f8b88439e96dd63cf7ca25c0525ebe b155 -````` - -stderr: - -````` -ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why -ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sortutil.h::rw::sortutil::lessByScoreDescId' — that is the id --for/--expand key notes by -````` - -## `./build/ripwire . --notes` - -*The note is listed under the canonical id, dangling="0" — i.e. it will actually surface. (Before the H1 fix the bare name was stored verbatim and read dangling="1": recorded, and surfaced nowhere.)* - -````` - - - - - - - - - - - - - - - - gate scripts' claim (~line 1305) is NOT enforced — the derived-vs-stated sibling loop here covers docs/EVALS.md only. It drifted 407→451 unnoticed (fixed 2026-08-23). To close: grep both files ('file:line:' parsing) in the gateCountClaims arm.]]> - - - - -````` - -## `./build/ripwire . --note-add="gitOneLine: which one?"` - -*Two definitions carry this name, so the write REFUSES rather than pick one: a note keys ONE canonical id, and an ambiguous selector is refused, never silently narrowed. Every candidate is named, with a runnable retry.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why -ripwire: --note-add: target 'gitOneLine' is ambiguous — it matches 2 definitions in 2 distinct contracts, and a note keys ONE canonical id (it would surface on one of them and look absent on the rest). Qualify one: ./src/handoff.h:gitOneLine, ./src/quality.h:gitOneLine — e.g. --note-add="./src/h … [line truncated: 33 more bytes on this line] -````` - -## `./build/ripwire . --note-add="lessByScoreDescIdd: typo"` - -*A name that resolves to nothing is refused with the read verbs' own did-you-mean — never written as a dead note.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why -ripwire: --note-add: target not found: lessByScoreDescIdd (did you mean 'lessByScoreDescId'?) — a note keys the canonical id a read verb resolves; to note a FILE instead, pass a path (one with a '/' or an extension), which may name a file that does not exist yet -````` - -## `./build/ripwire . --note-add="src/infra/sortutil.h::rw::sortutil::lessByScoreDescId: chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort"` - -*The same symbol addressed by its CANONICAL id: already canonical, so nothing is rewritten and both notes land on ONE target.* - -````` -src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort e47df22661f8b88439e96dd63cf7ca25c0525ebe b155 -````` - -## `./build/ripwire . --expand=lessByScoreDescId --top-k=0` - -*Both notes riding along with the symbol's body — the elements follow the body, past the display cut, so they are extracted below.* - -````` - - - - - - - - - - - - - -````` - -## `./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h` - -*Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call.* - -**wall time: 4.63s** - -````` -{"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":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} -````` - -stderr: - -````` -ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: bash test/greptiercheck.sh -````` - -## `./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h --no-post-check` - -*The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr.* - -**wall time: 2.19s** - -````` -{"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] -````` - -stderr: - -````` -ripwire edit: applied atomically; receipt carries region, blob_sha (post-check skipped); next: --edit-check=src/infra/sortutil.h:lessByScoreDescId -````` - -## `./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=./build/sc/aux/payload_note.h --edit-target-file=src/infra/sortutil.h` - -*Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured).* - -**wall time: 5.07s** - -````` -{"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] -{"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":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} -````` - -stderr: - -````` -ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: --uses=src/infra/sortutil.h:nonNegativeFloatDescKey -````` - -## `./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc/aux/payload_note.h` - -*An unknown TARGET refuses and leaves every file byte-identical.* - -**exit code: 1** — **wall time: 2.15s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --replace-symbol-body: symbol 'DoesNotExist' not found -````` - -## `./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json --dry-run` - -*A versioned multi-edit TRANSACTION preflighted without writing: the receipt shows what each op would read and touch.* - -**wall time: 2.20s** - -Input file: - -````` -{ - "version": 1, - "edits": [ - { - "op": "insert_before_symbol", - "target": "nonNegativeFloatDescKey", - "payload": "plan_note.h" - } - ] -} -````` - -````` -{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 282 more bytes on this line] -````` - -## `./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json --apply` - -*The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure.* - -**wall time: 4.65s** - -````` -{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15150,"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: 466 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":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true}}]} -````` - -## `./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json` - -*Neither --dry-run nor --apply: the mode is explicit, so this refuses.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --edit-plan requires exactly one of --dry-run or --apply -````` - -## `./build/ripwire . --quality-delta` - -*After the agent's edits: the complexity/nesting rows on lessByScoreDescId are gone (the replace undid them), the rest still gate (exit 2).* - -**exit code: 2** — **wall time: 11.11s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [145 more display lines; full output is 17117 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: --quality-delta gating: 2 preexisting-worse major finding(s); first: duplication src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:88 (was=0 now=59) -````` - -## `./build/ripwire . --quality-baseline` - -*REFUSES, exit 1: this sandbox tree is already regressed, and pinning here would swallow that debt into the floor so every later delta read clean. It names how many gating findings it would absorb, the first of them, and the way forward.* - -**exit code: 1** — **wall time: 6.47s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --quality-baseline: this tree already holds 2 gating finding(s) against HEAD — pinning here would absorb - them into the floor, and every later --quality-delta would read clean. First: duplication src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey (was=0 now=59) - Commit the tree first, or pass --allow-dirty to pin anyway (the sidecar then records the 2 absorbed, and every - report against it carries baseline_absorbed="2"). -````` - -## `./build/ripwire . --quality-baseline --allow-dirty` - -*The consent form: pin anyway. The sidecar is stamped with the dirty pin and the absorbed count, so the fact outlives the process that knew it.* - -**wall time: 10.05s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --quality-baseline --allow-dirty: pinned with 2 gating finding(s) ABSORBED into the floor (stamped in the sidecar; every --quality-delta against it carries baseline_absorbed="2") -ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30766 per-symbol rows, 31704 indexed symbols total) -````` - -Artifact written: - -````` -5208125 .ripwire_quality_baseline -# ripwire quality baseline v6 — regenerate with --quality-baseline; do not hand-edit -producer 95a5aa40644062cd8ddb0c7725ac755d112333f011e507d1c703684c2d334646 -head e47df22661f8b88439e96dd63cf7ca25c0525ebe -dirty 1 -absorbed 2 -ccx 67c15011ee8b 0 -ccx d19d7c13cbc7 2 -ccx 1f7edbff929e5 10 -ccx 6a732f6699b -````` - -## `./build/ripwire . --quality-delta` - -*Against that sidecar the same tree reads regressions=0 — but baseline_absorbed= is on the root, so this green means clean SINCE THE PIN, never clean. A baseline is a floor YOU chose, and it belongs BEFORE the change.* - -**wall time: 10.86s** - -````` - - -````` - - ---- - -# the MCP dialect — the same verbs over stdio JSON-RPC (one-shot exchange, not a persistent server) - -## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ./build/ripwire --mcp` - -*initialize + tools/list: the manifest an agent host loads at session start — every verb's name, description and input schema.* - -````` -{"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: 738 more bytes on this line] -{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"analyze","description":"Architecture map for a directory: signatures and the call graph for the top symbols. Use when landing cold in a repo or subdir, before reading files; for a task-scoped inventory use 'for', for one symbol's neighborhood find_ … [line truncated: 742 more bytes on this line] -{"name":"rank_by","description":"The SAME architecture map 'analyze' serves, ranked by a different signal instead of plain PageRank. rank_by = pagerank (default, omit it — the CLI's own unbiased --rank-by=pagerank; 'analyze' can rank differently on a tree with uncommitted changes, where it biases … [line truncated: 1077 more bytes on this line] -{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read.rite/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] -{"name":"find_referencing_symbols","description":"Direct (1-hop) callers of a symbol, each with a fetch_body handle. For the full transitive blast radius use 'impact', for read.rite/import sites 'uses'. JSON {symbol, calledBy, defs, count, hop_tested, hop_untested, declined_calls, counts_floor}; ca … [line truncated: 945 more bytes on this line] -{"name":"grep","description":"Trigram literal search; each hit annotated with its enclosing symbol (which function/class it is in). Hits carry text; enclosing rows a fetch_body handle. pattern = the literal; in=any lifts the span tiering (default: tightest non-empty tier; rest rides as suppressed_co … [line truncated: 837 more bytes on this line] -{"name":"cochange","description":"Files that historically change together with this file — the co-edit partners. Fowler's Shotgun Surgery as change coupling. dep_capable=false means neither side could carry one (sh/md/json/binary), so surprising is undefined rather than informative. file = the fil … [line truncated: 700 more bytes on this line] -{"name":"memory_recall","description":"Most relevant memory notes / docs for a task, full text — the few that matter, not the whole corpus. path = docs/memory dir; task = what you're working on; top_k = docs to return, 1..1000 (default 8), refused outside that band, never clamped; budget_tokens = … [line truncated: 790 more bytes on this line] -{"name":"situational_awareness","description":"The 5 things to know about a diff, as JSON: blast_radius, tests_to_run, forgotten (usual co-change partners missing from this diff), hotspot_alert, modules_touched. forgotten = the Shotgun Surgery check. diff/files optional — defaults to 'git diff HEA … [line truncated: 1297 more bytes on this line] -{"name":"mentions","description":"Docs (markdown plans/designs) that name a code symbol in a backtick. symbol = the code symbol name; limit/offset page the files. An @FILE:LINE line-seed rebinds to the innermost definition enclosing that line and answers for it, disclosing the rebound name as 'sym' … [line truncated: 625 more bytes on this line] -{"name":"for","description":"Task-lens ranked, signatures-only inventory of the building blocks most relevant to a task (cx=complexity, in=reuse-count). task = the task in plain words; budget_tokens = an optional soft row target (the CLI --for --token-budget). The header carries route= (which ranker … [line truncated: 1061 more bytes on this line] -{"name":"lego","description":"Interface-to-impls view for ONE named interface/base: its method contract plus EVERY implementor (own-language only), each with file path. Use when implementing against a KNOWN interface (contrast 'for', which sprays top interfaces for a task). type = interface/base nam … [line truncated: 841 more bytes on this line] -{"name":"owners","description":"Bus-factor: recency-weighted (6-month half-life) author ownership per file. symbol = optional, restricts to the file that defines it; limit/offset page the rows. at= is the commit these numbers were computed at (+dirty = the working tree differed). An @FILE:LINE line- … [line truncated: 879 more bytes on this line] -{"name":"replace_symbol_body","description":"Replace a symbol's ENTIRE definition (signature through closing brace) with new_body — splices over the full def span, preserving every byte outside it verbatim; new_body must be a complete, well-formed definition. One trailing newline folds (trailing_n … [line truncated: 1323 more bytes on this line] -{"name":"insert_before_symbol","description":"Insert text immediately BEFORE a symbol's definition (its first byte); padded to the file's own blank-line seam (separator_padded=N). Same refusal contract as replace_symbol_body (not found / ambiguous / stale index / symlink / concurrent write, file unc … [line truncated: 877 more bytes on this line] -{"name":"insert_after_symbol","description":"Insert text immediately AFTER a symbol's definition (past its final byte, which is preserved exactly); padded to the file's own blank-line seam (separator_padded=N); one trailing newline folds (trailing_newline_folded). Same refusal contract as replace_sy … [line truncated: 878 more bytes on this line] -{"name":"fetch_body","description":"Full (or partial-range) source of a symbol's definition, addressed by the stable `handle` a read verb attached to it (bodies on request, not by default). start_line/end_line are optional, 1-based, INCLUSIVE and BODY-RELATIVE (line 1 = the def's first line), clampe … [line truncated: 1049 more bytes on this line] -{"name":"exemplar","description":"BEFORE writing a function / method / class / struct / interface / variable, get the repo's single best-in-class instance of that kind to imitate — signature AND full body. chosen by ROLE, NEVER by text similarity to your task: candidates are first filtered to cogn … [line truncated: 1375 more bytes on this line] -{"name":"quality_delta","description":"Your PR self-check, run every time you think a change is DONE — pairs with the CLI-only --test-gate (names the tests to run + the untested blast radius; not MCP-exposed) to form the two-step pre-PR gate. Reports ONLY what your working tree made WORSE vs basel … [line truncated: 862 more bytes on this line] -{"name":"quality_baseline","description":"PIN the quality floor: writes .ripwire_quality_baseline stamped with the current git HEAD sha, snapshotting complexity / duplication / dead-code / API surface. Call once at the start of non-trivial work, then quality_delta compares against this pinned floor … [line truncated: 445 more bytes on this line] -{"name":"impact","description":"IS IT SAFE TO CHANGE X? — the TRANSITIVE blast radius of a symbol via calls, nearest first (d= hop depth), then PageRank. Use before modifying or deleting a symbol; it beats find_referencing_symbols (direct callers only), and 'uses' catches the read.rite/import sit … [line truncated: 1325 more bytes on this line] -{"name":"uses","description":"The STATICALLY RESOLVABLE use-sites of a symbol, not just calls: role (call | read | write | import | extends), file:line, and enclosing symbol. Use to see the footprint before renaming or changing a name — find_referencing_symbols and impact follow only calls. extern … [line truncated: 1146 more bytes on this line] -{"name":"affected","description":"WHICH TESTS TO RUN for a change — test files that transitively reach the changed files/symbols, ranked by evidence (edited > partner-named > hop distance). files = changed files and/or symbols, comma-separated: each item is tried as an indexed PATH pattern first, … [line truncated: 1238 more bytes on this line] -{"name":"path_between","description":"Does A REACH B, and HOW? — the shortest directed CALL path between two symbols, hop-by-hop. reachable=\"0\" hops=\"0\" is a valid 'not reachable' answer — call edges are name-based, so a missing dynamic/callback edge can hide a real path. Named path_between … [line truncated: 709 more bytes on this line] -{"name":"connect","description":"When a task touches 2..16 named symbols, returns the minimal subgraph RELATING them - terminals, the fewest joining intermediaries (with signatures), and call edges in true direction - finding the shared-caller joins a directed path_between cannot; unrelated symbols … [line truncated: 950 more bytes on this line] -{"name":"explore","description":"ONE-call task orientation: the routed+anchored ranking, full bodies of the top hits, their 1-hop callers, field notes, and tests_to_run — ALL under one deterministic byte budget, in a fixed section order (ranking > bodies > callers > notes > tests) that degrades gr … [line truncated: 2135 more bytes on this line] -{"name":"from_trace","description":"Paste a stack trace / sanitizer report / compiler error and get it mapped onto indexed symbols, ranked INNERMOST-first: the parsed frame map, the ranked suspects' signatures, and the innermost in-corpus symbol's FULL body. Out-of-corpus frames are listed a … [line truncated: 1233 more bytes on this line] -{"name":"edit_check","description":"Just edited a symbol? Did its CONTRACT (param count + publicness) change vs git HEAD, and which 1-hop callers are NOW INCOMPATIBLE with the new arity by fixed-arity evidence (not a guess — every folded definition disagrees)? This is call sites worth OPENING, not … [line truncated: 1908 more bytes on this line] -{"name":"whereis","description":"WHERE DOES THIS CONTENT LIVE? Which branch's tree defines or mentions a symbol, HEAD first, with on-head=0 naming the case this verb exists for: content that lives only on a branch (a finished fix stranded on 1 of 30 refs). Each distinct blob is read once (content-ad … [line truncated: 1475 more bytes on this line] -{"name":"stray_content","description":"Per branch: the lines its own divergent work AUTHORED (vs its merge-base with HEAD) that the live line does NOT have. Four verdicts (unmerged+superseded+merged+unknown=refs): v=unmerged is genuinely absent; v=superseded means the live line re-implemented the wo … [line truncated: 1123 more bytes on this line] -{"name":"flags","description":"WHAT IS BUILT BUT DARK here — the answer to 'why don't I see feature X?'. Harvests all three gate patterns (ifndef/define header gates, CMake option(), getenv reads) with each gate's kind, DEFAULT, the size of the code it guards, and its read sites. When a name is bo … [line truncated: 1434 more bytes on this line] -{"name":"doc_drift","description":"WHICH OF THIS REPO'S DOC CLAIMS ARE NOW FALSE. Verifies the CHECKABLE anchors in every markdown file against the live index and returns ONLY the ones that no longer hold: file:line refs (missing-file / past-eof / line-moved), backticked symbol mentions (undefined), … [line truncated: 1167 more bytes on this line] -{"name":"slice","description":"WHERE IS THIS VARIABLE DEFINED AND USED inside one function — NAME-BASED intra-procedural def-use rows of one variable inside ONE uniquely-resolved definition (the ARISE slicer, arXiv:2605.03117). symbol alone lists the sliceable locals to pick from; add var (or spel … [line truncated: 1722 more bytes on this line] -{"name":"batch","description":"ONE-TURN CONTEXT SWEEP: answer up to 16 heterogeneous READ sub-queries in a single call (the deterministic $0 counterpart of a parallel-search agent). queries = array over the SAME path, in EITHER grammar: {verb, ...args} objects, or the CLI --batch file's own \"verb:a … [line truncated: 2040 more bytes on this line] -````` - -The manifest, summarised (name / description bytes / required args) — what the host pays in context every session: - -````` -tools= 33 manifest_bytes= 47445 (~tokens at 4 bytes/token: 11861 ) -explore desc_bytes= 1340 schema_bytes= 958 required=['task'] -batch desc_bytes= 1235 schema_bytes= 962 required=['queries'] -edit_check desc_bytes= 1180 schema_bytes= 889 required=['symbol'] -slice desc_bytes= 953 schema_bytes= 932 required=['symbol'] -whereis desc_bytes= 701 schema_bytes= 941 required=['symbol'] -flags desc_bytes= 881 schema_bytes= 720 required=[] -exemplar desc_bytes= 954 schema_bytes= 591 required=[] -replace_symbol_body desc_bytes= 865 schema_bytes= 610 required=['symbol', 'new_body'] -impact desc_bytes= 821 schema_bytes= 666 required=['symbol'] -situational_awareness desc_bytes= 865 schema_bytes= 581 required=[] -affected desc_bytes= 790 schema_bytes= 610 required=['files'] -from_trace desc_bytes= 836 schema_bytes= 559 required=['trace'] -find_symbol desc_bytes= 752 schema_bytes= 590 required=['symbol'] -doc_drift desc_bytes= 728 schema_bytes= 604 required=[] -uses desc_bytes= 626 schema_bytes= 682 required=['symbol'] -stray_content desc_bytes= 678 schema_bytes= 604 required=[] -rank_by desc_bytes= 758 schema_bytes= 481 required=[] -for desc_bytes= 453 schema_bytes= 777 required=['task'] -fetch_body desc_bytes= 623 schema_bytes= 588 required=['handle'] -connect desc_bytes= 535 schema_bytes= 580 required=['symbols'] -find_referencing_symbols desc_bytes= 505 schema_bytes= 590 required=['symbol'] -insert_after_symbol desc_bytes= 458 schema_bytes= 577 required=['symbol', 'text'] -insert_before_symbol desc_bytes= 455 schema_bytes= 578 required=['symbol', 'text'] -owners desc_bytes= 425 schema_bytes= 625 required=[] -quality_delta desc_bytes= 742 schema_bytes= 279 required=[] -lego desc_bytes= 360 schema_bytes= 651 required=['type'] -grep desc_bytes= 445 schema_bytes= 562 required=['pattern'] -memory_recall desc_bytes= 447 schema_bytes= 500 required=['task'] -path_between desc_bytes= 357 schema_bytes= 506 required=['from', 'to'] -cochange desc_bytes= 388 schema_bytes= 476 required=['file'] -analyze desc_bytes= 546 schema_bytes= 318 required=[] -mentions desc_bytes= 305 schema_bytes= 486 required=['symbol'] -quality_baseline desc_bytes= 407 schema_bytes= 193 required=[] -````` - -## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ./build/ripwire --mcp --mcp-tools=core` - -*--mcp-tools=core: the server lists only the core profile's tools (explore, batch, from_trace, impact, uses, fetch_body, edit_check, quality_delta), so a host that loads every schema at session start pays only for those.* - -````` -{"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: 955 more bytes on this line] -{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"fetch_body","description":"Full (or partial-range) source of a symbol's definition, addressed by the stable `handle` a read verb attached to it (bodies on request, not by default). start_line/end_line are optional, 1-based, INCLUSIVE and BODY-RELAT … [line truncated: 1092 more bytes on this line] -{"name":"quality_delta","description":"Your PR self-check, run every time you think a change is DONE — pairs with the CLI-only --test-gate (names the tests to run + the untested blast radius; not MCP-exposed) to form the two-step pre-PR gate. Reports ONLY what your working tree made WORSE vs basel … [line truncated: 862 more bytes on this line] -{"name":"impact","description":"IS IT SAFE TO CHANGE X? — the TRANSITIVE blast radius of a symbol via calls, nearest first (d= hop depth), then PageRank. Use before modifying or deleting a symbol; it beats find_referencing_symbols (direct callers only), and 'uses' catches the read.rite/import sit … [line truncated: 1325 more bytes on this line] -{"name":"uses","description":"The STATICALLY RESOLVABLE use-sites of a symbol, not just calls: role (call | read | write | import | extends), file:line, and enclosing symbol. Use to see the footprint before renaming or changing a name — find_referencing_symbols and impact follow only calls. extern … [line truncated: 1146 more bytes on this line] -{"name":"explore","description":"ONE-call task orientation: the routed+anchored ranking, full bodies of the top hits, their 1-hop callers, field notes, and tests_to_run — ALL under one deterministic byte budget, in a fixed section order (ranking > bodies > callers > notes > tests) that degrades gr … [line truncated: 2135 more bytes on this line] -{"name":"from_trace","description":"Paste a stack trace / sanitizer report / compiler error and get it mapped onto indexed symbols, ranked INNERMOST-first: the parsed frame map, the ranked suspects' signatures, and the innermost in-corpus symbol's FULL body. Out-of-corpus frames are listed a … [line truncated: 1233 more bytes on this line] -{"name":"edit_check","description":"Just edited a symbol? Did its CONTRACT (param count + publicness) change vs git HEAD, and which 1-hop callers are NOW INCOMPATIBLE with the new arity by fixed-arity evidence (not a guess — every folded definition disagrees)? This is call sites worth OPENING, not … [line truncated: 1908 more bytes on this line] -{"name":"batch","description":"ONE-TURN CONTEXT SWEEP: answer up to 16 heterogeneous READ sub-queries in a single call (the deterministic $0 counterpart of a parallel-search agent). queries = array over the SAME path, in EITHER grammar: {verb, ...args} objects, or the CLI --batch file's own \"verb:a … [line truncated: 2040 more bytes on this line] -````` - -The core manifest, summarised (name / description bytes / required args): - -````` -tools= 8 manifest_bytes= 14186 (~tokens at 4 bytes/token: 3546 ) -explore desc_bytes= 1340 schema_bytes= 958 required=['task'] -batch desc_bytes= 1235 schema_bytes= 962 required=['queries'] -edit_check desc_bytes= 1180 schema_bytes= 889 required=['symbol'] -impact desc_bytes= 821 schema_bytes= 666 required=['symbol'] -from_trace desc_bytes= 836 schema_bytes= 559 required=['trace'] -uses desc_bytes= 626 schema_bytes= 682 required=['symbol'] -fetch_body desc_bytes= 623 schema_bytes= 588 required=['handle'] -quality_delta desc_bytes= 742 schema_bytes= 279 required=[] -````` - -## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"for","arguments":{"path":".","task":"pagerank power iteration"}}}' | ./build/ripwire --mcp` - -*MCP `for`: always bundle=sigs (never the CLI's compact route), the same ranked signatures as --for.* - -**wall time: 1.45s** - -````` -{"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: 738 more bytes on this line] -{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":". window: shown= capped= (capped=1 cut). at=: commit+dirty+shallow. next= … [line truncated: 1194 more bytes on this line] -"_index":"[index: files=3607 symbols=31702 hash=1d175297]","_fresh":"ok"}} -{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":" - + @@ -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 +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=952 -━━ 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] -### `--field-affinity[=STRUCT]` +━━ commands.md (relevance 11.026) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 589285 B; lines="556-581"; dropped_by_budget=163] [truncated: 1854 of 4257 bytes] +#### Pattern: a directory of dumped tool output as a knowledge base -**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. +**Answers:** can `--recall` serve as a zero-setup knowledge base over dumped tool output — a +`git log`, an API response dump, a fetched doc, ` --help` text — sitting in a scratch +directory, instead of a source repo? -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] +Yes, unmodified. `--recall` never distinguishes "a codebase" from any other directory it can +walk: point it at the scratch dir and query it. No index to build, no daemon, no mutable store +between runs — the whole cost is one cold parse. Two conditions decide whether it works at all, +and both are yours, because the file you write is the only thing that sets them: -(capped: 1 of 2 relevant document files omitted — raise --max-tokens/budget_tokens or narrow the query for 1 more (~2548-byte budget)) +... [17 more line(s); run it to see the whole thing] ``` ### `--tree` @@ -623,7 +628,7 @@ _File-by-file orientation map (top symbols per file)._ ``` $ ./build/ripwire . --tree - + @@ -632,7 +637,7 @@ $ ./build/ripwire . --tree - + @@ -727,7 +732,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 +766,7 @@ $ ./build/ripwire . --around=rankGraphTeleport - + @@ -813,18 +818,18 @@ _What SYM calls (1-hop out-edges)._ ``` $ ./build/ripwire . --callees=rankGraphTeleport - - + + - - - - - - + + + + + + ``` @@ -848,10 +853,10 @@ _The resolvable use-sites (call/read/write/import/extends) with file:line; count ``` $ ./build/ripwire . --uses=rankGraphTeleport - + - - + + @@ -882,13 +887,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 +924,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 +959,12 @@ _Shortest directed call-path SRC -> DST. CHANGED: now reports from_p/to_p/from_d ``` $ ./build/ripwire . --path=main,rankGraphTeleport - + - + ``` @@ -976,10 +981,10 @@ _Minimal connecting subgraph over 3 symbols (finds shared-caller joins)._ ``` $ ./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex - + - + @@ -1086,7 +1091,7 @@ _Test files that transitively reach the changed file._ ``` $ ./build/ripwire . --affected=src/graph.h - @@ -1143,7 +1148,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: 79e691876 (0 changed files — working tree is clean, nothing to analyze) ``` @@ -1162,18 +1167,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 +1202,7 @@ _Pre-PR gate on a CLEAN tree: no obligations, exit 0._ ``` $ ./build/ripwire . --test-gate - ``` @@ -1280,18 +1285,18 @@ _Boolean grep: hits where BOTH literals share the matched line (--grep-scope=lin $ ./build/ripwire . --grep=DISCLOSE --and=cache - + - + - + @@ -1524,7 +1529,7 @@ _Importance-weighted detail: FULL bodies for top-2, signatures for the rest._ ``` $ ./build/ripwire . --for="pagerank power iteration" --detail=2 - + @@ -1559,7 +1564,7 @@ $ ./build/ripwire . --pack-signatures --top-k=10 - + @@ -1590,7 +1595,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 +1626,7 @@ $ ./build/ripwire . --top-k=0 --expand=rankGraphTeleport - + + - + - + @@ -1794,7 +1799,7 @@ _File->file dependency graph (god-files, cycles)._ $ ./build/ripwire . --deps - + @@ -1830,10 +1835,10 @@ _Complexity x recent git churn (maintenance pain)._ $ ./build/ripwire . --hotspots - - + + - + @@ -1858,7 +1863,7 @@ _Token-normalized duplicate bodies._ ``` $ ./build/ripwire . --clones - + @@ -1868,7 +1873,7 @@ $ ./build/ripwire . --clones - + ... [17 more line(s); run it to see the whole thing] @@ -1889,8 +1894,8 @@ _Per-function size ranking, largest Halstead volume/token entropy/lines first ``` $ ./build/ripwire . --biggest-first --limit=8 - - + + @@ -1922,7 +1927,7 @@ _Per function, the non-local MUTABLE state it can reach (transitively), most wri ``` $ ./build/ripwire . --nonlocal-state --limit=8 - @@ -1957,7 +1962,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -1988,17 +1993,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 +2030,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 +2061,8 @@ _Score the naming-* rules against this repo's own rename history: proxy=old/(old ``` $ ./build/ripwire . --naming-calibration - - + + @@ -2091,10 +2096,10 @@ _The corpus's OWN case-convention vote per (language, kind) group; off-conventio ``` $ ./build/ripwire . --naming-consistency --limit=8 - - - - + + + + @@ -2128,7 +2133,7 @@ _The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/ ``` $ ./build/ripwire . --lint --naming-locals - + @@ -2163,7 +2168,7 @@ _Functions WITH a doc comment, most name-restating first: c_coeff (high = the co ``` $ ./build/ripwire . --comment-coherence --limit=8 - + @@ -2196,16 +2201,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 +2233,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 +2259,7 @@ _Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none ``` $ ./build/ripwire . --cochange --cochange-groups - + @@ -2283,10 +2288,10 @@ _Hotspots scoped to RECENT churn (the regression lens)._ ``` $ ./build/ripwire . --hotspots --since="2 weeks ago" - - + + - + @@ -2294,7 +2299,7 @@ $ ./build/ripwire . --hotspots --since="2 weeks ago" - + ... [17 more line(s); run it to see the whole thing] ``` @@ -2321,7 +2326,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - @@ -2351,7 +2356,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - @@ -2377,7 +2382,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - @@ -2404,7 +2409,7 @@ _Built-in AST checks (c-cast, goto, unsafe-c-fn, ...)._ ``` $ ./build/ripwire . --lint - + @@ -2627,15 +2632,15 @@ _Cluster the call graph into cohesive modules._ ``` $ ./build/ripwire . --communities - + - + - + @@ -2658,7 +2663,7 @@ _Drill into ONE call-graph community by id — the drill= the --communities outp ``` $ ./build/ripwire . --community=0 - ``` @@ -2683,15 +2688,15 @@ _Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels ``` $ ./build/ripwire . --zoom - - + + - - + + - + @@ -2720,15 +2725,15 @@ $ ./build/ripwire . --report # ripwire architecture report -3618 files · 31790 symbols · 29969 edges · 3610 modules (14921 call-graph isolated) +3627 files · 31838 symbols · 30013 edges · 3619 modules (14940 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, 3382 source, 5130 document; 0 connected Louvain singletons -## Modules (call-graph clusters; showing 12 of 3610) +## Modules (call-graph clusters; showing 12 of 3619) - **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1631 symbols -- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 547 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 +2751,7 @@ _Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped._ ``` $ ./build/ripwire . --seams - + @@ -2777,15 +2782,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"] + n961["test/slotjoinfix
175"] + n803["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 +2811,8 @@ _Bus-factor: recency-weighted author ownership per file._ ``` $ ./build/ripwire . --owners - - + + @@ -2837,7 +2842,7 @@ _Internal functions with no caller found in the index — a name-based graph rea ``` $ ./build/ripwire . --dead-code=src - + ``` @@ -2902,7 +2907,7 @@ _The same clean verdict with what it folded printed back: every stale acknowledg ``` $ ./build/ripwire . --quality-delta --show-stale - @@ -2931,7 +2936,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2956,7 +2961,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2981,7 +2986,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 -

-

+

-

+

-… [154 more display lines; full output is 16043 bytes on 1 raw line(s)] +… [156 more display lines; full output is 16229 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --lint --naming-locals` *The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/C++ only, only inside functions already past a size/complexity gate.* -**wall time: 3.89s** +**wall time: 3.82s** ````` - + @@ -5891,7 +5898,7 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir - + @@ -5911,7 +5918,7 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The built-in rule registry — one row per rule with sev=/category=/rationale/lang=/since=; no corpus needed.* -**wall time: 1.16s** +**wall time: 1.99s** ````` @@ -5989,7 +5996,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *Run ONLY one rule family; the root carries selected="K of N" so a filtered zero is never confusable with an unfiltered one.* -**wall time: 3.34s** +**wall time: 4.53s** ````` @@ -6029,7 +6036,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *DROP two families, applied after selection; the raw select=/ignore= you passed rides on the root.* -**wall time: 3.06s** +**wall time: 4.56s** ````` @@ -6069,7 +6076,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *A rule that spends its own match budget (here 4, set BELOW the default 5000 so the floor shows on this repo): goto carries count_capped="1", its count= is a FLOOR, and the root names the call that counts the rest — findings_next= re-runs only the floored rules under a 10x budget.* -**wall time: 2.91s** +**wall time: 4.31s** ````` @@ -6086,7 +6093,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *Pasting that findings_next=: the same rule under a 10x budget counts its true total — no count_capped=, no findings_next=.* -**wall time: 3.26s** +**wall time: 7.17s** ````` @@ -6117,7 +6124,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *An unresolvable PREFIX refuses (exit 1) with a did-you-mean from a real edit distance (one character off cache-).* -**exit code: 1** — **wall time: 2.98s** +**exit code: 1** — **wall time: 4.29s** ````` (empty) @@ -6133,7 +6140,7 @@ ripwire: --lint-select: 'cach-' matches no rule or family (did you mean 'cache-' *A PREFIX with no near miss at all: the refusal points at --lint-catalog instead of guessing.* -**exit code: 1** — **wall time: 2.80s** +**exit code: 1** — **wall time: 3.70s** ````` (empty) @@ -6149,7 +6156,7 @@ ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint- *The SAME findings as SARIF 2.1.0 (what github/codeql-action/upload-sarif consumes) — pure re-serialization, results count == the native run's.* -**wall time: 3.34s** +**wall time: 4.41s** ````` {"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"name":"ripwire","rules":[{"id":"c-style-cast","shortDescription":{"text":"c-style-cast"},"properties":{"builtin":true,"capped":false,"applicable": … [line truncated: 7 more bytes on this line] @@ -6182,13 +6189,13 @@ ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint- {"id":"atom-nested-ternary","shortDescription":{"text":"atom-nested-ternary"},"properties":{"builtin":true,"capped":false,"applicable":true}}, {"id":"atom-implicit-predicate","shortDescription":{"text":"atom-implicit-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, {"id":"atom-octal-literal","shortDescription":{"text":"atom-octal-literal"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -… [13475 more display lines; full output is 1907616 bytes on 1 raw line(s)] +… [13479 more display lines; full output is 1908209 bytes on 1 raw line(s)] ````` Parsed summary of the same SARIF (past the display cut): ````` -sarif 2.1.0 rules= 39 results= 6733 +sarif 2.1.0 rules= 39 results= 6735 ````` ## `./build/ripwire . --lint --sarif --limit=5` @@ -6211,11 +6218,11 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The Delta Maintainability Model scalar for the WORKING TREE vs HEAD — recorded against a CLEAN tree (the sandbox section shows a real delta). UNAVAILABLE is a stated reason, never 0 or 1.* -**wall time: 8.72s** +**wall time: 18.66s** ````` -

@@ -6226,11 +6233,11 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The per-commit scalar: HEAD vs its first parent, with the three separately actionable sub-scores.* -**wall time: 17.60s** +**wall time: 30.01s** ````` -

@@ -6241,14 +6248,14 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The range form: tree HEAD vs tree HEAD~3.* -**wall time: 16.23s** +**wall time: 24.93s** ````` - -

-

+ +

+

````` @@ -6256,11 +6263,11 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none of which it depends on" — a greedy cover, disclosed as greedy.* -**wall time: 4.06s** +**wall time: 10.00s** ````` - + @@ -6289,48 +6296,48 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M -… [846 more display lines; full output is 56221 bytes on 1 raw line(s)] +… [847 more display lines; full output is 56290 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --cochange --cochange-recur=2` *Only pairs whose co-change RECURS in 2+ sub-windows of the mined window (sub_windows= is the denominator) — a one-off sprint stops reading like a structural defect.* -**wall time: 4.76s** +**wall time: 12.14s** ````` - + - - - + + + - + - - + + + + - + - + - - - + ````` @@ -6338,7 +6345,7 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector).* -**wall time: 4.25s** +**wall time: 9.28s** ````` (empty) @@ -6347,14 +6354,14 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M Artifact written: ````` - 156171 /aux/map2.html + 156039 /aux/map2.html ````` ## `./build/ripwire . --index-out=/aux/ci_index` *CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout.* -**wall time: 5.75s** +**wall time: 7.32s** ````` (empty) @@ -6363,28 +6370,28 @@ Artifact written: stderr: ````` -ripwire: --index-out wrote /aux/ci_index.lean.ripwirecache (28475910 bytes, lean family) -ripwire: --index-out wrote /aux/ci_index.rich.ripwirecache (58343715 bytes, rich family) +ripwire: --index-out wrote /aux/ci_index.lean.ripwirecache (28772140 bytes, lean family) +ripwire: --index-out wrote /aux/ci_index.rich.ripwirecache (58967687 bytes, rich family) ````` Artifact written: ````` - 28475910 /aux/ci_index.lean.ripwirecache - 58343715 /aux/ci_index.rich.ripwirecache - 86819625 total + 28772140 /aux/ci_index.lean.ripwirecache + 58967687 /aux/ci_index.rich.ripwirecache + 87739827 total ````` ## `./build/ripwire . --cache=/aux/ci_index.lean.ripwirecache --top-k=3` *Consume the lean artifact in a PR job: restore-equivalence, never blob-byte-identity.* -**wall time: 1.77s** +**wall time: 2.95s** ````` - + @@ -6399,7 +6406,7 @@ Artifact written: - + @@ -6419,12 +6426,12 @@ Artifact written: *Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target.* -**wall time: 2.81s** +**wall time: 4.57s** ````` - + @@ -6439,7 +6446,7 @@ Artifact written: - + @@ -6466,18 +6473,18 @@ Artifact written: # whose template-argument list spans lines keeps its line break as \n instead of splitting the row. # line is the 1-based call-site line in the caller's file (v2, appended LAST so v1 readers are unchanged): # the key a SCIP occurrence joins on, so a coverage loss can be classified per site instead of guessed. - 129411 /aux/pin_census.tsv + 129568 /aux/pin_census.tsv ````` ## `./build/ripwire . --plan-lint=test/planlintfix/wave.md` *The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates.* -**exit code: 2** — **wall time: 4.10s** +**exit code: 2** — **wall time: 6.82s** ````` - + @@ -6495,11 +6502,11 @@ Artifact written: *The ledger-shaped fixture through the same check (exit 2: one gating card).* -**exit code: 2** — **wall time: 4.38s** +**exit code: 2** — **wall time: 11.51s** ````` - + @@ -6511,18 +6518,18 @@ Artifact written: *--doctor plus a LIVE integration inspection for one agent: PATH binary, installed-skill manifest parity, hook executability, MCP wiring — read-only, fixed repair commands, never config contents; exit 1 when any check fails.* -**exit code: 1** — **wall time: 35.51s** +**exit code: 1** — **wall time: 61.05s** ````` - - + - - + + - - + @@ -6535,7 +6542,7 @@ Artifact written: *Other --agent values refuse.* -**exit code: 1** +**exit code: 1** — **wall time: 1.46s** ````` (empty) @@ -6558,15 +6565,15 @@ Everything below runs with `cwd` = the throwaway clone at `/dirty` (`gi *Situational report for a real diff: blast radius + tests + co-change + forgotten co-change partners.* -**wall time: 15.47s** +**wall time: 18.77s** ````` ripwire situational-awareness — 1 changed file(s), 13 symbols in them root: . -at: d3605fde7+dirty +at: 79e691876+dirty change_set: granularity=file changed_symbols=13 file_symbols=13 files_narrowed=0 files_file_granular=1 diff_hunks=7 diff_hunks_located=6 diff_hunks_unlocated=1 — seeds = symbols a diff -U0-vs-HEAD hunk overlaps (function/method body spans only); an unlocated hunk (module-level, deletion, rename) … [line truncated: 34 more bytes on this line] [1] blast radius: 246 symbols across 58 files transitively depend on these changes (showing 8 of 58 files — shown=8 total=58 capped=1 prcontext_cap=20 (--pr-context's own per-file list is cut at 20 too); next: --situ --limit=58) - counts_floor=1 graph_ambiguous=2927 graph_unresolved=15221 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] + counts_floor=1 graph_ambiguous=2932 graph_unresolved=15244 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] src/mcpverbs.h (33 dependent symbols) src/quality.h (15 dependent symbols) src/verbs_quality.h (14 dependent symbols) @@ -6582,8 +6589,8 @@ at: d3605fde7+dirty test/verify_csr.cpp [hops=2] (run: bash test/a9disclosurecheck.sh) test/rustimport_unit.cpp [hops=4] (run: bash test/rustimportprecisecheck.sh) script_gates_unmodelled=782 — test/*.sh gates never appear above: script-to-binary edges are not call edges (a path count) - [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5267": - (none — 5267 commits were mined and none co-edited a file outside your diff) + [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5284": + (none — 5284 commits were mined and none co-edited a file outside your diff) next: --test-gate ````` @@ -6591,11 +6598,11 @@ at: d3605fde7+dirty *The pre-PR gate with real obligations — exit 4 when tests-to-run or untested blast radius is non-empty.* -**exit code: 4** — **wall time: 11.69s** +**exit code: 4** — **wall time: 17.32s** ````` - @@ -6606,7 +6613,7 @@ at: d3605fde7+dirty - + @@ -6633,11 +6640,11 @@ at: d3605fde7+dirty *Every row carries p="file:line", the gating rows are marked gating="1" and now bar= (the threshold each numeric row is judged against), and the exit-2 refusal prints a naming line on stderr; a gating row carries a pasteable next=.* -**exit code: 2** — **wall time: 48.22s** +**exit code: 2** — **wall time: 63.43s** ````` - @@ -6672,7 +6679,6 @@ at: d3605fde7+dirty stderr: ````` -ripwire: cache : over its 2048 MiB budget — evicted 29 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) ````` @@ -6681,11 +6687,11 @@ ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: ap *The same gating report under --legend=full — same rows, same exit 2; the default compact comment (schema="ripwire.quality-delta/v1", the shape an agent's edit loop should run) becomes ~4 KB of prose legend.* -**exit code: 2** — **wall time: 29.04s** +**exit code: 2** — **wall time: 39.15s** ````` - @@ -6728,10 +6734,10 @@ ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: ap *The same findings as JSON (one of the CI/scripting verbs --json supports) — same exit 2 as the XML form.* -**exit code: 2** — **wall time: 28.47s** +**exit code: 2** — **wall time: 32.41s** ````` -{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"d3605fde7+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] +{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"79e691876+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] {"kind":"complexity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":67,"p":"src/infra/sortutil.h:49","gating":true}, {"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy","p":"src/infra/sortutil.h:119","origin":"new-symbol"}, {"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","p":"src/infra/sortutil.h:129","origin":"new-symbol"}, @@ -6775,7 +6781,7 @@ ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: ap *NEW FLAG: --ack-only matching nothing REFUSES rather than falling back to acking everything.* -**exit code: 1** — **wall time: 18.31s** +**exit code: 1** — **wall time: 25.59s** ````` (empty) @@ -6793,7 +6799,7 @@ ripwire: --ack-only=zzznope matched none of the 9 finding(s) — nothing written *NEW FLAG: ack only the api-surface findings — a per-finding ratchet instead of a rubber stamp.* -**wall time: 21.91s** +**wall time: 23.30s** ````` (empty) @@ -6811,11 +6817,11 @@ ripwire: acknowledged 1 of 9 finding(s) (8 left UNACKED by --ack-only, 0 already *Re-run after the partial ack: acked=3, the rest still gate (exit 2).* -**exit code: 2** — **wall time: 30.42s** +**exit code: 2** — **wall time: 41.14s** ````` - @@ -6874,11 +6880,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - @@ -6890,11 +6896,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire row identical.* -**wall time: 7.72s** +**wall time: 4.85s** ````` - @@ -6906,11 +6912,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - @@ -6946,13 +6952,13 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire ) and selectors take it. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. --> - - + + @@ -6977,11 +6983,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire of ; dup_loc=/dup_pct=. window: shown= total= capped= has_more= next_offset= offset= limit= (capped=1 cut; next_offset= pastes as offset=). root=: p= relative to it. groups=/type3=: Type-2 and Type-3 group totals over all groups; total= is their sum. exempt_groups=N: groups whose members all sit on fixture/shell-runner paths quality-delta duplication ignores. idiom_groups=/demoted_groups=: groups of one recognized idiom / those quality-delta demotes to minor; floors. clone_groups=N: clusters after merging pairs (rows sharing gid=); a floor under type3_capped=1. total_loc=N: lines of every function body the detector considered; dup_pct= is dup_loc= over it. group exempt=fixture|shell-runner: every member is on such a path; quality-delta duplication ignores it. group idiom=: the recognized shape every member spells: threshold-ladder, switch-name-table, builder-chain. --> - + @@ -6991,7 +6997,7 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - + @@ -7006,7 +7012,7 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - + @@ -7017,12 +7023,12 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire ; v=unknown = no merge base. at=: commit+dirty+shallow. head=: the HEAD commit, bare 9-hex sha (at= adds +dirty). head_ref=: HEAD's branch (HEAD when detached); that branch itself is not scanned. refs=N: local branches scanned (refs/heads only); unmerged + superseded + merged + unknown = refs. blobs=N: distinct git blobs read for the sweep. unmerged=N: refs whose authored work the live line genuinely lacks. superseded=N: refs whose work the live line re-implemented (removed the same base code). merged=N: refs whose work HEAD already has; omitted from the rows. name=: the local branch. tip=: the branch tip commit (9 hex). date=: the tip's committer date, YYYY-MM-DD. files=N: files with stray lines; rows capped at 12, a more element counts the rest (detail=1 lists all). ref superseded=N>: of this ref's stray= lines, those in files the live line re-implemented. unknown=N: refs that could not be analysed (v=unknown, e.g. no merge base); never counted merged. --> - - + + ````` @@ -7037,11 +7043,11 @@ stderr: *CHANGED: --plan surfaces those same refs as an row rather than silently dropping them.* -**wall time: 10.90s** +**wall time: 18.10s** ````` - + ````` @@ -7056,11 +7062,11 @@ stderr: *The DMM scalar on a REAL delta: the sandbox edit grew one unit past the nesting/complexity thresholds and added an 8-parameter one, so dmm is low and the three sub-scores say which property moved.* -**wall time: 12.21s** +**wall time: 14.73s** ````` -

@@ -7071,11 +7077,11 @@ stderr: *OWNERSHIP partition for a shared tree: every regression here lives in src/infra/, so under a scope naming src/graph.h they ALL print under with a do-not-ack banner and never gate — scoped-out-gating= says how many would have.* -**wall time: 31.39s** +**wall time: 22.40s** ````` - @@ -7117,7 +7123,7 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *The rubber-stamp guard: an --ack-only that names an OUT-OF-SCOPE row refuses (exit 1) and writes nothing.* -**exit code: 1** — **wall time: 25.91s** +**exit code: 1** — **wall time: 17.86s** ````` (empty) @@ -7137,11 +7143,11 @@ ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=sr *The continuation packet with a REAL diff: verified changed symbols + blast radius + tests-to-run, then the heuristic rows.* -**wall time: 19.11s** +**wall time: 12.31s** ````` - + @@ -7166,11 +7172,11 @@ ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=sr - - - - - + + + + + ````` @@ -7179,10 +7185,10 @@ ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=sr *Pin a field note (write-side memory) to a symbol; committed to .ripwire_notes in the sandbox. The BARE name is resolved through the same resolver the read verbs use and stored as the canonical id — the rewrite is echoed on stderr, because a silent one is not a disclosure.* -**wall time: 4.48s** +**wall time: 4.38s** ````` -src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 keep this branch-free — it sits inside the PageRank sort comparator d3605fde7ff60e4b1fca435f5a35be61b5879617 integration/train-35 +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 keep this branch-free — it sits inside the PageRank sort comparator 79e6918767f2b64a78d55955c4ddfd1cdeb31874 integration/train-36 ````` stderr: @@ -7196,7 +7202,7 @@ ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sort *The note is listed under the canonical id, dangling="0" — i.e. it will actually surface. (Before the H1 fix the bare name was stored verbatim and read dangling="1": recorded, and surfaced nowhere.)* -**wall time: 2.01s** +**wall time: 1.53s** ````` @@ -7209,7 +7215,7 @@ ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sort - + @@ -7226,7 +7232,7 @@ ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sort *Two definitions carry this name, so the write REFUSES rather than pick one: a note keys ONE canonical id, and an ambiguous selector is refused, never silently narrowed. Every candidate is named, with a runnable retry.* -**exit code: 1** — **wall time: 1.61s** +**exit code: 1** — **wall time: 1.64s** ````` (empty) @@ -7243,7 +7249,7 @@ ripwire: --note-add: target 'gitOneLine' is ambiguous — it matches 2 definitio *A name that resolves to nothing is refused with the read verbs' own did-you-mean — never written as a dead note.* -**exit code: 1** — **wall time: 1.89s** +**exit code: 1** — **wall time: 2.10s** ````` (empty) @@ -7260,17 +7266,17 @@ ripwire: --note-add: target not found: lessByScoreDescIdd (did you mean 'lessByS *The same symbol addressed by its CANONICAL id: already canonical, so nothing is rewritten and both notes land on ONE target.* -**wall time: 4.92s** +**wall time: 4.38s** ````` -src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort d3605fde7ff60e4b1fca435f5a35be61b5879617 integration/train-35 +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort 79e6918767f2b64a78d55955c4ddfd1cdeb31874 integration/train-36 ````` ## `./build/ripwire . --expand=lessByScoreDescId --top-k=0` *Both notes riding along with the symbol's body — the elements follow the body, past the display cut, so they are extracted below.* -**wall time: 2.25s** +**wall time: 1.72s** ````` @@ -7309,10 +7315,10 @@ src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat The element on the same output — past the 30-line display cut above: ````` - + - + ````` @@ -7337,7 +7343,7 @@ ripwire: --edit-payload is empty; empty never means delete *Whole-symbol replace without a whole-file read: the payload is the ORIGINAL flat body, so this edit undoes the sandbox's deep-nesting regression. The receipt's span is the POST-edit byte range; replaced_bytes counts the old bytes overwritten.* -**wall time: 12.04s** +**wall time: 13.31s** Input file: @@ -7354,17 +7360,18 @@ inline bool lessByScoreDescId( const std::vector& scores, std::uint32_t a ````` {"applied":"replace_symbol_body","symbol":"lessByScoreDescId","file":"src/infra/sortutil.h","span":{"start":2162,"end":2375},"lines":{"start":49,"end":56},"replaced_bytes":1718,"old_file_bytes":12329,"new_file_bytes":10824,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separa … [line truncated: 726 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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ````` stderr: ````` +ripwire: cache : over its 2048 MiB budget — evicted 189 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: bash test/greptiercheck.sh ````` @@ -7372,15 +7379,15 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *The closed loop: contract unchanged (same params, same publicness) after the replace — nothing provably incompatible.* -**wall time: 7.03s** +**wall time: 6.77s** ````` - + - + @@ -7394,16 +7401,16 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call.* -**wall time: 10.36s** +**wall time: 8.39s** ````` {"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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ````` stderr: @@ -7416,7 +7423,7 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr.* -**wall time: 4.81s** +**wall time: 2.85s** ````` {"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] @@ -7432,19 +7439,19 @@ ripwire edit: applied atomically; receipt carries region, blob_sha (post-check s *Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured).* -**wall time: 12.13s** +**wall time: 6.44s** ````` {"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] {"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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ````` stderr: @@ -7457,7 +7464,7 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *An unknown TARGET refuses and leaves every file byte-identical.* -**exit code: 1** — **wall time: 5.26s** +**exit code: 1** — **wall time: 2.79s** ````` (empty) @@ -7473,7 +7480,7 @@ ripwire: --replace-symbol-body: symbol 'DoesNotExist' not found *A versioned multi-edit TRANSACTION preflighted without writing: the receipt shows what each op would read and touch.* -**wall time: 4.45s** +**wall time: 2.38s** Input file: @@ -7491,21 +7498,21 @@ Input file: ````` ````` -{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 344 more bytes on this line] +{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 353 more bytes on this line] ````` ## `./build/ripwire . --edit-plan=/aux/edit_plan.json --apply` *The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure.* -**wall time: 11.12s** +**wall time: 7.72s** ````` -{"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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true}}]} ````` ## `./build/ripwire . --edit-plan=/aux/edit_plan.json` @@ -7528,11 +7535,11 @@ ripwire: --edit-plan requires exactly one of --dry-run or --apply *After the agent's edits: the complexity/nesting rows on lessByScoreDescId are gone (the replace undid them), the rest still gate (exit 2).* -**exit code: 2** — **wall time: 29.22s** +**exit code: 2** — **wall time: 28.21s** ````` - @@ -7575,7 +7582,7 @@ ripwire: --quality-delta gating: 2 preexisting-worse major finding(s); first: du *REFUSES, exit 1: this sandbox tree is already regressed, and pinning here would swallow that debt into the floor so every later delta read clean. It names how many gating findings it would absorb, the first of them, and the way forward.* -**exit code: 1** — **wall time: 18.75s** +**exit code: 1** — **wall time: 26.75s** ````` (empty) @@ -7594,7 +7601,7 @@ ripwire: --quality-baseline: this tree already holds 2 gating finding(s) against *The consent form: pin anyway. The sidecar is stamped with the dirty pin and the absorbed count, so the fact outlives the process that knew it.* -**wall time: 24.54s** +**wall time: 21.24s** ````` (empty) @@ -7604,16 +7611,16 @@ stderr: ````` ripwire: --quality-baseline --allow-dirty: pinned with 2 gating finding(s) ABSORBED into the floor (stamped in the sidecar; every --quality-delta against it carries baseline_absorbed="2") -ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30854 per-symbol rows, 31792 indexed symbols total) +ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30902 per-symbol rows, 31840 indexed symbols total) ````` Artifact written: ````` - 5222950 .ripwire_quality_baseline + 5231049 .ripwire_quality_baseline # ripwire quality baseline v6 — regenerate with --quality-baseline; do not hand-edit -producer 934e2d834419518852b1c5321e5f49e8c32c33360e02046f99df50af7118aef1 -head d3605fde7ff60e4b1fca435f5a35be61b5879617 +producer 72f3abff6b630f368c12b1d27b427d7c9f2d913bf0dc07f5a47404b420717362 +head 79e6918767f2b64a78d55955c4ddfd1cdeb31874 dirty 1 absorbed 2 ccx 67c15011ee8b 0 @@ -7626,11 +7633,11 @@ ccx 6a732f6699b *Against that sidecar the same tree reads regressions=0 — but baseline_absorbed= is on the root, so this green means clean SINCE THE PIN, never clean. A baseline is a floor YOU chose, and it belongs BEFORE the change.* -**wall time: 23.04s** +**wall time: 22.65s** ````` - ````` @@ -7753,57 +7760,57 @@ quality_delta desc_bytes= 742 schema_bytes= 279 required=[] *MCP `for`: always bundle=sigs (never the CLI's compact route), the same ranked signatures as --for.* -**wall time: 5.74s** +**wall time: 7.04s** ````` {"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: 738 more bytes on this line] -{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":". window: shown= capped= (capped=1 cut). at=: commit+dirty+shallow. next= … [line truncated: 6553 more bytes on this line] -"_index":"[index: files=3618 symbols=31790 hash=09a95744]","_fresh":"ok"}} +"_index":"[index: files=3627 symbols=31838 hash=998d23bf]","_fresh":"ok"}} {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":" - + @@ -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,11 +215,11 @@ _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 ### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e` @@ -252,7 +252,7 @@ _Restore the / sections the --for bundle collapses to a counted s ``` $ ./build/ripwire . --for="tree-sitter parse of a source file" --sections=lego,compose - + @@ -279,11 +279,11 @@ _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 ### Wave-2 adversarial verification (2026-08-19) — six probes against `aa97c9e` @@ -314,7 +314,7 @@ _Opt OUT of compact conceptual serving: restore the rank-first auto wal ``` $ ./build/ripwire . --for="tree-sitter parse of a source file" --auto-bodies - + @@ -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,7 +378,7 @@ _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 - + @@ -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,7 +439,7 @@ _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 - + @@ -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=952 +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 11.026) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 589285 B; lines="556-581"; dropped_by_budget=163] [truncated: 1854 of 4257 bytes] -#### Pattern: a directory of dumped tool output as a knowledge base +━━ 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:** can `--recall` serve as a zero-setup knowledge base over dumped tool output — a -`git log`, an API response dump, a fetched doc, ` --help` text — sitting in a scratch -directory, instead of a source repo? +**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. -Yes, unmodified. `--recall` never distinguishes "a codebase" from any other directory it can -walk: point it at the scratch dir and query it. No index to build, no daemon, no mutable store -between runs — the whole cost is one cold parse. Two conditions decide whether it works at all, -and both are yours, because the file you write is the only thing that sets them: +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] -... [17 more line(s); run it to see the whole thing] +(capped: 1 of 2 relevant document files omitted — raise --max-tokens/budget_tokens or narrow the query for 1 more (~2548-byte budget)) ``` ### `--tree` @@ -628,7 +623,7 @@ _File-by-file orientation map (top symbols per file)._ ``` $ ./build/ripwire . --tree - + @@ -732,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 - + @@ -766,7 +761,7 @@ $ ./build/ripwire . --around=rankGraphTeleport - + @@ -818,7 +813,7 @@ _What SYM calls (1-hop out-edges)._ ``` $ ./build/ripwire . --callees=rankGraphTeleport - + @@ -853,7 +848,7 @@ _The resolvable use-sites (call/read/write/import/extends) with file:line; count ``` $ ./build/ripwire . --uses=rankGraphTeleport - + @@ -887,7 +882,7 @@ _Composable node-set query: functions within 2 caller-hops of rankGraphTeleport. ``` $ ./build/ripwire . --graph-query='and(callers(name("rankGraphTeleport"),2),kind(all,fn))' - + @@ -924,8 +919,8 @@ _Names referenced but never defined in-corpus (stdlib/third-party surface). The ``` $ ./build/ripwire . --external-surface - - + + @@ -959,7 +954,7 @@ _Shortest directed call-path SRC -> DST. CHANGED: now reports from_p/to_p/from_d ``` $ ./build/ripwire . --path=main,rankGraphTeleport - + @@ -981,7 +976,7 @@ _Minimal connecting subgraph over 3 symbols (finds shared-caller joins)._ ``` $ ./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex - + @@ -1091,7 +1086,7 @@ _Test files that transitively reach the changed file._ ``` $ ./build/ripwire . --affected=src/graph.h - @@ -1148,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: 79e691876 +at: 0712a5182 (0 changed files — working tree is clean, nothing to analyze) ``` @@ -1167,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] ``` @@ -1314,14 +1309,14 @@ _Drop every hit in a file that ALSO contains the --not literal anywhere (file sc $ ./build/ripwire . --grep=DISCLOSE --not=test --grep-scope=file - + - + - + @@ -1529,7 +1524,7 @@ _Importance-weighted detail: FULL bodies for top-2, signatures for the rest._ ``` $ ./build/ripwire . --for="pagerank power iteration" --detail=2 - + @@ -1564,7 +1559,7 @@ $ ./build/ripwire . --pack-signatures --top-k=10 - + @@ -1695,7 +1690,7 @@ $ ./build/ripwire . --pack-top-n=3 --top-k=0 - + : files the ranked rows show / do not (sum = files=), each named or counted below. : a program entry by its language's convention (C/Go/Rust main, Java/C# static main, a script main its module scope calls, __main__.py), callees as c rows; manifest entries not read. : n= unshown files under dir p=; f= names its code files, the rest (tests, docs, config, test/doc/example dirs) counted. declined=K: K call sites without edges, including inert Elixir quote sites after unquote/unquote_splicing re-entry. external=K: K calls proven outside the tree, no edge. locality_pinned=K: K calls pinned by locality alone (a guess). extent_suspect_syms=K: K defs failed containment, corpus-wide. macro_blanked_files=K: K files indexed from a macro-blanked re-parse. prov=scip|binding|import|split|final-segment: how that edge bound (absent: one unique name); split = one arm of an amb= pick; final-segment = a qualified type matched by last name only. files=/symbols=: files and symbols indexed; edges= distinct call edges; shown= symbols printed, a merged row counting each def; ambiguous= calls split over several defs, corpus-wide; unresolved= calls with in-tree evidence and no edge (every def language-filtered or unreachable, or binding refused); order= rows by rank (important-first, important-last; (auto:fill) = flipped past a size threshold) or by path (stable). skipped_oversize=K: K files over a size ceiling, not indexed. unindexed=ext:N: N text files of that extension no grammar reads (6 extensions at most). unindexed_exts=E: E such extensions in all, the list cut. : a non-test row an indexed test transitively reaches (absent otherwise, never 0). : that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= lcom4= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, class cohesion, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> - + @@ -1799,7 +1794,7 @@ _File->file dependency graph (god-files, cycles)._ $ ./build/ripwire . --deps - + @@ -1809,8 +1804,8 @@ $ ./build/ripwire . --deps + - ... [17 more line(s); run it to see the whole thing] ``` @@ -1835,8 +1830,8 @@ _Complexity x recent git churn (maintenance pain)._ $ ./build/ripwire . --hotspots - - + + @@ -1844,7 +1839,7 @@ $ ./build/ripwire . --hotspots - + ... [17 more line(s); run it to see the whole thing] @@ -1863,7 +1858,7 @@ _Token-normalized duplicate bodies._ ``` $ ./build/ripwire . --clones - + @@ -1894,10 +1889,10 @@ _Per-function size ranking, largest Halstead volume/token entropy/lines first ``` $ ./build/ripwire . --biggest-first --limit=8 - + - + @@ -1927,7 +1922,7 @@ _Per function, the non-local MUTABLE state it can reach (transitively), most wri ``` $ ./build/ripwire . --nonlocal-state --limit=8 - @@ -1962,7 +1957,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -1993,7 +1988,7 @@ _THE single wide-angle quality read: six families in one pass, an eligible/ranke ``` $ ./build/ripwire . --quality-panel - @@ -2003,7 +1998,7 @@ $ ./build/ripwire . --quality-panel - + ... [17 more line(s); run it to see the whole thing] @@ -2030,7 +2025,7 @@ _The local-reasoning lens: to understand this symbol, how much must you know tha ``` $ ./build/ripwire . --context-ratio --limit=8 - @@ -2061,7 +2056,7 @@ _Score the naming-* rules against this repo's own rename history: proxy=old/(old ``` $ ./build/ripwire . --naming-calibration - + @@ -2133,7 +2128,7 @@ _The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/ ``` $ ./build/ripwire . --lint --naming-locals - + @@ -2168,7 +2163,7 @@ _Functions WITH a doc comment, most name-restating first: c_coeff (high = the co ``` $ ./build/ripwire . --comment-coherence --limit=8 - + @@ -2201,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] ``` @@ -2233,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] ``` @@ -2259,7 +2254,7 @@ _Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none ``` $ ./build/ripwire . --cochange --cochange-groups - + @@ -2288,15 +2283,15 @@ _Hotspots scoped to RECENT churn (the regression lens)._ ``` $ ./build/ripwire . --hotspots --since="2 weeks ago" - - + + - + @@ -2326,7 +2321,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - @@ -2356,7 +2351,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - @@ -2382,7 +2377,7 @@ _Enforce layering rules (exit 2 on violation) — run against the repo's own tes $ ./build/ripwire . --arch=test/archfix/rules.txt - @@ -2409,7 +2404,7 @@ _Built-in AST checks (c-cast, goto, unsafe-c-fn, ...)._ ``` $ ./build/ripwire . --lint - + @@ -2632,8 +2627,8 @@ _Cluster the call graph into cohesive modules._ ``` $ ./build/ripwire . --communities - + @@ -2663,7 +2658,7 @@ _Drill into ONE call-graph community by id — the drill= the --communities outp ``` $ ./build/ripwire . --community=0 - ``` @@ -2688,9 +2683,9 @@ _Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels ``` $ ./build/ripwire . --zoom - - + @@ -2725,14 +2720,14 @@ $ ./build/ripwire . --report # ripwire architecture report -3627 files · 31838 symbols · 30013 edges · 3619 modules (14940 call-graph isolated) +3631 files · 31860 symbols · 30033 edges · 3620 modules (14942 call-graph isolated) Root: `.` -Call-graph isolate provenance: 3978 declaration, 2450 header, 3382 source, 5130 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 3619) -- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1631 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] @@ -2751,7 +2746,7 @@ _Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped._ ``` $ ./build/ripwire . --seams - + @@ -2789,8 +2784,8 @@ flowchart LR n104["test
5523"] n571["test/legochargefix
546"] n405["test/fixtures/recallpassage
314"] - n961["test/slotjoinfix
175"] - n803["test/ownerhopfix/py/pkg
158"] + 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] @@ -2811,8 +2806,8 @@ _Bus-factor: recency-weighted author ownership per file._ ``` $ ./build/ripwire . --owners - - + + @@ -2842,7 +2837,7 @@ _Internal functions with no caller found in the index — a name-based graph rea ``` $ ./build/ripwire . --dead-code=src - + ``` @@ -2907,7 +2902,7 @@ _The same clean verdict with what it folded printed back: every stale acknowledg ``` $ ./build/ripwire . --quality-delta --show-stale - @@ -2936,7 +2931,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2961,7 +2956,7 @@ _On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox ``` $ ./build/ripwire . --quality-delta - ``` @@ -2986,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 -

@@ -3079,7 +3074,7 @@ _OWNERSHIP partition for a shared tree: every regression here lives in src/infra ``` $ ./build/ripwire . --quality-delta --scope=src/graph.h - @@ -3109,7 +3104,7 @@ _Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree ``` $ ./build/ripwire . --edit-check=rankGraphTeleport - @@ -3163,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"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` @@ -3184,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"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):** @@ -3235,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"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` @@ -3299,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":2932,"graph_unresolved":15244,"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] +{"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true}}]} +"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true}}]} ``` **Shaped by:** `--edit-check` @@ -3349,7 +3344,7 @@ _Bare --slice=SYM: the INVENTORY of sliceable locals (), so a calle ``` $ ./build/ripwire . --slice=rankGraphTeleport - + @@ -3386,7 +3381,7 @@ _Forward flow: which statements the seed's value reaches, at the default depth b ``` $ ./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=fwd - + @@ -3467,7 +3462,7 @@ _No-LLM review-evidence bundle for the working-tree diff (clean tree = empty)._ ``` $ ./build/ripwire . --pr-context - ``` @@ -3493,11 +3488,11 @@ _Pairwise cross-arm conflict sites + suggested landing order (any committish sha ``` $ ./build/ripwire . --merge-scout=HEAD~2,HEAD~1 - - + + - + @@ -3572,7 +3567,7 @@ _Which refs of the `lane/` ref family still hold divergent authored work vs HEAD ``` $ ./build/ripwire . --stray-content=lane/ - + @@ -3606,7 +3601,7 @@ _Select the genuinely-unmerged refs of the `lane/` ref family and feed them to m ``` $ ./build/ripwire . --stray-content=lane/ --plan - + @@ -3642,8 +3637,8 @@ _Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract d ``` $ ./build/ripwire . --stray-content=lane/ --abi - + @@ -3677,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] @@ -3707,8 +3702,8 @@ _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 - - + + @@ -3735,8 +3730,8 @@ _The whole hit list asked for by name: under the same 60-row cap HEAD's referenc ``` $ ./build/ripwire . --whereis=rankGraphTeleport --whereis-listing=all - - + + @@ -3767,7 +3762,7 @@ _The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gat $ ./build/ripwire . --flags - + @@ -3848,7 +3843,7 @@ _The cache-locality lens over every aggregate: fields READ TOGETHER but declared ``` $ ./build/ripwire . --field-affinity - @@ -3883,7 +3878,7 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - + @@ -3917,7 +3912,7 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - + @@ -3950,8 +3945,8 @@ _Same report, with git history splitting stale mentions into deleted-by-commit v ``` $ ./build/ripwire . --doc-drift --with-history - - + + @@ -3984,7 +3979,7 @@ _The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when ``` $ ./build/ripwire . --plan-lint=test/planlintfix/wave.md - + @@ -4049,7 +4044,7 @@ _A command that exits 0: a minimal success record (exit, measured duration, disc $ ./build/ripwire . --run-trace="true" - + ``` @@ -4209,7 +4204,7 @@ _Task lens + a compact Mermaid flowchart of the top anchors' 1-hop edges._ ``` $ ./build/ripwire . --for="pagerank power iteration" --with-graph - + @@ -4282,13 +4277,13 @@ _Environment self-check: binary staleness, grammars, cache dir, git, tracked-bin ``` $ ./build/ripwire . --doctor - - + - - + + - + @@ -4316,13 +4311,13 @@ _--doctor plus a LIVE integration inspection for one agent: PATH binary, install ``` $ ./build/ripwire . --doctor --agent=claude - - + - - + + - + @@ -4351,7 +4346,7 @@ $ ./build/ripwire . --skipped - @@ -4439,8 +4434,8 @@ _Rank by git change-frequency prior instead of PageRank._ $ ./build/ripwire . --rank-by=churn --top-k=5 - - + + @@ -4472,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~6 --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 - - - - - - - - + + + + - - - -... [8 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` @@ -4549,7 +4544,7 @@ _The same gating report under --legend=full — same rows, same exit 2; the defa ``` $ ./build/ripwire . --quality-delta --legend=full - @@ -4630,7 +4625,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -4666,7 +4661,7 @@ _Drop matching paths (repeatable) before ranking._ $ ./build/ripwire . --exclude=present --exclude=bench --top-k=5 - + @@ -4697,8 +4692,8 @@ _Full map re-ranked with teleport toward git-changed files — clean tree, so ch $ ./build/ripwire . --map-diff --top-k=5 - - + + @@ -4731,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 - + @@ -4781,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 - + @@ -4812,7 +4807,7 @@ _Crawl paths the repo's own .gitignore covers (default honours it and discloses $ ./build/ripwire . --no-ignore --top-k=3 - + @@ -4848,7 +4843,7 @@ _Skip files above a size bound before parsing (note the corpus shrink in the hea $ ./build/ripwire . --max-file-size=8K --top-k=3 - + @@ -4928,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 - + @@ -4983,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":" - + @@ -63,12 +63,12 @@ *Same map, capped to the 5 highest-ranked symbols.* -**wall time: 4.11s** +**wall time: 3.58s** ````` - + @@ -87,7 +87,7 @@ - + @@ -103,12 +103,12 @@ *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: 6.87s** +**wall time: 2.14s** ````` - + @@ -134,14 +134,14 @@ *NEW since the last capture: --top-k=0 means PAYLOAD-ONLY — no ranked map rides along with the body you asked for.* -**wall time: 6.35s** +**wall time: 1.83s** ````` - + @@ -211,7 +211,7 @@ ripwire: --top-k=0 means "no ranked map, payload only" — pass a payload verb ( *GATE form: exit 3 if the map's own est_tokens exceeds the budget (over-budget failure shape).* -**exit code: 3** — **wall time: 9.59s** +**exit code: 3** — **wall time: 1.91s** ````` @@ -228,16 +228,16 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *The task lens: ranked signatures + quality metrics framed for the task.* -**wall time: 25.90s** +**wall time: 6.50s** ````` - - - + + 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] @@ -248,36 +248,36 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 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)] +… [127 more display lines; full output is 20072 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: 18.76s** +**wall time: 7.04s** ````` - + - + 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` @@ -287,8 +287,8 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 - - + + @@ -299,7 +299,7 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 - + & p, float alpha = 0.85f ) … [28 more display lines; full output is 5868 bytes on 29 raw line(s)] ````` @@ -308,23 +308,23 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *Same query with routing forced OFF (plain subtoken+body BM25) — contrast with the routed run.* -**wall time: 24.05s** +**wall time: 5.99s** ````` - + - + 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 ) +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 ) @@ -337,9 +337,9 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 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 +#### 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)] ````` @@ -348,16 +348,16 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *T3 opt-out: the signatures-only lens (no auto bodies, no bundle="auto" attribute) — contrast with the terminal default above.* -**wall time: 16.52s** +**wall time: 7.62s** ````` - + - + 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` @@ -372,25 +372,25 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *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: 18.76s** +**wall time: 8.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 ) +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 +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -403,7 +403,7 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 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)] ````` @@ -412,10 +412,10 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *Mention anchoring (default-on): a path and a Symbol literally named in the task get lifted; the header says what anchored.* -**wall time: 18.32s** +**wall time: 10.07s** ````` - @@ -441,21 +441,21 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 ) +inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) +std::optional<int> runEvalViews( const MainDispatch& d ) struct RecallSectionPick inline double binomialChoose( std::size_t n, std::size_t k ) -… [146 more display lines; full output is 21527 bytes on 18 raw line(s)] +… [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: 15.74s** +**wall time: 10.87s** ````` - @@ -481,8 +481,8 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 ) +inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) +std::optional<int> runEvalViews( const MainDispatch& d ) 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)] @@ -492,12 +492,12 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *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: 3.24s** +**wall time: 2.77s** ````` - + @@ -510,12 +510,12 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *The repo's best-in-class instance to imitate before writing new code (picked by ROLE).* -**wall time: 5.91s** +**wall time: 6.07s** ````` - + budget=100 *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: 4.53s** +**wall time: 5.29s** ````` @@ -551,7 +551,7 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *The honest half of the contract: a task with no ripwire-shaped evidence ABSTAINS with zero commands rather than guessing.* -**wall time: 5.59s** +**wall time: 3.66s** ````` @@ -564,12 +564,12 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *Most relevant DOCS' full bodies (markdown only) — recall what is already written down.* -**wall time: 2.61s** +**wall time: 2.54s** ````` -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 +ripwire recall — "quality delta gating exit codes" — 121 relevant of 268 document files, best-first — total=121 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] +━━ README.md (relevance 8.095) ━━ [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. @@ -593,7 +593,7 @@ refuses by default. -━━ CHANGELOG.md (relevance 7.519) ━━ [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] +━━ CHANGELOG.md (relevance 7.522) ━━ [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 @@ -602,38 +602,17 @@ A tripped memory guard in the range form used to give exit 5 and nothing, so on ## `./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 1356233-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.* +*The directory-as-knowledge-base pattern: --recall pointed at a 1360588-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=952 - -━━ commands.md (relevance 11.026) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 589285 B; lines="556-581"; dropped_by_budget=163] [truncated: 1854 of 4257 bytes] -#### Pattern: a directory of dumped tool output as a knowledge base +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 -**Answers:** can `--recall` serve as a zero-setup knowledge base over dumped tool output — a -`git log`, an API response dump, a fetched doc, ` --help` text — sitting in a scratch -directory, instead of a source repo? +━━ 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] +### `--field-affinity[=STRUCT]` -Yes, unmodified. `--recall` never distinguishes "a codebase" from any other directory it can -walk: point it at the scratch dir and query it. No index to build, no daemon, no mutable store -between runs — the whole cost is one cold parse. Two conditions decide whether it works at all, -and both are yours, because the file you write is the only thing that sets them: +**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. -1. **Dump to `.md`.** `--recall` ranks DOCUMENT files: `.md`, plus the docparse'd - `.ipynb`/`.html`/`.csv` (and Office/PDF through the optional markitdown bridge). `.txt`, - `.log`, `.json` and extensionless files are **not** documents to it. A directory of those - answers `0 relevant of 0 document files` and exits 0 — which reads like "nothing matched - your terms" when what happened is "nothing was indexed at all". Redirect to `notes.md`, - never `notes.txt`. The recorded run below is that rule's own demonstration: its scratch dir - holds five dumps, and the header says `2 relevant of 2 document files` because only the two - `.md` ones are documents — the `git log`, the `--help` text and the JSON access log are not - in the population at all. - -2. **Keep `##` headings in the dump.** A headed document is served as whole ranked SECTIONS, so - an answer buried mid-file arrives at a small `--max-tokens`, and — while the served document - SET stays fixed — a larger ceiling returns a strict superset of it; the `[sections: S of R - selected (N in doc) … lines="…"; dropped_by_budget=D]` note names the ranges you actually got - and what the ceiling cost. … +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)) ````` @@ -648,11 +627,11 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas *File-by-file orientation map (top symbols per file).* -**wall time: 1.99s** +**wall time: 1.58s** ````` - + @@ -661,7 +640,7 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas - + @@ -688,7 +667,7 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas *Self-contained HTML force-directed call graph.* -**wall time: 9.76s** +**wall time: 6.95s** ````` (empty) @@ -697,14 +676,14 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas Artifact written: ````` - 156034 /aux/map2.html + 156166 /aux/map2.html ````` ## `./build/ripwire . --order=stable --top-k=5` *Stable (path/id) emit order — provider KV-cache hits across re-runs.* -**wall time: 2.84s** +**wall time: 2.28s** ````` @@ -727,7 +706,7 @@ Artifact written: - + @@ -749,13 +728,13 @@ Artifact written: *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: 2.41s** +**wall time: 1.37s** ````` - + @@ -789,14 +768,14 @@ Artifact written: *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.84s** +**wall time: 1.53s** ````` - - + + @@ -822,20 +801,20 @@ Artifact written: -… [1951 more display lines; full output is 53260 bytes on 1 raw line(s)] +… [1950 more display lines; full output is 53230 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: 3.02s** +**wall time: 1.81s** ````` - + @@ -878,14 +857,14 @@ Artifact written: *Who calls SYM (1-hop in-edges).* -**wall time: 2.81s** +**wall time: 1.39s** ````` - + - - + + @@ -897,15 +876,15 @@ Artifact written: *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.* -**wall time: 3.66s** +**wall time: 1.42s** ````` - + - - + + @@ -917,7 +896,7 @@ Artifact written: *Unknown-symbol REFUSAL shape (exit 1) with a did-you-mean from real edit distance.* -**exit code: 1** — **wall time: 6.80s** +**exit code: 1** — **wall time: 5.16s** ````` @@ -934,22 +913,22 @@ ripwire: --callers symbol not found: DoesNotExist *What SYM calls (1-hop out-edges).* -**wall time: 3.40s** +**wall time: 1.74s** ````` - - + + - - - - - - + + + + + + ````` @@ -957,14 +936,14 @@ ripwire: --callers symbol not found: DoesNotExist *The resolvable use-sites (call/read/write/import/extends) with file:line; count= is a floor.* -**wall time: 3.51s** +**wall time: 2.39s** ````` - + - - + + @@ -978,17 +957,17 @@ ripwire: --callers symbol not found: DoesNotExist *Composable node-set query: functions within 2 caller-hops of rankGraphTeleport.* -**wall time: 3.01s** +**wall time: 2.09s** ````` - + - + - + @@ -1018,38 +997,38 @@ ripwire: --callers symbol not found: DoesNotExist *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: 4.09s** +**wall time: 2.76s** ````` - - - - - - - + + + + + + + - + - - - + + + - + - - + + - + … [73 more display lines; full output is 5604 bytes on 1 raw line(s)] ````` @@ -1058,39 +1037,39 @@ ripwire: --callers symbol not found: DoesNotExist *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: 3.47s** +**wall time: 2.80s** ````` - - - - + + + + - - + + - - - - + + + + - + - - - + + + - + … [73 more display lines; full output is 5478 bytes on 1 raw line(s)] ````` @@ -1098,16 +1077,16 @@ ripwire: --callers symbol not found: DoesNotExist *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: 2.44s** +**wall time: 3.22s** ````` - + - + ````` @@ -1115,14 +1094,14 @@ ripwire: --callers symbol not found: DoesNotExist *Minimal connecting subgraph over 3 symbols (finds shared-caller joins).* -**wall time: 4.40s** +**wall time: 2.79s** ````` - + - + @@ -1134,7 +1113,7 @@ ripwire: --callers symbol not found: DoesNotExist *Transitive blast radius — everything that reaches SYM. NOW carries shown/capped.* -**wall time: 6.68s** +**wall time: 6.50s** ````` @@ -1156,8 +1135,8 @@ ripwire: --callers symbol not found: DoesNotExist - - + + @@ -1174,7 +1153,7 @@ ripwire: --callers symbol not found: DoesNotExist *Markdown docs that name SYM in a backtick (doc<->code edges).* -**wall time: 4.58s** +**wall time: 4.75s** ````` @@ -1193,11 +1172,11 @@ ripwire: --callers symbol not found: DoesNotExist *Test files that transitively reach the changed file.* -**wall time: 3.17s** +**wall time: 4.71s** ````` - @@ -1212,12 +1191,12 @@ ripwire: --callers symbol not found: DoesNotExist *Mid-task situational report for the current git diff — recorded against a CLEAN tree (contrast with the sandbox run below).* -**wall time: 8.52s** +**wall time: 7.67s** ````` ripwire situational-awareness — 0 changed file(s), 0 symbols in them root: . -at: 79e691876 +at: d3605fde7 (0 changed files — working tree is clean, nothing to analyze) ````` @@ -1225,11 +1204,11 @@ at: 79e691876 *Pre-PR gate on a CLEAN tree: no obligations, exit 0.* -**wall time: 11.88s** +**wall time: 10.09s** ````` - ````` @@ -1237,7 +1216,7 @@ at: 79e691876 *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: 3.84s** +**wall time: 3.00s** ````` @@ -1420,11 +1399,11 @@ at: 79e691876 *The same shape query WITH an explicit capture — identical hits, no auto_captured= attribute.* -**wall time: 3.67s** +**wall time: 3.61s** ````` -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 @@ -1460,20 +1439,20 @@ at: 79e691876 *Raw BM25 ranking (debug lens; --for is the real verb).* -**wall time: 3.80s** +**wall time: 3.93s** ````` - + - + - + @@ -1484,12 +1463,12 @@ at: 79e691876 - + - + @@ -1505,10 +1484,10 @@ at: 79e691876 *Importance-weighted detail: FULL bodies for top-2, signatures for the rest.* -**wall time: 9.41s** +**wall time: 6.50s** ````` - + @@ -1519,14 +1498,14 @@ at: 79e691876 The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) -struct RankedGraph +struct RankedGraph 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… inline std::uint32_t sliceRdIterationCeiling() noexcept struct PageRankRun What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure -inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept -inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept inline std::string powerShellSingleQuote( std::string_view s ) noexcept @@ -1545,14 +1524,14 @@ at: 79e691876 *Body-elided decl skeletons — recounted on this corpus. Measured as element bytes: the signature+doc elements --pack-signatures emits, against the SAME symbols' full bodies from --expand, with the CORPUS-ROOT PREFIX SUBTRACTED FROM BOTH SIDES. That subtraction is the whole methodology and the figure is meaningless without it: the root repeats inside every element's id= and p=, it is not what this verb elides, and counting it makes the headline a function of how deep the checkout happens to sit on disk — on one corpus, three spellings of the same root read 18.6 points apart before the subtraction and agree exactly after it. Root-neutralised on THIS repo: 88.8% fewer bytes at top-10, 86.2% at top-50, 87.4% at top-100 (re-derived 2026-10-10 when the C++ standard-member gate stopped std::vector/std::string calls such as out.push_back() and s.empty() from binding to in-tree namesakes by name: the ranked top-10/50 lost one-line container accessors (svector::push_back, WidePath::c_str, every empty) and gained one-line forwarding helpers and macros (kindIs, ASSUME, formatTo, emitTo) whose signature is nearly the whole body, so less of the set is elidable, from 92.7/88.7/87.6; before that, re-derived 2026-09-20 when the native Windows port landed: src/infra/os_win32.cpp and os_win32_logic.h are ~3,900 lines of new, heavily commented infra that the ranked top-10/50/100 now reach, and their bodies are this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new, from top-50 87.1. Measured by test/showcasecapturecheck.sh's own recount arm on the combined tree, which is the gate that would otherwise report the drift; before that, re-derived 2026-09-17 at the self-check macro vocabulary rename: VERIFY/VERIFY_TEXT/VERIFY_DEBUG_ONLY/VERIFY_NOT_REACHED/VERIFY_SAME_THREAD/VERIFY_NO_ALIAS*/DYNMAP_VERIFY/DEGRADED_PATH_ALERT renamed to ASSUME/EXPECTS/ENSURES/DASSERT/UNREACHABLE/ASSUME_SAME_THREAD*/ASSUME_NO_ALIAS*/DYNMAP_ASSUME/DISCLOSE (plus new VALIDATE sites) across 839 identifier renames in 179 files, and a hand-written Diagnostics.h/diagnostics.cpp replacing the old ones outright: this moves both WHICH symbols the ranked top-10/50/100 hold and how large their bodies are, from top-50 85.2. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-12 when the rows dropped the path-repeating id= for the short sc= scope: the signature side shrank, the bodies did not; before that, 89.5% / 81.8% / 84.3% re-derived 2026-09-10 at the sibs= cap raise: kMaxExpandSibs went 8 -> 100, so --expand's bodies now carry the file context the old cap hid — 89.3% of all sibling names — and the body side is this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new. Measured on a fixed tree with the top-50 membership and the signature side unchanged: top-50 from 71.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-09 at the printf-family -> std::print conversion: converting ~1,500 emitter call sites to rw::emitTo/emitRaw/formatTo across 93 files changes how large the ranked symbols' BODIES are, and the body side is this ratio's denominator — top-50 from 72.3. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-08 at the confident-zero round, issues #62/#63/#66: that change adds symbols to src/graphlegend.h and the new src/preprocdead.h and re-homes two long comment blocks from call sites onto the helpers they explain, which moves both WHICH symbols the ranked top-50 holds and how large their bodies are — top-50 from 74.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-06 at the stranger-audit fix round: the doctor, cache-sweep and html-provenance bodies grew this corpus's BODY side, moving top-50 from 75.6 — a real re-derivation, not a tolerance edit; before that, re-derived 2026-09-05 at the capture-audit close: lane L7's P16 caps --expand's sibs= at 8 names, which SHRINKS the body side of this ratio and moved the figure down from 84.5/80.2/80.6 — the V1 2026-08-15 re-center, when sibs=/inc= first grew the body side from 70.0/61.0/63.8, in reverse; both were real re-derivations, not tolerance edits). top-50 is the number to quote, because the sigs payload is top-50 regardless of --top-k and is therefore what THIS command emits. A single small/trivial body can still invert it (signature+doc bigger than the body), like the --format=columnar sibling below. test/showcasecapturecheck.sh (C) re-derives all three from this repo every run, in the same quantity, and fails if the caption and the recount drift apart.* -**wall time: 2.59s** +**wall time: 2.22s** ````` - + @@ -1585,14 +1564,14 @@ at: 79e691876 *Control-flow skeleton of one symbol, payload-only via the new --top-k=0.* -**wall time: 3.04s** +**wall time: 1.72s** ````` - + & p, float alpha = 0.85f ) { PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); @@ -1616,14 +1595,14 @@ at: 79e691876 *CHANGED: a line range on --outline is now STRIPPED with a stderr note (it used to refuse).* -**wall time: 3.87s** +**wall time: 1.73s** ````` - + & p, float alpha = 0.85f ) { PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); @@ -1653,14 +1632,14 @@ ripwire: --outline=rankGraphTeleport:1-10: --outline has no line-range form — *Full body + inline callee signatures.* -**wall time: 2.86s** +**wall time: 1.94s** ````` - + : files the ranked rows show / do not (sum = files=), each named or counted below. : a program entry by its language's convention (C/Go/Rust main, Java/C# static main, a script main its module scope calls, __main__.py), callees as c rows; manifest entries not read. : n= unshown files under dir p=; f= names its code files, the rest (tests, docs, config, test/doc/example dirs) counted. declined=K: K call sites without edges, including inert Elixir quote sites after unquote/unquote_splicing re-entry. external=K: K calls proven outside the tree, no edge. locality_pinned=K: K calls pinned by locality alone (a guess). extent_suspect_syms=K: K defs failed containment, corpus-wide. macro_blanked_files=K: K files indexed from a macro-blanked re-parse. prov=scip|binding|import|split|final-segment: how that edge bound (absent: one unique name); split = one arm of an amb= pick; final-segment = a qualified type matched by last name only. files=/symbols=: files and symbols indexed; edges= distinct call edges; shown= symbols printed, a merged row counting each def; ambiguous= calls split over several defs, corpus-wide; unresolved= calls with in-tree evidence and no edge (every def language-filtered or unreachable, or binding refused); order= rows by rank (important-first, important-last; (auto:fill) = flipped past a size threshold) or by path (stable). skipped_oversize=K: K files over a size ceiling, not indexed. unindexed=ext:N: N text files of that extension no grammar reads (6 extensions at most). unindexed_exts=E: E such extensions in all, the list cut. : a non-test row an indexed test transitively reaches (absent otherwise, never 0). : that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= lcom4= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, class cohesion, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> - + - + @@ -1893,12 +1872,12 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *File->file dependency graph (god-files, cycles).* -**wall time: 1.76s** +**wall time: 2.13s** ````` - + @@ -1933,15 +1912,15 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Complexity x recent git churn (maintenance pain).* -**wall time: 6.80s** +**wall time: 4.61s** ````` - - + + - + @@ -1950,9 +1929,9 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + - + @@ -1973,11 +1952,11 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Token-normalized duplicate bodies.* -**wall time: 3.55s** +**wall time: 3.68s** ````` - + @@ -1987,7 +1966,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + @@ -2002,7 +1981,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + @@ -2013,40 +1992,40 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Files that change together in git (hidden coupling).* -**wall time: 7.39s** +**wall time: 6.62s** ````` - + - - - + + + + + - - + + + + + + - - - - - - - - + - + + - - + + ````` @@ -2055,14 +2034,14 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Hotspots scoped to RECENT churn (the regression lens).* -**wall time: 8.97s** +**wall time: 8.76s** ````` - - + + - + @@ -2070,24 +2049,24 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + - + - + + - - + … [13 more display lines; full output is 5130 bytes on 1 raw line(s)] ````` @@ -2095,12 +2074,12 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Enforce layering rules (exit 2 on violation) — run against the repo's own test fixture rules.* -**wall time: 1.99s** +**wall time: 1.64s** ````` - @@ -2128,18 +2107,18 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan -… [1046 more display lines; full output is 154548 bytes on 1 raw line(s)] +… [1041 more display lines; full output is 153822 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --lint` *Built-in AST checks (c-cast, goto, unsafe-c-fn, ...).* -**wall time: 3.58s** +**wall time: 2.93s** ````` - + @@ -2155,7 +2134,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + @@ -2175,7 +2154,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *User lint rules (YAML, ast-grep style) from a directory.* -**wall time: 1.51s** +**wall time: 2.13s** ````` @@ -2202,6 +2181,8 @@ ripwire: AST query did not compile for any grammar: (this_is_not_a_real_node @x *Join MEASURED heat onto --lint findings — runs in a tiny fabricated demo corpus (one cache-pointer-chase-loop finding under a PROFILE_SCOPE site) because a real report needs a RIPWIRE_PROFILE build; the finding inside the profiled scope gains heat_* columns from the report's #PROF_TSV row.* +**wall time: 1.89s** + Input file: ````` @@ -2255,59 +2236,59 @@ The joined finding — past the display cut above, extracted so the join is visi *Cluster the call graph into cohesive modules.* -**wall time: 1.50s** +**wall time: 3.09s** ````` - + - + - + - + - + - + -… [189 more display lines; full output is 16947 bytes on 1 raw line(s)] +… [189 more display lines; full output is 16914 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --zoom` *Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels_shown="2" of levels= BY DEFAULT over the 40 largest top modules (~8 KB, where the whole tree is ~220 KB); a module AT the cut carries children=.* -**wall time: 1.82s** +**wall time: 2.05s** ````` - - + + - - + + - + @@ -2318,16 +2299,16 @@ The joined finding — past the display cut above, extracted so the join is visi - - + + - - + + … [135 more display lines; full output is 7291 bytes on 1 raw line(s)] ````` @@ -2335,72 +2316,72 @@ The joined finding — past the display cut above, extracted so the join is visi *The restoring knob: --zoom-levels=N prints N levels (0 = the whole tree); here three, ~11 KB.* -**wall time: 2.06s** +**wall time: 1.68s** ````` - - - + + + - + - + - + - + - + - + - + - + - + -… [271 more display lines; full output is 12259 bytes on 1 raw line(s)] +… [273 more display lines; full output is 12337 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --report` *Architecture summary (modules, god-files, cycles) as markdown.* -**wall time: 1.26s** +**wall time: 1.68s** ````` # ripwire architecture report -3627 files · 31838 symbols · 30013 edges · 3619 modules (14940 call-graph isolated) +3618 files · 31790 symbols · 29969 edges · 3610 modules (14921 call-graph isolated) Root: `.` -Call-graph isolate provenance: 3978 declaration, 2450 header, 3382 source, 5130 document; 0 connected Louvain singletons +Call-graph isolate provenance: 3976 declaration, 2448 header, 3371 source, 5126 document; 0 connected Louvain singletons -## Modules (call-graph clusters; showing 12 of 3619) +## 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]** — 548 symbols +- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 547 symbols - **src::DISCLOSE@infra/Diagnostics.h:616:43369 [read,compute,resolve]** — 335 symbols - **docs::`--top-k=N`@COMMANDS.md:59:9077 [pack,allow,insert]** — 181 symbols - **test/ownerhopfix/py/pkg::big_handler_001@broadcast.py:3:72** — 106 symbols -- **src::buf@infra/svector.h:125:8942 [insert,find,push]** — 91 symbols - **src/infra::fail@os_win32.cpp:63:2553 [open,get,close]** — 89 symbols - **test::no@estchargecheck.sh:52:4108 [skip,set]** — 63 symbols - **src::child@ingest_valuerefs.h:656:33874 [emit,resolve,open]** — 62 symbols -- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 55 symbols +- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 54 symbols - **src::sliceKindIs@slice.h:368:24239 [match,collect,push]** — 48 symbols - **src/infra::DYNMAP_ASSUME@dynamic_map.hpp:90:4411 [insert,erase,find]** — 44 symbols +- **src::tokText@defectshape.h:128:5308 [scan,find,join]** — 41 symbols ## God files (most depended-on; showing 10 of 230) - `src/model.h` — 105 dependents @@ -2408,16 +2389,18 @@ Call-graph isolate provenance: 3978 declaration, 2450 header, 3382 source, 5130 - `src/infra/Diagnostics.h` — 65 dependents - `src/graph.h` — 47 dependents - `src/serialize.h` — 45 dependents -… [35 more lines, 3998 bytes total] +… [35 more lines, 4007 bytes total] ````` ## `./build/ripwire . --seams` *Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped.* +**wall time: 1.82s** + ````` - + @@ -2453,29 +2436,29 @@ Call-graph isolate provenance: 3978 declaration, 2450 header, 3382 source, 5130 *Module (directory) dependency graph as a Mermaid diagram.* -**wall time: 1.61s** +**wall time: 1.40s** ````` %% 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
9435"] + n102["src
9422"] n103["src/infra
1301"] end subgraph sg1 ["test"] - n104["test
5523"] - n571["test/legochargefix
546"] - n405["test/fixtures/recallpassage
314"] - n961["test/slotjoinfix
175"] - n803["test/ownerhopfix/py/pkg
158"] + n104["test
5517"] + n566["test/legochargefix
546"] + n400["test/fixtures/recallpassage
314"] + n956["test/slotjoinfix
175"] + n798["test/ownerhopfix/py/pkg
158"] n342["test/expandmodefix
151"] n344["test/expandsibsfix
149"] - n944["test/rubyschemafix
99"] - n424["test/forbodyfoldfix/py
98"] - n926["test/rubyattrsfix
85"] - n734["test/lib
81"] + n939["test/rubyschemafix
99"] + n419["test/forbodyfoldfix/py
98"] + n921["test/rubyattrsfix
85"] + n729["test/lib
81"] end - n74["docs
862"] + n74["docs
860"] n2[".github
628"] n0["(root)
606"] subgraph sg5 ["bench"] @@ -2493,12 +2476,12 @@ flowchart LR *Bus-factor: recency-weighted author ownership per file.* -**wall time: 5.94s** +**wall time: 8.50s** ````` - - + + @@ -2526,18 +2509,18 @@ flowchart LR -… [974 more display lines; full output is 106558 bytes on 1 raw line(s)] +… [971 more display lines; full output is 106118 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --dead-code=src` *Internal functions with no caller found in the index — a name-based graph reading, not a confidence score. NOTE the filter is a path-COMPONENT match: 'src' matches any .../src/... segment; use ./src to pin the root directory.* -**wall time: 1.50s** +**wall time: 2.22s** ````` - + ````` @@ -2546,7 +2529,7 @@ flowchart LR *Which symbols a TEST FILE exercises — the reverse direction of --affected.* -**wall time: 1.22s** +**wall time: 2.40s** ````` @@ -2559,11 +2542,11 @@ flowchart LR *Drill into ONE call-graph community by id — the drill= the --communities output itself advertises.* -**wall time: 1.44s** +**wall time: 3.71s** ````` - ````` @@ -2572,11 +2555,11 @@ flowchart LR *On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox section below.* -**wall time: 31.33s** +**wall time: 45.92s** ````` - ````` @@ -2584,18 +2567,17 @@ stderr: ````` ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -ripwire: cache : over its 2048 MiB budget — evicted 49 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) ````` ## `./build/ripwire . --quality-delta --show-stale` *The same clean verdict with what it folded printed back: every stale acknowledgement as an row and the full header. The regression-free answer above keeps only stale= and stale_by_kind= (and stale_next= names this call), and folds only when that saves a quarter of the bytes. Refused without --quality-delta.* -**wall time: 28.75s** +**wall time: 35.47s** ````` - @@ -2637,14 +2619,14 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree).* -**wall time: 18.90s** +**wall time: 21.31s** ````` - - - + + @@ -2656,11 +2638,11 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *No-LLM review-evidence bundle for the working-tree diff (clean tree = empty).* -**wall time: 3.74s** +**wall time: 5.23s** ````` - ````` @@ -2669,13 +2651,25 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *The BASEREF form: diffed against merge-base(BASEREF, HEAD), never the ref tip — here the previous commit on the current line (a ref with NO merge base falls back to a disclosed two-dot diff: anchor="ref-tip-two-dot").* -**wall time: 7.83s** +**wall time: 11.91s** ````` - - + - + + + + + + + + + + + + + ````` @@ -2683,15 +2677,15 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Pairwise cross-arm conflict sites + suggested landing order (any committish sharing a merge base with HEAD works as an arm; one that does not is reported ok="0", never compared).* -**wall time: 30.15s** +**wall time: 28.14s** ````` - - + + - + @@ -2703,11 +2697,11 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Which refs of the `lane/` ref family still hold divergent authored work vs HEAD, with verdicts.* -**wall time: 65.59s** +**wall time: 70.40s** ````` - + @@ -2736,18 +2730,18 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g -… [245 more display lines; full output is 32365 bytes on 1 raw line(s)] +… [200 more display lines; full output is 27194 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --stray-content=arm/for-howitworks-067-f2add` *A second selection, the one branch `arm/for-howitworks-067-f2add` (no ref family left to select on this checkout), picked at capture time from the refs this checkout really has and never the selection above: merged refs are OMITTED from the rows and counted in merged=; refs sharing no merge base with HEAD (a shallow clone, or a pre-rewrite history) land in unknown= with ok="0" — the counters always reconcile against refs=.* -**wall time: 13.65s** +**wall time: 11.70s** ````` - + @@ -2770,11 +2764,11 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Select the genuinely-unmerged refs of the `lane/` ref family and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root).* -**wall time: 197.74s** +**wall time: 152.24s** ````` - + @@ -2787,10 +2781,7 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g - - - @@ -2803,14 +2794,17 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g -… [33523 more display lines; full output is 4640725 bytes on 1 raw line(s)] + + + +… [33520 more display lines; full output is 4640491 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --stray-content=zzzz-no-such-ref --plan` *A --plan filter that selects NO ref REFUSES (exit 1) naming the substring — before the wave-3 close this fell through to the '>512 refs match' sentence, and --abi under the same filter answered an empty measurement at exit 0.* -**exit code: 1** — **wall time: 22.16s** +**exit code: 1** — **wall time: 5.70s** ````` (empty) @@ -2827,29 +2821,21 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all.* -**exit code: 2** — **wall time: 470.46s** +**exit code: 2** — **wall time: 435.49s** ````` - - - - - - - - - + - + - + @@ -2860,29 +2846,29 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Which ref's tree defines or mentions SYM — HEAD first, then every local branch. The default lists the kind="def" rows (here the first 60, most on branches, each carrying tip= and date=) and counts the references in : on this symbol HEAD's references would fill the 60-row cap before the branch definitions arrive, so the whole list (below) shows fewer definitions, and the default serves the page that shows more of them, whatever its bytes.* -**wall time: 25.27s** +**wall time: 26.49s** ````` - - - - + + + + - + - + - - - - - - + + + + + + ````` @@ -2890,15 +2876,15 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *The whole hit list asked for by name: under the same 60-row cap HEAD's references fill the list, so it shows far fewer definitions (here HEAD's one) than the default above (here 60). The default serves the all page only when it shows the same definitions as the defs page in strictly fewer bytes (a tie serves it too).* -**wall time: 24.43s** +**wall time: 24.99s** ````` - - + + - - + + - - - - - - + + + + + + @@ -2930,11 +2916,11 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *A ref range run for two of the twelve kinds only: the named kinds' rows are exactly their rows in the full answer, the header names the others (kinds_skipped=, skipped_why="selector"), and a pass no named kind needs does not run. The replay a memory-stopped range answer hands back (kinds_next=) is this flag. Refused without --quality-delta=A..B.* -**wall time: 32.33s** +**wall time: 24.35s** ````` - - - - + + + - - - - - - + + + + + + @@ -2982,15 +2968,15 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Same, plus a git-history row (never / removed-by-commit) for names no tree carries.* -**wall time: 34.13s** +**wall time: 37.19s** ````` - - + + - - + + ````` @@ -2998,12 +2984,12 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gates from comments/heredocs, so the count only reflects real ifndef/define, CMake option(), and getenv gates.* -**wall time: 1.69s** +**wall time: 2.87s** ````` - + @@ -3038,11 +3024,11 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Blast radius of turning ONE gate on: live code, symbols, transitive reach, covering tests.* -**wall time: 2.17s** +**wall time: 2.81s** ````` - + @@ -3076,7 +3062,7 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Unknown-gate refusal (exit 1) with a did-you-mean from a real edit distance (one character off RIPWIRE_ASAN).* -**exit code: 1** — **wall time: 3.47s** +**exit code: 1** — **wall time: 2.63s** ````` (empty) @@ -3093,10 +3079,10 @@ ripwire: run `ripwire . --flags` for the gate table *NEW VERB: pre-hoc lane plan — which of 3 parallel worktrees would COLLIDE, before a line is written. JSON on stdout.* -**wall time: 7.01s** +**wall time: 6.65s** ````` -{"v":1,"verb":"plan-lanes","at":"79e691876","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3627,"symbols":31838,"edges":300 … [line truncated: 338 more bytes on this line] +{"v":1,"verb":"plan-lanes","at":"d3605fde7","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3618,"symbols":31790,"edges":299 … [line truncated: 338 more bytes on this line] "symbols":[{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","l":286,"id":"./src/docdrift.h::DriftResult::DriftResult"}, {"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","l":2441,"id":"./src/docdrift.h::docdrift::computeDocDrift"}, {"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","l":2739,"id":"./src/docdrift.h::docdrift::kDocDriftLegend"}, @@ -3114,7 +3100,7 @@ ripwire: run `ripwire . --flags` for the gate table {"p":"./src/main.cpp","n":"emitNoteAddUnprovenDefs","scope":"","key":"a950332ccfce6b8d","id":null,"id_addressable":false,"id_collides_with":0,"l":691,"ord":0,"overloads":1,"amb":1,"cx":2,"ccx":1,"churn":453,"tested":0}, {"p":"./src/docdrift.h","n":"sortDocsByLiveDrift","scope":"docdrift","key":"d5de682411b9a9a9","id":"./src/docdrift.h::docdrift::sortDocsByLiveDrift","id_addressable":true,"id_collides_with":0,"l":2390,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":2,"churn":36,"tested":0}, {"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5840,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":466,"tested":0}], -"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":56}, +"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":55}, {"p":"./src/docdrift.h","symbols":4,"churn":36,"ccx":14,"hotspot_rank":38}, {"p":"./src/editcheck.h","symbols":1,"churn":61,"ccx":10,"hotspot_rank":41}, {"p":"./src/main.cpp","symbols":2,"churn":453,"ccx":12,"hotspot_rank":5}, @@ -3133,7 +3119,7 @@ ripwire: run `ripwire . --flags` for the gate table *NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode).* -**wall time: 7.96s** +**wall time: 8.67s** Input file: @@ -3144,7 +3130,7 @@ write regression tests for the new filter ````` ````` -{"v":1,"verb":"plan-lanes","at":"79e691876","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3627,"symbols":31838,"edges":30013,"ambiguous":2932,"unresolved":15244},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] +{"v":1,"verb":"plan-lanes","at":"d3605fde7","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3618,"symbols":31790,"edges":29969,"ambiguous":2927,"unresolved":15221},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] "symbols":[]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb","claims":{"symbols":[{"p":"./src/docdrift.h","n":"recordUnchecked","scope":"docdrift","key":"12641dab14abc8fd","id":"./src/docdrift.h::docdrift::recordUnchecked","id_addressable":true,"id_collides_with":0,"l":2 … [line truncated: 72 more bytes on this line] {"p":"./src/docdrift.h","n":"sortWeakGroupsByPath","scope":"docdrift","key":"1944ba506280ff80","id":"./src/docdrift.h::docdrift::sortWeakGroupsByPath","id_addressable":true,"id_collides_with":0,"l":2401,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":36,"tested":0}, {"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","key":"1fa68e8d93c05a59","id":"./src/mcpverbs.h::rw::docDriftText","id_addressable":true,"id_collides_with":0,"l":655,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":466,"tested":0}, @@ -3163,13 +3149,13 @@ write regression tests for the new filter {"p":"./src/mcpverbs.h","symbols":2,"churn":466,"ccx":2,"hotspot_rank":4}, {"p":"./src/recall.h","symbols":1,"churn":27,"ccx":4,"hotspot_rank":64}, {"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":4,"hotspot_rank":25}], -"symbols_total":3466,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], +"symbols_total":3464,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], "tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":13,"module_span":6,"notes":[], "execution":{"policy":"codex-lane/v1","model":"gpt-5.6-sol","reasoning":"xhigh","rule":"wide-contract-work","basis":"structural-only","signals":{"claims":12,"files":6,"module_span":6,"max_ccx":38,"sum_ccx":64,"ambiguous_calls":12,"blast_reaches":13,"contract_touches":1,"conflicts":0,"untested":13,"t … [line truncated: 139 more bytes on this line] {"id":"lane-1","task":"add the CLI parse arm and help text for the new filter","claims":{"symbols":[{"p":"./scripts/optremarks.py","n":"main","scope":"","key":"01b3b880f77d1512","id":null,"id_addressable":false,"id_collides_with":134,"l":279,"ord":0,"overloads":1,"amb":0,"cx":23,"ccx":31,"churn":14, … [line truncated: 12 more bytes on this line] {"p":"./src/cli.h","n":"HelpLine","scope":"rw","key":"1489844dbc310b82","id":"./src/cli.h::rw::HelpLine","id_addressable":true,"id_collides_with":0,"l":2948,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, {"p":"./src/cli.h","n":"HelpFilter","scope":"HelpFilter","key":"3103a5e8bfc33d38","id":"./src/cli.h::HelpFilter::HelpFilter","id_addressable":true,"id_collides_with":0,"l":3027,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, -{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":134,"l":885,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":18,"tested":0}, +{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":134,"l":865,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":17,"tested":0}, {"p":"./src/mcprefusal.h","n":"kMcpValueFields","scope":"rw::mcprefuse","key":"4a7106e488a2aa80","id":"./src/mcprefusal.h::rw::mcprefuse::kMcpValueFields","id_addressable":true,"id_collides_with":0,"l":304,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":49,"tested":0}, {"p":"./src/cli.h","n":"serveHelpSelector","scope":"rw","key":"4b247ee064fc4e94","id":"./src/cli.h::rw::serveHelpSelector","id_addressable":true,"id_collides_with":0,"l":3092,"ord":0,"overloads":1,"amb":1,"cx":4,"ccx":3,"churn":511,"tested":0}, {"p":"./src/query.h","n":"tryParsePredicateOnAll","scope":"query","key":"786acc4dbfec612b","id":"./src/query.h::query::tryParsePredicateOnAll","id_addressable":false,"id_collides_with":1,"l":113,"ord":0,"overloads":2,"amb":0,"cx":1,"ccx":0,"churn":20,"tested":0}, @@ -3197,7 +3183,7 @@ ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out *CPU/GPU contract view of one struct: computed offsets/sizes/padding + mirror check.* -**wall time: 2.34s** +**wall time: 1.74s** ````` @@ -3239,7 +3225,7 @@ ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out *The honest refusal (exit 1): Lang is an `enum class`, not a struct — no offsets are fabricated.* -**exit code: 1** — **wall time: 1.89s** +**exit code: 1** — **wall time: 3.73s** ````` (empty) @@ -3255,11 +3241,11 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped *Which of this repo's doc claims are now false. CHANGED: row attribute at= renamed to tgt= (at= is now only the root sha stamp).* -**wall time: 6.61s** +**wall time: 6.07s** ````` - +
@@ -3279,8 +3265,8 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped - - + + @@ -3288,18 +3274,18 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped -… [228 more display lines; full output is 23860 bytes on 1 raw line(s)] +… [226 more display lines; full output is 23806 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --doc-drift --gateability` *The finishable to-do list: docs whose LIVE failing anchors a date-stamp would reclassify.* -**wall time: 8.85s** +**wall time: 4.98s** ````` - + @@ -3319,8 +3305,8 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped - - + + @@ -3328,7 +3314,7 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped -… [255 more display lines; full output is 25115 bytes on 1 raw line(s)] +… [253 more display lines; full output is 25061 bytes on 1 raw line(s)] ````` Tail of the same output — the `` section: @@ -3338,11 +3324,11 @@ Tail of the same output — the `` section: + - @@ -3365,12 +3351,12 @@ Tail of the same output — the `` section: *Same report, with git history splitting stale mentions into deleted-by-commit vs never-existed.* -**wall time: 11.01s** +**wall time: 5.78s** ````` - - + + @@ -3390,22 +3376,22 @@ Tail of the same output — the `` section: - - + + - - -… [208 more display lines; full output is 23839 bytes on 1 raw line(s)] + + +… [206 more display lines; full output is 23785 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --from-trace=-` *Map a pasted stack trace onto indexed symbols. CHANGED: in_corpus= now reports the real count (was 0).* -**wall time: 3.62s** +**wall time: 2.24s** Input file: @@ -3413,8 +3399,8 @@ Input file: 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:11811 - #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11852 + #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 #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) @@ -3422,25 +3408,25 @@ AddressSanitizer:DEADLYSIGNAL ````` ````` - + - - + + - + 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] - + uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f ) int runDefaultMap( const MainDispatch& d ) int main( int argc, char** argv ) - + & p, float alpha = 0.85f ) { PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); @@ -3459,7 +3445,7 @@ AddressSanitizer:DEADLYSIGNAL *List all field notes (write-side memory) — the committed .ripwire_notes at the repo root, each with the sha/branch it was recorded at.* -**wall time: 3.44s** +**wall time: 2.94s** ````` @@ -3484,7 +3470,7 @@ AddressSanitizer:DEADLYSIGNAL *ONE budget-shared bundle: ranking + top bodies + caller sigs + notes + tests_to_run. CHANGED: rows now carry n=/id=.* -**wall time: 3.15s** +**wall time: 2.76s** ````` @@ -3524,7 +3510,7 @@ AddressSanitizer:DEADLYSIGNAL *Fan-out form: one shared core + 3 per-agent slices carved along call-graph communities.* -**wall time: 4.27s** +**wall time: 1.75s** ````` + @@ -3578,14 +3564,14 @@ AddressSanitizer:DEADLYSIGNAL The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) -struct RankedGraph +struct RankedGraph 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… inline std::uint32_t sliceRdIterationCeiling() noexcept struct PageRankRun What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure -inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept -inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept inline std::string powerShellSingleQuote( std::string_view s ) noexcept @@ -3604,7 +3590,7 @@ AddressSanitizer:DEADLYSIGNAL *Per-file metrics as CodeCharta cc.json.* -**wall time: 7.13s** +**wall time: 4.86s** ````` (empty) @@ -3613,7 +3599,7 @@ AddressSanitizer:DEADLYSIGNAL Artifact written: ````` - 562619 /aux/ripwire2.cc.json + 560892 /aux/ripwire2.cc.json {"projectName":"project","apiVersion":"1.3","attributeDescriptors":{"loc":{"title":"Lines of Code","description":"Physical line count","direction":-1},"symbols":{"title":"Symbols","description":"Definitions in the file","direction":-1},"cx":{"title":"Cyclomatic Complexity","description":"Sum of per-symbol cyclomatic complexity","direction":-1},"cognitive_cx":{"title":"Cognitive Complexity","descri ````` @@ -3621,7 +3607,7 @@ Artifact written: *One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped .* -**wall time: 10.93s** +**wall time: 3.96s** Input file: @@ -3636,12 +3622,12 @@ lego:Vehicle - + - + incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…constexpr std::uint32_t kCacheMagic = 0x4b505443 Composed exactly the way every OTHER blob family is (quality.h): one fixed-width identity hex pe…inline std::string spanTierMemoPath( const std::string& diskPath ) @@ -3649,9 +3635,9 @@ lego:Vehicle Ingest the tree at `sha`, materialized out of `root`'s object store. The HEAD side reuses the SA…inline bool ingestCommitTree( const std::string& root, const std::string& sha, const std::vector<std::string>& excludes, std::size_t maxFileBytes, IngestResult&… … [line truncated: 4 more bytes on this line] P1-15 — the `_reingest` envelope field for a response whose handling ran an INCREMENTAL pass, …inline bool mcpRefreshedThisRequest( std::uint64_t passesAtEntry ) -struct FileHealth +struct FileHealth inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::ve … [line truncated: 8 more bytes on this line] -inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… +inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… inline RawFacts runParsePool( IngestResult& result, const char* rootDir, std::string_view cacheFile, bool captureValueUses, HashMap<std::string, FileFacts>& cache, const CacheLoadStats& cac … [line truncated: 66 more bytes on this line] inline McpRebuildBaseline mcpRebuildBaseline( const McpIndex& ix, bool isIncrementalPass ) inline const McpIndex& getIndex( const std::string& root ) @@ -3675,18 +3661,18 @@ lego:Vehicle *Environment self-check: binary staleness, grammars, cache dir, git, tracked-binary staleness — exit 1 when any check fails (here: the PATH install is older than ./build).* -**exit code: 1** — **wall time: 38.31s** +**exit code: 1** — **wall time: 41.39s** ````` - - + - - + + - - + @@ -3738,13 +3724,13 @@ ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s *Rank by git change-frequency prior instead of PageRank.* -**wall time: 8.89s** +**wall time: 7.13s** ````` - - + + @@ -3764,34 +3750,44 @@ ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s ````` -## `./build/ripwire . --rank-by=churn-decay --since=HEAD~6 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3` +## `./build/ripwire . --rank-by=churn-decay --since=HEAD~4 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3` *Scope the recent-changes answer to ONE directory. 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.* -**wall time: 12.47s** +**wall time: 11.61s** ````` - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - + ````` @@ -3799,7 +3795,7 @@ ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s *An unknown value REFUSES (exit 1), NAMED, with the supported set listed.* -**exit code: 1** — **wall time: 1.01s** +**exit code: 1** ````` (empty) @@ -3815,19 +3811,19 @@ ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf *Columnar output: paths table + parallel arrays, ~15-60% fewer tokens on MANY-row lists — small results can be LARGER (the columnar legend is a fixed cost).* -**wall time: 4.40s** +**wall time: 1.30s** ````` - + 0=src/mcpindex.h 1=src/graph.h 2=src/eval.h 3=src/main.cpp 0,1,1,2,3,3,3 getIndex,rankGraph,anchoredLexicalRank,runEval,churnDecayRanking,churnRankedGraph,runDefaultMap -1184,11850,12496,171,1425,1464,1751 +1184,11791,12437,171,1425,1464,1751 fn,fn,fn,fn,fn,fn,fn 0,0,0,0,0,0,0 -src/mcpindex.h:1288,src/graph.h:11853,src/graph.h:12547,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 +src/mcpindex.h:1288,src/graph.h:11794,src/graph.h:12488,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 ````` @@ -3836,24 +3832,24 @@ ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf *Flat top-K export for an external reranker.* -**wall time: 9.06s** +**wall time: 6.02s** ````` - - + + inline std::string spanTierMemoPath( const std::string& diskPath ) - + inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::vector<NodeId>& surfaceIds ) - + ### See the map — not just the numbers - + inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) - + const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) @@ -3879,12 +3875,12 @@ ripwire: --format: unknown value 'bogus' (supported: xml|columnar|rows|candidate *Machine-parseable JSON, same content, keys mirror the XML attrs.* -**wall time: 1.69s** +**wall time: 1.21s** ````` -{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, -{"t":"fn","n":"rankGraph","p":"src/graph.h:11850","sites_at":["src/graph.h:11853"]}, -{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12496","sites_at":["src/graph.h:12547"]}, +{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, +{"t":"fn","n":"rankGraph","p":"src/graph.h:11791","sites_at":["src/graph.h:11794"]}, +{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12437","sites_at":["src/graph.h:12488"]}, {"t":"fn","n":"runEval","p":"src/eval.h:171","sites_at":["src/eval.h:328"]}, {"t":"fn","n":"churnDecayRanking","p":"src/main.cpp:1425","sites_at":["src/main.cpp:1439"]}, {"t":"fn","n":"churnRankedGraph","p":"src/main.cpp:1464","sites_at":["src/main.cpp:1478","src/main.cpp:1479","src/main.cpp:1493"]}, @@ -3911,12 +3907,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Pagination: 3 items, skipping the first 3 (deterministic seams).* -**wall time: 7.19s** +**wall time: 4.58s** ````` - + @@ -3927,12 +3923,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Drop test paths from the corpus before ranking.* -**wall time: 2.44s** +**wall time: 1.90s** ````` - + @@ -3943,7 +3939,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -3951,7 +3947,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -3967,12 +3963,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Drop matching paths (repeatable) before ranking.* -**wall time: 2.32s** +**wall time: 1.93s** ````` - + @@ -3991,7 +3987,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -4007,13 +4003,13 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Full map re-ranked with teleport toward git-changed files — clean tree, so changed=0 and it degrades to the plain map.* -**wall time: 4.76s** +**wall time: 4.89s** ````` - - + + @@ -4038,12 +4034,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm cost.* -**wall time: 4.24s** +**wall time: 3.36s** ````` - + @@ -4058,7 +4054,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -4078,12 +4074,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Explicit incremental cache at a path OUTSIDE the repo (first call writes it).* -**wall time: 4.51s** +**wall time: 3.43s** ````` - + @@ -4098,7 +4094,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -4117,22 +4113,22 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m Artifact written: ````` - 28772140 /aux/warm2.ripwirecache + 28475910 /aux/warm2.ripwirecache ````` ## `./build/ripwire . --max-file-size=8K --top-k=3` *Skip files above a size bound before parsing (note the corpus shrink in the header).* -**wall time: 3.22s** +**wall time: 1.15s** ````` - + - + @@ -4143,7 +4139,7 @@ Artifact written: - + @@ -4152,7 +4148,7 @@ Artifact written: - + @@ -4180,12 +4176,12 @@ ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather t *Multi-root workspace: ONE merged graph over two roots, paths labeled /.* -**wall time: 5.42s** +**wall time: 1.99s** ````` - + @@ -4213,19 +4209,19 @@ ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather t *Self-eval: co-change recall vs BM25.* -**wall time: 22.29s** +**wall time: 19.24s** ````` ripwire --eval (co-change recovery, averaged over 80 historical commits) ranker recall@5 recall@10 recall@20 - ripwire 6.2% 6.8% 13.3% - BM25 14.7% 16.3% 18.4% - BM25sub 15.5% 23.7% 28.6% - BM25body 18.3% 24.9% 35.8% - fused 12.3% 16.0% 25.5% - anchored 18.3% 24.9% 36.2% - same-dir 0.9% 4.5% 10.3% - random 0.1% 0.3% 0.6% <- floor (random ranking over F=3627 files) + ripwire 5.4% 6.4% 13.4% + BM25 13.3% 15.9% 16.9% + BM25sub 14.0% 23.1% 30.1% + BM25body 15.5% 22.3% 33.9% + fused 7.8% 14.6% 27.3% + anchored 15.5% 22.7% 34.2% + same-dir 0.9% 4.6% 10.9% + random 0.1% 0.3% 0.6% <- floor (random ranking over F=3618 files) note: `ripwire` here is the DEFAULT MAP's structural-only PageRank (importance, not relatedness) — it is NOT what a --for/--query retrieval call ranks with. BM25 / BM25sub / BM25body are QUERY-TIME lexical rankers (whole-name / subtoken / @@ -4241,23 +4237,23 @@ ripwire --eval (co-change recovery, averaged over 80 historical commits) *Known-item retrieval eval: MRR + recall@k per ranker per query mode.* -**wall time: 160.73s** +**wall time: 159.70s** ````` ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-corpus by construction) - sample: population=8002 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population + sample: population=7994 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population (smallest fnv1a64(scope::name) over the population, cut on the key so an identity is never split; path- and order-independent, but a corpus this size is NOT graded exhaustively — say so when citing it) ingest: lex=rich (persisted subtoken stats; no per-query corpus re-tokenize) ranker query-mode MRR recall@1 recall@5 recall@10 subtoken name 0.680 54.5% 84.8% 90.0% - subtoken doc-phrase 0.904 88.3% 92.3% 93.5% + subtoken doc-phrase 0.903 88.3% 92.2% 93.5% name-exact name 0.898 82.2% 95.9% 97.4% - name-exact doc-phrase 0.013 0.5% 1.8% 2.6% - anchored name 0.687 56.2% 84.1% 88.7% - anchored doc-phrase 0.900 87.6% 92.3% 93.0% + name-exact doc-phrase 0.013 0.5% 1.9% 2.6% + anchored name 0.688 56.2% 84.1% 88.7% + anchored doc-phrase 0.899 87.5% 92.2% 92.9% routed name 0.900 82.4% 96.0% 97.6% - routed doc-phrase 0.902 88.3% 92.1% 93.3% + routed doc-phrase 0.902 88.2% 92.0% 93.2% note: routing chose name-exact on 3989/4000 NAME queries (a NAME query is always identifier-shaped); the confidence gate routes doc-phrase queries to name-exact ONLY when EVERY content word names a symbol (or an explicit camel/snake token appears) AND every matched name is specific enough to anchor on — @@ -4270,7 +4266,7 @@ ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-co *Labelled verdict-accuracy eval for --stray-content — three labels over REAL local refs (names resolved at capture time); exit 3 when accuracy is under the floor. Read got= against v= in the stray-content run: a ref the verb could not analyse (unknown) must never be credited as a merged hit.* -**exit code: 3** — **wall time: 92.71s** +**exit code: 3** — **wall time: 86.65s** Input file: @@ -4294,7 +4290,7 @@ arm/orient-map-067-narrow merged *Labelled skill-ROUTING eval over the repo's own skills/ directory (4 hand-labelled prompts).* -**wall time: 2.47s** +**wall time: 3.47s** Input file: @@ -4336,15 +4332,13 @@ ripwire --eval-skills (skill routing over K=16 candidate skills [ripwire-router ripwire-write-tests 0 0 0 0 0 misses (overlap): line 3 want=ripwire-change-check got=ripwire-before-you-build "plan parallel worktrees so the lanes do not collide" -… [19 more lines, 3665 bytes total] +… [19 more lines, 3664 bytes total] ````` ## `./build/ripwire wrap claude` *Print the recipe to wire ripwire into Claude Code as an MCP server.* -**wall time: 1.56s** - ````` # ripwire -> Claude Code (CLI-first) # RECOMMENDED — this agent can run shell commands, so call the CLI directly. It costs @@ -4383,10 +4377,10 @@ Reach for it BEFORE blind grep + whole-file reads. First call ~1s cold; after th *Version + short build info.* -**wall time: 1.85s** +**wall time: 1.92s** ````` -ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=185ba69da) +ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=45d52a1ee) ````` @@ -4394,31 +4388,31 @@ ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=185b # navigate — seeds, claims, slices, shapes -## `./build/ripwire . --at=src/graph.h:11811` +## `./build/ripwire . --at=src/graph.h:11752` *Hold a LOCATION, not a name: the enclosing-definition chain at FILE:LINE (a compiler error, a diff hunk, a stack frame), outermost -> innermost.* -**wall time: 2.71s** +**wall time: 2.74s** ````` - - + + ````` -## `./build/ripwire . --callers=@src/graph.h:11811` +## `./build/ripwire . --callers=@src/graph.h:11752` *The same seed in a SELECTOR position: @FILE:LINE resolves to the innermost enclosing definition, then --callers runs on it.* -**wall time: 3.71s** +**wall time: 1.96s** ````` - + - - + + @@ -4430,7 +4424,7 @@ ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=185b *A seed past the end of the file — the refusal shape for a faulted location.* -**exit code: 1** — **wall time: 3.76s** +**exit code: 1** — **wall time: 2.50s** ````` (empty) @@ -4439,20 +4433,20 @@ ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=185b stderr: ````` -ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16276 lines — the seed asked for line 999999) +ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16217 lines — the seed asked for line 999999) ````` ## `./build/ripwire . --verify="calls(runDefaultMap, rankGraphTeleport)"` *VERIFY a closed claim in one call: three-valued verdict (confirmed / refuted / not-established) with the evidence rows inline.* -**wall time: 2.32s** +**wall time: 3.53s** ````` - + - + ````` @@ -4460,14 +4454,14 @@ ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph. *A claim that is FALSE — the refuted shape, with the references that refute it.* -**wall time: 5.13s** +**wall time: 2.32s** ````` - + - - + + @@ -4481,7 +4475,7 @@ ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph. *A literal-scan absence: refuted only with complete= evidence, never on a partial scan.* -**wall time: 1.86s** +**wall time: 2.88s** ````` @@ -4493,7 +4487,7 @@ ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph. *An unparseable claim — the refusal names the accepted shapes.* -**exit code: 1** — **wall time: 2.82s** +**exit code: 1** — **wall time: 5.56s** ````` (empty) @@ -4509,25 +4503,25 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *Bare --slice=SYM: the INVENTORY of sliceable locals (), so a caller can pick VAR.* -**wall time: 5.00s** +**wall time: 6.63s** ````` - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + ````` @@ -4535,21 +4529,21 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *Intra-procedural def-use slice of ONE variable: one row per line touching it, k=def|use|both, reaching definitions flow-sensitive (reach=cfg).* -**wall time: 7.33s** +**wall time: 5.45s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + @@ -4559,30 +4553,30 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *TRANSITIVE backward value-flow from the seed variable, bounded BFS (depth= disclosed; a cut frontier says flow_truncated=1).* -**wall time: 6.31s** +**wall time: 8.19s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + - + pw = biasPrior( g, p );]]> - + & p, float alpha = 0.85f )]]> - + & p, float alpha = 0.85f )]]> @@ -4592,42 +4586,42 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *Forward flow: which statements the seed's value reaches, at the default depth bound.* -**wall time: 7.45s** +**wall time: 7.61s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + - + - + - + - + - + 0.0 )]]> - + - + @@ -4637,7 +4631,7 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *A variable the definition does not bind — the refusal shape, naming the inventory.* -**exit code: 1** — **wall time: 4.26s** +**exit code: 1** — **wall time: 2.38s** ````` (empty) @@ -4669,21 +4663,21 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *The compact legend posture: rows byte-identical, a versioned schema id replaces the repeated explanatory prose — for a many-small-calls loop.* -**wall time: 4.35s** +**wall time: 5.32s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + @@ -4693,12 +4687,12 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *Structural search written in CODE: $NAME binds one node; grammars=/shapes= disclose what the pattern became per grammar (a 3-argument call shape — the 2-argument spelling has no call site in this repo and correctly reports hits=0).* -**wall time: 3.64s** +**wall time: 3.48s** ````` rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) +rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) ````` @@ -4706,7 +4700,7 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *The ellipsis form over a macro-shaped call site; unsupported= names the families this verb does not serve.* -**wall time: 2.91s** +**wall time: 2.87s** ````` @@ -4746,7 +4740,7 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *A pattern that collapses to a bare token is REFUSED — never reported as hits=0.* -**exit code: 1** — **wall time: 1.90s** +**exit code: 1** — **wall time: 1.60s** ````` (empty) @@ -4762,30 +4756,28 @@ ripwire: --pattern: this pattern collapses to a single bare token, which is a TE *Boolean grep: hits where BOTH literals share the matched line (--grep-scope=line is the default).* -**wall time: 1.96s** - ````` 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -5049,7 +5041,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? 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 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 19751 bytes on 44 raw line(s)] ````` @@ -5058,25 +5050,25 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Restore the / sections the --for bundle collapses to a counted stub by default (this is the stub's own next= spelling).* -**wall time: 11.88s** +**wall time: 14.53s** ````` - + 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -5089,7 +5081,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? 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 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 ) … [149 more display lines; full output is 20084 bytes on 44 raw line(s)] ````` @@ -5098,25 +5090,25 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Opt OUT of compact conceptual serving: restore the rank-first auto walk (bundle="auto").* -**wall time: 11.57s** +**wall time: 9.49s** ````` - + 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -5129,7 +5121,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? 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 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 ) … [134 more display lines; full output is 20303 bytes on 55 raw line(s)] ````` @@ -5138,17 +5130,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Doc-mention surfacing (default ON): a markdown doc naming a top-resolved symbol in a backtick rides in below that symbol — the legend's [doc mentions: …] clause says it fired.* -**wall time: 18.94s** +**wall time: 8.77s** ````` - + 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 inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… @@ -5160,17 +5152,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? std::optional<int> runQualityDelta( const MainDispatch& d ) struct DeltaBasis int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] -inline const char* kAcksFile = ".ripwire_quality_acks" +inline const char* kAcksFile = ".ripwire_quality_acks" DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) -struct IdentityHealing +struct IdentityHealing inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) -inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) -inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) inline std::string qualityAcksPath( const std::string& root ) struct QualityDeltaOutcome std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) -inline bool atomicWriteFile( const std::string& path, const std::string& blob ) -inline std::string gitHeadSha( const std::string& root ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) … [193 more display lines; full output is 22995 bytes on 45 raw line(s)] ````` @@ -5178,17 +5170,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *The same task with doc-mention surfacing OFF — the contrast the flag exists for (no [doc mentions] clause, one fewer row).* -**wall time: 10.95s** +**wall time: 8.51s** ````` - + 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 inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… @@ -5200,17 +5192,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? std::optional<int> runQualityDelta( const MainDispatch& d ) struct DeltaBasis int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] -inline const char* kAcksFile = ".ripwire_quality_acks" +inline const char* kAcksFile = ".ripwire_quality_acks" DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) -struct IdentityHealing +struct IdentityHealing inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) -inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) -inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) inline std::string qualityAcksPath( const std::string& root ) struct QualityDeltaOutcome std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) -inline bool atomicWriteFile( const std::string& path, const std::string& blob ) -inline std::string gitHeadSha( const std::string& root ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) … [193 more display lines; full output is 22814 bytes on 45 raw line(s)] ````` @@ -5218,14 +5210,14 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *"Can I delete this?" — callers + transitive impact + every use site + how much of the radius is tested, composed in ONE call; risk= names what was found, never a verdict.* -**wall time: 3.97s** +**wall time: 2.43s** ````` - - - + + @@ -5237,7 +5229,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Unknown-symbol refusal shape for --safe-delete.* -**exit code: 1** — **wall time: 2.70s** +**exit code: 1** — **wall time: 2.28s** ````` (empty) @@ -5253,22 +5245,22 @@ ripwire: --safe-delete symbol not found: DoesNotExist *The continuation packet for the NEXT session: disk truth (branch/sha, changed symbols, blast radius, tests) + labeled suggestions. Recorded against a CLEAN tree.* -**wall time: 14.56s** +**wall time: 19.43s** ````` - + - + - - - + + + + ````` @@ -5277,18 +5269,19 @@ ripwire: --safe-delete symbol not found: DoesNotExist *The same packet under a hard ceiling: heuristic rows drop tail-first (withheld= disclosed), verified rows never drop.* -**wall time: 13.38s** +**wall time: 10.91s** ````` - - + + - + ````` @@ -5297,14 +5290,14 @@ ripwire: --safe-delete symbol not found: DoesNotExist *WHY a file is not in the index (oversize / excluded / unsupported-ext / gitignored) and which indexed files it cannot vouch for (degraded-parse, minified-suspect), plus the per-language census.* -**wall time: 1.53s** +**wall time: 1.49s** ````` - @@ -5337,12 +5330,12 @@ ripwire: --safe-delete symbol not found: DoesNotExist *Crawl paths the repo's own .gitignore covers (default honours it and discloses ignored_files=/ignored_dirs= only when it dropped anything — this repo's crawl drops nothing, so the header is identical to the default map's; --skipped's ignore_mode= says which rule applied).* -**wall time: 1.68s** +**wall time: 1.04s** ````` - + @@ -5357,7 +5350,7 @@ ripwire: --safe-delete symbol not found: DoesNotExist - + @@ -5377,12 +5370,12 @@ ripwire: --safe-delete symbol not found: DoesNotExist *--no-stable outside --mcp: what the flag does (or says) when there is no stable-by-default ordering to opt out of.* -**wall time: 2.22s** +**wall time: 1.78s** ````` - + @@ -5397,7 +5390,7 @@ ripwire: --safe-delete symbol not found: DoesNotExist - + @@ -5423,21 +5416,21 @@ ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable o *EXEC-MODE --from-trace: run a command, and on a non-zero exit map its captured output onto indexed symbols in the same call — the whole fix-loop entry. ripwire exits 4 here because the wrapped command failed, which is the signal, not an incident.* -**exit code: 4** — **wall time: 1.65s** +**exit code: 4** — **wall time: 1.71s** ````` - + - + const&, float) src/graph.h:11811 - #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11852 + #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 #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)]]> pw = biasPrior( g, p ); @@ -5465,19 +5458,19 @@ ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable o std::vector r( N, 0.f ); std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); return { std::move( r ), run.iterationCount, run.hasConverged }; -}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] +}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] ````` ## `./build/ripwire . --run-trace="true"` *A command that exits 0: a minimal success record (exit, measured duration, disclosed output tail) and NO bundle — nothing failed, nothing to map.* -**wall time: 1.75s** +**wall time: 1.51s** ````` - + ````` @@ -5485,7 +5478,7 @@ ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable o *A command still running at the cap: its process group is killed and the run reports timed_out=1 — an honest timeout, never an empty success.* -**exit code: 4** — **wall time: 3.47s** +**exit code: 4** — **wall time: 3.28s** ````` @@ -5525,21 +5518,21 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *THE single wide-angle quality read: six families in one pass, an eligible/ranked shortlist rather than a firehose.* -**wall time: 10.46s** +**wall time: 10.07s** ````` - - - + + - + @@ -5555,9 +5548,9 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir - + - + … [188 more display lines; full output is 15676 bytes on 1 raw line(s)] ````` @@ -5565,12 +5558,12 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Per-function size ranking, largest Halstead volume/token entropy/lines first — a size proxy, not a readability order (withdrawn, docs/EVALS.md §8) — a RANKING lens, not a grade.* -**wall time: 1.67s** +**wall time: 2.24s** ````` - - + + @@ -5585,11 +5578,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Functions WITH a doc comment, most name-restating first: c_coeff (high = the comment repeats the name) and cic (Jaccard of comment vs identifier vocabulary), both reported, never collapsed.* -**wall time: 1.89s** +**wall time: 2.76s** ````` - + @@ -5605,37 +5598,37 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The local-reasoning lens: to understand this symbol, how much must you know that is NOT in front of you (ent_ratio= edge share, read_ratio= token-weighted).* -**wall time: 2.12s** +**wall time: 1.59s** ````` - + - + - - - - - - - + + + + + + + - - - + + + - - - - + + + + - - + + … [21 more display lines; full output is 11151 bytes on 1 raw line(s)] @@ -5645,11 +5638,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Per function, the non-local MUTABLE state it can reach (transitively), most writes first — unsound by construction, and the legend says where.* -**wall time: 3.30s** +**wall time: 3.54s** ````` - @@ -5685,11 +5678,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The family join: per function, which of four orthogonal evidence families fire, ranked by how many agree.* -**wall time: 7.65s** +**wall time: 6.43s** ````` - @@ -5725,11 +5718,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The cache-locality lens over every aggregate: fields READ TOGETHER but declared FAR APART (split-line / straddle findings, Chilimbi separation weight) — advice only, never a rewrite.* -**wall time: 2.19s** +**wall time: 2.27s** ````` - @@ -5765,11 +5758,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The same lens narrowed to ONE struct — the one --layout=Symbol shows the offsets for.* -**wall time: 2.23s** +**wall time: 2.88s** ````` - @@ -5801,14 +5794,14 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The corpus's OWN case-convention vote per (language, kind) group; off-convention names get a mechanical propose= (a suggestion, never a blind rename).* -**wall time: 1.28s** +**wall time: 1.47s** ````` - - - - + + + + @@ -5821,7 +5814,7 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir - + @@ -5841,12 +5834,12 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Score the naming-* rules against this repo's own rename history: proxy=old/(old+new) per rule, 0.50 = chance; read pairs= (sample size) first.* -**wall time: 14.43s** +**wall time: 14.69s** ````` - - + + @@ -5864,25 +5857,25 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir

-

+

-

+

-… [156 more display lines; full output is 16229 bytes on 1 raw line(s)] +… [154 more display lines; full output is 16043 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --lint --naming-locals` *The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/C++ only, only inside functions already past a size/complexity gate.* -**wall time: 3.82s** +**wall time: 3.89s** ````` - + @@ -5898,7 +5891,7 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir - + @@ -5918,7 +5911,7 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The built-in rule registry — one row per rule with sev=/category=/rationale/lang=/since=; no corpus needed.* -**wall time: 1.99s** +**wall time: 1.16s** ````` @@ -5996,7 +5989,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *Run ONLY one rule family; the root carries selected="K of N" so a filtered zero is never confusable with an unfiltered one.* -**wall time: 4.53s** +**wall time: 3.34s** ````` @@ -6036,7 +6029,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *DROP two families, applied after selection; the raw select=/ignore= you passed rides on the root.* -**wall time: 4.56s** +**wall time: 3.06s** ````` @@ -6076,7 +6069,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *A rule that spends its own match budget (here 4, set BELOW the default 5000 so the floor shows on this repo): goto carries count_capped="1", its count= is a FLOOR, and the root names the call that counts the rest — findings_next= re-runs only the floored rules under a 10x budget.* -**wall time: 4.31s** +**wall time: 2.91s** ````` @@ -6093,7 +6086,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *Pasting that findings_next=: the same rule under a 10x budget counts its true total — no count_capped=, no findings_next=.* -**wall time: 7.17s** +**wall time: 3.26s** ````` @@ -6124,7 +6117,7 @@ ripwire.connect/v1 : minimal joining subgraph: groups, terminal *An unresolvable PREFIX refuses (exit 1) with a did-you-mean from a real edit distance (one character off cache-).* -**exit code: 1** — **wall time: 4.29s** +**exit code: 1** — **wall time: 2.98s** ````` (empty) @@ -6140,7 +6133,7 @@ ripwire: --lint-select: 'cach-' matches no rule or family (did you mean 'cache-' *A PREFIX with no near miss at all: the refusal points at --lint-catalog instead of guessing.* -**exit code: 1** — **wall time: 3.70s** +**exit code: 1** — **wall time: 2.80s** ````` (empty) @@ -6156,7 +6149,7 @@ ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint- *The SAME findings as SARIF 2.1.0 (what github/codeql-action/upload-sarif consumes) — pure re-serialization, results count == the native run's.* -**wall time: 4.41s** +**wall time: 3.34s** ````` {"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"name":"ripwire","rules":[{"id":"c-style-cast","shortDescription":{"text":"c-style-cast"},"properties":{"builtin":true,"capped":false,"applicable": … [line truncated: 7 more bytes on this line] @@ -6189,13 +6182,13 @@ ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint- {"id":"atom-nested-ternary","shortDescription":{"text":"atom-nested-ternary"},"properties":{"builtin":true,"capped":false,"applicable":true}}, {"id":"atom-implicit-predicate","shortDescription":{"text":"atom-implicit-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, {"id":"atom-octal-literal","shortDescription":{"text":"atom-octal-literal"},"properties":{"builtin":true,"capped":false,"applicable":true}}, -… [13479 more display lines; full output is 1908209 bytes on 1 raw line(s)] +… [13475 more display lines; full output is 1907616 bytes on 1 raw line(s)] ````` Parsed summary of the same SARIF (past the display cut): ````` -sarif 2.1.0 rules= 39 results= 6735 +sarif 2.1.0 rules= 39 results= 6733 ````` ## `./build/ripwire . --lint --sarif --limit=5` @@ -6218,11 +6211,11 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The Delta Maintainability Model scalar for the WORKING TREE vs HEAD — recorded against a CLEAN tree (the sandbox section shows a real delta). UNAVAILABLE is a stated reason, never 0 or 1.* -**wall time: 18.66s** +**wall time: 8.72s** ````` -

@@ -6233,11 +6226,11 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The per-commit scalar: HEAD vs its first parent, with the three separately actionable sub-scores.* -**wall time: 30.01s** +**wall time: 17.60s** ````` -

@@ -6248,14 +6241,14 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The range form: tree HEAD vs tree HEAD~3.* -**wall time: 24.93s** +**wall time: 16.23s** ````` - -

-

+ +

+

````` @@ -6263,11 +6256,11 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none of which it depends on" — a greedy cover, disclosed as greedy.* -**wall time: 10.00s** +**wall time: 4.06s** ````` - + @@ -6296,48 +6289,48 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M -… [847 more display lines; full output is 56290 bytes on 1 raw line(s)] +… [846 more display lines; full output is 56221 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --cochange --cochange-recur=2` *Only pairs whose co-change RECURS in 2+ sub-windows of the mined window (sub_windows= is the denominator) — a one-off sprint stops reading like a structural defect.* -**wall time: 12.14s** +**wall time: 4.76s** ````` - + + + - - - + - + - - + + - - - - + + + + + - ````` @@ -6345,7 +6338,7 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M *The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector).* -**wall time: 9.28s** +**wall time: 4.25s** ````` (empty) @@ -6354,14 +6347,14 @@ ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M Artifact written: ````` - 156039 /aux/map2.html + 156171 /aux/map2.html ````` ## `./build/ripwire . --index-out=/aux/ci_index` *CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout.* -**wall time: 7.32s** +**wall time: 5.75s** ````` (empty) @@ -6370,28 +6363,28 @@ Artifact written: stderr: ````` -ripwire: --index-out wrote /aux/ci_index.lean.ripwirecache (28772140 bytes, lean family) -ripwire: --index-out wrote /aux/ci_index.rich.ripwirecache (58967687 bytes, rich family) +ripwire: --index-out wrote /aux/ci_index.lean.ripwirecache (28475910 bytes, lean family) +ripwire: --index-out wrote /aux/ci_index.rich.ripwirecache (58343715 bytes, rich family) ````` Artifact written: ````` - 28772140 /aux/ci_index.lean.ripwirecache - 58967687 /aux/ci_index.rich.ripwirecache - 87739827 total + 28475910 /aux/ci_index.lean.ripwirecache + 58343715 /aux/ci_index.rich.ripwirecache + 86819625 total ````` ## `./build/ripwire . --cache=/aux/ci_index.lean.ripwirecache --top-k=3` *Consume the lean artifact in a PR job: restore-equivalence, never blob-byte-identity.* -**wall time: 2.95s** +**wall time: 1.77s** ````` - + @@ -6406,7 +6399,7 @@ Artifact written: - + @@ -6426,12 +6419,12 @@ Artifact written: *Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target.* -**wall time: 4.57s** +**wall time: 2.81s** ````` - + @@ -6446,7 +6439,7 @@ Artifact written: - + @@ -6473,18 +6466,18 @@ Artifact written: # whose template-argument list spans lines keeps its line break as \n instead of splitting the row. # line is the 1-based call-site line in the caller's file (v2, appended LAST so v1 readers are unchanged): # the key a SCIP occurrence joins on, so a coverage loss can be classified per site instead of guessed. - 129568 /aux/pin_census.tsv + 129411 /aux/pin_census.tsv ````` ## `./build/ripwire . --plan-lint=test/planlintfix/wave.md` *The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates.* -**exit code: 2** — **wall time: 6.82s** +**exit code: 2** — **wall time: 4.10s** ````` - + @@ -6502,11 +6495,11 @@ Artifact written: *The ledger-shaped fixture through the same check (exit 2: one gating card).* -**exit code: 2** — **wall time: 11.51s** +**exit code: 2** — **wall time: 4.38s** ````` - + @@ -6518,18 +6511,18 @@ Artifact written: *--doctor plus a LIVE integration inspection for one agent: PATH binary, installed-skill manifest parity, hook executability, MCP wiring — read-only, fixed repair commands, never config contents; exit 1 when any check fails.* -**exit code: 1** — **wall time: 61.05s** +**exit code: 1** — **wall time: 35.51s** ````` - - + - - + + - - + @@ -6542,7 +6535,7 @@ Artifact written: *Other --agent values refuse.* -**exit code: 1** — **wall time: 1.46s** +**exit code: 1** ````` (empty) @@ -6565,15 +6558,15 @@ Everything below runs with `cwd` = the throwaway clone at `/dirty` (`gi *Situational report for a real diff: blast radius + tests + co-change + forgotten co-change partners.* -**wall time: 18.77s** +**wall time: 15.47s** ````` ripwire situational-awareness — 1 changed file(s), 13 symbols in them root: . -at: 79e691876+dirty +at: d3605fde7+dirty change_set: granularity=file changed_symbols=13 file_symbols=13 files_narrowed=0 files_file_granular=1 diff_hunks=7 diff_hunks_located=6 diff_hunks_unlocated=1 — seeds = symbols a diff -U0-vs-HEAD hunk overlaps (function/method body spans only); an unlocated hunk (module-level, deletion, rename) … [line truncated: 34 more bytes on this line] [1] blast radius: 246 symbols across 58 files transitively depend on these changes (showing 8 of 58 files — shown=8 total=58 capped=1 prcontext_cap=20 (--pr-context's own per-file list is cut at 20 too); next: --situ --limit=58) - counts_floor=1 graph_ambiguous=2932 graph_unresolved=15244 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] + counts_floor=1 graph_ambiguous=2927 graph_unresolved=15221 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] src/mcpverbs.h (33 dependent symbols) src/quality.h (15 dependent symbols) src/verbs_quality.h (14 dependent symbols) @@ -6589,8 +6582,8 @@ at: 79e691876+dirty test/verify_csr.cpp [hops=2] (run: bash test/a9disclosurecheck.sh) test/rustimport_unit.cpp [hops=4] (run: bash test/rustimportprecisecheck.sh) script_gates_unmodelled=782 — test/*.sh gates never appear above: script-to-binary edges are not call edges (a path count) - [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5284": - (none — 5284 commits were mined and none co-edited a file outside your diff) + [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5267": + (none — 5267 commits were mined and none co-edited a file outside your diff) next: --test-gate ````` @@ -6598,11 +6591,11 @@ at: 79e691876+dirty *The pre-PR gate with real obligations — exit 4 when tests-to-run or untested blast radius is non-empty.* -**exit code: 4** — **wall time: 17.32s** +**exit code: 4** — **wall time: 11.69s** ````` - @@ -6613,7 +6606,7 @@ at: 79e691876+dirty - + @@ -6640,11 +6633,11 @@ at: 79e691876+dirty *Every row carries p="file:line", the gating rows are marked gating="1" and now bar= (the threshold each numeric row is judged against), and the exit-2 refusal prints a naming line on stderr; a gating row carries a pasteable next=.* -**exit code: 2** — **wall time: 63.43s** +**exit code: 2** — **wall time: 48.22s** ````` - @@ -6679,6 +6672,7 @@ at: 79e691876+dirty stderr: ````` +ripwire: cache : over its 2048 MiB budget — evicted 29 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) ````` @@ -6687,11 +6681,11 @@ ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: ap *The same gating report under --legend=full — same rows, same exit 2; the default compact comment (schema="ripwire.quality-delta/v1", the shape an agent's edit loop should run) becomes ~4 KB of prose legend.* -**exit code: 2** — **wall time: 39.15s** +**exit code: 2** — **wall time: 29.04s** ````` - @@ -6734,10 +6728,10 @@ ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: ap *The same findings as JSON (one of the CI/scripting verbs --json supports) — same exit 2 as the XML form.* -**exit code: 2** — **wall time: 32.41s** +**exit code: 2** — **wall time: 28.47s** ````` -{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"79e691876+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] +{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"d3605fde7+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] {"kind":"complexity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":67,"p":"src/infra/sortutil.h:49","gating":true}, {"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy","p":"src/infra/sortutil.h:119","origin":"new-symbol"}, {"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","p":"src/infra/sortutil.h:129","origin":"new-symbol"}, @@ -6781,7 +6775,7 @@ ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: ap *NEW FLAG: --ack-only matching nothing REFUSES rather than falling back to acking everything.* -**exit code: 1** — **wall time: 25.59s** +**exit code: 1** — **wall time: 18.31s** ````` (empty) @@ -6799,7 +6793,7 @@ ripwire: --ack-only=zzznope matched none of the 9 finding(s) — nothing written *NEW FLAG: ack only the api-surface findings — a per-finding ratchet instead of a rubber stamp.* -**wall time: 23.30s** +**wall time: 21.91s** ````` (empty) @@ -6817,11 +6811,11 @@ ripwire: acknowledged 1 of 9 finding(s) (8 left UNACKED by --ack-only, 0 already *Re-run after the partial ack: acked=3, the rest still gate (exit 2).* -**exit code: 2** — **wall time: 41.14s** +**exit code: 2** — **wall time: 30.42s** ````` - @@ -6880,11 +6874,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - @@ -6896,11 +6890,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire row identical.* -**wall time: 4.85s** +**wall time: 7.72s** ````` - @@ -6912,11 +6906,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - @@ -6952,13 +6946,13 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire ) and selectors take it. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. --> - - + + @@ -6983,11 +6977,11 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire of ; dup_loc=/dup_pct=. window: shown= total= capped= has_more= next_offset= offset= limit= (capped=1 cut; next_offset= pastes as offset=). root=: p= relative to it. groups=/type3=: Type-2 and Type-3 group totals over all groups; total= is their sum. exempt_groups=N: groups whose members all sit on fixture/shell-runner paths quality-delta duplication ignores. idiom_groups=/demoted_groups=: groups of one recognized idiom / those quality-delta demotes to minor; floors. clone_groups=N: clusters after merging pairs (rows sharing gid=); a floor under type3_capped=1. total_loc=N: lines of every function body the detector considered; dup_pct= is dup_loc= over it. group exempt=fixture|shell-runner: every member is on such a path; quality-delta duplication ignores it. group idiom=: the recognized shape every member spells: threshold-ladder, switch-name-table, builder-chain. --> - + @@ -6997,7 +6991,7 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - + @@ -7012,7 +7006,7 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire - + @@ -7023,12 +7017,12 @@ ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire ; v=unknown = no merge base. at=: commit+dirty+shallow. head=: the HEAD commit, bare 9-hex sha (at= adds +dirty). head_ref=: HEAD's branch (HEAD when detached); that branch itself is not scanned. refs=N: local branches scanned (refs/heads only); unmerged + superseded + merged + unknown = refs. blobs=N: distinct git blobs read for the sweep. unmerged=N: refs whose authored work the live line genuinely lacks. superseded=N: refs whose work the live line re-implemented (removed the same base code). merged=N: refs whose work HEAD already has; omitted from the rows. name=: the local branch. tip=: the branch tip commit (9 hex). date=: the tip's committer date, YYYY-MM-DD. files=N: files with stray lines; rows capped at 12, a more element counts the rest (detail=1 lists all). ref superseded=N>: of this ref's stray= lines, those in files the live line re-implemented. unknown=N: refs that could not be analysed (v=unknown, e.g. no merge base); never counted merged. --> - - + + ````` @@ -7043,11 +7037,11 @@ stderr: *CHANGED: --plan surfaces those same refs as an row rather than silently dropping them.* -**wall time: 18.10s** +**wall time: 10.90s** ````` - + ````` @@ -7062,11 +7056,11 @@ stderr: *The DMM scalar on a REAL delta: the sandbox edit grew one unit past the nesting/complexity thresholds and added an 8-parameter one, so dmm is low and the three sub-scores say which property moved.* -**wall time: 14.73s** +**wall time: 12.21s** ````` -

@@ -7077,11 +7071,11 @@ stderr: *OWNERSHIP partition for a shared tree: every regression here lives in src/infra/, so under a scope naming src/graph.h they ALL print under with a do-not-ack banner and never gate — scoped-out-gating= says how many would have.* -**wall time: 22.40s** +**wall time: 31.39s** ````` - @@ -7123,7 +7117,7 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *The rubber-stamp guard: an --ack-only that names an OUT-OF-SCOPE row refuses (exit 1) and writes nothing.* -**exit code: 1** — **wall time: 17.86s** +**exit code: 1** — **wall time: 25.91s** ````` (empty) @@ -7143,11 +7137,11 @@ ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=sr *The continuation packet with a REAL diff: verified changed symbols + blast radius + tests-to-run, then the heuristic rows.* -**wall time: 12.31s** +**wall time: 19.11s** ````` - + @@ -7172,11 +7166,11 @@ ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=sr - - - - - + + + + + ````` @@ -7185,10 +7179,10 @@ ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=sr *Pin a field note (write-side memory) to a symbol; committed to .ripwire_notes in the sandbox. The BARE name is resolved through the same resolver the read verbs use and stored as the canonical id — the rewrite is echoed on stderr, because a silent one is not a disclosure.* -**wall time: 4.38s** +**wall time: 4.48s** ````` -src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 keep this branch-free — it sits inside the PageRank sort comparator 79e6918767f2b64a78d55955c4ddfd1cdeb31874 integration/train-36 +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 keep this branch-free — it sits inside the PageRank sort comparator d3605fde7ff60e4b1fca435f5a35be61b5879617 integration/train-35 ````` stderr: @@ -7202,7 +7196,7 @@ ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sort *The note is listed under the canonical id, dangling="0" — i.e. it will actually surface. (Before the H1 fix the bare name was stored verbatim and read dangling="1": recorded, and surfaced nowhere.)* -**wall time: 1.53s** +**wall time: 2.01s** ````` @@ -7215,7 +7209,7 @@ ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sort - + @@ -7232,7 +7226,7 @@ ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sort *Two definitions carry this name, so the write REFUSES rather than pick one: a note keys ONE canonical id, and an ambiguous selector is refused, never silently narrowed. Every candidate is named, with a runnable retry.* -**exit code: 1** — **wall time: 1.64s** +**exit code: 1** — **wall time: 1.61s** ````` (empty) @@ -7249,7 +7243,7 @@ ripwire: --note-add: target 'gitOneLine' is ambiguous — it matches 2 definitio *A name that resolves to nothing is refused with the read verbs' own did-you-mean — never written as a dead note.* -**exit code: 1** — **wall time: 2.10s** +**exit code: 1** — **wall time: 1.89s** ````` (empty) @@ -7266,17 +7260,17 @@ ripwire: --note-add: target not found: lessByScoreDescIdd (did you mean 'lessByS *The same symbol addressed by its CANONICAL id: already canonical, so nothing is rewritten and both notes land on ONE target.* -**wall time: 4.38s** +**wall time: 4.92s** ````` -src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort 79e6918767f2b64a78d55955c4ddfd1cdeb31874 integration/train-36 +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort d3605fde7ff60e4b1fca435f5a35be61b5879617 integration/train-35 ````` ## `./build/ripwire . --expand=lessByScoreDescId --top-k=0` *Both notes riding along with the symbol's body — the elements follow the body, past the display cut, so they are extracted below.* -**wall time: 1.72s** +**wall time: 2.25s** ````` @@ -7315,10 +7309,10 @@ src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-25 chose the flat The element on the same output — past the 30-line display cut above: ````` - + - + ````` @@ -7343,7 +7337,7 @@ ripwire: --edit-payload is empty; empty never means delete *Whole-symbol replace without a whole-file read: the payload is the ORIGINAL flat body, so this edit undoes the sandbox's deep-nesting regression. The receipt's span is the POST-edit byte range; replaced_bytes counts the old bytes overwritten.* -**wall time: 13.31s** +**wall time: 12.04s** Input file: @@ -7360,18 +7354,17 @@ inline bool lessByScoreDescId( const std::vector& scores, std::uint32_t a ````` {"applied":"replace_symbol_body","symbol":"lessByScoreDescId","file":"src/infra/sortutil.h","span":{"start":2162,"end":2375},"lines":{"start":49,"end":56},"replaced_bytes":1718,"old_file_bytes":12329,"new_file_bytes":10824,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separa … [line truncated: 726 more bytes on this line] -"graph_ambiguous":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"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"}, {"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":2932,"graph_unresolved":15244,"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":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ````` stderr: ````` -ripwire: cache : over its 2048 MiB budget — evicted 189 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: bash test/greptiercheck.sh ````` @@ -7379,15 +7372,15 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *The closed loop: contract unchanged (same params, same publicness) after the replace — nothing provably incompatible.* -**wall time: 6.77s** +**wall time: 7.03s** ````` - + - + @@ -7401,16 +7394,16 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call.* -**wall time: 8.39s** +**wall time: 10.36s** ````` {"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"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"}, {"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":2932,"graph_unresolved":15244,"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":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ````` stderr: @@ -7423,7 +7416,7 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr.* -**wall time: 2.85s** +**wall time: 4.81s** ````` {"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] @@ -7439,19 +7432,19 @@ ripwire edit: applied atomically; receipt carries region, blob_sha (post-check s *Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured).* -**wall time: 6.44s** +**wall time: 12.13s** ````` {"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] {"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"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"}, {"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":2932,"graph_unresolved":15244,"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":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ````` stderr: @@ -7464,7 +7457,7 @@ ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, *An unknown TARGET refuses and leaves every file byte-identical.* -**exit code: 1** — **wall time: 2.79s** +**exit code: 1** — **wall time: 5.26s** ````` (empty) @@ -7480,7 +7473,7 @@ ripwire: --replace-symbol-body: symbol 'DoesNotExist' not found *A versioned multi-edit TRANSACTION preflighted without writing: the receipt shows what each op would read and touch.* -**wall time: 2.38s** +**wall time: 4.45s** Input file: @@ -7498,21 +7491,21 @@ Input file: ````` ````` -{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 353 more bytes on this line] +{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 344 more bytes on this line] ````` ## `./build/ripwire . --edit-plan=/aux/edit_plan.json --apply` *The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure.* -**wall time: 7.72s** +**wall time: 11.12s** ````` -{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15244,"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] +{"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] {"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true}}]} +"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true}}]} ````` ## `./build/ripwire . --edit-plan=/aux/edit_plan.json` @@ -7535,11 +7528,11 @@ ripwire: --edit-plan requires exactly one of --dry-run or --apply *After the agent's edits: the complexity/nesting rows on lessByScoreDescId are gone (the replace undid them), the rest still gate (exit 2).* -**exit code: 2** — **wall time: 28.21s** +**exit code: 2** — **wall time: 29.22s** ````` - @@ -7582,7 +7575,7 @@ ripwire: --quality-delta gating: 2 preexisting-worse major finding(s); first: du *REFUSES, exit 1: this sandbox tree is already regressed, and pinning here would swallow that debt into the floor so every later delta read clean. It names how many gating findings it would absorb, the first of them, and the way forward.* -**exit code: 1** — **wall time: 26.75s** +**exit code: 1** — **wall time: 18.75s** ````` (empty) @@ -7601,7 +7594,7 @@ ripwire: --quality-baseline: this tree already holds 2 gating finding(s) against *The consent form: pin anyway. The sidecar is stamped with the dirty pin and the absorbed count, so the fact outlives the process that knew it.* -**wall time: 21.24s** +**wall time: 24.54s** ````` (empty) @@ -7611,16 +7604,16 @@ stderr: ````` ripwire: --quality-baseline --allow-dirty: pinned with 2 gating finding(s) ABSORBED into the floor (stamped in the sidecar; every --quality-delta against it carries baseline_absorbed="2") -ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30902 per-symbol rows, 31840 indexed symbols total) +ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30854 per-symbol rows, 31792 indexed symbols total) ````` Artifact written: ````` - 5231049 .ripwire_quality_baseline + 5222950 .ripwire_quality_baseline # ripwire quality baseline v6 — regenerate with --quality-baseline; do not hand-edit -producer 72f3abff6b630f368c12b1d27b427d7c9f2d913bf0dc07f5a47404b420717362 -head 79e6918767f2b64a78d55955c4ddfd1cdeb31874 +producer 934e2d834419518852b1c5321e5f49e8c32c33360e02046f99df50af7118aef1 +head d3605fde7ff60e4b1fca435f5a35be61b5879617 dirty 1 absorbed 2 ccx 67c15011ee8b 0 @@ -7633,11 +7626,11 @@ ccx 6a732f6699b *Against that sidecar the same tree reads regressions=0 — but baseline_absorbed= is on the root, so this green means clean SINCE THE PIN, never clean. A baseline is a floor YOU chose, and it belongs BEFORE the change.* -**wall time: 22.65s** +**wall time: 23.04s** ````` - ````` @@ -7760,57 +7753,57 @@ quality_delta desc_bytes= 742 schema_bytes= 279 required=[] *MCP `for`: always bundle=sigs (never the CLI's compact route), the same ranked signatures as --for.* -**wall time: 7.04s** +**wall time: 5.74s** ````` {"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: 738 more bytes on this line] -{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":". window: shown= capped= (capped=1 cut). at=: commit+dirty+shallow. next= … [line truncated: 6553 more bytes on this line] -"_index":"[index: files=3627 symbols=31838 hash=998d23bf]","_fresh":"ok"}} +"_index":"[index: files=3618 symbols=31790 hash=09a95744]","_fresh":"ok"}} {"jsonrpc":"2.0","id":3,"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…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** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [21 more display lines; full output is 3219 bytes on 1 raw line(s)] +````` + + +--- + +# zoom the detail ladder + +## `./build/ripwire . --for="pagerank power iteration" --detail=2` + +*Importance-weighted detail: FULL bodies for top-2, signatures for the rest.* + +**wall time: 6.70s** + +````` + + + + + +NodeId order. Renumbering an otherwise-identical graph (the exact "same probe file, different so…inline constexpr float kScoreTieAbsEps = 1e-6f + +Render one form of the disclosure. Empty string whenever there is nothing to say — no power it…inline std::string renderDisclosure( const RankDisclosure& d, DiscloseAs as ) + +The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] +inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) +struct RankedGraph +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… +inline std::uint32_t sliceRdIterationCeiling() noexcept +struct PageRankRun + +What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window +inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept +inline std::string powerShellSingleQuote( std::string_view s ) noexcept +inline std::string path_prepend_hint( std::string_view dir ) +HOT_FILES = ( "src/pagerank.cpp", # the power-iteration loop — G2's no-allocation scope "src/infra/radixSort.h", # LSD radix entry points "src/infra/radixSort.inl", # the counting … [line truncated: 76 more bytes on this line] +handle_t leftmost_leaf() const +inline void discloseUniformChurnFallback( bool hasChurnEvidence, bool stubbed, const char* verbLabel, const std::string& windowStamp ) +inline std::string doctorPathPrependLine( const std::string& selfPath ) +inline std::string doctorWhichRipwire( rw::os::stat_t& st ) +std::uint32_t testIterationCeiling() noexcept +inline const char* rankByLegendFor( const char* label ) noexcept +… [156 more display lines; full output is 22215 bytes on 72 raw line(s)] +````` + +## `./build/ripwire . --pack-signatures --top-k=10` + +*Body-elided decl skeletons — recounted on this corpus. Measured as element bytes: the signature+doc elements --pack-signatures emits, against the SAME symbols' full bodies from --expand, with the CORPUS-ROOT PREFIX SUBTRACTED FROM BOTH SIDES. That subtraction is the whole methodology and the figure is meaningless without it: the root repeats inside every element's id= and p=, it is not what this verb elides, and counting it makes the headline a function of how deep the checkout happens to sit on disk — on one corpus, three spellings of the same root read 18.6 points apart before the subtraction and agree exactly after it. Root-neutralised on THIS repo: 88.8% fewer bytes at top-10, 86.2% at top-50, 87.4% at top-100 (re-derived 2026-10-10 when the C++ standard-member gate stopped std::vector/std::string calls such as out.push_back() and s.empty() from binding to in-tree namesakes by name: the ranked top-10/50 lost one-line container accessors (svector::push_back, WidePath::c_str, every empty) and gained one-line forwarding helpers and macros (kindIs, ASSUME, formatTo, emitTo) whose signature is nearly the whole body, so less of the set is elidable, from 92.7/88.7/87.6; before that, re-derived 2026-09-20 when the native Windows port landed: src/infra/os_win32.cpp and os_win32_logic.h are ~3,900 lines of new, heavily commented infra that the ranked top-10/50/100 now reach, and their bodies are this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new, from top-50 87.1. Measured by test/showcasecapturecheck.sh's own recount arm on the combined tree, which is the gate that would otherwise report the drift; before that, re-derived 2026-09-17 at the self-check macro vocabulary rename: VERIFY/VERIFY_TEXT/VERIFY_DEBUG_ONLY/VERIFY_NOT_REACHED/VERIFY_SAME_THREAD/VERIFY_NO_ALIAS*/DYNMAP_VERIFY/DEGRADED_PATH_ALERT renamed to ASSUME/EXPECTS/ENSURES/DASSERT/UNREACHABLE/ASSUME_SAME_THREAD*/ASSUME_NO_ALIAS*/DYNMAP_ASSUME/DISCLOSE (plus new VALIDATE sites) across 839 identifier renames in 179 files, and a hand-written Diagnostics.h/diagnostics.cpp replacing the old ones outright: this moves both WHICH symbols the ranked top-10/50/100 hold and how large their bodies are, from top-50 85.2. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-12 when the rows dropped the path-repeating id= for the short sc= scope: the signature side shrank, the bodies did not; before that, 89.5% / 81.8% / 84.3% re-derived 2026-09-10 at the sibs= cap raise: kMaxExpandSibs went 8 -> 100, so --expand's bodies now carry the file context the old cap hid — 89.3% of all sibling names — and the body side is this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new. Measured on a fixed tree with the top-50 membership and the signature side unchanged: top-50 from 71.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-09 at the printf-family -> std::print conversion: converting ~1,500 emitter call sites to rw::emitTo/emitRaw/formatTo across 93 files changes how large the ranked symbols' BODIES are, and the body side is this ratio's denominator — top-50 from 72.3. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-08 at the confident-zero round, issues #62/#63/#66: that change adds symbols to src/graphlegend.h and the new src/preprocdead.h and re-homes two long comment blocks from call sites onto the helpers they explain, which moves both WHICH symbols the ranked top-50 holds and how large their bodies are — top-50 from 74.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-06 at the stranger-audit fix round: the doctor, cache-sweep and html-provenance bodies grew this corpus's BODY side, moving top-50 from 75.6 — a real re-derivation, not a tolerance edit; before that, re-derived 2026-09-05 at the capture-audit close: lane L7's P16 caps --expand's sibs= at 8 names, which SHRINKS the body side of this ratio and moved the figure down from 84.5/80.2/80.6 — the V1 2026-08-15 re-center, when sibs=/inc= first grew the body side from 70.0/61.0/63.8, in reverse; both were real re-derivations, not tolerance edits). top-50 is the number to quote, because the sigs payload is top-50 regardless of --top-k and is therefore what THIS command emits. A single small/trivial body can still invert it (signature+doc bigger than the body), like the --format=columnar sibling below. test/showcasecapturecheck.sh (C) re-derives all three from this repo every run, in the same quantity, and fails if the caption and the recount drift apart.* + +**wall time: 3.50s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [148 more display lines; full output is 14953 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --outline=rankGraphTeleport --top-k=0` + +*Control-flow skeleton of one symbol, payload-only via the new --top-k=0.* + +**wall time: 6.59s** + +````` + + + + +& p, float alpha = 0.85f ) +{ + PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); + const std::vector pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + ... + } + std::vector r( N, 0.f ); + std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); + return { std::move( r ), run.iterationCount, run.hasConverged }; +} +]]> +````` + +## `./build/ripwire . --outline=rankGraphTeleport:1-10 --top-k=0` + +*CHANGED: a line range on --outline is now STRIPPED with a stderr note (it used to refuse).* + +**wall time: 2.72s** + +````` + + + + +& p, float alpha = 0.85f ) +{ + PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); + const std::vector pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + ... + } + std::vector r( N, 0.f ); + std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); + return { std::move( r ), run.iterationCount, run.hasConverged }; +} +]]> +````` + +stderr: + +````` +ripwire: --outline=rankGraphTeleport:1-10: --outline has no line-range form — outlining the whole symbol (use --expand=rankGraphTeleport:1-10 for a body slice) +````` + +## `./build/ripwire . --expand=rankGraphTeleport --top-k=0` + +*Full body + inline callee signatures.* + +**wall time: 2.78s** + +````` + + + + +: files the ranked rows show / do not (sum = files=), each named or counted below. : a program entry by its language's convention (C/Go/Rust main, Java/C# static main, a script main its module scope calls, __main__.py), callees as c rows; manifest entries not read. : n= unshown files under dir p=; f= names its code files, the rest (tests, docs, config, test/doc/example dirs) counted. declined=K: K call sites without edges, including inert Elixir quote sites after unquote/unquote_splicing re-entry. external=K: K calls proven outside the tree, no edge. locality_pinned=K: K calls pinned by locality alone (a guess). extent_suspect_syms=K: K defs failed containment, corpus-wide. macro_blanked_files=K: K files indexed from a macro-blanked re-parse. prov=scip|binding|import|split|final-segment: how that edge bound (absent: one unique name); split = one arm of an amb= pick; final-segment = a qualified type matched by last name only. files=/symbols=: files and symbols indexed; edges= distinct call edges; shown= symbols printed, a merged row counting each def; ambiguous= calls split over several defs, corpus-wide; unresolved= calls with in-tree evidence and no edge (every def language-filtered or unreachable, or binding refused); order= rows by rank (important-first, important-last; (auto:fill) = flipped past a size threshold) or by path (stable). skipped_oversize=K: K files over a size ceiling, not indexed. unindexed=ext:N: N text files of that extension no grammar reads (6 extensions at most). unindexed_exts=E: E such extensions in all, the list cut. : a non-test row an indexed test transitively reaches (absent otherwise, never 0). : that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= lcom4= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, class cohesion, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [102 more display lines; full output is 11385 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --deps` + +*File->file dependency graph (god-files, cycles).* + +**wall time: 1.92s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [904 more display lines; full output is 24136 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --hotspots` + +*Complexity x recent git churn (maintenance pain).* + +**wall time: 6.87s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [14 more display lines; full output is 5767 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --clones` + +*Token-normalized duplicate bodies.* + +**wall time: 3.73s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [308 more display lines; full output is 16199 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --cochange` + +*Files that change together in git (hidden coupling).* + +**wall time: 5.67s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --hotspots --since="2 weeks ago"` + +*Hotspots scoped to RECENT churn (the regression lens).* + +**wall time: 8.47s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [13 more display lines; full output is 5130 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --arch=test/archfix/rules.txt` + +*Enforce layering rules (exit 2 on violation) — run against the repo's own test fixture rules.* + +**wall time: 1.24s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [1047 more display lines; full output is 154687 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint` + +*Built-in AST checks (c-cast, goto, unsafe-c-fn, ...).* + +**wall time: 2.58s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [685 more display lines; full output is 70581 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint-rules=test/lintrulesfix/rules` + +*User lint rules (YAML, ast-grep style) from a directory.* + +**wall time: 1.58s** + +````` + + + + +use LOG() instead of printf +use LOG() instead of printf +use LOG() instead of printf +use LOG() instead of printf +use LOG() instead of printf + +````` + +stderr: + +````` +ripwire: lint-rules: test/lintrulesfix/rules/malformed.yaml:5: expected 'key: value' — file skipped +[math degraded] lint-rules: malformed rule file skipped (lintrules.h:399, auto rw::parseLintRuleFile(const std::string &, std::string_view, std::vector &)::(anonymous class)::operator()(std::size_t, const char *) const — logged once per site) +ripwire: AST query did not compile for any grammar: (this_is_not_a_real_node @x @@@ ((( ) +````` + +## `./build/ripwire . --lint --with-profile=report.txt` + +*Join MEASURED heat onto --lint findings — runs in a tiny fabricated demo corpus (one cache-pointer-chase-loop finding under a PROFILE_SCOPE site) because a real report needs a RIPWIRE_PROFILE build; the finding inside the profiled scope gains heat_* columns from the report's #PROF_TSV row.* + +Input file: + +````` +#PROF_TSV_BEGIN one row per scope, aggregated across threads; counters are RAW integers +scope file line calls total_ms l1d_mpki +walk: chase pass x.cpp 9 12 48.500 7.250 +#PROF_TSV_END +````` + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [13 more display lines; full output is 3428 bytes on 1 raw line(s)] +````` + +The joined finding — past the display cut above, extracted so the join is visible: + +````` +p = p->next +````` + +## `./build/ripwire . --communities` + +*Cluster the call graph into cohesive modules.* + +**wall time: 1.10s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [189 more display lines; full output is 16947 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --zoom` + +*Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels_shown="2" of levels= BY DEFAULT over the 40 largest top modules (~8 KB, where the whole tree is ~220 KB); a module AT the cut carries children=.* + +**wall time: 1.09s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [135 more display lines; full output is 7291 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --zoom --zoom-levels=3` + +*The restoring knob: --zoom-levels=N prints N levels (0 = the whole tree); here three, ~11 KB.* + +**wall time: 1.50s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [273 more display lines; full output is 12337 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --report` + +*Architecture summary (modules, god-files, cycles) as markdown.* + +**wall time: 1.33s** + +````` + + +# ripwire architecture report + +3631 files · 31860 symbols · 30033 edges · 3620 modules (14942 call-graph isolated) + +Root: `.` + +Call-graph isolate provenance: 3978 declaration, 2450 header, 3384 source, 5130 document; 0 connected Louvain singletons + +## 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 +- **docs::`--top-k=N`@COMMANDS.md:59:9077 [pack,allow,insert]** — 181 symbols +- **test/ownerhopfix/py/pkg::big_handler_001@broadcast.py:3:72** — 106 symbols +- **src::buf@infra/svector.h:125:8942 [insert,find,push]** — 91 symbols +- **src/infra::fail@os_win32.cpp:63:2553 [open,get,close]** — 89 symbols +- **test::no@estchargecheck.sh:52:4108 [skip,set]** — 63 symbols +- **src::child@ingest_valuerefs.h:656:33874 [emit,resolve,open]** — 62 symbols +- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 55 symbols +- **src::sliceKindIs@slice.h:368:24239 [match,collect,push]** — 48 symbols +- **src/infra::DYNMAP_ASSUME@dynamic_map.hpp:90:4411 [insert,erase,find]** — 44 symbols + +## God files (most depended-on; showing 10 of 230) +- `src/model.h` — 105 dependents +- `src/infra/emit.h` — 87 dependents +- `src/infra/Diagnostics.h` — 65 dependents +- `src/graph.h` — 47 dependents +- `src/serialize.h` — 45 dependents +… [35 more lines, 3998 bytes total] +````` + +## `./build/ripwire . --seams` + +*Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped.* + +**wall time: 1.14s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [60 more display lines; full output is 9244 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --mermaid` + +*Module (directory) dependency graph as a Mermaid diagram.* + +**wall time: 1.14s** + +````` +%% 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
9435"] + n103["src/infra
1301"] + end + subgraph sg1 ["test"] + 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"] + n945["test/rubyschemafix
99"] + n424["test/forbodyfoldfix/py
98"] + n927["test/rubyattrsfix
85"] + n734["test/lib
81"] + end + n74["docs
862"] + n2[".github
628"] + n0["(root)
606"] + subgraph sg5 ["bench"] + n4["bench
545"] + n5["bench/agentloop
331"] + n49["bench/locbench/results/r5_pooling
237"] + n50["bench/locbench/results/r6_expansion
187"] + n59["bench/recalleval
113"] + n43["bench/locbench
107"] + n38["bench/headtohead/r3-headroom-2026-08-03
102"] +… [20 more lines, 1592 bytes total] +````` + +## `./build/ripwire . --owners` + +*Bus-factor: recency-weighted author ownership per file.* + +**wall time: 3.88s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [974 more display lines; full output is 106558 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --dead-code=src` + +*Internal functions with no caller found in the index — a name-based graph reading, not a confidence score. NOTE the filter is a path-COMPONENT match: 'src' matches any .../src/... segment; use ./src to pin the root directory.* + +**wall time: 1.23s** + +````` + + + + +````` + +## `./build/ripwire . --exercises=test/regression.sh` + +*Which symbols a TEST FILE exercises — the reverse direction of --affected.* + +**wall time: 1.12s** + +````` + + + +````` + +## `./build/ripwire . --community=0` + +*Drill into ONE call-graph community by id — the drill= the --communities output itself advertises.* + +**wall time: 1.12s** + +````` + + + +````` + +## `./build/ripwire . --quality-delta` + +*On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox section below.* + +**wall time: 32.37s** + +````` + + +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +````` + +## `./build/ripwire . --quality-delta --show-stale` + +*The same clean verdict with what it folded printed back: every stale acknowledgement as an row and the full header. The regression-free answer above keeps only stale= and stale_by_kind= (and stale_next= names this call), and folds only when that saves a quarter of the bytes. Refused without --quality-delta.* + +**wall time: 28.04s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [140 more display lines; full output is 16170 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +````` + +## `./build/ripwire . --edit-check=rankGraphTeleport` + +*Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree).* + +**wall time: 18.07s** + +````` + + + + + + + + + +````` + +## `./build/ripwire . --pr-context` + +*No-LLM review-evidence bundle for the working-tree diff (clean tree = empty).* + +**wall time: 4.32s** + +````` + + + +````` + +## `./build/ripwire . --pr-context=HEAD~1` + +*The BASEREF form: diffed against merge-base(BASEREF, HEAD), never the ref tip — here the previous commit on the current line (a ref with NO merge base falls back to a disclosed two-dot diff: anchor="ref-tip-two-dot").* + +**wall time: 12.23s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [102 more display lines; full output is 8319 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --merge-scout=HEAD~2,HEAD~1` + +*Pairwise cross-arm conflict sites + suggested landing order (any committish sharing a merge base with HEAD works as an arm; one that does not is reported ok="0", never compared).* + +**wall time: 24.28s** + +````` + + + + + + + + + + + +````` + +## `./build/ripwire . --stray-content=lane/` + +*Which refs of the `lane/` ref family still hold divergent authored work vs HEAD, with verdicts.* + +**wall time: 50.87s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [258 more display lines; full output is 33874 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --stray-content=arm/for-howitworks-067-f2add` + +*A second selection, the one branch `arm/for-howitworks-067-f2add` (no ref family left to select on this checkout), picked at capture time from the refs this checkout really has and never the selection above: merged refs are OMITTED from the rows and counted in merged=; refs sharing no merge base with HEAD (a shallow clone, or a pre-rewrite history) land in unknown= with ok="0" — the counters always reconcile against refs=.* + +**wall time: 11.55s** + +````` + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --stray-content=lane/ --plan` + +*Select the genuinely-unmerged refs of the `lane/` ref family and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root).* + +**wall time: 173.44s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [33524 more display lines; full output is 4640806 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --stray-content=zzzz-no-such-ref --plan` + +*A --plan filter that selects NO ref REFUSES (exit 1) naming the substring — before the wave-3 close this fell through to the '>512 refs match' sentence, and --abi under the same filter answered an empty measurement at exit 0.* + +**exit code: 1** — **wall time: 9.83s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zero here would be a failure, not a measurement + (the filter is a substring match against refs/heads names; run bare --stray-content to list them, e.g. --stray-content=feat/) +````` + +## `./build/ripwire . --stray-content=lane/ --abi` + +*Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all.* + +**exit code: 2** — **wall time: 471.53s** + +````` + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --whereis=rankGraphTeleport` + +*Which ref's tree defines or mentions SYM — HEAD first, then every local branch. The default lists the kind="def" rows (here the first 60, most on branches, each carrying tip= and date=) and counts the references in : on this symbol HEAD's references would fill the 60-row cap before the branch definitions arrive, so the whole list (below) shows fewer definitions, and the default serves the page that shows more of them, whatever its bytes.* + +**wall time: 30.28s** + +````` + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --whereis=rankGraphTeleport --whereis-listing=all` + +*The whole hit list asked for by name: under the same 60-row cap HEAD's references fill the list, so it shows far fewer definitions (here HEAD's one) than the default above (here 60). The default serves the all page only when it shows the same definitions as the defs page in strictly fewer bytes (a tie serves it too).* + +**wall time: 28.18s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [36 more display lines; full output is 13362 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --quality-delta=HEAD~1..HEAD --quality-kinds=complexity,dead-code` + +*A ref range run for two of the twelve kinds only: the named kinds' rows are exactly their rows in the full answer, the header names the others (kinds_skipped=, skipped_why="selector"), and a pass no named kind needs does not run. The replay a memory-stopped range answer hands back (kinds_next=) is this flag. Refused without --quality-delta=A..B.* + +**wall time: 18.23s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [35 more display lines; full output is 14375 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --whereis=computeOnePairOverlap --with-history` + +*Same, plus a git-history row (never / removed-by-commit) for names no tree carries.* + +**wall time: 35.26s** + +````` + + + + + + + +````` + +## `./build/ripwire . --flags` + +*The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gates from comments/heredocs, so the count only reflects real ifndef/define, CMake option(), and getenv gates.* + +**wall time: 4.57s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [409 more display lines; full output is 25048 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --flags --flip=RIPWIRE_ASAN` + +*Blast radius of turning ONE gate on: live code, symbols, transitive reach, covering tests.* + +**wall time: 3.58s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --flags --flip=RIPWIRE_ASA` + +*Unknown-gate refusal (exit 1) with a did-you-mean from a real edit distance (one character off RIPWIRE_ASAN).* + +**exit code: 1** — **wall time: 3.10s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --flip: no gate named 'RIPWIRE_ASA' in . (did you mean 'RIPWIRE_ASAN'?) +ripwire: run `ripwire . --flags` for the gate table +````` + +## `./build/ripwire . --plan-lanes=3 --task="add a --since filter to the doc-drift verb and cover it with tests"` + +*NEW VERB: pre-hoc lane plan — which of 3 parallel worktrees would COLLIDE, before a line is written. JSON on stdout.* + +**wall time: 11.48s** + +````` +{"v":1,"verb":"plan-lanes","at":"0712a5182","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3631,"symbols":31860,"edges":300 … [line truncated: 338 more bytes on this line] +"symbols":[{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","l":286,"id":"./src/docdrift.h::DriftResult::DriftResult"}, +{"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","l":2441,"id":"./src/docdrift.h::docdrift::computeDocDrift"}, +{"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","l":2739,"id":"./src/docdrift.h::docdrift::kDocDriftLegend"}, +{"p":"./src/docdrift.h","n":"writeDocDriftPage","scope":"docdrift","l":2909,"id":"./src/docdrift.h::docdrift::writeDocDriftPage"}, +{"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","l":655,"id":"./src/mcpverbs.h::rw::docDriftText"}, +{"p":"./src/verbs_change.h","n":"runDocDrift","scope":"","l":1678,"id":null}]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb and cover it with tests","claims":{"symbols":[{"p":"./src/verbs_change.h","n":"runAbiCheck","scope":"","key":"183da9aaf74a4a92","id":null,"id_addr … [line truncated: 113 more bytes on this line] +{"p":"./src/editcheck.h","n":"editCheckPriceRoot","scope":"rw","key":"33219bb04158a6a8","id":"./src/editcheck.h::rw::editCheckPriceRoot","id_addressable":true,"id_collides_with":0,"l":1211,"ord":0,"overloads":1,"amb":0,"cx":8,"ccx":10,"churn":61,"tested":0}, +{"p":"./src/docdrift.h","n":"writeGateability","scope":"docdrift","key":"42c456dfb55faee4","id":"./src/docdrift.h::docdrift::writeGateability","id_addressable":true,"id_collides_with":0,"l":2685,"ord":0,"overloads":1,"amb":2,"cx":6,"ccx":6,"churn":36,"tested":0}, +{"p":"./src/darkflags.h","n":"writeFlags","scope":"darkflags","key":"5c2c4a2b311b8dba","id":"./src/darkflags.h::darkflags::writeFlags","id_addressable":true,"id_collides_with":0,"l":1298,"ord":0,"overloads":1,"amb":1,"cx":8,"ccx":8,"churn":32,"tested":0}, +{"p":"./src/docdrift.h","n":"docDriftNextAttr","scope":"docdrift","key":"7723ed789a1c9c09","id":"./src/docdrift.h::docdrift::docDriftNextAttr","id_addressable":true,"id_collides_with":0,"l":2864,"ord":0,"overloads":1,"amb":0,"cx":6,"ccx":5,"churn":36,"tested":0}, +{"p":"./src/docdrift.h","n":"recordWeakDisclosures","scope":"docdrift","key":"972779210e49c0cf","id":"./src/docdrift.h::docdrift::recordWeakDisclosures","id_addressable":true,"id_collides_with":0,"l":2430,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":1,"churn":36,"tested":0}, +{"p":"./src/testmap.h","n":"scriptGatesUnmodelledCount","scope":"rw","key":"98c4487e2e9e08bc","id":"./src/testmap.h::rw::scriptGatesUnmodelledCount","id_addressable":true,"id_collides_with":0,"l":1793,"ord":0,"overloads":1,"amb":0,"cx":4,"ccx":4,"churn":61,"tested":0}, +{"p":"./src/main.cpp","n":"scanReportVerbPrecedence","scope":"","key":"9ab981e987e8108e","id":null,"id_addressable":false,"id_collides_with":0,"l":3031,"ord":0,"overloads":1,"amb":0,"cx":8,"ccx":11,"churn":453,"tested":0}, +{"p":"./src/pageview.h","n":"secondaryCutAttrs","scope":"rw","key":"a10ea8d3bdca1dfb","id":"./src/pageview.h::rw::secondaryCutAttrs","id_addressable":true,"id_collides_with":0,"l":399,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":28,"tested":0}, +{"p":"./src/main.cpp","n":"emitNoteAddUnprovenDefs","scope":"","key":"a950332ccfce6b8d","id":null,"id_addressable":false,"id_collides_with":0,"l":691,"ord":0,"overloads":1,"amb":1,"cx":2,"ccx":1,"churn":453,"tested":0}, +{"p":"./src/docdrift.h","n":"sortDocsByLiveDrift","scope":"docdrift","key":"d5de682411b9a9a9","id":"./src/docdrift.h::docdrift::sortDocsByLiveDrift","id_addressable":true,"id_collides_with":0,"l":2390,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":2,"churn":36,"tested":0}, +{"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5840,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":466,"tested":0}], +"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":56}, +{"p":"./src/docdrift.h","symbols":4,"churn":36,"ccx":14,"hotspot_rank":38}, +{"p":"./src/editcheck.h","symbols":1,"churn":61,"ccx":10,"hotspot_rank":41}, +{"p":"./src/main.cpp","symbols":2,"churn":453,"ccx":12,"hotspot_rank":5}, +{"p":"./src/mcpverbs.h","symbols":1,"churn":466,"ccx":2,"hotspot_rank":4}, +{"p":"./src/pageview.h","symbols":1,"churn":28,"ccx":2,"hotspot_rank":129}, +{"p":"./src/testmap.h","symbols":1,"churn":61,"ccx":4,"hotspot_rank":33}, +{"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":9,"hotspot_rank":25}]},"blast_radius":{"reaches":47,"files_total":16,"capped":false,"files":["./src/darkflags.h","./src/docdrift.h","./src/editcheck.h","./src/editplan.h","./src/editpreview.h","./src/flipimpact.h","./src/main.cpp","./src/mcp.h … [line truncated: 182 more bytes on this line] +"tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":47,"module_span":1,"notes":[], +"execution":{"policy":"codex-lane/v1","model":"gpt-5.6-terra","reasoning":"high","rule":"moderate-cross-module","basis":"structural-only","signals":{"claims":12,"files":8,"module_span":1,"max_ccx":11,"sum_ccx":61,"ambiguous_calls":6,"blast_reaches":47,"contract_touches":0,"conflicts":0,"untested":47 … [line truncated: 142 more bytes on this line] +{"id":"lane-1","task":"add a --since filter to the doc-drift verb and cover it with tests","claims":{"symbols":[{"p":"./src/gitmine.h","n":"gitWindowBoundarySha","scope":"rw","key":"18627516699d7062","id":"./src/gitmine.h::rw::gitWindowBoundarySha","id_addressable":true,"id_collides_with":0,"l":1674 … [line truncated: 69 more bytes on this line] +{"p":"./src/cli.h","n":"kViewFlags","scope":"rw","key":"2a2f2487082cc6d8","id":"./src/cli.h::rw::kViewFlags","id_addressable":true,"id_collides_with":0,"l":3327,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +… [69 more display lines; full output is 20481 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --plan-lanes --brief=/aux/lanes_brief.txt` + +*NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode).* + +**wall time: 13.97s** + +Input file: + +````` +add a --since filter to the doc-drift verb +add the CLI parse arm and help text for the new filter +write regression tests for the new filter +````` + +````` +{"v":1,"verb":"plan-lanes","at":"0712a5182","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3631,"symbols":31860,"edges":30033,"ambiguous":2933,"unresolved":15249},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] +"symbols":[]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb","claims":{"symbols":[{"p":"./src/docdrift.h","n":"recordUnchecked","scope":"docdrift","key":"12641dab14abc8fd","id":"./src/docdrift.h::docdrift::recordUnchecked","id_addressable":true,"id_collides_with":0,"l":2 … [line truncated: 72 more bytes on this line] +{"p":"./src/docdrift.h","n":"sortWeakGroupsByPath","scope":"docdrift","key":"1944ba506280ff80","id":"./src/docdrift.h::docdrift::sortWeakGroupsByPath","id_addressable":true,"id_collides_with":0,"l":2401,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":36,"tested":0}, +{"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","key":"1fa68e8d93c05a59","id":"./src/mcpverbs.h::rw::docDriftText","id_addressable":true,"id_collides_with":0,"l":655,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":466,"tested":0}, +{"p":"./src/cli.h","n":"kViewFlags","scope":"rw","key":"2a2f2487082cc6d8","id":"./src/cli.h::rw::kViewFlags","id_addressable":true,"id_collides_with":0,"l":3327,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +{"p":"./src/recall.h","n":"docFileMask","scope":"rw","key":"3149a219f599664c","id":"./src/recall.h::rw::docFileMask","id_addressable":true,"id_collides_with":0,"l":110,"ord":0,"overloads":1,"amb":0,"cx":4,"ccx":4,"churn":27,"tested":0}, +{"p":"./src/docdrift.h","n":"writeDocDriftPage","scope":"docdrift","key":"380b7de5df1cfd73","id":"./src/docdrift.h::docdrift::writeDocDriftPage","id_addressable":true,"id_collides_with":0,"l":2909,"ord":0,"overloads":1,"amb":10,"cx":14,"ccx":15,"churn":36,"tested":0}, +{"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","key":"3b19cc3d8996c3b2","id":"./src/docdrift.h::docdrift::computeDocDrift","id_addressable":true,"id_collides_with":0,"l":2441,"ord":0,"overloads":1,"amb":1,"cx":26,"ccx":38,"churn":36,"tested":0}, +{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","key":"422ab39546b6e0bd","id":"./src/docdrift.h::DriftResult::DriftResult","id_addressable":true,"id_collides_with":0,"l":286,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":36,"tested":0}, +{"p":"./src/verbs_change.h","n":"runDocDrift","scope":"","key":"904831e5c0f66b39","id":null,"id_addressable":false,"id_collides_with":0,"l":1678,"ord":0,"overloads":1,"amb":1,"cx":5,"ccx":4,"churn":82,"tested":0}, +{"p":"./src/ensemble.h","n":"kEnsembleChurnSince","scope":"ensemble","key":"a34fc78c05bf56a8","id":"./src/ensemble.h::ensemble::kEnsembleChurnSince","id_addressable":true,"id_collides_with":0,"l":120,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":23,"tested":0}, +{"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5840,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":466,"tested":0}, +{"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","key":"ff2ba74637bbbebf","id":"./src/docdrift.h::docdrift::kDocDriftLegend","id_addressable":true,"id_collides_with":0,"l":2739,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":36,"tested":0}], +"files":[{"p":"./src/cli.h","symbols":1,"churn":511,"ccx":0,"hotspot_rank":6}, +{"p":"./src/docdrift.h","symbols":6,"churn":36,"ccx":54,"hotspot_rank":38}, +{"p":"./src/ensemble.h","symbols":1,"churn":23,"ccx":0,"hotspot_rank":105}, +{"p":"./src/mcpverbs.h","symbols":2,"churn":466,"ccx":2,"hotspot_rank":4}, +{"p":"./src/recall.h","symbols":1,"churn":27,"ccx":4,"hotspot_rank":64}, +{"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":4,"hotspot_rank":25}], +"symbols_total":3466,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], +"tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":13,"module_span":6,"notes":[], +"execution":{"policy":"codex-lane/v1","model":"gpt-5.6-sol","reasoning":"xhigh","rule":"wide-contract-work","basis":"structural-only","signals":{"claims":12,"files":6,"module_span":6,"max_ccx":38,"sum_ccx":64,"ambiguous_calls":12,"blast_reaches":13,"contract_touches":1,"conflicts":0,"untested":13,"t … [line truncated: 139 more bytes on this line] +{"id":"lane-1","task":"add the CLI parse arm and help text for the new filter","claims":{"symbols":[{"p":"./scripts/optremarks.py","n":"main","scope":"","key":"01b3b880f77d1512","id":null,"id_addressable":false,"id_collides_with":134,"l":279,"ord":0,"overloads":1,"amb":0,"cx":23,"ccx":31,"churn":14, … [line truncated: 12 more bytes on this line] +{"p":"./src/cli.h","n":"HelpLine","scope":"rw","key":"1489844dbc310b82","id":"./src/cli.h::rw::HelpLine","id_addressable":true,"id_collides_with":0,"l":2948,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +{"p":"./src/cli.h","n":"HelpFilter","scope":"HelpFilter","key":"3103a5e8bfc33d38","id":"./src/cli.h::HelpFilter::HelpFilter","id_addressable":true,"id_collides_with":0,"l":3027,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, +{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":134,"l":885,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":18,"tested":0}, +{"p":"./src/mcprefusal.h","n":"kMcpValueFields","scope":"rw::mcprefuse","key":"4a7106e488a2aa80","id":"./src/mcprefusal.h::rw::mcprefuse::kMcpValueFields","id_addressable":true,"id_collides_with":0,"l":304,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":49,"tested":0}, +{"p":"./src/cli.h","n":"serveHelpSelector","scope":"rw","key":"4b247ee064fc4e94","id":"./src/cli.h::rw::serveHelpSelector","id_addressable":true,"id_collides_with":0,"l":3092,"ord":0,"overloads":1,"amb":1,"cx":4,"ccx":3,"churn":511,"tested":0}, +{"p":"./src/query.h","n":"tryParsePredicateOnAll","scope":"query","key":"786acc4dbfec612b","id":"./src/query.h::query::tryParsePredicateOnAll","id_addressable":false,"id_collides_with":1,"l":113,"ord":0,"overloads":2,"amb":0,"cx":1,"ccx":0,"churn":20,"tested":0}, +{"p":"./src/cli.h","n":"printUsageTier","scope":"rw","key":"82b7af67acdca479","id":"./src/cli.h::rw::printUsageTier","id_addressable":true,"id_collides_with":0,"l":3078,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":1,"churn":511,"tested":0}, +… [60 more display lines; full output is 18606 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --plan-lanes=99 --task=x` + +*Out-of-range refusal shape for the lane count.* + +**exit code: 1** — **wall time: 2.48s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out) +````` + +## `./build/ripwire . --layout=Symbol` + +*CPU/GPU contract view of one struct: computed offsets/sizes/padding + mirror check.* + +**wall time: 1.70s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --layout=Lang` + +*The honest refusal (exit 1): Lang is an `enum class`, not a struct — no offsets are fabricated.* + +**exit code: 1** — **wall time: 1.70s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped enum's underlying type is not a byte layout) +````` + +## `./build/ripwire . --doc-drift` + +*Which of this repo's doc claims are now false. CHANGED: row attribute at= renamed to tgt= (at= is now only the root sha stamp).* + +**wall time: 5.52s** + +````` + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +… [228 more display lines; full output is 23860 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --doc-drift --gateability` + +*The finishable to-do list: docs whose LIVE failing anchors a date-stamp would reclassify.* + +**wall time: 4.54s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [255 more display lines; full output is 25115 bytes on 1 raw line(s)] +````` + +Tail of the same output — the `` section: + +````` + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --doc-drift --with-history` + +*Same report, with git history splitting stale mentions into deleted-by-commit vs never-existed.* + +**wall time: 8.96s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [208 more display lines; full output is 23839 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --from-trace=-` + +*Map a pasted stack trace onto indexed symbols. CHANGED: in_corpus= now reports the real count (was 0).* + +**wall time: 2.44s** + +Input file: + +````` +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: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) +==41337==ABORTING +````` + +````` + + + + + + + + + + + +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] + +uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f ) +int runDefaultMap( const MainDispatch& d ) +int main( int argc, char** argv ) + + + +& p, float alpha = 0.85f ) +{ + PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); + const std::vector pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + double teleportMass = 0.0; +… [18 more display lines; full output is 4915 bytes on 29 raw line(s)] +````` + +## `./build/ripwire . --notes` + +*List all field notes (write-side memory) — the committed .ripwire_notes at the repo root, each with the sha/branch it was recorded at.* + +**wall time: 1.51s** + +````` + + + + + + + + + + + gate scripts' claim (~line 1305) is NOT enforced — the derived-vs-stated sibling loop here covers docs/EVALS.md only. It drifted 407→451 unnoticed (fixed 2026-08-23). To close: grep both files ('file:line:' parsing) in the gateCountClaims arm.]]> + + + + +````` + +## `./build/ripwire . --pack-task="add a new output format flag to the CLI"` + +*ONE budget-shared bundle: ranking + top bodies + caller sigs + notes + tests_to_run. CHANGED: rows now carry n=/id=.* + +**wall time: 2.60s** + +````` + + + + +Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept + +claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of its newlineinline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) + +ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION does not vary by agent — only the MCP alternative does. Before this there were four near-identical CLI-fiinline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, c … [line truncated: 83 more bytes on this line] + +mcp-tools pass-through. Written into the server command only where its argument shape is known to be one more plain argument: the JSON args arrays (cursor/windsurf/gemini), opencode's command arrayinline bool wrapWritesToolsArg( const AgentTarget& row ) noexcept + +L8 (train 29): the NEXT PAGE of a callers listing — the CLI --callers root's next=, find_referencing_symbols' next and find_symbol's calledBy_next all name this one call, so the three cannot spell tinline std::string callHierarchyPageNext( bool wantCallers, std::string_vi … [line truncated: 98 more bytes on this line] +inline std::string classNewGroupXml( const IngestResult& ing, std::span<const ClassNewRow> rows, std::string_view rootPrefix, EscapeFn ex ) + + + + + + + + + +… [67 more display lines; full output is 12092 bytes on 59 raw line(s)] +````` + +## `./build/ripwire . --pack-task="add a new output format flag to the CLI" --partition=3` + +*Fan-out form: one shared core + 3 per-agent slices carved along call-graph communities.* + +**wall time: 2.22s** + +````` + wraps a ; bundle role=core|partition i= symbols= modules= bytes= tokens=: one agent's ctx, symbols= ids assigned, bytes= its size; tokens= = est_tokens= = bytes/2.36 (flat, the densest rate; the inner ctx est_tokens= is language-weighted). Inner ctx task= root= budget_tokens= dropped_positive=: the task, p= base, the slice's token target, ranked candidates its budget cut. of_top=: rows ranked (far) / bodies (callers); s rel=caller|callee shared=: 1-hop edge, bodies reached (absent at 1). window: shown= total= capped= (capped=1 cut). run_unknown=1: no runner derivable (a guess would be worse). est_tokens=: price as emitted (an upper bound under compact). : rank N in this ranking, rows in r= order. : cyclomatic/cognitive complexity. : N callers in the index (absent: not measured). route=: the ranker: name-exact(X) = the task names symbol X (anchors: its evidence), subtoken+body = conceptual BM25 (:broad = 1-2 plain words, plain rg may also win; :declined(...) = a name hit refused as a common name). sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. next=: the one pasteable follow-up. pure=1: const/constexpr signature (Swift: non-mutating) and no transitive side effect found; a hint. partitions=/requested=: partitions carved / asked for. modules=/split=: call-graph groups found / cuts forced to split one. core_symbols=/surface=: ids in the shared core / core plus the assignable remainder. budget_per_agent_tokens=: one agent's budget, core_budget_tokens= plus partition_budget_tokens=. total_bytes=N: bytes of all bundles together. overlap_mean=/overlap_max=: pairwise Jaccard over the ids partitions name, before trimming. shared_symbols=/union_symbols=: ids two or more partitions name / ids any partition names. core_overlap=: share of the core surface a partition reaches anyway. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. --> + + + + + +Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept + +claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of…inline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) + +ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION doe…inline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, const std::string_view executablePath, const WrapListing& listing ) noexcept + +mcp-tools pass-through. Written into the server command only where its argument shape is known t…inline bool wrapWritesToolsArg( const AgentTarget& row ) noexcept + + + + + +inline bool printUsageTier( std::FILE* out, HelpTier tier, std::string_view want ) noexcept + + + + + + + + +NodeId order. Renumbering an otherwise-identical graph (the exact "same probe file, different so…inline constexpr float kScoreTieAbsEps = 1e-6f + +Render one form of the disclosure. Empty string whenever there is nothing to say — no power it…inline std::string renderDisclosure( const RankDisclosure& d, DiscloseAs as ) + +The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] +inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) +struct RankedGraph +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… +inline std::uint32_t sliceRdIterationCeiling() noexcept +struct PageRankRun + +What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window +inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept +inline std::string powerShellSingleQuote( std::string_view s ) noexcept +inline std::string path_prepend_hint( std::string_view dir ) +HOT_FILES = ( "src/pagerank.cpp", # the power-iteration loop — G2's no-allocation scope "src/infra/radixSort.h", # LSD radix entry points "src/infra/radixSort.inl", # the counting … [line truncated: 76 more bytes on this line] +handle_t leftmost_leaf() const +inline void discloseUniformChurnFallback( bool hasChurnEvidence, bool stubbed, const char* verbLabel, const std::string& windowStamp ) +inline std::string doctorPathPrependLine( const std::string& selfPath ) +inline std::string doctorWhichRipwire( rw::os::stat_t& st ) +std::uint32_t testIterationCeiling() noexcept +inline const char* rankByLegendFor( const char* label ) noexcept +… [124 more display lines; full output is 19081 bytes on 10 raw line(s)] +````` + +## `./build/ripwire . --export=cc.json:/aux/ripwire2.cc.json` + +*Per-file metrics as CodeCharta cc.json.* + +**wall time: 6.36s** + +````` +(empty) +````` + +Artifact written: + +````` + 563192 /aux/ripwire2.cc.json +{"projectName":"project","apiVersion":"1.3","attributeDescriptors":{"loc":{"title":"Lines of Code","description":"Physical line count","direction":-1},"symbols":{"title":"Symbols","description":"Definitions in the file","direction":-1},"cx":{"title":"Cyclomatic Complexity","description":"Sum of per-symbol cyclomatic complexity","direction":-1},"cognitive_cx":{"title":"Cognitive Complexity","descri +````` + +## `./build/ripwire . --batch=/aux/batch2.txt` + +*One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped .* + +**wall time: 11.27s** + +Input file: + +````` +for:incremental cache invalidation +callers:rankGraphTeleport +grep:DISCLOSE +lego:Vehicle +````` + +````` + + + + + + + + + +incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…constexpr std::uint32_t kCacheMagic = 0x4b505443 + +Composed exactly the way every OTHER blob family is (quality.h): one fixed-width identity hex pe…inline std::string spanTierMemoPath( const std::string& diskPath ) + +Ingest the tree at `sha`, materialized out of `root`'s object store. The HEAD side reuses the SA…inline bool ingestCommitTree( const std::string& root, const std::string& sha, const std::vector<std::string>& excludes, std::size_t maxFileBytes, IngestResult&… … [line truncated: 4 more bytes on this line] + +P1-15 — the `_reingest` envelope field for a response whose handling ran an INCREMENTAL pass, …inline bool mcpRefreshedThisRequest( std::uint64_t passesAtEntry ) +struct FileHealth +inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::ve … [line truncated: 8 more bytes on this line] +inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… +inline RawFacts runParsePool( IngestResult& result, const char* rootDir, std::string_view cacheFile, bool captureValueUses, HashMap<std::string, FileFacts>& cache, const CacheLoadStats& cac … [line truncated: 66 more bytes on this line] +inline McpRebuildBaseline mcpRebuildBaseline( const McpIndex& ix, bool isIncrementalPass ) +inline const McpIndex& getIndex( const std::string& root ) +inline std::string mcpFreshFields( std::uint64_t passesAtEntry ) +struct McpIndex +inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) +IngestResult ingest( const char* rootDir, const std::vector<std::string>& excludeSubstr, std::string_view cacheFile, std::size_t maxFileBytes, bool captureValueUses, std::string_view excludeLabel, bool … [line truncated: 37 more bytes on this line] +const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) +static bool cachePathIsDirectory( const std::string& cachePath ) +inline std::string oracleCachePath( const std::string& root, const std::string& headSha ) +HashMap<const TSLanguage*, TSQuery*>& compiledQueryCache() +… [107 more display lines; full output is 51554 bytes on 1 raw line(s)] +````` + + +--- + +# self-diagnosis + +## `./build/ripwire . --doctor` + +*Environment self-check: binary staleness, grammars, cache dir, git, tracked-binary staleness — exit 1 when any check fails (here: the PATH install is older than ./build).* + +**exit code: 1** — **wall time: 54.51s** + +````` + + + + + + + + + + +````` + + +--- + +# security + +## `./build/ripwire --scan-skill=skills/ripwire-orient/SKILL.md` + +*Scan a single skill file for injection/exfiltration patterns before installing.* + +````` + + + +````` + +stderr: + +````` +ripwire scan: 0 finding(s) in skills/ripwire-orient/SKILL.md +````` + +## `./build/ripwire --scan-skills=skills` + +*Scan a whole skills directory (exit 2 = CRITICAL, 1 = WARN). Explicit-DIR form only.* + +````` + + + +````` + +stderr: + +````` +ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s) skipped, 0 denylisted subtree(s) not descended) +````` + + +--- + +# knobs / modes + +## `./build/ripwire . --rank-by=churn --top-k=5` + +*Rank by git change-frequency prior instead of PageRank.* + +**wall time: 11.58s** + +````` + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --rank-by=churn-decay --since=HEAD~2 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3` + +*Scope the recent-changes answer to ONE directory. 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.* + +**wall time: 14.03s** + +````` + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --rank-by=bogus --top-k=5` + +*An unknown value REFUSES (exit 1), NAMED, with the supported set listed.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf|churn|churn-decay) +````` + +## `./build/ripwire . --callers=rankGraphTeleport --format=columnar` + +*Columnar output: paths table + parallel arrays, ~15-60% fewer tokens on MANY-row lists — small results can be LARGER (the columnar legend is a fixed cost).* + +**wall time: 3.49s** + +````` + + +0=src/mcpindex.h 1=src/graph.h 2=src/eval.h 3=src/main.cpp + +0,1,1,2,3,3,3 +getIndex,rankGraph,anchoredLexicalRank,runEval,churnDecayRanking,churnRankedGraph,runDefaultMap +1184,11850,12496,171,1425,1464,1751 +fn,fn,fn,fn,fn,fn,fn +0,0,0,0,0,0,0 +src/mcpindex.h:1288,src/graph.h:11853,src/graph.h:12547,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 + + +````` + +## `./build/ripwire . --for="cache invalidation" --format=candidates --top-k=5` + +*Flat top-K export for an external reranker.* + +**wall time: 7.77s** + +````` + + + +inline std::string spanTierMemoPath( const std::string& diskPath ) + + +inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::vector<NodeId>& surfaceIds ) + + +### See the map — not just the numbers + + +inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) + + +const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) + + +````` + +## `./build/ripwire . --callers=rankGraphTeleport --format=bogus` + +*An unknown --format value REFUSES (exit 1), named, with the supported set listed.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --format: unknown value 'bogus' (supported: xml|columnar|rows|candidates) +````` + +## `./build/ripwire . --callers=rankGraphTeleport --json` + +*Machine-parseable JSON, same content, keys mirror the XML attrs.* + +**wall time: 11.87s** + +````` +{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, +{"t":"fn","n":"rankGraph","p":"src/graph.h:11850","sites_at":["src/graph.h:11853"]}, +{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12496","sites_at":["src/graph.h:12547"]}, +{"t":"fn","n":"runEval","p":"src/eval.h:171","sites_at":["src/eval.h:328"]}, +{"t":"fn","n":"churnDecayRanking","p":"src/main.cpp:1425","sites_at":["src/main.cpp:1439"]}, +{"t":"fn","n":"churnRankedGraph","p":"src/main.cpp:1464","sites_at":["src/main.cpp:1478","src/main.cpp:1479","src/main.cpp:1493"]}, +{"t":"fn","n":"runDefaultMap","p":"src/main.cpp:1751","sites_at":["src/main.cpp:1871"]}]} +````` + +## `./build/ripwire . --hotspots --json` + +*JSON refusal shape: an unsupported verb refuses loudly instead of silently falling back to XML.* + +**exit code: 1** — **wall time: 1.75s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --json is not yet supported for --hotspots — supported: the default map, --for, --pack-task, --callers/--callees, --impact, --quality-delta, --test-gate, --metrics, and --plan-lanes which is JSON-native (e.g. ripwire

--callers=SYM --json) +````` + +## `./build/ripwire . --hotspots --limit=3 --offset=3` + +*Pagination: 3 items, skipping the first 3 (deterministic seams).* + +**wall time: 22.35s** + +````` + + + + + + + +````` + +## `./build/ripwire . --ignore-tests --top-k=5` + +*Drop test paths from the corpus before ranking.* + +**wall time: 3.47s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [67 more display lines; full output is 8139 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --exclude=present --exclude=bench --top-k=5` + +*Drop matching paths (repeatable) before ranking.* + +**wall time: 3.53s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [65 more display lines; full output is 8119 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --map-diff --top-k=5` + +*Full map re-ranked with teleport toward git-changed files — clean tree, so changed=0 and it degrades to the plain map.* + +**wall time: 6.65s** + +````` + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --no-cache --top-k=3` + +*Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm cost.* + +**wall time: 6.36s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8141 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --cache=/aux/warm2.ripwirecache --top-k=3` + +*Explicit incremental cache at a path OUTSIDE the repo (first call writes it).* + +**wall time: 6.22s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8141 bytes on 1 raw line(s)] +````` + +Artifact written: + +````` + 28779725 /aux/warm2.ripwirecache +````` + +## `./build/ripwire . --max-file-size=8K --top-k=3` + +*Skip files above a size bound before parsing (note the corpus shrink in the header).* + +**wall time: 2.86s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [18 more display lines; full output is 4246 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --scip=does_not_exist.scip --callers=rankGraphTeleport` + +*SCIP overlay with a missing index REFUSES (exit 1) naming the file — never silently serves the name-based map you named a precision index to improve on (it used to degrade in silence).* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather than serving the name-based map you named a precision index to improve on (generate one with scip-clang/scip-python, or drop --scip) +````` + +## `./build/ripwire src test --top-k=5` + +*Multi-root workspace: ONE merged graph over two roots, paths labeled /.* + +**wall time: 5.09s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + +````` + +stderr: + +````` +ripwire: cache : over its 2048 MiB budget — evicted 31 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) +````` + +## `./build/ripwire . --eval` + +*Self-eval: co-change recall vs BM25.* + +**wall time: 20.52s** + +````` +ripwire --eval (co-change recovery, averaged over 80 historical commits) + ranker recall@5 recall@10 recall@20 + ripwire 7.0% 7.5% 13.5% + BM25 15.4% 16.9% 19.0% + BM25sub 17.4% 25.2% 29.4% + BM25body 19.5% 25.7% 36.0% + fused 12.9% 16.3% 26.6% + anchored 19.7% 26.0% 36.5% + same-dir 2.8% 6.1% 11.4% + random 0.1% 0.3% 0.6% <- floor (random ranking over F=3631 files) + note: `ripwire` here is the DEFAULT MAP's structural-only PageRank (importance, not + relatedness) — it is NOT what a --for/--query retrieval call ranks with. BM25 / + BM25sub / BM25body are QUERY-TIME lexical rankers (whole-name / subtoken / + subtoken+body); fused = RRF(ripwire, BM25sub); anchored = BM25body + anchored PPR + expansion (--for --anchor, EXPERIMENTAL). The SHIPPED default for --for/--query is + the subtoken+body lexical family (routed to name-exact only for an identifier-shaped + query — lexical.h chooseForRanker), so a gap between the ripwire and BM25* rows here + is structural-importance-vs-lexical-relatedness on a co-change task, not the shipped + retrieval path losing to an alternative it was never running. +````` + +## `./build/ripwire . --eval-retrieval` + +*Known-item retrieval eval: MRR + recall@k per ranker per query mode.* + +**wall time: 154.38s** + +````` +ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-corpus by construction) + sample: population=8003 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population + (smallest fnv1a64(scope::name) over the population, cut on the key so an identity is never split; + path- and order-independent, but a corpus this size is NOT graded exhaustively — say so when citing it) + ingest: lex=rich (persisted subtoken stats; no per-query corpus re-tokenize) + ranker query-mode MRR recall@1 recall@5 recall@10 + subtoken name 0.680 54.5% 84.8% 90.0% + subtoken doc-phrase 0.904 88.3% 92.3% 93.5% + name-exact name 0.898 82.2% 95.9% 97.4% + name-exact doc-phrase 0.013 0.5% 1.8% 2.6% + anchored name 0.687 56.2% 84.1% 88.7% + anchored doc-phrase 0.900 87.6% 92.3% 93.0% + routed name 0.900 82.4% 96.0% 97.6% + routed doc-phrase 0.902 88.3% 92.1% 93.3% + note: routing chose name-exact on 3989/4000 NAME queries (a NAME query is always identifier-shaped); + the confidence gate routes doc-phrase queries to name-exact ONLY when EVERY content word names a symbol + (or an explicit camel/snake token appears) AND every matched name is specific enough to anchor on — + a common name (many definitions, or a subtoken carried by many symbol names) declines the route — so + conceptual prose falls back to subtoken+body; routed tracks the better ranker on BOTH modes + (routed==name-exact on name, ~=subtoken+body on doc-phrase). +````` + +## `./build/ripwire . --eval-stray=/aux/stray_labels2.tsv` + +*Labelled verdict-accuracy eval for --stray-content — three labels over REAL local refs (names resolved at capture time); exit 3 when accuracy is under the floor. Read got= against v= in the stray-content run: a ref the verb could not analyse (unknown) must never be credited as a merged hit.* + +**exit code: 3** — **wall time: 81.90s** + +Input file: + +````` +# refverdict labels for --eval-stray (the first three local branches, resolved at capture time; a missing branch is padded with a nonexistent name on purpose) +arm/for-howitworks-067-f2add merged +arm/for-howitworks-067-placebo unmerged +arm/orient-map-067-narrow merged +````` + +````` + + + + + + +````` + +## `./build/ripwire skills --eval-skills=/aux/skills_labels2.tsv` + +*Labelled skill-ROUTING eval over the repo's own skills/ directory (4 hand-labelled prompts).* + +**wall time: 1.11s** + +Input file: + +````` +orient in an unfamiliar codebase fast ripwire-orient judged +who calls this function and what is the blast radius ripwire-navigate judged +plan parallel worktrees so the lanes do not collide ripwire-change-check judged +what is the weather in Paris none neg +````` + +````` +ripwire --eval-skills (skill routing over K=16 candidate skills [ripwire-router excluded]; 3 positive + 1 negative prompts; corpus '/aux/skills_labels2.tsv'; split test=4 dev=0) + arm hit@1 hit@2 mrr sep-auc fire/abstain@ORACLE-th (upper bound) + overlap 66.7% 66.7% 0.689 0.000 50.0% (th=-1.000) + name 33.3% 66.7% 0.537 0.667 50.0% (th=0.000) + bm25-desc 66.7% 66.7% 0.689 0.667 75.0% (th=2.865) + bm25-full 33.3% 66.7% 0.611 1.000 50.0% (th=0.426) + for-routed 33.3% 33.3% 0.556 1.000 50.0% (th=0.663) + random 6.2% 12.5% 0.211 0.500 <- floor (uniform-random ranking; auc 0.5 by definition) + provenance hit@1 (bm25-desc): router 0/0, desc 0/0, judged 2/3 (desc rows quote the descriptions - expect them easiest; judged is the honest number) + judged-only hit@1 per arm: overlap 2/3, name 1/3, bm25-desc 2/3, bm25-full 1/3, for-routed 1/3 + router-magnet: with ripwire-router ADMITTED as a candidate it takes top-1 on 1/3 positive prompts (bm25-desc arm) - why it is excluded above + per-skill (bm25-desc): name / permitted-rows / won / pos-fires / false-fires / neg-fires + ripwire-before-you-build 0 0 1 1 0 + ripwire-change-check 1 0 0 0 0 + ripwire-find-bug 0 0 0 0 0 + ripwire-fresh-eyes 0 0 0 0 1 + ripwire-graph-query 0 0 0 0 0 + ripwire-handoff 0 0 0 0 0 + ripwire-layers 0 0 0 0 0 + ripwire-mcp 0 0 0 0 0 + ripwire-navigate 1 1 1 0 0 + ripwire-opt-remarks 0 0 0 0 0 + ripwire-orient 1 1 1 0 0 + ripwire-perf-target 0 0 0 0 0 + ripwire-quality-bar 0 0 0 0 0 + ripwire-reuse-first 0 0 0 0 0 + ripwire-security-scan 0 0 0 0 0 + ripwire-write-tests 0 0 0 0 0 + misses (overlap): + line 3 want=ripwire-change-check got=ripwire-before-you-build "plan parallel worktrees so the lanes do not collide" +… [19 more lines, 3665 bytes total] +````` + +## `./build/ripwire wrap claude` + +*Print the recipe to wire ripwire into Claude Code as an MCP server.* + +````` +# ripwire -> Claude Code (CLI-first) +# RECOMMENDED — this agent can run shell commands, so call the CLI directly. It costs +# nothing until you invoke it, and it reads CLAUDE.md, so the paste block below IS the wiring: +ripwire . --for="" +# +# ...every follow-up call answers with the compact legend by default (terse definitions of only the +# attributes the answer carries; the payload is byte-identical either way). Add --legend=full when a +# definition's reasoning is needed -- `ripwire --help` carries the measured saving (one place, +# gate-held) -- this line does not repeat it, because two copies of a number is one that goes stale: +# ripwire . --callers=SYM --legend=full +# +# ALTERNATIVE — register the MCP server instead, for a warm index across calls: +claude mcp add ripwire -- ripwire --mcp +# verbs the agent can then call mid-task (33 total): +# read: analyze, rank_by, find_symbol, find_referencing_symbols, grep, cochange, memory_recall, situational_awareness, mentions, for, lego, owners, fetch_body, batch, flags, doc_drift, slice +# flagship reflex: exemplar, quality_delta, quality_baseline, impact, uses, affected, path_between, connect, explore, from_trace, edit_check, whereis, stray_content +# edit: replace_symbol_body, insert_before_symbol, insert_after_symbol +bash skills/install.sh # deploy to ${CLAUDE_CONFIG_DIR:-~/.claude}/skills (drift-gated) +bash skills/install.sh --hook # RECOMMENDED: advisory Read/Grep -> ripwire CLI nudge + session primer (opt-in, never blocks) +# +# context wiring — a binary on PATH is invisible to an agent until its rules file says when +# to reach for it. Paste the block below into CLAUDE.md: +# --- paste into CLAUDE.md --- +## ripwire — deterministic codebase maps (on PATH as `ripwire`) +Reach for it BEFORE blind grep + whole-file reads. First call ~1s cold; after that warm, ~0.1s. +- Orient on a task: `ripwire --for=""` — ranked, quality-annotated + signatures. Paste symbol/file names from the issue verbatim; named mentions get anchored. +- One task: `--pack-task="" --legend=compact`; before parallel agents: `--plan-lanes=N --task=""`, then read `lanes[].execution`. +- Have a stack trace / build error: `ripwire --from-trace=FILE --legend=compact` (`-` = stdin) — + paste the error, don't paraphrase it into a query. +… [14 more lines, 4058 bytes total] +````` + +## `./build/ripwire --version` + +*Version + short build info.* + +````` +ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=0712a5182) +````` + + +--- + +# navigate — seeds, claims, slices, shapes + +## `./build/ripwire . --at=src/graph.h:11811` + +*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 . --callers=@src/graph.h:11811` + +*The same seed in a SELECTOR position: @FILE:LINE resolves to the innermost enclosing definition, then --callers runs on it.* + +**wall time: 1.43s** + +````` + + + + + + + + + + +````` + +## `./build/ripwire . --at=src/graph.h:999999` + +*A seed past the end of the file — the refusal shape for a faulted location.* + +**exit code: 1** — **wall time: 1.33s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16280 lines — the seed asked for line 999999) +````` + +## `./build/ripwire . --verify="calls(runDefaultMap, rankGraphTeleport)"` + +*VERIFY a closed claim in one call: three-valued verdict (confirmed / refuted / not-established) with the evidence rows inline.* + +**wall time: 3.39s** + +````` + + + + + +````` + +## `./build/ripwire . --verify="unused(rankGraphTeleport)"` + +*A claim that is FALSE — the refuted shape, with the references that refute it.* + +**wall time: 2.24s** + +````` + + + + + + + + + + + + +````` + +## `./build/ripwire . --verify="contains(src/graph.h, \"no such literal anywhere\")"` + +*A literal-scan absence: refuted only with complete= evidence, never on a partial scan.* + +**wall time: 2.05s** + +````` + + + +````` + +## `./build/ripwire . --verify="frobnicate(x)"` + +*An unparseable claim — the refusal names the accepted shapes.* + +**exit code: 1** — **wall time: 1.51s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. The claim language is CLOSED; the shapes are: calls(A, B) does A transitively call B · uses(SYM) is SYM referenced anywhere · unused(SYM) is SYM referenced nowhere · contains(FILE, "LITERAL") do FILE's bytes contain t … [line truncated: 218 more bytes on this line] +````` + +## `./build/ripwire . --slice=rankGraphTeleport` + +*Bare --slice=SYM: the INVENTORY of sliceable locals (), so a caller can pick VAR.* + +**wall time: 4.32s** + +````` + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport` + +*Intra-procedural def-use slice of ONE variable: one row per line touching it, k=def|use|both, reaching definitions flow-sensitive (reach=cfg).* + +**wall time: 4.58s** + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=back --slice-depth=3` + +*TRANSITIVE backward value-flow from the seed variable, bounded BFS (depth= disclosed; a cut frontier says flow_truncated=1).* + +**wall time: 5.45s** + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + + pw = biasPrior( g, p );]]> + + +& p, float alpha = 0.85f )]]> + + +& p, float alpha = 0.85f )]]> + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport --slice-flow=fwd` + +*Forward flow: which statements the seed's value reaches, at the default depth bound.* + +**wall time: 2.97s** + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + + + + + + + + + + + + + + 0.0 )]]> + + + + + + + + +````` + +## `./build/ripwire . --slice=rankGraphTeleport:nosuchvar` + +*A variable the definition does not bind — the refusal shape, naming the inventory.* + +**exit code: 1** — **wall time: 1.27s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --slice: no occurrence of 'nosuchvar' in rankGraphTeleport — sliceable locals: alpha, g, p, pw, N, teleport, rankDouble, run, teleportMass, value, inverseMass, r (bare --slice=rankGraphTeleport lists them with first-def lines) +````` + +## `./build/ripwire . --slice-depth=3` + +*--slice-depth without --slice-flow is refused loudly rather than silently ignored.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire --slice=parseArgs:argIndex --slice-flow=fwd --slice-depth=4) +````` + +## `./build/ripwire . --slice=rankGraphTeleport:teleport --legend=compact` + +*The compact legend posture: rows byte-identical, a versioned schema id replaces the repeated explanatory prose — for a many-small-calls loop.* + +**wall time: 3.07s** + +````` + + + + + + + teleport( pw.begin(), pw.end() );]]> + + + + + + + + +````` + +## `./build/ripwire . --pattern='rankGraphTeleport($A, $B, $C)'` + +*Structural search written in CODE: $NAME binds one node; grammars=/shapes= disclose what the pattern became per grammar (a 3-argument call shape — the 2-argument spelling has no call site in this repo and correctly reports hits=0).* + +**wall time: 2.04s** + +````` + +rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) + +````` + +## `./build/ripwire . --pattern='DISCLOSE(...)'` + +*The ellipsis form over a macro-shaped call site; unsupported= names the families this verb does not serve.* + +**wall time: 2.53s** + +````` + +DISCLOSE( result, AbiResult::DisclosureWhy::NoMergeBase, "abi: no merge-base for a ref (unrelated history?) — that ref +DISCLOSE( Diagnostics::answerRefused, "--arch exits 1 with path:line and the reason on stderr; no report is printed", +DISCLOSE( baseline, ArchBaselineRead::DisclosureWhy::SymlinkRefused, "arch: refusing to read the arch baseline sidecar t +DISCLOSE( Diagnostics::answerRefused, "--baseline exits 1: pathguard names the refused link on stderr and the verb says +DISCLOSE( ex, Exclusions::DisclosureWhy::ForHeaderSaturated, "atoms: the for-header exclusion stream spent its whole bud +DISCLOSE( ex, Exclusions::DisclosureWhy::StmtCrementSaturated, "atoms: the statement-crement exclusion stream spent its +DISCLOSE( ex, Exclusions::DisclosureWhy::StmtAssignSaturated, "atoms: the statement-assign exclusion stream spent its wh +DISCLOSE( ex, Exclusions::DisclosureWhy::InnerCommaSaturated, "atoms: the inner-comma exclusion stream spent its whole b +DISCLOSE( st, Type3Stats::DisclosureWhy::PairCapHit, "clones: Type-3 pair cap hit — first N compared (both-gate-surviv +DISCLOSE( scan, CommentCoherenceScan::DisclosureWhy::UnreadableFile, "comment-coherence: an indexed file could not be re +DISCLOSE( st, StreamBlobStats::DisclosureWhy::ListUnwritable, "crossref: cannot write the blob-batch list — cross-bran +DISCLOSE( st, StreamBlobStats::DisclosureWhy::BatchNotStarted, "crossref: git cat-file --batch failed to start — cross +DISCLOSE( st, StreamBlobStats::DisclosureWhy::StreamEndedMidBlob, "crossref: git cat-file stream e +DISCLOSE( dropSink, RefEnumeration::DisclosureWhy::TipNotObjectName, "crossref: for-each-ref yielded a ref whose tip is +DISCLOSE( "crossref: refusing a diff whose revision arguments are not resolved object names" ) +DISCLOSE( sweep, ParallelSweep::DisclosureWhy::WorkerThrew, "crossref: a git worker threw — this shard of the sweep is +DISCLOSE( stats, StreamBlobStats::DisclosureWhy::BatchNotStarted, "crossref: a blob-stream slice was never read — comp +DISCLOSE( plumb, RefPlumbing::DisclosureWhy::RevisionNotObjectName, "crossref: ref tip or HEAD is not a resolved object +DISCLOSE( plumb, RefPlumbing::DisclosureWhy::MergeBaseNotObjectName, "crossref: merge-base returned something that is no +DISCLOSE( plumb, RefPlumbing::DisclosureWhy::NoMergeBase, "crossref: no merge-base for ref (shallow clone or unrelated h +DISCLOSE( "crossref: refusing to list a tree whose revision argument is not a resolved object name" ) +DISCLOSE( "whereis: the index's def sites match no HEAD row (working tree drifted from HEAD?) — keeping the lexical la +DISCLOSE( reads[ k ], BranchBlobReadBack::DisclosureWhy::NotReadBackWhole, "whereis: a blob the pa +DISCLOSE( scan, WorktreeScan::DisclosureWhy::ListingFailed, "whereis: git could not list the working tree's changes — +DISCLOSE( scan, WorktreeScan::DisclosureWhy::OverPathCap, "whereis: more changed paths than the overlay reads — the re +DISCLOSE( scan, WorktreeScan::DisclosureWhy::CopyUnread, "whereis: a changed path could not be read from the working tre +DISCLOSE( Diagnostics::answerUnchanged, "lsTree lists the same rows per ref: only slower", "crossref: +DISCLOSE( out, CMakeScan::DisclosureWhy::SymlinkEscapesRoot, "flags: a CMake file's symlink target leaves the root — f +… [73 more display lines; full output is 17772 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --pattern='x'` + +*A pattern that collapses to a bare token is REFUSED — never reported as hits=0.* + +**exit code: 1** — **wall time: 1.79s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --pattern: this pattern collapses to a single bare token, which is a TEXT search, not a structural one — a clean parse is not enough (a bare word parses fine in most grammars and means nothing structural). Give it a shape (foo($X), $A + $B, if ($C) { ... }) or use the grep flag for litera … [line truncated: 176 more bytes on this line] +````` + +## `./build/ripwire . --grep=DISCLOSE --and=cache` + +*Boolean grep: hits where BOTH literals share the matched line (--grep-scope=line is the default).* + +**wall time: 2.42s** + +````` + + + +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…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 19751 bytes on 44 raw line(s)] +````` + +## `./build/ripwire . --for="tree-sitter parse of a source file" --sections=lego,compose` + +*Restore the / sections the --for bundle collapses to a counted stub by default (this is the stub's own next= spelling).* + +**wall time: 3.60s** + +````` + + + + +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…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 ) +… [149 more display lines; full output is 20084 bytes on 44 raw line(s)] +````` + +## `./build/ripwire . --for="tree-sitter parse of a source file" --auto-bodies` + +*Opt OUT of compact conceptual serving: restore the rank-first auto walk (bundle="auto").* + +**wall time: 4.28s** + +````` + + + + +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…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 ) +… [134 more display lines; full output is 20303 bytes on 55 raw line(s)] +````` + +## `./build/ripwire . --for="quality delta acks ledger rubber stamp"` + +*Doc-mention surfacing (default ON): a markdown doc naming a top-resolved symbol in a backtick rides in below that symbol — the legend's [doc mentions: …] clause says it fired.* + +**wall time: 3.77s** + +````` + + + + + +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 constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at +inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) +inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… +inline const char* kNotesFile = ".ripwire_notes" +inline void writePlanLint( std::FILE* out, const LintResult& res ) + +The REF-PAIR floor's comparison, once loadRefPairDelta has both sides: the base snapshot is the …void refPairBasis( const rw::Config& cfg, const std::string& root, RefPairDelta& refs, DeltaBasis& out ) +std::optional<int> refuseForeignAckSelection( const rw::Config& cfg, const rw::quality::Scope& scope, const std::vector<rw::quality::Regression>& outOf … [line truncated: 16 more bytes on this line] +std::optional<int> runQualityDelta( const MainDispatch& d ) +struct DeltaBasis +int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] +inline const char* kAcksFile = ".ripwire_quality_acks" +DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) +struct IdentityHealing +inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline std::string qualityAcksPath( const std::string& root ) +struct QualityDeltaOutcome +std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) +… [193 more display lines; full output is 22995 bytes on 45 raw line(s)] +````` + +## `./build/ripwire . --for="quality delta acks ledger rubber stamp" --no-doc-mention` + +*The same task with doc-mention surfacing OFF — the contrast the flag exists for (no [doc mentions] clause, one fewer row).* + +**wall time: 4.52s** + +````` + + + + + +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 constexpr const char* kAtStampLegend = "<!-- at= is the git commit these numbers were computed at +inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) +inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… +inline const char* kNotesFile = ".ripwire_notes" +inline void writePlanLint( std::FILE* out, const LintResult& res ) + +The REF-PAIR floor's comparison, once loadRefPairDelta has both sides: the base snapshot is the …void refPairBasis( const rw::Config& cfg, const std::string& root, RefPairDelta& refs, DeltaBasis& out ) +std::optional<int> refuseForeignAckSelection( const rw::Config& cfg, const rw::quality::Scope& scope, const std::vector<rw::quality::Regression>& outOf … [line truncated: 16 more bytes on this line] +std::optional<int> runQualityDelta( const MainDispatch& d ) +struct DeltaBasis +int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] +inline const char* kAcksFile = ".ripwire_quality_acks" +DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) +struct IdentityHealing +inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline std::string qualityAcksPath( const std::string& root ) +struct QualityDeltaOutcome +std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) +… [193 more display lines; full output is 22814 bytes on 45 raw line(s)] +````` + +## `./build/ripwire . --safe-delete=rankGraphTeleport` + +*"Can I delete this?" — callers + transitive impact + every use site + how much of the radius is tested, composed in ONE call; risk= names what was found, never a verdict.* + +**wall time: 1.62s** + +````` + + + + + + + + + +````` + +## `./build/ripwire . --safe-delete=DoesNotExist` + +*Unknown-symbol refusal shape for --safe-delete.* + +**exit code: 1** — **wall time: 1.46s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --safe-delete symbol not found: DoesNotExist +````` + +## `./build/ripwire . --handoff` + +*The continuation packet for the NEXT session: disk truth (branch/sha, changed symbols, blast radius, tests) + labeled suggestions. Recorded against a CLEAN tree.* + +**wall time: 7.50s** + +````` + + + + + + + + + + + + + +````` + +## `./build/ripwire . --handoff --token-budget=1200` + +*The same packet under a hard ceiling: heuristic rows drop tail-first (withheld= disclosed), verified rows never drop.* + +**wall time: 6.73s** + +````` + + + + + + + + + + +````` + +## `./build/ripwire . --skipped` + +*WHY a file is not in the index (oversize / excluded / unsupported-ext / gitignored) and which indexed files it cannot vouch for (degraded-parse, minified-suspect), plus the per-language census.* + +**wall time: 1.29s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [441 more display lines; full output is 46965 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --no-ignore --top-k=3` + +*Crawl paths the repo's own .gitignore covers (default honours it and discloses ignored_files=/ignored_dirs= only when it dropped anything — this repo's crawl drops nothing, so the header is identical to the default map's; --skipped's ignore_mode= says which rule applied).* + +**wall time: 1.27s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8141 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --no-stable --top-k=3` + +*--no-stable outside --mcp: what the flag does (or says) when there is no stable-by-default ordering to opt out of.* + +**wall time: 2.07s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8141 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable ordering the server turns on) — it changed nothing here; the CLI map orders important-first unless you pass --order=stable +````` + +## `./build/ripwire . --run-trace="cat /aux/asan_trace_now.txt; exit 1"` + +*EXEC-MODE --from-trace: run a command, and on a non-zero exit map its captured output onto indexed symbols in the same call — the whole fix-loop entry. ripwire exits 4 here because the wrapped command failed, which is the signal, not an incident.* + +**exit code: 4** — **wall time: 2.19s** + +````` + + + + + + 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)]]> pw = biasPrior( g, p ); + const std::size_t N = pw.size(); + std::vector teleport( pw.begin(), pw.end() ); + std::vector rankDouble( N, 0.0 ); + PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun + if( N ) + { + double teleportMass = 0.0; + for( const double value : teleport ) + { + teleportMass += value; + } + if( teleportMass > 0.0 ) + { + const double inverseMass = 1.0 / teleportMass; + for( double& value : teleport ) + { + value *= inverseMass; + } + } + run = pageRankDouble( g.inEdges, g.wOutDeg, teleport, rankDouble, PageRankConfig{ .alpha = double( alpha ) } ); + } + std::vector r( N, 0.f ); + std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); + return { std::move( r ), run.iterationCount, run.hasConverged }; +}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] +````` + +## `./build/ripwire . --run-trace="true"` + +*A command that exits 0: a minimal success record (exit, measured duration, disclosed output tail) and NO bundle — nothing failed, nothing to map.* + +**wall time: 2.01s** + +````` + + + + +````` + +## `./build/ripwire . --run-trace="sleep 30" --run-timeout=2` + +*A command still running at the cap: its process group is killed and the run reports timed_out=1 — an honest timeout, never an empty success.* + +**exit code: 4** — **wall time: 3.84s** + +````` + + + + +````` + +stderr: + +````` +ripwire: --run-trace: TIMEOUT — the command exceeded the 2 s cap; its process group was killed +````` + +## `./build/ripwire . --run-timeout=5` + +*--run-timeout alone is refused loudly (it only modifies --run-trace).* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwire --run-trace="make -j" --run-timeout=60) +````` + + +--- + +# assess quality — the wider lens family + +## `./build/ripwire . --quality-panel` + +*THE single wide-angle quality read: six families in one pass, an eligible/ranked shortlist rather than a firehose.* + +**wall time: 11.03s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [188 more display lines; full output is 15676 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --biggest-first --limit=8` + +*Per-function size ranking, largest Halstead volume/token entropy/lines first — a size proxy, not a readability order (withdrawn, docs/EVALS.md §8) — a RANKING lens, not a grade.* + +**wall time: 1.55s** + +````` + + + + + + + + + + + +````` + +## `./build/ripwire . --comment-coherence --limit=8` + +*Functions WITH a doc comment, most name-restating first: c_coeff (high = the comment repeats the name) and cic (Jaccard of comment vs identifier vocabulary), both reported, never collapsed.* + +**wall time: 2.56s** + +````` + + + + + + + + + + + +````` + +## `./build/ripwire . --context-ratio --limit=8` + +*The local-reasoning lens: to understand this symbol, how much must you know that is NOT in front of you (ent_ratio= edge share, read_ratio= token-weighted).* + +**wall time: 1.95s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [21 more display lines; full output is 11151 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --nonlocal-state --limit=8` + +*Per function, the non-local MUTABLE state it can reach (transitively), most writes first — unsound by construction, and the legend says where.* + +**wall time: 4.01s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [41 more display lines; full output is 7601 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --ensemble --limit=8` + +*The family join: per function, which of four orthogonal evidence families fire, ranked by how many agree.* + +**wall time: 6.83s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [36 more display lines; full output is 7490 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --field-affinity` + +*The cache-locality lens over every aggregate: fields READ TOGETHER but declared FAR APART (split-line / straddle findings, Chilimbi separation weight) — advice only, never a rewrite.* + +**wall time: 2.41s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [510 more display lines; full output is 45635 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --field-affinity=Symbol` + +*The same lens narrowed to ONE struct — the one --layout=Symbol shows the offsets for.* + +**wall time: 2.19s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --naming-consistency --limit=8` + +*The corpus's OWN case-convention vote per (language, kind) group; off-convention names get a mechanical propose= (a suggestion, never a blind rename).* + +**wall time: 1.22s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [13 more display lines; full output is 4430 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --naming-calibration` + +*Score the naming-* rules against this repo's own rename history: proxy=old/(old+new) per rule, 0.50 = chance; read pairs= (sample size) first.* + +**wall time: 14.75s** + +````` + + + + + + + + + + + +

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+… [156 more display lines; full output is 16229 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint --naming-locals` + +*The opt-in --lint modifier: naming predicates over LOCAL variable names too, C/C++ only, only inside functions already past a size/complexity gate.* + +**wall time: 3.92s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [641 more display lines; full output is 72667 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint-catalog` + +*The built-in rule registry — one row per rule with sev=/category=/rationale/lang=/since=; no corpus needed.* + +**wall time: 1.61s** + +````` + + +a C-style cast — cppcoreguidelines-pro-type-cstyle-cast prefers the explicit static_cast/const_cast/reinterpret_cast +a goto statement — cppcoreguidelines-avoid-goto +a do/while loop shape (on Swift, its do/catch block shares the same grammar node and also matches) +a call to an unbounded C string function (strcpy/strcat/sprintf/gets) +a call to a broken hash or cipher (MD5/SHA1/MD4/RC4) +a doubly-parenthesized expression — readability-redundant-parentheses +an if-body that is just `;` — bugprone-suspicious-semicolon +a C-style typedef struct/union where `using` is preferred +a non-trivial numeric literal inside a function body, outside a const/constexpr init +a catch block with an empty body +x = x — almost always a copy-paste bug +a function body over 80 lines +brace nesting depth over 4 inside a function body +a bare `return;` mixed with a value-returning return in the same function +a statement after an unconditional return/break/continue/throw/raise in the same block +a 1-2 letter Function/Method/Var name — visible far beyond any tiny scope [Beniamini/Hofmeister] +more than 5 split tokens in one name [Butler; AlSuhaibani] +foo1/foo2/... digit-suffix siblings sharing a base name in one scope [Butler] +internal consecutive underscores, or a C-family reserved __x/_X form [Butler] +snake_case and camelCase mixed inside one name [Butler] +an is/has/can/should/was-prefixed name whose KNOWN return type is not bool-like [LAPD A2] +a set-prefixed name whose KNOWN return type is not void-like [LAPD A3] +a co-visible pair within edit distance <=2, reordered tokens, or a bare/digit-suffixed twin [Namesake] +every split subtoken is corpus-ubiquitous (BM25 idf) on a body past the size floor — fires only at the low end [Sparck Jones 1972] +the comma operator inside an expression (never a for-header comma) [Gopstein FSE 2017] +++/-- evaluated inside a larger expression (never a whole statement) [Gopstein FSE 2017] +an assignment whose VALUE is consumed (a condition, an argument, ...) [Gopstein FSE 2017] +a conditional expression inside a conditional expression [Gopstein FSE 2017] +… [12 more display lines; full output is 7800 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --legend-dict` + +*The session legend dictionary the MCP server serves as ripwire://legend-dict/full — one definition per line, headed by its dictv= version; no corpus needed. =roster lists the completeness attributes it defines.* + +````` +ripwire legend dictionary ripwire.dict/v1 dictv=8c941c6c17d27549 entries=932 +: the answer's rows come first; its root keeps only task= changed= from= to=, and this LAST child carries every other root attribute unchanged (schema= included); legend="ref": a definition is sent once per session (this dictionary's core, or the first answer that ne … [line truncated: 83 more bytes on this line] +schema=ripwire.KEY/v1: the line ripwire.KEY/v1 below reads the answer's rows +window: shown= total= capped= has_more= next_offset= offset= limit= page a list (capped=1 cut; next_offset= pastes as offset=) +X_capped= (any attribute ending _capped): 1 = cut +under ref, est_tokens= and over_ceiling= price the answer with its inline legend: an upper bound +under ref, a group of n <= 8 runner-less rows prints as its n single rows, each run_unknown=1 +ripwire.map/v1 : ranked symbol map: groups rows (k= rank), resolved callees; the header comment is data +ripwire.map-diff/v1 : the ranked map anchored at at=: what the diff touched, the map's row vocabulary +ripwire.metrics/v1 : the ranked map with per-symbol metrics +ripwire.around/v1 : call neighbourhood of of=: depth= hops, fanout= kept per hop; absent rows lie outside that boundary +ripwire.query/v1 : lexical-rank map for the query term, the map's row vocabulary +ripwire.pack-signatures/v1 : the ranked map plus signature rows +ripwire.pack-top-n/v1 : the ranked map plus bodies of the top-N symbols +ripwire.skipped/v1 : why the index lacks a file ; indexed but unvouched ; census +ripwire.notes/v1 : field notes by target: holds ; the kept count comment: notes= rows, targets= rows, dangling= targets matching nothing indexed (listed, surfaced nowhere) +ripwire.lego/v1 : ONE interface/base type: , its method contract, every implementor +ripwire.expand/v1 : full bodies: of ; resolved callees +ripwire.expand-file/v1 : the file's own text: ; per scoped symbol; full id = p::sc::n +ripwire.candidate-page/v1 : budgeted-bundle candidate page: a resumable window over the ranked candidate set the bundle cuts, for task= under budget_tokens=, one tier per page, ranks global across pages +ripwire.pack-task/v1 : one-call task bundle for task= under budget_tokens=: ranking, ranked but over 1 hop out (of_top= ranked rows) > with callees > 1-hop from the bodies (o … [line truncated: 105 more bytes on this line] +ripwire.from-trace/v1 : trace frames mapped to indexed symbols, innermost first; the innermost in-corpus body included +ripwire.exemplar/v1 : the best-in-class instance of kind= for the task, chosen by role: , to imitate +ripwire.pack-task/v1 : N minimally overlapping agent bundles carved along call-graph communities plus one shared core; each wraps a ; bundle role=core|partition i= symbols= modules= bytes= tokens=: one agent's ctx, symbols= ids assigned, bytes= its size; tokens= = est_t … [line truncated: 345 more bytes on this line] +ripwire.callers/v1 : 1-hop CALLERS of of= (defs= matched, count= distinct symbols): ; hop_tested=/hop_untested= +ripwire.callees/v1 : 1-hop CALLEES of of= (defs= matched, count= distinct symbols): +ripwire.uses/v1 : resolvable use-sites of of=: +ripwire.impact/v1 : transitive blast radius of of=: reach set, importers; defs= matched, reaches= their transitive callers, radius_tested= non-tests an indexed test reaches, radius_untested= the rest; importers= files that #include/import a def's file +ripwire.path/v1 : one DIRECTED call path from= to to=, each a hop; reachable=0 hops=0 when none +ripwire.connect/v1 : minimal joining subgraph: groups, terminals, joins, edges, +… [903 more display lines; full output is 97621 bytes on 933 raw line(s)] +````` + +## `./build/ripwire . --lint --lint-select=cache-` + +*Run ONLY one rule family; the root carries selected="K of N" so a filtered zero is never confusable with an unfiltered one.* + +**wall time: 3.34s** + +````` + + + + + + + + + + +vector<std::vector<double>> +nodes[ perm[i] ] +nodes[ perm[ i + 1 ] ] +p = p->next +map +byName[ symN[i] ] +vector<std::vector<std::vector<std::uint32_t>>> +vector<std::vector<std::uint32_t>> +m[ symN[id] ] +vector<std::vector<double>> +m[ in.keys[ i ] ] +map +vector<std::vector<std::vector<std::uint32_t>>> +vector<std::vector<std::uint32_t>> +m[ symN[id] ] +map +m[ g_pool[ g_keyOf[i] ] ] +g_pool[ g_readOf[i] ] +g_pool[ g_readOf[i] ] +m[ g_pool[i] ] +… [607 more display lines; full output is 73564 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint --lint-ignore=naming-,cache-` + +*DROP two families, applied after selection; the raw select=/ignore= you passed rides on the root.* + +**wall time: 2.91s** + +````` + + + + + + + + + + + + + + + + + + + + + + + +0.5 +1023u +main (90 lines) +20 +delta < 0.02 && delta > -0.02 +0.02 +… [724 more display lines; full output is 66380 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --lint --lint-select=goto --lint-max-per-rule=4` + +*A rule that spends its own match budget (here 4, set BELOW the default 5000 so the floor shows on this repo): goto carries count_capped="1", its count= is a FLOOR, and the root names the call that counts the rest — findings_next= re-runs only the floored rules under a 10x budget.* + +**wall time: 2.83s** + +````` + + + +goto done; +goto epilogue; +goto epilogue; +goto epilogue; + +````` + +## `./build/ripwire . --lint --lint-select=goto --lint-max-per-rule=40` + +*Pasting that findings_next=: the same rule under a 10x budget counts its true total — no count_capped=, no findings_next=.* + +**wall time: 3.01s** + +````` + + + +goto done; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto epilogue; +goto error; +goto error; +goto error; +goto done; +goto done; + +````` + +## `./build/ripwire . --lint --lint-select=cach-` + +*An unresolvable PREFIX refuses (exit 1) with a did-you-mean from a real edit distance (one character off cache-).* + +**exit code: 1** — **wall time: 2.84s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --lint-select: 'cach-' matches no rule or family (did you mean 'cache-'?) — see --lint-catalog for the full registry +````` + +## `./build/ripwire . --lint --lint-select=nosuchfamily` + +*A PREFIX with no near miss at all: the refusal points at --lint-catalog instead of guessing.* + +**exit code: 1** — **wall time: 2.80s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --lint-select: 'nosuchfamily' matches no rule or family — see --lint-catalog for the full registry +````` + +## `./build/ripwire . --lint --sarif` + +*The SAME findings as SARIF 2.1.0 (what github/codeql-action/upload-sarif consumes) — pure re-serialization, results count == the native run's.* + +**wall time: 2.76s** + +````` +{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"name":"ripwire","rules":[{"id":"c-style-cast","shortDescription":{"text":"c-style-cast"},"properties":{"builtin":true,"capped":false,"applicable": … [line truncated: 7 more bytes on this line] +{"id":"goto","shortDescription":{"text":"goto"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"do-while","shortDescription":{"text":"do-while"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"unsafe-c-fn","shortDescription":{"text":"unsafe-c-fn"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"weak-crypto","shortDescription":{"text":"weak-crypto"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"redundant-parens","shortDescription":{"text":"redundant-parens"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"suspicious-semicolon","shortDescription":{"text":"suspicious-semicolon"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"typedef-over-using","shortDescription":{"text":"typedef-over-using"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"magic-number","shortDescription":{"text":"magic-number"},"properties":{"builtin":true,"capped":true,"applicable":true}}, +{"id":"empty-catch","shortDescription":{"text":"empty-catch"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"self-assign","shortDescription":{"text":"self-assign"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"large-function","shortDescription":{"text":"large-function"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"deep-nesting","shortDescription":{"text":"deep-nesting"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"inconsistent-return","shortDescription":{"text":"inconsistent-return"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"unreachable-code","shortDescription":{"text":"unreachable-code"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-short","shortDescription":{"text":"naming-short"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-wordy","shortDescription":{"text":"naming-wordy"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-series","shortDescription":{"text":"naming-series"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-underscore","shortDescription":{"text":"naming-underscore"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-case","shortDescription":{"text":"naming-case"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-predicate","shortDescription":{"text":"naming-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-setter","shortDescription":{"text":"naming-setter"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-confusable","shortDescription":{"text":"naming-confusable"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"naming-uninformative","shortDescription":{"text":"naming-uninformative"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-comma-operator","shortDescription":{"text":"atom-comma-operator"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-embedded-crement","shortDescription":{"text":"atom-embedded-crement"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-assign-as-value","shortDescription":{"text":"atom-assign-as-value"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-nested-ternary","shortDescription":{"text":"atom-nested-ternary"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-implicit-predicate","shortDescription":{"text":"atom-implicit-predicate"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +{"id":"atom-octal-literal","shortDescription":{"text":"atom-octal-literal"},"properties":{"builtin":true,"capped":false,"applicable":true}}, +… [13515 more display lines; full output is 1913639 bytes on 1 raw line(s)] +````` + +Parsed summary of the same SARIF (past the display cut): + +````` +sarif 2.1.0 rules= 39 results= 6753 +````` + +## `./build/ripwire . --lint --sarif --limit=5` + +*SARIF is always the FULL result set: paging alongside it refuses loudly.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --sarif always emits the full result set — drop --limit=N/--offset=M +````` + +## `./build/ripwire . --dmm` + +*The Delta Maintainability Model scalar for the WORKING TREE vs HEAD — recorded against a CLEAN tree (the sandbox section shows a real delta). UNAVAILABLE is a stated reason, never 0 or 1.* + +**wall time: 9.93s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --dmm=HEAD` + +*The per-commit scalar: HEAD vs its first parent, with the three separately actionable sub-scores.* + +**wall time: 16.42s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --dmm=HEAD~3..HEAD` + +*The range form: tree HEAD vs tree HEAD~3.* + +**wall time: 17.74s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --cochange --cochange-groups` + +*Modularity-violation GROUPS instead of pairs: "X co-changes with {A,B,C}, none of which it depends on" — a greedy cover, disclosed as greedy.* + +**wall time: 5.56s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [847 more display lines; full output is 56290 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --cochange --cochange-recur=2` + +*Only pairs whose co-change RECURS in 2+ sub-windows of the mined window (sub_windows= is the denominator) — a one-off sprint stops reading like a structural defect.* + +**wall time: 5.41s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --html=/aux/map2.html --color-by=community` + +*The HTML graph with the initial colour mode set to community (the page embeds all five modes and keeps a live selector).* + +**wall time: 4.67s** + +````` +(empty) +````` + +Artifact written: + +````` + 156039 /aux/map2.html +````` + +## `./build/ripwire . --index-out=/aux/ci_index` + +*CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout.* + +**wall time: 6.02s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --index-out wrote /aux/ci_index.lean.ripwirecache (28779725 bytes, lean family) +ripwire: --index-out wrote /aux/ci_index.rich.ripwirecache (58976312 bytes, rich family) +````` + +Artifact written: + +````` + 28779725 /aux/ci_index.lean.ripwirecache + 58976312 /aux/ci_index.rich.ripwirecache + 87756037 total +````` + +## `./build/ripwire . --cache=/aux/ci_index.lean.ripwirecache --top-k=3` + +*Consume the lean artifact in a PR job: restore-equivalence, never blob-byte-identity.* + +**wall time: 1.86s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8141 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --pin-census=/aux/pin_census.tsv --top-k=3` + +*Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target.* + +**wall time: 2.37s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [63 more display lines; full output is 8141 bytes on 1 raw line(s)] +````` + +Artifact written: + +````` +# ripwire pin-census v3 C=kind\tmech\tpre\tpost\tflags\tcaller_id\tcallee\ttargets(|-sep)\tline +# v3 field escape: every id and callee field is escaped, so no separator occurs inside one. A backslash is +# written \\, TAB \t, LF \n, CR \r, every other control byte 0x00-0x1f and the targets separator | as \xHH +# (lowercase hex). Split lines on LF, fields on TAB and targets on |, THEN decode. Columns are unchanged +# from v2 and an id without those bytes is spelled exactly as in v2; a C++ out-of-line template member +# whose template-argument list spans lines keeps its line break as \n instead of splitting the row. +# line is the 1-based call-site line in the caller's file (v2, appended LAST so v1 readers are unchanged): +# the key a SCIP occurrence joins on, so a coverage loss can be classified per site instead of guessed. + 129635 /aux/pin_census.tsv +````` + +## `./build/ripwire . --plan-lint=test/planlintfix/wave.md` + +*The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates.* + +**exit code: 2** — **wall time: 3.44s** + +````` + + + + + + + + + + + + + +````` + +## `./build/ripwire . --plan-lint=test/planlintfix/wave_ledger.md` + +*The ledger-shaped fixture through the same check (exit 2: one gating card).* + +**exit code: 2** — **wall time: 3.12s** + +````` + + + + + + + +````` + +## `./build/ripwire . --doctor --agent=claude` + +*--doctor plus a LIVE integration inspection for one agent: PATH binary, installed-skill manifest parity, hook executability, MCP wiring — read-only, fixed repair commands, never config contents; exit 1 when any check fails.* + +**exit code: 1** — **wall time: 28.14s** + +````` + + + + + + + + + + + + + +````` + +## `./build/ripwire . --doctor --agent=nosuch` + +*Other --agent values refuse.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: unsupported --agent value 'nosuch' (supported: codex, claude) +````` + + +--- + +# the dirty-tree verbs (throwaway clone, NOT the read-only repo) + +Everything below runs with `cwd` = the throwaway clone at `/dirty` (`git clone --local` of this repo, then one deliberate regression in `src/infra/sortutil.h`). The read-only repo is never touched. The binary is the same `build/ripwire`, addressed absolutely. + +## `./build/ripwire . --situ` + +*Situational report for a real diff: blast radius + tests + co-change + forgotten co-change partners.* + +**wall time: 12.42s** + +````` +ripwire situational-awareness — 1 changed file(s), 13 symbols in them +root: . +at: 0712a5182+dirty + change_set: granularity=file changed_symbols=13 file_symbols=13 files_narrowed=0 files_file_granular=1 diff_hunks=7 diff_hunks_located=6 diff_hunks_unlocated=1 — seeds = symbols a diff -U0-vs-HEAD hunk overlaps (function/method body spans only); an unlocated hunk (module-level, deletion, rename) … [line truncated: 34 more bytes on this line] + [1] blast radius: 246 symbols across 58 files transitively depend on these changes (showing 8 of 58 files — shown=8 total=58 capped=1 prcontext_cap=20 (--pr-context's own per-file list is cut at 20 too); next: --situ --limit=58) + counts_floor=1 graph_ambiguous=2933 graph_unresolved=15249 graph_unindexed=269 (files no grammar in this build could read at all) (the map header's own gauges) — every count above is a FLOOR, never a total: call edges are name-based, so dynamic dispatch, callbacks and macros can be missing … [line truncated: 45 more bytes on this line] + src/mcpverbs.h (33 dependent symbols) + src/quality.h (15 dependent symbols) + src/verbs_quality.h (14 dependent symbols) + src/verbs_for.h (13 dependent symbols) + src/editcheck.h (9 dependent symbols) + src/resolve.h (9 dependent symbols) + src/verbs_navigate.h (9 dependent symbols) + src/graph.h (8 dependent symbols) + [2] tests to run (5) order=evidence: [changed] you edited it, [partner] named after a changed file, then hops asc (1 = direct); "(n): a, b" = n runner-less files sharing that evidence; a (run: …) is relative to root: + test/verify_radix.cpp [hops=1] (run: bash test/greptiercheck.sh) + test/adaptivecutshapefix/adaptive_cut_shape_test.cpp [hops=2] (run: bash test/adaptivecutshapecheck.sh) + test/includeprecise_unit.cpp [hops=2] (run: bash test/includeprecisecheck.sh) + test/verify_csr.cpp [hops=2] (run: bash test/a9disclosurecheck.sh) + test/rustimport_unit.cpp [hops=4] (run: bash test/rustimportprecisecheck.sh) + script_gates_unmodelled=782 — test/*.sh gates never appear above: script-to-binary edges are not call edges (a path count) + [3] co-change — usually edited with these but NOT in your diff (0) window="18mo@HEAD" commits="5296": + (none — 5296 commits were mined and none co-edited a file outside your diff) + next: --test-gate +````` + +## `./build/ripwire . --test-gate` + +*The pre-PR gate with real obligations — exit 4 when tests-to-run or untested blast radius is non-empty.* + +**exit code: 4** — **wall time: 9.40s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --quality-delta` + +*Every row carries p="file:line", the gating rows are marked gating="1" and now bar= (the threshold each numeric row is judged against), and the exit-2 refusal prints a naming line on stderr; a gating row carries a pasteable next=.* + +**exit code: 2** — **wall time: 39.75s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [149 more display lines; full output is 18050 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) +````` + +## `./build/ripwire . --quality-delta --legend=full` + +*The same gating report under --legend=full — same rows, same exit 2; the default compact comment (schema="ripwire.quality-delta/v1", the shape an agent's edit loop should run) becomes ~4 KB of prose legend.* + +**exit code: 2** — **wall time: 20.10s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [149 more display lines; full output is 23042 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) +````` + +## `./build/ripwire . --quality-delta --json` + +*The same findings as JSON (one of the CI/scripting verbs --json supports) — same exit 2 as the XML form.* + +**exit code: 2** — **wall time: 20.08s** + +````` +{"baseline":"git-HEAD","regressions":9,"minor":1,"acked":0,"stale":167,"preexisting-worse":6,"new-symbol":3,"gating":5,"register-macro-excluded":62,"api-new-surface":2,"at":"0712a5182+dirty","renames":62,"rename_window_commits":400,"acked_by_rename":0,"acked_by_content":0,"renames_window_truncated": … [line truncated: 239 more bytes on this line] +{"kind":"complexity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":67,"p":"src/infra/sortutil.h:49","gating":true}, +{"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy","p":"src/infra/sortutil.h:119","origin":"new-symbol"}, +{"kind":"dead-code","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","p":"src/infra/sortutil.h:129","origin":"new-symbol"}, +{"kind":"duplication","members":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey","tokens":59,"p":"src/infra/sortutil.h:119","gating":true}, +{"kind":"nesting","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":1,"now":6,"p":"src/infra/sortutil.h:49","gating":true}, +{"kind":"new-clone-of-reused-helper","sym":"src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey","was":0,"now":4,"p":"src/infra/sortutil.h:119","gating":true}, +{"kind":"params","sym":"src/infra/sortutil.h::rw::sortutil::sortScoredIdsWithOptions","was":0,"now":8,"p":"src/infra/sortutil.h:129","origin":"new-symbol"}, +{"kind":"verbosity","sym":"src/infra/sortutil.h::rw::sortutil::lessByScoreDescId","was":8,"now":47,"p":"src/infra/sortutil.h:49","sev":"minor"}], +"sa":[{"kind":"api-surface","key":"085e3d408c2c4a35","why":"target-gone"}, +{"kind":"api-surface","key":"155d74d341a49f3c","why":"target-gone"}, +{"kind":"api-surface","key":"1a15386c2d1e47af","why":"target-gone"}, +{"kind":"api-surface","key":"298e798c7f075715","why":"target-gone"}, +{"kind":"api-surface","key":"56acdf9b5c314a14","why":"target-gone"}, +{"kind":"api-surface","key":"5a07390012b46e06","why":"target-gone"}, +{"kind":"api-surface","key":"6eef859578c8c376","why":"target-gone"}, +{"kind":"api-surface","key":"6f2394762f82a855","why":"target-gone"}, +{"kind":"api-surface","key":"7f2c3eefdf6e512e","why":"target-gone"}, +{"kind":"api-surface","key":"802e513731103806","why":"target-gone"}, +{"kind":"api-surface","key":"b6a24afef32a68a8","why":"target-gone"}, +{"kind":"api-surface","key":"c923e661c197b265","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"1926b0d9e94541a0","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"1d3814ba687a4aef","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"1db76028879244ef","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"25c9f0504fd376a4","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"36e39c7ab0fc1686","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"4bce64bd920de0c3","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"61f0e361ef7dee27","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"79625906f9f71ad0","why":"target-gone"}, +{"kind":"api-surface:new-symbol","key":"8ecb190954dce18a","why":"target-gone"}, +… [146 more display lines; full output is 16644 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 5 preexisting-worse major finding(s); first: api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 (was=1 now=2) +````` + +## `./build/ripwire . --quality-delta --quality-ack --ack-only=zzznope` + +*NEW FLAG: --ack-only matching nothing REFUSES rather than falling back to acking everything.* + +**exit code: 1** — **wall time: 15.47s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: ack provenance backfill — 0 clone row(s) reconstructed from the current tree, 213 re-derived, 21 left UNVERIFIED (their group was not found here — a floor, not proof it is gone), 56 left legacy (member set not found cloning here — a floor, not proof it is gone), 1311 ineligible (no cu … [line truncated: 200 more bytes on this line] +ripwire: --ack-only=zzznope matched none of the 9 finding(s) — nothing written +````` + +## `./build/ripwire . --quality-delta --quality-ack --ack-only=api-surface` + +*NEW FLAG: ack only the api-surface findings — a per-finding ratchet instead of a rubber stamp.* + +**wall time: 18.13s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: ack provenance backfill — 0 clone row(s) reconstructed from the current tree, 213 re-derived, 21 left UNVERIFIED (their group was not found here — a floor, not proof it is gone), 56 left legacy (member set not found cloning here — a floor, not proof it is gone), 1311 ineligible (no cu … [line truncated: 200 more bytes on this line] +ripwire: acknowledged 1 of 9 finding(s) (8 left UNACKED by --ack-only, 0 already acked) → ./.ripwire_quality_acks +````` + +## `./build/ripwire . --quality-delta` + +*Re-run after the partial ack: acked=3, the rest still gate (exit 2).* + +**exit code: 2** — **wall time: 23.07s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [148 more display lines; full output is 17753 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 4 preexisting-worse major finding(s); first: complexity src/infra/sortutil.h::rw::sortutil::lessByScoreDescId at src/infra/sortutil.h:49 (was=1 now=67) +````` + +## `./build/ripwire . --ack-only=gating` + +*--ack-only WITHOUT --quality-ack REFUSES loudly (exit 1, the pairing named) — it used to be silently ignored.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --ack-only=SUBSTR narrows --quality-ack — pass both (e.g. ripwire

--quality-delta --ack-only=contract-change --quality-ack="reason") +````` + +## `./build/ripwire . --edit-check=nonNegativeFloatDescKey` + +*A real contract-change: was=1 now=2 params, with the call sites that are now provably incompatible, and a pasteable next= (--uses=SYM) on the root.* + +**wall time: 4.38s** + +````` + + + + + + +````` + +## `./build/ripwire . --edit-check=nonNegativeFloatDescKey --legend=full` + +*The same verdict under --legend=full: the default's one compact comment (the post-edit reflex at its cheapest) becomes ~5.7 KB of prose legend, every row identical.* + +**wall time: 4.12s** + +````` + + + + + + +````` + +## `./build/ripwire . --pr-context` + +*The review-evidence bundle with an actual changed file.* + +**wall time: 7.45s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [80 more display lines; full output is 8063 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --map-diff --top-k=5` + +*The map re-ranked with a teleport toward the changed file (changed=1 here, not 0).* + +**wall time: 6.20s** + +````` + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --clones` + +*The duplicated helper the sandbox edit introduced shows up as a clone group.* + +**wall time: 3.16s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [308 more display lines; full output is 16199 bytes on 1 raw line(s)] +````` + +## `./build/ripwire . --stray-content=zz-orphan` + +*CHANGED: a ref with NO merge base with HEAD now reports v="unknown" ok="0" in its own bucket — the absence of an answer, never a claim it is merged. (The sandbox carries a deliberately parentless branch built with `git commit-tree`; a shallow CI clone puts every ref here.)* + +**wall time: 5.56s** + +````` + + + + + +````` + +stderr: + +````` +[math degraded] crossref: no merge-base for ref (shallow clone or unrelated history?) — verdict is unknown, not merged (crossref.h:1274, RefPlumbing rw::crossref::probeRefBase(const std::string &, const RefInfo &, const std::string &) — logged once per site) +````` + +## `./build/ripwire . --stray-content=zz-orphan --plan` + +*CHANGED: --plan surfaces those same refs as an row rather than silently dropping them.* + +**wall time: 7.89s** + +````` + + + + +````` + +stderr: + +````` +[math degraded] crossref: no merge-base for ref (shallow clone or unrelated history?) — verdict is unknown, not merged (crossref.h:1274, RefPlumbing rw::crossref::probeRefBase(const std::string &, const RefInfo &, const std::string &) — logged once per site) +````` + +## `./build/ripwire . --dmm` + +*The DMM scalar on a REAL delta: the sandbox edit grew one unit past the nesting/complexity thresholds and added an 8-parameter one, so dmm is low and the three sub-scores say which property moved.* + +**wall time: 9.39s** + +````` + + +

+

+ +````` + +## `./build/ripwire . --quality-delta --scope=src/graph.h` + +*OWNERSHIP partition for a shared tree: every regression here lives in src/infra/, so under a scope naming src/graph.h they ALL print under with a do-not-ack banner and never gate — scoped-out-gating= says how many would have.* + +**wall time: 21.65s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [151 more display lines; full output is 18020 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +````` + +## `./build/ripwire . --quality-delta --quality-ack --scope=src/graph.h --ack-only=api-surface` + +*The rubber-stamp guard: an --ack-only that names an OUT-OF-SCOPE row refuses (exit 1) and writes nothing.* + +**exit code: 1** — **wall time: 21.16s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --ack-only=api-surface selects 1 finding(s) OUT OF SCOPE for --scope=src/graph.h — refusing, and writing nothing at all: + api-surface src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:109 + those rows belong to whoever is editing those paths. Acking them here writes their debt into a committed ledger under YOUR + reason string, which is how a per-finding ratchet becomes a rubber stamp. Narrow the pattern, or widen the scope if they really are yours. +````` + +## `./build/ripwire . --handoff` + +*The continuation packet with a REAL diff: verified changed symbols + blast radius + tests-to-run, then the heuristic rows.* + +**wall time: 17.15s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +````` + +## `./build/ripwire . --note-add="lessByScoreDescId: keep this branch-free — it sits inside the PageRank sort comparator"` + +*Pin a field note (write-side memory) to a symbol; committed to .ripwire_notes in the sandbox. The BARE name is resolved through the same resolver the read verbs use and stored as the canonical id — the rewrite is echoed on stderr, because a silent one is not a disclosure.* + +**wall time: 3.80s** + +````` +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-26 keep this branch-free — it sits inside the PageRank sort comparator 0712a5182ef61b6885b76af328cae18e839eb110 integration/train-36 +````` + +stderr: + +````` +ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why +ripwire: --note-add: target 'lessByScoreDescId' canonicalised to 'src/infra/sortutil.h::rw::sortutil::lessByScoreDescId' — that is the id --for/--expand key notes by +````` + +## `./build/ripwire . --notes` + +*The note is listed under the canonical id, dangling="0" — i.e. it will actually surface. (Before the H1 fix the bare name was stored verbatim and read dangling="1": recorded, and surfaced nowhere.)* + +**wall time: 1.58s** + +````` + + + + + + + + + + + + + + + + gate scripts' claim (~line 1305) is NOT enforced — the derived-vs-stated sibling loop here covers docs/EVALS.md only. It drifted 407→451 unnoticed (fixed 2026-08-23). To close: grep both files ('file:line:' parsing) in the gateCountClaims arm.]]> + + + + +````` + +## `./build/ripwire . --note-add="gitOneLine: which one?"` + +*Two definitions carry this name, so the write REFUSES rather than pick one: a note keys ONE canonical id, and an ambiguous selector is refused, never silently narrowed. Every candidate is named, with a runnable retry.* + +**exit code: 1** — **wall time: 1.29s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why +ripwire: --note-add: target 'gitOneLine' is ambiguous — it matches 2 definitions in 2 distinct contracts, and a note keys ONE canonical id (it would surface on one of them and look absent on the rest). Qualify one: ./src/handoff.h:gitOneLine, ./src/quality.h:gitOneLine — e.g. --note-add="./src/h … [line truncated: 33 more bytes on this line] +````` + +## `./build/ripwire . --note-add="lessByScoreDescIdd: typo"` + +*A name that resolves to nothing is refused with the read verbs' own did-you-mean — never written as a dead note.* + +**exit code: 1** — **wall time: 1.16s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --note-add: tip: notes that say "chose X over Y because Z" surface better — consider adding the why +ripwire: --note-add: target not found: lessByScoreDescIdd (did you mean 'lessByScoreDescId'?) — a note keys the canonical id a read verb resolves; to note a FILE instead, pass a path (one with a '/' or an extension), which may name a file that does not exist yet +````` + +## `./build/ripwire . --note-add="src/infra/sortutil.h::rw::sortutil::lessByScoreDescId: chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort"` + +*The same symbol addressed by its CANONICAL id: already canonical, so nothing is rewritten and both notes land on ONE target.* + +**wall time: 2.79s** + +````` +src/infra/sortutil.h::rw::sortutil::lessByScoreDescId 2026-10-26 chose the flat two-branch compare over the nested ladder because the comparator sits inside the PageRank sort 0712a5182ef61b6885b76af328cae18e839eb110 integration/train-36 +````` + +## `./build/ripwire . --expand=lessByScoreDescId --top-k=0` + +*Both notes riding along with the symbol's body — the elements follow the body, past the display cut, so they are extracted below.* + +**wall time: 1.87s** + +````` + + + + + + + + + + + + + +````` + +## `./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=/aux/payload_note.h` + +*Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call.* + +**wall time: 6.16s** + +````` +{"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":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":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} +````` + +stderr: + +````` +ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: bash test/greptiercheck.sh +````` + +## `./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=/aux/payload_note.h --no-post-check` + +*The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr.* + +**wall time: 2.81s** + +````` +{"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] +````` + +stderr: + +````` +ripwire edit: applied atomically; receipt carries region, blob_sha (post-check skipped); next: --edit-check=src/infra/sortutil.h:lessByScoreDescId +````` + +## `./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=/aux/payload_note.h --edit-target-file=src/infra/sortutil.h` + +*Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured).* + +**wall time: 7.47s** + +````` +{"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] +{"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":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":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} +````` + +stderr: + +````` +ripwire edit: applied atomically; receipt carries region, blob_sha, edit_check, tests_to_run; next: --uses=src/infra/sortutil.h:nonNegativeFloatDescKey +````` + +## `./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=/aux/payload_note.h` + +*An unknown TARGET refuses and leaves every file byte-identical.* + +**exit code: 1** — **wall time: 3.49s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --replace-symbol-body: symbol 'DoesNotExist' not found +````` + +## `./build/ripwire . --edit-plan=/aux/edit_plan.json --dry-run` + +*A versioned multi-edit TRANSACTION preflighted without writing: the receipt shows what each op would read and touch.* + +**wall time: 3.52s** + +Input file: + +````` +{ + "version": 1, + "edits": [ + { + "op": "insert_before_symbol", + "target": "nonNegativeFloatDescKey", + "payload": "plan_note.h" + } + ] +} +````` + +````` +{"schema":"ripwire.edit-plan/v1","mode":"dry-run","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true,"atomic_scope":"per-file","rollback_on_write_error":true,"recheck_before_each_write":true,"multifile_crash_atomic":false," … [line truncated: 353 more bytes on this line] +````` + +## `./build/ripwire . --edit-plan=/aux/edit_plan.json --apply` + +*The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure.* + +**wall time: 6.87s** + +````` +{"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":2933,"graph_unresolved":15249,"graph_unindexed":269,"counts_floor":true}}]} +````` + +## `./build/ripwire . --edit-plan=/aux/edit_plan.json` + +*Neither --dry-run nor --apply: the mode is explicit, so this refuses.* + +**exit code: 1** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --edit-plan requires exactly one of --dry-run or --apply +````` + +## `./build/ripwire . --quality-delta` + +*After the agent's edits: the complexity/nesting rows on lessByScoreDescId are gone (the replace undid them), the rest still gate (exit 2).* + +**exit code: 2** — **wall time: 23.81s** + +````` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +… [145 more display lines; full output is 17117 bytes on 1 raw line(s)] +````` + +stderr: + +````` +ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: --quality-delta gating: 2 preexisting-worse major finding(s); first: duplication src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey at src/infra/sortutil.h:88 (was=0 now=59) +````` + +## `./build/ripwire . --quality-baseline` + +*REFUSES, exit 1: this sandbox tree is already regressed, and pinning here would swallow that debt into the floor so every later delta read clean. It names how many gating findings it would absorb, the first of them, and the way forward.* + +**exit code: 1** — **wall time: 19.56s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --quality-baseline: this tree already holds 2 gating finding(s) against HEAD — pinning here would absorb + them into the floor, and every later --quality-delta would read clean. First: duplication src/infra/sortutil.h::rw::sortutil::nonNegativeFloatAscKeyCopy | src/infra/sortutil.h::rw::sortutil::nonNegativeFloatDescKey (was=0 now=59) + Commit the tree first, or pass --allow-dirty to pin anyway (the sidecar then records the 2 absorbed, and every + report against it carries baseline_absorbed="2"). +````` + +## `./build/ripwire . --quality-baseline --allow-dirty` + +*The consent form: pin anyway. The sidecar is stamped with the dirty pin and the absorbed count, so the fact outlives the process that knew it.* + +**wall time: 28.37s** + +````` +(empty) +````` + +stderr: + +````` +ripwire: --quality-baseline --allow-dirty: pinned with 2 gating finding(s) ABSORBED into the floor (stamped in the sidecar; every --quality-delta against it carries baseline_absorbed="2") +ripwire: wrote ./.ripwire_quality_baseline (snapshot of 30924 per-symbol rows, 31862 indexed symbols total) +````` + +Artifact written: + +````` + 5234589 .ripwire_quality_baseline +# ripwire quality baseline v6 — regenerate with --quality-baseline; do not hand-edit +producer 2f117b08357d2069e6aa7f22cdc9d010e6bf33bff6cdd6cf3280d637183ba207 +head 0712a5182ef61b6885b76af328cae18e839eb110 +dirty 1 +absorbed 2 +ccx 67c15011ee8b 0 +ccx d19d7c13cbc7 2 +ccx 1f7edbff929e5 10 +ccx 6a732f6699b +````` + +## `./build/ripwire . --quality-delta` + +*Against that sidecar the same tree reads regressions=0 — but baseline_absorbed= is on the root, so this green means clean SINCE THE PIN, never clean. A baseline is a floor YOU chose, and it belongs BEFORE the change.* + +**wall time: 18.92s** + +````` + + +````` + + +--- + +# the MCP dialect — the same verbs over stdio JSON-RPC (one-shot exchange, not a persistent server) + +## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ./build/ripwire --mcp` + +*initialize + tools/list: the manifest an agent host loads at session start — every verb's name, description and input schema.* + +````` +{"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: 738 more bytes on this line] +{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"analyze","description":"Architecture map for a directory: signatures and the call graph for the top symbols. Use when landing cold in a repo or subdir, before reading files; for a task-scoped inventory use 'for', for one symbol's neighborhood find_ … [line truncated: 742 more bytes on this line] +{"name":"rank_by","description":"The SAME architecture map 'analyze' serves, ranked by a different signal instead of plain PageRank. rank_by = pagerank (default, omit it — the CLI's own unbiased --rank-by=pagerank; 'analyze' can rank differently on a tree with uncommitted changes, where it biases … [line truncated: 1077 more bytes on this line] +{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read/write/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] +{"name":"find_referencing_symbols","description":"Direct (1-hop) callers of a symbol, each with a fetch_body handle. For the full transitive blast radius use 'impact', for read/write/import sites 'uses'. JSON {symbol, calledBy, defs, count, hop_tested, hop_untested, declined_calls, counts_floor}; ca … [line truncated: 945 more bytes on this line] +{"name":"grep","description":"Trigram literal search; each hit annotated with its enclosing symbol (which function/class it is in). Hits carry text; enclosing rows a fetch_body handle. pattern = the literal; in=any lifts the span tiering (default: tightest non-empty tier; rest rides as suppressed_co … [line truncated: 837 more bytes on this line] +{"name":"cochange","description":"Files that historically change together with this file — the co-edit partners. Fowler's Shotgun Surgery as change coupling. dep_capable=false means neither side could carry one (sh/md/json/binary), so surprising is undefined rather than informative. file = the fil … [line truncated: 700 more bytes on this line] +{"name":"memory_recall","description":"Most relevant memory notes / docs for a task, full text — the few that matter, not the whole corpus. path = docs/memory dir; task = what you're working on; top_k = docs to return, 1..1000 (default 8), refused outside that band, never clamped; budget_tokens = … [line truncated: 790 more bytes on this line] +{"name":"situational_awareness","description":"The 5 things to know about a diff, as JSON: blast_radius, tests_to_run, forgotten (usual co-change partners missing from this diff), hotspot_alert, modules_touched. forgotten = the Shotgun Surgery check. diff/files optional — defaults to 'git diff HEA … [line truncated: 1297 more bytes on this line] +{"name":"mentions","description":"Docs (markdown plans/designs) that name a code symbol in a backtick. symbol = the code symbol name; limit/offset page the files. An @FILE:LINE line-seed rebinds to the innermost definition enclosing that line and answers for it, disclosing the rebound name as 'sym' … [line truncated: 625 more bytes on this line] +{"name":"for","description":"Task-lens ranked, signatures-only inventory of the building blocks most relevant to a task (cx=complexity, in=reuse-count). task = the task in plain words; budget_tokens = an optional soft row target (the CLI --for --token-budget). The header carries route= (which ranker … [line truncated: 1061 more bytes on this line] +{"name":"lego","description":"Interface-to-impls view for ONE named interface/base: its method contract plus EVERY implementor (own-language only), each with file path. Use when implementing against a KNOWN interface (contrast 'for', which sprays top interfaces for a task). type = interface/base nam … [line truncated: 841 more bytes on this line] +{"name":"owners","description":"Bus-factor: recency-weighted (6-month half-life) author ownership per file. symbol = optional, restricts to the file that defines it; limit/offset page the rows. at= is the commit these numbers were computed at (+dirty = the working tree differed). An @FILE:LINE line- … [line truncated: 879 more bytes on this line] +{"name":"replace_symbol_body","description":"Replace a symbol's ENTIRE definition (signature through closing brace) with new_body — splices over the full def span, preserving every byte outside it verbatim; new_body must be a complete, well-formed definition. One trailing newline folds (trailing_n … [line truncated: 1323 more bytes on this line] +{"name":"insert_before_symbol","description":"Insert text immediately BEFORE a symbol's definition (its first byte); padded to the file's own blank-line seam (separator_padded=N). Same refusal contract as replace_symbol_body (not found / ambiguous / stale index / symlink / concurrent write, file unc … [line truncated: 877 more bytes on this line] +{"name":"insert_after_symbol","description":"Insert text immediately AFTER a symbol's definition (past its final byte, which is preserved exactly); padded to the file's own blank-line seam (separator_padded=N); one trailing newline folds (trailing_newline_folded). Same refusal contract as replace_sy … [line truncated: 878 more bytes on this line] +{"name":"fetch_body","description":"Full (or partial-range) source of a symbol's definition, addressed by the stable `handle` a read verb attached to it (bodies on request, not by default). start_line/end_line are optional, 1-based, INCLUSIVE and BODY-RELATIVE (line 1 = the def's first line), clampe … [line truncated: 1049 more bytes on this line] +{"name":"exemplar","description":"BEFORE writing a function / method / class / struct / interface / variable, get the repo's single best-in-class instance of that kind to imitate — signature AND full body. chosen by ROLE, NEVER by text similarity to your task: candidates are first filtered to cogn … [line truncated: 1375 more bytes on this line] +{"name":"quality_delta","description":"Your PR self-check, run every time you think a change is DONE — pairs with the CLI-only --test-gate (names the tests to run + the untested blast radius; not MCP-exposed) to form the two-step pre-PR gate. Reports ONLY what your working tree made WORSE vs basel … [line truncated: 862 more bytes on this line] +{"name":"quality_baseline","description":"PIN the quality floor: writes .ripwire_quality_baseline stamped with the current git HEAD sha, snapshotting complexity / duplication / dead-code / API surface. Call once at the start of non-trivial work, then quality_delta compares against this pinned floor … [line truncated: 445 more bytes on this line] +{"name":"impact","description":"IS IT SAFE TO CHANGE X? — the TRANSITIVE blast radius of a symbol via calls, nearest first (d= hop depth), then PageRank. Use before modifying or deleting a symbol; it beats find_referencing_symbols (direct callers only), and 'uses' catches the read/write/import sit … [line truncated: 1325 more bytes on this line] +{"name":"uses","description":"The STATICALLY RESOLVABLE use-sites of a symbol, not just calls: role (call | read | write | import | extends), file:line, and enclosing symbol. Use to see the footprint before renaming or changing a name — find_referencing_symbols and impact follow only calls. extern … [line truncated: 1146 more bytes on this line] +{"name":"affected","description":"WHICH TESTS TO RUN for a change — test files that transitively reach the changed files/symbols, ranked by evidence (edited > partner-named > hop distance). files = changed files and/or symbols, comma-separated: each item is tried as an indexed PATH pattern first, … [line truncated: 1238 more bytes on this line] +{"name":"path_between","description":"Does A REACH B, and HOW? — the shortest directed CALL path between two symbols, hop-by-hop. reachable=\"0\" hops=\"0\" is a valid 'not reachable' answer — call edges are name-based, so a missing dynamic/callback edge can hide a real path. Named path_between … [line truncated: 709 more bytes on this line] +{"name":"connect","description":"When a task touches 2..16 named symbols, returns the minimal subgraph RELATING them - terminals, the fewest joining intermediaries (with signatures), and call edges in true direction - finding the shared-caller joins a directed path_between cannot; unrelated symbols … [line truncated: 950 more bytes on this line] +{"name":"explore","description":"ONE-call task orientation: the routed+anchored ranking, full bodies of the top hits, their 1-hop callers, field notes, and tests_to_run — ALL under one deterministic byte budget, in a fixed section order (ranking > bodies > callers > notes > tests) that degrades gr … [line truncated: 2135 more bytes on this line] +{"name":"from_trace","description":"Paste a stack trace / sanitizer report / compiler error and get it mapped onto indexed symbols, ranked INNERMOST-first: the parsed frame map, the ranked suspects' signatures, and the innermost in-corpus symbol's FULL body. Out-of-corpus frames are listed a … [line truncated: 1233 more bytes on this line] +{"name":"edit_check","description":"Just edited a symbol? Did its CONTRACT (param count + publicness) change vs git HEAD, and which 1-hop callers are NOW INCOMPATIBLE with the new arity by fixed-arity evidence (not a guess — every folded definition disagrees)? This is call sites worth OPENING, not … [line truncated: 1908 more bytes on this line] +{"name":"whereis","description":"WHERE DOES THIS CONTENT LIVE? Which branch's tree defines or mentions a symbol, HEAD first, with on-head=0 naming the case this verb exists for: content that lives only on a branch (a finished fix stranded on 1 of 30 refs). Each distinct blob is read once (content-ad … [line truncated: 1475 more bytes on this line] +{"name":"stray_content","description":"Per branch: the lines its own divergent work AUTHORED (vs its merge-base with HEAD) that the live line does NOT have. Four verdicts (unmerged+superseded+merged+unknown=refs): v=unmerged is genuinely absent; v=superseded means the live line re-implemented the wo … [line truncated: 1123 more bytes on this line] +{"name":"flags","description":"WHAT IS BUILT BUT DARK here — the answer to 'why don't I see feature X?'. Harvests all three gate patterns (ifndef/define header gates, CMake option(), getenv reads) with each gate's kind, DEFAULT, the size of the code it guards, and its read sites. When a name is bo … [line truncated: 1434 more bytes on this line] +{"name":"doc_drift","description":"WHICH OF THIS REPO'S DOC CLAIMS ARE NOW FALSE. Verifies the CHECKABLE anchors in every markdown file against the live index and returns ONLY the ones that no longer hold: file:line refs (missing-file / past-eof / line-moved), backticked symbol mentions (undefined), … [line truncated: 1167 more bytes on this line] +{"name":"slice","description":"WHERE IS THIS VARIABLE DEFINED AND USED inside one function — NAME-BASED intra-procedural def-use rows of one variable inside ONE uniquely-resolved definition (the ARISE slicer, arXiv:2605.03117). symbol alone lists the sliceable locals to pick from; add var (or spel … [line truncated: 1722 more bytes on this line] +{"name":"batch","description":"ONE-TURN CONTEXT SWEEP: answer up to 16 heterogeneous READ sub-queries in a single call (the deterministic $0 counterpart of a parallel-search agent). queries = array over the SAME path, in EITHER grammar: {verb, ...args} objects, or the CLI --batch file's own \"verb:a … [line truncated: 2040 more bytes on this line] +````` + +The manifest, summarised (name / description bytes / required args) — what the host pays in context every session: + +````` +tools= 33 manifest_bytes= 47445 (~tokens at 4 bytes/token: 11861 ) +explore desc_bytes= 1340 schema_bytes= 958 required=['task'] +batch desc_bytes= 1235 schema_bytes= 962 required=['queries'] +edit_check desc_bytes= 1180 schema_bytes= 889 required=['symbol'] +slice desc_bytes= 953 schema_bytes= 932 required=['symbol'] +whereis desc_bytes= 701 schema_bytes= 941 required=['symbol'] +flags desc_bytes= 881 schema_bytes= 720 required=[] +exemplar desc_bytes= 954 schema_bytes= 591 required=[] +replace_symbol_body desc_bytes= 865 schema_bytes= 610 required=['symbol', 'new_body'] +impact desc_bytes= 821 schema_bytes= 666 required=['symbol'] +situational_awareness desc_bytes= 865 schema_bytes= 581 required=[] +affected desc_bytes= 790 schema_bytes= 610 required=['files'] +from_trace desc_bytes= 836 schema_bytes= 559 required=['trace'] +find_symbol desc_bytes= 752 schema_bytes= 590 required=['symbol'] +doc_drift desc_bytes= 728 schema_bytes= 604 required=[] +uses desc_bytes= 626 schema_bytes= 682 required=['symbol'] +stray_content desc_bytes= 678 schema_bytes= 604 required=[] +rank_by desc_bytes= 758 schema_bytes= 481 required=[] +for desc_bytes= 453 schema_bytes= 777 required=['task'] +fetch_body desc_bytes= 623 schema_bytes= 588 required=['handle'] +connect desc_bytes= 535 schema_bytes= 580 required=['symbols'] +find_referencing_symbols desc_bytes= 505 schema_bytes= 590 required=['symbol'] +insert_after_symbol desc_bytes= 458 schema_bytes= 577 required=['symbol', 'text'] +insert_before_symbol desc_bytes= 455 schema_bytes= 578 required=['symbol', 'text'] +owners desc_bytes= 425 schema_bytes= 625 required=[] +quality_delta desc_bytes= 742 schema_bytes= 279 required=[] +lego desc_bytes= 360 schema_bytes= 651 required=['type'] +grep desc_bytes= 445 schema_bytes= 562 required=['pattern'] +memory_recall desc_bytes= 447 schema_bytes= 500 required=['task'] +path_between desc_bytes= 357 schema_bytes= 506 required=['from', 'to'] +cochange desc_bytes= 388 schema_bytes= 476 required=['file'] +analyze desc_bytes= 546 schema_bytes= 318 required=[] +mentions desc_bytes= 305 schema_bytes= 486 required=['symbol'] +quality_baseline desc_bytes= 407 schema_bytes= 193 required=[] +````` + +## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ./build/ripwire --mcp --mcp-tools=core` + +*--mcp-tools=core: the server lists only the core profile's tools (explore, batch, from_trace, impact, uses, fetch_body, edit_check, quality_delta), so a host that loads every schema at session start pays only for those.* + +````` +{"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: 955 more bytes on this line] +{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"fetch_body","description":"Full (or partial-range) source of a symbol's definition, addressed by the stable `handle` a read verb attached to it (bodies on request, not by default). start_line/end_line are optional, 1-based, INCLUSIVE and BODY-RELAT … [line truncated: 1092 more bytes on this line] +{"name":"quality_delta","description":"Your PR self-check, run every time you think a change is DONE — pairs with the CLI-only --test-gate (names the tests to run + the untested blast radius; not MCP-exposed) to form the two-step pre-PR gate. Reports ONLY what your working tree made WORSE vs basel … [line truncated: 862 more bytes on this line] +{"name":"impact","description":"IS IT SAFE TO CHANGE X? — the TRANSITIVE blast radius of a symbol via calls, nearest first (d= hop depth), then PageRank. Use before modifying or deleting a symbol; it beats find_referencing_symbols (direct callers only), and 'uses' catches the read/write/import sit … [line truncated: 1325 more bytes on this line] +{"name":"uses","description":"The STATICALLY RESOLVABLE use-sites of a symbol, not just calls: role (call | read | write | import | extends), file:line, and enclosing symbol. Use to see the footprint before renaming or changing a name — find_referencing_symbols and impact follow only calls. extern … [line truncated: 1146 more bytes on this line] +{"name":"explore","description":"ONE-call task orientation: the routed+anchored ranking, full bodies of the top hits, their 1-hop callers, field notes, and tests_to_run — ALL under one deterministic byte budget, in a fixed section order (ranking > bodies > callers > notes > tests) that degrades gr … [line truncated: 2135 more bytes on this line] +{"name":"from_trace","description":"Paste a stack trace / sanitizer report / compiler error and get it mapped onto indexed symbols, ranked INNERMOST-first: the parsed frame map, the ranked suspects' signatures, and the innermost in-corpus symbol's FULL body. Out-of-corpus frames are listed a … [line truncated: 1233 more bytes on this line] +{"name":"edit_check","description":"Just edited a symbol? Did its CONTRACT (param count + publicness) change vs git HEAD, and which 1-hop callers are NOW INCOMPATIBLE with the new arity by fixed-arity evidence (not a guess — every folded definition disagrees)? This is call sites worth OPENING, not … [line truncated: 1908 more bytes on this line] +{"name":"batch","description":"ONE-TURN CONTEXT SWEEP: answer up to 16 heterogeneous READ sub-queries in a single call (the deterministic $0 counterpart of a parallel-search agent). queries = array over the SAME path, in EITHER grammar: {verb, ...args} objects, or the CLI --batch file's own \"verb:a … [line truncated: 2040 more bytes on this line] +````` + +The core manifest, summarised (name / description bytes / required args): + +````` +tools= 8 manifest_bytes= 14186 (~tokens at 4 bytes/token: 3546 ) +explore desc_bytes= 1340 schema_bytes= 958 required=['task'] +batch desc_bytes= 1235 schema_bytes= 962 required=['queries'] +edit_check desc_bytes= 1180 schema_bytes= 889 required=['symbol'] +impact desc_bytes= 821 schema_bytes= 666 required=['symbol'] +from_trace desc_bytes= 836 schema_bytes= 559 required=['trace'] +uses desc_bytes= 626 schema_bytes= 682 required=['symbol'] +fetch_body desc_bytes= 623 schema_bytes= 588 required=['handle'] +quality_delta desc_bytes= 742 schema_bytes= 279 required=[] +````` + +## `printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"for","arguments":{"path":".","task":"pagerank power iteration"}}}' | ./build/ripwire --mcp` + +*MCP `for`: always bundle=sigs (never the CLI's compact route), the same ranked signatures as --for.* + +**wall time: 3.85s** + +````` +{"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: 738 more bytes on this line] +{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":". window: shown= capped= (capped=1 cut). at=: commit+dirty+shallow. next= … [line truncated: 6553 more bytes on this line] +"_index":"[index: files=3631 symbols=31860 hash=2da1730f]","_fresh":"ok"}} +{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"

@@ -3074,7 +3079,7 @@ _OWNERSHIP partition for a shared tree: every regression here lives in src/infra ``` $ ./build/ripwire . --quality-delta --scope=src/graph.h - @@ -3104,10 +3109,10 @@ _Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree ``` $ ./build/ripwire . --edit-check=rankGraphTeleport - - - + + @@ -3158,12 +3163,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ``` ### `--insert-after-symbol=TARGET` @@ -3179,12 +3184,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ``` **Caveats (stated by the binary):** @@ -3230,12 +3235,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ``` **Shaped by:** `--insert-after-symbol` @@ -3294,11 +3299,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":2932,"graph_unresolved":15244,"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":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true}}]} ``` **Shaped by:** `--edit-check` @@ -3344,19 +3349,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 +3386,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 +3440,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 +3467,7 @@ _No-LLM review-evidence bundle for the working-tree diff (clean tree = empty)._ ``` $ ./build/ripwire . --pr-context - ``` @@ -3488,11 +3493,11 @@ _Pairwise cross-arm conflict sites + suggested landing order (any committish sha ``` $ ./build/ripwire . --merge-scout=HEAD~2,HEAD~1 - - + + - + @@ -3567,7 +3572,7 @@ _Which refs of the `lane/` ref family still hold divergent authored work vs HEAD ``` $ ./build/ripwire . --stray-content=lane/ - + @@ -3601,7 +3606,7 @@ _Select the genuinely-unmerged refs of the `lane/` ref family and feed them to m ``` $ ./build/ripwire . --stray-content=lane/ --plan - + @@ -3637,20 +3642,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 +3677,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 +3707,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 +3735,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 +3767,7 @@ _The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gat $ ./build/ripwire . --flags - + @@ -3843,7 +3848,7 @@ _The cache-locality lens over every aggregate: fields READ TOGETHER but declared ``` $ ./build/ripwire . --field-affinity - @@ -3878,7 +3883,7 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - + @@ -3912,7 +3917,7 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - + @@ -3945,8 +3950,8 @@ _Same report, with git history splitting stale mentions into deleted-by-commit v ``` $ ./build/ripwire . --doc-drift --with-history - - + + @@ -3979,7 +3984,7 @@ _The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when ``` $ ./build/ripwire . --plan-lint=test/planlintfix/wave.md - + @@ -4014,8 +4019,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 +4049,7 @@ _A command that exits 0: a minimal success record (exit, measured duration, disc $ ./build/ripwire . --run-trace="true" - + ``` @@ -4204,7 +4209,7 @@ _Task lens + a compact Mermaid flowchart of the top anchors' 1-hop edges._ ``` $ ./build/ripwire . --for="pagerank power iteration" --with-graph - + @@ -4277,14 +4282,14 @@ _Environment self-check: binary staleness, grammars, cache dir, git, tracked-bin ``` $ ./build/ripwire . --doctor - - + - - + + - - + @@ -4311,14 +4316,14 @@ _--doctor plus a LIVE integration inspection for one agent: PATH binary, install ``` $ ./build/ripwire . --doctor --agent=claude - - + - - + + - - + @@ -4346,7 +4351,7 @@ $ ./build/ripwire . --skipped - @@ -4434,8 +4439,8 @@ _Rank by git change-frequency prior instead of PageRank._ $ ./build/ripwire . --rank-by=churn --top-k=5 - - + + @@ -4467,22 +4472,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~6 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3 - - - - - - - - - - - - -... [18 more line(s); run it to see the whole thing] + + + + + + + + + + + + +... [8 more line(s); run it to see the whole thing] ``` **Shaped by:** `--external-surface`, `--doctor`, `--legend`, `--max-memory` @@ -4544,7 +4549,7 @@ _The same gating report under --legend=full — same rows, same exit 2; the defa ``` $ ./build/ripwire . --quality-delta --legend=full - @@ -4625,7 +4630,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -4661,7 +4666,7 @@ _Drop matching paths (repeatable) before ranking._ $ ./build/ripwire . --exclude=present --exclude=bench --top-k=5 - + @@ -4692,8 +4697,8 @@ _Full map re-ranked with teleport toward git-changed files — clean tree, so ch $ ./build/ripwire . --map-diff --top-k=5 - - + + @@ -4726,7 +4731,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 +4781,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 +4812,7 @@ _Crawl paths the repo's own .gitignore covers (default honours it and discloses $ ./build/ripwire . --no-ignore --top-k=3 - + @@ -4843,10 +4848,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 +4928,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 +4983,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":" - + @@ -63,12 +63,12 @@ *Same map, capped to the 5 highest-ranked symbols.* -**wall time: 3.58s** +**wall time: 4.11s** ````` - + @@ -87,7 +87,7 @@ - + @@ -103,12 +103,12 @@ *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: 2.14s** +**wall time: 6.87s** ````` - + @@ -134,14 +134,14 @@ *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.83s** +**wall time: 6.35s** ````` - + @@ -211,7 +211,7 @@ ripwire: --top-k=0 means "no ranked map, payload only" — pass a payload verb ( *GATE form: exit 3 if the map's own est_tokens exceeds the budget (over-budget failure shape).* -**exit code: 3** — **wall time: 1.91s** +**exit code: 3** — **wall time: 9.59s** ````` @@ -228,16 +228,16 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *The task lens: ranked signatures + quality metrics framed for the task.* -**wall time: 6.50s** +**wall time: 25.90s** ````` - - - + + 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] @@ -248,36 +248,36 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 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 20072 bytes on 8 raw line(s)] +… [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: 7.04s** +**wall time: 18.76s** ````` - + - + 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` @@ -287,8 +287,8 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 - - + + @@ -299,7 +299,7 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 - + & p, float alpha = 0.85f ) … [28 more display lines; full output is 5868 bytes on 29 raw line(s)] ````` @@ -308,23 +308,23 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *Same query with routing forced OFF (plain subtoken+body BM25) — contrast with the routed run.* -**wall time: 5.99s** +**wall time: 24.05s** ````` - + - + 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 ) +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 ) @@ -337,9 +337,9 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 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 +#### 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)] ````` @@ -348,16 +348,16 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *T3 opt-out: the signatures-only lens (no auto bodies, no bundle="auto" attribute) — contrast with the terminal default above.* -**wall time: 7.62s** +**wall time: 16.52s** ````` - + - + 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` @@ -372,25 +372,25 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *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: 8.70s** +**wall time: 18.76s** ````` - + 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -403,7 +403,7 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 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 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)] ````` @@ -412,10 +412,10 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *Mention anchoring (default-on): a path and a Symbol literally named in the task get lifted; the header says what anchored.* -**wall time: 10.07s** +**wall time: 18.32s** ````` - @@ -441,21 +441,21 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 inline constexpr int kLexWeightDoc = 2 struct CandidateProvenance inline std::vector<float> lexicalScoresNameExact( const IngestResult& ing, std::string_view query ) -inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) -std::optional<int> runEvalViews( const MainDispatch& d ) +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)] +… [146 more display lines; full output is 21527 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: 10.87s** +**wall time: 15.74s** ````` - @@ -481,8 +481,8 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 inline constexpr int kLexWeightDoc = 2 struct CandidateProvenance inline std::vector<float> lexicalScoresNameExact( const IngestResult& ing, std::string_view query ) -inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) -std::optional<int> runEvalViews( const MainDispatch& d ) +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)] @@ -492,12 +492,12 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *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: 2.77s** +**wall time: 3.24s** ````` - + @@ -510,12 +510,12 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *The repo's best-in-class instance to imitate before writing new code (picked by ROLE).* -**wall time: 6.07s** +**wall time: 5.91s** ````` - + budget=100 *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: 5.29s** +**wall time: 4.53s** ````` @@ -551,7 +551,7 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *The honest half of the contract: a task with no ripwire-shaped evidence ABSTAINS with zero commands rather than guessing.* -**wall time: 3.66s** +**wall time: 5.59s** ````` @@ -564,12 +564,12 @@ ripwire: --token-budget exceeded: withheld_est_tokens=10709 > budget=100 *Most relevant DOCS' full bodies (markdown only) — recall what is already written down.* -**wall time: 2.54s** +**wall time: 2.61s** ````` -ripwire recall — "quality delta gating exit codes" — 121 relevant of 268 document files, best-first — total=121 shown=8 capped=1 truncated=6 generated_demoted=3 max_tokens=8000 share_bytes=2468 est_tokens=4165 +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.095) ━━ [sections: 2 of 25 selected (60 in doc), section-granular; whole doc 222723 B; lines="2747-2759,2760-2767"; dropped_by_budget=23] +━━ 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. @@ -593,7 +593,7 @@ refuses by default. -━━ CHANGELOG.md (relevance 7.522) ━━ [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] +━━ CHANGELOG.md (relevance 7.519) ━━ [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 @@ -602,17 +602,38 @@ A tripped memory guard in the range form used to give exit 5 and nothing, so on ## `./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 1360588-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.* +*The directory-as-knowledge-base pattern: --recall pointed at a 1356233-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 +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=952 + +━━ commands.md (relevance 11.026) ━━ [sections: 1 of 164 selected (192 in doc), section-granular; whole doc 589285 B; lines="556-581"; dropped_by_budget=163] [truncated: 1854 of 4257 bytes] +#### Pattern: a directory of dumped tool output as a knowledge base -━━ 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] -### `--field-affinity[=STRUCT]` +**Answers:** can `--recall` serve as a zero-setup knowledge base over dumped tool output — a +`git log`, an API response dump, a fetched doc, ` --help` text — sitting in a scratch +directory, instead of a source repo? -**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. +Yes, unmodified. `--recall` never distinguishes "a codebase" from any other directory it can +walk: point it at the scratch dir and query it. No index to build, no daemon, no mutable store +between runs — the whole cost is one cold parse. Two conditions decide whether it works at all, +and both are yours, because the file you write is the only thing that sets them: -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] +1. **Dump to `.md`.** `--recall` ranks DOCUMENT files: `.md`, plus the docparse'd + `.ipynb`/`.html`/`.csv` (and Office/PDF through the optional markitdown bridge). `.txt`, + `.log`, `.json` and extensionless files are **not** documents to it. A directory of those + answers `0 relevant of 0 document files` and exits 0 — which reads like "nothing matched + your terms" when what happened is "nothing was indexed at all". Redirect to `notes.md`, + never `notes.txt`. The recorded run below is that rule's own demonstration: its scratch dir + holds five dumps, and the header says `2 relevant of 2 document files` because only the two + `.md` ones are documents — the `git log`, the `--help` text and the JSON access log are not + in the population at all. + +2. **Keep `##` headings in the dump.** A headed document is served as whole ranked SECTIONS, so + an answer buried mid-file arrives at a small `--max-tokens`, and — while the served document + SET stays fixed — a larger ceiling returns a strict superset of it; the `[sections: S of R + selected (N in doc) … lines="…"; dropped_by_budget=D]` note names the ranges you actually got + and what the ceiling cost. … (capped: 1 of 2 relevant document files omitted — raise --max-tokens/budget_tokens or narrow the query for 1 more (~2548-byte budget)) ````` @@ -627,11 +648,11 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas *File-by-file orientation map (top symbols per file).* -**wall time: 1.58s** +**wall time: 1.99s** ````` - + @@ -640,7 +661,7 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas - + @@ -667,7 +688,7 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas *Self-contained HTML force-directed call graph.* -**wall time: 6.95s** +**wall time: 9.76s** ````` (empty) @@ -676,14 +697,14 @@ ripwire: redacted 1 secret from emitted context (keyword-gated-secret=1) — pas Artifact written: ````` - 156166 /aux/map2.html + 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: 2.28s** +**wall time: 2.84s** ````` @@ -706,7 +727,7 @@ Artifact written: - + @@ -728,13 +749,13 @@ Artifact written: *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.37s** +**wall time: 2.41s** ````` - + @@ -768,14 +789,14 @@ Artifact written: *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.53s** +**wall time: 1.84s** ````` - - + + @@ -801,20 +822,20 @@ Artifact written: -… [1950 more display lines; full output is 53230 bytes on 1 raw line(s)] +… [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.81s** +**wall time: 3.02s** ````` - + @@ -857,14 +878,14 @@ Artifact written: *Who calls SYM (1-hop in-edges).* -**wall time: 1.39s** +**wall time: 2.81s** ````` - + - - + + @@ -876,15 +897,15 @@ Artifact written: *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.* -**wall time: 1.42s** +**wall time: 3.66s** ````` - + - - + + @@ -896,7 +917,7 @@ Artifact written: *Unknown-symbol REFUSAL shape (exit 1) with a did-you-mean from real edit distance.* -**exit code: 1** — **wall time: 5.16s** +**exit code: 1** — **wall time: 6.80s** ````` @@ -913,22 +934,22 @@ ripwire: --callers symbol not found: DoesNotExist *What SYM calls (1-hop out-edges).* -**wall time: 1.74s** +**wall time: 3.40s** ````` - - + + - - - - - - + + + + + + ````` @@ -936,14 +957,14 @@ ripwire: --callers symbol not found: DoesNotExist *The resolvable use-sites (call/read/write/import/extends) with file:line; count= is a floor.* -**wall time: 2.39s** +**wall time: 3.51s** ````` - + - - + + @@ -957,17 +978,17 @@ ripwire: --callers symbol not found: DoesNotExist *Composable node-set query: functions within 2 caller-hops of rankGraphTeleport.* -**wall time: 2.09s** +**wall time: 3.01s** ````` - + - + - + @@ -997,38 +1018,38 @@ ripwire: --callers symbol not found: DoesNotExist *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: 2.76s** +**wall time: 4.09s** ````` - - - - - - - + + + + + + + - + - - - + + + - + - - + + - + … [73 more display lines; full output is 5604 bytes on 1 raw line(s)] ````` @@ -1037,39 +1058,39 @@ ripwire: --callers symbol not found: DoesNotExist *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: 2.80s** +**wall time: 3.47s** ````` - - - - + + + + - - + + - - - - + + + + - + - - - + + + - + … [73 more display lines; full output is 5478 bytes on 1 raw line(s)] ````` @@ -1077,16 +1098,16 @@ ripwire: --callers symbol not found: DoesNotExist *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: 3.22s** +**wall time: 2.44s** ````` - + - + ````` @@ -1094,14 +1115,14 @@ ripwire: --callers symbol not found: DoesNotExist *Minimal connecting subgraph over 3 symbols (finds shared-caller joins).* -**wall time: 2.79s** +**wall time: 4.40s** ````` - + - + @@ -1113,7 +1134,7 @@ ripwire: --callers symbol not found: DoesNotExist *Transitive blast radius — everything that reaches SYM. NOW carries shown/capped.* -**wall time: 6.50s** +**wall time: 6.68s** ````` @@ -1135,8 +1156,8 @@ ripwire: --callers symbol not found: DoesNotExist - - + + @@ -1153,7 +1174,7 @@ ripwire: --callers symbol not found: DoesNotExist *Markdown docs that name SYM in a backtick (doc<->code edges).* -**wall time: 4.75s** +**wall time: 4.58s** ````` @@ -1172,11 +1193,11 @@ ripwire: --callers symbol not found: DoesNotExist *Test files that transitively reach the changed file.* -**wall time: 4.71s** +**wall time: 3.17s** ````` - @@ -1191,12 +1212,12 @@ ripwire: --callers symbol not found: DoesNotExist *Mid-task situational report for the current git diff — recorded against a CLEAN tree (contrast with the sandbox run below).* -**wall time: 7.67s** +**wall time: 8.52s** ````` ripwire situational-awareness — 0 changed file(s), 0 symbols in them root: . -at: d3605fde7 +at: 79e691876 (0 changed files — working tree is clean, nothing to analyze) ````` @@ -1204,11 +1225,11 @@ at: d3605fde7 *Pre-PR gate on a CLEAN tree: no obligations, exit 0.* -**wall time: 10.09s** +**wall time: 11.88s** ````` - ````` @@ -1216,7 +1237,7 @@ at: d3605fde7 *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: 3.00s** +**wall time: 3.84s** ````` @@ -1399,11 +1420,11 @@ at: d3605fde7 *The same shape query WITH an explicit capture — identical hits, no auto_captured= attribute.* -**wall time: 3.61s** +**wall time: 3.67s** ````` -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 @@ -1439,20 +1460,20 @@ at: d3605fde7 *Raw BM25 ranking (debug lens; --for is the real verb).* -**wall time: 3.93s** +**wall time: 3.80s** ````` - + - + - + @@ -1463,12 +1484,12 @@ at: d3605fde7 - + - + @@ -1484,10 +1505,10 @@ at: d3605fde7 *Importance-weighted detail: FULL bodies for top-2, signatures for the rest.* -**wall time: 6.50s** +**wall time: 9.41s** ````` - + @@ -1498,14 +1519,14 @@ at: d3605fde7 The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) -struct RankedGraph +struct RankedGraph 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… inline std::uint32_t sliceRdIterationCeiling() noexcept struct PageRankRun What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure -inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept -inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept inline std::string powerShellSingleQuote( std::string_view s ) noexcept @@ -1524,14 +1545,14 @@ at: d3605fde7 *Body-elided decl skeletons — recounted on this corpus. Measured as element bytes: the signature+doc elements --pack-signatures emits, against the SAME symbols' full bodies from --expand, with the CORPUS-ROOT PREFIX SUBTRACTED FROM BOTH SIDES. That subtraction is the whole methodology and the figure is meaningless without it: the root repeats inside every element's id= and p=, it is not what this verb elides, and counting it makes the headline a function of how deep the checkout happens to sit on disk — on one corpus, three spellings of the same root read 18.6 points apart before the subtraction and agree exactly after it. Root-neutralised on THIS repo: 88.8% fewer bytes at top-10, 86.2% at top-50, 87.4% at top-100 (re-derived 2026-10-10 when the C++ standard-member gate stopped std::vector/std::string calls such as out.push_back() and s.empty() from binding to in-tree namesakes by name: the ranked top-10/50 lost one-line container accessors (svector::push_back, WidePath::c_str, every empty) and gained one-line forwarding helpers and macros (kindIs, ASSUME, formatTo, emitTo) whose signature is nearly the whole body, so less of the set is elidable, from 92.7/88.7/87.6; before that, re-derived 2026-09-20 when the native Windows port landed: src/infra/os_win32.cpp and os_win32_logic.h are ~3,900 lines of new, heavily commented infra that the ranked top-10/50/100 now reach, and their bodies are this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new, from top-50 87.1. Measured by test/showcasecapturecheck.sh's own recount arm on the combined tree, which is the gate that would otherwise report the drift; before that, re-derived 2026-09-17 at the self-check macro vocabulary rename: VERIFY/VERIFY_TEXT/VERIFY_DEBUG_ONLY/VERIFY_NOT_REACHED/VERIFY_SAME_THREAD/VERIFY_NO_ALIAS*/DYNMAP_VERIFY/DEGRADED_PATH_ALERT renamed to ASSUME/EXPECTS/ENSURES/DASSERT/UNREACHABLE/ASSUME_SAME_THREAD*/ASSUME_NO_ALIAS*/DYNMAP_ASSUME/DISCLOSE (plus new VALIDATE sites) across 839 identifier renames in 179 files, and a hand-written Diagnostics.h/diagnostics.cpp replacing the old ones outright: this moves both WHICH symbols the ranked top-10/50/100 hold and how large their bodies are, from top-50 85.2. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-12 when the rows dropped the path-repeating id= for the short sc= scope: the signature side shrank, the bodies did not; before that, 89.5% / 81.8% / 84.3% re-derived 2026-09-10 at the sibs= cap raise: kMaxExpandSibs went 8 -> 100, so --expand's bodies now carry the file context the old cap hid — 89.3% of all sibling names — and the body side is this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new. Measured on a fixed tree with the top-50 membership and the signature side unchanged: top-50 from 71.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-09 at the printf-family -> std::print conversion: converting ~1,500 emitter call sites to rw::emitTo/emitRaw/formatTo across 93 files changes how large the ranked symbols' BODIES are, and the body side is this ratio's denominator — top-50 from 72.3. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-08 at the confident-zero round, issues #62/#63/#66: that change adds symbols to src/graphlegend.h and the new src/preprocdead.h and re-homes two long comment blocks from call sites onto the helpers they explain, which moves both WHICH symbols the ranked top-50 holds and how large their bodies are — top-50 from 74.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-06 at the stranger-audit fix round: the doctor, cache-sweep and html-provenance bodies grew this corpus's BODY side, moving top-50 from 75.6 — a real re-derivation, not a tolerance edit; before that, re-derived 2026-09-05 at the capture-audit close: lane L7's P16 caps --expand's sibs= at 8 names, which SHRINKS the body side of this ratio and moved the figure down from 84.5/80.2/80.6 — the V1 2026-08-15 re-center, when sibs=/inc= first grew the body side from 70.0/61.0/63.8, in reverse; both were real re-derivations, not tolerance edits). top-50 is the number to quote, because the sigs payload is top-50 regardless of --top-k and is therefore what THIS command emits. A single small/trivial body can still invert it (signature+doc bigger than the body), like the --format=columnar sibling below. test/showcasecapturecheck.sh (C) re-derives all three from this repo every run, in the same quantity, and fails if the caption and the recount drift apart.* -**wall time: 2.22s** +**wall time: 2.59s** ````` - + @@ -1564,14 +1585,14 @@ at: d3605fde7 *Control-flow skeleton of one symbol, payload-only via the new --top-k=0.* -**wall time: 1.72s** +**wall time: 3.04s** ````` - + & p, float alpha = 0.85f ) { PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); @@ -1595,14 +1616,14 @@ at: d3605fde7 *CHANGED: a line range on --outline is now STRIPPED with a stderr note (it used to refuse).* -**wall time: 1.73s** +**wall time: 3.87s** ````` - + & p, float alpha = 0.85f ) { PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); @@ -1632,14 +1653,14 @@ ripwire: --outline=rankGraphTeleport:1-10: --outline has no line-range form — *Full body + inline callee signatures.* -**wall time: 1.94s** +**wall time: 2.86s** ````` - + : files the ranked rows show / do not (sum = files=), each named or counted below. : a program entry by its language's convention (C/Go/Rust main, Java/C# static main, a script main its module scope calls, __main__.py), callees as c rows; manifest entries not read. : n= unshown files under dir p=; f= names its code files, the rest (tests, docs, config, test/doc/example dirs) counted. declined=K: K call sites without edges, including inert Elixir quote sites after unquote/unquote_splicing re-entry. external=K: K calls proven outside the tree, no edge. locality_pinned=K: K calls pinned by locality alone (a guess). extent_suspect_syms=K: K defs failed containment, corpus-wide. macro_blanked_files=K: K files indexed from a macro-blanked re-parse. prov=scip|binding|import|split|final-segment: how that edge bound (absent: one unique name); split = one arm of an amb= pick; final-segment = a qualified type matched by last name only. files=/symbols=: files and symbols indexed; edges= distinct call edges; shown= symbols printed, a merged row counting each def; ambiguous= calls split over several defs, corpus-wide; unresolved= calls with in-tree evidence and no edge (every def language-filtered or unreachable, or binding refused); order= rows by rank (important-first, important-last; (auto:fill) = flipped past a size threshold) or by path (stable). skipped_oversize=K: K files over a size ceiling, not indexed. unindexed=ext:N: N text files of that extension no grammar reads (6 extensions at most). unindexed_exts=E: E such extensions in all, the list cut. : a non-test row an indexed test transitively reaches (absent otherwise, never 0). : that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= lcom4= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, class cohesion, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> - + - + @@ -1872,12 +1893,12 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *File->file dependency graph (god-files, cycles).* -**wall time: 2.13s** +**wall time: 1.76s** ````` - + @@ -1912,15 +1933,15 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Complexity x recent git churn (maintenance pain).* -**wall time: 4.61s** +**wall time: 6.80s** ````` - - + + - + @@ -1929,9 +1950,9 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + - + @@ -1952,11 +1973,11 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Token-normalized duplicate bodies.* -**wall time: 3.68s** +**wall time: 3.55s** ````` - + @@ -1966,7 +1987,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + @@ -1981,7 +2002,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + @@ -1992,40 +2013,40 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Files that change together in git (hidden coupling).* -**wall time: 6.62s** +**wall time: 7.39s** ````` - + - - - - - + + + - - - - - + + - - + - + + + + + + - + + - - + + ````` @@ -2034,14 +2055,14 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Hotspots scoped to RECENT churn (the regression lens).* -**wall time: 8.76s** +**wall time: 8.97s** ````` - - + + - + @@ -2049,24 +2070,24 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + - + - + - + + - … [13 more display lines; full output is 5130 bytes on 1 raw line(s)] ````` @@ -2074,12 +2095,12 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *Enforce layering rules (exit 2 on violation) — run against the repo's own test fixture rules.* -**wall time: 1.64s** +**wall time: 1.99s** ````` - @@ -2107,18 +2128,18 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan -… [1041 more display lines; full output is 153822 bytes on 1 raw line(s)] +… [1046 more display lines; full output is 154548 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --lint` *Built-in AST checks (c-cast, goto, unsafe-c-fn, ...).* -**wall time: 2.93s** +**wall time: 3.58s** ````` - + @@ -2134,7 +2155,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan - + @@ -2154,7 +2175,7 @@ ripwire: --pack-top-n is deprecated — use --pack-task/--detail instead (unchan *User lint rules (YAML, ast-grep style) from a directory.* -**wall time: 2.13s** +**wall time: 1.51s** ````` @@ -2181,8 +2202,6 @@ ripwire: AST query did not compile for any grammar: (this_is_not_a_real_node @x *Join MEASURED heat onto --lint findings — runs in a tiny fabricated demo corpus (one cache-pointer-chase-loop finding under a PROFILE_SCOPE site) because a real report needs a RIPWIRE_PROFILE build; the finding inside the profiled scope gains heat_* columns from the report's #PROF_TSV row.* -**wall time: 1.89s** - Input file: ````` @@ -2236,59 +2255,59 @@ The joined finding — past the display cut above, extracted so the join is visi *Cluster the call graph into cohesive modules.* -**wall time: 3.09s** +**wall time: 1.50s** ````` - + - + - + - + - + - + -… [189 more display lines; full output is 16914 bytes on 1 raw line(s)] +… [189 more display lines; full output is 16947 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --zoom` *Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels_shown="2" of levels= BY DEFAULT over the 40 largest top modules (~8 KB, where the whole tree is ~220 KB); a module AT the cut carries children=.* -**wall time: 2.05s** +**wall time: 1.82s** ````` - - + + - - + + - + @@ -2299,16 +2318,16 @@ The joined finding — past the display cut above, extracted so the join is visi - - + + - - + + … [135 more display lines; full output is 7291 bytes on 1 raw line(s)] ````` @@ -2316,72 +2335,72 @@ The joined finding — past the display cut above, extracted so the join is visi *The restoring knob: --zoom-levels=N prints N levels (0 = the whole tree); here three, ~11 KB.* -**wall time: 1.68s** +**wall time: 2.06s** ````` - - - + + + - + - + - + - + - + - + - + - + - + -… [273 more display lines; full output is 12337 bytes on 1 raw line(s)] +… [271 more display lines; full output is 12259 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --report` *Architecture summary (modules, god-files, cycles) as markdown.* -**wall time: 1.68s** +**wall time: 1.26s** ````` # ripwire architecture report -3618 files · 31790 symbols · 29969 edges · 3610 modules (14921 call-graph isolated) +3627 files · 31838 symbols · 30013 edges · 3619 modules (14940 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, 3382 source, 5130 document; 0 connected Louvain singletons -## Modules (call-graph clusters; showing 12 of 3610) +## Modules (call-graph clusters; showing 12 of 3619) - **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1631 symbols -- **src::kindIs@infra/nodekind.h:46:3271 [push,emit,collect]** — 547 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 - **docs::`--top-k=N`@COMMANDS.md:59:9077 [pack,allow,insert]** — 181 symbols - **test/ownerhopfix/py/pkg::big_handler_001@broadcast.py:3:72** — 106 symbols +- **src::buf@infra/svector.h:125:8942 [insert,find,push]** — 91 symbols - **src/infra::fail@os_win32.cpp:63:2553 [open,get,close]** — 89 symbols - **test::no@estchargecheck.sh:52:4108 [skip,set]** — 63 symbols - **src::child@ingest_valuerefs.h:656:33874 [emit,resolve,open]** — 62 symbols -- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 54 symbols +- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 55 symbols - **src::sliceKindIs@slice.h:368:24239 [match,collect,push]** — 48 symbols - **src/infra::DYNMAP_ASSUME@dynamic_map.hpp:90:4411 [insert,erase,find]** — 44 symbols -- **src::tokText@defectshape.h:128:5308 [scan,find,join]** — 41 symbols ## God files (most depended-on; showing 10 of 230) - `src/model.h` — 105 dependents @@ -2389,18 +2408,16 @@ Call-graph isolate provenance: 3976 declaration, 2448 header, 3371 source, 5126 - `src/infra/Diagnostics.h` — 65 dependents - `src/graph.h` — 47 dependents - `src/serialize.h` — 45 dependents -… [35 more lines, 4007 bytes total] +… [35 more lines, 3998 bytes total] ````` ## `./build/ripwire . --seams` *Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped.* -**wall time: 1.82s** - ````` - + @@ -2436,29 +2453,29 @@ Call-graph isolate provenance: 3976 declaration, 2448 header, 3371 source, 5126 *Module (directory) dependency graph as a Mermaid diagram.* -**wall time: 1.40s** +**wall time: 1.61s** ````` %% 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"] + n961["test/slotjoinfix
175"] + n803["test/ownerhopfix/py/pkg
158"] n342["test/expandmodefix
151"] n344["test/expandsibsfix
149"] - n939["test/rubyschemafix
99"] - n419["test/forbodyfoldfix/py
98"] - n921["test/rubyattrsfix
85"] - n729["test/lib
81"] + n944["test/rubyschemafix
99"] + n424["test/forbodyfoldfix/py
98"] + n926["test/rubyattrsfix
85"] + n734["test/lib
81"] end - n74["docs
860"] + n74["docs
862"] n2[".github
628"] n0["(root)
606"] subgraph sg5 ["bench"] @@ -2476,12 +2493,12 @@ flowchart LR *Bus-factor: recency-weighted author ownership per file.* -**wall time: 8.50s** +**wall time: 5.94s** ````` - - + + @@ -2509,18 +2526,18 @@ flowchart LR -… [971 more display lines; full output is 106118 bytes on 1 raw line(s)] +… [974 more display lines; full output is 106558 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --dead-code=src` *Internal functions with no caller found in the index — a name-based graph reading, not a confidence score. NOTE the filter is a path-COMPONENT match: 'src' matches any .../src/... segment; use ./src to pin the root directory.* -**wall time: 2.22s** +**wall time: 1.50s** ````` - + ````` @@ -2529,7 +2546,7 @@ flowchart LR *Which symbols a TEST FILE exercises — the reverse direction of --affected.* -**wall time: 2.40s** +**wall time: 1.22s** ````` @@ -2542,11 +2559,11 @@ flowchart LR *Drill into ONE call-graph community by id — the drill= the --communities output itself advertises.* -**wall time: 3.71s** +**wall time: 1.44s** ````` - ````` @@ -2555,11 +2572,11 @@ flowchart LR *On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox section below.* -**wall time: 45.92s** +**wall time: 31.33s** ````` - ````` @@ -2567,17 +2584,18 @@ stderr: ````` ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) +ripwire: cache : over its 2048 MiB budget — evicted 49 blob(s) of other roots or other ripwire builds (this build's blobs for this root are kept) ````` ## `./build/ripwire . --quality-delta --show-stale` *The same clean verdict with what it folded printed back: every stale acknowledgement as an row and the full header. The regression-free answer above keeps only stale= and stale_by_kind= (and stale_next= names this call), and folds only when that saves a quarter of the bytes. Refused without --quality-delta.* -**wall time: 35.47s** +**wall time: 28.75s** ````` - @@ -2619,14 +2637,14 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree).* -**wall time: 21.31s** +**wall time: 18.90s** ````` - - - + + @@ -2638,11 +2656,11 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *No-LLM review-evidence bundle for the working-tree diff (clean tree = empty).* -**wall time: 5.23s** +**wall time: 3.74s** ````` - ````` @@ -2651,25 +2669,13 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *The BASEREF form: diffed against merge-base(BASEREF, HEAD), never the ref tip — here the previous commit on the current line (a ref with NO merge base falls back to a disclosed two-dot diff: anchor="ref-tip-two-dot").* -**wall time: 11.91s** +**wall time: 7.83s** ````` - - + - - - - - - - - - - - - - + ````` @@ -2677,15 +2683,15 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Pairwise cross-arm conflict sites + suggested landing order (any committish sharing a merge base with HEAD works as an arm; one that does not is reported ok="0", never compared).* -**wall time: 28.14s** +**wall time: 30.15s** ````` - - + + - + @@ -2697,11 +2703,11 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Which refs of the `lane/` ref family still hold divergent authored work vs HEAD, with verdicts.* -**wall time: 70.40s** +**wall time: 65.59s** ````` - + @@ -2730,18 +2736,18 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g -… [200 more display lines; full output is 27194 bytes on 1 raw line(s)] +… [245 more display lines; full output is 32365 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --stray-content=arm/for-howitworks-067-f2add` *A second selection, the one branch `arm/for-howitworks-067-f2add` (no ref family left to select on this checkout), picked at capture time from the refs this checkout really has and never the selection above: merged refs are OMITTED from the rows and counted in merged=; refs sharing no merge base with HEAD (a shallow clone, or a pre-rewrite history) land in unknown= with ok="0" — the counters always reconcile against refs=.* -**wall time: 11.70s** +**wall time: 13.65s** ````` - + @@ -2764,11 +2770,11 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g *Select the genuinely-unmerged refs of the `lane/` ref family and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root).* -**wall time: 152.24s** +**wall time: 197.74s** ````` - + @@ -2781,7 +2787,10 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g + + + @@ -2794,17 +2803,14 @@ ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs g - - - -… [33520 more display lines; full output is 4640491 bytes on 1 raw line(s)] +… [33523 more display lines; full output is 4640725 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --stray-content=zzzz-no-such-ref --plan` *A --plan filter that selects NO ref REFUSES (exit 1) naming the substring — before the wave-3 close this fell through to the '>512 refs match' sentence, and --abi under the same filter answered an empty measurement at exit 0.* -**exit code: 1** — **wall time: 5.70s** +**exit code: 1** — **wall time: 22.16s** ````` (empty) @@ -2821,21 +2827,29 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all.* -**exit code: 2** — **wall time: 435.49s** +**exit code: 2** — **wall time: 470.46s** ````` - + + + + + + + + + - + - + @@ -2846,29 +2860,29 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Which ref's tree defines or mentions SYM — HEAD first, then every local branch. The default lists the kind="def" rows (here the first 60, most on branches, each carrying tip= and date=) and counts the references in : on this symbol HEAD's references would fill the 60-row cap before the branch definitions arrive, so the whole list (below) shows fewer definitions, and the default serves the page that shows more of them, whatever its bytes.* -**wall time: 26.49s** +**wall time: 25.27s** ````` - - - - + + + + - + - + - - - - - - + + + + + + ````` @@ -2876,15 +2890,15 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *The whole hit list asked for by name: under the same 60-row cap HEAD's references fill the list, so it shows far fewer definitions (here HEAD's one) than the default above (here 60). The default serves the all page only when it shows the same definitions as the defs page in strictly fewer bytes (a tie serves it too).* -**wall time: 24.99s** +**wall time: 24.43s** ````` - - + + - - + + - - - - - - + + + + + + @@ -2916,11 +2930,11 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *A ref range run for two of the twelve kinds only: the named kinds' rows are exactly their rows in the full answer, the header names the others (kinds_skipped=, skipped_why="selector"), and a pass no named kind needs does not run. The replay a memory-stopped range answer hands back (kinds_next=) is this flag. Refused without --quality-delta=A..B.* -**wall time: 24.35s** +**wall time: 32.33s** ````` - - - - + + + - - - - - - + + + + + + @@ -2968,15 +2982,15 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Same, plus a git-history row (never / removed-by-commit) for names no tree carries.* -**wall time: 37.19s** +**wall time: 34.13s** ````` - - + + - - + + ````` @@ -2984,12 +2998,12 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gates from comments/heredocs, so the count only reflects real ifndef/define, CMake option(), and getenv gates.* -**wall time: 2.87s** +**wall time: 1.69s** ````` - + @@ -3024,11 +3038,11 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Blast radius of turning ONE gate on: live code, symbols, transitive reach, covering tests.* -**wall time: 2.81s** +**wall time: 2.17s** ````` - + @@ -3062,7 +3076,7 @@ ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zer *Unknown-gate refusal (exit 1) with a did-you-mean from a real edit distance (one character off RIPWIRE_ASAN).* -**exit code: 1** — **wall time: 2.63s** +**exit code: 1** — **wall time: 3.47s** ````` (empty) @@ -3079,10 +3093,10 @@ ripwire: run `ripwire . --flags` for the gate table *NEW VERB: pre-hoc lane plan — which of 3 parallel worktrees would COLLIDE, before a line is written. JSON on stdout.* -**wall time: 6.65s** +**wall time: 7.01s** ````` -{"v":1,"verb":"plan-lanes","at":"d3605fde7","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3618,"symbols":31790,"edges":299 … [line truncated: 338 more bytes on this line] +{"v":1,"verb":"plan-lanes","at":"79e691876","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3627,"symbols":31838,"edges":300 … [line truncated: 338 more bytes on this line] "symbols":[{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","l":286,"id":"./src/docdrift.h::DriftResult::DriftResult"}, {"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","l":2441,"id":"./src/docdrift.h::docdrift::computeDocDrift"}, {"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","l":2739,"id":"./src/docdrift.h::docdrift::kDocDriftLegend"}, @@ -3100,7 +3114,7 @@ ripwire: run `ripwire . --flags` for the gate table {"p":"./src/main.cpp","n":"emitNoteAddUnprovenDefs","scope":"","key":"a950332ccfce6b8d","id":null,"id_addressable":false,"id_collides_with":0,"l":691,"ord":0,"overloads":1,"amb":1,"cx":2,"ccx":1,"churn":453,"tested":0}, {"p":"./src/docdrift.h","n":"sortDocsByLiveDrift","scope":"docdrift","key":"d5de682411b9a9a9","id":"./src/docdrift.h::docdrift::sortDocsByLiveDrift","id_addressable":true,"id_collides_with":0,"l":2390,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":2,"churn":36,"tested":0}, {"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5840,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":466,"tested":0}], -"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":55}, +"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":56}, {"p":"./src/docdrift.h","symbols":4,"churn":36,"ccx":14,"hotspot_rank":38}, {"p":"./src/editcheck.h","symbols":1,"churn":61,"ccx":10,"hotspot_rank":41}, {"p":"./src/main.cpp","symbols":2,"churn":453,"ccx":12,"hotspot_rank":5}, @@ -3119,7 +3133,7 @@ ripwire: run `ripwire . --flags` for the gate table *NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode).* -**wall time: 8.67s** +**wall time: 7.96s** Input file: @@ -3130,7 +3144,7 @@ write regression tests for the new filter ````` ````` -{"v":1,"verb":"plan-lanes","at":"d3605fde7","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3618,"symbols":31790,"edges":29969,"ambiguous":2927,"unresolved":15221},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] +{"v":1,"verb":"plan-lanes","at":"79e691876","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3627,"symbols":31838,"edges":30013,"ambiguous":2932,"unresolved":15244},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] "symbols":[]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb","claims":{"symbols":[{"p":"./src/docdrift.h","n":"recordUnchecked","scope":"docdrift","key":"12641dab14abc8fd","id":"./src/docdrift.h::docdrift::recordUnchecked","id_addressable":true,"id_collides_with":0,"l":2 … [line truncated: 72 more bytes on this line] {"p":"./src/docdrift.h","n":"sortWeakGroupsByPath","scope":"docdrift","key":"1944ba506280ff80","id":"./src/docdrift.h::docdrift::sortWeakGroupsByPath","id_addressable":true,"id_collides_with":0,"l":2401,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":36,"tested":0}, {"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","key":"1fa68e8d93c05a59","id":"./src/mcpverbs.h::rw::docDriftText","id_addressable":true,"id_collides_with":0,"l":655,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":466,"tested":0}, @@ -3149,13 +3163,13 @@ write regression tests for the new filter {"p":"./src/mcpverbs.h","symbols":2,"churn":466,"ccx":2,"hotspot_rank":4}, {"p":"./src/recall.h","symbols":1,"churn":27,"ccx":4,"hotspot_rank":64}, {"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":4,"hotspot_rank":25}], -"symbols_total":3464,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], +"symbols_total":3466,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], "tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":13,"module_span":6,"notes":[], "execution":{"policy":"codex-lane/v1","model":"gpt-5.6-sol","reasoning":"xhigh","rule":"wide-contract-work","basis":"structural-only","signals":{"claims":12,"files":6,"module_span":6,"max_ccx":38,"sum_ccx":64,"ambiguous_calls":12,"blast_reaches":13,"contract_touches":1,"conflicts":0,"untested":13,"t … [line truncated: 139 more bytes on this line] {"id":"lane-1","task":"add the CLI parse arm and help text for the new filter","claims":{"symbols":[{"p":"./scripts/optremarks.py","n":"main","scope":"","key":"01b3b880f77d1512","id":null,"id_addressable":false,"id_collides_with":134,"l":279,"ord":0,"overloads":1,"amb":0,"cx":23,"ccx":31,"churn":14, … [line truncated: 12 more bytes on this line] {"p":"./src/cli.h","n":"HelpLine","scope":"rw","key":"1489844dbc310b82","id":"./src/cli.h::rw::HelpLine","id_addressable":true,"id_collides_with":0,"l":2948,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, {"p":"./src/cli.h","n":"HelpFilter","scope":"HelpFilter","key":"3103a5e8bfc33d38","id":"./src/cli.h::HelpFilter::HelpFilter","id_addressable":true,"id_collides_with":0,"l":3027,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, -{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":134,"l":865,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":17,"tested":0}, +{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":134,"l":885,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":18,"tested":0}, {"p":"./src/mcprefusal.h","n":"kMcpValueFields","scope":"rw::mcprefuse","key":"4a7106e488a2aa80","id":"./src/mcprefusal.h::rw::mcprefuse::kMcpValueFields","id_addressable":true,"id_collides_with":0,"l":304,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":49,"tested":0}, {"p":"./src/cli.h","n":"serveHelpSelector","scope":"rw","key":"4b247ee064fc4e94","id":"./src/cli.h::rw::serveHelpSelector","id_addressable":true,"id_collides_with":0,"l":3092,"ord":0,"overloads":1,"amb":1,"cx":4,"ccx":3,"churn":511,"tested":0}, {"p":"./src/query.h","n":"tryParsePredicateOnAll","scope":"query","key":"786acc4dbfec612b","id":"./src/query.h::query::tryParsePredicateOnAll","id_addressable":false,"id_collides_with":1,"l":113,"ord":0,"overloads":2,"amb":0,"cx":1,"ccx":0,"churn":20,"tested":0}, @@ -3183,7 +3197,7 @@ ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out *CPU/GPU contract view of one struct: computed offsets/sizes/padding + mirror check.* -**wall time: 1.74s** +**wall time: 2.34s** ````` @@ -3225,7 +3239,7 @@ ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out *The honest refusal (exit 1): Lang is an `enum class`, not a struct — no offsets are fabricated.* -**exit code: 1** — **wall time: 3.73s** +**exit code: 1** — **wall time: 1.89s** ````` (empty) @@ -3241,11 +3255,11 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped *Which of this repo's doc claims are now false. CHANGED: row attribute at= renamed to tgt= (at= is now only the root sha stamp).* -**wall time: 6.07s** +**wall time: 6.61s** ````` - +
@@ -3265,8 +3279,8 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped - - + + @@ -3274,18 +3288,18 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped -… [226 more display lines; full output is 23806 bytes on 1 raw line(s)] +… [228 more display lines; full output is 23860 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --doc-drift --gateability` *The finishable to-do list: docs whose LIVE failing anchors a date-stamp would reclassify.* -**wall time: 4.98s** +**wall time: 8.85s** ````` - + @@ -3305,8 +3319,8 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped - - + + @@ -3314,7 +3328,7 @@ ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped -… [253 more display lines; full output is 25061 bytes on 1 raw line(s)] +… [255 more display lines; full output is 25115 bytes on 1 raw line(s)] ````` Tail of the same output — the `` section: @@ -3324,11 +3338,11 @@ Tail of the same output — the `` section: - + @@ -3351,12 +3365,12 @@ Tail of the same output — the `` section: *Same report, with git history splitting stale mentions into deleted-by-commit vs never-existed.* -**wall time: 5.78s** +**wall time: 11.01s** ````` - - + + @@ -3376,22 +3390,22 @@ Tail of the same output — the `` section: - - + + - - -… [206 more display lines; full output is 23785 bytes on 1 raw line(s)] + + +… [208 more display lines; full output is 23839 bytes on 1 raw line(s)] ````` ## `./build/ripwire . --from-trace=-` *Map a pasted stack trace onto indexed symbols. CHANGED: in_corpus= now reports the real count (was 0).* -**wall time: 2.24s** +**wall time: 3.62s** Input file: @@ -3399,8 +3413,8 @@ Input file: 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) @@ -3408,25 +3422,25 @@ AddressSanitizer:DEADLYSIGNAL ````` ````` - + - - + + - + 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] - + uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f ) int runDefaultMap( const MainDispatch& d ) int main( int argc, char** argv ) - + & p, float alpha = 0.85f ) { PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); @@ -3445,7 +3459,7 @@ AddressSanitizer:DEADLYSIGNAL *List all field notes (write-side memory) — the committed .ripwire_notes at the repo root, each with the sha/branch it was recorded at.* -**wall time: 2.94s** +**wall time: 3.44s** ````` @@ -3470,7 +3484,7 @@ AddressSanitizer:DEADLYSIGNAL *ONE budget-shared bundle: ranking + top bodies + caller sigs + notes + tests_to_run. CHANGED: rows now carry n=/id=.* -**wall time: 2.76s** +**wall time: 3.15s** ````` @@ -3510,7 +3524,7 @@ AddressSanitizer:DEADLYSIGNAL *Fan-out form: one shared core + 3 per-agent slices carved along call-graph communities.* -**wall time: 1.75s** +**wall time: 4.27s** ````` + @@ -3564,14 +3578,14 @@ AddressSanitizer:DEADLYSIGNAL The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) -struct RankedGraph +struct RankedGraph 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… inline std::uint32_t sliceRdIterationCeiling() noexcept struct PageRankRun What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure -inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept -inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) +inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept +inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept inline std::string powerShellSingleQuote( std::string_view s ) noexcept @@ -3590,7 +3604,7 @@ AddressSanitizer:DEADLYSIGNAL *Per-file metrics as CodeCharta cc.json.* -**wall time: 4.86s** +**wall time: 7.13s** ````` (empty) @@ -3599,7 +3613,7 @@ AddressSanitizer:DEADLYSIGNAL Artifact written: ````` - 560892 /aux/ripwire2.cc.json + 562619 /aux/ripwire2.cc.json {"projectName":"project","apiVersion":"1.3","attributeDescriptors":{"loc":{"title":"Lines of Code","description":"Physical line count","direction":-1},"symbols":{"title":"Symbols","description":"Definitions in the file","direction":-1},"cx":{"title":"Cyclomatic Complexity","description":"Sum of per-symbol cyclomatic complexity","direction":-1},"cognitive_cx":{"title":"Cognitive Complexity","descri ````` @@ -3607,7 +3621,7 @@ Artifact written: *One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped .* -**wall time: 3.96s** +**wall time: 10.93s** Input file: @@ -3622,12 +3636,12 @@ lego:Vehicle - + - + incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…constexpr std::uint32_t kCacheMagic = 0x4b505443 Composed exactly the way every OTHER blob family is (quality.h): one fixed-width identity hex pe…inline std::string spanTierMemoPath( const std::string& diskPath ) @@ -3635,9 +3649,9 @@ lego:Vehicle Ingest the tree at `sha`, materialized out of `root`'s object store. The HEAD side reuses the SA…inline bool ingestCommitTree( const std::string& root, const std::string& sha, const std::vector<std::string>& excludes, std::size_t maxFileBytes, IngestResult&… … [line truncated: 4 more bytes on this line] P1-15 — the `_reingest` envelope field for a response whose handling ran an INCREMENTAL pass, …inline bool mcpRefreshedThisRequest( std::uint64_t passesAtEntry ) -struct FileHealth +struct FileHealth inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::ve … [line truncated: 8 more bytes on this line] -inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… +inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… inline RawFacts runParsePool( IngestResult& result, const char* rootDir, std::string_view cacheFile, bool captureValueUses, HashMap<std::string, FileFacts>& cache, const CacheLoadStats& cac … [line truncated: 66 more bytes on this line] inline McpRebuildBaseline mcpRebuildBaseline( const McpIndex& ix, bool isIncrementalPass ) inline const McpIndex& getIndex( const std::string& root ) @@ -3661,18 +3675,18 @@ lego:Vehicle *Environment self-check: binary staleness, grammars, cache dir, git, tracked-binary staleness — exit 1 when any check fails (here: the PATH install is older than ./build).* -**exit code: 1** — **wall time: 41.39s** +**exit code: 1** — **wall time: 38.31s** ````` - - + - - + + - - + @@ -3724,13 +3738,13 @@ ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s *Rank by git change-frequency prior instead of PageRank.* -**wall time: 7.13s** +**wall time: 8.89s** ````` - - + + @@ -3750,44 +3764,34 @@ ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(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~6 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3` *Scope the recent-changes answer to ONE directory. 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.* -**wall time: 11.61s** +**wall time: 12.47s** ````` - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - + ````` @@ -3795,7 +3799,7 @@ ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s *An unknown value REFUSES (exit 1), NAMED, with the supported set listed.* -**exit code: 1** +**exit code: 1** — **wall time: 1.01s** ````` (empty) @@ -3811,19 +3815,19 @@ ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf *Columnar output: paths table + parallel arrays, ~15-60% fewer tokens on MANY-row lists — small results can be LARGER (the columnar legend is a fixed cost).* -**wall time: 1.30s** +**wall time: 4.40s** ````` - + 0=src/mcpindex.h 1=src/graph.h 2=src/eval.h 3=src/main.cpp 0,1,1,2,3,3,3 getIndex,rankGraph,anchoredLexicalRank,runEval,churnDecayRanking,churnRankedGraph,runDefaultMap -1184,11791,12437,171,1425,1464,1751 +1184,11850,12496,171,1425,1464,1751 fn,fn,fn,fn,fn,fn,fn 0,0,0,0,0,0,0 -src/mcpindex.h:1288,src/graph.h:11794,src/graph.h:12488,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 +src/mcpindex.h:1288,src/graph.h:11853,src/graph.h:12547,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 ````` @@ -3832,24 +3836,24 @@ ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf *Flat top-K export for an external reranker.* -**wall time: 6.02s** +**wall time: 9.06s** ````` - - + + inline std::string spanTierMemoPath( const std::string& diskPath ) - + inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::vector<NodeId>& surfaceIds ) - + ### See the map — not just the numbers - + inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) - + const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) @@ -3875,12 +3879,12 @@ ripwire: --format: unknown value 'bogus' (supported: xml|columnar|rows|candidate *Machine-parseable JSON, same content, keys mirror the XML attrs.* -**wall time: 1.21s** +**wall time: 1.69s** ````` -{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2927,"graph_unresolved":15221,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, -{"t":"fn","n":"rankGraph","p":"src/graph.h:11791","sites_at":["src/graph.h:11794"]}, -{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12437","sites_at":["src/graph.h:12488"]}, +{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2932,"graph_unresolved":15244,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, +{"t":"fn","n":"rankGraph","p":"src/graph.h:11850","sites_at":["src/graph.h:11853"]}, +{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12496","sites_at":["src/graph.h:12547"]}, {"t":"fn","n":"runEval","p":"src/eval.h:171","sites_at":["src/eval.h:328"]}, {"t":"fn","n":"churnDecayRanking","p":"src/main.cpp:1425","sites_at":["src/main.cpp:1439"]}, {"t":"fn","n":"churnRankedGraph","p":"src/main.cpp:1464","sites_at":["src/main.cpp:1478","src/main.cpp:1479","src/main.cpp:1493"]}, @@ -3907,12 +3911,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Pagination: 3 items, skipping the first 3 (deterministic seams).* -**wall time: 4.58s** +**wall time: 7.19s** ````` - + @@ -3923,12 +3927,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Drop test paths from the corpus before ranking.* -**wall time: 1.90s** +**wall time: 2.44s** ````` - + @@ -3939,7 +3943,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -3947,7 +3951,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -3963,12 +3967,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Drop matching paths (repeatable) before ranking.* -**wall time: 1.93s** +**wall time: 2.32s** ````` - + @@ -3987,7 +3991,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -4003,13 +4007,13 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Full map re-ranked with teleport toward git-changed files — clean tree, so changed=0 and it degrades to the plain map.* -**wall time: 4.89s** +**wall time: 4.76s** ````` - - + + @@ -4034,12 +4038,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm cost.* -**wall time: 3.36s** +**wall time: 4.24s** ````` - + @@ -4054,7 +4058,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -4074,12 +4078,12 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m *Explicit incremental cache at a path OUTSIDE the repo (first call writes it).* -**wall time: 3.43s** +**wall time: 4.51s** ````` - + @@ -4094,7 +4098,7 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m - + @@ -4113,22 +4117,22 @@ ripwire: --json is not yet supported for --hotspots — supported: the default m Artifact written: ````` - 28475910 /aux/warm2.ripwirecache + 28772140 /aux/warm2.ripwirecache ````` ## `./build/ripwire . --max-file-size=8K --top-k=3` *Skip files above a size bound before parsing (note the corpus shrink in the header).* -**wall time: 1.15s** +**wall time: 3.22s** ````` - + - + @@ -4139,7 +4143,7 @@ Artifact written: - + @@ -4148,7 +4152,7 @@ Artifact written: - + @@ -4176,12 +4180,12 @@ ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather t *Multi-root workspace: ONE merged graph over two roots, paths labeled /.* -**wall time: 1.99s** +**wall time: 5.42s** ````` - + @@ -4209,19 +4213,19 @@ ripwire: --scip=does_not_exist.scip: cannot open the index — refusing rather t *Self-eval: co-change recall vs BM25.* -**wall time: 19.24s** +**wall time: 22.29s** ````` ripwire --eval (co-change recovery, averaged over 80 historical commits) ranker recall@5 recall@10 recall@20 - ripwire 5.4% 6.4% 13.4% - BM25 13.3% 15.9% 16.9% - BM25sub 14.0% 23.1% 30.1% - BM25body 15.5% 22.3% 33.9% - fused 7.8% 14.6% 27.3% - anchored 15.5% 22.7% 34.2% - same-dir 0.9% 4.6% 10.9% - random 0.1% 0.3% 0.6% <- floor (random ranking over F=3618 files) + ripwire 6.2% 6.8% 13.3% + BM25 14.7% 16.3% 18.4% + BM25sub 15.5% 23.7% 28.6% + BM25body 18.3% 24.9% 35.8% + fused 12.3% 16.0% 25.5% + anchored 18.3% 24.9% 36.2% + same-dir 0.9% 4.5% 10.3% + random 0.1% 0.3% 0.6% <- floor (random ranking over F=3627 files) note: `ripwire` here is the DEFAULT MAP's structural-only PageRank (importance, not relatedness) — it is NOT what a --for/--query retrieval call ranks with. BM25 / BM25sub / BM25body are QUERY-TIME lexical rankers (whole-name / subtoken / @@ -4237,23 +4241,23 @@ ripwire --eval (co-change recovery, averaged over 80 historical commits) *Known-item retrieval eval: MRR + recall@k per ranker per query mode.* -**wall time: 159.70s** +**wall time: 160.73s** ````` ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-corpus by construction) - sample: population=7994 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population + sample: population=8002 scored=4000 rule=smallest-key CAPPED — a SUBSET, not the population (smallest fnv1a64(scope::name) over the population, cut on the key so an identity is never split; path- and order-independent, but a corpus this size is NOT graded exhaustively — say so when citing it) ingest: lex=rich (persisted subtoken stats; no per-query corpus re-tokenize) ranker query-mode MRR recall@1 recall@5 recall@10 subtoken name 0.680 54.5% 84.8% 90.0% - subtoken doc-phrase 0.903 88.3% 92.2% 93.5% + subtoken doc-phrase 0.904 88.3% 92.3% 93.5% name-exact name 0.898 82.2% 95.9% 97.4% - name-exact doc-phrase 0.013 0.5% 1.9% 2.6% - anchored name 0.688 56.2% 84.1% 88.7% - anchored doc-phrase 0.899 87.5% 92.2% 92.9% + name-exact doc-phrase 0.013 0.5% 1.8% 2.6% + anchored name 0.687 56.2% 84.1% 88.7% + anchored doc-phrase 0.900 87.6% 92.3% 93.0% routed name 0.900 82.4% 96.0% 97.6% - routed doc-phrase 0.902 88.2% 92.0% 93.2% + routed doc-phrase 0.902 88.3% 92.1% 93.3% note: routing chose name-exact on 3989/4000 NAME queries (a NAME query is always identifier-shaped); the confidence gate routes doc-phrase queries to name-exact ONLY when EVERY content word names a symbol (or an explicit camel/snake token appears) AND every matched name is specific enough to anchor on — @@ -4266,7 +4270,7 @@ ripwire --eval-retrieval (known-item, 4000 doc-commented symbols; gold is in-co *Labelled verdict-accuracy eval for --stray-content — three labels over REAL local refs (names resolved at capture time); exit 3 when accuracy is under the floor. Read got= against v= in the stray-content run: a ref the verb could not analyse (unknown) must never be credited as a merged hit.* -**exit code: 3** — **wall time: 86.65s** +**exit code: 3** — **wall time: 92.71s** Input file: @@ -4290,7 +4294,7 @@ arm/orient-map-067-narrow merged *Labelled skill-ROUTING eval over the repo's own skills/ directory (4 hand-labelled prompts).* -**wall time: 3.47s** +**wall time: 2.47s** Input file: @@ -4332,13 +4336,15 @@ ripwire --eval-skills (skill routing over K=16 candidate skills [ripwire-router ripwire-write-tests 0 0 0 0 0 misses (overlap): line 3 want=ripwire-change-check got=ripwire-before-you-build "plan parallel worktrees so the lanes do not collide" -… [19 more lines, 3664 bytes total] +… [19 more lines, 3665 bytes total] ````` ## `./build/ripwire wrap claude` *Print the recipe to wire ripwire into Claude Code as an MCP server.* +**wall time: 1.56s** + ````` # ripwire -> Claude Code (CLI-first) # RECOMMENDED — this agent can run shell commands, so call the CLI directly. It costs @@ -4377,10 +4383,10 @@ Reach for it BEFORE blind grep + whole-file reads. First call ~1s cold; after th *Version + short build info.* -**wall time: 1.92s** +**wall time: 1.85s** ````` -ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=45d52a1ee) +ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=185ba69da) ````` @@ -4388,31 +4394,31 @@ ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=45d5 # navigate — seeds, claims, slices, shapes -## `./build/ripwire . --at=src/graph.h:11752` +## `./build/ripwire . --at=src/graph.h:11811` *Hold a LOCATION, not a name: the enclosing-definition chain at FILE:LINE (a compiler error, a diff hunk, a stack frame), outermost -> innermost.* -**wall time: 2.74s** +**wall time: 2.71s** ````` - - + + ````` -## `./build/ripwire . --callers=@src/graph.h:11752` +## `./build/ripwire . --callers=@src/graph.h:11811` *The same seed in a SELECTOR position: @FILE:LINE resolves to the innermost enclosing definition, then --callers runs on it.* -**wall time: 1.96s** +**wall time: 3.71s** ````` - + - - + + @@ -4424,7 +4430,7 @@ ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=45d5 *A seed past the end of the file — the refusal shape for a faulted location.* -**exit code: 1** — **wall time: 2.50s** +**exit code: 1** — **wall time: 3.76s** ````` (empty) @@ -4433,20 +4439,20 @@ ripwire 0.6.8 (dev, AppleClang 21.0.0.21000101, emit=std::print, built_from=45d5 stderr: ````` -ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16217 lines — the seed asked for line 999999) +ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph.h has only 16276 lines — the seed asked for line 999999) ````` ## `./build/ripwire . --verify="calls(runDefaultMap, rankGraphTeleport)"` *VERIFY a closed claim in one call: three-valued verdict (confirmed / refuted / not-established) with the evidence rows inline.* -**wall time: 3.53s** +**wall time: 2.32s** ````` - + - + ````` @@ -4454,14 +4460,14 @@ ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph. *A claim that is FALSE — the refuted shape, with the references that refute it.* -**wall time: 2.32s** +**wall time: 5.13s** ````` - + - - + + @@ -4475,7 +4481,7 @@ ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph. *A literal-scan absence: refuted only with complete= evidence, never on a partial scan.* -**wall time: 2.88s** +**wall time: 1.86s** ````` @@ -4487,7 +4493,7 @@ ripwire: the at flag's seed 'src/graph.h:999999' named no location (./src/graph. *An unparseable claim — the refusal names the accepted shapes.* -**exit code: 1** — **wall time: 5.56s** +**exit code: 1** — **wall time: 2.82s** ````` (empty) @@ -4503,25 +4509,25 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *Bare --slice=SYM: the INVENTORY of sliceable locals (), so a caller can pick VAR.* -**wall time: 6.63s** +**wall time: 5.00s** ````` - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + ````` @@ -4529,21 +4535,21 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *Intra-procedural def-use slice of ONE variable: one row per line touching it, k=def|use|both, reaching definitions flow-sensitive (reach=cfg).* -**wall time: 5.45s** +**wall time: 7.33s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + @@ -4553,30 +4559,30 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *TRANSITIVE backward value-flow from the seed variable, bounded BFS (depth= disclosed; a cut frontier says flow_truncated=1).* -**wall time: 8.19s** +**wall time: 6.31s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + - + pw = biasPrior( g, p );]]> - + & p, float alpha = 0.85f )]]> - + & p, float alpha = 0.85f )]]> @@ -4586,42 +4592,42 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *Forward flow: which statements the seed's value reaches, at the default depth bound.* -**wall time: 7.61s** +**wall time: 7.45s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + - + - + - + - + - + 0.0 )]]> - + - + @@ -4631,7 +4637,7 @@ ripwire: --verify claim not recognized: 'frobnicate(x)' — unknown shape word. *A variable the definition does not bind — the refusal shape, naming the inventory.* -**exit code: 1** — **wall time: 2.38s** +**exit code: 1** — **wall time: 4.26s** ````` (empty) @@ -4663,21 +4669,21 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *The compact legend posture: rows byte-identical, a versioned schema id replaces the repeated explanatory prose — for a many-small-calls loop.* -**wall time: 5.32s** +**wall time: 4.35s** ````` - - + + - + teleport( pw.begin(), pw.end() );]]> - + - + @@ -4687,12 +4693,12 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *Structural search written in CODE: $NAME binds one node; grammars=/shapes= disclose what the pattern became per grammar (a 3-argument call shape — the 2-argument spelling has no call site in this repo and correctly reports hits=0).* -**wall time: 3.48s** +**wall time: 3.64s** ````` rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) +rankGraphTeleport( g, std::vector<float>( N, N ? 1.0f / float( N ) : 0.f ), alpha ) ````` @@ -4700,7 +4706,7 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *The ellipsis form over a macro-shaped call site; unsupported= names the families this verb does not serve.* -**wall time: 2.87s** +**wall time: 2.91s** ````` @@ -4740,7 +4746,7 @@ ripwire: --slice-depth bounds the --slice-flow BFS — pass both (e.g. ripwire < *A pattern that collapses to a bare token is REFUSED — never reported as hits=0.* -**exit code: 1** — **wall time: 1.60s** +**exit code: 1** — **wall time: 1.90s** ````` (empty) @@ -4756,28 +4762,30 @@ ripwire: --pattern: this pattern collapses to a single bare token, which is a TE *Boolean grep: hits where BOTH literals share the matched line (--grep-scope=line is the default).* +**wall time: 1.96s** + ````` 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -5041,7 +5049,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? 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 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 19751 bytes on 44 raw line(s)] ````` @@ -5050,25 +5058,25 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Restore the / sections the --for bundle collapses to a counted stub by default (this is the stub's own next= spelling).* -**wall time: 14.53s** +**wall time: 11.88s** ````` - + 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -5081,7 +5089,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? 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 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 ) … [149 more display lines; full output is 20084 bytes on 44 raw line(s)] ````` @@ -5090,25 +5098,25 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Opt OUT of compact conceptual serving: restore the rank-first auto walk (bundle="auto").* -**wall time: 9.49s** +**wall time: 11.57s** ````` - + 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() -struct FileHealth +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…struct SliceScan enum class AstWalk : std::uint8_t -inline bool astroFenceTailIsBlank( std::string_view src, std::size_t from, std::size_t to ) noexcept +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 ) @@ -5121,7 +5129,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? 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 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 ) … [134 more display lines; full output is 20303 bytes on 55 raw line(s)] ````` @@ -5130,17 +5138,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Doc-mention surfacing (default ON): a markdown doc naming a top-resolved symbol in a backtick rides in below that symbol — the legend's [doc mentions: …] clause says it fired.* -**wall time: 8.77s** +**wall time: 18.94s** ````` - + 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 inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… @@ -5152,17 +5160,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? std::optional<int> runQualityDelta( const MainDispatch& d ) struct DeltaBasis int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] -inline const char* kAcksFile = ".ripwire_quality_acks" +inline const char* kAcksFile = ".ripwire_quality_acks" DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) -struct IdentityHealing +struct IdentityHealing inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) -inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) -inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) inline std::string qualityAcksPath( const std::string& root ) struct QualityDeltaOutcome std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) -inline bool atomicWriteFile( const std::string& path, const std::string& blob ) -inline std::string gitHeadSha( const std::string& root ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) … [193 more display lines; full output is 22995 bytes on 45 raw line(s)] ````` @@ -5170,17 +5178,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *The same task with doc-mention surfacing OFF — the contrast the flag exists for (no [doc mentions] clause, one fewer row).* -**wall time: 8.51s** +**wall time: 10.95s** ````` - + 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 inline rw::pathguard::NoFollowRead openRegularFileStream( std::string_view what, const std::string& path ) inline Result computeDmm( const std::string& root, std::string_view spec, const IngestResult& wo… @@ -5192,17 +5200,17 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? std::optional<int> runQualityDelta( const MainDispatch& d ) struct DeltaBasis int ackNothingToAccept( const std::string& acksFile, const gtl::btree_map<std::string, rw::quality::AckRecord>& acks, const rw::quality::Scope& scope, std::size… … [line truncated: 4 more bytes on this line] -inline const char* kAcksFile = ".ripwire_quality_acks" +inline const char* kAcksFile = ".ripwire_quality_acks" DirtyPinVerdict inspectDirtyBaselinePin( const MainDispatch& d, const std::string& acksFile ) -struct IdentityHealing +struct IdentityHealing inline std::pair<std::string, std::string> qualityDeltaJson( const std::string& root, bool showStale = false ) -inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) -inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) +inline bool writeAckRecords( const std::string& path, const gtl::btree_map<std::string, AckRecord>& acks ) +inline std::string staleAcksXml( const std::vector<StaleAck>& staleAcks, EscapeFn esc ) inline std::string qualityAcksPath( const std::string& root ) struct QualityDeltaOutcome std::optional<int> resolveDeltaBasis( const MainDispatch& d, const std::string& baselineFile, RefPairDelta& refs, DeltaBasis& out ) -inline bool atomicWriteFile( const std::string& path, const std::string& blob ) -inline std::string gitHeadSha( const std::string& root ) +inline bool atomicWriteFile( const std::string& path, const std::string& blob ) +inline std::string gitHeadSha( const std::string& root ) … [193 more display lines; full output is 22814 bytes on 45 raw line(s)] ````` @@ -5210,14 +5218,14 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *"Can I delete this?" — callers + transitive impact + every use site + how much of the radius is tested, composed in ONE call; risk= names what was found, never a verdict.* -**wall time: 2.43s** +**wall time: 3.97s** ````` - - - + + @@ -5229,7 +5237,7 @@ ripwire: --grep given twice; did you mean --grep='A' --and='B'? *Unknown-symbol refusal shape for --safe-delete.* -**exit code: 1** — **wall time: 2.28s** +**exit code: 1** — **wall time: 2.70s** ````` (empty) @@ -5245,22 +5253,22 @@ ripwire: --safe-delete symbol not found: DoesNotExist *The continuation packet for the NEXT session: disk truth (branch/sha, changed symbols, blast radius, tests) + labeled suggestions. Recorded against a CLEAN tree.* -**wall time: 19.43s** +**wall time: 14.56s** ````` - + - + - - - + + + + ````` @@ -5269,19 +5277,18 @@ ripwire: --safe-delete symbol not found: DoesNotExist *The same packet under a hard ceiling: heuristic rows drop tail-first (withheld= disclosed), verified rows never drop.* -**wall time: 10.91s** +**wall time: 13.38s** ````` - - + + - + ````` @@ -5290,14 +5297,14 @@ ripwire: --safe-delete symbol not found: DoesNotExist *WHY a file is not in the index (oversize / excluded / unsupported-ext / gitignored) and which indexed files it cannot vouch for (degraded-parse, minified-suspect), plus the per-language census.* -**wall time: 1.49s** +**wall time: 1.53s** ````` - @@ -5330,12 +5337,12 @@ ripwire: --safe-delete symbol not found: DoesNotExist *Crawl paths the repo's own .gitignore covers (default honours it and discloses ignored_files=/ignored_dirs= only when it dropped anything — this repo's crawl drops nothing, so the header is identical to the default map's; --skipped's ignore_mode= says which rule applied).* -**wall time: 1.04s** +**wall time: 1.68s** ````` - + @@ -5350,7 +5357,7 @@ ripwire: --safe-delete symbol not found: DoesNotExist - + @@ -5370,12 +5377,12 @@ ripwire: --safe-delete symbol not found: DoesNotExist *--no-stable outside --mcp: what the flag does (or says) when there is no stable-by-default ordering to opt out of.* -**wall time: 1.78s** +**wall time: 2.22s** ````` - + @@ -5390,7 +5397,7 @@ ripwire: --safe-delete symbol not found: DoesNotExist - + @@ -5416,21 +5423,21 @@ ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable o *EXEC-MODE --from-trace: run a command, and on a non-zero exit map its captured output onto indexed symbols in the same call — the whole fix-loop entry. ripwire exits 4 here because the wrapped command failed, which is the signal, not an incident.* -**exit code: 4** — **wall time: 1.71s** +**exit code: 4** — **wall time: 1.65s** ````` - + - + 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)]]> pw = biasPrior( g, p ); @@ -5458,19 +5465,19 @@ ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable o std::vector r( N, 0.f ); std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); return { std::move( r ), run.iterationCount, run.hasConverged }; -}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] +}]]>inline std::vector<float> biasPrior( const Graph& g, const std::vector<float>& p )#define PROFILE_SCOPE_DESCRIBE( desc )#define PROFILE_SCOPE_DESC … [line truncated: 289 more bytes on this line] ````` ## `./build/ripwire . --run-trace="true"` *A command that exits 0: a minimal success record (exit, measured duration, disclosed output tail) and NO bundle — nothing failed, nothing to map.* -**wall time: 1.51s** +**wall time: 1.75s** ````` - + ````` @@ -5478,7 +5485,7 @@ ripwire: --no-stable is read only by --mcp/--listen (it opts out of the stable o *A command still running at the cap: its process group is killed and the run reports timed_out=1 — an honest timeout, never an empty success.* -**exit code: 4** — **wall time: 3.28s** +**exit code: 4** — **wall time: 3.47s** ````` @@ -5518,21 +5525,21 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *THE single wide-angle quality read: six families in one pass, an eligible/ranked shortlist rather than a firehose.* -**wall time: 10.07s** +**wall time: 10.46s** ````` - - - + + - + @@ -5548,9 +5555,9 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir - + - + … [188 more display lines; full output is 15676 bytes on 1 raw line(s)] ````` @@ -5558,12 +5565,12 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Per-function size ranking, largest Halstead volume/token entropy/lines first — a size proxy, not a readability order (withdrawn, docs/EVALS.md §8) — a RANKING lens, not a grade.* -**wall time: 2.24s** +**wall time: 1.67s** ````` - - + + @@ -5578,11 +5585,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Functions WITH a doc comment, most name-restating first: c_coeff (high = the comment repeats the name) and cic (Jaccard of comment vs identifier vocabulary), both reported, never collapsed.* -**wall time: 2.76s** +**wall time: 1.89s** ````` - + @@ -5598,37 +5605,37 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The local-reasoning lens: to understand this symbol, how much must you know that is NOT in front of you (ent_ratio= edge share, read_ratio= token-weighted).* -**wall time: 1.59s** +**wall time: 2.12s** ````` - + - + - - - - - - - + + + + + + + - - - + + + - - - - + + + + - - + + … [21 more display lines; full output is 11151 bytes on 1 raw line(s)] @@ -5638,11 +5645,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Per function, the non-local MUTABLE state it can reach (transitively), most writes first — unsound by construction, and the legend says where.* -**wall time: 3.54s** +**wall time: 3.30s** ````` - @@ -5678,11 +5685,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The family join: per function, which of four orthogonal evidence families fire, ranked by how many agree.* -**wall time: 6.43s** +**wall time: 7.65s** ````` - @@ -5718,11 +5725,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The cache-locality lens over every aggregate: fields READ TOGETHER but declared FAR APART (split-line / straddle findings, Chilimbi separation weight) — advice only, never a rewrite.* -**wall time: 2.27s** +**wall time: 2.19s** ````` - @@ -5758,11 +5765,11 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The same lens narrowed to ONE struct — the one --layout=Symbol shows the offsets for.* -**wall time: 2.88s** +**wall time: 2.23s** ````` - @@ -5794,14 +5801,14 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *The corpus's OWN case-convention vote per (language, kind) group; off-convention names get a mechanical propose= (a suggestion, never a blind rename).* -**wall time: 1.47s** +**wall time: 1.28s** ````` - - - - + + + + @@ -5814,7 +5821,7 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir - + @@ -5834,12 +5841,12 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir *Score the naming-* rules against this repo's own rename history: proxy=old/(old+new) per rule, 0.50 = chance; read pairs= (sample size) first.* -**wall time: 14.69s** +**wall time: 14.43s** ````` - - + + @@ -5857,25 +5864,25 @@ ripwire: --run-timeout=SECONDS modifies --run-trace — pass it too (e.g. ripwir

@@ -3069,8 +3078,8 @@ _OWNERSHIP partition for a shared tree: every regression here lives in src/infra ``` $ ./build/ripwire . --quality-delta --scope=src/graph.h - -, acked. value-ref-excluded=N: internal functions kept off because a table, field or argument in another function or at file scope holds them (matched by name, not a proven call); a floor. at=: commit+dirty+shallow. stale=N: ack ledger rows whose target no longer applies (sa rows); never gating. preexisting-worse=N: regressions on symbols that existed at baseline; they gate when major. new-symbol=N: findings on NEW code; new-symbol rows never gate, except defect-shape format-arity. register-macro-excluded=N: symbols kept out of dead-code as self-registering test/bench macros; a floor. declined-call-excluded=N: symbols kept out of dead-code only because a declined call may mean them; a floor. api-new-surface=N: new PUBLIC symbols; a count, never gates, not in regressions=. renames=/rename_window_commits=: git rename pairs read over that many commits, to re-file baseline and acks. acked_by_rename=/acked_by_content=: acked= suppressions matched via git renames / an equal body hash. renames_window_truncated=1: history is deeper than the rename window, older renames unread. r surface=: the api-surface tier, new-symbol or contract-change. acked=N: findings suppressed by the ack ledger, listed as sa rows; never gating. r sev=minor: a small numeric delta, counted in minor=, never gating (absent: major). r origin=new-symbol: a finding on NEW code (absent: preexisting-worse). sa key=/why=: the stale ack's ledger hash / target-gone (names nothing now) or finding-gone (no longer fires). r members=/tokens=: a duplication row's clone group (member ids) / their shared normalized-token count. --> + @@ -3100,10 +3109,10 @@ _Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree ``` $ ./build/ripwire . --edit-check=rankGraphTeleport - - - + + @@ -3130,7 +3139,7 @@ disclosed as trailing_newline_folded=true; a second one, a deliberate blank line _An unknown TARGET refuses and leaves every file byte-identical._ ``` -$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc/aux/payload_note.h +$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=/aux/payload_note.h (empty) ``` @@ -3149,17 +3158,17 @@ $ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc _Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured)._ ``` -$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=./build/sc/aux/payload_note.h --edit-target-file=src/infra/sortutil.h +$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=/aux/payload_note.h --edit-target-file=src/infra/sortutil.h {"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] {"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":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"graph_ambiguous":2925,"graph_unresolved":15128,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ``` ### `--insert-after-symbol=TARGET` @@ -3173,14 +3182,14 @@ Both inserts PAD the block (newlines only, never removed) so it is separated fro _Insert immediately AFTER one uniquely-resolved definition; replaced_bytes=0 because the insert verbs never overwrite. The receipt carries the folded post-edit verification (lines=, edit_check, tests_to_run) so the loop closes in one call._ ``` -$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h +$ ./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":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"graph_ambiguous":2925,"graph_unresolved":15128,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} +"order":"evidence","partners":0,"run_first":1,"tests":5,"script_gates_unmodelled":779,"graph_ambiguous":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true,"next":"bash test/greptiercheck.sh"} ``` **Caveats (stated by the binary):** @@ -3200,7 +3209,7 @@ empty payloads refuse, never imply deletion _An unknown TARGET refuses and leaves every file byte-identical._ ``` -$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=./build/sc/aux/payload_note.h +$ ./build/ripwire . --replace-symbol-body=DoesNotExist --edit-payload=/aux/payload_note.h (empty) ``` @@ -3221,17 +3230,17 @@ RELATIVE (matched against the indexed spelling) or ABSOLUTE (matched against the _Insert BEFORE, with --edit-target-file pinning which same-named definition (here unambiguous — the disambiguator is simply honoured)._ ``` -$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=./build/sc/aux/payload_note.h --edit-target-file=src/infra/sortutil.h +$ ./build/ripwire . --insert-before-symbol=nonNegativeFloatDescKey --edit-payload=/aux/payload_note.h --edit-target-file=src/infra/sortutil.h {"applied":"insert_before_symbol","symbol":"nonNegativeFloatDescKey","file":"src/infra/sortutil.h","span":{"start":2895,"end":2983},"lines":{"start":74,"end":75},"replaced_bytes":0,"old_file_bytes":11000,"new_file_bytes":11088,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":false,"s … [line truncated: 755 more bytes on this line] {"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":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true},"tests_to_run":[{"p":"test/verify_radix.cpp","hops":1,"run":"bash test/greptiercheck.sh"}, +"graph_ambiguous":2925,"graph_unresolved":15128,"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":779,"graph_ambiguous":2932,"graph_unresolved":15150,"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":779,"graph_ambiguous":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true,"next":"--uses=src/infra/sortutil.h:nonNegativeFloatDescKey"} ``` **Shaped by:** `--insert-after-symbol` @@ -3253,7 +3262,7 @@ pass this when you are about to edit again immediately). The MCP spelling is pos _The opt-out: the same insert with the folded verification skipped — lines= still rides (it is free), edit_check/tests_to_run do not, and the two pasteable commands stay on stderr._ ``` -$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=./build/sc/aux/payload_note.h --no-post-check +$ ./build/ripwire . --insert-after-symbol=lessByScoreDescId --edit-payload=/aux/payload_note.h --no-post-check {"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":10912,"new_file_bytes":11000,"file_eol":"lf","eol_normalized":false,"trailing_newline_folded":true,"separator … [line truncated: 572 more bytes on this line] ``` @@ -3274,7 +3283,7 @@ op is one of replace_symbol_body, insert_before_symbol, insert_after_symbol each _Neither --dry-run nor --apply: the mode is explicit, so this refuses._ ``` -$ ./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json +$ ./build/ripwire . --edit-plan=/aux/edit_plan.json (empty) ``` @@ -3289,12 +3298,12 @@ exactly one of the two is required the plan's explicit mode: --dry-run preflight _The same plan committed: per-file locks, re-verify-before-write, atomic rename, rollback on a later failure._ ``` -$ ./build/ripwire . --edit-plan=./build/sc/aux/edit_plan.json --apply -{"schema":"ripwire.edit-plan/v1","mode":"apply","edits":1,"files":1,"callers_union":4,"graph_ambiguous":2932,"graph_unresolved":15150,"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: 466 more bytes on this line] +$ ./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":2925,"graph_unresolved":15128,"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":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true}}]} +"graph_ambiguous":2925,"graph_unresolved":15128,"graph_unindexed":269,"counts_floor":true}}]} ``` **Shaped by:** `--edit-check` @@ -3340,19 +3349,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] ``` @@ -3377,17 +3386,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] @@ -3431,10 +3440,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:11793 +$ ./build/ripwire . --at=src/graph.h:11751 - - + + ``` @@ -3458,7 +3467,7 @@ _No-LLM review-evidence bundle for the working-tree diff (clean tree = empty)._ ``` $ ./build/ripwire . --pr-context - ``` @@ -3484,11 +3493,11 @@ _Pairwise cross-arm conflict sites + suggested landing order (any committish sha ``` $ ./build/ripwire . --merge-scout=HEAD~2,HEAD~1 - - + + - + @@ -3538,7 +3547,7 @@ Each line is ranked on its own — no community carve, no bin packing — so the _NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode)._ ``` -$ ./build/ripwire . --plan-lanes --brief=./build/sc/aux/lanes_brief.txt +$ ./build/ripwire . --plan-lanes --brief=/aux/lanes_brief.txt add a --since filter to the doc-drift verb add the CLI parse arm and help text for the new filter write regression tests for the new filter @@ -3558,13 +3567,22 @@ Per local ref (SUBSTR filters ref names): the lines its own divergent work AUTHO **Try it** -_Which refs of the one branch `b155` (no ref family left to select on this checkout) still hold divergent authored work vs HEAD, with verdicts._ +_Which refs of the `lane/` ref family still hold divergent authored work vs HEAD, with verdicts._ ``` -$ ./build/ripwire . --stray-content=b155 - - - +$ ./build/ripwire . --stray-content=lane/ + + + + + + + + + + + +... [20 more line(s); run it to see the whole thing] ``` **Shaped by:** `--plan`, `--abi`, `--whereis`, `--limit`, `--eval-stray` @@ -3583,13 +3601,25 @@ $ ./build/ripwire . --stray-content=b155 **Try it** -_Select the genuinely-unmerged refs of the one branch `b155` (no ref family left to select on this checkout) and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root)._ +_Select the genuinely-unmerged refs of the `lane/` ref family and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root)._ ``` -$ ./build/ripwire . --stray-content=b155 --plan +$ ./build/ripwire . --stray-content=lane/ --plan - - + + + + + + + + + + + + + +... [17 more line(s); run it to see the whole thing] ``` **Shaped by:** `--stray-content`, `--legend`, `--json` @@ -3607,13 +3637,25 @@ SCOPE is what each ref AUTHORED — the paths `git diff base..tip` reports again **Try it** -_Cross-branch ABI-break gate over the one branch `b155` (no ref family left to select on this checkout): struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all._ +_Cross-branch ABI-break gate over the `lane/` ref family: struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all._ ``` -$ ./build/ripwire . --stray-content=b155 --abi +$ ./build/ripwire . --stray-content=lane/ --abi - - + + + + + + + + + + + + +... [2 more line(s); run it to see the whole thing] ``` **Caveats (stated by the binary):** @@ -3634,11 +3676,14 @@ _Which ref's tree defines or mentions SYM — HEAD first, then every local branc ``` $ ./build/ripwire . --whereis=rankGraphTeleport - - - - -<.hereis> + + + + + + + +... [14 more line(s); run it to see the whole thing] ``` **Shaped by:** `--whereis-full-text`, `--whereis-listing`, `--with-history`, `--limit` @@ -3661,13 +3706,13 @@ _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] +... [23 more line(s); run it to see the whole thing] ``` **Shaped by:** `--whereis` @@ -3721,8 +3767,8 @@ _The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gat $ ./build/ripwire . --flags - - + + @@ -3802,7 +3848,7 @@ _The cache-locality lens over every aggregate: fields READ TOGETHER but declared ``` $ ./build/ripwire . --field-affinity - @@ -3836,8 +3882,8 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - - + + @@ -3870,8 +3916,8 @@ _Which of this repo's doc claims are now false. CHANGED: row attribute at= renam ``` $ ./build/ripwire . --doc-drift - - + + @@ -3903,9 +3949,9 @@ _Same report, with git history splitting stale mentions into deleted-by-commit v ``` $ ./build/ripwire . --doc-drift --with-history - - - + + + @@ -3936,9 +3982,9 @@ FILE is read directly (like --from-trace's FILE, not through the crawled index), _The house PLAN/DESIGN format's STRUCTURE check — never semantics; exit 2 when a card or ledger row gates._ ``` -$ ./build/ripwire . --plan-lint=test/planlintfix.ave.md +$ ./build/ripwire . --plan-lint=test/planlintfix/wave.md - + @@ -3973,8 +4019,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:11793 - #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11834 + #0 0x102f4a1c8 in rw::rankGraphTeleport(Graph const&, std::vector const&, float) src/graph.h:11751 + #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11792 #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) @@ -4003,7 +4049,7 @@ _A command that exits 0: a minimal success record (exit, measured duration, disc $ ./build/ripwire . --run-trace="true" - + ``` @@ -4105,7 +4151,7 @@ $ ./build/ripwire . --pack-task="add a new output format flag to the CLI" Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept - + claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of its newlineinline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) ... [17 more line(s); run it to see the whole thing] ``` @@ -4138,9 +4184,9 @@ $ ./build/ripwire . --pack-task="add a new output format flag to the CLI" --part Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept - + claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of…inline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) - + ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION doe…inline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, const std::string_view executablePath, const WrapListing& listing ) noexcept ... [19 more line(s); run it to see the whole thing] ``` @@ -4163,7 +4209,7 @@ _Task lens + a compact Mermaid flowchart of the top anchors' 1-hop edges._ ``` $ ./build/ripwire . --for="pagerank power iteration" --with-graph - + @@ -4188,7 +4234,7 @@ feeds a CodeCharta 3D city _Per-file metrics as CodeCharta cc.json._ ``` -$ ./build/ripwire . --export=cc.json:./build/sc/aux/ripwire2.cc.json +$ ./build/ripwire . --export=cc.json:/aux/ripwire2.cc.json (empty) ``` @@ -4205,7 +4251,7 @@ caps at 16 (over-cap = capped=1). THE SAME `verb:arg` line is accepted by the MC _One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped ._ ``` -$ ./build/ripwire . --batch=./build/sc/aux/batch2.txt +$ ./build/ripwire . --batch=/aux/batch2.txt for:incremental cache invalidation callers:rankGraphTeleport grep:DISCLOSE @@ -4235,15 +4281,15 @@ _Environment self-check: binary staleness, grammars, cache dir, git, tracked-bin ``` $ ./build/ripwire . --doctor - - - + - - + + - - + @@ -4269,19 +4315,20 @@ _--doctor plus a LIVE integration inspection for one agent: PATH binary, install ``` $ ./build/ripwire . --doctor --agent=claude - - - + - - + + - - + - -... [3 more line(s); run it to see the whole thing] + + +... [2 more line(s); run it to see the whole thing] ``` **Caveats (stated by the binary):** @@ -4304,7 +4351,7 @@ $ ./build/ripwire . --skipped - @@ -4392,8 +4439,8 @@ _Rank by git change-frequency prior instead of PageRank._ $ ./build/ripwire . --rank-by=churn --top-k=5 - - + + @@ -4425,22 +4472,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~5 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3 +$ ./build/ripwire . --rank-by=churn-decay --since=HEAD~6 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3 - - - - - - - - - - - - -... [8 more line(s); run it to see the whole thing] + + + + + + + + + + + + +... [17 more line(s); run it to see the whole thing] ``` **Shaped by:** `--external-surface`, `--doctor`, `--legend`, `--max-memory` @@ -4502,7 +4549,7 @@ _The same gating report under --legend=full — same rows, same exit 2; the defa ``` $ ./build/ripwire . --quality-delta --legend=full - @@ -4582,7 +4629,7 @@ _The family join: per function, which of four orthogonal evidence families fire, ``` $ ./build/ripwire . --ensemble --limit=8 - @@ -4618,7 +4665,7 @@ _Drop matching paths (repeatable) before ranking._ $ ./build/ripwire . --exclude=present --exclude=bench --top-k=5 - + @@ -4629,7 +4676,7 @@ $ ./build/ripwire . --exclude=present --exclude=bench --top-k=5 - + ... [17 more line(s); run it to see the whole thing] ``` @@ -4649,14 +4696,14 @@ _Full map re-ranked with teleport toward git-changed files — clean tree, so ch $ ./build/ripwire . --map-diff --top-k=5 - - + + - + - + @@ -4680,17 +4727,17 @@ $ ./build/ripwire . --map-diff --top-k=5 _Explicit incremental cache at a path OUTSIDE the repo (first call writes it)._ ``` -$ ./build/ripwire . --cache=./build/sc/aux.arm2.ripwirecache --top-k=3 +$ ./build/ripwire . --cache=/aux/warm2.ripwirecache --top-k=3 - + - + - + @@ -4711,7 +4758,7 @@ Writes BOTH families — BASE.lean.ripwirecache (map/ nav/--pr-context) and BASE _CI generate-and-exit: cold-parse and write BOTH committable cache families (lean + rich), no map on stdout._ ``` -$ ./build/ripwire . --index-out=./build/sc/aux/ci_index +$ ./build/ripwire . --index-out=/aux/ci_index (empty) ``` @@ -4733,14 +4780,14 @@ _Force a cold parse (bypass the warm TMPDIR cache) — shows the cold-vs-warm co $ ./build/ripwire . --no-cache --top-k=3 - + - + - + @@ -4764,14 +4811,14 @@ _Crawl paths the repo's own .gitignore covers (default honours it and discloses $ ./build/ripwire . --no-ignore --top-k=3 - + - + - + @@ -4800,13 +4847,13 @@ _Skip files above a size bound before parsing (note the corpus shrink in the hea $ ./build/ripwire . --max-file-size=8K --top-k=3 - + - + @@ -4877,17 +4924,17 @@ Under --scip it also writes the index's covered sites, so a precision join needs _Eval-only: a per-call-site census of WHICH mechanism resolved each call, and the canonical id of every surviving target._ ``` -$ ./build/ripwire . --pin-census=./build/sc/aux/pin_census.tsv --top-k=3 +$ ./build/ripwire . --pin-census=/aux/pin_census.tsv --top-k=3 - + - + - + @@ -4910,7 +4957,7 @@ $ ./build/ripwire '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' '{"jso {"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: 738 more bytes on this line] {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"analyze","description":"Architecture map for a directory: signatures and the call graph for the top symbols. Use when landing cold in a repo or subdir, before reading files; for a task-scoped inventory use 'for', for one symbol's neighborhood find_ … [line truncated: 742 more bytes on this line] {"name":"rank_by","description":"The SAME architecture map 'analyze' serves, ranked by a different signal instead of plain PageRank. rank_by = pagerank (default, omit it — the CLI's own unbiased --rank-by=pagerank; 'analyze' can rank differently on a tree with uncommitted changes, where it biases … [line truncated: 1077 more bytes on this line] -{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read.rite/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] +{"name":"find_symbol","description":"A symbol's 1-hop neighborhood: the symbol (with a fetch_body handle) plus direct callers (calledBy) and callees (calls). Full transitive reach: 'impact'. Read/write/import sites, not just calls: 'uses'. JSON {symbol, calledBy, calls, defs, count, hop_tested, hop_ … [line truncated: 1181 more bytes on this line] ... [30 more line(s); run it to see the whole thing] ``` @@ -4934,10 +4981,10 @@ _--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":" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [735 more display lines; full output is 23597 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --top-k=5` - -*Same map, capped to the 5 highest-ranked symbols.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [67 more display lines; full output is 8256 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.* - -````` - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./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.* - -````` - - - - - - - - - - -````` - -## `./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** - -````` - - -````` - -stderr: - -````` -ripwire: --token-budget exceeded: withheld_est_tokens=9507 > 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: 2.48s** - -````` - - - - -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.hy).* - -**wall time: 1.39s** - -````` - - - - - -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: 1.38s** - -````` - - - - - -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: 1.39s** - -````` - - - - - -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: 1.49s** - -````` - - - - -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…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 19980 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: 1.46s** - -````` - - - - -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 ) -inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) -std::optional<int> runEvalViews( const MainDispatch& d ) -struct RecallSectionPick -inline double binomialChoose( std::size_t n, std::size_t k ) -… [146 more display lines; full output is 21540 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: 1.46s** - -````` - - - - -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 ) -inline std::string_view takeQualifiedIdent( std::string_view src, std::size_t& i ) -std::optional<int> runEvalViews( const MainDispatch& d ) -struct RecallSectionPick -inline double binomialChoose( std::size_t n, std::size_t k ) -… [155 more display lines; full output is 21617 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.* - -````` - - - - - - - - - -````` - -## `./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: 1.32s** - -````` - - - - - -````` - -## `./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.* - -````` - - - - -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.* - -````` - - - - -````` - -## `./build/ripwire . --recall="quality delta gating exit codes"` - -*Most relevant DOCS' full bodies (markdown only) — recall what is already written down.* - -````` -ripwire recall — "quality delta gating exit codes" — 121 relevant of 265 document files, best-first — total=121 shown=8 capped=1 truncated=6 generated_demoted=3 max_tokens=8000 share_bytes=2468 est_tokens=4165 - -━━ README.md (relevance 8.095) ━━ [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.525) ━━ [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 ./build/sc/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 1347635-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.054) ━━ [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] -### `--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: - -````` -[math degraded] ingest: the git ignore probe exited non-zero — full walk (ingest_crawl.h:1481, rw::{anonymous}::GitIgnoreSet rw::{anonymous}::parseGitIgnoreProbe(const GitIgnoreProbeRaw&) — logged once per site) -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).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [368 more display lines; full output is 11197 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --html=./build/sc/aux/map2.html` - -*Self-contained HTML force-directed call graph.* - -**wall time: 1.55s** - -````` -(empty) -````` - -Artifact written: - -````` -155999 ./build/sc/aux/map2.html -````` - -## `./build/ripwire . --order=stable --top-k=5` - -*Stable (path/id) emit order — provider KV-cache hits across re-runs.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [67 more display lines; full output is 8274 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.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [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.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [1948 more display lines; full output is 53189 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.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --callers=rankGraphTeleport` - -*Who calls SYM (1-hop in-edges).* - -````` - - - - - - - - - - -````` - -## `./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** - -````` - - -````` - -stderr: - -````` -ripwire: --callers symbol not found: DoesNotExist -````` - -## `./build/ripwire . --callees=rankGraphTeleport` - -*What SYM calls (1-hop out-edges).* - -````` - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --uses=rankGraphTeleport` - -*The resolvable use-sites (call/read.rite/import/extends) with file:line; count= is a floor.* - -**wall time: 1.32s** - -````` - - - - - - - - - - - - -````` - -## `./build/ripwire . --graph-query='and(callers(name("rankGraphTeleport"),2),kind(all,fn))'` - -*Composable node-set query: functions within 2 caller-hops of rankGraphTeleport.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [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.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [73 more display lines; full output is 5600 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).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [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").* - -````` - - - - - - - - -````` - -## `./build/ripwire . --connect=rankGraphTeleport,runEval,getIndex` - -*Minimal connecting subgraph over 3 symbols (finds shared-caller joins).* - -````` - - - - - - - - - - -````` - -## `./build/ripwire . --impact=rankGraphTeleport` - -*Transitive blast radius — everything that reaches SYM. NOW carries shown/capped.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [69 more display lines; full output is 6423 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --mentions=rankGraphTeleport` - -*Markdown docs that name SYM in a backtick (doc<->code edges).* - -````` - - - - - - - - - - -````` - -## `./build/ripwire . --affected=src/graph.h` - -*Test files that transitively reach the changed file.* - -````` - - - - - - - - - -````` - -## `./build/ripwire . --situ` - -*Mid-task situational report for the current git diff — recorded against a CLEAN tree (contrast with the sandbox run below).* - -````` -ripwire situational-awareness — 0 changed file(s), 0 symbols in them -root: . -at: e47df2266 - (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: 2.16s** - -````` - - -````` - -## `./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.* - -````` - -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: 1.17s** - -````` - -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).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [21 more display lines; full output is 3219 bytes on 1 raw line(s)] -````` - - ---- - -# zoom the detail ladder - -## `./build/ripwire . --for="pagerank power iteration" --detail=2` - -*Importance-weighted detail: FULL bodies for top-2, signatures for the rest.* - -**wall time: 1.45s** - -````` - - - - - -NodeId order. Renumbering an otherwise-identical graph (the exact "same probe file, different so…inline constexpr float kScoreTieAbsEps = 1e-6f - -Render one form of the disclosure. Empty string whenever there is nothing to say — no power it…inline std::string renderDisclosure( const RankDisclosure& d, DiscloseAs as ) - -The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] -inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) -struct RankedGraph -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… -inline std::uint32_t sliceRdIterationCeiling() noexcept -struct PageRankRun - -What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure -inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept -inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) -inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window -inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept -inline std::string powerShellSingleQuote( std::string_view s ) noexcept -inline std::string path_prepend_hint( std::string_view dir ) -HOT_FILES = ( "src/pagerank.cpp", # the power-iteration loop — G2's no-allocation scope "src/infra/radixSort.h", # LSD radix entry points "src/infra/radixSort.inl", # the counting … [line truncated: 76 more bytes on this line] -handle_t leftmost_leaf() const -inline void discloseUniformChurnFallback( bool hasChurnEvidence, bool stubbed, const char* verbLabel, const std::string& windowStamp ) -inline std::string doctorPathPrependLine( const std::string& selfPath ) -inline std::string doctorWhichRipwire( rw::os::stat_t& st ) -std::uint32_t testIterationCeiling() noexcept -inline const char* rankByLegendFor( const char* label ) noexcept -… [156 more display lines; full output is 22215 bytes on 72 raw line(s)] -````` - -## `./build/ripwire . --pack-signatures --top-k=10` - -*Body-elided decl skeletons — recounted on this corpus. Measured as element bytes: the signature+doc elements --pack-signatures emits, against the SAME symbols' full bodies from --expand, with the CORPUS-ROOT PREFIX SUBTRACTED FROM BOTH SIDES. That subtraction is the whole methodology and the figure is meaningless without it: the root repeats inside every element's id= and p=, it is not what this verb elides, and counting it makes the headline a function of how deep the checkout happens to sit on disk — on one corpus, three spellings of the same root read 18.6 points apart before the subtraction and agree exactly after it. Root-neutralised on THIS repo: 88.8% fewer bytes at top-10, 86.2% at top-50, 87.4% at top-100 (re-derived 2026-10-10 when the C++ standard-member gate stopped std::vector/std::string calls such as out.push_back() and s.empty() from binding to in-tree namesakes by name: the ranked top-10/50 lost one-line container accessors (svector::push_back, WidePath::c_str, every empty) and gained one-line forwarding helpers and macros (kindIs, ASSUME, formatTo, emitTo) whose signature is nearly the whole body, so less of the set is elidable, from 92.7/88.7/87.6; before that, re-derived 2026-09-20 when the native Windows port landed: src/infra/os_win32.cpp and os_win32_logic.h are ~3,900 lines of new, heavily commented infra that the ranked top-10/50/100 now reach, and their bodies are this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new, from top-50 87.1. Measured by test/showcasecapturecheck.sh's own recount arm on the combined tree, which is the gate that would otherwise report the drift; before that, re-derived 2026-09-17 at the self-check macro vocabulary rename: VERIFY/VERIFY_TEXT/VERIFY_DEBUG_ONLY/VERIFY_NOT_REACHED/VERIFY_SAME_THREAD/VERIFY_NO_ALIAS*/DYNMAP_VERIFY/DEGRADED_PATH_ALERT renamed to ASSUME/EXPECTS/ENSURES/DASSERT/UNREACHABLE/ASSUME_SAME_THREAD*/ASSUME_NO_ALIAS*/DYNMAP_ASSUME/DISCLOSE (plus new VALIDATE sites) across 839 identifier renames in 179 files, and a hand-written Diagnostics.h/diagnostics.cpp replacing the old ones outright: this moves both WHICH symbols the ranked top-10/50/100 hold and how large their bodies are, from top-50 85.2. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-12 when the rows dropped the path-repeating id= for the short sc= scope: the signature side shrank, the bodies did not; before that, 89.5% / 81.8% / 84.3% re-derived 2026-09-10 at the sibs= cap raise: kMaxExpandSibs went 8 -> 100, so --expand's bodies now carry the file context the old cap hid — 89.3% of all sibling names — and the body side is this ratio's DENOMINATOR, so the figure rises without --pack-signatures eliding anything new. Measured on a fixed tree with the top-50 membership and the signature side unchanged: top-50 from 71.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-09 at the printf-family -> std::print conversion: converting ~1,500 emitter call sites to rw::emitTo/emitRaw/formatTo across 93 files changes how large the ranked symbols' BODIES are, and the body side is this ratio's denominator — top-50 from 72.3. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-08 at the confident-zero round, issues #62/#63/#66: that change adds symbols to src/graphlegend.h and the new src/preprocdead.h and re-homes two long comment blocks from call sites onto the helpers they explain, which moves both WHICH symbols the ranked top-50 holds and how large their bodies are — top-50 from 74.0. A real re-derivation of a corpus that changed, not a tolerance edit; previously re-derived 2026-09-06 at the stranger-audit fix round: the doctor, cache-sweep and html-provenance bodies grew this corpus's BODY side, moving top-50 from 75.6 — a real re-derivation, not a tolerance edit; before that, re-derived 2026-09-05 at the capture-audit close: lane L7's P16 caps --expand's sibs= at 8 names, which SHRINKS the body side of this ratio and moved the figure down from 84.5/80.2/80.6 — the V1 2026-08-15 re-center, when sibs=/inc= first grew the body side from 70.0/61.0/63.8, in reverse; both were real re-derivations, not tolerance edits). top-50 is the number to quote, because the sigs payload is top-50 regardless of --top-k and is therefore what THIS command emits. A single small/trivial body can still invert it (signature+doc bigger than the body), like the --format=columnar sibling below. test/showcasecapturecheck.sh (C) re-derives all three from this repo every run, in the same quantity, and fails if the caption and the recount drift apart.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [148 more display lines; full output is 14953 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --outline=rankGraphTeleport --top-k=0` - -*Control-flow skeleton of one symbol, payload-only via the new --top-k=0.* - -````` - - - - -& p, float alpha = 0.85f ) -{ - PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); - const std::vector pw = biasPrior( g, p ); - const std::size_t N = pw.size(); - std::vector teleport( pw.begin(), pw.end() ); - std::vector rankDouble( N, 0.0 ); - PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun - if( N ) - { - ... - } - std::vector r( N, 0.f ); - std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); - return { std::move( r ), run.iterationCount, run.hasConverged }; -} -]]> -````` - -## `./build/ripwire . --outline=rankGraphTeleport:1-10 --top-k=0` - -*CHANGED: a line range on --outline is now STRIPPED with a stderr note (it used to refuse).* - -````` - - - - -& p, float alpha = 0.85f ) -{ - PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); - const std::vector pw = biasPrior( g, p ); - const std::size_t N = pw.size(); - std::vector teleport( pw.begin(), pw.end() ); - std::vector rankDouble( N, 0.0 ); - PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun - if( N ) - { - ... - } - std::vector r( N, 0.f ); - std::transform( rankDouble.begin(), rankDouble.end(), r.begin(), []( double value ) { return float( value ); } ); - return { std::move( r ), run.iterationCount, run.hasConverged }; -} -]]> -````` - -stderr: - -````` -ripwire: --outline=rankGraphTeleport:1-10: --outline has no line-range form — outlining the whole symbol (use --expand=rankGraphTeleport:1-10 for a body slice) -````` - -## `./build/ripwire . --expand=rankGraphTeleport --top-k=0` - -*Full body + inline callee signatures.* - -````` - - - - -: files the ranked rows show / do not (sum = files=), each named or counted below. : a program entry by its language's convention (C/Go/Rust main, Java/C# static main, a script main its module scope calls, __main__.py), callees as c rows; manifest entries not read. : n= unshown files under dir p=; f= names its code files, the rest (tests, docs, config, test/doc/example dirs) counted. declined=K: K call sites without edges, including inert Elixir quote sites after unquote/unquote_splicing re-entry. external=K: K calls proven outside the tree, no edge. locality_pinned=K: K calls pinned by locality alone (a guess). extent_suspect_syms=K: K defs failed containment, corpus-wide. macro_blanked_files=K: K files indexed from a macro-blanked re-parse. prov=scip|binding|import|split|final-segment: how that edge bound (absent: one unique name); split = one arm of an amb= pick; final-segment = a qualified type matched by last name only. files=/symbols=: files and symbols indexed; edges= distinct call edges; shown= symbols printed, a merged row counting each def; ambiguous= calls split over several defs, corpus-wide; unresolved= calls with in-tree evidence and no edge (every def language-filtered or unreachable, or binding refused); order= rows by rank (important-first, important-last; (auto:fill) = flipped past a size threshold) or by path (stable). skipped_oversize=K: K files over a size ceiling, not indexed. unindexed=ext:N: N text files of that extension no grammar reads (6 extensions at most). unindexed_exts=E: E such extensions in all, the list cut. : a non-test row an indexed test transitively reaches (absent otherwise, never 0). : that callee matched by name alone (receiver unproven); it does NOT mean the edge is false. sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. amb=K: K calls split over several defs. locals_floor=1: locals= is a floor. role=hub: in= is 8 or more. s in= out= cx= ccx= loc= params= nest= cbo= amp=: callers, callees, cyclomatic/cognitive complexity, lines, parameters, nesting depth, coupled types, callers + co-changed files. ev=/ev_why=: essential complexity (2+: jumps block extract-method; absent: 1) / the jumps behind it, tag:count. ev_floor=1: ev= is a FLOOR; noreturn calls, macro-hidden exits and unresolved gotos are unseen. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. l=N: start line; only on a same-name overload's row, one row per body (bodyless decls fold into overloads=). --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [97 more display lines; full output is 10931 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --deps` - -*File->file dependency graph (god-files, cycles).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [899 more display lines; full output is 24018 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --hotspots` - -*Complexity x recent git churn (maintenance pain).* - -**wall time: 1.50s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [14 more display lines; full output is 5767 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --clones` - -*Token-normalized duplicate bodies.* - -**wall time: 2.99s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [308 more display lines; full output is 16222 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --cochange` - -*Files that change together in git (hidden coupling).* - -**wall time: 1.43s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --hotspots --since="2 weeks ago"` - -*Hotspots scoped to RECENT churn (the regression lens).* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [13 more display lines; full output is 5128 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --arch=test/archfix/rules.txt` - -*Enforce layering rules (exit 2 on violation) — run against the repo's own test fixture rules.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [1038 more display lines; full output is 153440 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --lint` - -*Built-in AST checks (c-cast, goto, unsafe-c-fn, ...).* - -**wall time: 2.44s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [685 more display lines; full output is 70581 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --lint-rules=test/lintrulesfix/rules` - -*User lint rules (YAML, ast-grep style) from a directory.* - -**wall time: 1.04s** - -````` - - - - -use LOG() instead of printf -use LOG() instead of printf -use LOG() instead of printf -use LOG() instead of printf -use LOG() instead of printf - -````` - -stderr: - -````` -ripwire: lint-rules: test/lintrulesfix/rules/malformed.yaml:5: expected 'key: value' — file skipped -[math degraded] lint-rules: malformed rule file skipped (lintrules.h:399, rw::parseLintRuleFile(const std::string&, std::string_view, std::vector&):: — logged once per site) -ripwire: AST query did not compile for any grammar: (this_is_not_a_real_node @x @@@ ((( ) -````` - -## `./build/ripwire . --lint --with-profile=report.txt` - -*Join MEASURED heat onto --lint findings — runs in a tiny fabricated demo corpus (one cache-pointer-chase-loop finding under a PROFILE_SCOPE site) because a real report needs a RIPWIRE_PROFILE build; the finding inside the profiled scope gains heat_* columns from the report's #PROF_TSV row.* - -Input file: - -````` -#PROF_TSV_BEGIN one row per scope, aggregated across threads; counters are RAW integers -scope file line calls total_ms l1d_mpki -walk: chase pass x.cpp 9 12 48.500 7.250 -#PROF_TSV_END -````` - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [13 more display lines; full output is 3428 bytes on 1 raw line(s)] -````` - -stderr: - -````` -[math degraded] ingest: the git ignore probe exited non-zero — full walk (ingest_crawl.h:1481, rw::{anonymous}::GitIgnoreSet rw::{anonymous}::parseGitIgnoreProbe(const GitIgnoreProbeRaw&) — logged once per site) -````` - -The joined finding — past the display cut above, extracted so the join is visible: - -````` -p = p->next -````` - -## `./build/ripwire . --communities` - -*Cluster the call graph into cohesive modules.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [189 more display lines; full output is 16860 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --zoom` - -*Nested module hierarchy (multi-level Louvain) + cross-module bridges — levels_shown="2" of levels= BY DEFAULT over the 40 largest top modules (~8 KB, where the whole tree is ~220 KB); a module AT the cut carries children=.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [135 more display lines; full output is 7291 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --zoom --zoom-levels=3` - -*The restoring knob: --zoom-levels=N prints N levels (0 = the whole tree); here three, ~11 KB.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [271 more display lines; full output is 12259 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --report` - -*Architecture summary (modules, god-files, cycles) as markdown.* - -````` - - -# ripwire architecture report - -3607 files · 31702 symbols · 29921 edges · 3598 modules (14863 call-graph isolated) - -Root: `.` - -Call-graph isolate provenance: 3961 declaration, 2444 header, 3343 source, 5115 document; 0 connected Louvain singletons - -## Modules (call-graph clusters; showing 12 of 3598) -- **src::emitTo@infra/emit.h:53:2760 [write,run,emit]** — 1618 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 -- **docs::`--top-k=N`@COMMANDS.md:59:9077 [pack,allow,insert]** — 181 symbols -- **test/ownerhopfix/py/pkg::big_handler_001@broadcast.py:3:72** — 106 symbols -- **src::buf@infra/svector.h:125:8942 [insert,find,push]** — 91 symbols -- **src/infra::fail@os_win32.cpp:63:2553 [open,get,close]** — 89 symbols -- **test::no@estchargecheck.sh:52:4108 [skip,set]** — 63 symbols -- **src::child@ingest_valuerefs.h:656:33874 [emit,resolve,open]** — 62 symbols -- **src::rowOffsets@infra/sparseCsr.h:248:8990 [connect,compute,expand]** — 55 symbols -- **src::sliceKindIs@slice.h:368:24239 [match,collect,push]** — 48 symbols -- **src/infra::DYNMAP_ASSUME@dynamic_map.hpp:90:4411 [insert,erase,find]** — 44 symbols - -## God files (most depended-on; showing 10 of 228) -- `src/model.h` — 103 dependents -- `src/infra/emit.h` — 87 dependents -- `src/infra/Diagnostics.h` — 65 dependents -- `src/graph.h` — 46 dependents -- `src/serialize.h` — 45 dependents -… [35 more lines, 3956 bytes total] -````` - -## `./build/ripwire . --seams` - -*Cross-module call seams no test reaches. NOW carries seam_pairs/shown/capped.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [57 more display lines; full output is 9051 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --mermaid` - -*Module (directory) dependency graph as a Mermaid diagram.* - -````` -%% 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
9389"] - n103["src/infra
1301"] - end - subgraph sg1 ["test"] - n104["test
5507"] - n568["test/legochargefix
546"] - n405["test/fixtures/recallpassage
314"] - n953["test/slotjoinfix
175"] - n795["test/ownerhopfix/py/pkg
158"] - n342["test/expandmodefix
151"] - n344["test/expandsibsfix
149"] - n936["test/rubyschemafix
99"] - n424["test/forbodyfoldfix/py
98"] - n918["test/rubyattrsfix
85"] - n731["test/lib
81"] - end - n74["docs
858"] - n2[".github
625"] - n0["(root)
606"] - subgraph sg5 ["bench"] - n4["bench
545"] - n5["bench/agentloop
331"] - n49["bench/locbench/results/r5_pooling
237"] - n50["bench/locbench/results/r6_expansion
187"] - n59["bench/recalleval
113"] - n43["bench/locbench
107"] - n38["bench/headtohead/r3-headroom-2026-08-03
102"] -… [20 more lines, 1592 bytes total] -````` - -## `./build/ripwire . --owners` - -*Bus-factor: recency-weighted author ownership per file.* - -**wall time: 1.42s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [971 more display lines; full output is 106097 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --dead-code=src` - -*Internal functions with no caller found in the index — a name-based graph reading, not a confidence score. NOTE the filter is a path-COMPONENT match: 'src' matches any .../src/... segment; use ./src to pin the root directory.* - -````` - - - - -````` - -## `./build/ripwire . --exercises=test/regression.sh` - -*Which symbols a TEST FILE exercises — the reverse direction of --affected.* - -````` - - - -````` - -## `./build/ripwire . --community=0` - -*Drill into ONE call-graph community by id — the drill= the --communities output itself advertises.* - -````` - - - -````` - -## `./build/ripwire . --quality-delta` - -*On a CLEAN tree: nothing got worse, exit 0. The gating shape is in the sandbox section below.* - -**wall time: 16.12s** - -````` - - -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -````` - -## `./build/ripwire . --quality-delta --show-stale` - -*The same clean verdict with what it folded printed back: every stale acknowledgement as an row and the full header. The regression-free answer above keeps only stale= and stale_by_kind= (and stale_next= names this call), and folds only when that saves a quarter of the bytes. Refused without --quality-delta.* - -**wall time: 12.74s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [140 more display lines; full output is 16170 bytes on 1 raw line(s)] -````` - -stderr: - -````` -ripwire: no ./.ripwire_quality_baseline — auto-comparing the working tree vs git HEAD (commit the baseline with --quality-baseline to pin it) -````` - -## `./build/ripwire . --edit-check=rankGraphTeleport` - -*Fast per-symbol post-edit contract check vs git HEAD (unchanged on a clean tree).* - -**wall time: 8.44s** - -````` - - - - - - - - - -````` - -## `./build/ripwire . --pr-context` - -*No-LLM review-evidence bundle for the working-tree diff (clean tree = empty).* - -````` - - - -````` - -## `./build/ripwire . --pr-context=HEAD~1` - -*The BASEREF form: diffed against merge-base(BASEREF, HEAD), never the ref tip — here the previous commit on the current line (a ref with NO merge base falls back to a disclosed two-dot diff: anchor="ref-tip-two-dot").* - -**wall time: 2.14s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [21 more display lines; full output is 5229 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --merge-scout=HEAD~2,HEAD~1` - -*Pairwise cross-arm conflict sites + suggested landing order (any committish sharing a merge base with HEAD works as an arm; one that does not is reported ok="0", never compared).* - -**wall time: 7.56s** - -````` - - - - - - - - - - - -````` - -## `./build/ripwire . --stray-content=b155` - -*Which refs of the one branch `b155` (no ref family left to select on this checkout) still hold divergent authored work vs HEAD, with verdicts.* - -````` - - - -````` - -## `./build/ripwire . --stray-content=no-such-ref` - -*A second selection, `no-such-ref`, which no local ref carries, so the verb REFUSES (exit 1), picked at capture time from the refs this checkout really has and never the selection above: merged refs are OMITTED from the rows and counted in merged=; refs sharing no merge base with HEAD (a shallow clone, or a pre-rewrite history) land in unknown= with ok="0" — the counters always reconcile against refs=.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --stray-content=no-such-ref matches no local ref — a zero here would be a failure, not a measurement - (the filter is a substring match against refs/heads names; run bare --stray-content to list them, e.g. --stray-content=feat/) -````` - -## `./build/ripwire . --stray-content=b155 --plan` - -*Select the genuinely-unmerged refs of the one branch `b155` (no ref family left to select on this checkout) and feed them to merge-scout for a landing order (a fully merged selection yields an empty landing set — still a measurement, disclosed on the root).* - -````` - - - -````` - -## `./build/ripwire . --stray-content=zzzz-no-such-ref --plan` - -*A --plan filter that selects NO ref REFUSES (exit 1) naming the substring — before the wave-3 close this fell through to the '>512 refs match' sentence, and --abi under the same filter answered an empty measurement at exit 0.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --plan: --stray-content=zzzz-no-such-ref matches no local ref — a zero here would be a failure, not a measurement - (the filter is a substring match against refs/heads names; run bare --stray-content to list them, e.g. --stray-content=feat/) -````` - -## `./build/ripwire . --stray-content=b155 --abi` - -*Cross-branch ABI-break gate over the one branch `b155` (no ref family left to select on this checkout): struct byte-contract drift on each ref's AUTHORED paths — exit 2 when any drift row is found (the only kind that gates), 0 when the compared refs are clean, and exit 1 if the --stray-content filter matches no ref at all.* - -````` - - - -````` - -## `./build/ripwire . --whereis=rankGraphTeleport` - -*Which ref's tree defines or mentions SYM — HEAD first, then every local branch. The default lists the kind="def" rows (here the first 60, most on branches, each carrying tip= and date=) and counts the references in : on this symbol HEAD's references would fill the 60-row cap before the branch definitions arrive, so the whole list (below) shows fewer definitions, and the default serves the page that shows more of them, whatever its bytes.* - -**wall time: 1.23s** - -````` - - - - -<.hereis> -````` - -## `./build/ripwire . --whereis=rankGraphTeleport --whereis-listing=all` - -*The whole hit list asked for by name: under the same 60-row cap HEAD's references fill the list, so it shows far fewer definitions (here HEAD's one) than the default above (here 60). The default serves the all page only when it shows the same definitions as the defs page in strictly fewer bytes (a tie serves it too).* - -**wall time: 1.25s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [35 more display lines; full output is 12690 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --quality-delta=HEAD~1..HEAD --quality-kinds=complexity,dead-code` - -*A ref range run for two of the twelve kinds only: the named kinds' rows are exactly their rows in the full answer, the header names the others (kinds_skipped=, skipped_why="selector"), and a pass no named kind needs does not run. The replay a memory-stopped range answer hands back (kinds_next=) is this flag. Refused without --quality-delta=A..B.* - -**wall time: 7.61s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [34 more display lines; full output is 13667 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --whereis=computeOnePairOverlap --with-history` - -*Same, plus a git-history row (never / removed-by-commit) for names no tree carries.* - -**wall time: 11.54s** - -````` - - - - - -<.hereis> -````` - -## `./build/ripwire . --flags` - -*The dark-content dashboard: gates BUILT but OFF. CHANGED: no longer invents gates from comments/heredocs, so the count only reflects real ifndef/define, CMake option(), and getenv gates.* - -**wall time: 1.18s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [400 more display lines; full output is 24541 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --flags --flip=RIPWIRE_ASAN` - -*Blast radius of turning ONE gate on: live code, symbols, transitive reach, covering tests.* - -**wall time: 1.16s** - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --flags --flip=RIPWIRE_ASA` - -*Unknown-gate refusal (exit 1) with a did-you-mean from a real edit distance (one character off RIPWIRE_ASAN).* - -**exit code: 1** — **wall time: 1.12s** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --flip: no gate named 'RIPWIRE_ASA' in . (did you mean 'RIPWIRE_ASAN'?) -ripwire: run `ripwire . --flags` for the gate table -````` - -## `./build/ripwire . --plan-lanes=3 --task="add a --since filter to the doc-drift verb and cover it with tests"` - -*NEW VERB: pre-hoc lane plan — which of 3 parallel worktrees would COLLIDE, before a line is written. JSON on stdout.* - -**wall time: 1.52s** - -````` -{"v":1,"verb":"plan-lanes","at":"e47df2266","root":".","task":"add a --since filter to the doc-drift verb and cover it with tests","source":"partition","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3607,"symbols":31702,"edges":299 … [line truncated: 338 more bytes on this line] -"symbols":[{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","l":286,"id":"./src/docdrift.h::DriftResult::DriftResult"}, -{"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","l":2441,"id":"./src/docdrift.h::docdrift::computeDocDrift"}, -{"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","l":2739,"id":"./src/docdrift.h::docdrift::kDocDriftLegend"}, -{"p":"./src/docdrift.h","n":"writeDocDriftPage","scope":"docdrift","l":2909,"id":"./src/docdrift.h::docdrift::writeDocDriftPage"}, -{"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","l":655,"id":"./src/mcpverbs.h::rw::docDriftText"}, -{"p":"./src/verbs_change.h","n":"runDocDrift","scope":"","l":1678,"id":null}]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb and cover it with tests","claims":{"symbols":[{"p":"./src/verbs_change.h","n":"runAbiCheck","scope":"","key":"183da9aaf74a4a92","id":null,"id_addr … [line truncated: 113 more bytes on this line] -{"p":"./src/editcheck.h","n":"editCheckPriceRoot","scope":"rw","key":"33219bb04158a6a8","id":"./src/editcheck.h::rw::editCheckPriceRoot","id_addressable":true,"id_collides_with":0,"l":1202,"ord":0,"overloads":1,"amb":0,"cx":8,"ccx":10,"churn":57,"tested":0}, -{"p":"./src/docdrift.h","n":"writeGateability","scope":"docdrift","key":"42c456dfb55faee4","id":"./src/docdrift.h::docdrift::writeGateability","id_addressable":true,"id_collides_with":0,"l":2685,"ord":0,"overloads":1,"amb":2,"cx":6,"ccx":6,"churn":36,"tested":0}, -{"p":"./src/darkflags.h","n":"writeFlags","scope":"darkflags","key":"5c2c4a2b311b8dba","id":"./src/darkflags.h::darkflags::writeFlags","id_addressable":true,"id_collides_with":0,"l":1298,"ord":0,"overloads":1,"amb":1,"cx":8,"ccx":8,"churn":32,"tested":0}, -{"p":"./src/docdrift.h","n":"docDriftNextAttr","scope":"docdrift","key":"7723ed789a1c9c09","id":"./src/docdrift.h::docdrift::docDriftNextAttr","id_addressable":true,"id_collides_with":0,"l":2864,"ord":0,"overloads":1,"amb":0,"cx":6,"ccx":5,"churn":36,"tested":0}, -{"p":"./src/docdrift.h","n":"recordWeakDisclosures","scope":"docdrift","key":"972779210e49c0cf","id":"./src/docdrift.h::docdrift::recordWeakDisclosures","id_addressable":true,"id_collides_with":0,"l":2430,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":1,"churn":36,"tested":0}, -{"p":"./src/testmap.h","n":"scriptGatesUnmodelledCount","scope":"rw","key":"98c4487e2e9e08bc","id":"./src/testmap.h::rw::scriptGatesUnmodelledCount","id_addressable":true,"id_collides_with":0,"l":1793,"ord":0,"overloads":1,"amb":0,"cx":4,"ccx":4,"churn":61,"tested":0}, -{"p":"./src/main.cpp","n":"scanReportVerbPrecedence","scope":"","key":"9ab981e987e8108e","id":null,"id_addressable":false,"id_collides_with":0,"l":3031,"ord":0,"overloads":1,"amb":0,"cx":8,"ccx":11,"churn":453,"tested":0}, -{"p":"./src/pageview.h","n":"secondaryCutAttrs","scope":"rw","key":"a10ea8d3bdca1dfb","id":"./src/pageview.h::rw::secondaryCutAttrs","id_addressable":true,"id_collides_with":0,"l":399,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":28,"tested":0}, -{"p":"./src/main.cpp","n":"emitNoteAddUnprovenDefs","scope":"","key":"a950332ccfce6b8d","id":null,"id_addressable":false,"id_collides_with":0,"l":691,"ord":0,"overloads":1,"amb":1,"cx":2,"ccx":1,"churn":453,"tested":0}, -{"p":"./src/docdrift.h","n":"sortDocsByLiveDrift","scope":"docdrift","key":"d5de682411b9a9a9","id":"./src/docdrift.h::docdrift::sortDocsByLiveDrift","id_addressable":true,"id_collides_with":0,"l":2390,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":2,"churn":36,"tested":0}, -{"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5838,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":459,"tested":0}], -"files":[{"p":"./src/darkflags.h","symbols":1,"churn":32,"ccx":8,"hotspot_rank":55}, -{"p":"./src/docdrift.h","symbols":4,"churn":36,"ccx":14,"hotspot_rank":38}, -{"p":"./src/editcheck.h","symbols":1,"churn":57,"ccx":10,"hotspot_rank":42}, -{"p":"./src/main.cpp","symbols":2,"churn":453,"ccx":12,"hotspot_rank":5}, -{"p":"./src/mcpverbs.h","symbols":1,"churn":459,"ccx":2,"hotspot_rank":4}, -{"p":"./src/pageview.h","symbols":1,"churn":28,"ccx":2,"hotspot_rank":129}, -{"p":"./src/testmap.h","symbols":1,"churn":61,"ccx":4,"hotspot_rank":33}, -{"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":9,"hotspot_rank":25}]},"blast_radius":{"reaches":47,"files_total":16,"capped":false,"files":["./src/darkflags.h","./src/docdrift.h","./src/editcheck.h","./src/editplan.h","./src/editpreview.h","./src/flipimpact.h","./src/main.cpp","./src/mcp.h … [line truncated: 182 more bytes on this line] -"tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":47,"module_span":1,"notes":[], -"execution":{"policy":"codex-lane/v1","model":"gpt-5.6-terra","reasoning":"high","rule":"moderate-cross-module","basis":"structural-only","signals":{"claims":12,"files":8,"module_span":1,"max_ccx":11,"sum_ccx":61,"ambiguous_calls":6,"blast_reaches":47,"contract_touches":0,"conflicts":0,"untested":47 … [line truncated: 142 more bytes on this line] -{"id":"lane-1","task":"add a --since filter to the doc-drift verb and cover it with tests","claims":{"symbols":[{"p":"./src/gitmine.h","n":"gitWindowBoundarySha","scope":"rw","key":"18627516699d7062","id":"./src/gitmine.h::rw::gitWindowBoundarySha","id_addressable":true,"id_collides_with":0,"l":1674 … [line truncated: 69 more bytes on this line] -{"p":"./src/cli.h","n":"kViewFlags","scope":"rw","key":"2a2f2487082cc6d8","id":"./src/cli.h::rw::kViewFlags","id_addressable":true,"id_collides_with":0,"l":3327,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, -… [69 more display lines; full output is 20481 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --plan-lanes --brief=./build/sc/aux/lanes_brief.txt` - -*NEW VERB, explicit form: one line per lane, lane boundaries are the ones you wrote (the defensible mode).* - -**wall time: 1.62s** - -Input file: - -````` -add a --since filter to the doc-drift verb -add the CLI parse arm and help text for the new filter -write regression tests for the new filter -````` - -````` -{"v":1,"verb":"plan-lanes","at":"e47df2266","root":".","task":null,"source":"brief","requested":3,"lane_count":3,"claim_key":"path+scope+name","on_conflict":"producing-lane-rebases","corpus":{"files":3607,"symbols":31702,"edges":29921,"ambiguous":2932,"unresolved":15150},"carve":null,"core":{"files" … [line truncated: 4 more bytes on this line] -"symbols":[]},"lanes":[{"id":"lane-0","task":"add a --since filter to the doc-drift verb","claims":{"symbols":[{"p":"./src/docdrift.h","n":"recordUnchecked","scope":"docdrift","key":"12641dab14abc8fd","id":"./src/docdrift.h::docdrift::recordUnchecked","id_addressable":true,"id_collides_with":0,"l":2 … [line truncated: 72 more bytes on this line] -{"p":"./src/docdrift.h","n":"sortWeakGroupsByPath","scope":"docdrift","key":"1944ba506280ff80","id":"./src/docdrift.h::docdrift::sortWeakGroupsByPath","id_addressable":true,"id_collides_with":0,"l":2401,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":36,"tested":0}, -{"p":"./src/mcpverbs.h","n":"docDriftText","scope":"rw","key":"1fa68e8d93c05a59","id":"./src/mcpverbs.h::rw::docDriftText","id_addressable":true,"id_collides_with":0,"l":655,"ord":0,"overloads":1,"amb":0,"cx":1,"ccx":0,"churn":459,"tested":0}, -{"p":"./src/cli.h","n":"kViewFlags","scope":"rw","key":"2a2f2487082cc6d8","id":"./src/cli.h::rw::kViewFlags","id_addressable":true,"id_collides_with":0,"l":3327,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, -{"p":"./src/recall.h","n":"docFileMask","scope":"rw","key":"3149a219f599664c","id":"./src/recall.h::rw::docFileMask","id_addressable":true,"id_collides_with":0,"l":110,"ord":0,"overloads":1,"amb":0,"cx":4,"ccx":4,"churn":27,"tested":0}, -{"p":"./src/docdrift.h","n":"writeDocDriftPage","scope":"docdrift","key":"380b7de5df1cfd73","id":"./src/docdrift.h::docdrift::writeDocDriftPage","id_addressable":true,"id_collides_with":0,"l":2909,"ord":0,"overloads":1,"amb":10,"cx":14,"ccx":15,"churn":36,"tested":0}, -{"p":"./src/docdrift.h","n":"computeDocDrift","scope":"docdrift","key":"3b19cc3d8996c3b2","id":"./src/docdrift.h::docdrift::computeDocDrift","id_addressable":true,"id_collides_with":0,"l":2441,"ord":0,"overloads":1,"amb":1,"cx":26,"ccx":38,"churn":36,"tested":0}, -{"p":"./src/docdrift.h","n":"DriftResult","scope":"DriftResult","key":"422ab39546b6e0bd","id":"./src/docdrift.h::DriftResult::DriftResult","id_addressable":true,"id_collides_with":0,"l":286,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":36,"tested":0}, -{"p":"./src/verbs_change.h","n":"runDocDrift","scope":"","key":"904831e5c0f66b39","id":null,"id_addressable":false,"id_collides_with":0,"l":1678,"ord":0,"overloads":1,"amb":1,"cx":5,"ccx":4,"churn":82,"tested":0}, -{"p":"./src/ensemble.h","n":"kEnsembleChurnSince","scope":"ensemble","key":"a34fc78c05bf56a8","id":"./src/ensemble.h::ensemble::kEnsembleChurnSince","id_addressable":true,"id_collides_with":0,"l":120,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":23,"tested":0}, -{"p":"./src/mcpverbs.h","n":"unknownSubVerbRefusal","scope":"rw","key":"e336d39b0a6addea","id":"./src/mcpverbs.h::rw::unknownSubVerbRefusal","id_addressable":true,"id_collides_with":0,"l":5838,"ord":0,"overloads":1,"amb":0,"cx":3,"ccx":2,"churn":459,"tested":0}, -{"p":"./src/docdrift.h","n":"kDocDriftLegend","scope":"docdrift","key":"ff2ba74637bbbebf","id":"./src/docdrift.h::docdrift::kDocDriftLegend","id_addressable":true,"id_collides_with":0,"l":2739,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":36,"tested":0}], -"files":[{"p":"./src/cli.h","symbols":1,"churn":511,"ccx":0,"hotspot_rank":6}, -{"p":"./src/docdrift.h","symbols":6,"churn":36,"ccx":54,"hotspot_rank":38}, -{"p":"./src/ensemble.h","symbols":1,"churn":23,"ccx":0,"hotspot_rank":105}, -{"p":"./src/mcpverbs.h","symbols":2,"churn":459,"ccx":2,"hotspot_rank":4}, -{"p":"./src/recall.h","symbols":1,"churn":27,"ccx":4,"hotspot_rank":64}, -{"p":"./src/verbs_change.h","symbols":1,"churn":82,"ccx":4,"hotspot_rank":25}], -"symbols_total":3458,"symbols_capped":true},"blast_radius":{"reaches":13,"files_total":7,"capped":false,"files":["./src/docdrift.h","./src/main.cpp","./src/mcp.h","./src/mcpserver.h","./src/mcpverbs.h","./src/recall.h","./src/verbs_for.h"]},"tests_to_run":[], -"tests_total":0,"tests_capped":false,"tests_granularity":"claimed-symbols","untested":13,"module_span":6,"notes":[], -"execution":{"policy":"codex-lane/v1","model":"gpt-5.6-sol","reasoning":"xhigh","rule":"wide-contract-work","basis":"structural-only","signals":{"claims":12,"files":6,"module_span":6,"max_ccx":38,"sum_ccx":64,"ambiguous_calls":12,"blast_reaches":13,"contract_touches":1,"conflicts":0,"untested":13,"t … [line truncated: 139 more bytes on this line] -{"id":"lane-1","task":"add the CLI parse arm and help text for the new filter","claims":{"symbols":[{"p":"./scripts/optremarks.py","n":"main","scope":"","key":"01b3b880f77d1512","id":null,"id_addressable":false,"id_collides_with":133,"l":279,"ord":0,"overloads":1,"amb":0,"cx":23,"ccx":31,"churn":14, … [line truncated: 12 more bytes on this line] -{"p":"./src/cli.h","n":"HelpLine","scope":"rw","key":"1489844dbc310b82","id":"./src/cli.h::rw::HelpLine","id_addressable":true,"id_collides_with":0,"l":2948,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, -{"p":"./src/cli.h","n":"HelpFilter","scope":"HelpFilter","key":"3103a5e8bfc33d38","id":"./src/cli.h::HelpFilter::HelpFilter","id_addressable":true,"id_collides_with":0,"l":3027,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":511,"tested":0}, -{"p":"./docs/docs_commands_build.py","n":"main","scope":"","key":"4015853681ded3bc","id":null,"id_addressable":false,"id_collides_with":133,"l":865,"ord":0,"overloads":1,"amb":0,"cx":19,"ccx":28,"churn":17,"tested":0}, -{"p":"./src/mcprefusal.h","n":"kMcpValueFields","scope":"rw::mcprefuse","key":"4a7106e488a2aa80","id":"./src/mcprefusal.h::rw::mcprefuse::kMcpValueFields","id_addressable":true,"id_collides_with":0,"l":304,"ord":0,"overloads":1,"amb":0,"cx":0,"ccx":0,"churn":49,"tested":0}, -{"p":"./src/cli.h","n":"serveHelpSelector","scope":"rw","key":"4b247ee064fc4e94","id":"./src/cli.h::rw::serveHelpSelector","id_addressable":true,"id_collides_with":0,"l":3092,"ord":0,"overloads":1,"amb":1,"cx":4,"ccx":3,"churn":511,"tested":0}, -{"p":"./src/query.h","n":"tryParsePredicateOnAll","scope":"query","key":"786acc4dbfec612b","id":"./src/query.h::query::tryParsePredicateOnAll","id_addressable":false,"id_collides_with":1,"l":113,"ord":0,"overloads":2,"amb":0,"cx":1,"ccx":0,"churn":20,"tested":0}, -{"p":"./src/cli.h","n":"printUsageTier","scope":"rw","key":"82b7af67acdca479","id":"./src/cli.h::rw::printUsageTier","id_addressable":true,"id_collides_with":0,"l":3078,"ord":0,"overloads":1,"amb":0,"cx":2,"ccx":1,"churn":511,"tested":0}, -… [60 more display lines; full output is 18606 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --plan-lanes=99 --task=x` - -*Out-of-range refusal shape for the lane count.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --plan-lanes=99 is out of range — N must be 2..16 (1 is not a fan-out) -````` - -## `./build/ripwire . --layout=Symbol` - -*CPU/GPU contract view of one struct: computed offsets/sizes/padding + mirror check.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --layout=Lang` - -*The honest refusal (exit 1): Lang is an `enum class`, not a struct — no offsets are fabricated.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --layout: 'Lang' is an enum, --layout models structs (a scoped/unscoped enum's underlying type is not a byte layout) -````` - -## `./build/ripwire . --doc-drift` - -*Which of this repo's doc claims are now false. CHANGED: row attribute at= renamed to tgt= (at= is now only the root sha stamp).* - -````` - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -… [228 more display lines; full output is 23906 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --doc-drift --gateability` - -*The finishable to-do list: docs whose LIVE failing anchors a date-stamp would reclassify.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [255 more display lines; full output is 25161 bytes on 1 raw line(s)] -````` - -Tail of the same output — the `` section: - -````` - - - - - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --doc-drift --with-history` - -*Same report, with git history splitting stale mentions into deleted-by-commit vs never-existed.* - -````` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -… [208 more display lines; full output is 23885 bytes on 1 raw line(s)] -````` - -## `./build/ripwire . --from-trace=-` - -*Map a pasted stack trace onto indexed symbols. CHANGED: in_corpus= now reports the real count (was 0).* - -Input file: - -````` -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:11793 - #1 0x102f3e884 in rw::rankGraph(Graph const&, float) src/graph.h:11834 - #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) -==41337==ABORTING -````` - -````` - - - - - - - - - - - -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] - -uniform-teleport PageRank (the defaultinline RankedGraph rankGraph( const Graph& g, float alpha = 0.85f ) -int runDefaultMap( const MainDispatch& d ) -int main( int argc, char** argv ) - - - -& p, float alpha = 0.85f ) -{ - PROFILE_SCOPE_DESCRIBE( "rankGraph: PageRank (power iteration)" ); - const std::vector pw = biasPrior( g, p ); - const std::size_t N = pw.size(); - std::vector teleport( pw.begin(), pw.end() ); - std::vector rankDouble( N, 0.0 ); - PageRankRun run{}; // an N == 0 graph never enters the kernel: { 0, converged } — see PageRankRun - if( N ) - { - double teleportMass = 0.0; -… [18 more display lines; full output is 4915 bytes on 29 raw line(s)] -````` - -## `./build/ripwire . --notes` - -*List all field notes (write-side memory) — the committed .ripwire_notes at the repo root, each with the sha/branch it was recorded at.* - -````` - - - - - - - - - - - gate scripts' claim (~line 1305) is NOT enforced — the derived-vs-stated sibling loop here covers docs/EVALS.md only. It drifted 407→451 unnoticed (fixed 2026-08-23). To close: grep both files ('file:line:' parsing) in the gateCountClaims arm.]]> - - - - -````` - -## `./build/ripwire . --pack-task="add a new output format flag to the CLI"` - -*ONE budget-shared bundle: ranking + top bodies + caller sigs + notes + tests_to_run. CHANGED: rows now carry n=/id=.* - -````` - - - - -Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept - -claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of its newlineinline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) - -ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION does not vary by agent — only the MCP alternative does. Before this there were four near-identical CLI-fiinline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, c … [line truncated: 83 more bytes on this line] - -mcp-tools pass-through. Written into the server command only where its argument shape is known to be one more plain argument: the JSON args arrays (cursor.indsurf/gemini), opencode's command arrayinline bool wrapWritesToolsArg( const AgentTarget& row ) noexcept - -L8 (train 29): the NEXT PAGE of a callers listing — the CLI --callers root's next=, find_referencing_symbols' next and find_symbol's calledBy_next all name this one call, so the three cannot spell tinline std::string callHierarchyPageNext( bool wantCallers, std::string_vi … [line truncated: 98 more bytes on this line] -inline std::string classNewGroupXml( const IngestResult& ing, std::span<const ClassNewRow> rows, std::string_view rootPrefix, EscapeFn ex ) - - - - - - - - - -… [67 more display lines; full output is 12092 bytes on 59 raw line(s)] -````` - -## `./build/ripwire . --pack-task="add a new output format flag to the CLI" --partition=3` - -*Fan-out form: one shared core + 3 per-agent slices carved along call-graph communities.* - -````` - wraps a ; bundle role=core|partition i= symbols= modules= bytes= tokens=: one agent's ctx, symbols= ids assigned, bytes= its size; tokens= = est_tokens= = bytes/2.36 (flat, the densest rate; the inner ctx est_tokens= is language-weighted). Inner ctx task= root= budget_tokens= dropped_positive=: the task, p= base, the slice's token target, ranked candidates its budget cut. of_top=: rows ranked (far) / bodies (callers); s rel=caller|callee shared=: 1-hop edge, bodies reached (absent at 1). window: shown= total= capped= (capped=1 cut). run_unknown=1: no runner derivable (a guess would be worse). est_tokens=: price as emitted (an upper bound under compact). : rank N in this ranking, rows in r= order. : cyclomatic/cognitive complexity. : N callers in the index (absent: not measured). route=: the ranker: name-exact(X) = the task names symbol X (anchors: its evidence), subtoken+body = conceptual BM25 (:broad = 1-2 plain words, plain rg may also win; :declined(...) = a name hit refused as a common name). sc=: enclosing scope; the full id is p::sc::n (p= of the row or its ) and selectors take it. next=: the one pasteable follow-up. pure=1: const/constexpr signature (Swift: non-mutating) and no transitive side effect found; a hint. partitions=/requested=: partitions carved / asked for. modules=/split=: call-graph groups found / cuts forced to split one. core_symbols=/surface=: ids in the shared core / core plus the assignable remainder. budget_per_agent_tokens=: one agent's budget, core_budget_tokens= plus partition_budget_tokens=. total_bytes=N: bytes of all bundles together. overlap_mean=/overlap_max=: pairwise Jaccard over the ids partitions name, before trimming. shared_symbols=/union_symbols=: ids two or more partitions name / ids any partition names. core_overlap=: share of the core surface a partition reaches anyway. layer=: built-in arch layer (game|infra|render|math|audio|ai|test) from a dir name in p=; absent if none. --> - - - - - -Print the authoritative CLI usage and flag catalog to the caller-provided output streaminline void printUsage( std::FILE* out ) noexcept - -claude's `mcp add … -- ripwire --mcp`: the flag goes on the end of that command line, ahead of…inline std::string wrapCliAddPost( const AgentTarget& row, std::string_view toolsArg ) - -ONE recipe path for every agent that can shell out, and the point is that the RECOMMENDATION doe…inline void wrapEmitCliFirst( const AgentTarget& row, const std::string& token, const std::string_view executablePath, const WrapListing& listing ) noexcept - -mcp-tools pass-through. Written into the server command only where its argument shape is known t…inline bool wrapWritesToolsArg( const AgentTarget& row ) noexcept - - - - - -inline bool printUsageTier( std::FILE* out, HelpTier tier, std::string_view want ) noexcept - - - - - - - - -NodeId order. Renumbering an otherwise-identical graph (the exact "same probe file, different so…inline constexpr float kScoreTieAbsEps = 1e-6f - -Render one form of the disclosure. Empty string whenever there is nothing to say — no power it…inline std::string renderDisclosure( const RankDisclosure& d, DiscloseAs as ) - -The PageRank power iteration itself — the numeric kernel every ranked document's order comes f…PageRankRun pageRankDouble( const sparseCsr<float>& inEdges, std::span<const double> weightedOutDegree, std::span<const double> teleport, std::span<double> r … [line truncated: 10 more bytes on this line] -inline std::string rankByText( const std::string& root, std::string_view mode, int topK, bool stable = false ) -struct RankedGraph -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… -inline std::uint32_t sliceRdIterationCeiling() noexcept -struct PageRankRun - -What a ranked document discloses about the power iteration that ordered it. `isPageRank == false…struct RankDisclosure -inline std::uint32_t navRelevanceWeight( const Graph& g, NodeId n ) noexcept -inline RankedGraph rankGraphTeleport( const Graph& g, const std::vector<float>& p, float alpha = 0.85f ) -inline constexpr std::string_view kPowerShellPathPrependScope = "in PowerShell, for this window -inline std::string powerShellPathPrependHint( std::string_view programDir ) noexcept -inline std::string powerShellSingleQuote( std::string_view s ) noexcept -inline std::string path_prepend_hint( std::string_view dir ) -HOT_FILES = ( "src/pagerank.cpp", # the power-iteration loop — G2's no-allocation scope "src/infra/radixSort.h", # LSD radix entry points "src/infra/radixSort.inl", # the counting … [line truncated: 76 more bytes on this line] -handle_t leftmost_leaf() const -inline void discloseUniformChurnFallback( bool hasChurnEvidence, bool stubbed, const char* verbLabel, const std::string& windowStamp ) -inline std::string doctorPathPrependLine( const std::string& selfPath ) -inline std::string doctorWhichRipwire( rw::os::stat_t& st ) -std::uint32_t testIterationCeiling() noexcept -inline const char* rankByLegendFor( const char* label ) noexcept -… [124 more display lines; full output is 19081 bytes on 10 raw line(s)] -````` - -## `./build/ripwire . --export=cc.json:./build/sc/aux/ripwire2.cc.json` - -*Per-file metrics as CodeCharta cc.json.* - -**wall time: 1.47s** - -````` -(empty) -````` - -Artifact written: - -````` -559268 ./build/sc/aux/ripwire2.cc.json -{"projectName":"project","apiVersion":"1.3","attributeDescriptors":{"loc":{"title":"Lines of Code","description":"Physical line count","direction":-1},"symbols":{"title":"Symbols","description":"Definitions in the file","direction":-1},"cx":{"title":"Cyclomatic Complexity","description":"Sum of per-symbol cyclomatic complexity","direction":-1},"cognitive_cx":{"title":"Cognitive Complexity","descri -````` - -## `./build/ripwire . --batch=./build/sc/aux/batch2.txt` - -*One-turn sweep: 4 newline-delimited verb:arg sub-queries answered in ONE deduped .* - -**wall time: 2.60s** - -Input file: - -````` -for:incremental cache invalidation -callers:rankGraphTeleport -grep:DISCLOSE -lego:Vehicle -````` - -````` - - - - - - - - - -incremental cache (--cache): per-file content hash + raw facts so a re-run re-parses ONLY c…constexpr std::uint32_t kCacheMagic = 0x4b505443 - -Composed exactly the way every OTHER blob family is (quality.h): one fixed-width identity hex pe…inline std::string spanTierMemoPath( const std::string& diskPath ) - -Ingest the tree at `sha`, materialized out of `root`'s object store. The HEAD side reuses the SA…inline bool ingestCommitTree( const std::string& root, const std::string& sha, const std::vector<std::string>& excludes, std::size_t maxFileBytes, IngestResult&… … [line truncated: 4 more bytes on this line] - -P1-15 — the `_reingest` envelope field for a response whose handling ran an INCREMENTAL pass, …inline bool mcpRefreshedThisRequest( std::uint64_t passesAtEntry ) -struct FileHealth -inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::ve … [line truncated: 8 more bytes on this line] -inline std::pair<Snapshot, bool> computeHeadSnapshot( const std::string& root, const std::string_view* cacheNever = nullptr, std::size_t maxFileBytes = kDefault… -inline RawFacts runParsePool( IngestResult& result, const char* rootDir, std::string_view cacheFile, bool captureValueUses, HashMap<std::string, FileFacts>& cache, const CacheLoadStats& cac … [line truncated: 66 more bytes on this line] -inline McpRebuildBaseline mcpRebuildBaseline( const McpIndex& ix, bool isIncrementalPass ) -inline const McpIndex& getIndex( const std::string& root ) -inline std::string mcpFreshFields( std::uint64_t passesAtEntry ) -struct McpIndex -inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) -IngestResult ingest( const char* rootDir, const std::vector<std::string>& excludeSubstr, std::string_view cacheFile, std::size_t maxFileBytes, bool captureValueUses, std::string_view excludeLabel, bool … [line truncated: 37 more bytes on this line] -const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) -static bool cachePathIsDirectory( const std::string& cachePath ) -inline std::string oracleCachePath( const std::string& root, const std::string& headSha ) -HashMap<const TSLanguage*, TSQuery*>& compiledQueryCache() -… [107 more display lines; full output is 51596 bytes on 1 raw line(s)] -````` - - ---- - -# self-diagnosis - -## `./build/ripwire . --doctor` - -*Environment self-check: binary staleness, grammars, cache dir, git, tracked-binary staleness — exit 1 when any check fails (here: the PATH install is older than ./build).* - -**exit code: 1** — **wall time: 1.55s** - -````` - - - - - - - - - - -````` - -stderr: - -````` -ripwire --doctor: no ripwire resolves from PATH. To put this binary's directory first (for this shell; put the same line in your shell rc file), paste this line: -export PATH='./build':"$PATH" -````` - - ---- - -# security - -## `./build/ripwire --scan-skill=skills/ripwire-orient/SKILL.md` - -*Scan a single skill file for injection/exfiltration patterns before installing.* - -````` - - - -````` - -stderr: - -````` -ripwire scan: 0 finding(s) in skills/ripwire-orient/SKILL.md -````` - -## `./build/ripwire --scan-skills=skills` - -*Scan a whole skills directory (exit 2 = CRITICAL, 1 = WARN). Explicit-DIR form only.* - -````` - - - -````` - -stderr: - -````` -ripwire scan: 0 finding(s) total (26 skill file(s) scanned, 0 unscannable file(s) skipped, 0 denylisted subtree(s) not descended) -````` - - ---- - -# knobs / modes - -## `./build/ripwire . --rank-by=churn --top-k=5` - -*Rank by git change-frequency prior instead of PageRank.* - -**wall time: 1.50s** - -````` - - - - - - - - - - - - - - - - - - - - - -````` - -## `./build/ripwire . --rank-by=churn-decay --since=HEAD~5 --exclude=test --exclude=docs --exclude=skills --exclude=changelog.d --in=src --limit=3` - -*Scope the recent-changes answer to ONE directory. 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=bogus --top-k=5` - -*An unknown value REFUSES (exit 1), NAMED, with the supported set listed.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --rank-by: unknown value 'bogus' (supported: pagerank|authority|hub|rrf|churn|churn-decay) -````` - -## `./build/ripwire . --callers=rankGraphTeleport --format=columnar` - -*Columnar output: paths table + parallel arrays, ~15-60% fewer tokens on MANY-row lists — small results can be LARGER (the columnar legend is a fixed cost).* - -````` - - -0=src/mcpindex.h 1=src/graph.h 2=src/eval.h 3=src/main.cpp - -0,1,1,2,3,3,3 -getIndex,rankGraph,anchoredLexicalRank,runEval,churnDecayRanking,churnRankedGraph,runDefaultMap -1184,11832,12478,171,1425,1464,1751 -fn,fn,fn,fn,fn,fn,fn -0,0,0,0,0,0,0 -src/mcpindex.h:1288,src/graph.h:11835,src/graph.h:12529,src/eval.h:328,src/main.cpp:1439,src/main.cpp:1478 src/main.cpp:1479 src/main.cpp:1493,src/main.cpp:1871 - - -````` - -## `./build/ripwire . --for="cache invalidation" --format=candidates --top-k=5` - -*Flat top-K export for an external reranker.* - -**wall time: 1.35s** - -````` - - - -inline std::string spanTierMemoPath( const std::string& diskPath ) - - -inline std::vector<std::vector<NodeId>> legoImplementorsOnSurface( const IngestResult& ing, const std::vector<std::vector<NodeId>>& implementors, const std::vector<NodeId>& surfaceIds ) - - -### See the map — not just the numbers - - -inline std::string receiptNextFor( const std::string& fileIdentity, const std::string& symbolName, const std::string& foldJson, const std::string& firstTestRun ) - - -const char* cacheArtifactVerdict( const std::string& path, bool captureValueUses ) - - -````` - -## `./build/ripwire . --callers=rankGraphTeleport --format=bogus` - -*An unknown --format value REFUSES (exit 1), named, with the supported set listed.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --format: unknown value 'bogus' (supported: xml|columnar|rows|candidates) -````` - -## `./build/ripwire . --callers=rankGraphTeleport --json` - -*Machine-parseable JSON, same content, keys mirror the XML attrs.* - -````` -{"of":"rankGraphTeleport","defs":1,"count":7,"root":".","hop_tested":0,"hop_untested":7,"graph_ambiguous":2932,"graph_unresolved":15150,"graph_unindexed":269,"counts_floor":true,"callers":[{"t":"fn","n":"getIndex","p":"src/mcpindex.h:1184","sites_at":["src/mcpindex.h:1288"]}, -{"t":"fn","n":"rankGraph","p":"src/graph.h:11832","sites_at":["src/graph.h:11835"]}, -{"t":"fn","n":"anchoredLexicalRank","p":"src/graph.h:12478","sites_at":["src/graph.h:12529"]}, -{"t":"fn","n":"runEval","p":"src/eval.h:171","sites_at":["src/eval.h:328"]}, -{"t":"fn","n":"churnDecayRanking","p":"src/main.cpp:1425","sites_at":["src/main.cpp:1439"]}, -{"t":"fn","n":"churnRankedGraph","p":"src/main.cpp:1464","sites_at":["src/main.cpp:1478","src/main.cpp:1479","src/main.cpp:1493"]}, -{"t":"fn","n":"runDefaultMap","p":"src/main.cpp:1751","sites_at":["src/main.cpp:1871"]}]} -````` - -## `./build/ripwire . --hotspots --json` - -*JSON refusal shape: an unsupported verb refuses loudly instead of silently falling back to XML.* - -**exit code: 1** - -````` -(empty) -````` - -stderr: - -````` -ripwire: --json is not yet supported for --hotspots — supported: the default map, --for, --pack-task, --callers/--callees, --impact, --quality-delta, --test-gate, --metrics, and --plan-lanes which is JSON-native (e.g. ripwire