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
118 changes: 93 additions & 25 deletions .github/workflows/bench-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ on:

permissions:
contents: read
pull-requests: write

env:
ZIG_VERSION: 0.17.0-dev.813+2153f8143
ZIG_SHA256: b0d46ffc4587b9e8dd0b524ee5bc4da1e67f28bba55e7c534cec64af2f2d7a74
LEGACY_ZIG_VERSION: 0.16.0
LEGACY_ZIG_SHA256: 70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00
PAIRED_5829_BASE_SHA: dd36e9431925014ee2bed80346669a4afee7e42e
PAIRED_5829_SHA: 24e89c70d4f9cdaf5542a78d83d1890a42b4a046

jobs:
bench:
Expand All @@ -21,6 +22,9 @@ jobs:
with:
fetch-depth: 0

- name: Test paired benchmark comparator
run: python3 -m unittest scripts/test_compare_bench_paired.py

- name: Install pinned Zig toolchains
run: |
set -euo pipefail
Expand All @@ -47,12 +51,14 @@ jobs:
run: python3 scripts/run-bench-json.py bench-head.json

- name: Benchmark base with its declared compiler
id: base_bench
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail
git fetch origin "$BASE_REF" --depth=1
git worktree add ../codedb-base FETCH_HEAD
git cat-file -e "$BASE_SHA^{commit}" 2>/dev/null || git fetch origin "$BASE_SHA" --depth=1
git worktree add ../codedb-base "$BASE_SHA"
test "$(git -C ../codedb-base rev-parse HEAD)" = "$BASE_SHA"
cd ../codedb-base

base_zig_version=$(sed -n 's/.*\.minimum_zig_version = "\([^"]*\)".*/\1/p' build.zig.zon)
Expand All @@ -69,9 +75,84 @@ jobs:
;;
esac
test "$("$base_zig_dir/zig" version)" = "$base_zig_version"
echo "zig_version=$base_zig_version" >> "$GITHUB_OUTPUT"
echo "zig_dir=$base_zig_dir" >> "$GITHUB_OUTPUT"
PATH="$base_zig_dir:$PATH" \
python3 "$GITHUB_WORKSPACE/scripts/run-bench-json.py" "$GITHUB_WORKSPACE/bench-base.json"

- name: Paired counterbalanced benchmark with parity gate
env:
EVENT_BASE_SHA: ${{ github.event.pull_request.base.sha }}
BASE_ZIG_VERSION: ${{ steps.base_bench.outputs.zig_version }}
BASE_ZIG_DIR: ${{ steps.base_bench.outputs.zig_dir }}
PAIRS: 5
run: |
set -euo pipefail
if [[ "$BASE_ZIG_VERSION" != "$ZIG_VERSION" ]]; then
echo "Paired parity requires a pinned same-compiler baseline harness; refusing to skip the gate." >&2
exit 1
fi

paired_base="../codedb-base"
if ! grep -q corpus_hash "$paired_base/src/bench.zig"; then
if [[ "$EVENT_BASE_SHA" != "$PAIRED_5829_BASE_SHA" ]]; then
echo "No pinned parity harness exists for base $EVENT_BASE_SHA" >&2
exit 1
fi
git cat-file -e "$PAIRED_5829_SHA^{commit}" 2>/dev/null || {
git fetch origin bench/v0.2.5829-paired-baseline --depth=1
test "$(git rev-parse FETCH_HEAD)" = "$PAIRED_5829_SHA"
}
git merge-base --is-ancestor "$EVENT_BASE_SHA" "$PAIRED_5829_SHA"
test "$(git diff --name-only "$EVENT_BASE_SHA..$PAIRED_5829_SHA")" = $'src/bench.zig\nsrc/mcp.zig'
git worktree add ../codedb-paired-base "$PAIRED_5829_SHA"
paired_base="../codedb-paired-base"
fi

