Skip to content

feat: add performance benchmark suite for search, propose, bundle, an…#116

Merged
plind-junior merged 1 commit into
vouchdev:testfrom
Tet-9:feat/99-performance-benchmarks
Jun 9, 2026
Merged

feat: add performance benchmark suite for search, propose, bundle, an…#116
plind-junior merged 1 commit into
vouchdev:testfrom
Tet-9:feat/99-performance-benchmarks

Conversation

@Tet-9

@Tet-9 Tet-9 commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

benchmarks/ had a KB generator (gen_kb.py) and a detailed README describing exactly what to measure, but no timing harness and no published numbers. This adds the missing harness.

Changes

conftest.py — session-scoped fixtures that generate synthetic KBs once per session via gen_kb.py at 1k, 10k, and 100k claim sizes, keeping benchmark startup cost low across all modules.

bench_search.py — FTS5 and substring fallback search latency at 1k and 10k claim sizes. Captures the performance curve as the KB grows, which is the number that matters most for search.

bench_propose.py — propose_claim() write latency. This sits directly in the agent hot loop. Any regression past ~50ms on a warm SSD is a signal that something needs attention.

bench_bundle.py — export, import, and verify round-trips at 1k and 10k claims. Bundle imports gate cross-team KB sharing so a 10k-claim bundle should land in seconds, not minutes.

bench_index_rebuild.py — vouch index rebuild time at 1k and 10k claims. Measures the full reset-and-reindex path.

Usage

Run with:
pytest benchmarks/ --benchmark-only --benchmark-json=bench.json

Benchmarks live outside tests/ so a regular pytest run never pulls them in. Requires pytest-benchmark.

Closes #99

Summary by CodeRabbit

  • Tests

    • Added performance benchmark suite measuring search latency, proposal write throughput, bundle export/import/validation, and index rebuild time across multiple dataset sizes. Run with pytest benchmarks/ --benchmark-only.
  • Documentation

    • Updated CHANGELOG with new benchmark suite details and usage instructions.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 88482447-cdc9-4d0f-b32f-51c78c15121e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces a complete pytest-based performance benchmark suite that measures search latency, proposal write throughput, bundle operations, and index rebuild time across knowledge bases of 1k, 10k, and 100k claims. The infrastructure includes shared KB fixture generation and four independent benchmark modules that are now executable via pytest benchmarks/ --benchmark-only.

Changes

Performance Benchmark Suite

Layer / File(s) Summary
Benchmark Framework & KB Fixtures
benchmarks/conftest.py
Pytest configuration validates pytest-benchmark availability. Session-scoped fixtures generate prebuilt knowledge base artifacts at 1k, 10k, and 100k claim sizes using subprocess invocation of the existing KB generator.
Search Latency Benchmarks
benchmarks/bench_search.py
Store helper and module-scoped fixtures rebuild indexes. Four benchmark tests measure FTS5 full-text search and substring fallback search with fixed queries and limit=10 on 1k and 10k knowledge bases.
Proposal Write Throughput
benchmarks/bench_propose.py
Fresh temporary KBStore and evidence source fixtures support a single benchmark that repeatedly calls propose_claim with incrementing claim text, measuring write latency while asserting non-null results.
Index Rebuild Benchmarks
benchmarks/bench_index_rebuild.py
Two benchmark tests invoke rebuild_index on KBStore instances constructed from 1k and 10k KB fixtures, measuring index rebuild latency at each scale.
Bundle Operations Benchmarks
benchmarks/bench_bundle.py
Module-scoped fixtures pre-export bundle archives for 1k and 10k knowledge bases. Six benchmark tests measure fresh bundle export, bundle import with overwrite conflict handling, and bundle validation across both scales.
Benchmark Suite Documentation
CHANGELOG.md
Unreleased section entry documents the benchmark suite, specifies covered measurement areas (search, proposals, bundles, index rebuild), and provides the command to run benchmarks.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Hop through the benchmarks with care and delight,
From search to proposals, all measured just right,
A thousand, ten thousand, one hundred thousand claims,
Performance metrics now lighting the flames!
The frameworks are set, the fixtures are true,
A benchmark suite built just for you!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a performance benchmark suite covering search, propose, and bundle operations.
Linked Issues check ✅ Passed The PR implements all acceptance criteria from issue #99: measures search latency, proposal throughput, and bundle import time across KB sizes (1k, 10k); includes index rebuild benchmarks; provides single-command execution via pytest.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the performance benchmark suite: conftest.py fixtures, benchmark modules for search/propose/bundle/index-rebuild, and CHANGELOG.md documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
benchmarks/bench_search.py (1)

