@backbencher/brain 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +298 -0
- package/EMBEDDINGS.md +355 -0
- package/LICENSE +21 -0
- package/README.md +415 -2
- package/bin/bb +13 -0
- package/dist/analysis-exclusions-7ZJDXOVZ.js +35 -0
- package/dist/brain-index-health-KY7K552E.js +17 -0
- package/dist/brain-relationship-enrichment-QH7OOHUF.js +558 -0
- package/dist/brain.sql-EIM4WS4D.js +29 -0
- package/dist/chunk-2BSKD7O3.js +40 -0
- package/dist/chunk-2DE27DVC.js +1314 -0
- package/dist/chunk-2RRBMNBQ.js +322 -0
- package/dist/chunk-2RTN2DFU.js +711 -0
- package/dist/chunk-2WXYNLBA.js +29 -0
- package/dist/chunk-3CTFIJJB.js +17 -0
- package/dist/chunk-3LFTSMIV.js +174 -0
- package/dist/chunk-47HKX4AJ.js +930 -0
- package/dist/chunk-4H22TLOT.js +543 -0
- package/dist/chunk-5SD45FLC.js +818 -0
- package/dist/chunk-66A5ZFYA.js +1758 -0
- package/dist/chunk-6AIRWAO2.js +247 -0
- package/dist/chunk-6WNGD3NN.js +196 -0
- package/dist/chunk-7AN7U5IZ.js +371 -0
- package/dist/chunk-BHB7BYYI.js +626 -0
- package/dist/chunk-BQ3OVQ3P.js +125 -0
- package/dist/chunk-CW4XXSNN.js +1479 -0
- package/dist/chunk-D2Q4Y47A.js +53 -0
- package/dist/chunk-DIYAGQJL.js +34 -0
- package/dist/chunk-DYM4FQEE.js +90 -0
- package/dist/chunk-EWMWK7WN.js +75 -0
- package/dist/chunk-FVVQTSIM.js +3427 -0
- package/dist/chunk-FWSL4VG6.js +1290 -0
- package/dist/chunk-GBI7V7KY.js +69 -0
- package/dist/chunk-GEFFO6O2.js +152 -0
- package/dist/chunk-HOWAQXJO.js +236 -0
- package/dist/chunk-HQSPJDHI.js +613 -0
- package/dist/chunk-IFZNR5UJ.js +2863 -0
- package/dist/chunk-J4PMBXQQ.js +336 -0
- package/dist/chunk-KAET47ZL.js +125 -0
- package/dist/chunk-KCDECRJY.js +440 -0
- package/dist/chunk-KLK3PBTO.js +1119 -0
- package/dist/chunk-L5TDYKYK.js +76 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-OWISBAOF.js +61 -0
- package/dist/chunk-PJTNGD3Z.js +6924 -0
- package/dist/chunk-QLK6ED4Q.js +235 -0
- package/dist/chunk-R2GW4F6R.js +19 -0
- package/dist/chunk-RCMTFSEF.js +87 -0
- package/dist/chunk-RH7KC5HU.js +12050 -0
- package/dist/chunk-RM3PY6TG.js +376 -0
- package/dist/chunk-ROMM6KMC.js +433 -0
- package/dist/chunk-SK6YVHFZ.js +211 -0
- package/dist/chunk-SM7RFQRO.js +214 -0
- package/dist/chunk-UFE77L67.js +782 -0
- package/dist/chunk-UGR4QIGS.js +67 -0
- package/dist/chunk-UUNHHX4M.js +13 -0
- package/dist/chunk-V44PGPA6.js +2104 -0
- package/dist/chunk-VL52PL2T.js +71 -0
- package/dist/chunk-VURYFIHW.js +201 -0
- package/dist/chunk-XJKJYIPP.js +7436 -0
- package/dist/chunk-YI6FF2ZR.js +340 -0
- package/dist/cli/index.js +37 -0
- package/dist/config-HZAAYDP3.js +10 -0
- package/dist/content-search-642F7E5V.js +593 -0
- package/dist/database-TCTZDLE5.js +9 -0
- package/dist/doctor-GXCKSJOX.js +395 -0
- package/dist/edit-engine-KM7MPFEC.js +51 -0
- package/dist/engine-42TZFNIZ.js +11 -0
- package/dist/engine-LO6L4JLQ.js +18 -0
- package/dist/fingerprint-XDXFRWO6.js +33 -0
- package/dist/framework-intelligence-DWFCKV44.js +860 -0
- package/dist/freshness-3K6VU5OT.js +174 -0
- package/dist/graph-engine-PL5YA7BA.js +21 -0
- package/dist/graph_request-MM4REP6H.js +350 -0
- package/dist/impact_request-WDE47IZ5.js +68 -0
- package/dist/index-space-IUUN5WYV.js +15 -0
- package/dist/index-status-6BD7UBHR.js +34 -0
- package/dist/index.js +159 -0
- package/dist/instance-FO6QZRLH.js +19 -0
- package/dist/language-detection-DFCAU5DZ.js +11 -0
- package/dist/lsp/server.js +4301 -0
- package/dist/mcp/server.js +132 -0
- package/dist/onboard-DIQZV2NW.js +161 -0
- package/dist/override-companion-pass-XR7MHTP7.js +117 -0
- package/dist/parallel-indexer-4PW3AFXP.js +88 -0
- package/dist/pool-worker.js +1153 -0
- package/dist/project-health-ZS5TS2Z6.js +94 -0
- package/dist/project-index-5SDPHITE.js +57 -0
- package/dist/project-registry-DGZBIZS7.js +355 -0
- package/dist/real-bash-analyzer-SXSV67E2.js +2201 -0
- package/dist/real-c-analyzer-SY7FTZ6W.js +5942 -0
- package/dist/real-clean-analyzer-IGDHHLZK.js +3470 -0
- package/dist/real-clojure-analyzer-4OH7IWLB.js +2818 -0
- package/dist/real-cpp-analyzer-7LTDRJRJ.js +4101 -0
- package/dist/real-csharp-analyzer-KICU3TLH.js +3298 -0
- package/dist/real-css-analyzer-HPU277Q6.js +15 -0
- package/dist/real-dart-analyzer-7LZ5LCMW.js +3944 -0
- package/dist/real-elixir-analyzer-BE3MEVZO.js +2192 -0
- package/dist/real-erlang-analyzer-BZMAKYBK.js +1731 -0
- package/dist/real-fsharp-analyzer-5QLTOV3E.js +2390 -0
- package/dist/real-go-analyzer-POD7MZQR.js +4126 -0
- package/dist/real-graphql-analyzer-MAQRZ6QW.js +1442 -0
- package/dist/real-groovy-analyzer-MEWSUPMJ.js +2285 -0
- package/dist/real-haskell-analyzer-I5L2GR3Y.js +2533 -0
- package/dist/real-hcl-analyzer-DBOPXSWJ.js +725 -0
- package/dist/real-html-analyzer-O63XZLZD.js +1759 -0
- package/dist/real-java-analyzer-CHCW3EKA.js +4677 -0
- package/dist/real-javascript-analyzer-QAAJQYZE.js +14 -0
- package/dist/real-json-analyzer-UGBR7YQN.js +1640 -0
- package/dist/real-julia-analyzer-35Q4GHOZ.js +2085 -0
- package/dist/real-kotlin-analyzer-GRAYCWW2.js +3956 -0
- package/dist/real-lua-analyzer-5BAPDZDF.js +1957 -0
- package/dist/real-makefile-analyzer-YJKAHNAS.js +920 -0
- package/dist/real-markdown-analyzer-UKUQZO4F.js +1215 -0
- package/dist/real-matlab-analyzer-FVIKQZKG.js +480 -0
- package/dist/real-nim-analyzer-M7FAIABG.js +3603 -0
- package/dist/real-objective-c-analyzer-XMYQIGQI.js +1518 -0
- package/dist/real-perl-analyzer-ZLY6M2DZ.js +1865 -0
- package/dist/real-php-analyzer-KI2ZAM7X.js +9368 -0
- package/dist/real-powershell-analyzer-B3T5ZP6U.js +2915 -0
- package/dist/real-protobuf-analyzer-23OZ75XV.js +867 -0
- package/dist/real-python-analyzer-I4TIUB6D.js +4880 -0
- package/dist/real-r-analyzer-FJZJXXS6.js +2596 -0
- package/dist/real-ruby-analyzer-M3UFIVTQ.js +2429 -0
- package/dist/real-rust-analyzer-LVSONPAN.js +3359 -0
- package/dist/real-scala-analyzer-CWPI33Q2.js +3293 -0
- package/dist/real-scss-analyzer-TGRJQ7TH.js +1515 -0
- package/dist/real-solidity-analyzer-4P2VBVWA.js +2608 -0
- package/dist/real-sql-analyzer-J7DYZOZR.js +3840 -0
- package/dist/real-svelte-analyzer-NHEN2SX5.js +2532 -0
- package/dist/real-swift-analyzer-2NSYULWI.js +2311 -0
- package/dist/real-toml-analyzer-L3C66L7Q.js +929 -0
- package/dist/real-typescript-analyzer-FTC6ETRQ.js +14 -0
- package/dist/real-vb-analyzer-ORY7LAQS.js +3145 -0
- package/dist/real-vba-analyzer-JH2TTUFI.js +466 -0
- package/dist/real-vue-analyzer-OO4FUGBV.js +2680 -0
- package/dist/real-xml-analyzer-6CQVR477.js +2405 -0
- package/dist/real-yaml-analyzer-J6MQG3YX.js +3528 -0
- package/dist/real-zig-analyzer-EFKCPJNU.js +2430 -0
- package/dist/regex-search-OPTLKUN5.js +239 -0
- package/dist/rules-I453JTRC.js +152 -0
- package/dist/scoped-path-MJYWJZQX.js +11 -0
- package/dist/setup-show-Y5GB5KXA.js +15 -0
- package/dist/setup-wizard-G5YYR5T6.js +24 -0
- package/dist/symbol-search-KB4MU4SI.js +16 -0
- package/dist/taint-YOTN5X55.js +202 -0
- package/dist/taint-analyzer-N7YLZU3N.js +163 -0
- package/dist/tool-handlers-G4NAGJIH.js +72 -0
- package/dist/tool-registry-BPEJNSZG.js +17 -0
- package/dist/tool-validation-RF675A3C.js +32 -0
- package/dist/type-inference-4Y7WTMFE.js +13 -0
- package/dist/vector-binary-LMY4QGAN.js +19 -0
- package/dist/version-LXGNFO37.js +9 -0
- package/dist/wasm-NMWO3WXY.js +16 -0
- package/docs/EMBEDDINGS.md +132 -0
- package/docs/README.md +178 -0
- package/docs/data/m10-baseline.json +602 -0
- package/docs/data/m10-benchmark-baseline.json +57 -0
- package/docs/data/m10-benchmark-last-run.json +127 -0
- package/docs/data/m10-final-audit.json +215 -0
- package/docs/data/m12-final-audit.json +138 -0
- package/docs/data/m12-surface-matrix.json +50 -0
- package/docs/data/public-tools.json +1902 -0
- package/docs/indexing/DEAD-ASSETS.md +88 -0
- package/docs/indexing/INDEXER-REVIEW.md +634 -0
- package/docs/indexing/PERFORMANCE-FINDINGS.md +106 -0
- package/docs/indexing/README.md +427 -0
- package/docs/indexing/discovery-matrix.md +41 -0
- package/docs/indexing/embeddings.md +325 -0
- package/docs/indexing/environment-variables.md +77 -0
- package/docs/indexing/performance.md +323 -0
- package/docs/indexing/resume.md +345 -0
- package/docs/indexing/troubleshooting.md +391 -0
- package/docs/man/bb.1 +190 -0
- package/docs/tools/bb_analyze.md +147 -0
- package/docs/tools/bb_annotate.md +110 -0
- package/docs/tools/bb_annotations.md +106 -0
- package/docs/tools/bb_ask.md +101 -0
- package/docs/tools/bb_cross_language.md +103 -0
- package/docs/tools/bb_doc.md +169 -0
- package/docs/tools/bb_edit.md +185 -0
- package/docs/tools/bb_graph.md +169 -0
- package/docs/tools/bb_health.md +156 -0
- package/docs/tools/bb_impact.md +117 -0
- package/docs/tools/bb_index.md +108 -0
- package/docs/tools/bb_migrate.md +135 -0
- package/docs/tools/bb_patterns.md +140 -0
- package/docs/tools/bb_search.md +150 -0
- package/docs/tools/bb_security.md +100 -0
- package/docs/tools/bb_visualize.md +184 -0
- package/grammars/README.md +57 -0
- package/grammars/THIRD-PARTY-NOTICES.md +50 -0
- package/grammars/tree-sitter-c/LICENSE +21 -0
- package/grammars/tree-sitter-clojure/LICENSE.md +21 -0
- package/grammars/tree-sitter-cpp/LICENSE +21 -0
- package/grammars/tree-sitter-csharp/LICENSE +21 -0
- package/grammars/tree-sitter-css/LICENSE +21 -0
- package/grammars/tree-sitter-css/README.md +21 -0
- package/grammars/tree-sitter-dart/LICENSE +20 -0
- package/grammars/tree-sitter-dart-upstream/LICENSE +20 -0
- package/grammars/tree-sitter-dart-upstream/README.md +18 -0
- package/grammars/tree-sitter-elixir/LICENSE +176 -0
- package/grammars/tree-sitter-elixir/README.md +11 -0
- package/grammars/tree-sitter-fsharp/LICENSE +21 -0
- package/grammars/tree-sitter-fsharp/README.md +45 -0
- package/grammars/tree-sitter-graphql/LICENSE +21 -0
- package/grammars/tree-sitter-graphql/README.md +106 -0
- package/grammars/tree-sitter-groovy/LICENSE +21 -0
- package/grammars/tree-sitter-groovy/README.md +4 -0
- package/grammars/tree-sitter-haskell/LICENSE +21 -0
- package/grammars/tree-sitter-haskell/README.md +394 -0
- package/grammars/tree-sitter-hcl/CHANGELOG.md +102 -0
- package/grammars/tree-sitter-hcl/LICENSE +201 -0
- package/grammars/tree-sitter-hcl/README.md +39 -0
- package/grammars/tree-sitter-html/LICENSE +21 -0
- package/grammars/tree-sitter-html/README.md +21 -0
- package/grammars/tree-sitter-julia/LICENSE +21 -0
- package/grammars/tree-sitter-julia/README.md +24 -0
- package/grammars/tree-sitter-kotlin/LICENSE +9 -0
- package/grammars/tree-sitter-lua/LICENSE.md +21 -0
- package/grammars/tree-sitter-lua/README.md +29 -0
- package/grammars/tree-sitter-make/LICENSE +21 -0
- package/grammars/tree-sitter-matlab/LICENSE +19 -0
- package/grammars/tree-sitter-matlab/README.md +99 -0
- package/grammars/tree-sitter-nim/LICENSE +373 -0
- package/grammars/tree-sitter-nim/README.md +46 -0
- package/grammars/tree-sitter-objc/LICENSE +21 -0
- package/grammars/tree-sitter-objc/README.md +20 -0
- package/grammars/tree-sitter-perl/LICENSE +7 -0
- package/grammars/tree-sitter-perl/README.md +100 -0
- package/grammars/tree-sitter-powershell/LICENSE +21 -0
- package/grammars/tree-sitter-powershell/README.md +7 -0
- package/grammars/tree-sitter-proto/LICENSE +21 -0
- package/grammars/tree-sitter-proto/README.md +105 -0
- package/grammars/tree-sitter-r/LICENSE +9 -0
- package/grammars/tree-sitter-r/README.md +66 -0
- package/grammars/tree-sitter-ruby/LICENSE +22 -0
- package/grammars/tree-sitter-scss/LICENSE +21 -0
- package/grammars/tree-sitter-scss/README.md +17 -0
- package/grammars/tree-sitter-solidity/LICENSE +7 -0
- package/grammars/tree-sitter-sql/LICENSE +21 -0
- package/grammars/tree-sitter-typescript/LICENSE +21 -0
- package/grammars/tree-sitter-vba/LICENSE +21 -0
- package/grammars/tree-sitter-vba/README.md +738 -0
- package/grammars/tree-sitter-vbnet/LICENSE +21 -0
- package/grammars/tree-sitter-vbnet/README.md +322 -0
- package/grammars/tree-sitter-xml/LICENSE +19 -0
- package/grammars/tree-sitter-yaml/LICENSE +20 -0
- package/grammars/tree-sitter-yaml/README.md +21 -0
- package/package.json +184 -4
- package/wasm/dart.wasm +0 -0
- package/wasm/tree-sitter-bash.wasm +0 -0
- package/wasm/tree-sitter-c.wasm +0 -0
- package/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/wasm/tree-sitter-clean.wasm +0 -0
- package/wasm/tree-sitter-clojure.wasm +0 -0
- package/wasm/tree-sitter-core_schema.wasm +0 -0
- package/wasm/tree-sitter-cpp.wasm +0 -0
- package/wasm/tree-sitter-css.wasm +0 -0
- package/wasm/tree-sitter-dart.wasm +0 -0
- package/wasm/tree-sitter-elisp.wasm +0 -0
- package/wasm/tree-sitter-elixir.wasm +0 -0
- package/wasm/tree-sitter-elm.wasm +0 -0
- package/wasm/tree-sitter-embedded_template.wasm +0 -0
- package/wasm/tree-sitter-erlang.wasm +0 -0
- package/wasm/tree-sitter-fsharp.wasm +0 -0
- package/wasm/tree-sitter-fsharp_signature.wasm +0 -0
- package/wasm/tree-sitter-go.wasm +0 -0
- package/wasm/tree-sitter-graphql.wasm +0 -0
- package/wasm/tree-sitter-groovy.wasm +0 -0
- package/wasm/tree-sitter-haskell.wasm +0 -0
- package/wasm/tree-sitter-hcl.wasm +0 -0
- package/wasm/tree-sitter-html.wasm +0 -0
- package/wasm/tree-sitter-java.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-json.wasm +0 -0
- package/wasm/tree-sitter-json_schema.wasm +0 -0
- package/wasm/tree-sitter-julia.wasm +0 -0
- package/wasm/tree-sitter-kotlin.wasm +0 -0
- package/wasm/tree-sitter-lua.wasm +0 -0
- package/wasm/tree-sitter-make.wasm +0 -0
- package/wasm/tree-sitter-markdown.wasm +0 -0
- package/wasm/tree-sitter-markdown_inline.wasm +0 -0
- package/wasm/tree-sitter-matlab.wasm +0 -0
- package/wasm/tree-sitter-nim.wasm +0 -0
- package/wasm/tree-sitter-objc.wasm +0 -0
- package/wasm/tree-sitter-ocaml.wasm +0 -0
- package/wasm/tree-sitter-perl.wasm +0 -0
- package/wasm/tree-sitter-php.wasm +0 -0
- package/wasm/tree-sitter-php_only.wasm +0 -0
- package/wasm/tree-sitter-powershell.wasm +0 -0
- package/wasm/tree-sitter-protobuf.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-ql.wasm +0 -0
- package/wasm/tree-sitter-r.wasm +0 -0
- package/wasm/tree-sitter-rescript.wasm +0 -0
- package/wasm/tree-sitter-ruby.wasm +0 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
- package/wasm/tree-sitter-scala.wasm +0 -0
- package/wasm/tree-sitter-scss.wasm +0 -0
- package/wasm/tree-sitter-solidity.wasm +0 -0
- package/wasm/tree-sitter-sql.wasm +0 -0
- package/wasm/tree-sitter-svelte.wasm +0 -0
- package/wasm/tree-sitter-swift.wasm +0 -0
- package/wasm/tree-sitter-systemrdl.wasm +0 -0
- package/wasm/tree-sitter-terraform.wasm +0 -0
- package/wasm/tree-sitter-tlaplus.wasm +0 -0
- package/wasm/tree-sitter-toml.wasm +0 -0
- package/wasm/tree-sitter-tsx.wasm +0 -0
- package/wasm/tree-sitter-typescript.wasm +0 -0
- package/wasm/tree-sitter-vba.wasm +0 -0
- package/wasm/tree-sitter-vbnet.wasm +0 -0
- package/wasm/tree-sitter-vue.wasm +0 -0
- package/wasm/tree-sitter-xml.wasm +0 -0
- package/wasm/tree-sitter-yaml.wasm +0 -0
- package/wasm/tree-sitter-zig.wasm +0 -0
- package/wasm/tree-sitter.wasm +0 -0
- package/wasm/tsx.wasm +0 -0
- package/wasm/typescript.wasm +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Author: Muhammad Ishaq Khan
|
|
3
|
+
|
|
4
|
+
WHAT THIS DOCUMENT IS — the generated reference for bb_health: contract, input schema, returns, examples, errors, limitations, performance, safety and evidence semantics.
|
|
5
|
+
WHO IT IS FOR — callers of bb_health through any MCP host, the CLI (`bb tool bb_health`), or a library.
|
|
6
|
+
EDIT TOGETHER WHEN THIS CHANGES — src/mcp/tools/bb_health/descriptor.ts, src/mcp/tools/bb_health/handler.ts, script/tool-docs/curation/bb_health.ts; regenerate with `npx tsx script/verify-tool-docs.ts --only bb_health --write`.
|
|
7
|
+
-->
|
|
8
|
+
# `bb_health`
|
|
9
|
+
|
|
10
|
+
Unified index health: file/symbol/relationship/imports counts, embedding model + coverage, schema version, runtime, file freshness, what this call cost, and (when asked) the integrity battery, analysis-history totals and index completeness. There is no `mode` parameter: a call reports status, and `refresh`/`force` select the one behaviour that mutates the index. The default output names WHY each file was classified: `freshness why` separates fresh-verified-by-content-hash from fresh-verified-by-mtime+size-only (the file was not read), and names content-changed, deleted-from-disk, unreadable and unindexed separately, because those need different fixes and a single 'N stale' number is not actionable. Every report carries a top-level `healthy` boolean on the tool result (and inside the JSON payload when history=true): false exactly when the report contains an error-severity finding; a broken index is a successful REPORT, not a tool error (isError stays false), while wrong input is refused with isError. Options the chosen call cannot honour are refused: `limit` needs history=true; `wait` needs refresh/force; `sampleSize` belongs to sampled freshness only. Use verbose=true for a per-language breakdown, PER-LANGUAGE SEARCHABILITY (the share of each language's symbols a semantic query can reach — a language at 0% is invisible to bb_ask), the embedded/unembedded symbol kinds and stale-file names; verbose=true is also the only call that runs the per-symbol embedding aggregates, so a default call is bounded by the file count, not the symbol count. integrity=true runs the index integrity check battery, which NAMES each non-ok check with its remediation; with the default sampled freshness the battery falls back to a COMPLETE disk pass over the indexed files (it content-hashes files whose metadata changed), so it is materially more expensive than a status call. freshness="complete" (not a `complete` option) checks every indexed file instead of a sample; includeAnalysisRuns=true adds persisted run/finding totals; history=true answers with a JSON object { health, history, healthy } instead of the text report and is the only caller of `limit` (minimum 1, default 20). checkUnindexed=true walks the project and reports files the indexer would index but the index does not contain — a stat per eligible file, opt-in because a default call must not silently acquire a walk. refresh=true reindexes before reporting (`wait` defaults true; wait=false detaches it and the NEXT call reports the outcome once, success or failure); force=true wipes and rebuilds first and is DESTRUCTIVE. Freshness defaults to a DETERMINISTIC sample spread across the whole index: `stale` is then a lower bound on the project, not a total, and the report says so — pass freshness="complete" when you need the exact count.
|
|
11
|
+
|
|
12
|
+
## Contract
|
|
13
|
+
|
|
14
|
+
- Category: `lifecycle`
|
|
15
|
+
- Mutability: `read`
|
|
16
|
+
- Requires index: `false`
|
|
17
|
+
- Modes: `status`, `refresh`
|
|
18
|
+
- Planned modes (roadmap, not executable): (none)
|
|
19
|
+
- Defaults: `{"verbose":false,"history":false,"limit":20,"refresh":false,"force":false,"wait":true,"freshness":"sampled","sampleSize":200,"integrity":false,"includeAnalysisRuns":false}`
|
|
20
|
+
|
|
21
|
+
## Input Schema
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"verbose": {
|
|
28
|
+
"type": "boolean",
|
|
29
|
+
"description": "include the per-language breakdown, per-language searchability, embedded/unembedded symbol kinds, embedding config/chain and stale/missing file names (default false). This is the only value that runs the per-symbol embedding aggregates; a default call skips them so it stays bounded by the file count"
|
|
30
|
+
},
|
|
31
|
+
"history": {
|
|
32
|
+
"type": "boolean",
|
|
33
|
+
"description": "return persisted analysis history (default false). CHANGES THE OUTPUT SHAPE: this mode answers with a JSON object { health, history, healthy } instead of the text report, so a caller must not parse the text form when asking for it; the result also carries the same top-level `healthy` boolean as the text form"
|
|
34
|
+
},
|
|
35
|
+
"limit": {
|
|
36
|
+
"type": "number",
|
|
37
|
+
"description": "analysis-history page size (default 20); must be a whole number >= 1 and is only read when history=true — supplying it without history is REFUSED"
|
|
38
|
+
},
|
|
39
|
+
"refresh": {
|
|
40
|
+
"type": "boolean",
|
|
41
|
+
"description": "reindex the project before reporting"
|
|
42
|
+
},
|
|
43
|
+
"force": {
|
|
44
|
+
"type": "boolean",
|
|
45
|
+
"description": "force a full in-place reindex before reporting — DESTRUCTIVE: the index is wiped before it is rebuilt, so a failure leaves it empty"
|
|
46
|
+
},
|
|
47
|
+
"wait": {
|
|
48
|
+
"type": "boolean",
|
|
49
|
+
"description": "applies to refresh/force only (default true; supplying it without refresh/force is REFUSED). wait=false detaches the rebuild and returns the current snapshot; the NEXT call reports the detached outcome once — completion as well as failure"
|
|
50
|
+
},
|
|
51
|
+
"freshness": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": [
|
|
54
|
+
"sampled",
|
|
55
|
+
"complete"
|
|
56
|
+
],
|
|
57
|
+
"description": "freshness mode (default sampled — a deterministic, unbiased sample spread over every indexed file, NOT the first N; freshness=\"complete\" checks every indexed file and makes the stale count exact)"
|
|
58
|
+
},
|
|
59
|
+
"sampleSize": {
|
|
60
|
+
"type": "number",
|
|
61
|
+
"description": "freshness sample count (default 200); must be a whole number >= 1 and applies to freshness=\"sampled\" only — supplying it together with freshness=\"complete\" is REFUSED"
|
|
62
|
+
},
|
|
63
|
+
"integrity": {
|
|
64
|
+
"type": "boolean",
|
|
65
|
+
"description": "run the index integrity check battery (14 checks, each named with its remediation when not ok). Cost: with the default sampled freshness the battery performs a COMPLETE disk pass over the indexed files (content-hashing those whose metadata changed), so this is the most expensive opt-in"
|
|
66
|
+
},
|
|
67
|
+
"includeAnalysisRuns": {
|
|
68
|
+
"type": "boolean",
|
|
69
|
+
"description": "add persisted analysis run/finding totals (full-table counts, not a page length)"
|
|
70
|
+
},
|
|
71
|
+
"paths": {
|
|
72
|
+
"type": "array",
|
|
73
|
+
"items": {
|
|
74
|
+
"type": "string"
|
|
75
|
+
},
|
|
76
|
+
"description": "report the state of these project-relative files INSTEAD of a project-wide freshness answer — for the question an agent actually has after an edit, at O(files named) rather than O(project). At most 50, no duplicates, no blank entries. The answer is a SEPARATE self-describing block, so every other number in the report stays project-wide and the two can never be read as one. Each path is FIVE-state, not a boolean: fresh (indexed, on disk, unchanged), stale (content changed), gone (indexed, no longer readable on disk — `reason` distinguishes file-gone from unreadable), NOT-INDEXED (on disk, the indexer has not run since it appeared — a freshness verdict here would be meaningless), or absent (no such path). Paths that resolve outside the project, or through a symlink out of it, are REFUSED and reported as unchecked rather than answered"
|
|
77
|
+
},
|
|
78
|
+
"checkUnindexed": {
|
|
79
|
+
"type": "boolean",
|
|
80
|
+
"description": "WALK the project and report files on disk that the indexer would index but the index does NOT contain — the direction freshness cannot see (freshness reports files IN the index and gone from disk). Costs a stat per eligible file, i.e. the discovery phase of an index run, so it is opt-in. Uses the INDEXER'S OWN discovery rules, so gitignored files, node_modules, unsupported extensions and >5MB files are correctly NOT counted, and the output names that population. Without this option, index completeness is not asserted at all"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Returns
|
|
87
|
+
|
|
88
|
+
- Counts (files, symbols, relationships, imports, syntax-error files), schema version, runtime, embedding model/coverage and a `freshness` block that states whether it checked a SAMPLE or the whole index
|
|
89
|
+
- The freshness reason mix per file (content-changed, deleted, unreadable, unindexed) and, on verbose, the bounded stale/missing file names
|
|
90
|
+
- When `paths` is given: a separate five-state block (fresh / stale / gone / not-indexed / absent) for exactly those files, while every other number stays project-wide
|
|
91
|
+
- When `checkUnindexed` is given: files on disk the indexer would index but the index does not contain, with the population named
|
|
92
|
+
- When `integrity` is given: the integrity checks with their status and remediation, naming each non-ok check rather than only a score
|
|
93
|
+
- When `includeAnalysisRuns` is given: persisted run/finding totals as full-table counts; `history` instead answers with JSON `{ health, history, healthy }`
|
|
94
|
+
- A `healthy` boolean on the result (and inside the history JSON): false exactly when the report contains an error-severity finding
|
|
95
|
+
|
|
96
|
+
## Examples
|
|
97
|
+
|
|
98
|
+
`{"verbose":true}`
|
|
99
|
+
|
|
100
|
+
`{"history":true,"limit":5}`
|
|
101
|
+
|
|
102
|
+
`{"refresh":true,"wait":false}`
|
|
103
|
+
|
|
104
|
+
`{"force":true}`
|
|
105
|
+
|
|
106
|
+
`{"integrity":true}`
|
|
107
|
+
|
|
108
|
+
`{"freshness":"complete"}`
|
|
109
|
+
|
|
110
|
+
`{"includeAnalysisRuns":true}`
|
|
111
|
+
|
|
112
|
+
`{"paths":["src/mcp/server.ts"]}`
|
|
113
|
+
|
|
114
|
+
`{"checkUnindexed":true}`
|
|
115
|
+
|
|
116
|
+
## Errors
|
|
117
|
+
|
|
118
|
+
- An option the selected behaviour cannot honour: `limit` without `history=true`, `wait` without `refresh`/`force`, `sampleSize` with `freshness="complete"` — each refused with the accepted form named
|
|
119
|
+
- Invalid values: unknown `freshness`, `sampleSize` below 1, a non-integer `limit` (and `limit: 0` with `history=true`)
|
|
120
|
+
- `paths` problems: an empty list, more than 50 entries, duplicate entries, blank entries, or a path that escapes the project (directly or through a symlink)
|
|
121
|
+
- An index that cannot be opened read-only is reported as an EMPTY_INDEX error finding, not as a tool failure: a broken index is a successful report
|
|
122
|
+
|
|
123
|
+
## Limitations
|
|
124
|
+
|
|
125
|
+
- Sampled freshness (the default) is a deterministic sample, so `stale` is a LOWER BOUND on the project, not a total; `freshness="complete"` is the exact census
|
|
126
|
+
- A `fresh` verdict reached through the mtime+size fast path never read the file: a same-size edit that preserves the mtime reads fresh (the same trade-off as git's stat-cache)
|
|
127
|
+
- Embedding coverage reports stored vectors, not semantic quality or retrieval accuracy; verbose=true is what joins it to per-language searchability
|
|
128
|
+
- `integrity: true` with the default sampled freshness performs a COMPLETE disk pass over the indexed files, and `checkUnindexed: true` walks the project — both are opt-in precisely because a default call must not acquire them
|
|
129
|
+
- The default call does not run the per-symbol embedding aggregates (per-language symbol counts, searchable-by-language, embedded/unembedded kinds, provider chain); those run only for verbose=true, which is what keeps a default answer bounded by file count rather than symbol count
|
|
130
|
+
- No `mode` parameter exists: a call reports status, and `refresh`/`force` are the only behaviours selected by flags
|
|
131
|
+
|
|
132
|
+
## Performance
|
|
133
|
+
|
|
134
|
+
Measured warm through the MCP door on the campaign checkout: a default call answers in about 0.8 s p50 / 0.9 s p95 on the workspace index (6,452 files / 310,423 symbols / 3.6 GB), and about 2.6 s p50 / 3.3 s p95 on a 1,283,638-symbol copy of that index; the first call after a cold start measured 8.3 s and 25.3 s respectively on those two indexes. The 5-file polyglot fixture measures ~53 ms p50 and the 100-file synthetic fixture ~35 ms p50 through the same code path. `verbose=true` adds the per-symbol embedding aggregates, `integrity=true` adds a complete disk pass, `freshness="complete"` hashes/indexes every file, and `checkUnindexed=true` adds a project walk — all opt-in and declared for that reason.
|
|
135
|
+
|
|
136
|
+
## Safety
|
|
137
|
+
|
|
138
|
+
A status call is read-only: the index is opened through the driver's read-only mode, so no migrations, healers or WAL writes run. refresh=true and force=true are the only index mutations and are explicit: refresh reindexes, force WIPES the index before rebuilding and is destructive; wait=false detaches a rebuild and the next call reports its outcome once. `healthy:false` never means the tool failed — the report is the answer.
|
|
139
|
+
|
|
140
|
+
## Evidence Semantics
|
|
141
|
+
|
|
142
|
+
Counts, schema version and embedding rows are measured from the brain database; freshness compares indexed metadata with the filesystem and names the reason per file, separating content-verified fresh verdicts from mtime+size fast-path ones; integrity results are computed from stored rows and disk state; sampled answers declare that they are samples. `brain_index_status` counters are labelled when they describe the last index RUN rather than the index itself.
|
|
143
|
+
|
|
144
|
+
## Relationship to other tools
|
|
145
|
+
|
|
146
|
+
For index size/counts use `bb index status` (CLI) or the stats surface; this tool reports index health, freshness, completeness and integrity.
|
|
147
|
+
|
|
148
|
+
## Deep guides
|
|
149
|
+
|
|
150
|
+
- [Index health and freshness](../BB_HEALTH.md)
|
|
151
|
+
|
|
152
|
+
## Staleness
|
|
153
|
+
|
|
154
|
+
Freshness applies to the tool's read output (no registered per-mode split). Staleness surfaces as: a top-level `freshness` block on every report (`{ mode, requestedMode, checked, total, fresh, stale, missing, staleFiles, missingFiles, unresolved, isComplete, reasons }`) — `mode` is what was actually CHECKED, `isComplete` is the boolean to branch on before reading `stale` as a project total, `unresolved` is counted as neither fresh nor stale, and `reasons` carries the verdict mix (`{ byKind, freshVerifiedByContent, freshVerifiedByMetadata, isSample }`) so a consumer can tell a content-hash-verified file from an `mtime+size` fast-path one without reading the prose. `paths` answers per-path state for named files; `verbose` adds the stale/missing file NAMES. It does not auto-refresh on a read: the report DESCRIBES the index and a reindex happens only when asked for (`refresh: true` reindexes before reporting, `force: true` wipes and rebuilds first and is destructive, `wait: false` detaches it), so a stale report is a measurement, not a repair. When the report names stale or missing files, repair them with the manual interface: run: `bb index --changed` (or the `bb_index` tool with the project path — incremental, changed files only), or pass `paths` to check named files instead of scanning the project. Detection uses a mtime+size fast path with a content-hash fallback: an edit that leaves both size and mtime unchanged is reported fresh without hashing (same trade-off as git's index stat-cache; accepted, documented in `src/brain/freshness.ts`).
|
|
155
|
+
|
|
156
|
+
This page is generated from the executable registry and curated documentation. Run `npm run docs:generate` to update it, or `npx tsx script/verify-tool-docs.ts --only <tool> --write` for a single page.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Author: Muhammad Ishaq Khan
|
|
3
|
+
|
|
4
|
+
WHAT THIS DOCUMENT IS — the generated reference for bb_impact: contract, input schema, returns, examples, errors, limitations, performance, safety and evidence semantics.
|
|
5
|
+
WHO IT IS FOR — callers of bb_impact through any MCP host, the CLI (`bb tool bb_impact`), or a library.
|
|
6
|
+
EDIT TOGETHER WHEN THIS CHANGES — src/mcp/tools/bb_impact/descriptor.ts, src/mcp/tools/bb_impact/handler.ts, script/tool-docs/curation/bb_impact.ts; regenerate with `npx tsx script/verify-tool-docs.ts --only bb_impact --write`.
|
|
7
|
+
-->
|
|
8
|
+
# `bb_impact`
|
|
9
|
+
|
|
10
|
+
Bounded reverse-dependency impact for one symbol via the same component the editor graph panel uses: declared node budget (200) and depth (5), truncation as a first-class field with reason, and a declared total that is the size of the set the answer is a prefix of — measured, not inferred, so an answer that is short of the whole set says so even when no bound fired. Unknown symbols are loud declared errors — an empty impact set is never invented. Owner-cascade applies: impact includes dependents attributed at class level, not only exact-symbol rows. The relationship kinds that count are named in every answer's `rule.relationshipTypes` and can be overridden; a dependent carries its evidence tier, cross-language flag, bridge and position.
|
|
11
|
+
|
|
12
|
+
## Contract
|
|
13
|
+
|
|
14
|
+
- Category: `graph`
|
|
15
|
+
- Mutability: `read`
|
|
16
|
+
- Requires index: `true`
|
|
17
|
+
- Modes: `impact`
|
|
18
|
+
- Planned modes (roadmap, not executable): (none)
|
|
19
|
+
- Defaults: `{}`
|
|
20
|
+
|
|
21
|
+
## Input Schema
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"symbol": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "symbol name to compute impact for (`target`/`symbolName`/`query` are accepted as aliases)"
|
|
30
|
+
},
|
|
31
|
+
"relationshipTypes": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"description": "stored relationship kinds to count as dependencies. Default: calls, instantiates, extends, implements. A kind that is not listed is never reported, and the applied list is echoed in `rule.relationshipTypes` on every answer. This is the same control bb_graph has, so a caller who wants the type-level `uses`/`references` rows can ask for them on either door."
|
|
37
|
+
},
|
|
38
|
+
"file": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "optional defining-file hint for a symbol NAME that several stored symbols carry — the same server-resolved identity the editor's hover sends as `file`. Accept the stored project-relative path, or an absolute path ending in it. It must identify the symbol: a hint that does not is REFUSED with a named error, never silently ignored and never silently relabelled to another same-named copy. Ambiguous MEMBER names (constructors, members outside the graph's root types) resolve through their owning declaration at the hinted file; for a traversable name the walk roots where the graph engine resolves it, and a hint naming another copy is refused rather than answered. Omit it for unique names."
|
|
41
|
+
},
|
|
42
|
+
"refresh": {
|
|
43
|
+
"type": "boolean",
|
|
44
|
+
"description": "set false to skip the bounded staleness repair and answer from the existing index. When omitted, stale files inside the answer are repaired and the walk is re-run so the answer is not built from the rows the refresh replaced."
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"required": [
|
|
48
|
+
"symbol"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Returns
|
|
54
|
+
|
|
55
|
+
- The rule the answer was MEASURED under, in `rule`: which relationship kinds count as dependencies (the applied list is echoed here on every answer), the owner-cascade, the noise policy, and the depth cap. The set and the declared total are measurements of this same list
|
|
56
|
+
- The declared limits, from the component that owns them: `budget` (node budget 200, depth cap 5, the three work ceilings the declared total is computed under, and the two WALL-CLOCK deadlines — `walkTimeCeilingMs` for the engine walk and `callDeadlineMs` for the component's own work) and `traversal` (depth actually reached, the engine's own truncation state and reason, its per-query site limit, its capped-query count, its returned caller rows, and the root's uncapped caller count when computable). `maxDepth` is an EXPANSION cap: direct dependents are `depth: 0`, so the deepest dependent the engine can report is `maxDepth - 1` (4), and the depth cap is shared by the completeness measurement, so a declared total is the total UNDER that cap
|
|
57
|
+
- Whether the set is the WHOLE truth or a prefix of a larger one, and how that was established: whenever truncation was declared or the walk reached the last expandable depth, the returned set is measured against an unbounded walk of the same rule, and a prefix is declared when the two disagree. `countVerification` carries `ran`, `skipped`, `timedOut`, `boundarySuspect` and `complete` — `complete: true` means the measurement proved the returned set IS the whole truth (an ENGINE row cap may still have fired on the way; it is then published in `traversal.engineTruncated`, because a row cap that dropped only duplicate call sites of an already-counted dependent hides no dependent), `false` means a prefix or a declared unknown, and `null` means no measurement was bought because the set is complete by construction (shallow walk, no bound fired)
|
|
58
|
+
- Downstream dependents of the symbol with per-edge evidence tiers and confidence, cross-language flags, bridge mechanism, and each dependent's own position. Every one of those describes ONE stored row, and `evidenceAtDepth` says which path that row is on: `depth` is the MEASURED shortest path, while the graph engine walks depth-first and stamps the first trace, so the two can name different rows (measured across nine repositories before this was fixed: 340 of 4 258 rows, 7.98%). The evidence is re-read at the reported depth, and where no row can be attributed every evidence field is null rather than quoted from a longer path
|
|
59
|
+
- How the requested name became the root it walked: `rootMatch` carries the name asked for, whether the match was exact, an `exact-exempt-kind` hit (the name matched EXACTLY and unambiguously but the kind — an enum variant, a constant, a plain field — is outside the graph whitelist, so the walk is the one every other root gets and nothing was substituted), a containment match, or the member→owner substitution, and how many stored symbols carry that exact name. An ambiguous traversable name is ANSWERED about the copy the engine resolves, with `rootMatch.nameMatches` disclosing the ambiguity; an ambiguous member name is refused unless a `file` hint identifies its owning declaration
|
|
60
|
+
- How each dependent is a dependent, per row, in `via`: `exact` (the stored row names the symbol asked about), `member` (it names one of its members — the owner cascade working as declared, with the member named in `viaMember`), or `range-folded` (it names neither, and the row is in the answer only because the cascade RANGE widened). `cascade` is the composition of the returned set by those three, or `null` when the index refused the member lookups it needs to establish it
|
|
61
|
+
- `directCount` — the number of DIRECT dependents (depth 0), or `null` when the completeness measurement hit a declared ceiling, was refused, stopped on its clock, or was skipped because the walk had already spent the call's wall-clock deadline. `totalCountIfKnown` is the transitive total under the same rule, or `null` for the same declared unknowns. Neither is ever smaller than `shownCount`; when the measurement proves the set complete they equal it
|
|
62
|
+
- `file` — an optional defining-file hint for a name several stored symbols carry. For a member name (a constructor, or a member the graph cannot root) it resolves the walk through the MEMBER'S OWNING DECLARATION at that file and the result says so in `resolution`. For a traversable name the walk roots where the graph engine resolves the name, and the hint is a REFUSAL input: it either identifies that copy or the answer is a named error, never a silent relabel to another copy
|
|
63
|
+
- Freshness: a per-dependent `stale` flag (`true`/`false`, or `null` when the file is not in the index at all) and a summary `freshness` envelope; `rootStale` declares the root's own file separately, since a stale root with fresh dependents is still a stale answer. Stale files inside the answer are repaired within budget and the walk is re-run, declared in `autoRefresh`; `refresh=false` opts out
|
|
64
|
+
- Loud declared errors instead of fabricated empty sets: an unknown symbol, an ambiguous member name with no usable hint, a hint that does not identify the symbol, an empty `relationshipTypes` list, and the option refusals the shared validator raises are all named errors with `isError` set
|
|
65
|
+
|
|
66
|
+
## Examples
|
|
67
|
+
|
|
68
|
+
`{"symbol":"handleRequest"}`
|
|
69
|
+
|
|
70
|
+
## Errors
|
|
71
|
+
|
|
72
|
+
- Missing symbol
|
|
73
|
+
- Symbol not found in the index — a declared error, never an empty impact set that would read as "nothing depends on this"
|
|
74
|
+
- The requested NAME is an ambiguous MEMBER name (a constructor or a kind outside the graph's root types) and no usable `file` hint was given. The error lists the candidate copies with file and line (bounded to 8, plus a count of the rest) and names the `file` option as the remediation
|
|
75
|
+
- A `file` hint that does not identify the symbol — an unknown path, or a path naming a different copy than the symbol the walk would root at — is refused with a named error instead of being ignored or answered about another copy
|
|
76
|
+
- `relationshipTypes` given as an empty list: refused rather than silently re-read as the engine's default kind set (an empty rule matches nothing, and the engine would substitute its default)
|
|
77
|
+
- The root resolves to a non-traversable kind AND is not the symbol that was asked for — a gravity pick, a containment match, or a re-root through an owner. The graph whitelist exists so a request is never answered about a DIFFERENT symbol, and that is the only case left where it applies
|
|
78
|
+
- An option this tool does not accept, or a value of the wrong type, is rejected by the shared tool validator with the accepted options named
|
|
79
|
+
|
|
80
|
+
## Limitations
|
|
81
|
+
|
|
82
|
+
- Static impact analysis cannot establish runtime behavior: it reads stored relationship rows, not executed calls
|
|
83
|
+
- The depth cap is an EXPANSION cap. Direct dependents are `depth: 0`, the deepest reported dependent is `maxDepth - 1` (4), and the completeness measurement shares that cap — so a declared total is the total under the declared depth, and a chain deeper than the cap keeps a declared `caller-depth-cap-reached` truncation rather than claiming a bounded set is the whole truth
|
|
84
|
+
- The engine's row bounds are not truncations of the DEPENDENT SET: a per-query call-site limit, a per-traversal caller budget and a total-edge cap drop ROWS. When the measurement proves the returned set complete, those bounds stay visible in `traversal.engineTruncated` / `engineTruncationReason` and `truncated` stays false — the set is whole even though the engine stopped emitting rows
|
|
85
|
+
- When the completeness measurement cannot finish — 50 000 scanned rows, 2 000 expansions, its own circuit breaker, or the call deadline — `totalCountIfKnown` and `directCount` are BOTH `null` (a declared unknown), `countVerification` says whether it timed out or was skipped for the deadline, `reproducible: false` is published, and the truncation reason names it. The clock is the one bound that is a property of the machine rather than the index, so it is always declared rather than inferred
|
|
86
|
+
- The walk is bounded in WALL TIME by a declared deadline (`budget.walkTimeCeilingMs`): the graph engine applies no clock of its own, so this tool asks for one, and a walk that reaches it is a SAMPLE — declared with `truncated`, a truncation reason naming `walk-time-budget-exhausted`, the engine's returned/uncapped counts in `traversal`, and `reproducible: false`. It is the honest response to a hub whose answer would otherwise run past the tool's 5 s budget, not a hidden cut
|
|
87
|
+
- Latency depends on the index's planner state as well as on its size. Two index shapes were measured and fixed: the owner-range index made the walk's owner-cascade lookup cheap, and the counting walk's level query is now a FLAT target-id list rather than `IN(subquery over ids OR owner ranges)` — the old form could not use the target index and took 4 349 ms for ONE level-1 batch where the flat form returns the same rows in 4.1 ms. With both fixes plus the declared deadlines, a real hub (`getRawInstance`, the case that breached 5 s) answers in p50 2 424–2 805 ms / p95 2 450–3 148 ms across two baseline-protocol series (3 measured runs after one warm-up) and p95 3 029 ms over eight warm runs — measured byte-read-only, index files byte-identical after. The fixture tiers are the regression baselines (see Performance)
|
|
88
|
+
- Owner-cascade attribution applies: dependents through class-member relationships are attributed to the owner class. The cascade RANGE is a strict SUPERSET of the owner relation — it never loses a dependent the owner relation has, but it folds in siblings of a member: ripgrep `RegexMatcher` answered 21 dependents of which 7 were `range-folded` and 0 were real members. `cascade.rangeFolded` counts those rows, so the over-count is visible instead of silent
|
|
89
|
+
- A `file` hint cannot select a DIFFERENT copy of a traversable name: the graph engine roots by name (gravity-ordered), and the hint can only confirm that copy or refuse. Member names are the case the hint resolves, through their owning declaration
|
|
90
|
+
- `relationshipTypes` is not validated against the index's stored-kind vocabulary: a misspelled kind is measured as an empty set with `truncated: false`, and `rule.relationshipTypes` echoes the misspelling so the mistake is auditable rather than disguised as "no dependents"
|
|
91
|
+
- Reflects the index as of the last index run; the freshness envelope and the per-dependent `stale` flags state how far that is from the files on disk
|
|
92
|
+
|
|
93
|
+
## Performance
|
|
94
|
+
|
|
95
|
+
Warm, five-run measurements on the three declared tiers, with the exact commands and raw runs in validation/tools/bb_impact/LATENCY.json. All three tiers are inside budget on the current index. Fixture tiers: p50 83.8 ms / p95 100.8 ms on test/fixtures/polyglot/ts-js and p50 176.5 ms / p95 243.5 ms on the 100-file synthetic scale fixture, both default-argument calls. Reference large index (.bb-data, 11,440 files, ~3.4 GB, measured through the tool's byte-read-only open with the index's own files hashed before and after, `dbUnchanged: true`): per-symbol p95 was 327.7 ms for the widest studied hub (`join`), 321.2 ms for `named`, 236.0 ms for `refReachable` and 153.6 ms for `computeImpact` — every measured call stayed inside the 5 s budget, and p50s were 42.9–284.2 ms. The walk's per-symbol caller query is planned through `brain_symbol_project_owner_idx` for the owner range and `brain_rel_proj_type_target_idx` for the relationship filter, so the cost is index-bounded. The HUB case is measured too, because it is the one that breached the budget: default `{symbol:"getRawInstance"}` on the reference index answered p50 2 424–2 805 ms / p95 2 450–3 148 ms across two baseline-protocol series (one warm-up, three measured runs each) and p95 3 029 ms over eight warm runs — all inside the 5 000 ms budget, with the answer declaring its walk clock (`traversal.walkTimeExhausted`), its measured total (`totalCountIfKnown`) and its completeness state. Before the fix the same call measured p50 6 337 / p95 6 539 ms; the cause was ONE counting statement that could not use the target index (4 349 ms), not the walk. One correction belongs on the record: an earlier campaign measurement on THIS index returned 13.7–359.5 s for default calls, and a hand-built comparison attributed it to the engine's owner-cascade JOIN form (10,351 ms against 12.5 ms for a flat target-indexed form). That measurement predates the owner-range index and the planner state now on disk; re-measured byte-read-only on the current index, the same JOIN form answers in 1.1 ms and the walk in 40–63 ms. The absolute millisecond figures belong to the machine, so the fixture-tier numbers are the regression baselines this tool holds.
|
|
96
|
+
|
|
97
|
+
## Safety
|
|
98
|
+
|
|
99
|
+
Read-only. It does not modify source files or index data. Staleness repair, when it runs, reindexes changed files through the shared bounded auto-refresh budget and never rewrites source.
|
|
100
|
+
|
|
101
|
+
## Evidence Semantics
|
|
102
|
+
|
|
103
|
+
Impact derives from brain_relationship rows through the same graph engine the editor impact panel uses. The returned set is the engine's caller traversal under the declared dependency kinds, owner cascade, noise policy and depth; the declared total is an INDEPENDENT bounded walk under exactly that rule, so it is the size of the set the answer is a prefix of. Completeness is PROVED rather than inferred: whenever truncation was declared or the walk reached the last expandable depth, the set is measured against an unbounded walk of the same rule, so an answer that is short of the whole truth says so even when no bound fired (measured: cobra `HasAvailableFlags` answers 28 with `truncated: true` instead of 27 with `truncated: false`), and an engine row cap that hides no dependent no longer masquerades as a truncation. Evidence lives in validation/tools/bb_impact/ (AUDIT.md, LATENCY.json, probes, latency-t2-query-cost.json) and in the gate evidence of the three verifiers named below.
|
|
104
|
+
|
|
105
|
+
## Relationship to other tools
|
|
106
|
+
|
|
107
|
+
This is the bounded-impact specialist; `bb_analyze` mode `impact` aggregates the same canonical walk with file-level risk — the numbers are identical by gate.
|
|
108
|
+
|
|
109
|
+
## Deep guides
|
|
110
|
+
|
|
111
|
+
- [Impact: budgets, completeness and the wall clock](../BB_IMPACT.md)
|
|
112
|
+
|
|
113
|
+
## Staleness
|
|
114
|
+
|
|
115
|
+
Freshness modes (registered as `freshnessModes`): `impact`. Staleness surfaces as: per-dependent `stale` flag (three states: `true`/`false`, or `null` when the file is not in the index at all), the root's own `rootStale`, and a `freshness` envelope (`{ fresh, stale, missing, staleRatio, mode, remediation }`). Stale files inside the answer are repaired within budget and the walk is re-run, declared in `autoRefresh`; `refresh=false` opts out. When something is stale/missing, the remediation names the registered reindex interfaces: project scope → `reads auto-refresh stale files within budget when enabled — disable with BB_NO_AUTO_REFRESH=1 or refresh=false; manual repair: run: bb index --changed (or the bb_index tool with the project path — incremental, changed files only)`; file scope → `reads auto-refresh this file within budget when enabled — disable with BB_NO_AUTO_REFRESH=1 or refresh=false; manual repair: run: bb index "<file>" (or the bb_index tool with that file path)`. Nothing is stale → silence (no remediation text). Detection uses a mtime+size fast path with a content-hash fallback: an edit that leaves both size and mtime unchanged is reported fresh without hashing (same trade-off as git's index stat-cache; accepted, documented in `src/brain/freshness.ts`).
|
|
116
|
+
|
|
117
|
+
This page is generated from the executable registry and curated documentation. Run `npm run docs:generate` to update it, or `npx tsx script/verify-tool-docs.ts --only <tool> --write` for a single page.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Author: Muhammad Ishaq Khan
|
|
3
|
+
|
|
4
|
+
WHAT THIS DOCUMENT IS — the generated reference for bb_index: contract, input schema, returns, examples, errors, limitations, performance, safety and evidence semantics.
|
|
5
|
+
WHO IT IS FOR — callers of bb_index through any MCP host, the CLI (`bb tool bb_index`), or a library.
|
|
6
|
+
EDIT TOGETHER WHEN THIS CHANGES — src/mcp/tools/bb_index/descriptor.ts, src/mcp/tools/bb_index/handler.ts, script/tool-docs/curation/bb_index.ts; regenerate with `npx tsx script/verify-tool-docs.ts --only bb_index --write`.
|
|
7
|
+
-->
|
|
8
|
+
# `bb_index`
|
|
9
|
+
|
|
10
|
+
Reindex a file or directory so the index reflects edits immediately (agent-fresh). Accepts a path (file or dir); a file reindexes only that file, a dir runs an incremental index of that dir (changed files only). mode=post re-runs the heavy derived-data phases (relationships/enrichment/gravity/taints/health) WITHOUT re-parsing — the remediation after edits on incremental paths. Every mode requires `path`, and it MUST resolve inside this project: an absolute path elsewhere, a `../` traversal, a foreign directory and a symlink inside the project pointing out of it are all REFUSED, because an out-of-tree file would be stored with a `relative_path` that is not relative to anything and every scoped query, file name and freshness check for it would then be wrong. For mode=post the path must additionally NOT be a file: the phases are project-wide, so pass the project root (or a directory inside it). The report says what happened rather than only how much: `outcome` is `indexed`, `partial` or `no-op`; a no-op carries a `reason` that distinguishes "nothing changed: the file already matches the index (mtime, size and sha256 agree)" from "this file holds nothing the indexer extracts", and `unchanged`/`declined`/`skipped` say how many files fell into each case. When errors occurred, `errorDetail` names the file and the message beside the `errors` count, and `walCheckpointed` says whether the write WAL was reclaimed after the run. Paths in the report are PROJECT-RELATIVE, so the same request returns the same bytes on any machine. The counts are stable between identical calls; the `ms` fields are measured wall-clock and are expected to vary.
|
|
11
|
+
|
|
12
|
+
## Contract
|
|
13
|
+
|
|
14
|
+
- Category: `operations`
|
|
15
|
+
- Mutability: `write`
|
|
16
|
+
- Requires index: `false`
|
|
17
|
+
- Modes: `auto`, `file`, `dir`, `post`
|
|
18
|
+
- Planned modes (roadmap, not executable): (none)
|
|
19
|
+
- Defaults: `{"mode":"auto"}`
|
|
20
|
+
|
|
21
|
+
## Input Schema
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"path": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Project-relative file (reindex only that file) or directory (incremental index of changed files); for mode=post, the project root or a directory inside it whose derived phases should be re-run (a file path is refused). REQUIRED in every mode and checked rather than ignored. Must resolve INSIDE the project: both sides are resolved through realpath, so a symlink inside the project pointing out of it is refused too."
|
|
30
|
+
},
|
|
31
|
+
"mode": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"enum": [
|
|
34
|
+
"auto",
|
|
35
|
+
"file",
|
|
36
|
+
"dir",
|
|
37
|
+
"post"
|
|
38
|
+
],
|
|
39
|
+
"description": "auto (default) infers file vs dir from path; file reindexes one file (unchanged files answer no-op instead of being re-parsed); dir runs an incremental directory index; post re-runs derived phases (relationships/taints/health) without re-parsing"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"required": [
|
|
43
|
+
"path"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Returns
|
|
49
|
+
|
|
50
|
+
- `indexed`, `deleted`, `errors`, `unchanged`, `declined` and `skipped` counts for the refreshed path
|
|
51
|
+
- The mode actually applied (`auto` resolves to `file` or `dir`; `file`/`dir`/`post` are reported as named)
|
|
52
|
+
- `outcome` — `indexed`, `partial`, or `no-op`. A no-op also carries `reason`, and the two reasons are different facts: "nothing changed" (mtime, size and sha256 all still match the stored row) versus "this file holds nothing the indexer extracts" (an extension the indexer does not parse)
|
|
53
|
+
- `errorDetail`: the file and the message for each failure, beside the `errors` count
|
|
54
|
+
- `walCheckpointed`: whether the write-ahead log was reclaimed after the run (a refused checkpoint — another reader holding a snapshot — reports false, never success)
|
|
55
|
+
- For mode=dir, `candidates` (files the walk found changed) beside `processed`, so a partial dir index is visible as a count, and `unchanged: true` when the tree is settled
|
|
56
|
+
- For mode=post, the per-phase report (relationships, enrichment, gravity, taint, health, integrity, planner stats, vector blobs, analysis) with each phase's timing and outcome, `totalMs`, and the post-run `integrityHealth` score
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
`{"path":"src/new-file.ts"}`
|
|
61
|
+
|
|
62
|
+
`{"path":"src","mode":"dir"}`
|
|
63
|
+
|
|
64
|
+
`{"path":".","mode":"post"}`
|
|
65
|
+
|
|
66
|
+
## Errors
|
|
67
|
+
|
|
68
|
+
- Missing or blank path
|
|
69
|
+
- A path that resolves OUTSIDE the project — an absolute path elsewhere, a `../` traversal, a foreign directory, or a symlink inside the project pointing out of it — for file, dir, auto AND post mode
|
|
70
|
+
- mode=post with a path that does not exist, or with a FILE path: the post pass re-derives project-wide phases, so it takes the project root (or a directory inside it)
|
|
71
|
+
- mode=file on a directory, or mode=dir on a file
|
|
72
|
+
- Unknown mode, or an option this tool does not accept (the refusal names the accepted set)
|
|
73
|
+
- Another LIVE indexer holding the project lock; the refusal names the holder's pid, host and start time, and the remedy. A lock whose holder is dead, a lock naming no process once it is older than the grace window, and a foreign-host lock past its 24h expiry are reclaimed automatically
|
|
74
|
+
|
|
75
|
+
## Limitations
|
|
76
|
+
|
|
77
|
+
- A file reindex updates only that file's evidence; cross-file relationships are repaired within the bounded post-pass for the touched files (see `derived.pass`), while callers in unrelated files can lag until the next dir or full index
|
|
78
|
+
- Dir mode reuses the incremental indexer: unchanged files are skipped by design, a settled tree answers `unchanged: true`, and a file the walk's skip rules exclude is left untouched in the index rather than being treated as deleted — an index row is deleted only when the file is genuinely gone from disk
|
|
79
|
+
- File mode's `no-op` is a real no-op: an unchanged file is detected by mtime+size and confirmed by comparing the stored sha256 with the bytes on disk, so a repeated call does not re-parse (and does not pay a parse's latency)
|
|
80
|
+
- The COUNTS in a report are stable between identical calls; the `ms` fields are measured wall-clock and DO vary, so a diff of two reports will show timing drift
|
|
81
|
+
- Dir mode walks with the indexer's own skip rules; a directory that the indexer excludes from DISCOVERY (build output, dependency trees) is not revisited by an incremental dir walk. The walk's skip list matches discovery's for the names that matter here — `vendor` is indexed, because it is first-party source in Go and in repositories that curate code under src/vendor
|
|
82
|
+
- A reindex does not run the full derived pipeline: `derived.pass` is `bounded` for incremental runs, and mode=post is the explicit remedy when derived data looks stale
|
|
83
|
+
|
|
84
|
+
## Performance
|
|
85
|
+
|
|
86
|
+
A single-file reindex is bounded by that file's parse cost plus the incremental post-pass; dir mode is bounded by the changed-file set and reports how many candidates it found against how many it processed. A no-op refresh (unchanged file or settled directory) performs no parse at all. Measured on an isolated tiny fixture, a warm file-mode call was 11.8 s when it always re-parsed and 0.0 s–0.1 s as a no-op; the parse path is dominated by worker-pool startup, not the file.
|
|
87
|
+
|
|
88
|
+
## Safety
|
|
89
|
+
|
|
90
|
+
Write-capable against INDEX data only — it never modifies source files, and it never deletes an index row for a file that still exists on disk. It will only index paths inside this project: both sides are resolved through realpath, so a symlink inside the project pointing out of it is refused and a symlink to a file inside it is allowed. Concurrent index runs are refused by the project index lock rather than interleaved.
|
|
91
|
+
|
|
92
|
+
## Evidence Semantics
|
|
93
|
+
|
|
94
|
+
Counts come from the real parse/store pipeline. The report's own assertions are checked by the m40 A1/A3 gates (post entry, write-path parity including the delete guard and the unchanged-file no-op), m43 P1 (lock), m22 E1/D3 (agent-fresh), and by real MCP stdio door probes under validation/tools/bb_index/.
|
|
95
|
+
|
|
96
|
+
## Relationship to other tools
|
|
97
|
+
|
|
98
|
+
The CLI twin is `bb index`. The MCP path is incremental only: `auto`/`file`/`dir` refresh changed files, `post` re-derives the heavy phases; a full rebuild is the CLI's `bb index --force`. Refresh changed files after agent edits with mode `dir`/`file` or the CLI `--changed`.
|
|
99
|
+
|
|
100
|
+
## Deep guides
|
|
101
|
+
|
|
102
|
+
- [Indexing guide: flags, resume, performance, troubleshooting](../indexing/README.md)
|
|
103
|
+
|
|
104
|
+
## Staleness
|
|
105
|
+
|
|
106
|
+
This tool does not report per-file index staleness and does not auto-refresh. Output reflects the index as of the last index run; when files changed after indexing, refresh first: run: bb index --changed (or the bb_index tool with the project path — incremental, changed files only).
|
|
107
|
+
|
|
108
|
+
This page is generated from the executable registry and curated documentation. Run `npm run docs:generate` to update it, or `npx tsx script/verify-tool-docs.ts --only <tool> --write` for a single page.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Author: Muhammad Ishaq Khan
|
|
3
|
+
|
|
4
|
+
WHAT THIS DOCUMENT IS — the generated reference for bb_migrate: contract, input schema, returns, examples, errors, limitations, performance, safety and evidence semantics.
|
|
5
|
+
WHO IT IS FOR — callers of bb_migrate through any MCP host, the CLI (`bb tool bb_migrate`), or a library.
|
|
6
|
+
EDIT TOGETHER WHEN THIS CHANGES — src/mcp/tools/bb_migrate/descriptor.ts, src/mcp/tools/bb_migrate/handler.ts, script/tool-docs/curation/bb_migrate.ts; regenerate with `npx tsx script/verify-tool-docs.ts --only bb_migrate --write`.
|
|
7
|
+
-->
|
|
8
|
+
# `bb_migrate`
|
|
9
|
+
|
|
10
|
+
Read-only single or batch migration planning with dependency order, explicit effort methodology, library mappings, risks, truncation, and unsupported cases. A request is a list of entries (symbol names, indexed symbol ids, project-relative paths) unioned and capped at 100; every entry resolves to at most one component before any relationship is read, and a component named through more than one entry is planned once. Plans whose source file changed since the last index are flagged stale up front — a plan is a claim about current code; JSON output carries the freshness block.
|
|
11
|
+
|
|
12
|
+
## Contract
|
|
13
|
+
|
|
14
|
+
- Category: `analysis`
|
|
15
|
+
- Mutability: `read`
|
|
16
|
+
- Requires index: `true`
|
|
17
|
+
- Modes: `plan`
|
|
18
|
+
- Planned modes (roadmap, not executable): (none)
|
|
19
|
+
- Defaults: `{"format":"text"}`
|
|
20
|
+
|
|
21
|
+
## Input Schema
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"symbolName": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "legacy single-symbol alias for symbolNames; when both are supplied the entries are UNIONED, never silently dropped"
|
|
30
|
+
},
|
|
31
|
+
"symbolNames": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"description": "one or more component names; a name that matches several symbols in different files is refused with candidate ids to re-run against symbolIds. Blank entries are refused by name"
|
|
37
|
+
},
|
|
38
|
+
"paths": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
},
|
|
43
|
+
"description": "project-relative file or DIRECTORY paths (absolute paths inside the project are accepted); every indexed symbol in them joins the request, so a whole module can be planned in one call. UNION with symbolNames, not a replacement: naming a symbol AND a path that contains it plans it once. A path that matches no indexed file is refused by name"
|
|
44
|
+
},
|
|
45
|
+
"symbolIds": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"items": {
|
|
48
|
+
"type": "string"
|
|
49
|
+
},
|
|
50
|
+
"description": "indexed symbol ids (shape `<projectId>:<relative file>:<name>:<line>`), the ONLY unambiguous way to name a component. Use this when a refusal reported that a name matches several symbols; a name is not an identity, and ids come from an earlier result's plans or an ambiguity refusal's candidates. An id no symbol carries is refused by name"
|
|
51
|
+
},
|
|
52
|
+
"targetLanguage": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"description": "e.g. rust, go, python. An unknown target is refused; a known target with no dictionary rows for the source pair is planned with the missing-data gap declared and no mapping invented. Blank is refused"
|
|
55
|
+
},
|
|
56
|
+
"format": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"enum": [
|
|
59
|
+
"text",
|
|
60
|
+
"json"
|
|
61
|
+
],
|
|
62
|
+
"description": "output format (default text)"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"required": [
|
|
66
|
+
"targetLanguage"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Returns
|
|
72
|
+
|
|
73
|
+
- Dependency-ordered migration plans, grouped into parallel-workable waves, one plan per component named by the request
|
|
74
|
+
- Scope completeness: how much of the cited integration surface the request actually covers
|
|
75
|
+
- Cohort rollup by source file and by wave, plus the zero-indexed `cohort.wavePlan` keyed by symbol id
|
|
76
|
+
- Effort methodology with its rates published as data, library mappings by provenance, and measured risks
|
|
77
|
+
- Explicit unsupported entries with typed reasons (missing-symbol, ambiguous-symbol with candidate ids, same-language, unsupported-source, unsupported-target)
|
|
78
|
+
- Truncation split into `deduplicated` (entries that resolved to an already-planned component) and `capped` (entries the 100-entry cap dropped, named in `cappedNames`)
|
|
79
|
+
- Freshness of every plan's source file: per-plan `stale` flags, an up-front stale-plan notice in text, and the `freshness` envelope in JSON
|
|
80
|
+
|
|
81
|
+
## Examples
|
|
82
|
+
|
|
83
|
+
`{"symbolName":"handleRequest","targetLanguage":"go"}`
|
|
84
|
+
|
|
85
|
+
`{"symbolNames":["parse","handle"],"targetLanguage":"rust","format":"json"}`
|
|
86
|
+
|
|
87
|
+
`{"paths":["src/api"],"targetLanguage":"go"}`
|
|
88
|
+
|
|
89
|
+
`{"symbolIds":["<projectId>:src/api/handler.ts:handleRequest:12"],"targetLanguage":"go"}`
|
|
90
|
+
|
|
91
|
+
## Errors
|
|
92
|
+
|
|
93
|
+
- Missing targetLanguage
|
|
94
|
+
- A blank targetLanguage (refused: the tool will not resolve an empty language name)
|
|
95
|
+
- No symbolName, symbolNames, symbolIds or paths
|
|
96
|
+
- A blank entry in symbolNames, symbolIds or paths (refused by name: a blank entry would silently narrow the request)
|
|
97
|
+
- A path that matches no indexed file (the tool says so rather than returning an empty plan set)
|
|
98
|
+
- A symbol id that no indexed symbol carries (the tool names the id, because an id is the only unambiguous selector)
|
|
99
|
+
- No index for the project (the tool is read-only and refuses with the `bb index` remediation rather than creating one)
|
|
100
|
+
- Unknown option (the door names the accepted options)
|
|
101
|
+
|
|
102
|
+
## Limitations
|
|
103
|
+
|
|
104
|
+
- Plans are estimates, not translated source; the tool does not generate, replace or compile target-language code
|
|
105
|
+
- Library mappings are advisory and unsupported routes remain explicit; an unmapped third-party library is named at confidence 0 and charged 6h of research, never claimed as supported
|
|
106
|
+
- A library with an observed import but no registered target is reported with `target: null` and `confidence: 0` — declared absence, never an invented equivalence
|
|
107
|
+
- Dependency ordering and mapping depend on the analyzer-extracted symbol and relationship graph; reflection, dynamic dispatch, or relations the grammar does not model limit the completeness of the resulting plan
|
|
108
|
+
- A request names a bounded set of components, and the cited integration surface is usually much larger: measured 98.6-99.8% out of scope on the cobra corpus for requests of 1-16 symbols. The `scope` block reports this on every result
|
|
109
|
+
- The dictionary carries 486 rows across 30 source languages and 21 target languages, covering 126 of the 630 possible source-to-target pairs (20%). Two keys (`flutter/material`, `shadcn/ui` — 4 of 486 rows, 0.8%) cannot be produced by import canonicalization at all; the audit enforces that class in both directions. A further 31 rows carry knowledge an import lookup can only reach through a specifier real source code does not write (API idioms such as `pool.query`, a framework name, 16 Flutter widget or type names, and display names with spaces) — they are kept, and this is their stated limit. Audited by script/m20/verify-migration-dictionary.ts
|
|
110
|
+
|
|
111
|
+
## Performance
|
|
112
|
+
|
|
113
|
+
Work is bounded by the request, not by repository size. A request is capped at 100 entries, and each entry resolves to at most one component before any relationship is read, so a common name cannot expand the load: on the 6,452-file / 310,423-symbol reference index a 12-name batch loaded 844 symbols and 46,753 relationships before this rule and stays inside the 5 s read-tool budget after it. `cohort.work` reports what a call actually read, and `truncation.cappedNames` names every dropped entry.
|
|
114
|
+
|
|
115
|
+
## Safety
|
|
116
|
+
|
|
117
|
+
Read-only, including the index open: plans are computed from a byte-read-only connection, no migrations run on a read, and the tool never creates an index. It does not generate, replace, or compile target-language source.
|
|
118
|
+
|
|
119
|
+
## Evidence Semantics
|
|
120
|
+
|
|
121
|
+
Dependency ordering comes from indexed relationships; effort and library mappings are labelled methodology-driven estimates, with the rates published as data. Relationship line, confidence, cross-language flag, bridge mechanism and both external endpoint names are read from the index; none is synthesized.
|
|
122
|
+
|
|
123
|
+
## Relationship to other tools
|
|
124
|
+
|
|
125
|
+
For dependency structure use `bb_graph`; this tool produces migration plans with declared limitations.
|
|
126
|
+
|
|
127
|
+
## Deep guides
|
|
128
|
+
|
|
129
|
+
- [Migration plans, ordering and honesty](../BB_MIGRATE.md)
|
|
130
|
+
|
|
131
|
+
## Staleness
|
|
132
|
+
|
|
133
|
+
Freshness modes (registered as `freshnessModes`): `plan`. Staleness surfaces as: per-plan `sourceFile` + `stale` flags with an up-front stale-plan notice + `freshness` envelope (`{ fresh, stale, missing, staleRatio, mode, remediation }`) on JSON. This tool does NOT auto-refresh and has no `refresh` option: the flags and the envelope DESCRIBE the index as it stands, and the repair is manual — project scope → run: `bb index --changed` (or the `bb_index` tool with the project path — incremental, changed files only); file scope → run: `bb index "<file>"` for the file the plan belongs to. Nothing is stale → silence (no remediation text). Detection uses a mtime+size fast path with a content-hash fallback: an edit that leaves both size and mtime unchanged is reported fresh without hashing (same trade-off as git's index stat-cache; accepted, documented in `src/brain/freshness.ts`).
|
|
134
|
+
|
|
135
|
+
This page is generated from the executable registry and curated documentation. Run `npm run docs:generate` to update it, or `npx tsx script/verify-tool-docs.ts --only <tool> --write` for a single page.
|