Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/perf-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ jobs:
MAX_INDEX_SECONDS: '8'
MIN_NODES: '40'
MAX_PHANTOM_DROP_RATIO: '50'
# Memory ceiling for `codeiq enrich` on fixture-multi-lang. Local
# baseline post-Phase-A+B+C of the 2026-05-13 OOM-fix plan: ~108 MB
# peak RSS. 300 MB ceiling gives ~2.7x headroom — tight enough to
# surface real regressions, loose enough to absorb GC / scheduler
# variance on CI runners. Bump only if a deliberate enrich-mem
# regression is documented in a PR.
MAX_ENRICH_RSS_KB: '307200'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
Expand Down Expand Up @@ -108,3 +115,33 @@ jobs:
fi
fi
exit $fail
# Enrich memory regression gate. Locks in the gains from the
# 2026-05-13 OOM-fix plan (Phases A-C). Pre-Phase-A on the same
# fixture peaked at ~600 MB; current main lives at ~108 MB peak.
# If a refactor pushes peak past MAX_ENRICH_RSS_KB, fail the PR.
- name: Enrich memory gate
run: |
set -euo pipefail
# Run enrich against the already-indexed fixture; /usr/bin/time
# -v reports peak RSS.
/usr/bin/time -v /tmp/codeiq enrich /tmp/fm-perf \
> /tmp/perf-enrich.log 2> /tmp/perf-enrich.time
RSS=$(awk -F': ' '/Maximum resident set size/ {print $2}' /tmp/perf-enrich.time)
RSS=${RSS:-0}
ELAPSED=$(awk -F': ' '/Elapsed \(wall clock\)/ {print $2}' /tmp/perf-enrich.time)

{
echo ""
echo "## codeiq enrich memory gate"
echo ""
echo "| metric | value | budget |"
echo "|---|---:|---:|"
echo "| peak RSS (KB) | $RSS | <= $MAX_ENRICH_RSS_KB |"
echo "| wall-clock | $ELAPSED | — |"
} >> "$GITHUB_STEP_SUMMARY"
cat /tmp/perf-enrich.log >> "$GITHUB_STEP_SUMMARY"

if [ "$RSS" -gt "$MAX_ENRICH_RSS_KB" ]; then
echo "::error::enrich peak RSS ${RSS} KB exceeds budget ${MAX_ENRICH_RSS_KB} KB"
exit 1
fi
28 changes: 28 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,34 @@ Release pipeline:
System.Security.Cryptography.X509Certificates;`. Use a STRICT
keyword list (high-signal markers only — not path extensions) in
any cross-language regex pre-screen.
- **Enrich memory ceiling (Phase A+B+C OOM-fix plan, 2026-05-13).**
Pre-fix `codeiq enrich` peaked at 3.8 GB on the airflow polyglot
target (9k Python files) and OOM-killed at exit 137 on ~/projects/-
scale (49k files). Three landed fixes brought peak RSS down to:
- **fixture-multi-lang (22 files): ~108 MB** (CI-gated via
perf-gate workflow at 300 MB ceiling)
- **airflow (9,151 files): 1.27 GB** (1× /usr/bin/time -v on
16 GB CI host)
- **~/projects/ (49,076 files): 3.12 GB** (well under the 4 GiB
acceptance bar from the plan)

The three fixes:
1. `intelligence/extractor/enricher.go` parses tree-sitter trees
once per file (was per-node, ~13× over-parse on Python).
2. `intelligence/extractor/enricher.go` bounds the per-file
goroutine pool to `2 * GOMAXPROCS` (was unbounded — 7k+ goroutines
held live trees + file content strings).
3. `graph.Open()` caps Kuzu `BufferPoolSize` to 2 GiB by default
(was 80% of system RAM via `kuzu.DefaultSystemConfig()`).

Tunable knobs on `codeiq enrich`:
- `--memprofile=<path>` writes a Go heap profile (analyze with
`go tool pprof -top -inuse_space ...`).
- `--max-buffer-pool=N` overrides the 2 GiB Kuzu cap.
- `--copy-threads=N` overrides `MaxNumThreads` (default `min(4,
GOMAXPROCS)`).

Plan + research history: `docs/superpowers/plans/2026-05-13-enrich-oom-fix.md`.

### Release / signing

Expand Down
Loading