19-47: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

100k search benchmark coverage is missing vs the stated acceptance criteria.

This file only benchmarks 1k/10k, but the objective requires search latency across 1k, 10k, and 100k claims. Add a store_100k fixture and corresponding FTS5/substring tests so results are complete and comparable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarks/bench_search.py` around lines 19 - 47, Add a 100k fixture and
corresponding benchmark tests: create a pytest.fixture named
store_100k(scope="module") that returns _store(kb_100k), then add two tests
mirroring the existing ones — test_search_fts5_100k(benchmark, store_100k) that
calls benchmark(index_db.search, store_100k.kb_dir, "auth uses JWT", limit=10)
and test_search_substring_100k(benchmark, store_100k) that calls
benchmark(store_100k.search_substring, "auth", limit=10) so FTS5 and substring
fallbacks are measured for 100k like the 1k/10k cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmarks/bench_bundle.py`:
- Around line 37-60: The import benchmarks currently reuse a single dest_kb
(KBStore.init(tmp_path)) so iterations measure overwrite behavior; update
test_bundle_import_1k and test_bundle_import_10k to initialize a fresh KBStore
for each benchmark iteration by wrapping bundle.import_apply in a small callable
that calls KBStore.init(...) inside the benchmark invocation (so each run
imports into a fresh KB instead of overwriting), and add a new
test_bundle_import_100k that mirrors the 1k/10k tests but uses
exported_bundle_100k and the same per-iteration KBStore initialization pattern.

In `@benchmarks/bench_propose.py`:
- Around line 21-35: The benchmark test_propose_claim_latency mutates shared
state by inserting new claims into fresh_store on each iteration, making latency
results non-comparable; change it so each measured invocation sees an equivalent
store state: create a size-parameterized seed (e.g., sizes like 1k/10k/100k),
pre-seed a template store for each size, and in _propose use a fresh copy/clone
of that template store (or re-initialize fresh_store) so propose_claim always
runs against the same initial KB; keep source_id and proposed_by the same but
ensure benchmark(_propose) operates on an isolated per-iteration store so
metrics are stable and follow the required throughput sweep.

In `@benchmarks/conftest.py`:
- Around line 39-41: The subprocess.call currently uses a relative path
"benchmarks/fixtures/gen_kb.py" which makes KB generation cwd-dependent; change
it to compute an absolute path to the generator (e.g., build script_path =
Path(__file__).parent / "fixtures" / "gen_kb.py" and use
str(script_path.resolve())) and pass that absolute path into the
subprocess.check_call invocation (keep sys.executable, and the existing "--out"
and "--claims" args) so the call no longer depends on the current working
directory.

In `@CHANGELOG.md`:
- Line 10: Update the CHANGELOG entry for the "Performance benchmark suite in
`benchmarks/`" so it reflects coverage at 1k/10k/100k (not just 1k/10k) and
amend the example command `pytest benchmarks/ --benchmark-only` to optionally
show the documented JSON output flag (e.g., add
`--benchmark-json=benchmarks/results.json`) so the entry accurately reports
scope and how to produce machine-readable results.

---

Outside diff comments:
In `@benchmarks/bench_search.py`:
- Around line 19-47: Add a 100k fixture and corresponding benchmark tests:
create a pytest.fixture named store_100k(scope="module") that returns
_store(kb_100k), then add two tests mirroring the existing ones —
test_search_fts5_100k(benchmark, store_100k) that calls
benchmark(index_db.search, store_100k.kb_dir, "auth uses JWT", limit=10) and
test_search_substring_100k(benchmark, store_100k) that calls
benchmark(store_100k.search_substring, "auth", limit=10) so FTS5 and substring
fallbacks are measured for 100k like the 1k/10k cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fb21cc8b-bd5b-49c3-bbe9-2a92fd5541cf

📥 Commits

Reviewing files that changed from the base of the PR and between 3beb821 and 56a512f.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • benchmarks/bench_bundle.py
  • benchmarks/bench_index_rebuild.py
  • benchmarks/bench_propose.py
  • benchmarks/bench_search.py
  • benchmarks/conftest.py