mkdir -p bench-paired
corpus_source=$(realpath ../codedb-base)
head_source_sha=$(git rev-parse HEAD)
head_tree_sha=$(git rev-parse 'HEAD^{tree}')
git worktree add ../codedb-paired-head "$head_source_sha"
head_cwd=$(realpath ../codedb-paired-head)
run_sample() {
side="$1"
pair="$2"
order="$3"
sequence="$4"
if [[ "$side" == base ]]; then
cwd="$paired_base"
zig_dir="$BASE_ZIG_DIR"
production_sha="$EVENT_BASE_SHA"
else
cwd="$head_cwd"
zig_dir="$GITHUB_WORKSPACE/zig-x86_64-linux-${ZIG_VERSION}"
production_sha="$head_source_sha"
fi
(
cd "$cwd"
PATH="$zig_dir:$PATH" python3 "$head_cwd/scripts/run-bench-json.py" \
--bench-side "$side" --bench-pair "$pair" --bench-order "$order" --bench-sequence "$sequence" \
--production-source-sha "$production_sha" --corpus-source-sha "$EVENT_BASE_SHA" \
"$GITHUB_WORKSPACE/bench-paired/$side-$(printf '%02d' "$pair").json" \
--corpus-source "$corpus_source"
)
}

for ((pair = 1; pair <= PAIRS; pair++)); do
if (( pair % 2 == 1 )); then
run_sample base "$pair" AB 1
run_sample head "$pair" AB 2
else
run_sample head "$pair" BA 1
run_sample base "$pair" BA 2
fi
done
python3 "$head_cwd/scripts/compare-bench-paired.py" bench-paired --require-parity --require-provenance \
--allow-parity-skip codedb_snapshot --allow-parity-skip codedb_status \
--expected-head-sha "$head_source_sha" --expected-head-tree-sha "$head_tree_sha" \
--threshold-pct 10 --min-abs-ns 50000 --markdown-out bench-paired-report.md

- name: Compare
run: |
python3 scripts/compare-bench.py bench-base.json bench-head.json --threshold-pct 10 --markdown-out bench-report.md
Expand All @@ -84,25 +165,12 @@ jobs:
bench-base.json
bench-head.json
bench-report.md
bench-paired/
bench-paired-report.md

- name: Comment PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('bench-report.md', 'utf8');
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
} catch (err) {
if (err.status === 403) {
core.warning('Skipping benchmark PR comment because this run token cannot write comments.');
} else {
throw err;
}
}
- name: Publish benchmark summary
if: always()
run: |
report=bench-paired-report.md
[[ -f "$report" ]] || report=bench-report.md
[[ -f "$report" ]] && cat "$report" >> "$GITHUB_STEP_SUMMARY"
2 changes: 1 addition & 1 deletion .github/workflows/pr-base-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
const msg = [
"👋 Thanks for the contribution! Quick heads-up: this repo lands changes on the **current `release/*` branch**, not `main`.",
"",
"Please retarget this PR via **Edit → base branch** to the active release branch (currently `release/0.2.5825`).",
"Please retarget this PR via **Edit → base branch** to the active `release/*` branch shown in the repository branch list.",
"",
"_(Automated hint — reply here if you need a hand.)_",
].join("\n");
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/release-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ jobs:
zig_sha256: b0d46ffc4587b9e8dd0b524ee5bc4da1e67f28bba55e7c534cec64af2f2d7a74
zig_target: aarch64-linux
asset_name: codedb-linux-arm64
- runner: ubuntu-24.04
zig_host: x86_64-linux
zig_sha256: b0d46ffc4587b9e8dd0b524ee5bc4da1e67f28bba55e7c534cec64af2f2d7a74
zig_target: x86_64-windows
asset_name: codedb-windows-x86_64.exe
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.release.tag_name }}
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
Expand Down Expand Up @@ -106,7 +111,10 @@ jobs:
else
zig build -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig_target }}
fi
cp zig-out/bin/codedb "${{ matrix.asset_name }}"
binary=zig-out/bin/codedb
[[ -f "$binary" ]] || binary=zig-out/bin/codedb.exe
test -f "$binary"
cp "$binary" "${{ matrix.asset_name }}"

