UsageBench is Bifrost's curated LSP-parity and recurring regression suite for the static-analysis task of discovering usages of source symbols.
The Starlight site under docs/ explains the comparison
methodology, current Bifrost-versus-LSP results, and case-level language
differences.
Mature language servers provide the baseline and calibration evidence. Bifrost is expected to match them where their behavior agrees with reviewed language semantics, and may preserve justified precision improvements or additional static coverage. The benchmark format remains analyzer-neutral so future competitors can be evaluated against the same source contracts.
LSPs primarily serve developers through interactive editor features. Bifrost serves repository code analysis and navigation for machine consumers, especially coding agents and static-analysis tools. UsageBench measures their overlapping usage and navigation contract: parity preserves the quality developers expect, while reviewed Bifrost-specific edges exercise the analysis substrate agents depend on. It does not compare either product's complete feature surface.
The independently reviewed
real-project-v1 evaluation is
published as immutable release
v0.2.0. It
compares Bifrost with gopls, Pyright, and TypeScript language server across 12
source-only sampled repositories and 36 preregistered cases. The broader 24
July 2026 ten-language development run remains available as
historical regression evidence
and is not pooled with the evaluation result.
The benchmark corpus is authored by source location instead of by an analyzer-specific symbol ID. Each case points at a declaration, expected usage sites, and reverse usage-to-declaration probes using LSP-shaped ranges.
Benchmark releases package each raw report, a manifest with its SHA-256 digest, and generated result fragments. Generate (or check) those fragments from an extracted release evidence directory with:
cargo run -- generate-results \
--manifest evidence/freeze-manifest.json \
--output-directory generated-results
cargo run -- generate-results \
--manifest evidence/freeze-manifest.json \
--output-directory generated-results \
--checkThe generator rejects missing, altered, mismatched, or non-snapshot reports
before it writes a page. Evaluation pages additionally verify the freeze ID,
bounded claim scope, artifact provenance, denominators, exclusions, and
replacements, and cannot mix development documents into an evaluation claim.
freeze-manifest writes a sibling *.timings.json even when validation fails;
the freeze workflow retains it together with staging, corpus hashing,
frozen-input hashing, report validation, and manifest-writing timings. Staged
bundles also contain .usagebench-corpus-hashes.json, whose root digest binds
the exact input file set and is independently reverified during shard
aggregation before its per-file hashes are reused.
Location-level precision, recall, and range-quality tables require reports
produced by UsageBench 0.2.0 or newer; older reports remain readable for their
existing strict and required-destination fields but are never interpreted as
having zero location metrics. The current site summary is derived from the
hash-bound v0.2.0 release. The hand-authored 24 July summary predates the
release evidence pipeline and is retained only as explicitly labelled
development history.
benchmarks: Authored benchmark case files and corpus documentation.fixtures: Small in-repository source corpora used by the baseline cases.schema: JSON Schema for benchmark case documents.src: Rust validation CLI, schema model, and analyzer runner adapters.adapters/lsp: Versioned language-server profiles and reproduction notes.containers/reference: Versioned, digest-pinned reference environments.scripts: Local image build, offline execution, and report reproduction tools.docs: Public Starlight content plus adapter design notes and execution plans.
Benchmark cases use YAML authored around an LSP-shaped location model. Validate them with:
cargo run -- validate benchmarks/casesCI runs the same Rust test and validation path:
cargo test
cargo run -- validate benchmarks/casesThe pinned real-project evaluation source archives under
benchmarks/evaluation/real-project-v1/sources/ are tracked with Git LFS. A
checkout must materialize those objects before validating or running the full
corpus:
git lfs install
git lfs pullGitHub workflows that consume the full corpus enable LFS during checkout.
The current corpus uses small checked-in fixtures for Java, Go, Python, TypeScript, JavaScript, Rust, Scala, C#, PHP, C++, and Ruby. These fixtures are the source of truth for issue #8; the older broad Java/Go/Python generator stack has been removed from the active benchmark path.
Each document is schema v2 and explicitly labeled development,
analyzer_informed, and legacy_unattributed. All 158 current cases across 35
documents have completed a first human review, preserved in
benchmarks/reviews/2026-07-17-DavidBakerEffendi.md.
This remains a regression and diagnosis corpus, not an independently reviewed
evaluation partition: promotion still requires a second reviewer,
preregistered selection, and a freeze ID.
benchmarks/cases/evaluation/real-project-v1 is a separate, preregistered,
source-locked slice: four repositories and three declarations for each of
Go/gopls, Python/Pyright, and TypeScript/TypeScript LS, for 12 repositories and
36 cases. Its source archives, selection, review, adjudication, and source lock
are checked in and hash-bound. The historical same-provider review is retained,
and all 36 cases now also have blinded OpenAI and Anthropic derivations plus
accountable human adjudication under the schema-v2 protocol. Its analyzer
evidence is frozen in immutable release
v0.2.0. Every
published table is evaluation-only and limited to the
protocol's descriptive per-profile claim; it is not pooled with development
fixtures or presented as language-wide, ecosystem-wide, causal, or performance
evidence.
Runner adapters under src/runners translate tool-specific output into one
analyzer-neutral report shape. Every report records the requested and resolved
tool version plus per-operation capability levels (native, recovered, or
unsupported). Reports distinguish exact passes, position-unverified results,
hard failures, and runner errors, and separate development from evaluation
totals. Print the JSON Schema with:
cargo run -- report-schemaThe existing Bifrost command remains stable:
cargo run -- run-bifrost benchmarks/cases \
--bifrost-repo /path/to/bifrost \
--bifrost-working-treerun-bifrost supplies an explicit 300-second wall-clock budget to each
scan_usages_by_location call. This batch-oriented default avoids inheriting
Bifrost's five-second interactive budget and is recorded in report invocation
metadata. Use --scan-usages-max-duration-secs <0-300> to select a smaller
per-scan budget for development runs. When --output is set, the runner also
atomically updates a sibling *.partial.json checkpoint after each completed
benchmark document so interrupted batch runs retain valid evidence. Checkpoints
record completed: false plus the full requestedCaseFiles scope and are
rejected by snapshot and release tooling as completed evidence.
Source-based runs also retain a Bifrost build cache in --work-dir. A build is
reused only when the resolved commit, Cargo and rustc identity, build plan,
target/profile/compiler environment, and cached executable metadata still
match. The executable SHA-256 is verified on the first use and reused only
while its size, modification/change time, device, and inode identity remain
unchanged (with the portable metadata subset used off Unix). The same verified
provenance cache applies to --bifrost-binary; the required
--bifrost-resolved-commit remains report provenance and is not a caller-
supplied digest. Reports and CLI output separate checkout/setup, build,
provenance hashing, workspace readiness, and analyzer query milliseconds.
The generic LSP adapter starts a versioned stdio language server, opens an isolated fixture workspace, and translates the protocol's native references, definition, and type-definition responses into the same report:
cargo run -- run-lsp benchmarks/cases \
--profile adapters/lsp/gopls.json \
--output benchmark-output/gopls-v0.23.0.jsonProfiles cover all eleven corpus languages through clangd, Roslyn and
csharp-ls, gopls, Eclipse JDT LS, Pyright, Ruby LSP, Metals, Intelephense,
rust-analyzer, and typescript-language-server. The executable named by a
profile must be installed or available through the profile's package launcher;
--server-command can override only the executable while preserving its
arguments. See the LSP profile guide for setup and
the measured comparison.
The primary public profile registry distinguishes canonical reference runners
from native LSP profiles. Bifrost and gopls use the canonical linux/amd64
environment. Each remaining advertised LSP row is frozen from one pinned run
whose report records the profile checksum, resolved analyzer identity,
executable provenance, environment, and result checksum. Apple clangd 21 and
upstream clangd 22 remain separate candidate identities.
UsageBench deliberately stays focused on the LSP-shaped task of finding symbol
references and navigating those references back to declarations and types.
Broader analysis contracts should use sibling suites—for example, a future
callbench for call-graph resolution and taintbench for taint-flow analysis—
so each benchmark can model its own ground truth without tool-specific private
hooks or weakened semantics.
Benchmark corpus releases use immutable SemVer tags such as v0.1.0. The
benchmark release version is independent from the Rust package version in
Cargo.toml and the benchmark document schemaVersion. See
RELEASES.md for the version policy and curated release contents.
Use the root CITATION.cff when citing UsageBench. It describes
the latest release and intentionally contains no placeholder DOI. If an archival
service assigns a DOI later, the real version-specific identifier will be added
to the citation file and that release's notes.
A run report records:
usagebenchVersion: the Rust CLI and adapter implementation version;usagebenchRevision: the exact UsageBench commit, with-dirtywhen local changes prevent commit-only reproduction;usagebenchRelease: thevMAJOR.MINOR.PATCHcorpus tag when available; and- the logical invocation, native or container platform scope, analyzer executable checksum, toolchains, reference-environment definition, and runner's requested and resolved version.
Reference environment version 1 provides the canonical linux/amd64 path for
Bifrost and gopls. Save a published container report as report.json, extract
the release bundle named by the report, and run one command:
./scripts/reproduce-report.sh report.json reproduced.jsonThe command restores the checksum-addressed image when its complete identity
and immutable registry digest verify, otherwise builds the recorded environment
locally, reruns without network access, and compares the reports semantically.
Release bundles still contain everything needed for an independent forced
rebuild. See ARTIFACT.md for
the artifact-review procedure, security boundary, expected build cost, and
manual commands. Native runner commands remain available for development but
are labeled host-specific and are not the canonical reproducibility claim.
If usagebenchRevision ends in -dirty or usagebenchRelease is absent, the
report identifies a development run and is rejected by the canonical
reproduction command.
UsageBench is licensed under the permissive MIT License, covering the corpus fixtures, assertions, adapter profiles, and harness code in this repository.
The daily GitHub Actions workflow in .github/workflows/benchmark.yml runs the
curated corpus against Bifrost master on ubuntu-latest. This makes every
reviewed parity decision, precision edge, and known gap part of a recurring
regression signal rather than a one-time comparison.
The workflow:
- validates
benchmarks/cases - checks out
BrokkAi/bifrost - builds
usagebench - runs
usagebench run-bifrost benchmarks/caseswith the versioned current expected-pass overlay - uploads the JSON report from
benchmark-output - publishes a GitHub step summary
- optionally posts a payload to Slack
Scheduled runs use Bifrost master. Manual workflow_dispatch runs from the
default UsageBench branch can set a specific bifrost_ref and can opt into
cases marked unsupported.
Without --bifrost-working-tree, run-bifrost creates an isolated checkout
under target/usagebench and checks out --bifrost-commit.
The Bifrost checkout is public and does not use a separate checkout secret. Checkout credentials are removed before repository-controlled commands run.
Slack delivery is best-effort and does not change the benchmark result. To
enable it, configure the repository secret
SLACK_DAILY_USAGEBENCH_WEBHOOK_URL. The workflow sends a benchmark-specific
payload with:
okerror_textworkflow_run_urlhead_sha_shortusagebench_revisionusagebench_releasebifrost_refbifrost_sha_shortrun_outcomecases_countpassed_countimproved_counttotal_passed_countfailed_countexpected_failures_countnot_planned_countunsupported_countskipped_counterrors_count
Repository-enforced controls and the required administrative settings are documented in GitHub Actions security operations.