Comment on lines +37 to +60
def test_bundle_import_1k(benchmark, exported_bundle_1k, tmp_path):
dest_kb = KBStore.init(tmp_path)
benchmark(
bundle.import_apply,
dest_kb.kb_dir,
exported_bundle_1k,
on_conflict="overwrite",
actor="bench",
)


def test_bundle_export_check_1k(benchmark, exported_bundle_1k):
benchmark(bundle.export_check, exported_bundle_1k)


def test_bundle_import_10k(benchmark, exported_bundle_10k, tmp_path):
dest_kb = KBStore.init(tmp_path)
benchmark(
bundle.import_apply,
dest_kb.kb_dir,
exported_bundle_10k,
on_conflict="overwrite",
actor="bench",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Bundle import benchmark currently measures overwrite-on-existing-KB behavior and misses 100k coverage.

dest_kb is initialized once, so repeated benchmark iterations mostly measure import+overwrite conflict handling rather than fresh import cost. Also, imports are only benchmarked for 1k/10k despite the stated 1k/10k/100k requirement.

Suggested fix sketch
 def test_bundle_import_1k(benchmark, exported_bundle_1k, tmp_path):
-    dest_kb = KBStore.init(tmp_path)
-    benchmark(
-        bundle.import_apply,
-        dest_kb.kb_dir,
-        exported_bundle_1k,
-        on_conflict="overwrite",
-        actor="bench",
-    )
+    def _run():
+        dest_kb = KBStore.init(tmp_path / "run_1k")
+        return bundle.import_apply(dest_kb.kb_dir, exported_bundle_1k, on_conflict="overwrite", actor="bench")
+    benchmark(_run)

Mirror this for 10k and add a 100k variant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarks/bench_bundle.py` around lines 37 - 60, The import benchmarks
currently reuse a single dest_kb (KBStore.init(tmp_path)) so iterations measure
overwrite behavior; update test_bundle_import_1k and test_bundle_import_10k to
initialize a fresh KBStore for each benchmark iteration by wrapping
bundle.import_apply in a small callable that calls KBStore.init(...) inside the
benchmark invocation (so each run imports into a fresh KB instead of
overwriting), and add a new test_bundle_import_100k that mirrors the 1k/10k
tests but uses exported_bundle_100k and the same per-iteration KBStore
initialization pattern.

Comment on lines +21 to +35
def test_propose_claim_latency(benchmark, fresh_store, source_id):
"""propose_claim() write latency — sits in the agent hot loop."""
counter = [0]

def _propose():
counter[0] += 1
return propose_claim(
fresh_store,
text=f"benchmark claim {counter[0]}",
evidence=[source_id],
proposed_by="bench-agent",
)

result = benchmark(_propose)
assert result is not None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

This benchmark mixes changing workload state, so latency numbers are not comparable.

Line 23+ keeps inserting new claims into the same store during one benchmark run, so later iterations are measuring a larger KB than earlier ones. That skews a single reported metric and weakens regression tracking. It also does not implement the 1k/10k/100k throughput sweep from the objective.

Suggested direction
- def test_propose_claim_latency(benchmark, fresh_store, source_id):
+ `@pytest.mark.parametrize`("kb_size", ["1k", "10k", "100k"])
+ def test_propose_claim_latency(benchmark, kb_size, ...):
     ...
-    result = benchmark(_propose)
+    # Keep per-iteration state constant (fresh destination store each invocation/round)
+    result = benchmark(_propose)

Use a size-parametrized seed input and ensure each measured invocation starts from equivalent state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarks/bench_propose.py` around lines 21 - 35, The benchmark
test_propose_claim_latency mutates shared state by inserting new claims into
fresh_store on each iteration, making latency results non-comparable; change it
so each measured invocation sees an equivalent store state: create a
size-parameterized seed (e.g., sizes like 1k/10k/100k), pre-seed a template
store for each size, and in _propose use a fresh copy/clone of that template
store (or re-initialize fresh_store) so propose_claim always runs against the
same initial KB; keep source_id and proposed_by the same but ensure
benchmark(_propose) operates on an isolated per-iteration store so metrics are
stable and follow the required throughput sweep.

Comment thread benchmarks/conftest.py
Comment on lines +39 to +41
subprocess.check_call(
[sys.executable, "benchmarks/fixtures/gen_kb.py",
"--out", str(out), "--claims", str(claims)],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use an absolute generator script path to avoid cwd-dependent failures.

subprocess.check_call currently depends on the process working directory. If invoked from another cwd, KB generation can fail at runtime.

Suggested fix
 def _gen_kb(tmp_path_factory, *, claims: int) -> Path:
     out = tmp_path_factory.mktemp(f"kb{claims}")
+    script = Path(__file__).resolve().parent / "fixtures" / "gen_kb.py"
     subprocess.check_call(
-        [sys.executable, "benchmarks/fixtures/gen_kb.py",
+        [sys.executable, str(script),
          "--out", str(out), "--claims", str(claims)],
     )
     return out
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmarks/conftest.py` around lines 39 - 41, The subprocess.call currently
uses a relative path "benchmarks/fixtures/gen_kb.py" which makes KB generation
cwd-dependent; change it to compute an absolute path to the generator (e.g.,
build script_path = Path(__file__).parent / "fixtures" / "gen_kb.py" and use
str(script_path.resolve())) and pass that absolute path into the
subprocess.check_call invocation (keep sys.executable, and the existing "--out"
and "--claims" args) so the call no longer depends on the current working
directory.

Comment thread CHANGELOG.md
## [Unreleased]

### Added
- Performance benchmark suite in `benchmarks/` covering search latency, proposal write throughput, bundle export/import/verify round-trips, and index rebuild time at 1k/10k claim sizes. Run with `pytest benchmarks/ --benchmark-only`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align changelog benchmark scope and command with stated objectives.

This line says coverage is 1k/10k only, but the PR objective/acceptance criteria call out 1k/10k/100k in the single-command suite. Please update the wording (and optionally include the documented JSON output command) so release notes don’t under-report benchmark scope.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 10, Update the CHANGELOG entry for the "Performance
benchmark suite in `benchmarks/`" so it reflects coverage at 1k/10k/100k (not
just 1k/10k) and amend the example command `pytest benchmarks/ --benchmark-only`
to optionally show the documented JSON output flag (e.g., add
`--benchmark-json=benchmarks/results.json`) so the entry accurately reports
scope and how to produce machine-readable results.

@Tet-9

Tet-9 commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

@plind-junior , you may review this now

@Tet-9

Tet-9 commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

@plind-junior , can you give this a check?
Has been lying down for a long while now

@Tet-9

Tet-9 commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

All issues or conflicts have all been fixed

@plind-junior

Copy link
Copy Markdown
Collaborator

Create the PR against test branch

@plind-junior

Copy link
Copy Markdown
Collaborator

One thing worth a follow-up before this is the safety net it's meant to be: fsck opens with store.list_claims(), which is strict — a single invalid YAML on disk (say, a legacy uncited claim from before the #82 validator) will raise ValidationError and the whole check aborts before reporting anything. That's exactly the kind of inconsistency a deep checker most needs to surface. lint() already has _load_claims_for_lint for this; could fsck reuse it so a bad YAML becomes an invalid_claim finding instead of a traceback?

@plind-junior

Copy link
Copy Markdown
Collaborator

Functionality is great — could the diff be a bit slimmer? Most of the +422 is the same shape repeated across the three kinds. A small helper would cut it noticeably without hurting clarity.

The biggest win is in _check_index_drift — the orphan/missing-row block is written out three times (claims, pages, entities). One little helper that takes (kind, indexed_ids, on_disk_ids) and emits the two findings collapses it to a few short calls, drops ~30 lines, and removes the "easy to drift between copies" trap.

Same idea on the test side: the orphan-claim / orphan-page / orphan-entity tests likely have near-identical setup, so a single @pytest.mark.parametrize("kind", …) would save another ~30 lines and make adding a kind a one-liner later.

Tiny extra: the three "if X not in claims → dangling finding" loops in _check_lifecycle_chains factor nicely into a two-line helper.

@Tet-9

Tet-9 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@plind-junior , could you reopen this once again, then I would fix the conflicts right away

@plind-junior plind-junior reopened this Jun 2, 2026
@plind-junior

Copy link
Copy Markdown
Collaborator

PR should target the test branch, not main

@Tet-9 Tet-9 changed the base branch from main to test June 2, 2026 11:53
…d index

benchmarks/ had a KB generator (gen_kb.py) and a detailed README but
no timing harness. Add four benchmark modules covering:

- bench_search.py: FTS5 and substring search latency at 1k/10k claims
- bench_propose.py: propose_claim() write latency (agent hot loop)
- bench_bundle.py: export, import, verify round-trips at 1k/10k claims
- bench_index_rebuild.py: index rebuild time at 1k/10k claims

Session-scoped fixtures in conftest.py generate synthetic KBs once
per session via gen_kb.py to keep benchmark startup cost low.

Run with: pytest benchmarks/ --benchmark-only --benchmark-json=bench.json

Closes vouchdev#99
@Tet-9 Tet-9 force-pushed the feat/99-performance-benchmarks branch from 56a512f to 8cffebe Compare June 2, 2026 12:32
@Tet-9

Tet-9 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

PR should target the test branch, not main

Fixed

@plind-junior

Copy link
Copy Markdown
Collaborator

Review

Summary: Adds the missing pytest-benchmark harness that issue #99 called for — five modules covering search, propose, bundle, and index-rebuild. The structure is clean and the module-scoped fixtures are the right call for keeping wall-clock startup cost low. A few gaps vs the acceptance criteria and one path portability issue need addressing.

What works

  • benchmarks/conftest.py:22-43 — session-scoped kb_1k / kb_10k fixtures correctly share generated KBs across the whole benchmark session, avoiding redundant gen_kb.py invocations.
  • benchmarks/bench_propose.py:23-34 — closure counter pattern correctly avoids reusing the same claim text across benchmark rounds, keeping the write path exercised each iteration.
  • benchmarks/bench_bundle.py:13-30 — module-scoped exported_bundle_* fixtures export once and let all import/verify benchmarks reuse the archive, which is the right performance isolation.
  • benchmarks/bench_index_rebuild.py — straightforward and correctly scoped; rebuilding from scratch each round is the right behaviour for this metric.
  • CHANGELOG.md entry is accurate and gives the run command.

Suggestions

  • [blocking] benchmarks/conftest.py:40 — The generator is called with a hard-coded relative path "benchmarks/fixtures/gen_kb.py". This breaks if pytest is invoked from any directory other than the repo root (e.g. pytest benchmarks/ from inside benchmarks/). Fix by anchoring to the script's own location:

    _FIXTURES = Path(__file__).parent / "fixtures" / "gen_kb.py"
    # then: [sys.executable, str(_FIXTURES), ...]
  • [blocking] benchmarks/conftest.py:34-37 — The kb_100k fixture is defined but never referenced in any bench file. Issue feat: performance benchmarks at 1k / 10k / 100k claims #99 acceptance criteria explicitly require "1k/10k/100k-claim KBs". Either add 100k variants to bench_search.py, bench_bundle.py, and bench_index_rebuild.py, or drop the fixture and address 100k coverage in a follow-up (updating the issue accordingly).

  • [blocking] Issue feat: performance benchmarks at 1k / 10k / 100k claims #99 acceptance: "a baseline is committed." No bench.json (or equivalent) is included. Without a committed baseline, there is nothing to diff future runs against, which was the main deliverable. Commit an initial benchmarks/baseline.json produced by running the suite on a reference machine, even if numbers vary — the structure matters more than the exact values at this stage.

  • [non-blocking] benchmarks/bench_bundle.py — The 10k coverage is incomplete: test_bundle_export_10k and test_bundle_export_check_10k exist for the import side (test_bundle_import_10k) but export and verify at 10k are missing. The exported_bundle_10k fixture is wired up solely to feed test_bundle_import_10k, so the export/verify performance curve at 10k is uncharted.

  • [non-blocking] benchmarks/bench_search.py:15-18_store() calls rebuild_index every time a module-scoped fixture is initialised. This is fine for correctness, but if kb_1k/kb_10k are ever reused across modules in the same session the index will be rebuilt redundantly. Consider promoting the rebuild into the session-scoped conftest fixtures so that each KB path is fully indexed once.

  • [non-blocking] benchmarks/bench_bundle.py:32-34test_bundle_export_1k creates a fresh KBStore(kb_1k) inside the benchmarked function call via the outer fixture, but the dest path is fixed to tmp_path / "out.tar.gz". On the second and subsequent benchmark rounds bundle.export will overwrite the same path, which is fine behaviourally but could mask errors if export is ever made append-safe. A round-unique path (e.g. using a counter) would make each round fully independent.

Verdict

Request changes — Two acceptance-criteria gaps (100k coverage and committed baseline) and one portability bug in the fixture path are blocking. The core harness design is solid; these are targeted fixes.

@plind-junior plind-junior merged commit 8337b89 into vouchdev:test Jun 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: performance benchmarks at 1k / 10k / 100k claims

2 participants