- name: Upload build artifact
uses: actions/upload-artifact@v7
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
# Changelog


## 0.2.5830 - 2026-07-12

The first performance batch for this release accelerates steady-state MCP and
core read-only tools while preserving response and retrieval parity. Measured
MCP round trips improve from **2.16x to 99.11x** across tree, outline, symbol,
read, find, word, search, and bundle workloads. Large synthetic handler cases
improve **12.8x-109.7x** for outlines, deep reads, trees, fuzzy file lookup, and
word output; exact symbols improve **22.4x** through direct hash-index lookup.

The implementation adds bounded, mutation-generation-validated render/score
caches, cached content hashes and line offsets, offset-based context body
extraction, a compact JSON-RPC framing fast path, and rolling generic trigram
construction. Ranking, parser, path-security, telemetry, and MCP schema behavior
are unchanged. Baseline/candidate MCP responses were byte-identical after ID
normalization, and the full suite, WASM build, and MCP E2E (20/20) pass.

Detailed methodology, per-tool tables, memory bounds, limitations, and follow-up
targets are in [`docs/performance-0.2.5830.md`](docs/performance-0.2.5830.md).
The release gate ran 20 counterbalanced AB/BA pairs against the immutable
0.2.5829 source plus a pinned harness-only parity backport. Every parity-enabled
tool matched across every measured iteration after normalizing only response
duration, and no benchmark crossed the 10% plus 50us regression threshold. The
runner enforces a shared corpus fingerprint, full JSON-RPC response hashes,
commit/tree/compiler/corpus/order provenance, paired medians, and bootstrap
intervals; single-run minima are diagnostic only.


## 0.2.5829 - 2026-07-11

The release toolchain moves to pinned Zig `0.17.0-dev.813+2153f8143` without
Expand Down
31 changes: 25 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,35 @@ If you changed benchmarks:
Benchmark-related PRs must say:

- what layer is being measured
- driver-only
- HTTP-only
- end-to-end HTTP+DB
- handler/driver-only
- in-process MCP/HTTP
- end-to-end transport and storage
- whether caches are on or off
- whether numbers are cold-start or warmed steady-state
- number of runs
- whether values are single-run or median
- number of paired runs and their counterbalanced execution order
- paired median and dispersion/confidence interval
- exact machine or CI environment
- whether base and head used the same compiler (source attribution) or each
revision's declared compiler (release-outcome comparison)

Do not publish cached results as uncached DB performance.
Performance claims must use output/hit parity on an identical corpus. Commit the
candidate so the runner can attest a clean source tree, then run:

```bash
CODEDB_BENCH_PAIRS=10 scripts/bench-ab.sh <base-ref>
```

The runner gives both revisions the same fixed corpus, alternates `base → head`
and `head → base`, validates source/compiler/corpus/order provenance, requires
full normalized JSON-RPC response parity for parity-enabled tools, and reports
paired medians with a deterministic bootstrap interval. Increase to 20 or more
pairs for release claims. A parity exemption must be explicit in the benchmark
case, justified by genuinely nondeterministic output, and included in the
comparator's explicit allowlist.

Single-run minima may be shown as diagnostics, but they are not acceptable
performance evidence and must not drive an acceptance claim. Do not publish
cached results as uncached performance.

