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.
- package/.vscode/settings.json +3 -0
- package/LICENSE +176 -0
- package/README.md +272 -0
- package/README_dev.md +199 -0
- package/dist/bundle/ci.d.ts +47 -0
- package/dist/bundle/ci.d.ts.map +1 -0
- package/dist/bundle/ci.js +113 -0
- package/dist/bundle/ci.js.map +1 -0
- package/dist/bundle/contract.d.ts +111 -0
- package/dist/bundle/contract.d.ts.map +1 -0
- package/dist/bundle/contract.js +352 -0
- package/dist/bundle/contract.js.map +1 -0
- package/dist/bundle/export.d.ts +36 -0
- package/dist/bundle/export.d.ts.map +1 -0
- package/dist/bundle/export.js +152 -0
- package/dist/bundle/export.js.map +1 -0
- package/dist/bundle/external.d.ts +66 -0
- package/dist/bundle/external.d.ts.map +1 -0
- package/dist/bundle/external.js +238 -0
- package/dist/bundle/external.js.map +1 -0
- package/dist/bundle/format.d.ts +94 -0
- package/dist/bundle/format.d.ts.map +1 -0
- package/dist/bundle/format.js +42 -0
- package/dist/bundle/format.js.map +1 -0
- package/dist/bundle/import.d.ts +49 -0
- package/dist/bundle/import.d.ts.map +1 -0
- package/dist/bundle/import.js +116 -0
- package/dist/bundle/import.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +1402 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +48 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +284 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/db/schema.d.ts +3 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +616 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/store.d.ts +1011 -0
- package/dist/db/store.d.ts.map +1 -0
- package/dist/db/store.js +3888 -0
- package/dist/db/store.js.map +1 -0
- package/dist/graph/pagerank.d.ts +9 -0
- package/dist/graph/pagerank.d.ts.map +1 -0
- package/dist/graph/pagerank.js +47 -0
- package/dist/graph/pagerank.js.map +1 -0
- package/dist/indexer/architecture.d.ts +72 -0
- package/dist/indexer/architecture.d.ts.map +1 -0
- package/dist/indexer/architecture.js +112 -0
- package/dist/indexer/architecture.js.map +1 -0
- package/dist/indexer/behavior.d.ts +75 -0
- package/dist/indexer/behavior.d.ts.map +1 -0
- package/dist/indexer/behavior.js +395 -0
- package/dist/indexer/behavior.js.map +1 -0
- package/dist/indexer/boundaries.d.ts +60 -0
- package/dist/indexer/boundaries.d.ts.map +1 -0
- package/dist/indexer/boundaries.js +366 -0
- package/dist/indexer/boundaries.js.map +1 -0
- package/dist/indexer/churn.d.ts +15 -0
- package/dist/indexer/churn.d.ts.map +1 -0
- package/dist/indexer/churn.js +49 -0
- package/dist/indexer/churn.js.map +1 -0
- package/dist/indexer/classify.d.ts +9 -0
- package/dist/indexer/classify.d.ts.map +1 -0
- package/dist/indexer/classify.js +90 -0
- package/dist/indexer/classify.js.map +1 -0
- package/dist/indexer/context.d.ts +176 -0
- package/dist/indexer/context.d.ts.map +1 -0
- package/dist/indexer/context.js +193 -0
- package/dist/indexer/context.js.map +1 -0
- package/dist/indexer/continuity.d.ts +67 -0
- package/dist/indexer/continuity.d.ts.map +1 -0
- package/dist/indexer/continuity.js +288 -0
- package/dist/indexer/continuity.js.map +1 -0
- package/dist/indexer/detectchanges.d.ts +32 -0
- package/dist/indexer/detectchanges.d.ts.map +1 -0
- package/dist/indexer/detectchanges.js +74 -0
- package/dist/indexer/detectchanges.js.map +1 -0
- package/dist/indexer/discovery.d.ts +37 -0
- package/dist/indexer/discovery.d.ts.map +1 -0
- package/dist/indexer/discovery.js +136 -0
- package/dist/indexer/discovery.js.map +1 -0
- package/dist/indexer/externaldeps.d.ts +18 -0
- package/dist/indexer/externaldeps.d.ts.map +1 -0
- package/dist/indexer/externaldeps.js +288 -0
- package/dist/indexer/externaldeps.js.map +1 -0
- package/dist/indexer/freshness.d.ts +48 -0
- package/dist/indexer/freshness.d.ts.map +1 -0
- package/dist/indexer/freshness.js +128 -0
- package/dist/indexer/freshness.js.map +1 -0
- package/dist/indexer/git.d.ts +144 -0
- package/dist/indexer/git.d.ts.map +1 -0
- package/dist/indexer/git.js +444 -0
- package/dist/indexer/git.js.map +1 -0
- package/dist/indexer/index.d.ts +145 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +930 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/modules.d.ts +62 -0
- package/dist/indexer/modules.d.ts.map +1 -0
- package/dist/indexer/modules.js +293 -0
- package/dist/indexer/modules.js.map +1 -0
- package/dist/indexer/preflight.d.ts +154 -0
- package/dist/indexer/preflight.d.ts.map +1 -0
- package/dist/indexer/preflight.js +399 -0
- package/dist/indexer/preflight.js.map +1 -0
- package/dist/indexer/protoScanner.d.ts +34 -0
- package/dist/indexer/protoScanner.d.ts.map +1 -0
- package/dist/indexer/protoScanner.js +133 -0
- package/dist/indexer/protoScanner.js.map +1 -0
- package/dist/indexer/risk.d.ts +115 -0
- package/dist/indexer/risk.d.ts.map +1 -0
- package/dist/indexer/risk.js +194 -0
- package/dist/indexer/risk.js.map +1 -0
- package/dist/indexer/serviceHostScanner.d.ts +25 -0
- package/dist/indexer/serviceHostScanner.d.ts.map +1 -0
- package/dist/indexer/serviceHostScanner.js +95 -0
- package/dist/indexer/serviceHostScanner.js.map +1 -0
- package/dist/indexer/serviceLinks.d.ts +105 -0
- package/dist/indexer/serviceLinks.d.ts.map +1 -0
- package/dist/indexer/serviceLinks.js +509 -0
- package/dist/indexer/serviceLinks.js.map +1 -0
- package/dist/indexer/shapehash.d.ts +98 -0
- package/dist/indexer/shapehash.d.ts.map +1 -0
- package/dist/indexer/shapehash.js +354 -0
- package/dist/indexer/shapehash.js.map +1 -0
- package/dist/indexer/skeleton.d.ts +15 -0
- package/dist/indexer/skeleton.d.ts.map +1 -0
- package/dist/indexer/skeleton.js +136 -0
- package/dist/indexer/skeleton.js.map +1 -0
- package/dist/indexer/symbolhistory.d.ts +41 -0
- package/dist/indexer/symbolhistory.d.ts.map +1 -0
- package/dist/indexer/symbolhistory.js +124 -0
- package/dist/indexer/symbolhistory.js.map +1 -0
- package/dist/indexer/watcher.d.ts +68 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +179 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/mcp/server.d.ts +80 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +1610 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/parser/index.d.ts +8 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +33 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/languages/cpp.d.ts +3 -0
- package/dist/parser/languages/cpp.d.ts.map +1 -0
- package/dist/parser/languages/cpp.js +350 -0
- package/dist/parser/languages/cpp.js.map +1 -0
- package/dist/parser/languages/csharp.d.ts +3 -0
- package/dist/parser/languages/csharp.d.ts.map +1 -0
- package/dist/parser/languages/csharp.js +239 -0
- package/dist/parser/languages/csharp.js.map +1 -0
- package/dist/parser/languages/go.d.ts +3 -0
- package/dist/parser/languages/go.d.ts.map +1 -0
- package/dist/parser/languages/go.js +259 -0
- package/dist/parser/languages/go.js.map +1 -0
- package/dist/parser/languages/java.d.ts +3 -0
- package/dist/parser/languages/java.d.ts.map +1 -0
- package/dist/parser/languages/java.js +391 -0
- package/dist/parser/languages/java.js.map +1 -0
- package/dist/parser/languages/python.d.ts +3 -0
- package/dist/parser/languages/python.d.ts.map +1 -0
- package/dist/parser/languages/python.js +396 -0
- package/dist/parser/languages/python.js.map +1 -0
- package/dist/parser/languages/rust.d.ts +3 -0
- package/dist/parser/languages/rust.d.ts.map +1 -0
- package/dist/parser/languages/rust.js +159 -0
- package/dist/parser/languages/rust.js.map +1 -0
- package/dist/parser/languages/typescript.d.ts +3 -0
- package/dist/parser/languages/typescript.d.ts.map +1 -0
- package/dist/parser/languages/typescript.js +1442 -0
- package/dist/parser/languages/typescript.js.map +1 -0
- package/dist/parser/parserContext.d.ts +77 -0
- package/dist/parser/parserContext.d.ts.map +1 -0
- package/dist/parser/parserContext.js +354 -0
- package/dist/parser/parserContext.js.map +1 -0
- package/dist/parser/walker.d.ts +81 -0
- package/dist/parser/walker.d.ts.map +1 -0
- package/dist/parser/walker.js +217 -0
- package/dist/parser/walker.js.map +1 -0
- package/dist/parser/worker.d.ts +66 -0
- package/dist/parser/worker.d.ts.map +1 -0
- package/dist/parser/worker.js +129 -0
- package/dist/parser/worker.js.map +1 -0
- package/dist/parser/workerpool.d.ts +107 -0
- package/dist/parser/workerpool.d.ts.map +1 -0
- package/dist/parser/workerpool.js +383 -0
- package/dist/parser/workerpool.js.map +1 -0
- package/dist/scip/format.d.ts +87 -0
- package/dist/scip/format.d.ts.map +1 -0
- package/dist/scip/format.js +31 -0
- package/dist/scip/format.js.map +1 -0
- package/dist/scip/import.d.ts +37 -0
- package/dist/scip/import.d.ts.map +1 -0
- package/dist/scip/import.js +180 -0
- package/dist/scip/import.js.map +1 -0
- package/dist/types.d.ts +392 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/docs/architecture.md +105 -0
- package/docs/benchmarks/methodology.md +134 -0
- package/docs/benchmarks/raw-results.md +71 -0
- package/docs/benchmarks.md +74 -0
- package/docs/cli.md +148 -0
- package/docs/examples/behavior-tests.md +70 -0
- package/docs/examples/change-history.md +85 -0
- package/docs/examples/pre-edit-context.md +81 -0
- package/docs/examples/service-links.md +88 -0
- package/docs/examples.md +80 -0
- package/docs/faq.md +70 -0
- package/docs/internals.md +104 -0
- package/docs/languages.md +70 -0
- package/docs/limits.md +52 -0
- package/docs/mcp.md +199 -0
- package/docs/quickstart.md +119 -0
- package/docs/testing.md +123 -0
- package/docs/tools.md +115 -0
- package/package.json +52 -0
- package/research-codebase.md +578 -0
- package/seer-cli-docs.md +326 -0
- package/seer-master-guide.md +246 -0
- package/src/bundle/ci.ts +141 -0
- package/src/bundle/contract.ts +387 -0
- package/src/bundle/export.ts +175 -0
- package/src/bundle/external.ts +285 -0
- package/src/bundle/format.ts +92 -0
- package/src/bundle/import.ts +157 -0
- package/src/cli/index.ts +1249 -0
- package/src/cli/init.ts +389 -0
- package/src/db/schema.ts +614 -0
- package/src/db/store.ts +4306 -0
- package/src/graph/pagerank.ts +53 -0
- package/src/indexer/architecture.ts +148 -0
- package/src/indexer/behavior.ts +466 -0
- package/src/indexer/boundaries.ts +374 -0
- package/src/indexer/churn.ts +58 -0
- package/src/indexer/classify.ts +96 -0
- package/src/indexer/context.ts +340 -0
- package/src/indexer/continuity.ts +322 -0
- package/src/indexer/detectchanges.ts +94 -0
- package/src/indexer/discovery.ts +176 -0
- package/src/indexer/externaldeps.ts +243 -0
- package/src/indexer/freshness.ts +166 -0
- package/src/indexer/git.ts +453 -0
- package/src/indexer/index.ts +1092 -0
- package/src/indexer/modules.ts +358 -0
- package/src/indexer/preflight.ts +548 -0
- package/src/indexer/protoScanner.ts +147 -0
- package/src/indexer/risk.ts +304 -0
- package/src/indexer/serviceHostScanner.ts +92 -0
- package/src/indexer/serviceLinks.ts +543 -0
- package/src/indexer/shapehash.ts +370 -0
- package/src/indexer/skeleton.ts +169 -0
- package/src/indexer/symbolhistory.ts +172 -0
- package/src/indexer/watcher.ts +206 -0
- package/src/mcp/server.ts +1659 -0
- package/src/parser/index.ts +37 -0
- package/src/parser/languages/cpp.ts +361 -0
- package/src/parser/languages/csharp.ts +235 -0
- package/src/parser/languages/go.ts +259 -0
- package/src/parser/languages/java.ts +382 -0
- package/src/parser/languages/python.ts +370 -0
- package/src/parser/languages/rust.ts +164 -0
- package/src/parser/languages/typescript.ts +1435 -0
- package/src/parser/parserContext.ts +392 -0
- package/src/parser/walker.ts +306 -0
- package/src/parser/worker.ts +181 -0
- package/src/parser/workerpool.ts +448 -0
- package/src/scip/format.ts +83 -0
- package/src/scip/import.ts +216 -0
- package/src/types.ts +457 -0
- package/tests/benchmark-service-links.ts +244 -0
- package/tests/bug-regressions.ts +626 -0
- package/tests/filters.ts +264 -0
- package/tests/fixtures/Counter.tsx +38 -0
- package/tests/fixtures/caller.ts +7 -0
- package/tests/fixtures/collisions.ts +23 -0
- package/tests/fixtures/local_helper.ts +5 -0
- package/tests/fixtures/overloads.java +17 -0
- package/tests/fixtures/remote_helper.ts +4 -0
- package/tests/fixtures/sample.c +15 -0
- package/tests/fixtures/sample.cpp +47 -0
- package/tests/fixtures/sample.cs +62 -0
- package/tests/fixtures/sample.go +68 -0
- package/tests/fixtures/sample.h +30 -0
- package/tests/fixtures/sample.java +85 -0
- package/tests/fixtures/sample.py +46 -0
- package/tests/fixtures/sample.rs +78 -0
- package/tests/fixtures/sample.ts +76 -0
- package/tests/fixtures-service/HttpClients.cs +30 -0
- package/tests/fixtures-service/HttpClients.java +24 -0
- package/tests/fixtures-service/billing.ts +15 -0
- package/tests/fixtures-service/docker-compose.yml +15 -0
- package/tests/fixtures-service/gateway.ts +10 -0
- package/tests/fixtures-service/get_user.ts +11 -0
- package/tests/fixtures-service/graphql_client.ts +63 -0
- package/tests/fixtures-service/graphql_server.ts +30 -0
- package/tests/fixtures-service/grpc_client.go +30 -0
- package/tests/fixtures-service/http_clients.go +23 -0
- package/tests/fixtures-service/http_clients.py +38 -0
- package/tests/fixtures-service/http_clients.ts +49 -0
- package/tests/fixtures-service/k8s/payment-service.yaml +22 -0
- package/tests/fixtures-service/k8s_calls.ts +20 -0
- package/tests/fixtures-service/messaging.ts +87 -0
- package/tests/fixtures-service/trpc_client.ts +39 -0
- package/tests/fixtures-service/trpc_server.ts +39 -0
- package/tests/fixtures-service/user_service.proto +33 -0
- package/tests/fixtures-trackcd/Cargo.toml +11 -0
- package/tests/fixtures-trackcd/SpringController.java +36 -0
- package/tests/fixtures-trackcd/auth_service.ts +19 -0
- package/tests/fixtures-trackcd/complex_module.py +50 -0
- package/tests/fixtures-trackcd/express_app.js +30 -0
- package/tests/fixtures-trackcd/fastapi_app.py +49 -0
- package/tests/fixtures-trackcd/fastify_object_routes.js +32 -0
- package/tests/fixtures-trackcd/go.mod +8 -0
- package/tests/fixtures-trackcd/package.json +15 -0
- package/tests/fixtures-trackcd/requirements.txt +4 -0
- package/tests/fixtures-trackcd/tests/auth_service.test.ts +13 -0
- package/tests/fixtures-tracke/auth/AuthService.ts +23 -0
- package/tests/fixtures-tracke/auth/crypto.ts +7 -0
- package/tests/fixtures-tracke/billing/Billing.ts +20 -0
- package/tests/fixtures-tracke/billing/Invoice.ts +10 -0
- package/tests/fixtures-tracke/billing/server.ts +17 -0
- package/tests/fixtures-tracke/package.json +7 -0
- package/tests/fixtures-tracke/tests/auth.test.ts +23 -0
- package/tests/fixtures-tracke/tests/billing.test.ts +14 -0
- package/tests/fixtures-trackf/package.json +5 -0
- package/tests/fixtures-trackf/src/auth.ts +26 -0
- package/tests/fixtures-trackf/src/handlers.ts +35 -0
- package/tests/fixtures-tracki/billing/routes.ts +12 -0
- package/tests/fixtures-tracki/gateway/client.ts +13 -0
- package/tests/git-features.ts +267 -0
- package/tests/init.ts +141 -0
- package/tests/mcp-jit.ts +130 -0
- package/tests/mcp-smoke.ts +191 -0
- package/tests/mcp-trackcd.ts +169 -0
- package/tests/mcp-tracke.ts +229 -0
- package/tests/mcp-trackf.ts +330 -0
- package/tests/mcp-trackg.ts +219 -0
- package/tests/mcp-tracki.ts +174 -0
- package/tests/mcp-watcher.ts +126 -0
- package/tests/optspec.ts +194 -0
- package/tests/parallel-index.ts +333 -0
- package/tests/parallel-read.ts +125 -0
- package/tests/parallel-recovery.ts +241 -0
- package/tests/perf-callers.ts +145 -0
- package/tests/query-parity.ts +184 -0
- package/tests/query-perf.ts +55 -0
- package/tests/scale-parallel-parity.ts +225 -0
- package/tests/scale-test.ts +523 -0
- package/tests/smoke.ts +396 -0
- package/tests/trackcd.ts +325 -0
- package/tests/tracke-collisions.ts +255 -0
- package/tests/tracke.ts +314 -0
- package/tests/trackf-bugs.ts +406 -0
- package/tests/trackf.ts +390 -0
- package/tests/trackg.ts +1372 -0
- package/tests/tracki-boundaries.ts +202 -0
- package/tests/tracki-continuity.ts +253 -0
- package/tests/tracki-contract-diff.ts +249 -0
- package/tests/tracki-external-bundles.ts +341 -0
- package/tests/tracki-preflight.ts +251 -0
- package/tests/verify-roles.ts +51 -0
- package/tests/worker-parity.ts +286 -0
- package/tests/worker-pool.ts +262 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seer Scale Test — exercises every large codebase under `Large Codebases/`,
|
|
3
|
+
* runs each one twice (fresh + cached), and writes a robust report.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists: after every foundational change (e.g. a future
|
|
6
|
+
* worker-thread parser, a new edge type, a schema migration) we need a
|
|
7
|
+
* one-shot way to confirm:
|
|
8
|
+
* 1. Every codebase still indexes without exceptions.
|
|
9
|
+
* 2. Counts are deterministic — fresh and cached runs produce identical
|
|
10
|
+
* symbol/edge/resolved totals. Drift here = a real bug.
|
|
11
|
+
* 3. The cache really rehydrates everything (reused == fresh-indexed).
|
|
12
|
+
* 4. No WASM aborts triggered (resets stay at 0).
|
|
13
|
+
* 5. Parse-error rate stays low.
|
|
14
|
+
* 6. PageRank produces nonzero variance.
|
|
15
|
+
* 7. Indexing speed isn't regressed (ms/file is logged for comparison).
|
|
16
|
+
*
|
|
17
|
+
* Outputs:
|
|
18
|
+
* tests/outputs/run-<ISO>.json — full machine-readable report
|
|
19
|
+
* tests/outputs/latest.md — human-readable summary (overwritten)
|
|
20
|
+
* tests/outputs/dbs/<name>.db — per-codebase SQLite index (kept for
|
|
21
|
+
* follow-up queries; safe to delete)
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* npm run scale-test # run all codebases
|
|
25
|
+
* npm run scale-test -- --only helix,react # subset
|
|
26
|
+
* npm run scale-test -- --skip unreal # exclude
|
|
27
|
+
* npm run scale-test -- --pass 3 # do 3 fresh passes (catches
|
|
28
|
+
* run-to-run non-determinism)
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import path from 'path';
|
|
32
|
+
import fs from 'fs';
|
|
33
|
+
import { Store } from '../src/db/store';
|
|
34
|
+
import { Indexer, IndexResult } from '../src/indexer/index';
|
|
35
|
+
|
|
36
|
+
interface CodebaseSpec {
|
|
37
|
+
name: string;
|
|
38
|
+
relativePath: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const CODEBASES: CodebaseSpec[] = [
|
|
42
|
+
{ name: 'helix', relativePath: 'Large Codebases/helix-master' },
|
|
43
|
+
{ name: 'client-go', relativePath: 'Large Codebases/client-go-master' },
|
|
44
|
+
{ name: 'react', relativePath: 'Large Codebases/react-main' },
|
|
45
|
+
{ name: 'godot', relativePath: 'Large Codebases/godot-master' },
|
|
46
|
+
{ name: 'linux', relativePath: 'Large Codebases/linux-master' },
|
|
47
|
+
{ name: 'typescript', relativePath: 'Large Codebases/TypeScript-main' },
|
|
48
|
+
{ name: 'unreal', relativePath: 'Large Codebases/UnrealEngine-release' },
|
|
49
|
+
// Self-validation: the codebase that surfaced the original dogfood gaps
|
|
50
|
+
// (.c handling, vendored pollution, parallel-read DB locks). Including it
|
|
51
|
+
// here so future regressions show up in the standard run.
|
|
52
|
+
{ name: 'cbm', relativePath: 'Large Codebases/codebase-memory-mcp-main' },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
interface TopSymbol {
|
|
56
|
+
name: string;
|
|
57
|
+
kind: string;
|
|
58
|
+
pagerank: number;
|
|
59
|
+
filePath: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface RunReport {
|
|
63
|
+
name: string;
|
|
64
|
+
status: 'ok' | 'warn' | 'error';
|
|
65
|
+
errors: string[];
|
|
66
|
+
warnings: string[];
|
|
67
|
+
|
|
68
|
+
// File-discovery breakdown
|
|
69
|
+
filesDiscovered: number;
|
|
70
|
+
filesIndexed: number;
|
|
71
|
+
filesReused: number; // from cached run — should equal filesIndexed
|
|
72
|
+
filesParseError: number;
|
|
73
|
+
filesSkipped: number;
|
|
74
|
+
filesSkippedTooLarge: number;
|
|
75
|
+
parseErrorPct: number;
|
|
76
|
+
|
|
77
|
+
// Graph totals (from fresh run; cached must match)
|
|
78
|
+
symbols: number;
|
|
79
|
+
edges: number;
|
|
80
|
+
resolvedEdges: number;
|
|
81
|
+
resolutionPct: number;
|
|
82
|
+
|
|
83
|
+
// Resolution breakdown (fresh run only)
|
|
84
|
+
sameFile: number;
|
|
85
|
+
imported: number;
|
|
86
|
+
global: number;
|
|
87
|
+
resolvedImports: number;
|
|
88
|
+
|
|
89
|
+
// Health markers
|
|
90
|
+
wasmResets: number;
|
|
91
|
+
languages: Record<string, number>;
|
|
92
|
+
|
|
93
|
+
// Timing
|
|
94
|
+
freshMs: number;
|
|
95
|
+
cachedMs: number;
|
|
96
|
+
msPerFileFresh: number;
|
|
97
|
+
cacheSpeedup: number; // freshMs / cachedMs
|
|
98
|
+
dbSizeMb: number;
|
|
99
|
+
|
|
100
|
+
// Determinism sample
|
|
101
|
+
topSymbols: TopSymbol[];
|
|
102
|
+
pagerankVariance: number; // stddev of top 20 PageRank values
|
|
103
|
+
|
|
104
|
+
// Determinism cross-checks (filled at compare time)
|
|
105
|
+
cachedSymbols: number;
|
|
106
|
+
cachedEdges: number;
|
|
107
|
+
cachedResolvedEdges: number;
|
|
108
|
+
|
|
109
|
+
// Lazy PageRank verification: the fresh run should ALWAYS recompute, the
|
|
110
|
+
// cached run should NEVER recompute (graph is identical, ranks are valid).
|
|
111
|
+
freshPagerankRecomputed: boolean;
|
|
112
|
+
cachedPagerankRecomputed: boolean;
|
|
113
|
+
|
|
114
|
+
// Schema + classification snapshots so a regression in either surfaces here
|
|
115
|
+
// alongside the determinism checks. `roles` is the file count broken down
|
|
116
|
+
// by classification; `schemaVersion` is what the DB pinned.
|
|
117
|
+
schemaVersion: number;
|
|
118
|
+
roles: { project: number; vendor: number; generated: number; test: number };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Run one codebase ──────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
async function runOne(spec: CodebaseSpec, repoRoot: string, dbPath: string): Promise<RunReport> {
|
|
124
|
+
// Clean DB + WAL sidecars so the fresh run is genuinely fresh
|
|
125
|
+
for (const ext of ['', '-wal', '-shm']) {
|
|
126
|
+
const p = dbPath + ext;
|
|
127
|
+
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── Fresh ──
|
|
131
|
+
const store1 = new Store(dbPath);
|
|
132
|
+
const indexer1 = new Indexer(store1);
|
|
133
|
+
const fresh = await indexer1.indexDirectory(repoRoot, { quiet: true });
|
|
134
|
+
const topAfterFresh = store1.getTopSymbols(20);
|
|
135
|
+
store1.close();
|
|
136
|
+
|
|
137
|
+
// ── Cached ──
|
|
138
|
+
const store2 = new Store(dbPath);
|
|
139
|
+
const indexer2 = new Indexer(store2);
|
|
140
|
+
const cached = await indexer2.indexDirectory(repoRoot, { quiet: true });
|
|
141
|
+
const topAfterCached = store2.getTopSymbols(20);
|
|
142
|
+
const stats = store2.getStats();
|
|
143
|
+
const schemaInfo = store2.schemaInfo();
|
|
144
|
+
const roles = store2.getRoleCounts();
|
|
145
|
+
store2.close();
|
|
146
|
+
|
|
147
|
+
const errors: string[] = [];
|
|
148
|
+
const warnings: string[] = [];
|
|
149
|
+
|
|
150
|
+
// ── Determinism: fresh vs cached must match ──
|
|
151
|
+
if (fresh.symbols !== cached.symbols) {
|
|
152
|
+
errors.push(`symbol drift: fresh=${fresh.symbols} cached=${cached.symbols}`);
|
|
153
|
+
}
|
|
154
|
+
if (fresh.edges !== cached.edges) {
|
|
155
|
+
errors.push(`edge drift: fresh=${fresh.edges} cached=${cached.edges}`);
|
|
156
|
+
}
|
|
157
|
+
// The post-pass resolved count is reported as the running DB total in
|
|
158
|
+
// IndexResult.resolvedEdges (see indexer/index.ts comment). It must be
|
|
159
|
+
// identical between fresh and cached because cached re-runs the same
|
|
160
|
+
// resolve passes against unchanged data.
|
|
161
|
+
if (fresh.resolvedEdges !== cached.resolvedEdges) {
|
|
162
|
+
errors.push(`resolved-edge drift: fresh=${fresh.resolvedEdges} cached=${cached.resolvedEdges}`);
|
|
163
|
+
}
|
|
164
|
+
// Cache rehydration: every file we indexed fresh should be reused next time.
|
|
165
|
+
if (cached.filesReusedFromCache !== fresh.filesIndexed) {
|
|
166
|
+
errors.push(
|
|
167
|
+
`cache reuse mismatch: fresh indexed ${fresh.filesIndexed} but cached reused ${cached.filesReusedFromCache}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
// Cached run must not re-resolve anything.
|
|
171
|
+
const cachedDelta =
|
|
172
|
+
cached.edgeResolution.sameFile + cached.edgeResolution.imported + cached.edgeResolution.global;
|
|
173
|
+
if (cachedDelta !== 0) {
|
|
174
|
+
errors.push(
|
|
175
|
+
`cached run resolved ${cachedDelta} new edges (should be 0 — implies edges left NULL after fresh)`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Lazy PageRank invariants: fresh must recompute, cached must skip.
|
|
180
|
+
// If cached recomputed despite no graph changes, the skip predicate is buggy.
|
|
181
|
+
// If fresh skipped, something is *really* wrong (we just inserted all symbols).
|
|
182
|
+
if (!fresh.pagerankRecomputed && fresh.symbols > 0) {
|
|
183
|
+
errors.push('fresh run skipped PageRank despite inserting symbols');
|
|
184
|
+
}
|
|
185
|
+
if (cached.pagerankRecomputed && cached.symbols > 0 && cachedDelta === 0) {
|
|
186
|
+
errors.push('cached run recomputed PageRank despite zero graph changes (lazy-skip predicate missed a case)');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Top-symbol determinism check: top-20 PageRanks should be byte-identical
|
|
190
|
+
// across fresh/cached. If they drift, our PageRank or ordering is unstable.
|
|
191
|
+
if (topAfterFresh.length !== topAfterCached.length) {
|
|
192
|
+
errors.push(`top-symbol count drifted: fresh=${topAfterFresh.length} cached=${topAfterCached.length}`);
|
|
193
|
+
} else {
|
|
194
|
+
for (let i = 0; i < topAfterFresh.length; i++) {
|
|
195
|
+
if (topAfterFresh[i].id !== topAfterCached[i].id) {
|
|
196
|
+
errors.push(`top-symbol[${i}] drifted: fresh-id=${topAfterFresh[i].id} cached-id=${topAfterCached[i].id}`);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// PageRank sanity: variance across top 20 should be nonzero if we have any
|
|
203
|
+
// edges. (Helix passes have shown ~5e-3 variance; flat-zero would mean
|
|
204
|
+
// PageRank failed to propagate.)
|
|
205
|
+
const ranks = topAfterFresh.map(s => s.pagerank);
|
|
206
|
+
const mean = ranks.reduce((a, b) => a + b, 0) / Math.max(ranks.length, 1);
|
|
207
|
+
const variance = ranks.length > 0
|
|
208
|
+
? ranks.reduce((a, b) => a + (b - mean) ** 2, 0) / ranks.length
|
|
209
|
+
: 0;
|
|
210
|
+
if (fresh.edges > 0 && variance === 0) {
|
|
211
|
+
errors.push('PageRank produced uniform values despite nonzero edges');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ── Schema version: must match the current build ──
|
|
215
|
+
if (schemaInfo.dbVersion !== schemaInfo.buildVersion) {
|
|
216
|
+
errors.push(`schema_version mismatch: db=${schemaInfo.dbVersion} build=${schemaInfo.buildVersion}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ── Track A regression: default top-symbol must not be a vendored file ──
|
|
220
|
+
// The reason this is enforced is that the very first dogfood-gap reported
|
|
221
|
+
// by indexing Codebase-Memory was that vendored grammar parsers were
|
|
222
|
+
// dominating the PageRank top-20. After classification + project-first
|
|
223
|
+
// defaults, the top symbol on any of these codebases should be project-owned.
|
|
224
|
+
if (topAfterFresh.length > 0) {
|
|
225
|
+
const top = topAfterFresh[0];
|
|
226
|
+
const norm = top.filePath.replace(/\\/g, '/');
|
|
227
|
+
const looksVendored =
|
|
228
|
+
/(^|\/)(vendor|vendored|thirdparty|third_party|external|node_modules)\//i.test(norm);
|
|
229
|
+
if (looksVendored) {
|
|
230
|
+
errors.push(`top symbol is in vendored path: ${top.filePath}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ── Warnings (informational, don't fail the run) ──
|
|
235
|
+
if (fresh.wasmResets > 0) {
|
|
236
|
+
warnings.push(`${fresh.wasmResets} WASM runtime reset(s) during fresh — recovered, but worth investigating`);
|
|
237
|
+
}
|
|
238
|
+
const totalParsed = fresh.filesIndexed + fresh.filesParseError;
|
|
239
|
+
const parseErrorPct = totalParsed > 0 ? (fresh.filesParseError / totalParsed) * 100 : 0;
|
|
240
|
+
if (parseErrorPct > 10) {
|
|
241
|
+
warnings.push(`parse error rate ${parseErrorPct.toFixed(1)}% > 10% — language extractor coverage might be slipping`);
|
|
242
|
+
}
|
|
243
|
+
if (fresh.edges > 0 && fresh.resolvedEdges / fresh.edges < 0.3) {
|
|
244
|
+
warnings.push(
|
|
245
|
+
`low resolution rate ${((fresh.resolvedEdges / fresh.edges) * 100).toFixed(1)}% — expected for languages without import resolution, but flag here for visibility`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ── DB size ──
|
|
250
|
+
let dbBytes = 0;
|
|
251
|
+
try { dbBytes = fs.statSync(dbPath).size; } catch { /* deleted? */ }
|
|
252
|
+
|
|
253
|
+
const status: 'ok' | 'warn' | 'error' =
|
|
254
|
+
errors.length > 0 ? 'error' : warnings.length > 0 ? 'warn' : 'ok';
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
name: spec.name,
|
|
258
|
+
status,
|
|
259
|
+
errors,
|
|
260
|
+
warnings,
|
|
261
|
+
filesDiscovered: fresh.filesDiscovered,
|
|
262
|
+
filesIndexed: fresh.filesIndexed,
|
|
263
|
+
filesReused: cached.filesReusedFromCache,
|
|
264
|
+
filesParseError: fresh.filesParseError,
|
|
265
|
+
filesSkipped: fresh.filesSkipped,
|
|
266
|
+
filesSkippedTooLarge: fresh.filesSkippedTooLarge,
|
|
267
|
+
parseErrorPct,
|
|
268
|
+
symbols: fresh.symbols,
|
|
269
|
+
edges: fresh.edges,
|
|
270
|
+
resolvedEdges: fresh.resolvedEdges,
|
|
271
|
+
resolutionPct: fresh.edges > 0 ? (fresh.resolvedEdges / fresh.edges) * 100 : 0,
|
|
272
|
+
sameFile: fresh.edgeResolution.sameFile,
|
|
273
|
+
imported: fresh.edgeResolution.imported,
|
|
274
|
+
global: fresh.edgeResolution.global,
|
|
275
|
+
resolvedImports: fresh.resolvedImports,
|
|
276
|
+
wasmResets: fresh.wasmResets,
|
|
277
|
+
languages: stats.languages,
|
|
278
|
+
freshMs: fresh.elapsedMs,
|
|
279
|
+
cachedMs: cached.elapsedMs,
|
|
280
|
+
msPerFileFresh: fresh.filesIndexed > 0 ? fresh.elapsedMs / fresh.filesIndexed : 0,
|
|
281
|
+
cacheSpeedup: cached.elapsedMs > 0 ? fresh.elapsedMs / cached.elapsedMs : 0,
|
|
282
|
+
dbSizeMb: dbBytes / (1024 * 1024),
|
|
283
|
+
topSymbols: topAfterFresh.slice(0, 5).map(s => ({
|
|
284
|
+
name: s.name,
|
|
285
|
+
kind: s.kind,
|
|
286
|
+
pagerank: s.pagerank,
|
|
287
|
+
filePath: path.relative(repoRoot, s.filePath).replace(/\\/g, '/'),
|
|
288
|
+
})),
|
|
289
|
+
pagerankVariance: variance,
|
|
290
|
+
cachedSymbols: cached.symbols,
|
|
291
|
+
cachedEdges: cached.edges,
|
|
292
|
+
cachedResolvedEdges: cached.resolvedEdges,
|
|
293
|
+
freshPagerankRecomputed: fresh.pagerankRecomputed,
|
|
294
|
+
cachedPagerankRecomputed: cached.pagerankRecomputed,
|
|
295
|
+
schemaVersion: schemaInfo.dbVersion,
|
|
296
|
+
roles,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ── Output formatters ────────────────────────────────────────────────────────
|
|
301
|
+
|
|
302
|
+
function fmtTime(ms: number): string {
|
|
303
|
+
if (ms < 1000) return `${ms.toFixed(0)}ms`;
|
|
304
|
+
if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
|
|
305
|
+
const min = Math.floor(ms / 60_000);
|
|
306
|
+
const sec = ((ms - min * 60_000) / 1000).toFixed(0);
|
|
307
|
+
return `${min}m${sec.padStart(2, '0')}s`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function printSummary(reports: RunReport[]): void {
|
|
311
|
+
const rows: Array<[string, string, string, string, string, string, string, string, string, string]> = [
|
|
312
|
+
['Name', 'Files', 'Symbols', 'Edges', 'Resolved%', 'Fresh', 'Cached', 'Speedup', 'ms/file', 'Status'],
|
|
313
|
+
];
|
|
314
|
+
for (const r of reports) {
|
|
315
|
+
rows.push([
|
|
316
|
+
r.name,
|
|
317
|
+
r.filesIndexed.toLocaleString(),
|
|
318
|
+
r.symbols.toLocaleString(),
|
|
319
|
+
r.edges.toLocaleString(),
|
|
320
|
+
r.resolutionPct.toFixed(1) + '%',
|
|
321
|
+
fmtTime(r.freshMs),
|
|
322
|
+
fmtTime(r.cachedMs),
|
|
323
|
+
r.cacheSpeedup.toFixed(1) + 'x',
|
|
324
|
+
r.msPerFileFresh.toFixed(1),
|
|
325
|
+
r.status === 'ok' ? 'OK' : r.status === 'warn' ? 'WARN' : 'ERROR',
|
|
326
|
+
]);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const widths = rows[0].map((_, i) => Math.max(...rows.map(r => r[i].length)) + 2);
|
|
330
|
+
for (let rIdx = 0; rIdx < rows.length; rIdx++) {
|
|
331
|
+
const cells = rows[rIdx].map((cell, i) => cell.padEnd(widths[i]));
|
|
332
|
+
console.log(' ' + cells.join(''));
|
|
333
|
+
if (rIdx === 0) {
|
|
334
|
+
console.log(' ' + widths.map(w => '─'.repeat(w - 1)).join(' '));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function generateMarkdown(reports: RunReport[]): string {
|
|
340
|
+
const ts = new Date().toISOString();
|
|
341
|
+
let md = `# Seer Scale-Test Results\n\n`;
|
|
342
|
+
md += `- Generated: ${ts}\n`;
|
|
343
|
+
md += `- Node: ${process.version}\n`;
|
|
344
|
+
md += `- Platform: ${process.platform}\n\n`;
|
|
345
|
+
|
|
346
|
+
md += `## Summary\n\n`;
|
|
347
|
+
md += `| Codebase | Files | Symbols | Edges | Resolved | Fresh | Cached | Speedup | ms/file | DB | Status |\n`;
|
|
348
|
+
md += `|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|:---:|\n`;
|
|
349
|
+
for (const r of reports) {
|
|
350
|
+
md += `| ${r.name} | ${r.filesIndexed.toLocaleString()} | ${r.symbols.toLocaleString()} | ${r.edges.toLocaleString()} | ${r.resolutionPct.toFixed(1)}% | ${fmtTime(r.freshMs)} | ${fmtTime(r.cachedMs)} | ${r.cacheSpeedup.toFixed(1)}× | ${r.msPerFileFresh.toFixed(2)} | ${r.dbSizeMb.toFixed(1)} MB | ${r.status === 'ok' ? '✓' : r.status === 'warn' ? '⚠' : '✗'} |\n`;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Issues / warnings
|
|
354
|
+
const withErrors = reports.filter(r => r.errors.length > 0);
|
|
355
|
+
const withWarns = reports.filter(r => r.warnings.length > 0);
|
|
356
|
+
if (withErrors.length > 0) {
|
|
357
|
+
md += `\n## Errors\n\nReal correctness or determinism failures. These must be fixed.\n\n`;
|
|
358
|
+
for (const r of withErrors) {
|
|
359
|
+
md += `### ${r.name}\n`;
|
|
360
|
+
for (const e of r.errors) md += `- ${e}\n`;
|
|
361
|
+
md += `\n`;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (withWarns.length > 0) {
|
|
365
|
+
md += `\n## Warnings\n\nLikely explainable but worth a look.\n\n`;
|
|
366
|
+
for (const r of withWarns) {
|
|
367
|
+
md += `### ${r.name}\n`;
|
|
368
|
+
for (const w of r.warnings) md += `- ${w}\n`;
|
|
369
|
+
md += `\n`;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Per-codebase detail
|
|
374
|
+
md += `\n## Detail\n\n`;
|
|
375
|
+
for (const r of reports) {
|
|
376
|
+
md += `### ${r.name}\n\n`;
|
|
377
|
+
md += `**Discovery & parsing**\n`;
|
|
378
|
+
md += `- Files: ${r.filesDiscovered.toLocaleString()} discovered → ${r.filesIndexed.toLocaleString()} indexed`;
|
|
379
|
+
md += `, ${r.filesParseError} parse errors (${r.parseErrorPct.toFixed(2)}%)`;
|
|
380
|
+
md += `, ${r.filesSkipped} skipped (no language match)`;
|
|
381
|
+
if (r.filesSkippedTooLarge > 0) md += `, ${r.filesSkippedTooLarge} skipped (size cap)`;
|
|
382
|
+
md += `\n`;
|
|
383
|
+
md += `- Languages: ${Object.entries(r.languages).sort((a, b) => b[1] - a[1]).map(([l, n]) => `${l}=${n.toLocaleString()}`).join(', ')}\n`;
|
|
384
|
+
md += `- WASM runtime resets during fresh: ${r.wasmResets}\n`;
|
|
385
|
+
md += `\n**Graph**\n`;
|
|
386
|
+
md += `- Symbols: ${r.symbols.toLocaleString()}\n`;
|
|
387
|
+
md += `- Edges: ${r.edges.toLocaleString()} (${r.resolvedEdges.toLocaleString()} resolved = ${r.resolutionPct.toFixed(1)}%)\n`;
|
|
388
|
+
md += `- Resolution: same-file ${r.sameFile.toLocaleString()}, imported ${r.imported.toLocaleString()}, global ${r.global.toLocaleString()}\n`;
|
|
389
|
+
md += `- Imports resolved to files: ${r.resolvedImports.toLocaleString()}\n`;
|
|
390
|
+
md += `- PageRank top-20 variance: ${r.pagerankVariance.toExponential(2)}\n`;
|
|
391
|
+
md += `\n**Cache & determinism**\n`;
|
|
392
|
+
md += `- Cached run reused: ${r.filesReused.toLocaleString()} / ${r.filesIndexed.toLocaleString()} (must match)\n`;
|
|
393
|
+
md += `- Cached symbols/edges/resolved: ${r.cachedSymbols.toLocaleString()} / ${r.cachedEdges.toLocaleString()} / ${r.cachedResolvedEdges.toLocaleString()} (must match fresh)\n`;
|
|
394
|
+
md += `- PageRank: fresh recomputed=${r.freshPagerankRecomputed}, cached recomputed=${r.cachedPagerankRecomputed} (cached should be \`false\` when no files changed)\n`;
|
|
395
|
+
md += `\n**Timing**\n`;
|
|
396
|
+
md += `- Fresh: ${fmtTime(r.freshMs)} (${r.msPerFileFresh.toFixed(2)} ms/file)\n`;
|
|
397
|
+
md += `- Cached: ${fmtTime(r.cachedMs)} (${r.cacheSpeedup.toFixed(1)}× cache speedup)\n`;
|
|
398
|
+
md += `- DB size: ${r.dbSizeMb.toFixed(1)} MB\n`;
|
|
399
|
+
md += `\n**Top 5 symbols by PageRank**\n`;
|
|
400
|
+
for (const s of r.topSymbols) {
|
|
401
|
+
md += `- \`${s.name}\` (${s.kind}) — ${s.pagerank.toFixed(5)} — ${s.filePath}\n`;
|
|
402
|
+
}
|
|
403
|
+
md += `\n`;
|
|
404
|
+
}
|
|
405
|
+
return md;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
409
|
+
|
|
410
|
+
async function main(): Promise<void> {
|
|
411
|
+
const repoRoot = path.resolve(__dirname, '..');
|
|
412
|
+
const args = process.argv.slice(2);
|
|
413
|
+
let onlySet: Set<string> | null = null;
|
|
414
|
+
let skipSet = new Set<string>();
|
|
415
|
+
for (let i = 0; i < args.length; i++) {
|
|
416
|
+
if (args[i] === '--only' && args[i + 1]) {
|
|
417
|
+
onlySet = new Set(args[i + 1].split(','));
|
|
418
|
+
i++;
|
|
419
|
+
} else if (args[i] === '--skip' && args[i + 1]) {
|
|
420
|
+
skipSet = new Set(args[i + 1].split(','));
|
|
421
|
+
i++;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const toRun = CODEBASES.filter(c => {
|
|
426
|
+
if (skipSet.has(c.name)) return false;
|
|
427
|
+
if (onlySet && !onlySet.has(c.name)) return false;
|
|
428
|
+
return true;
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const outDir = path.join(__dirname, 'outputs');
|
|
432
|
+
const dbDir = path.join(outDir, 'dbs');
|
|
433
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
434
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
435
|
+
|
|
436
|
+
console.log(`\nSeer Scale Test`);
|
|
437
|
+
console.log(`─────────────────`);
|
|
438
|
+
console.log(`Running ${toRun.length} codebase(s)\n`);
|
|
439
|
+
|
|
440
|
+
const reports: RunReport[] = [];
|
|
441
|
+
const overallStart = Date.now();
|
|
442
|
+
for (const spec of toRun) {
|
|
443
|
+
const repoPath = path.join(repoRoot, spec.relativePath);
|
|
444
|
+
if (!fs.existsSync(repoPath)) {
|
|
445
|
+
console.log(` ⤬ ${spec.name}: skipped (path not found: ${spec.relativePath})`);
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
const dbPath = path.join(dbDir, `${spec.name}.db`);
|
|
449
|
+
process.stdout.write(` ▸ ${spec.name}: indexing... `);
|
|
450
|
+
const start = Date.now();
|
|
451
|
+
try {
|
|
452
|
+
const r = await runOne(spec, repoPath, dbPath);
|
|
453
|
+
reports.push(r);
|
|
454
|
+
const totalSec = ((Date.now() - start) / 1000).toFixed(1);
|
|
455
|
+
const mark = r.status === 'ok' ? '✓' : r.status === 'warn' ? '⚠' : '✗';
|
|
456
|
+
process.stdout.write(`\r ${mark} ${spec.name.padEnd(11)} ${r.filesIndexed.toLocaleString().padStart(7)} files, ${r.symbols.toLocaleString().padStart(9)} symbols, ${r.edges.toLocaleString().padStart(9)} edges fresh=${fmtTime(r.freshMs).padStart(7)} cached=${fmtTime(r.cachedMs).padStart(6)} (run ${totalSec}s)\n`);
|
|
457
|
+
for (const e of r.errors) console.log(` ✗ ERROR: ${e}`);
|
|
458
|
+
for (const w of r.warnings) console.log(` ⚠ WARN: ${w}`);
|
|
459
|
+
} catch (err) {
|
|
460
|
+
process.stdout.write(`\n ✗ EXCEPTION: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
461
|
+
reports.push({
|
|
462
|
+
name: spec.name,
|
|
463
|
+
status: 'error',
|
|
464
|
+
errors: [`exception during indexing: ${err instanceof Error ? err.message : String(err)}`],
|
|
465
|
+
warnings: [],
|
|
466
|
+
filesDiscovered: 0, filesIndexed: 0, filesReused: 0, filesParseError: 0,
|
|
467
|
+
filesSkipped: 0, filesSkippedTooLarge: 0, parseErrorPct: 0,
|
|
468
|
+
symbols: 0, edges: 0, resolvedEdges: 0, resolutionPct: 0,
|
|
469
|
+
sameFile: 0, imported: 0, global: 0, resolvedImports: 0,
|
|
470
|
+
wasmResets: 0, languages: {},
|
|
471
|
+
freshMs: 0, cachedMs: 0, msPerFileFresh: 0, cacheSpeedup: 0,
|
|
472
|
+
dbSizeMb: 0, topSymbols: [], pagerankVariance: 0,
|
|
473
|
+
cachedSymbols: 0, cachedEdges: 0, cachedResolvedEdges: 0,
|
|
474
|
+
freshPagerankRecomputed: false, cachedPagerankRecomputed: false,
|
|
475
|
+
schemaVersion: 0,
|
|
476
|
+
roles: { project: 0, vendor: 0, generated: 0, test: 0 },
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const overallSec = ((Date.now() - overallStart) / 1000).toFixed(1);
|
|
481
|
+
|
|
482
|
+
// ── Save outputs ──
|
|
483
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
484
|
+
const jsonPath = path.join(outDir, `run-${ts}.json`);
|
|
485
|
+
const latestJson = path.join(outDir, 'latest.json');
|
|
486
|
+
const mdPath = path.join(outDir, 'latest.md');
|
|
487
|
+
|
|
488
|
+
const payload = {
|
|
489
|
+
timestamp: new Date().toISOString(),
|
|
490
|
+
node: process.version,
|
|
491
|
+
platform: process.platform,
|
|
492
|
+
totalDurationSec: Number(overallSec),
|
|
493
|
+
reports,
|
|
494
|
+
};
|
|
495
|
+
fs.writeFileSync(jsonPath, JSON.stringify(payload, null, 2));
|
|
496
|
+
fs.writeFileSync(latestJson, JSON.stringify(payload, null, 2));
|
|
497
|
+
fs.writeFileSync(mdPath, generateMarkdown(reports));
|
|
498
|
+
|
|
499
|
+
console.log(`\n Summary table:\n`);
|
|
500
|
+
printSummary(reports);
|
|
501
|
+
|
|
502
|
+
console.log(`\n Saved:`);
|
|
503
|
+
console.log(` ${path.relative(repoRoot, jsonPath)}`);
|
|
504
|
+
console.log(` ${path.relative(repoRoot, latestJson)}`);
|
|
505
|
+
console.log(` ${path.relative(repoRoot, mdPath)}`);
|
|
506
|
+
console.log(`\n Total wall time: ${overallSec}s\n`);
|
|
507
|
+
|
|
508
|
+
const failures = reports.filter(r => r.status === 'error');
|
|
509
|
+
const warns = reports.filter(r => r.status === 'warn');
|
|
510
|
+
if (failures.length > 0) {
|
|
511
|
+
console.error(` ✗ ${failures.length} codebase(s) reported errors.`);
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
if (warns.length > 0) {
|
|
515
|
+
console.log(` ⚠ ${warns.length} codebase(s) reported warnings (non-fatal).`);
|
|
516
|
+
}
|
|
517
|
+
console.log(` ✓ All ${reports.length} codebases passed consistency checks.\n`);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
main().catch(err => {
|
|
521
|
+
console.error('Scale test crashed:', err);
|
|
522
|
+
process.exit(1);
|
|
523
|
+
});
|