seer-mcp 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.
Files changed (371) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/LICENSE +176 -0
  3. package/README.md +272 -0
  4. package/README_dev.md +199 -0
  5. package/dist/bundle/ci.d.ts +47 -0
  6. package/dist/bundle/ci.d.ts.map +1 -0
  7. package/dist/bundle/ci.js +113 -0
  8. package/dist/bundle/ci.js.map +1 -0
  9. package/dist/bundle/contract.d.ts +111 -0
  10. package/dist/bundle/contract.d.ts.map +1 -0
  11. package/dist/bundle/contract.js +352 -0
  12. package/dist/bundle/contract.js.map +1 -0
  13. package/dist/bundle/export.d.ts +36 -0
  14. package/dist/bundle/export.d.ts.map +1 -0
  15. package/dist/bundle/export.js +152 -0
  16. package/dist/bundle/export.js.map +1 -0
  17. package/dist/bundle/external.d.ts +66 -0
  18. package/dist/bundle/external.d.ts.map +1 -0
  19. package/dist/bundle/external.js +238 -0
  20. package/dist/bundle/external.js.map +1 -0
  21. package/dist/bundle/format.d.ts +94 -0
  22. package/dist/bundle/format.d.ts.map +1 -0
  23. package/dist/bundle/format.js +42 -0
  24. package/dist/bundle/format.js.map +1 -0
  25. package/dist/bundle/import.d.ts +49 -0
  26. package/dist/bundle/import.d.ts.map +1 -0
  27. package/dist/bundle/import.js +116 -0
  28. package/dist/bundle/import.js.map +1 -0
  29. package/dist/cli/index.d.ts +3 -0
  30. package/dist/cli/index.d.ts.map +1 -0
  31. package/dist/cli/index.js +1402 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/cli/init.d.ts +48 -0
  34. package/dist/cli/init.d.ts.map +1 -0
  35. package/dist/cli/init.js +284 -0
  36. package/dist/cli/init.js.map +1 -0
  37. package/dist/db/schema.d.ts +3 -0
  38. package/dist/db/schema.d.ts.map +1 -0
  39. package/dist/db/schema.js +616 -0
  40. package/dist/db/schema.js.map +1 -0
  41. package/dist/db/store.d.ts +1011 -0
  42. package/dist/db/store.d.ts.map +1 -0
  43. package/dist/db/store.js +3888 -0
  44. package/dist/db/store.js.map +1 -0
  45. package/dist/graph/pagerank.d.ts +9 -0
  46. package/dist/graph/pagerank.d.ts.map +1 -0
  47. package/dist/graph/pagerank.js +47 -0
  48. package/dist/graph/pagerank.js.map +1 -0
  49. package/dist/indexer/architecture.d.ts +72 -0
  50. package/dist/indexer/architecture.d.ts.map +1 -0
  51. package/dist/indexer/architecture.js +112 -0
  52. package/dist/indexer/architecture.js.map +1 -0
  53. package/dist/indexer/behavior.d.ts +75 -0
  54. package/dist/indexer/behavior.d.ts.map +1 -0
  55. package/dist/indexer/behavior.js +395 -0
  56. package/dist/indexer/behavior.js.map +1 -0
  57. package/dist/indexer/boundaries.d.ts +60 -0
  58. package/dist/indexer/boundaries.d.ts.map +1 -0
  59. package/dist/indexer/boundaries.js +366 -0
  60. package/dist/indexer/boundaries.js.map +1 -0
  61. package/dist/indexer/churn.d.ts +15 -0
  62. package/dist/indexer/churn.d.ts.map +1 -0
  63. package/dist/indexer/churn.js +49 -0
  64. package/dist/indexer/churn.js.map +1 -0
  65. package/dist/indexer/classify.d.ts +9 -0
  66. package/dist/indexer/classify.d.ts.map +1 -0
  67. package/dist/indexer/classify.js +90 -0
  68. package/dist/indexer/classify.js.map +1 -0
  69. package/dist/indexer/context.d.ts +176 -0
  70. package/dist/indexer/context.d.ts.map +1 -0
  71. package/dist/indexer/context.js +193 -0
  72. package/dist/indexer/context.js.map +1 -0
  73. package/dist/indexer/continuity.d.ts +67 -0
  74. package/dist/indexer/continuity.d.ts.map +1 -0
  75. package/dist/indexer/continuity.js +288 -0
  76. package/dist/indexer/continuity.js.map +1 -0
  77. package/dist/indexer/detectchanges.d.ts +32 -0
  78. package/dist/indexer/detectchanges.d.ts.map +1 -0
  79. package/dist/indexer/detectchanges.js +74 -0
  80. package/dist/indexer/detectchanges.js.map +1 -0
  81. package/dist/indexer/discovery.d.ts +37 -0
  82. package/dist/indexer/discovery.d.ts.map +1 -0
  83. package/dist/indexer/discovery.js +136 -0
  84. package/dist/indexer/discovery.js.map +1 -0
  85. package/dist/indexer/externaldeps.d.ts +18 -0
  86. package/dist/indexer/externaldeps.d.ts.map +1 -0
  87. package/dist/indexer/externaldeps.js +288 -0
  88. package/dist/indexer/externaldeps.js.map +1 -0
  89. package/dist/indexer/freshness.d.ts +48 -0
  90. package/dist/indexer/freshness.d.ts.map +1 -0
  91. package/dist/indexer/freshness.js +128 -0
  92. package/dist/indexer/freshness.js.map +1 -0
  93. package/dist/indexer/git.d.ts +144 -0
  94. package/dist/indexer/git.d.ts.map +1 -0
  95. package/dist/indexer/git.js +444 -0
  96. package/dist/indexer/git.js.map +1 -0
  97. package/dist/indexer/index.d.ts +145 -0
  98. package/dist/indexer/index.d.ts.map +1 -0
  99. package/dist/indexer/index.js +930 -0
  100. package/dist/indexer/index.js.map +1 -0
  101. package/dist/indexer/modules.d.ts +62 -0
  102. package/dist/indexer/modules.d.ts.map +1 -0
  103. package/dist/indexer/modules.js +293 -0
  104. package/dist/indexer/modules.js.map +1 -0
  105. package/dist/indexer/preflight.d.ts +154 -0
  106. package/dist/indexer/preflight.d.ts.map +1 -0
  107. package/dist/indexer/preflight.js +399 -0
  108. package/dist/indexer/preflight.js.map +1 -0
  109. package/dist/indexer/protoScanner.d.ts +34 -0
  110. package/dist/indexer/protoScanner.d.ts.map +1 -0
  111. package/dist/indexer/protoScanner.js +133 -0
  112. package/dist/indexer/protoScanner.js.map +1 -0
  113. package/dist/indexer/risk.d.ts +115 -0
  114. package/dist/indexer/risk.d.ts.map +1 -0
  115. package/dist/indexer/risk.js +194 -0
  116. package/dist/indexer/risk.js.map +1 -0
  117. package/dist/indexer/serviceHostScanner.d.ts +25 -0
  118. package/dist/indexer/serviceHostScanner.d.ts.map +1 -0
  119. package/dist/indexer/serviceHostScanner.js +95 -0
  120. package/dist/indexer/serviceHostScanner.js.map +1 -0
  121. package/dist/indexer/serviceLinks.d.ts +105 -0
  122. package/dist/indexer/serviceLinks.d.ts.map +1 -0
  123. package/dist/indexer/serviceLinks.js +509 -0
  124. package/dist/indexer/serviceLinks.js.map +1 -0
  125. package/dist/indexer/shapehash.d.ts +98 -0
  126. package/dist/indexer/shapehash.d.ts.map +1 -0
  127. package/dist/indexer/shapehash.js +354 -0
  128. package/dist/indexer/shapehash.js.map +1 -0
  129. package/dist/indexer/skeleton.d.ts +15 -0
  130. package/dist/indexer/skeleton.d.ts.map +1 -0
  131. package/dist/indexer/skeleton.js +136 -0
  132. package/dist/indexer/skeleton.js.map +1 -0
  133. package/dist/indexer/symbolhistory.d.ts +41 -0
  134. package/dist/indexer/symbolhistory.d.ts.map +1 -0
  135. package/dist/indexer/symbolhistory.js +124 -0
  136. package/dist/indexer/symbolhistory.js.map +1 -0
  137. package/dist/indexer/watcher.d.ts +68 -0
  138. package/dist/indexer/watcher.d.ts.map +1 -0
  139. package/dist/indexer/watcher.js +179 -0
  140. package/dist/indexer/watcher.js.map +1 -0
  141. package/dist/mcp/server.d.ts +80 -0
  142. package/dist/mcp/server.d.ts.map +1 -0
  143. package/dist/mcp/server.js +1610 -0
  144. package/dist/mcp/server.js.map +1 -0
  145. package/dist/parser/index.d.ts +8 -0
  146. package/dist/parser/index.d.ts.map +1 -0
  147. package/dist/parser/index.js +33 -0
  148. package/dist/parser/index.js.map +1 -0
  149. package/dist/parser/languages/cpp.d.ts +3 -0
  150. package/dist/parser/languages/cpp.d.ts.map +1 -0
  151. package/dist/parser/languages/cpp.js +350 -0
  152. package/dist/parser/languages/cpp.js.map +1 -0
  153. package/dist/parser/languages/csharp.d.ts +3 -0
  154. package/dist/parser/languages/csharp.d.ts.map +1 -0
  155. package/dist/parser/languages/csharp.js +239 -0
  156. package/dist/parser/languages/csharp.js.map +1 -0
  157. package/dist/parser/languages/go.d.ts +3 -0
  158. package/dist/parser/languages/go.d.ts.map +1 -0
  159. package/dist/parser/languages/go.js +259 -0
  160. package/dist/parser/languages/go.js.map +1 -0
  161. package/dist/parser/languages/java.d.ts +3 -0
  162. package/dist/parser/languages/java.d.ts.map +1 -0
  163. package/dist/parser/languages/java.js +391 -0
  164. package/dist/parser/languages/java.js.map +1 -0
  165. package/dist/parser/languages/python.d.ts +3 -0
  166. package/dist/parser/languages/python.d.ts.map +1 -0
  167. package/dist/parser/languages/python.js +396 -0
  168. package/dist/parser/languages/python.js.map +1 -0
  169. package/dist/parser/languages/rust.d.ts +3 -0
  170. package/dist/parser/languages/rust.d.ts.map +1 -0
  171. package/dist/parser/languages/rust.js +159 -0
  172. package/dist/parser/languages/rust.js.map +1 -0
  173. package/dist/parser/languages/typescript.d.ts +3 -0
  174. package/dist/parser/languages/typescript.d.ts.map +1 -0
  175. package/dist/parser/languages/typescript.js +1442 -0
  176. package/dist/parser/languages/typescript.js.map +1 -0
  177. package/dist/parser/parserContext.d.ts +77 -0
  178. package/dist/parser/parserContext.d.ts.map +1 -0
  179. package/dist/parser/parserContext.js +354 -0
  180. package/dist/parser/parserContext.js.map +1 -0
  181. package/dist/parser/walker.d.ts +81 -0
  182. package/dist/parser/walker.d.ts.map +1 -0
  183. package/dist/parser/walker.js +217 -0
  184. package/dist/parser/walker.js.map +1 -0
  185. package/dist/parser/worker.d.ts +66 -0
  186. package/dist/parser/worker.d.ts.map +1 -0
  187. package/dist/parser/worker.js +129 -0
  188. package/dist/parser/worker.js.map +1 -0
  189. package/dist/parser/workerpool.d.ts +107 -0
  190. package/dist/parser/workerpool.d.ts.map +1 -0
  191. package/dist/parser/workerpool.js +383 -0
  192. package/dist/parser/workerpool.js.map +1 -0
  193. package/dist/scip/format.d.ts +87 -0
  194. package/dist/scip/format.d.ts.map +1 -0
  195. package/dist/scip/format.js +31 -0
  196. package/dist/scip/format.js.map +1 -0
  197. package/dist/scip/import.d.ts +37 -0
  198. package/dist/scip/import.d.ts.map +1 -0
  199. package/dist/scip/import.js +180 -0
  200. package/dist/scip/import.js.map +1 -0
  201. package/dist/types.d.ts +392 -0
  202. package/dist/types.d.ts.map +1 -0
  203. package/dist/types.js +4 -0
  204. package/dist/types.js.map +1 -0
  205. package/docs/architecture.md +105 -0
  206. package/docs/benchmarks/methodology.md +134 -0
  207. package/docs/benchmarks/raw-results.md +71 -0
  208. package/docs/benchmarks.md +74 -0
  209. package/docs/cli.md +148 -0
  210. package/docs/examples/behavior-tests.md +70 -0
  211. package/docs/examples/change-history.md +85 -0
  212. package/docs/examples/pre-edit-context.md +81 -0
  213. package/docs/examples/service-links.md +88 -0
  214. package/docs/examples.md +80 -0
  215. package/docs/faq.md +70 -0
  216. package/docs/internals.md +104 -0
  217. package/docs/languages.md +70 -0
  218. package/docs/limits.md +52 -0
  219. package/docs/mcp.md +199 -0
  220. package/docs/quickstart.md +119 -0
  221. package/docs/testing.md +123 -0
  222. package/docs/tools.md +115 -0
  223. package/package.json +52 -0
  224. package/research-codebase.md +578 -0
  225. package/seer-cli-docs.md +326 -0
  226. package/seer-master-guide.md +246 -0
  227. package/src/bundle/ci.ts +141 -0
  228. package/src/bundle/contract.ts +387 -0
  229. package/src/bundle/export.ts +175 -0
  230. package/src/bundle/external.ts +285 -0
  231. package/src/bundle/format.ts +92 -0
  232. package/src/bundle/import.ts +157 -0
  233. package/src/cli/index.ts +1249 -0
  234. package/src/cli/init.ts +389 -0
  235. package/src/db/schema.ts +614 -0
  236. package/src/db/store.ts +4306 -0
  237. package/src/graph/pagerank.ts +53 -0
  238. package/src/indexer/architecture.ts +148 -0
  239. package/src/indexer/behavior.ts +466 -0
  240. package/src/indexer/boundaries.ts +374 -0
  241. package/src/indexer/churn.ts +58 -0
  242. package/src/indexer/classify.ts +96 -0
  243. package/src/indexer/context.ts +340 -0
  244. package/src/indexer/continuity.ts +322 -0
  245. package/src/indexer/detectchanges.ts +94 -0
  246. package/src/indexer/discovery.ts +176 -0
  247. package/src/indexer/externaldeps.ts +243 -0
  248. package/src/indexer/freshness.ts +166 -0
  249. package/src/indexer/git.ts +453 -0
  250. package/src/indexer/index.ts +1092 -0
  251. package/src/indexer/modules.ts +358 -0
  252. package/src/indexer/preflight.ts +548 -0
  253. package/src/indexer/protoScanner.ts +147 -0
  254. package/src/indexer/risk.ts +304 -0
  255. package/src/indexer/serviceHostScanner.ts +92 -0
  256. package/src/indexer/serviceLinks.ts +543 -0
  257. package/src/indexer/shapehash.ts +370 -0
  258. package/src/indexer/skeleton.ts +169 -0
  259. package/src/indexer/symbolhistory.ts +172 -0
  260. package/src/indexer/watcher.ts +206 -0
  261. package/src/mcp/server.ts +1659 -0
  262. package/src/parser/index.ts +37 -0
  263. package/src/parser/languages/cpp.ts +361 -0
  264. package/src/parser/languages/csharp.ts +235 -0
  265. package/src/parser/languages/go.ts +259 -0
  266. package/src/parser/languages/java.ts +382 -0
  267. package/src/parser/languages/python.ts +370 -0
  268. package/src/parser/languages/rust.ts +164 -0
  269. package/src/parser/languages/typescript.ts +1435 -0
  270. package/src/parser/parserContext.ts +392 -0
  271. package/src/parser/walker.ts +306 -0
  272. package/src/parser/worker.ts +181 -0
  273. package/src/parser/workerpool.ts +448 -0
  274. package/src/scip/format.ts +83 -0
  275. package/src/scip/import.ts +216 -0
  276. package/src/types.ts +457 -0
  277. package/tests/benchmark-service-links.ts +244 -0
  278. package/tests/bug-regressions.ts +626 -0
  279. package/tests/filters.ts +264 -0
  280. package/tests/fixtures/Counter.tsx +38 -0
  281. package/tests/fixtures/caller.ts +7 -0
  282. package/tests/fixtures/collisions.ts +23 -0
  283. package/tests/fixtures/local_helper.ts +5 -0
  284. package/tests/fixtures/overloads.java +17 -0
  285. package/tests/fixtures/remote_helper.ts +4 -0
  286. package/tests/fixtures/sample.c +15 -0
  287. package/tests/fixtures/sample.cpp +47 -0
  288. package/tests/fixtures/sample.cs +62 -0
  289. package/tests/fixtures/sample.go +68 -0
  290. package/tests/fixtures/sample.h +30 -0
  291. package/tests/fixtures/sample.java +85 -0
  292. package/tests/fixtures/sample.py +46 -0
  293. package/tests/fixtures/sample.rs +78 -0
  294. package/tests/fixtures/sample.ts +76 -0
  295. package/tests/fixtures-service/HttpClients.cs +30 -0
  296. package/tests/fixtures-service/HttpClients.java +24 -0
  297. package/tests/fixtures-service/billing.ts +15 -0
  298. package/tests/fixtures-service/docker-compose.yml +15 -0
  299. package/tests/fixtures-service/gateway.ts +10 -0
  300. package/tests/fixtures-service/get_user.ts +11 -0
  301. package/tests/fixtures-service/graphql_client.ts +63 -0
  302. package/tests/fixtures-service/graphql_server.ts +30 -0
  303. package/tests/fixtures-service/grpc_client.go +30 -0
  304. package/tests/fixtures-service/http_clients.go +23 -0
  305. package/tests/fixtures-service/http_clients.py +38 -0
  306. package/tests/fixtures-service/http_clients.ts +49 -0
  307. package/tests/fixtures-service/k8s/payment-service.yaml +22 -0
  308. package/tests/fixtures-service/k8s_calls.ts +20 -0
  309. package/tests/fixtures-service/messaging.ts +87 -0
  310. package/tests/fixtures-service/trpc_client.ts +39 -0
  311. package/tests/fixtures-service/trpc_server.ts +39 -0
  312. package/tests/fixtures-service/user_service.proto +33 -0
  313. package/tests/fixtures-trackcd/Cargo.toml +11 -0
  314. package/tests/fixtures-trackcd/SpringController.java +36 -0
  315. package/tests/fixtures-trackcd/auth_service.ts +19 -0
  316. package/tests/fixtures-trackcd/complex_module.py +50 -0
  317. package/tests/fixtures-trackcd/express_app.js +30 -0
  318. package/tests/fixtures-trackcd/fastapi_app.py +49 -0
  319. package/tests/fixtures-trackcd/fastify_object_routes.js +32 -0
  320. package/tests/fixtures-trackcd/go.mod +8 -0
  321. package/tests/fixtures-trackcd/package.json +15 -0
  322. package/tests/fixtures-trackcd/requirements.txt +4 -0
  323. package/tests/fixtures-trackcd/tests/auth_service.test.ts +13 -0
  324. package/tests/fixtures-tracke/auth/AuthService.ts +23 -0
  325. package/tests/fixtures-tracke/auth/crypto.ts +7 -0
  326. package/tests/fixtures-tracke/billing/Billing.ts +20 -0
  327. package/tests/fixtures-tracke/billing/Invoice.ts +10 -0
  328. package/tests/fixtures-tracke/billing/server.ts +17 -0
  329. package/tests/fixtures-tracke/package.json +7 -0
  330. package/tests/fixtures-tracke/tests/auth.test.ts +23 -0
  331. package/tests/fixtures-tracke/tests/billing.test.ts +14 -0
  332. package/tests/fixtures-trackf/package.json +5 -0
  333. package/tests/fixtures-trackf/src/auth.ts +26 -0
  334. package/tests/fixtures-trackf/src/handlers.ts +35 -0
  335. package/tests/fixtures-tracki/billing/routes.ts +12 -0
  336. package/tests/fixtures-tracki/gateway/client.ts +13 -0
  337. package/tests/git-features.ts +267 -0
  338. package/tests/init.ts +141 -0
  339. package/tests/mcp-jit.ts +130 -0
  340. package/tests/mcp-smoke.ts +191 -0
  341. package/tests/mcp-trackcd.ts +169 -0
  342. package/tests/mcp-tracke.ts +229 -0
  343. package/tests/mcp-trackf.ts +330 -0
  344. package/tests/mcp-trackg.ts +219 -0
  345. package/tests/mcp-tracki.ts +174 -0
  346. package/tests/mcp-watcher.ts +126 -0
  347. package/tests/optspec.ts +194 -0
  348. package/tests/parallel-index.ts +333 -0
  349. package/tests/parallel-read.ts +125 -0
  350. package/tests/parallel-recovery.ts +241 -0
  351. package/tests/perf-callers.ts +145 -0
  352. package/tests/query-parity.ts +184 -0
  353. package/tests/query-perf.ts +55 -0
  354. package/tests/scale-parallel-parity.ts +225 -0
  355. package/tests/scale-test.ts +523 -0
  356. package/tests/smoke.ts +396 -0
  357. package/tests/trackcd.ts +325 -0
  358. package/tests/tracke-collisions.ts +255 -0
  359. package/tests/tracke.ts +314 -0
  360. package/tests/trackf-bugs.ts +406 -0
  361. package/tests/trackf.ts +390 -0
  362. package/tests/trackg.ts +1372 -0
  363. package/tests/tracki-boundaries.ts +202 -0
  364. package/tests/tracki-continuity.ts +253 -0
  365. package/tests/tracki-contract-diff.ts +249 -0
  366. package/tests/tracki-external-bundles.ts +341 -0
  367. package/tests/tracki-preflight.ts +251 -0
  368. package/tests/verify-roles.ts +51 -0
  369. package/tests/worker-parity.ts +286 -0
  370. package/tests/worker-pool.ts +262 -0
  371. package/tsconfig.json +20 -0
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Track E feature tests.
3
+ *
4
+ * Indexes `tests/fixtures-tracke/` once and exercises every Track-E feature:
5
+ * - Louvain module clustering (auto-built during indexDirectory)
6
+ * - Module MCP-style queries (listModules, listModuleMembers,
7
+ * moduleForFile, moduleDependencies, listModuleTopSymbols)
8
+ * - Bounded reverse / forward reachability with depth
9
+ * - File-import closure (seer_trace_file_dependencies basis)
10
+ * - Ranked seer_behavior 2.0 (direct / indirect / naming / same-file)
11
+ * - seer_risk decomposed signals
12
+ * - seer_context one-call packet
13
+ *
14
+ * Run with: npx tsx tests/tracke.ts
15
+ */
16
+
17
+ import path from 'path';
18
+ import fs from 'fs';
19
+ import os from 'os';
20
+ import { Indexer } from '../src/indexer/index';
21
+ import { Store } from '../src/db/store';
22
+ import { buildModules } from '../src/indexer/modules';
23
+ import { rankedBehavior } from '../src/indexer/behavior';
24
+ import { computeRisk } from '../src/indexer/risk';
25
+ import { buildContext } from '../src/indexer/context';
26
+
27
+ const FIXTURES = path.join(__dirname, 'fixtures-tracke');
28
+ const TMP_DB = path.join(os.tmpdir(), `seer-tracke-${Date.now()}.db`);
29
+
30
+ let passed = 0;
31
+ let failed = 0;
32
+
33
+ function assert(cond: boolean, msg: string): void {
34
+ if (cond) { console.log(` ✓ ${msg}`); passed++; }
35
+ else { console.error(` ✗ ${msg}`); failed++; }
36
+ }
37
+ function assertEq<T>(actual: T, expected: T, msg: string): void {
38
+ assert(actual === expected, `${msg} (got ${JSON.stringify(actual)}, expected ${JSON.stringify(expected)})`);
39
+ }
40
+
41
+ async function run(): Promise<void> {
42
+ console.log('\nSeer Track E Feature Tests');
43
+ console.log('============================\n');
44
+
45
+ if (!fs.existsSync(FIXTURES)) {
46
+ console.error(`Missing fixtures dir: ${FIXTURES}`);
47
+ process.exit(1);
48
+ }
49
+
50
+ const store = new Store(TMP_DB);
51
+ const indexer = new Indexer(store);
52
+ console.log(`Indexing ${FIXTURES}...`);
53
+ const r = await indexer.indexDirectory(FIXTURES, { quiet: true });
54
+ console.log(` files=${r.filesIndexed} symbols=${r.symbols} edges=${r.edges} modules=${r.modules}\n`);
55
+
56
+ // ── Schema version ────────────────────────────────────────────────────────
57
+ console.log('── Schema ──');
58
+ const schema = store.schemaInfo();
59
+ assertEq(schema.current, true, 'schema is current');
60
+ assertEq(schema.dbVersion, 10, 'schema version is v10');
61
+
62
+ // ── Modules: clustering built automatically ───────────────────────────────
63
+ console.log('\n── Module clustering ──');
64
+ assert(store.hasModulesData(), 'module clustering ran during indexDirectory');
65
+ const modules = store.listModules({ limit: 50 });
66
+ console.log(` ${modules.length} modules:`);
67
+ for (const m of modules) {
68
+ console.log(` [${m.id}] ${m.label.padEnd(20)} files=${m.sizeFiles} symbols=${m.sizeSymbols} primary=${m.primaryLanguage} cohesion=${m.cohesion.toFixed(2)} centrality=${m.centrality.toFixed(4)}`);
69
+ }
70
+ assert(modules.length >= 2, `at least 2 modules clustered (got ${modules.length})`);
71
+ // Every module is non-empty.
72
+ for (const m of modules) assert(m.sizeFiles > 0, `module "${m.label}" has at least 1 file`);
73
+ // Labels are unique.
74
+ const labelSet = new Set(modules.map(m => m.label));
75
+ assertEq(labelSet.size, modules.length, 'module labels are unique');
76
+ // Centrality is non-negative and finite.
77
+ for (const m of modules) assert(Number.isFinite(m.centrality) && m.centrality >= 0, `module "${m.label}" centrality is finite and non-negative`);
78
+ // Cohesion is in [0, 1].
79
+ for (const m of modules) assert(m.cohesion >= 0 && m.cohesion <= 1, `module "${m.label}" cohesion in [0, 1]`);
80
+
81
+ // ── Determinism: re-running buildModules produces the same labels + sizes
82
+ console.log('\n── Clustering determinism ──');
83
+ const before = store.listModules({ limit: 200, sortBy: 'label' });
84
+ buildModules(store);
85
+ const after = store.listModules({ limit: 200, sortBy: 'label' });
86
+ assertEq(before.length, after.length, 'rebuild produces same module count');
87
+ let identical = true;
88
+ for (let i = 0; i < before.length; i++) {
89
+ if (before[i].label !== after[i].label || before[i].sizeFiles !== after[i].sizeFiles) {
90
+ identical = false; break;
91
+ }
92
+ }
93
+ assert(identical, 'rebuild produces identical labels + sizes (determinism)');
94
+
95
+ // ── Module membership + lookups ──────────────────────────────────────────
96
+ console.log('\n── Module membership ──');
97
+ const authMod = modules.find(m => m.label === 'auth');
98
+ const billingMod = modules.find(m => m.label === 'billing');
99
+ assert(authMod !== undefined, 'auth module exists');
100
+ assert(billingMod !== undefined, 'billing module exists');
101
+
102
+ // moduleForFile: pick the AuthService.ts and verify it maps to auth.
103
+ const authFile = store.listFiles().find(f => f.relPath.endsWith('auth/AuthService.ts'));
104
+ assert(authFile !== undefined, 'auth/AuthService.ts is indexed');
105
+ const fileMod = authFile ? store.moduleForFile(authFile.id) : null;
106
+ assert(fileMod?.label === 'auth', `moduleForFile(auth/AuthService.ts) = auth (got ${fileMod?.label})`);
107
+
108
+ // Files in the auth module.
109
+ const authFiles = authMod ? store.listModuleMembers(authMod.id) : [];
110
+ assert(authFiles.length >= 2, `auth module has ≥2 files (got ${authFiles.length})`);
111
+ // Tests for the auth module should be co-located with auth (tests have very
112
+ // strong test-edge weight in the clusterer).
113
+ assert(authFiles.some(f => f.relPath.includes('auth/')), 'auth module contains auth/ files');
114
+
115
+ // Top symbols in auth: must include AuthService and validateCredentials.
116
+ const authSymbols = authMod ? store.listModuleTopSymbols(authMod.id, 20) : [];
117
+ assert(authSymbols.some(s => s.name === 'AuthService' || s.qualifiedName === 'AuthService'),
118
+ 'auth module top symbols include AuthService');
119
+
120
+ // ── Module dependencies ─────────────────────────────────────────────────
121
+ console.log('\n── Module dependencies ──');
122
+ // billing imports/calls into auth → there should be a billing→auth edge.
123
+ if (billingMod && authMod) {
124
+ const billOut = store.moduleDependencies(billingMod.id, { direction: 'out' });
125
+ console.log(` billing → ${billOut.map(d => `${d.label}(kind=${d.kind},w=${d.weight})`).join(', ')}`);
126
+ assert(billOut.some(d => d.label === 'auth'), 'billing depends on auth (outgoing)');
127
+ const authIn = store.moduleDependencies(authMod.id, { direction: 'in' });
128
+ console.log(` auth ← ${authIn.map(d => `${d.label}(kind=${d.kind},w=${d.weight})`).join(', ')}`);
129
+ assert(authIn.some(d => d.label === 'billing'), 'auth is depended on by billing (incoming)');
130
+ }
131
+
132
+ // ── Bounded reverse / forward reachability ──────────────────────────────
133
+ console.log('\n── Bounded BFS reachability ──');
134
+ const validate = store.getDefinition('validateCredentials')[0];
135
+ assert(validate !== undefined, 'validateCredentials is indexed');
136
+ const reverse = store.reverseReachableWithDepth(validate.id, 4);
137
+ console.log(` reverseReachableWithDepth(validateCredentials, 4) = ${reverse.length} hits`);
138
+ assert(reverse.length >= 1, 'reverseReachableWithDepth finds ≥1 caller');
139
+ // Every depth must be > 0 and ≤ 4.
140
+ assert(reverse.every(h => h.depth > 0 && h.depth <= 4), 'reverse depths are in (0, maxDepth]');
141
+
142
+ // Forward from a high-fanout function — must reach validateCredentials.
143
+ const charge = store.getDefinition('chargeCustomer')[0];
144
+ if (charge) {
145
+ const fwd = store.forwardReachableWithDepth(charge.id, 5);
146
+ assert(fwd.some(h => h.id === validate.id),
147
+ `forwardReachableWithDepth(chargeCustomer, 5) reaches validateCredentials`);
148
+ }
149
+
150
+ // ── File-import closure ─────────────────────────────────────────────────
151
+ console.log('\n── File-import closure ──');
152
+ const billingFile = store.listFiles().find(f => f.relPath.endsWith('billing/Billing.ts'));
153
+ assert(billingFile !== undefined, 'billing/Billing.ts indexed');
154
+ if (billingFile) {
155
+ const closure = store.fileImportClosure(billingFile.id, 4);
156
+ console.log(` fileImportClosure(billing/Billing.ts) = ${closure.length} files: ${closure.map(c => `${c.relPath}@${c.depth}`).join(', ')}`);
157
+ assert(closure.length >= 1, 'fileImportClosure(billing/Billing.ts) finds ≥1 file');
158
+ assert(closure.some(c => c.relPath.includes('auth/')),
159
+ 'fileImportClosure reaches auth/ files (billing imports auth)');
160
+ assert(closure.every(c => c.depth > 0 && c.depth <= 4), 'closure depths are in (0, maxDepth]');
161
+ }
162
+
163
+ // ── seer_behavior 2.0 ───────────────────────────────────────────────────
164
+ console.log('\n── Ranked behavior 2.0 ──');
165
+ const beh = rankedBehavior(store, 'validateCredentials', { limit: 30 });
166
+ assert(beh !== null, 'rankedBehavior returns a result for validateCredentials');
167
+ if (beh) {
168
+ console.log(` direct=${beh.direct} indirect=${beh.indirect} naming=${beh.namingMatches} same-file=${beh.sameFileMatches}`);
169
+ assert(beh.direct >= 1, 'validateCredentials has ≥1 direct test');
170
+ // The fixture has a "testValidate" test that calls login() (which calls
171
+ // validateCredentials) — that's the indirect coverage signal.
172
+ assert(beh.indirect >= 1, 'validateCredentials has ≥1 indirect test (via login)');
173
+ // The fixture has a sibling auth/AuthService.test.ts — naming convention
174
+ // OR direct/indirect should include test functions whose name mentions
175
+ // validate.
176
+ const validateTests = beh.tests.filter(t => /validate/i.test(t.testSymbol.name));
177
+ assert(validateTests.length >= 1, 'tests with "validate" in name are found');
178
+ // Specificity is sorted descending.
179
+ let monotonic = true;
180
+ for (let i = 1; i < beh.tests.length; i++) {
181
+ if (beh.tests[i].specificity > beh.tests[i - 1].specificity) { monotonic = false; break; }
182
+ }
183
+ assert(monotonic, 'tests sorted by specificity DESC');
184
+ // Direct tests outrank everything else.
185
+ if (beh.tests.length > 0 && beh.direct > 0) {
186
+ const firstDirectIndex = beh.tests.findIndex(t => t.relationship === 'direct-call');
187
+ const firstNonDirect = beh.tests.findIndex(t => t.relationship !== 'direct-call');
188
+ if (firstDirectIndex !== -1 && firstNonDirect !== -1) {
189
+ assert(firstDirectIndex < firstNonDirect || firstDirectIndex !== -1,
190
+ 'direct-call tests outrank non-direct tests');
191
+ }
192
+ }
193
+ // Assertion counts should be non-negative integers.
194
+ assert(beh.tests.every(t => Number.isInteger(t.assertionCount) && t.assertionCount >= 0),
195
+ 'assertion counts are non-negative integers');
196
+ }
197
+
198
+ // Behavior 2.0 with the indirect path turned off — direct only.
199
+ const behDirectOnly = rankedBehavior(store, 'validateCredentials', {
200
+ limit: 20, indirectDepth: 0, includeNamingConvention: false, includeSameFile: false,
201
+ });
202
+ if (behDirectOnly) {
203
+ assert(behDirectOnly.indirect === 0, 'indirect coverage disabled when indirectDepth=0');
204
+ assert(behDirectOnly.tests.every(t => t.relationship === 'direct-call'),
205
+ 'with all flags off, only direct-call tests are returned');
206
+ }
207
+
208
+ // ── seer_risk ───────────────────────────────────────────────────────────
209
+ console.log('\n── Risk profile ──');
210
+ const risk = computeRisk(store, 'validateCredentials');
211
+ assert(risk !== null, 'computeRisk returns a result');
212
+ if (risk) {
213
+ console.log(` risk=${risk.risk} score=${risk.score.toFixed(2)} dCallers=${risk.signals.directCallers} tCallers=${risk.signals.transitiveCallers} routeExposed=${risk.signals.routeExposed} directTests=${risk.signals.directTests}`);
214
+ assert(['low', 'medium', 'high'].includes(risk.risk), `risk verdict is one of low/medium/high`);
215
+ assert(Number.isFinite(risk.score), 'risk score is finite');
216
+ assert(risk.signalContributions.length >= 10, 'risk decomposes into ≥10 signals');
217
+ // Every signal contribution row has signal/value/contribution.
218
+ assert(risk.signalContributions.every(s => typeof s.signal === 'string' && Number.isFinite(s.contribution)),
219
+ 'every signal contribution is well-formed');
220
+ // validateCredentials has direct tests → directTests contribution must be ≤ 0.
221
+ const direct = risk.signalContributions.find(s => s.signal === 'directTests');
222
+ assert(direct !== undefined && direct.contribution <= 0,
223
+ 'directTests contribution is ≤ 0 when there are direct tests (coverage reduces risk)');
224
+ // directCallers signal value should match countCallers.
225
+ assertEq(risk.signals.directCallers, store.countCallers('validateCredentials'),
226
+ 'directCallers matches store.countCallers');
227
+ }
228
+
229
+ // Risk for a route handler must include routeExposed.
230
+ const handlerRisk = computeRisk(store, 'chargeCustomer');
231
+ if (handlerRisk) {
232
+ console.log(` chargeCustomer risk=${handlerRisk.risk} score=${handlerRisk.score.toFixed(2)} routeExposed=${handlerRisk.signals.routeExposed}`);
233
+ // chargeCustomer is registered as a route handler in fixtures.
234
+ assert(handlerRisk.signals.routeExposed, 'chargeCustomer is route-exposed');
235
+ assert(handlerRisk.signals.routes.length >= 1, 'chargeCustomer has ≥1 route');
236
+ }
237
+
238
+ // ── seer_context ────────────────────────────────────────────────────────
239
+ console.log('\n── Context packet ──');
240
+ const ctx = buildContext(store, 'validateCredentials');
241
+ assert(ctx !== null, 'buildContext returns a packet for validateCredentials');
242
+ if (ctx) {
243
+ console.log(` symbol=${ctx.symbol.qualifiedName ?? ctx.symbol.name} module=${ctx.module?.label} callers=${ctx.callers.total} callees=${ctx.callees.total} blast=${ctx.blastRadius.directCallers}+${ctx.blastRadius.transitiveCallers} behavior.direct=${ctx.behavior.direct} risk=${ctx.risk.risk}`);
244
+ // The packet must include every section.
245
+ assert(ctx.symbol && ctx.symbol.id === validate.id, 'context symbol matches lookup');
246
+ assert(ctx.module !== null, 'context.module is non-null when modules are built');
247
+ assert(ctx.callers.total >= 1, 'context.callers.total ≥ 1');
248
+ assert(ctx.callees.total >= 0, 'context.callees.total ≥ 0');
249
+ assert(ctx.behavior.direct >= 1, 'context.behavior.direct ≥ 1');
250
+ assert(['low', 'medium', 'high'].includes(ctx.risk.risk), 'context.risk.risk is a verdict');
251
+ assert(ctx.risk.signalContributions.length >= 10, 'context.risk decomposes into ≥10 signals');
252
+ // blastRadius.directCallers should equal callers.total (both are direct).
253
+ assertEq(ctx.blastRadius.directCallers, ctx.callers.total,
254
+ 'blastRadius.directCallers matches callers.total');
255
+ // The packet is JSON-serializable (no cyclic refs, no functions).
256
+ let serialized: string | null = null;
257
+ try { serialized = JSON.stringify(ctx); } catch { /* */ }
258
+ assert(serialized !== null && serialized.length > 100,
259
+ 'context packet is JSON-serializable');
260
+ }
261
+
262
+ // Context for a route handler must include the route.
263
+ const ctxRoute = buildContext(store, 'chargeCustomer');
264
+ if (ctxRoute) {
265
+ assert(ctxRoute.routes.length >= 1, 'context for chargeCustomer includes its route');
266
+ }
267
+
268
+ // Context for a non-existent symbol returns null.
269
+ const ctxMissing = buildContext(store, 'thisSymbolDoesNotExistAnywhere_xyz');
270
+ assertEq(ctxMissing, null, 'context for unknown symbol returns null');
271
+
272
+ // ── Empty / degenerate inputs ───────────────────────────────────────────
273
+ console.log('\n── Degenerate inputs ──');
274
+ assertEq(store.reverseReachableWithDepth(99999999, 4).length, 0,
275
+ 'reverseReachableWithDepth on unknown id returns empty');
276
+ assertEq(store.forwardReachableWithDepth(99999999, 4).length, 0,
277
+ 'forwardReachableWithDepth on unknown id returns empty');
278
+ assertEq(store.fileImportClosure(99999999, 4).length, 0,
279
+ 'fileImportClosure on unknown id returns empty');
280
+ assertEq(store.listModuleMembers(99999999).length, 0,
281
+ 'listModuleMembers on unknown id returns empty');
282
+ assertEq(store.moduleDependencies(99999999).length, 0,
283
+ 'moduleDependencies on unknown id returns empty');
284
+ assertEq(rankedBehavior(store, '__no_such_symbol__'), null,
285
+ 'rankedBehavior on unknown symbol returns null');
286
+ assertEq(computeRisk(store, '__no_such_symbol__'), null,
287
+ 'computeRisk on unknown symbol returns null');
288
+
289
+ // ── Module clustering on an empty store ─────────────────────────────────
290
+ console.log('\n── Empty-store clustering ──');
291
+ const TMP_DB2 = path.join(os.tmpdir(), `seer-tracke-empty-${Date.now()}.db`);
292
+ const emptyStore = new Store(TMP_DB2);
293
+ try {
294
+ const er = buildModules(emptyStore);
295
+ assertEq(er.modules, 0, 'empty store yields 0 modules');
296
+ assertEq(er.files, 0, 'empty store yields 0 files');
297
+ } finally {
298
+ emptyStore.close();
299
+ try { fs.unlinkSync(TMP_DB2); } catch { /* */ }
300
+ ['-wal', '-shm'].forEach(suf => { try { fs.unlinkSync(TMP_DB2 + suf); } catch { /* */ } });
301
+ }
302
+
303
+ // ── Cleanup ────────────────────────────────────────────────────────────
304
+ store.close();
305
+ if (fs.existsSync(TMP_DB)) fs.unlinkSync(TMP_DB);
306
+ ['-wal', '-shm'].forEach(suf => { try { fs.unlinkSync(TMP_DB + suf); } catch { /* */ } });
307
+
308
+ console.log(`\n══════════════════════════════════════════════════════════════`);
309
+ console.log(` Results: ${passed} passed, ${failed} failed`);
310
+ if (failed > 0) { console.error('\n TRACK E TEST FAILED\n'); process.exit(1); }
311
+ else { console.log('\n All Track E tests passed! ✓\n'); }
312
+ }
313
+
314
+ run().catch(err => { console.error('tracke crashed:', err); process.exit(1); });