## Review Expectations

Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.{
.name = .codedb2,
.fingerprint = 0x6e18d96ca2a31757,
.version = "0.2.5829",
.version = "0.2.5830",
.minimum_zig_version = "0.17.0-dev.813+2153f8143",
.dependencies = .{
.nanoregex = .{
Expand Down
40 changes: 40 additions & 0 deletions docs/bench-0.2.5830-paired-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 0.2.5830 paired release benchmark

- Date: 2026-07-12
- Machine: Apple M3 Ultra Mac Studio, 28 cores, 256 GB, macOS 26.5.1
- Production baseline: `dd36e9431925014ee2bed80346669a4afee7e42e` (`v0.2.5829`)
- Pinned parity-harness baseline: `24e89c70d4f9cdaf5542a78d83d1890a42b4a046`
- Candidate: `bc72bfca4f4dcb9316f2f00f0ca78ab18c4e3c74` (tree `2832e31eb08f7695518ad0d6c23967beb268d16b`)
- Compiler: Zig `0.17.0-dev.813+2153f8143`, executable SHA-256 `08abf236d78c05b8520431fbca99903ff98653b2f1cd1c3665a7f8c91247421c`
- Corpus source tree: `e705e2623b28d2456eb9d4934817b79f4de35216`
- Corpus: fixed 21-file set copied from `dd36e94`, plus generated `src/bench_target.zig`; fingerprint `13647708728832762745`
- Order: 20 counterbalanced AB/BA pairs, verified from per-sample pair/order/sequence metadata
- Regression gate: paired median >10% and >50,000 ns
- Parity gate: duration-normalized full JSON-RPC response hash rolled across every measured iteration
- Raw evidence archive: `bench-0.2.5830-paired-samples.tar.gz`, SHA-256 `104edc6875a9d121d2e5a4c1e69c12735f2c60128e48ae384aa8c6cfb950bc24` (attached to the GitHub Release)

Corpus parity: **PASS**

Source/compiler/order provenance: **PASS**

| Tool | Base median | Head median | Paired delta | Abs delta | 95% CI | Head wins | Output parity | Status |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- |
| `codedb_bundle` | 16980 | 12230 | -27.73% | -4790 | [-29.25%, -25.72%] | 20/20 | PASS | OK |
| `codedb_changes` | 2825 | 2830 | +1.77% | +50 | [-1.76%, +3.37%] | 7/20 (1 tie) | PASS | OK |
| `codedb_context` | 110990 | 97730 | -11.89% | -13230 | [-12.55%, -11.13%] | 20/20 | PASS | OK |
| `codedb_deps` | 60 | 60 | +0.00% | +0 | [+0.00%, +20.00%] | 5/20 (6 ties) | PASS | OK |
| `codedb_edit` | 51700 | 50900 | -2.04% | -1100 | [-5.09%, +2.52%] | 12/20 | PASS | OK |
| `codedb_find` | 600 | 590 | -3.27% | -20 | [-7.43%, +3.39%] | 11/20 (1 tie) | PASS | OK |
| `codedb_hot` | 4560 | 3750 | -17.81% | -820 | [-19.48%, -16.70%] | 20/20 | PASS | OK |
| `codedb_outline` | 5280 | 2115 | -59.79% | -3170 | [-60.91%, -59.05%] | 20/20 | PASS | OK |
| `codedb_read` | 14400 | 13630 | -4.81% | -685 | [-6.70%, -3.40%] | 18/20 | PASS | OK |
| `codedb_search` | 9770 | 9885 | +1.60% | +155 | [-1.02%, +2.76%] | 8/20 (1 tie) | PASS | OK |
| `codedb_snapshot` | 31225 | 31200 | -0.24% | -75 | [-0.88%, +0.24%] | 12/20 (1 tie) | SKIP | OK |
| `codedb_status` | 1815 | 1815 | -0.22% | -5 | [-2.69%, +1.91%] | 10/20 (2 ties) | SKIP | OK |
| `codedb_symbol` | 11780 | 2155 | -81.72% | -9625 | [-82.12%, -81.31%] | 20/20 | PASS | OK |
| `codedb_tree` | 5445 | 1780 | -67.60% | -3700 | [-68.49%, -66.73%] | 20/20 | PASS | OK |
| `codedb_word` | 3035 | 1915 | -37.16% | -1135 | [-38.46%, -35.19%] | 20/20 | PASS | OK |

`codedb_snapshot` is exempt because output embeds its temporary destination path. `codedb_status` is exempt because it intentionally exposes cache counters. Both exemptions are declared in the benchmark cases, must match between revisions, and are accepted only through the comparator's explicit tool allowlist.

No single-run minima were used. The confidence intervals are deterministic bootstrap intervals for the paired percentage median.
Loading