Skip to content

Commit 6efdbf0

Browse files
authored
Merge branch 'main' into feat/1071-clojure-rust-extractor
2 parents d9e3c9b + f6c0289 commit 6efdbf0

11 files changed

Lines changed: 1562 additions & 348 deletions

File tree

.github/workflows/ci.yml

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,162 @@ jobs:
295295
- name: Check compilation
296296
run: cargo check --workspace
297297

298+
# ── Pre-publish benchmark gate ──
299+
#
300+
# Mirrors the gate in publish.yml so every PR catches regressions before
301+
# merge instead of at release time. Measures the PR-built native artifact
302+
# against the local source as version "dev", appends to the benchmark
303+
# history files (in-job only — never committed from CI), and runs the
304+
# regression guard against the most recent release baseline.
305+
#
306+
# Long-running but parallel with the rest of CI, so it does not extend
307+
# the critical path for fast-failing checks (lint/typecheck/test).
308+
pre-publish-benchmark:
309+
name: Pre-publish benchmark gate
310+
# Only run on PRs — push-to-main re-runs the same benchmarks the merged
311+
# PR already gated on, doubling CI minutes per landed change with no new
312+
# signal. Mirrors the `if: github.event_name != 'push'` skip in
313+
# publish.yml's equivalent gate.
314+
if: github.event_name == 'pull_request'
315+
needs: native-host-build
316+
runs-on: ubuntu-latest
317+
env:
318+
# Surface why detectNoChanges returns false on each fast-skip pre-flight
319+
# so we can pinpoint the cause of the ~2s incremental-rebuild regression
320+
# observed in CI but not locally (#1066). Remove once root cause is fixed.
321+
CODEGRAPH_FAST_SKIP_DIAG: "1"
322+
323+
steps:
324+
- uses: actions/checkout@v6
325+
with:
326+
fetch-depth: 0
327+
328+
- uses: actions/setup-node@v6
329+
with:
330+
node-version: "22"
331+
cache: "npm"
332+
333+
- name: Setup Python (for resolution benchmark + tracer validation)
334+
uses: actions/setup-python@v6
335+
with:
336+
python-version: "3.12"
337+
338+
- name: Setup Go (for resolution benchmark + tracer validation)
339+
uses: actions/setup-go@v6
340+
with:
341+
go-version: "stable"
342+
cache: false
343+
344+
- name: Download PR-built native addon
345+
uses: actions/download-artifact@v8
346+
with:
347+
name: native-host-ubuntu-latest
348+
path: crates/codegraph-core/
349+
350+
- name: Install dependencies
351+
timeout-minutes: 20
352+
shell: bash
353+
run: |
354+
for attempt in 1 2 3; do
355+
npm install && break
356+
if [ "$attempt" -lt 3 ]; then
357+
echo "::warning::npm install attempt $attempt failed, retrying in 15s..."
358+
sleep 15
359+
else
360+
echo "::error::npm install failed after 3 attempts"
361+
exit 1
362+
fi
363+
done
364+
365+
- name: Install native addon over published binary
366+
run: node scripts/ci-install-native.mjs
367+
368+
# Build dist/ so benchmarks load the same compiled JS that ships to npm.
369+
# Historical baselines (v3.9.6 and earlier) were measured against dist/
370+
# via the post-publish --npm path; running against src/ with --strip-types
371+
# changes the load path and introduces version-to-version noise unrelated
372+
# to the code under test (#1055).
373+
- name: Build TypeScript
374+
run: npm run build
375+
376+
- name: Run build benchmark
377+
timeout-minutes: 20
378+
run: |
379+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
380+
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/benchmark.ts --version dev --dist > benchmark-result.json
381+
382+
- name: Run resolution benchmark
383+
timeout-minutes: 20
384+
run: |
385+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
386+
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/resolution-benchmark.ts --version dev --dist > resolution-result.json
387+
388+
- name: Gate on resolution thresholds
389+
timeout-minutes: 30
390+
run: npx vitest run tests/benchmarks/resolution/resolution-benchmark.test.ts --reporter=verbose
391+
392+
- name: Run tracer validation (same-file edge recall)
393+
timeout-minutes: 10
394+
run: npx vitest run tests/benchmarks/resolution/tracer/tracer-validation.test.ts --reporter=verbose
395+
396+
- name: Merge resolution into build result
397+
run: |
398+
node -e "
399+
const fs = require('fs');
400+
const build = JSON.parse(fs.readFileSync('benchmark-result.json', 'utf8'));
401+
const resolution = JSON.parse(fs.readFileSync('resolution-result.json', 'utf8'));
402+
build.resolution = resolution;
403+
fs.writeFileSync('benchmark-result.json', JSON.stringify(build, null, 2));
404+
"
405+
406+
- name: Run query benchmark
407+
timeout-minutes: 20
408+
run: |
409+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
410+
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/query-benchmark.ts --version dev --dist > query-benchmark-result.json
411+
412+
- name: Run incremental benchmark
413+
timeout-minutes: 20
414+
run: |
415+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
416+
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/incremental-benchmark.ts --version dev --dist > incremental-benchmark-result.json
417+
418+
- name: Update build report
419+
run: |
420+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
421+
node $STRIP_FLAG scripts/update-benchmark-report.ts benchmark-result.json
422+
423+
- name: Update query report
424+
run: |
425+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
426+
node $STRIP_FLAG scripts/update-query-report.ts query-benchmark-result.json
427+
428+
- name: Update incremental report
429+
run: |
430+
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
431+
node $STRIP_FLAG scripts/update-incremental-report.ts incremental-benchmark-result.json
432+
433+
- name: Regression guard
434+
env:
435+
RUN_REGRESSION_GUARD: "1"
436+
run: npm run test:regression-guard
437+
438+
# Always upload raw JSON so a failed regression guard is debuggable
439+
# without re-running the full benchmark suite locally.
440+
- name: Upload benchmark JSON results
441+
if: always()
442+
uses: actions/upload-artifact@v7
443+
with:
444+
name: benchmark-results-json
445+
path: |
446+
benchmark-result.json
447+
query-benchmark-result.json
448+
incremental-benchmark-result.json
449+
if-no-files-found: warn
450+
298451
ci-pipeline:
299452
if: always()
300-
needs: [lint, native-host-build, test, typecheck, audit, verify-imports, rust-check, parity]
453+
needs: [lint, native-host-build, test, typecheck, audit, verify-imports, rust-check, parity, pre-publish-benchmark]
301454
runs-on: ubuntu-latest
302455
name: CI Testing Pipeline
303456
steps:

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -617,19 +617,19 @@ Codegraph also extracts symbols from common callback patterns: Commander `.comma
617617

618618
Self-measured on every release via CI ([build benchmarks](generated/benchmarks/BUILD-BENCHMARKS.md) | [embedding benchmarks](generated/benchmarks/EMBEDDING-BENCHMARKS.md) | [query benchmarks](generated/benchmarks/QUERY-BENCHMARKS.md) | [incremental benchmarks](generated/benchmarks/INCREMENTAL-BENCHMARKS.md) | [resolution precision/recall](tests/benchmarks/resolution/)):
619619

620-
*Last updated: v3.9.6 (2026-04-30)*
620+
*Last updated: v3.10.0 (2026-05-11)*
621621

622622
| Metric | Native | WASM |
623623
|---|---|---|
624-
| Build speed | **5.8 ms/file** | **28.3 ms/file** |
625-
| Query time | **47ms** | **43ms** |
626-
| No-op rebuild | **13ms** | **134ms** |
627-
| 1-file rebuild | **78ms** | **68ms** |
628-
| Query: fn-deps | **3.4ms** | **2.4ms** |
629-
| Query: path | **3.1ms** | **2.2ms** |
630-
| ~50,000 files (est.) | **~290.0s build** | **~1415.0s build** |
631-
| Resolution precision | **90.5%** ||
632-
| Resolution recall | **42.0%** ||
624+
| Build speed | **4.8 ms/file** | **18.1 ms/file** |
625+
| Query time | **50ms** | **38ms** |
626+
| No-op rebuild | **24ms** | **15ms** |
627+
| 1-file rebuild | **67ms** | **51ms** |
628+
| Query: fn-deps | **2.2ms** | **2.1ms** |
629+
| Query: path | **2.3ms** | **2.1ms** |
630+
| ~50,000 files (est.) | **~240.0s build** | **~905.0s build** |
631+
| Resolution precision | **90.7%** ||
632+
| Resolution recall | **42.9%** ||
633633

634634
Metrics are normalized per file for cross-version comparability. Times above are for a full initial build — incremental rebuilds only re-parse changed files.
635635

@@ -652,7 +652,7 @@ Metrics are normalized per file for cross-version comparability. Times above are
652652
| gleam | 100.0% | 26.7% | 4 | 0 | 11 | 15 ||
653653
| go | 100.0% | 69.2% | 9 | 0 | 4 | 13 | 13/14 |
654654
| groovy | 100.0% | 7.7% | 1 | 0 | 12 | 13 ||
655-
| haskell | 0.0% | 0.0% | 0 | 0 | 12 | 12 ||
655+
| haskell | 100.0% | 33.3% | 4 | 0 | 8 | 12 ||
656656
| hcl | 0.0% | 0.0% | 0 | 0 | 2 | 2 ||
657657
| java | 100.0% | 52.9% | 9 | 0 | 8 | 17 ||
658658
| julia | 0.0% | 0.0% | 0 | 0 | 15 | 15 ||
@@ -676,10 +676,10 @@ Metrics are normalized per file for cross-version comparability. Times above are
676676

677677
| Mode | Resolved | Expected | Recall |
678678
|------|--------:|---------:|-------:|
679-
| module-function | 13 | 106 | 12.3% |
679+
| module-function | 16 | 106 | 15.1% |
680680
| receiver-typed | 17 | 104 | 16.3% |
681681
| static | 66 | 93 | 71.0% |
682-
| same-file | 47 | 86 | 54.7% |
682+
| same-file | 48 | 86 | 55.8% |
683683
| interface-dispatched | 7 | 12 | 58.3% |
684684
| class-inheritance | 0 | 4 | 0.0% |
685685
| trait-dispatch | 0 | 2 | 0.0% |

crates/codegraph-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "codegraph-core"
3-
version = "3.9.6"
3+
version = "3.10.0"
44
edition = "2021"
55
license = "Apache-2.0"
66

generated/DEPENDENCIES.json

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
{
2-
"version": "3.9.6",
2+
"version": "3.10.0",
33
"name": "@optave/codegraph",
44
"problems": [
5-
"extraneous: @emnapi/runtime@1.8.1 /home/runner/work/ops-codegraph-tool/ops-codegraph-tool/node_modules/@emnapi/runtime",
5+
"extraneous: @emnapi/runtime@1.10.0 /home/runner/work/ops-codegraph-tool/ops-codegraph-tool/node_modules/@emnapi/runtime",
66
"extraneous: tslib@2.8.1 /home/runner/work/ops-codegraph-tool/ops-codegraph-tool/node_modules/tslib"
77
],
88
"dependencies": {
99
"@emnapi/runtime": {
10-
"version": "1.8.1",
11-
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
10+
"version": "1.10.0",
11+
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
1212
"overridden": false,
1313
"extraneous": true,
1414
"problems": [
15-
"extraneous: @emnapi/runtime@1.8.1 /home/runner/work/ops-codegraph-tool/ops-codegraph-tool/node_modules/@emnapi/runtime"
15+
"extraneous: @emnapi/runtime@1.10.0 /home/runner/work/ops-codegraph-tool/ops-codegraph-tool/node_modules/@emnapi/runtime"
1616
],
1717
"dependencies": {
1818
"tslib": {
@@ -27,12 +27,12 @@
2727
"dependencies": {
2828
"@cfworker/json-schema": {},
2929
"@hono/node-server": {
30-
"version": "1.19.11",
31-
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz",
30+
"version": "1.19.14",
31+
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz",
3232
"overridden": false,
3333
"dependencies": {
3434
"hono": {
35-
"version": "4.12.9"
35+
"version": "4.12.18"
3636
}
3737
}
3838
},
@@ -57,8 +57,8 @@
5757
"overridden": false
5858
},
5959
"fast-uri": {
60-
"version": "3.1.0",
61-
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
60+
"version": "3.1.2",
61+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
6262
"overridden": false
6363
},
6464
"json-schema-traverse": {
@@ -147,16 +147,16 @@
147147
}
148148
},
149149
"express-rate-limit": {
150-
"version": "8.3.1",
151-
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.1.tgz",
150+
"version": "8.5.1",
151+
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz",
152152
"overridden": false,
153153
"dependencies": {
154154
"express": {
155155
"version": "5.2.1"
156156
},
157157
"ip-address": {
158-
"version": "10.1.0",
159-
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
158+
"version": "10.2.0",
159+
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
160160
"overridden": false
161161
}
162162
}
@@ -684,8 +684,8 @@
684684
}
685685
},
686686
"hono": {
687-
"version": "4.12.9",
688-
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.9.tgz",
687+
"version": "4.12.18",
688+
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
689689
"overridden": false
690690
},
691691
"jose": {
@@ -756,8 +756,8 @@
756756
"@optave/codegraph-darwin-x64": {},
757757
"@optave/codegraph-linux-arm64-gnu": {},
758758
"@optave/codegraph-linux-x64-gnu": {
759-
"version": "3.9.6",
760-
"resolved": "https://registry.npmjs.org/@optave/codegraph-linux-x64-gnu/-/codegraph-linux-x64-gnu-3.9.6.tgz",
759+
"version": "3.10.0",
760+
"resolved": "https://registry.npmjs.org/@optave/codegraph-linux-x64-gnu/-/codegraph-linux-x64-gnu-3.10.0.tgz",
761761
"overridden": false
762762
},
763763
"@optave/codegraph-linux-x64-musl": {},

0 commit comments

Comments
 (0)