Automatic known-target retrieval quality¶
Issue #59 compares embedding configurations using automatically derived, source-verifiable targets. There is no manual grading, result pooling, grading sheet, or LLM judge. The historical commit-path benchmark remains available; its changed-file labels are not treated as gold labels for this mode.
What the benchmark measures¶
A case contains an exact repository commit, query, intent, primary channel, known targets, source SHA-256, and derivation rule. Generation reads Git blobs at that commit, not mutable working-tree files. Execution regenerates the source witnesses and rejects edited queries, targets, or provenance.
| Intent | Query source | Known target | Primary channel |
|---|---|---|---|
symbol_lookup |
Python definition name | Definition path and starting line | emb |
architecture_lookup |
Module docstring summary | Owning module file | emb |
task_lookup |
Definition docstring summary | Definition path and starting line | emb |
docs_lookup |
Markdown heading outside fenced code | Heading path and line | docs |
error_or_trace_lookup |
Literal raise argument, or its immediately preceding literal assignment | Owning definition path and line | emb |
Nested errors belong to their nested definition, not its enclosing function. Interpolated messages, inferred call behavior, commit-changed paths, and cases without a verifiable source witness are excluded. Public definitions are used; test, fixture, benchmark, vendor and archive directories are excluded. Generation requires the requested count in every repository/intent cell and fails if a category is short. It does not fill gaps with guessed labels.
These labels are not exhaustive semantic relevance judgments. Module-file cases have coarser resolution than definition or heading cases. Source-derived queries can favor lexical matching. Recall means recall of known targets; with one target it equals Hit at the same cutoff. Unlabeled results are not established as irrelevant, and a better score does not prove more useful agent answers. This benchmark does not replace #53 task-success evaluation.
Versioned inputs¶
The public initial bank is
benchmarks/retrieval-quality/known-target-v1/cases.jsonl: 75 cases, with five
cases per intent for each of Codira, Fontshow, and sanikey. The adjacent
fixtures.json records public repository URLs and exact revisions. The full
initial local bank also includes one private repository and has 100 cases.
Its cases and locator manifest remain ignored under
.artifacts/benchmarks/retrieval-quality/datasets/known-target-20261008-v1/.
Private query text, target identities and source evidence must never be copied
into tracked documentation, fixtures or reports.
Regenerate cases through scripts/build_known_target_dataset.py. The
known-target-v1 format is validated by scripts/known_target_quality.py:
unique safe IDs, exact 40-character commits, known intents/channels, nonempty
queries and target sets, canonical repository-relative locations, positive
definition/heading lines (zero for file-level cases), and source digests.
Local locator manifests contain a repositories list with label, path,
and commit. Use the revisions from fixtures.json; leaving commit absent
selects current HEAD only when generating a new dataset. For example:
{
"schema_version": 1,
"repositories": [
{"label": "codira", "path": "ABSOLUTE_CODIRA_CHECKOUT", "commit": "PINNED_40_CHARACTER_SHA"}
]
}
Keep actual local paths and private repository entries in ignored storage. All repositories referenced by a case bank must be present in the locator manifest. A checkout may move or contain edits: execution archives its pinned Git revision and checks frozen contents before each resume.
Run, resume and rescore¶
Prerequisites: a Codira development checkout with uv sync completed; Git
objects for the pinned revisions; installed analyzers and embedding plugins;
the selected model assets available; and Linux for the campaign lock and
sampled process-tree RSS. Run commands from the Codira checkout. This mode
invokes its host codira executable and does not run a target project's UV
environment or setup scripts.
Create a local manifest at REPOSITORY_MANIFEST, then generate a new bank at
CASE_BANK if needed. Replace these names with actual paths before running:
uv run python -m scripts.build_known_target_dataset \
--repo-manifest REPOSITORY_MANIFEST \
--per-intent 5 \
--output CASE_BANK
Expected output: Generated N source-verified cases: .... A shortage or an
existing output path produces a nonzero exit. Correct the source/input issue
and select a new dataset output; do not overwrite existing evidence.
Choose a new ignored RUN_DIRECTORY under
.artifacts/benchmarks/retrieval-quality/runs/. Select models explicitly to
bound work; omitting --model-id selects the entire model manifest.
uv run python -m scripts.run_retrieval_quality_benchmark --known-target \
--dataset CASE_BANK \
--repo-manifest REPOSITORY_MANIFEST \
--model-manifest benchmarks/embedding/model-candidates.json \
--model-id bge-small-en-v1.5-onnx \
--model-id jina-embeddings-v2-base-code-onnx \
--baseline bge-small-en-v1.5-onnx \
--k 1 5 10 \
--output RUN_DIRECTORY
Execution defaults to SQLite, CPU embeddings, immediate indexing, fixed 4,000-character indexing text limits, and separate state per model/repository. The warm query daemon and indexing daemon are disabled. The run stores rendered configuration, runtime capabilities and digest, Codira executable digest, available local ONNX model/tokenizer digests, dataset/model-manifest checksums, repository commits/archive checksums, Python/platform/CPU metadata, K values, command timeouts, and benchmark harness source hashes. Local model asset paths in the model manifest are resolved from the Codira working directory before freezing. Named sentence-transformers models do not have local weight digests in this mode; pin and retain their upstream/cache assets separately before claiming exact weight reproducibility.
Each repository is indexed once per model. Every case runs its primary emb
or docs retrieval and a separate ctx probe. Rankings come only from the
returned ordered results; nested references and expanded context do not become
extra ranked hits. K is configurable up to 100; 1, 5 and 10 are always retained.
Archived sources receive an isolated Git index so Codira discovers exactly
their tracked contents instead of consulting the surrounding artifact host.
The generated .git metadata is separate from immutable source verification.
An empty or incomplete index is an execution failure.
Before querying, the runner verifies that the isolated SQLite vector bindings
match the complete structural embedding inventory, including cached payload
availability. Indexing counters alone do not establish search readiness.
Progress is enabled by default on stderr. An interactive terminal shows a
refreshing bar with completed/planned operations, model, repository, phase,
elapsed seconds and checkpoint reuse. Indexing has a heartbeat while its
subprocess runs. Redirected logs contain operation transitions and heartbeats
at most every 15 seconds between transitions. Percentages count operations;
they are not an estimate of elapsed-time completion, because indexing and
queries have different costs. Query text is excluded from progress output.
Use --quiet-progress to suppress these messages.
Expected successful terminal output: Known-target results: ..., exit 0,
quality-summary.json, and quality-summary.md. Failed indexing, incomplete
embeddings, nonzero commands, timeout, malformed JSON or invalid responses
produce a nonzero terminal status and retained evidence.
Default limits are 3,600 seconds per index and 900 seconds per query. Override
them with --index-timeout and --query-timeout when creating a run. Optional
--memory-budget-mib and --max-index-seconds record comparison budgets;
the latter applies to total model indexing time across selected repositories.
For long campaigns, supervise the same command with the established tmux
workflow and retain a log and separately written exit status alongside the run.
After interruption, rerun the same command with --resume appended. Successful
operations are reused only after checking their command and output digests.
Failures receive new numbered attempt directories; previous raw stdout,
stderr and measurements remain intact. Malformed successful responses are
retryable failures. Changed controls, runtime, model assets, source trees or
configurations require a new run identity. Do not edit saved records to force
reuse, and do not execute or rescore one identity concurrently.
Rescore without models, Git checkouts or retrieval execution:
uv run python -m scripts.run_retrieval_quality_benchmark --known-target \
--output RUN_DIRECTORY \
--rescore
Rescoring verifies the retained case checksum and successful raw-output
digests, reconstructs rankings from stdout, and rewrites only derived reports.
It returns nonzero if planned results or ctx probes are missing/failed.
Interpretation and model comparison¶
Reports contain Hit@1, known-target Recall@5, MRR@5/10, and other requested
cutoffs. Breakdowns cover repositories and intents. Macro means equal weight
per repository; micro means the mean per-query metric. Failed and missing
primary queries remain in the full planned denominator with zero scores;
valid empty rankings are misses. Failures, empty rankings and ctx failures
are reported separately. Operational exit 0 is not a retrieval hit.
Primary-query median latency is reported separately for emb and docs;
ctx median latency and full-index wall time are additional cost measurements.
RSS is the largest process-tree resident-memory sum observed every 50 ms from
Linux /proc. It is a sampled lower bound on peak, can double-count shared
pages, and cannot establish compliance with a hard peak-memory budget.
With an explicit baseline, report the macro Recall@5 and MRR@10 differences,
the issue's suggested material-gain thresholds (+0.05 absolute for either),
and emb/ctx median-latency ratios against the suggested 1.25x limit.
Incomplete coverage yields needs_more_data; a complete comparison without
material gain yields rejected; a material known-target gain yields
quality_profile_candidate pending broader usefulness and resource validation.
The baseline remains a reference. No candidate is automatically promoted to
the default, and no installed configuration is modified.
Use small synthetic fixtures for automated validation. A fixture executable tests the runner's protocol, persistence and scoring mechanics; it does not qualify real embedding quality. Retain actual runtime smoke results separately from a representative multi-repository comparison.
Recovering from missing vector bindings¶
The initial local known-target-full-20261008-v1 comparison completed its
commands but lost bindings from earlier indexing batches. Its zero quality
scores and model rejection cannot support a model-selection conclusion.
The backend now persists partial work segments incrementally. Keep that run
intact and repeat the documented execution with a new output identity, such
as .artifacts/benchmarks/retrieval-quality/runs/known-target-full-20261008-v2.
Do not append --resume to the old run after changing the harness or runtime.
Optional relevance judgments¶
After a corrected comparison finishes, use the independent LLM retrieval grader to assess pooled snippet relevance through OpenRouter. It requires an explicit judge and budget and keeps those judgments separate from automatic known-target metrics.