yams/tests/benchmarks/search/retrieval_quality_bench.cpp
Trevon 0dd3985db4
refactor: simplify runtime paths and harden retrieval (#61)
* refactor(tuning): prune dormant runtime knobs

Remove unused tuning controls and adaptive search budget state. Extract testable ONNX slot reconciliation and search telemetry hydration seams, and correct the Apple Silicon sysctl value width.

* refactor(vector): retire dormant backends

Remove unused FAISS, model-infrastructure, VectorIndexManager, and TurboQuant paths while keeping Simeon PQ and float-vector storage.

Migrate unused V2.2 quantized schemas transactionally to V2.3. Databases containing non-default quantized formats or packed-code blobs fail closed with recovery guidance and no mutation.

* refactor(plugins): remove legacy SDK tooling

Remove the Ghidra and SDK submodules, their bespoke tests, and stale scan exclusions. Retain generic PluginProcess coverage against the repository mock fixture.

* build(vector): remove stale FAISS overrides

* refactor(ipc): remove dormant FSM snapshots

* refactor(ingest): unify bounded KG enqueue

* fix(plugins): harden allocation contracts

Keep ABI outputs null or fully initialized when allocations fail, and represent empty object payloads without relying on malloc(0).

* fix(storage): define empty object reads

Return a null buffer with zero length for successful empty-object reads instead of treating malloc(0) as an allocation contract.

* refactor(storage): trim through string views

* test: prune dormant harness helpers

Remove unused readiness and fixture helpers, and keep benchmark client-count doubling in a wide integer domain.

* chore(cpp): initialize analyzer-facing locals

* build(simeon): advance analyzer cleanup

* refactor(config): drop dead daemon client keys

* refactor(ipc): inject daemon client transport

Socket and in-process execution now share DaemonClient request dispatch, so CLI fallbacks do not need alternate service paths.

* refactor(retrieval): route CLI through daemon

Search and grep now use the same daemon handlers over socket or in-process transport. Live grep remains an explicit freshness inspection.

* refactor(graph): move CLI scope into daemon

Graph CLI requests now share daemon handlers across socket and in-process transports. CWD filtering occurs before pagination so scoped totals and pages stay correct.

* build: isolate test-only runtime controls

* refactor(metadata): decouple lock telemetry

* fix(services): return on request timeout

* fix(retrieval): enforce workspace scope

* fix(graph): scope nodes before pagination

* fix(grep): drop binary result lines

* fix(daemon): bound checkpoint wait

* fix(repair): use KG health checks

* fix(storage): always verify compressed CRC

* perf(vector): skip unchanged PQ snapshots

* build(zyp): exclude bench from default build

* build: protect Meson files from formatter

* refactor: remove unreachable production APIs

* refactor(daemon): remove dormant runtime state

* fix(vector): harden daemon provider calls

Timed-out coroutines must own their client and requests. Provider discovery must also fail instead of returning synthetic embeddings in production.

* refactor(storage): remove unusable adapters

* fix(cli): unify in-process add requests

* fix(tsan): preserve async worker progress

* test(cli): isolate daemon-dependent suites

* fix(repair): expose queue backoff progress
2026-07-31 14:16:45 -04:00

9412 lines
458 KiB
C++

/*
retrieval_quality_bench.cpp - RAG Retrieval Quality Benchmark
Uses daemon-based ingestion to properly test retrieval quality with IR metrics.
Usage:
YAMS_TEST_SAFE_SINGLE_INSTANCE=1 ./builddir/tests/benchmarks/retrieval_quality_bench
Environment variables:
YAMS_TEST_SAFE_SINGLE_INSTANCE=1 - Required to prevent GlobalIOContext reset
YAMS_BENCH_CORPUS_SIZE=N - Number of documents to generate (default: 50)
YAMS_BENCH_NUM_QUERIES=N - Number of test queries (default: 10)
YAMS_BENCH_TOPK=N - Retrieve top K results (default: 10)
YAMS_BENCH_DATASET=<name> - Use synthetic, BEIR, or local-manifest dataset
YAMS_BENCH_DATASET_PATH=... - Path to BEIR directory or benchmark_manifest.json root
YAMS_BENCH_EMBED_BACKEND=simeon|onnx
Embedding backend (default: simeon)
YAMS_BENCH_ENABLE_GLINT=1 - Opt into Glint/GLiNER entity extraction on simeon runs
YAMS_BENCH_ENABLE_ONNX_RERANK=1 - Opt into ONNX reranker on simeon runs
YAMS_BENCH_TOPOLOGY_MODE=disabled|weak_query_only|hybrid_assist
YAMS_BENCH_TOPOLOGY_EXPANSION=clusters|graph_neighbors
Cluster partition vs pure semantic_neighbor expansion
YAMS_BENCH_TOPOLOGY_ENGINE=connected|louvain|kmeans
Write topology engine into isolated config
YAMS_BENCH_TOPOLOGY_ROUTE_SCORING=current|size_weighted|seed_coverage
Topology route scoring policy
YAMS_BENCH_TOPOLOGY_SPARSE_DENSE_ALPHA=0..1
Sparse seed overlap vs dense centroid blend
YAMS_BENCH_TOPOLOGY_MIN_ROUTE_SCORE=N.N
Reject routed clusters below score
YAMS_BENCH_TOPOLOGY_MEDOID_ONLY_EXPANSION=1
Expand only route medoids, not full clusters
YAMS_BENCH_TOPOLOGY_MIN_CLUSTERS=N Minimum adaptive routed-cluster prefix
YAMS_BENCH_TOPOLOGY_MAX_SEED_DOCUMENTS=N
Cap ranked lexical routing evidence
YAMS_BENCH_TOPOLOGY_ADAPTIVE_PROBE_SCORE_GAP=N.N
Grow route prefix while scores remain near the best
YAMS_BENCH_TOPOLOGY_NARROW_MIN_BOUNDARY_MARGIN=N.N
Abstain when selected/excluded route margin is smaller
YAMS_BENCH_TOPOLOGY_CLUSTER_OUTPUT=... Export evaluation-only cluster memberships as JSON
YAMS_BENCH_TOPOLOGY_SOURCE=vector|fts5|keyphrase|segment_keyphrase|kg|gliner|header|theme
Benchmark semantic_neighbor seeding source for topology
YAMS_SEARCH_ENABLE_TOPOLOGY_WEAK_ROUTING=1 - Legacy opt-in topology weak-query routing
YAMS_SEARCH_TOPOLOGY_MAX_CLUSTERS=N - Cap routed topology clusters (default: 2)
YAMS_SEARCH_TOPOLOGY_MAX_DOCS=N - Cap routed topology docs (default: 64)
YAMS_SEARCH_TOPOLOGY_GRAPH_VECTOR_SEED_PROBE=N
GraphNeighbors seed ANN k (0=off/product default; opt-in
e.g. 16)
Tuning for faster ingestion (recommended for large corpora):
YAMS_POST_EMBED_CONCURRENT=12 - Parallel embedding workers (default: 4-8)
YAMS_POST_EXTRACTION_CONCURRENT=12- Parallel content extraction (default: 4)
YAMS_POST_KG_CONCURRENT=12 - Parallel KG extraction (default: 4)
YAMS_POST_INGEST_BATCH_SIZE=24 - Documents per batch (default: 8, adaptive)
YAMS_EMBED_CHANNEL_CAPACITY=16384 - Embedding queue capacity (default: 8192)
YAMS_DB_POOL_MAX=48 - Database connection pool (default: 20)
Supported BEIR datasets (download from
https://public.ukp.informatik.tu-darmstadt.de/thakur/BEIR/datasets/): scifact - Scientific
fact verification (300 queries, 5K docs) cqadupstack - Community Q&A including programming (13K
queries, 457K docs) nfcorpus - NutritionFacts corpus (323 queries, 3.6K docs) arguana -
Argument retrieval (1.4K queries, 8.7K docs) scidocs - Scientific document similarity (1K
queries, 25K docs) fiqa - Financial question answering (648 queries, 57K docs) quora -
Duplicate question retrieval (10K queries, 523K docs) hotpotqa - Multi-hop question answering
(7.4K queries, 5.2M docs) fever - Fact verification (6.7K queries, 5.4M docs)
climate-fever - Climate claim verification (1.5K queries, 5.4M docs)
dbpedia-entity- Entity retrieval (400 queries, 4.6M docs)
trec-covid - COVID-19 retrieval (50 queries, 171K docs)
touche-2020 - Argument retrieval (49 queries, 382K docs)
Example (code-related benchmark):
mkdir -p ~/.cache/yams/benchmarks && cd ~/.cache/yams/benchmarks
curl -L -o cqadupstack.zip
https://public.ukp.informatik.tu-darmstadt.de/thakur/BEIR/datasets/cqadupstack.zip unzip
cqadupstack.zip YAMS_TEST_SAFE_SINGLE_INSTANCE=1 YAMS_BENCH_DATASET=cqadupstack
./builddir/tests/benchmarks/retrieval_quality_bench
Example (repo fixture / local manifest):
YAMS_TEST_SAFE_SINGLE_INSTANCE=1 \
YAMS_BENCH_DATASET=local-manifest \
YAMS_BENCH_DATASET_PATH=tests/benchmarks/data/retrieval_manifest_mini \
./builddir/tests/benchmarks/retrieval_quality_bench --benchmark_filter=BM_RetrievalQuality
*/
#include <sqlite3.h>
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include <benchmark/benchmark.h>
#include "retrieval_benchmark_support.h"
#include "tests/integration/daemon/test_daemon_harness.h"
#include <yams/cli/cli_sync.h>
#include <yams/cli/search_runner.h>
#include <yams/common/fs_utils.h>
#include <yams/crypto/hasher.h>
#include <yams/daemon/client/asio_connection_pool.h>
#include <yams/daemon/client/daemon_client.h>
#include <yams/daemon/components/ServiceManager.h>
#include <yams/daemon/resource/model_provider.h>
#include <yams/daemon/resource/plugin_trust.h>
#include <yams/search/internal_benchmark.h>
#include <yams/search/topology_routing_session.h>
#include <yams/topology/topology_metadata_store.h>
#include <yams/vector/vector_database.h>
#include <algorithm>
#include <cctype>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <yams/compat/unistd.h>
namespace fs = std::filesystem;
using namespace std::chrono_literals;
using namespace yams;
using json = nlohmann::json;
class BenchmarkMockModelProvider final : public yams::daemon::IModelProvider {
public:
explicit BenchmarkMockModelProvider(std::size_t dim) : dim_(dim) {}
void setProgressCallback(std::function<void(const yams::daemon::ModelLoadEvent&)> cb) override {
progress_ = std::move(cb);
}
Result<std::vector<float>> generateEmbedding(const std::string& text) override {
return generateEmbeddingFor(defaultModelName_, text);
}
Result<std::vector<std::vector<float>>>
generateBatchEmbeddings(const std::vector<std::string>& texts) override {
return generateBatchEmbeddingsFor(defaultModelName_, texts);
}
Result<std::vector<float>> generateEmbeddingFor(const std::string& modelName,
const std::string& text) override {
if (!isModelLoaded(modelName)) {
return Error{ErrorCode::NotFound, "model not loaded"};
}
std::vector<float> embedding(dim_, 0.0f);
std::hash<std::string> hasher;
const auto seed = hasher(text);
for (std::size_t i = 0; i < embedding.size(); ++i) {
embedding[i] = static_cast<float>((seed ^ (i * 131)) % 1000) / 1000.0f;
}
return embedding;
}
Result<std::vector<std::vector<float>>>
generateBatchEmbeddingsFor(const std::string& modelName,
const std::vector<std::string>& texts) override {
if (!isModelLoaded(modelName)) {
return Error{ErrorCode::NotFound, "model not loaded"};
}
std::vector<std::vector<float>> batch;
batch.reserve(texts.size());
for (const auto& text : texts) {
auto embedding = generateEmbeddingFor(modelName, text);
if (!embedding) {
return embedding.error();
}
batch.push_back(std::move(embedding.value()));
}
return batch;
}
Result<void> loadModel(const std::string& modelName) override {
if (progress_) {
yams::daemon::ModelLoadEvent ev;
ev.modelName = modelName;
ev.phase = "loading";
ev.message = "benchmark mock loading";
progress_(ev);
}
loadedModels_.insert(modelName);
defaultModelName_ = modelName;
if (progress_) {
yams::daemon::ModelLoadEvent ev;
ev.modelName = modelName;
ev.phase = "completed";
ev.message = "benchmark mock ready";
progress_(ev);
}
return Result<void>();
}
Result<void> unloadModel(const std::string& modelName) override {
loadedModels_.erase(modelName);
return Result<void>();
}
bool isModelLoaded(const std::string& modelName) const override {
return loadedModels_.contains(modelName);
}
std::vector<std::string> getLoadedModels() const override {
return std::vector<std::string>(loadedModels_.begin(), loadedModels_.end());
}
size_t getLoadedModelCount() const override { return loadedModels_.size(); }
Result<yams::daemon::ModelInfo> getModelInfo(const std::string& modelName) const override {
if (!isModelLoaded(modelName)) {
return Error{ErrorCode::NotFound, "model not loaded"};
}
yams::daemon::ModelInfo info;
info.name = modelName;
info.embeddingDim = dim_;
return info;
}
size_t getEmbeddingDim(const std::string&) const override { return dim_; }
std::shared_ptr<yams::vector::EmbeddingGenerator>
getEmbeddingGenerator(const std::string& = "") override {
return nullptr;
}
std::string getProviderName() const override { return "BenchmarkMockProvider"; }
std::string getProviderVersion() const override { return "1.0"; }
bool isAvailable() const override { return true; }
size_t getMemoryUsage() const override { return 0; }
void releaseUnusedResources() override {}
void shutdown() override { loadedModels_.clear(); }
private:
std::size_t dim_;
std::string defaultModelName_;
std::unordered_set<std::string> loadedModels_;
std::function<void(const yams::daemon::ModelLoadEvent&)> progress_;
};
template <typename T, typename Rep, typename Period>
static Result<T> benchRunSync(boost::asio::awaitable<Result<T>> aw,
const std::chrono::duration<Rep, Period>& timeout) {
return yams::cli::run_sync<T, Rep, Period>(std::move(aw), timeout);
}
static std::uint64_t parseAdditionalStat(const std::map<std::string, std::string>& stats,
std::string_view key) {
const auto it = stats.find(std::string(key));
if (it == stats.end() || it->second.empty()) {
return 0;
}
try {
return std::stoull(it->second);
} catch (...) {
return 0;
}
}
static Result<yams::search::BenchmarkDaemonGraphState>
observeDaemonGraphState(yams::daemon::DaemonClient& client) {
yams::daemon::GetStatsRequest request;
request.includeHealth = true;
auto statsResult = benchRunSync(client.getStats(request), 30s);
if (!statsResult) {
return statsResult.error();
}
const auto& stats = statsResult.value().additionalStats;
yams::search::BenchmarkDaemonGraphState state;
state.semanticDocumentsProcessed = parseAdditionalStat(stats, "embed_semantic_docs_processed");
state.semanticEdgesCreated = parseAdditionalStat(stats, "embed_semantic_edges_created");
state.semanticUpdateErrors = parseAdditionalStat(stats, "embed_semantic_update_errors");
state.topologyDocumentNodes = parseAdditionalStat(stats, "kg_topology_document_nodes");
state.topologySemanticEdges = parseAdditionalStat(stats, "kg_topology_semantic_edges");
state.topologyDocumentsWithNeighbors =
parseAdditionalStat(stats, "kg_topology_documents_with_neighbors");
state.topologyIsolatedDocuments = parseAdditionalStat(stats, "kg_topology_isolated_documents");
state.postIngestQueued = parseAdditionalStat(stats, "post_ingest_queued");
state.postIngestInFlight = parseAdditionalStat(stats, "post_ingest_inflight");
state.embeddingQueued = parseAdditionalStat(stats, "embed_svc_queued");
state.embeddingInFlight = parseAdditionalStat(stats, "embed_in_flight");
state.writeQueued = parseAdditionalStat(stats, "write_queue_depth");
state.writeInFlight = parseAdditionalStat(stats, "write_in_flight");
return state;
}
static std::string describeDaemonGraphState(const yams::search::BenchmarkDaemonGraphState& state) {
std::ostringstream message;
message << "semantic_docs_processed=" << state.semanticDocumentsProcessed
<< ", semantic_edges_created=" << state.semanticEdgesCreated
<< ", topology_document_nodes=" << state.topologyDocumentNodes
<< ", topology_semantic_edges=" << state.topologySemanticEdges
<< ", topology_documents_with_neighbors=" << state.topologyDocumentsWithNeighbors
<< ", topology_isolated_documents=" << state.topologyIsolatedDocuments
<< ", semantic_update_errors=" << state.semanticUpdateErrors
<< ", post_ingest_queued=" << state.postIngestQueued
<< ", post_ingest_in_flight=" << state.postIngestInFlight
<< ", embed_queued=" << state.embeddingQueued
<< ", embed_in_flight=" << state.embeddingInFlight
<< ", write_queued=" << state.writeQueued
<< ", write_in_flight=" << state.writeInFlight;
return message.str();
}
static Result<yams::search::BenchmarkDaemonGraphState>
waitForDaemonNativeGraph(yams::daemon::DaemonClient& client,
std::uint64_t minimumSemanticDocuments) {
spdlog::info("Waiting for daemon-native semantic graph production before query evaluation...");
const auto deadline = std::chrono::steady_clock::now() + 300s;
// Semantic-neighbor backfill is intentionally idle-only. A tight getStats loop keeps a
// non-health IPC connection active and prevents TuningManager from publishing an idle
// snapshot, so observing readiness too frequently can stop the work itself.
constexpr auto kObservationInterval = 15s;
auto observationAt = std::chrono::steady_clock::now() + kObservationInterval;
yams::search::BenchmarkDaemonGraphState state;
std::optional<yams::search::BenchmarkDaemonGraphState> previousReadyState;
while (std::chrono::steady_clock::now() < deadline) {
const auto now = std::chrono::steady_clock::now();
if (now < observationAt) {
std::this_thread::sleep_for(std::min(
500ms, std::chrono::duration_cast<std::chrono::milliseconds>(observationAt - now)));
continue;
}
observationAt = now + kObservationInterval;
auto observation = observeDaemonGraphState(client);
if (!observation) {
previousReadyState.reset();
spdlog::warn("Daemon graph observation failed: {}", observation.error().message);
continue;
}
state = std::move(observation.value());
spdlog::info("Daemon graph wait: {}", describeDaemonGraphState(state));
if (!yams::search::benchmarkDaemonGraphReady(state, minimumSemanticDocuments)) {
previousReadyState.reset();
continue;
}
if (!previousReadyState.has_value() ||
!yams::search::benchmarkDaemonGraphProductionStable(*previousReadyState, state)) {
previousReadyState = state;
continue;
}
spdlog::info("Daemon-native semantic graph ready: {}", describeDaemonGraphState(state));
return state;
}
return Error{ErrorCode::Timeout,
"Daemon-native semantic graph not ready before benchmark queries (" +
describeDaemonGraphState(state) + ")."};
}
static Result<void> exportTopologyClusters(yams::daemon::ServiceManager& serviceManager,
std::string_view snapshotId) {
const char* rawOutput = std::getenv("YAMS_BENCH_TOPOLOGY_CLUSTER_OUTPUT");
if (rawOutput == nullptr || *rawOutput == '\0') {
return {};
}
yams::topology::MetadataKgTopologyArtifactStore store(serviceManager.getMetadataRepo(),
serviceManager.getKgStore());
auto loaded = store.loadLatest(snapshotId);
if (!loaded) {
return loaded.error();
}
if (!loaded.value().has_value()) {
return Error{ErrorCode::NotFound, "topology snapshot unavailable for cluster export"};
}
const auto& snapshot = *loaded.value();
json memberships = json::array();
for (const auto& membership : snapshot.memberships) {
memberships.push_back({{"document_hash", membership.documentHash},
{"cluster_id", membership.clusterId},
{"overlap_cluster_ids", membership.overlapClusterIds}});
}
json clusters = json::array();
for (const auto& cluster : snapshot.clusters) {
clusters.push_back({{"cluster_id", cluster.clusterId},
{"member_count", cluster.memberCount},
{"overlap_cluster_ids", cluster.overlapClusterIds}});
}
const fs::path outputPath(rawOutput);
std::error_code ec;
if (!outputPath.parent_path().empty()) {
fs::create_directories(outputPath.parent_path(), ec);
if (ec) {
return Error{ErrorCode::WriteError,
"failed to create topology cluster output directory: " + ec.message()};
}
}
std::ofstream output(outputPath, std::ios::trunc);
if (!output) {
return Error{ErrorCode::WriteError, "failed to open topology cluster output"};
}
output << json{{"algorithm", snapshot.algorithm},
{"snapshot_id", snapshot.snapshotId},
{"topology_epoch", snapshot.topologyEpoch},
{"memberships", std::move(memberships)},
{"clusters", std::move(clusters)}}
.dump(2)
<< '\n';
if (!output) {
return Error{ErrorCode::WriteError, "failed to write topology cluster output"};
}
return {};
}
static Result<yams::daemon::TopologyManager::RebuildStats>
rebuildCanonicalDaemonTopology(yams::daemon::ServiceManager& serviceManager,
std::string_view topologyAlgorithm) {
auto& topologyManager = serviceManager.getTopologyManager();
const auto deadline = std::chrono::steady_clock::now() + 60s;
do {
if (topologyManager.isRebuildInProgress()) {
std::this_thread::sleep_for(50ms);
continue;
}
auto rebuilt =
topologyManager.rebuildArtifacts("benchmark_daemon_native_graph_canonicalization",
false, {}, std::string(topologyAlgorithm));
if (!rebuilt) {
return rebuilt.error();
}
if (!rebuilt.value().skipped) {
if (!rebuilt.value().stored) {
return Error{ErrorCode::InvalidState,
"canonical topology rebuild did not publish a stored snapshot"};
}
return std::move(rebuilt.value());
}
std::this_thread::sleep_for(50ms);
} while (std::chrono::steady_clock::now() < deadline);
return Error{ErrorCode::Timeout, "timed out waiting for canonical topology rebuild"};
}
static Result<std::string>
loadTopologyRoutingConstructionFingerprint(yams::daemon::ServiceManager& serviceManager,
std::string_view snapshotId) {
yams::topology::MetadataKgTopologyArtifactStore store(serviceManager.getMetadataRepo(),
serviceManager.getKgStore());
auto loaded = store.loadLatest(snapshotId);
if (!loaded) {
return loaded.error();
}
if (!loaded.value().has_value()) {
return Error{ErrorCode::NotFound,
"canonical topology snapshot unavailable for fingerprinting"};
}
return yams::search::topologyRoutingConstructionFingerprint(*loaded.value());
}
// Helper to discover GLiNER model path for entity extraction
// Searches standard locations where yams init downloads models
static std::string discoverGlinerModelPath() {
// Preferred model names in order
const std::vector<std::string> model_names = {
"gliner_small-v2.1-quantized",
"gliner_small-v2.1",
"gliner_medium-v2.1-quantized",
"gliner_medium-v2.1",
};
// Build list of base directories to search
std::vector<fs::path> search_dirs;
// YAMS_GLINT_MODEL_PATH - explicit override
if (const char* env_path = std::getenv("YAMS_GLINT_MODEL_PATH")) {
if (fs::exists(env_path)) {
spdlog::info("[Bench] Using GLiNER model from YAMS_GLINT_MODEL_PATH: {}", env_path);
return env_path;
}
}
// YAMS_DATA_DIR
if (const char* data_dir = std::getenv("YAMS_DATA_DIR")) {
search_dirs.emplace_back(fs::path(data_dir) / "models" / "gliner");
}
// YAMS_STORAGE
if (const char* storage = std::getenv("YAMS_STORAGE")) {
search_dirs.emplace_back(fs::path(storage) / "models" / "gliner");
}
// ~/.local/share/yams (XDG default)
if (const char* home = std::getenv("HOME")) {
search_dirs.emplace_back(fs::path(home) / ".local" / "share" / "yams" / "models" /
"gliner");
}
// Development path
search_dirs.emplace_back("/Volumes/picaso/yams/models/gliner");
// Homebrew path
search_dirs.emplace_back("/opt/homebrew/share/yams/models/gliner");
// Search for models
for (const auto& base_dir : search_dirs) {
if (!fs::exists(base_dir)) {
continue;
}
// Try preferred model names first
for (const auto& model_name : model_names) {
fs::path model_path = base_dir / model_name / "model.onnx";
if (fs::exists(model_path)) {
spdlog::info("[Bench] Found GLiNER model at: {}", model_path.string());
return model_path.string();
}
}
// Fall back to scanning directory for any model
std::error_code ec;
for (const auto& entry : fs::directory_iterator(base_dir, ec)) {
if (!entry.is_directory())
continue;
fs::path model_path = entry.path() / "model.onnx";
if (fs::exists(model_path)) {
spdlog::info("[Bench] Found GLiNER model at: {}", model_path.string());
return model_path.string();
}
}
}
spdlog::warn("[Bench] No GLiNER model found - entity extraction will use mock mode");
return "";
}
static bool forceMockEmbeddingsForBench() {
const char* env = std::getenv("YAMS_BENCH_FORCE_MOCK_EMBEDDINGS");
return env && std::string_view(env) == "1";
}
static void ensureBenchmarkEmbeddingsReady(yams::test::DaemonHarness* harness, bool vectorsDisabled,
bool forceMockEmbeddings, bool embedBackendSimeon) {
if (!harness || !harness->daemon() || vectorsDisabled) {
return;
}
auto serviceManager = harness->daemon()->getServiceManager();
if (!serviceManager) {
return;
}
if (forceMockEmbeddings) {
std::size_t dim = 768;
if (auto vectorDb = serviceManager->getVectorDatabase()) {
dim = vectorDb->getConfig().embedding_dim;
}
auto sharedProvider = std::make_shared<BenchmarkMockModelProvider>(dim);
serviceManager->__test_setModelProvider(sharedProvider);
}
if (embedBackendSimeon) {
auto ready = serviceManager->ensureEmbeddingModelReadySync("simeon-default", {}, 10000,
false, false);
if (!ready) {
spdlog::warn("[Bench] Simeon provider not ready for retrieval bench: {}",
ready.error().message);
}
return;
}
auto ready =
serviceManager->ensureEmbeddingModelReadySync("all-MiniLM-L6-v2", {}, 10000, false, false);
if (!ready) {
spdlog::warn("[Bench] Embedding model not ready for retrieval bench: {}",
ready.error().message);
}
}
using yams::bench::BEIRCorpusLoader;
using yams::bench::BEIRDataset;
using yams::bench::BEIRDocument;
using yams::bench::BEIRQuery;
using yams::bench::CorpusGenerator;
using yams::bench::RetrievalMetrics;
using yams::bench::StageMetricAccumulator;
using yams::bench::SyntheticCorpusMode;
using yams::bench::TestQuery;
static Result<BEIRDataset> loadSciFactDataset(const fs::path& cacheDir) {
const char* home = std::getenv("HOME");
if (!home) {
return Error{ErrorCode::InvalidArgument, "HOME environment variable not set"};
}
fs::path scifactDir =
cacheDir.empty() ? fs::path(home) / ".cache" / "yams" / "benchmarks" / "scifact" : cacheDir;
BEIRDataset dataset;
dataset.name = "SciFact";
dataset.basePath = scifactDir;
fs::path corpusFile = scifactDir / "corpus.jsonl";
fs::path queriesFile = scifactDir / "queries.jsonl";
fs::path qrelsFile = scifactDir / "qrels" / "test.tsv"; // Standard BEIR structure
if (!fs::exists(corpusFile) || !fs::exists(queriesFile) || !fs::exists(qrelsFile)) {
return Error{
ErrorCode::NotFound,
"SciFact dataset not found. Please download manually:\n"
" mkdir -p ~/.cache/yams/benchmarks && cd ~/.cache/yams/benchmarks\n"
" curl -L -o scifact.zip "
"https://public.ukp.informatik.tu-darmstadt.de/thakur/BEIR/datasets/scifact.zip\n"
" unzip scifact.zip"};
}
std::ifstream corpusIn(corpusFile);
std::string line;
while (std::getline(corpusIn, line)) {
if (line.empty())
continue;
try {
auto j = json::parse(line);
BEIRDocument doc;
doc.id = j.value("_id", "");
if (doc.id.empty())
doc.id = j.value("id", "");
doc.title = j.value("title", "");
doc.text = j.value("text", "");
if (!doc.id.empty() && !doc.text.empty()) {
dataset.documents[doc.id] = doc;
}
} catch (const json::exception& e) {
spdlog::warn("Failed to parse corpus line: {}", e.what());
}
}
corpusIn.close();
std::ifstream queriesIn(queriesFile);
while (std::getline(queriesIn, line)) {
if (line.empty())
continue;
try {
auto j = json::parse(line);
BEIRQuery q;
q.id = j.value("_id", "");
if (q.id.empty())
q.id = j.value("id", "");
q.text = j.value("text", "");
if (!q.id.empty() && !q.text.empty()) {
dataset.queries[q.id] = q;
}
} catch (const json::exception& e) {
spdlog::warn("Failed to parse query line: {}", e.what());
}
}
queriesIn.close();
std::ifstream qrelsIn(qrelsFile);
bool firstLine = true;
while (std::getline(qrelsIn, line)) {
if (line.empty() || line[0] == '#')
continue;
// Skip header row
if (firstLine) {
firstLine = false;
if (line.find("query-id") != std::string::npos)
continue;
}
std::istringstream iss(line);
std::string queryId, docId, scoreStr;
// BEIR format: query-id, corpus-id, score (3 columns, no iteration)
if (std::getline(iss, queryId, '\t') && std::getline(iss, docId, '\t') &&
std::getline(iss, scoreStr, '\t')) {
int score = std::stoi(scoreStr);
dataset.qrels.emplace(queryId, yams::bench::BEIRQrel{.docId = docId, .score = score});
}
}
qrelsIn.close();
spdlog::info("Loaded BEIR dataset: {} documents, {} queries, {} qrels",
dataset.documents.size(), dataset.queries.size(), dataset.qrels.size());
return dataset;
}
// Generic BEIR dataset loader — delegates to yams::bench::loadBEIRDataset.
static Result<BEIRDataset> loadBEIRDataset(const std::string& datasetName,
const fs::path& cacheDir) {
if (datasetName == "local-manifest") {
return yams::bench::loadBenchmarkManifestDataset(datasetName, cacheDir);
}
return yams::bench::loadBEIRDataset(datasetName, cacheDir);
}
static Result<BEIRDataset> selectBenchmarkBEIRDataset(const std::string& datasetName,
const fs::path& cacheDir,
const std::optional<int>& maxDocsOpt,
const std::optional<int>& maxQueriesOpt) {
Result<BEIRDataset> dsResult;
if (datasetName == "scifact") {
dsResult = loadSciFactDataset(cacheDir);
} else {
dsResult = loadBEIRDataset(datasetName, cacheDir);
}
if (!dsResult) {
return dsResult;
}
const BEIRDataset& fullDataset = dsResult.value();
BEIRDataset dataset;
dataset.name = fullDataset.name;
dataset.basePath = fullDataset.basePath;
const int maxDocs =
maxDocsOpt.has_value() ? *maxDocsOpt : static_cast<int>(fullDataset.documents.size());
const int maxQueries =
maxQueriesOpt.has_value() ? *maxQueriesOpt : static_cast<int>(fullDataset.queries.size());
std::set<std::string> qrelDocIds;
for (const auto& [queryId, docScore] : fullDataset.qrels) {
(void)queryId;
qrelDocIds.insert(docScore.docId);
}
spdlog::info("BEIR dataset has {} documents referenced by qrels", qrelDocIds.size());
std::set<std::string> includedDocIds;
for (const auto& docId : qrelDocIds) {
if (static_cast<int>(includedDocIds.size()) >= maxDocs) {
break;
}
if (fullDataset.documents.count(docId) > 0) {
dataset.documents[docId] = fullDataset.documents.at(docId);
includedDocIds.insert(docId);
}
}
spdlog::info("Included {} qrel-referenced documents", includedDocIds.size());
for (const auto& [id, doc] : fullDataset.documents) {
if (static_cast<int>(includedDocIds.size()) >= maxDocs) {
break;
}
if (includedDocIds.count(id) == 0) {
dataset.documents[id] = doc;
includedDocIds.insert(id);
}
}
int queryCount = 0;
for (const auto& [qid, query] : fullDataset.queries) {
if (queryCount >= maxQueries) {
break;
}
auto range = fullDataset.qrels.equal_range(qid);
bool hasRelevantDoc = false;
for (auto it = range.first; it != range.second; ++it) {
if (includedDocIds.count(it->second.docId) > 0) {
hasRelevantDoc = true;
break;
}
}
if (!hasRelevantDoc) {
continue;
}
dataset.queries[qid] = query;
for (auto it = range.first; it != range.second; ++it) {
if (includedDocIds.count(it->second.docId) > 0) {
dataset.qrels.emplace(qid, it->second);
}
}
queryCount++;
}
for (const auto& entity : fullDataset.kgEntities) {
if (includedDocIds.contains(entity.docId)) {
dataset.kgEntities.push_back(entity);
}
}
spdlog::debug(
"Limited BEIR dataset to {} docs, {} queries, {} qrels, {} kg entities (from {} docs, {} "
"queries)",
dataset.documents.size(), dataset.queries.size(), dataset.qrels.size(),
dataset.kgEntities.size(), fullDataset.documents.size(), fullDataset.queries.size());
return dataset;
}
using yams::test::DaemonHarness;
struct QueryDiagnosticsSummary {
std::uint64_t queryCount = 0;
std::uint64_t queryWithResultsCount = 0;
std::uint64_t queryWithoutResultsCount = 0;
std::uint64_t queryWithoutRelevantHitCount = 0;
std::uint64_t queryWithRelevantInPreFusionCount = 0;
std::uint64_t queryWithRelevantInPostFusionCount = 0;
std::uint64_t queryWithRelevantInGraphlessPostFusionCount = 0;
std::uint64_t queryWithRelevantInFinalWindowCount = 0;
std::uint64_t queryWithGraphAddedRelevantPostFusionCount = 0;
std::uint64_t queryWithGraphDisplacedRelevantPostFusionCount = 0;
std::uint64_t queryWithTopologyAddedRelevantPostFusionCount = 0;
std::uint64_t queryWithTopologyAddedRelevantFusionDroppedCount = 0;
std::uint64_t queryWithTopKDuplicateCount = 0;
std::uint64_t degradedQueryCount = 0;
std::uint64_t traceEnabledQueryCount = 0;
std::uint64_t graphRerankAppliedQueryCount = 0;
std::uint64_t compressedAnnEnabledQueryCount = 0;
std::uint64_t compressedAnnAppliedQueryCount = 0;
std::uint64_t semanticRescueNonZeroQueryCount = 0;
std::uint64_t missMissingPreFusionCount = 0;
std::uint64_t missFusionCutoffCount = 0;
std::uint64_t missRerankWindowDropCount = 0;
std::uint64_t missTopKDropCount = 0;
std::vector<double> semanticRescueRateSamples;
std::vector<double> semanticRescueFinalCountSamples;
std::vector<double> semanticRescueTargetSamples;
std::vector<double> compressedAnnResultCountSamples;
std::unordered_map<std::string, std::uint64_t> compressedAnnSkipReasonCounts;
std::vector<double> fusionPreFusionUniqueCountSamples;
std::vector<double> fusionPostFusionCountSamples;
std::vector<double> fusionDroppedCountSamples;
std::vector<double> fusionDroppedRateSamples;
std::vector<double> anchoredPreFusionCountSamples;
std::vector<double> anchoredFusionDroppedCountSamples;
std::vector<double> anchoredFusionDroppedRateSamples;
std::vector<double> topTextPreFusionCountSamples;
std::vector<double> topTextFusionDroppedCountSamples;
std::vector<double> topTextFusionDroppedRateSamples;
std::vector<double> vectorOnlyDocsSamples;
std::vector<double> vectorOnlyBelowThresholdSamples;
std::vector<double> vectorOnlyAboveThresholdSamples;
std::vector<double> vectorOnlyNearMissEligibleSamples;
std::uint64_t adaptiveFusionEnabledQueryCount = 0;
std::vector<double> strongVectorOnlyDocsSamples;
std::vector<double> strongVectorOnlyScoreEligibleDocsSamples;
std::vector<double> strongVectorOnlyRankEligibleDocsSamples;
std::vector<double> graphAddedPostFusionSamples;
std::vector<double> graphDisplacedPostFusionSamples;
std::vector<double> topologyRoutedDocsSamples;
std::vector<double> topologyRouteBestScoreSamples;
std::vector<double> topologyRouteMeanAcceptedScoreSamples;
std::vector<double> topologyRouteAcceptedCountSamples;
std::vector<double> topologySeedCountSamples;
std::vector<double> topologySeedCoverageCountSamples;
std::vector<double> topologyCoreCandidateCoverageSamples;
std::vector<double> topologyAddedCandidatesSamples;
std::vector<double> topologyDuplicateCandidatesSamples;
std::vector<double> topologyStaleCandidatesSamples;
std::vector<double> graphCommunitySupportedDocsSamples;
std::vector<double> graphCommunityEdgeCountSamples;
std::vector<double> graphCommunityLargestSizeSamples;
std::vector<double> graphCommunitySignalMassSamples;
std::vector<double> graphCommunityBoostedDocsSamples;
std::vector<double> graphCommunityWeightSamples;
std::vector<double> multiVectorGeneratedPhraseSamples;
std::vector<double> multiVectorRawHitSamples;
std::vector<double> multiVectorAddedNewSamples;
std::vector<double> multiVectorReplacedBaseSamples;
std::vector<double> subPhraseGeneratedSamples;
std::vector<double> subPhraseClauseSamples;
std::vector<double> subPhraseFtsHitSamples;
std::vector<double> subPhraseFtsAddedSamples;
std::vector<double> aggressiveFtsClauseSamples;
std::vector<double> aggressiveFtsHitSamples;
std::vector<double> aggressiveFtsAddedSamples;
std::unordered_map<std::string, std::vector<double>> timingSamplesMs;
std::unordered_map<std::string, std::uint64_t> stageEnabledCount;
std::unordered_map<std::string, std::uint64_t> stageAttemptedCount;
std::unordered_map<std::string, std::uint64_t> stageContributedCount;
std::unordered_map<std::string, std::uint64_t> stageSkippedCount;
std::unordered_map<std::string, std::uint64_t> stageRelevantPresenceCount;
std::unordered_map<std::string, std::vector<std::string>> stageSkipReasons;
std::unordered_map<std::string, std::vector<double>> fusionSourceScoreMassSamples;
std::unordered_map<std::string, std::vector<double>> fusionSourceFinalDocSamples;
std::unordered_map<std::string, std::vector<double>> stageUniqueDocCountSamples;
std::unordered_map<std::string, std::vector<double>> stageRelevantDocCountSamples;
std::map<std::string, StageMetricAccumulator> stageRetrievalMetrics;
std::unordered_map<std::string, std::vector<double>> tunerSignalSamples;
std::unordered_map<std::string, std::uint64_t> tunerDecisionCounts;
std::unordered_map<std::string, std::uint64_t> zoomLevelCounts;
};
static const std::vector<std::string>& trackedTimingKeys() {
static const std::vector<std::string> kKeys = {
"latency",
"embedding",
"concepts",
"text",
"vector",
"entity_vector",
"kg",
"path",
"tag",
"metadata",
"multi_vector",
"graph_rerank",
"topology_weak_query",
"topology_load",
"topology_validate",
"topology_request_prep",
"topology_route",
"topology_cluster_lookup",
"topology_doc_lookup",
"topology_candidate_insert",
};
return kKeys;
}
static std::string timingStatKey(const std::string& name) {
return std::string("timing_") + name + "_ms";
}
static std::unordered_set<std::string> splitTabSet(const std::string& value) {
std::unordered_set<std::string> out;
if (value.empty()) {
return out;
}
size_t start = 0;
while (start <= value.size()) {
const size_t end = value.find('\t', start);
const size_t len = (end == std::string::npos) ? (value.size() - start) : (end - start);
if (len > 0) {
out.insert(value.substr(start, len));
}
if (end == std::string::npos) {
break;
}
start = end + 1;
}
return out;
}
static std::vector<std::string> splitTabList(const std::string& value, size_t limit) {
std::vector<std::string> out;
if (value.empty() || limit == 0) {
return out;
}
size_t start = 0;
while (start <= value.size() && out.size() < limit) {
const size_t end = value.find('\t', start);
const size_t len = (end == std::string::npos) ? (value.size() - start) : (end - start);
if (len > 0) {
out.push_back(value.substr(start, len));
}
if (end == std::string::npos) {
break;
}
start = end + 1;
}
return out;
}
static std::optional<size_t> findRankInTabList(const std::string& value,
const std::string& needle) {
if (value.empty() || needle.empty()) {
return std::nullopt;
}
size_t start = 0;
size_t rank = 0;
while (start <= value.size()) {
const size_t end = value.find('\t', start);
const size_t len = (end == std::string::npos) ? (value.size() - start) : (end - start);
if (len > 0) {
++rank;
if (value.compare(start, len, needle) == 0 && len == needle.size()) {
return rank;
}
}
if (end == std::string::npos) {
break;
}
start = end + 1;
}
return std::nullopt;
}
static json buildRelevantDecisionTrace(const std::vector<std::string>& relevantDocIds,
const std::vector<std::string>& returnedDocIds,
const std::map<std::string, std::string>& searchStats) {
const std::string preFusionDocIds = searchStats.contains("trace_pre_fusion_doc_ids")
? searchStats.at("trace_pre_fusion_doc_ids")
: "";
const std::string postFusionDocIds = searchStats.contains("trace_post_fusion_doc_ids")
? searchStats.at("trace_post_fusion_doc_ids")
: "";
const std::string graphlessPostFusionDocIds =
searchStats.contains("trace_graphless_post_fusion_doc_ids")
? searchStats.at("trace_graphless_post_fusion_doc_ids")
: "";
const std::string finalWindowDocIds =
searchStats.contains("trace_final_doc_ids") ? searchStats.at("trace_final_doc_ids") : "";
const auto preSet = splitTabSet(searchStats.contains("trace_pre_fusion_doc_ids")
? searchStats.at("trace_pre_fusion_doc_ids")
: "");
const auto postSet = splitTabSet(searchStats.contains("trace_post_fusion_doc_ids")
? searchStats.at("trace_post_fusion_doc_ids")
: "");
const auto graphlessPostSet =
splitTabSet(searchStats.contains("trace_graphless_post_fusion_doc_ids")
? searchStats.at("trace_graphless_post_fusion_doc_ids")
: "");
const auto finalWindowSet = splitTabSet(
searchStats.contains("trace_final_doc_ids") ? searchStats.at("trace_final_doc_ids") : "");
std::string topologyAddedIds;
for (const std::string_view key : {
std::string_view{"topology_candidate_rescue_added_candidate_doc_ids"},
std::string_view{"topology_candidate_rescue_added_candidate_hashes"},
std::string_view{"topology_weak_query_added_candidate_doc_ids"},
std::string_view{"topology_weak_query_added_candidate_hashes"},
}) {
if (const auto it = searchStats.find(std::string(key));
it != searchStats.end() && !it->second.empty()) {
topologyAddedIds = it->second;
break;
}
}
const auto topologyAddedSet = splitTabSet(topologyAddedIds);
const auto topologyNovelSet =
splitTabSet(searchStats.contains("topology_candidate_rescue_novel_candidate_doc_ids")
? searchStats.at("topology_candidate_rescue_novel_candidate_doc_ids")
: "");
const auto topologyEvidenceRescueSet =
splitTabSet(searchStats.contains("topology_candidate_rescue_evidence_rescue_doc_ids")
? searchStats.at("topology_candidate_rescue_evidence_rescue_doc_ids")
: "");
const std::unordered_set<std::string> returnedTopKSet(returnedDocIds.begin(),
returnedDocIds.end());
json fusionTop = json::array();
if (auto it = searchStats.find("trace_fusion_top_json"); it != searchStats.end()) {
try {
fusionTop = json::parse(it->second);
} catch (...) {
}
}
json finalTop = json::array();
if (auto it = searchStats.find("trace_final_top_json"); it != searchStats.end()) {
try {
finalTop = json::parse(it->second);
} catch (...) {
}
}
json componentHits = json::object();
if (auto it = searchStats.find("trace_component_hits_json"); it != searchStats.end()) {
try {
componentHits = json::parse(it->second);
} catch (...) {
}
}
json stageSummary = json::object();
if (auto it = searchStats.find("trace_stage_summary_json"); it != searchStats.end()) {
try {
stageSummary = json::parse(it->second);
} catch (...) {
}
}
const auto findDoc = [](const json& docs, const std::string& docId) -> json {
if (!docs.is_array()) {
return json();
}
for (const auto& item : docs) {
if (item.is_object() && item.value("doc_id", "") == docId) {
return item;
}
}
return json();
};
const auto findComponentHit = [](const json& componentHitsJson,
const std::string& docId) -> json {
if (!componentHitsJson.is_object()) {
return json::array();
}
json matches = json::array();
for (const auto& [component, details] : componentHitsJson.items()) {
if (!details.is_object()) {
continue;
}
const auto hitsIt = details.find("top_hits");
if (hitsIt == details.end() || !hitsIt->is_array()) {
continue;
}
for (const auto& hit : *hitsIt) {
if (!hit.is_object() || hit.value("doc_id", "") != docId) {
continue;
}
json entry = hit;
entry["component"] = component;
matches.push_back(std::move(entry));
break;
}
}
return matches;
};
json relevant = json::array();
bool anyPre = false;
bool anyPost = false;
bool anyGraphlessPost = false;
bool anyFinalWindow = false;
bool anyReturnedTopK = false;
json graphAddedRelevant = json::array();
json graphDisplacedRelevant = json::array();
json topologyAddedRelevantPostFusion = json::array();
json topologyAddedRelevantDroppedByFusion = json::array();
json stageRelevantPresence = json::object();
if (stageSummary.is_object()) {
for (const auto& [stageName, stageData] : stageSummary.items()) {
if (!stageData.is_object()) {
continue;
}
bool anyRelevant = false;
std::size_t relevantDocCount = 0;
if (auto idsIt = stageData.find("unique_doc_ids");
idsIt != stageData.end() && idsIt->is_array()) {
for (const auto& id : *idsIt) {
if (!id.is_string()) {
continue;
}
if (std::find(relevantDocIds.begin(), relevantDocIds.end(),
id.get<std::string>()) != relevantDocIds.end()) {
anyRelevant = true;
++relevantDocCount;
}
}
}
stageRelevantPresence[stageName] = {
{"enabled", stageData.value("enabled", false)},
{"attempted", stageData.value("attempted", false)},
{"contributed", stageData.value("contributed", false)},
{"unique_doc_count", stageData.value("unique_doc_count", 0UL)},
{"any_relevant", anyRelevant},
{"relevant_doc_count", relevantDocCount},
};
}
}
for (const auto& docId : relevantDocIds) {
const bool inPre = preSet.contains(docId);
const bool inPost = postSet.contains(docId);
const bool inGraphlessPost = graphlessPostSet.contains(docId);
const bool inFinalWindow = finalWindowSet.contains(docId);
const bool inReturnedTopK = returnedTopKSet.contains(docId);
anyPre = anyPre || inPre;
anyPost = anyPost || inPost;
anyGraphlessPost = anyGraphlessPost || inGraphlessPost;
anyFinalWindow = anyFinalWindow || inFinalWindow;
anyReturnedTopK = anyReturnedTopK || inReturnedTopK;
if (inPost && !inGraphlessPost) {
graphAddedRelevant.push_back(docId);
}
if (inGraphlessPost && !inPost) {
graphDisplacedRelevant.push_back(docId);
}
const bool topologyAddedCandidate = topologyAddedSet.contains(docId);
const bool topologyNovelCandidate = topologyNovelSet.contains(docId);
const bool topologyEvidenceRescue = topologyEvidenceRescueSet.contains(docId);
if (topologyAddedCandidate && inPost) {
topologyAddedRelevantPostFusion.push_back(docId);
}
if (topologyAddedCandidate && !inPost) {
topologyAddedRelevantDroppedByFusion.push_back(docId);
}
json componentSources = json::array();
if (componentHits.is_object()) {
for (const auto& [component, details] : componentHits.items()) {
if (!details.is_object()) {
continue;
}
const auto topIdsIt = details.find("unique_top_doc_ids");
if (topIdsIt == details.end() || !topIdsIt->is_array()) {
continue;
}
for (const auto& id : *topIdsIt) {
if (id.is_string() && id.get<std::string>() == docId) {
componentSources.push_back(component);
break;
}
}
}
}
json entry = {
{"doc_id", docId},
{"in_pre_fusion", inPre},
{"in_post_fusion", inPost},
{"in_graphless_post_fusion", inGraphlessPost},
{"in_final_window", inFinalWindow},
{"in_returned_topk", inReturnedTopK},
{"topology_added_candidate", topologyAddedCandidate},
{"topology_novel_candidate", topologyNovelCandidate},
{"topology_evidence_rescue", topologyEvidenceRescue},
{"component_top_hits", componentSources},
{"component_top_hit_details", findComponentHit(componentHits, docId)},
};
const auto assignOptionalRank = [&entry](std::string_view key,
const std::optional<size_t>& rank) {
if (rank.has_value()) {
entry[std::string(key)] = *rank;
} else {
entry[std::string(key)] = nullptr;
}
};
assignOptionalRank("pre_fusion_rank", findRankInTabList(preFusionDocIds, docId));
assignOptionalRank("post_fusion_rank", findRankInTabList(postFusionDocIds, docId));
assignOptionalRank("graphless_post_fusion_rank",
findRankInTabList(graphlessPostFusionDocIds, docId));
assignOptionalRank("final_window_rank", findRankInTabList(finalWindowDocIds, docId));
if (auto match = findDoc(fusionTop, docId); !match.is_null()) {
entry["post_fusion"] = match;
}
if (auto match = findDoc(finalTop, docId); !match.is_null()) {
entry["final_window"] = match;
}
relevant.push_back(std::move(entry));
}
std::string missStage = "hit";
if (!anyReturnedTopK) {
if (!anyPre) {
missStage = "missing_pre_fusion";
} else if (!anyPost) {
missStage = "dropped_before_fusion_window";
} else if (!anyFinalWindow) {
missStage = "dropped_during_rerank_window";
} else {
missStage = "dropped_before_topk";
}
}
return {
{"trace_enabled",
searchStats.contains("trace_enabled") && searchStats.at("trace_enabled") == "1"},
{"graph_rerank_applied", searchStats.contains("trace_graph_rerank_applied") &&
searchStats.at("trace_graph_rerank_applied") == "1"},
{"cross_rerank_applied", searchStats.contains("trace_cross_rerank_applied") &&
searchStats.at("trace_cross_rerank_applied") == "1"},
{"any_relevant_in_pre_fusion", anyPre},
{"any_relevant_in_post_fusion", anyPost},
{"any_relevant_in_graphless_post_fusion", anyGraphlessPost},
{"any_relevant_in_final_window", anyFinalWindow},
{"any_relevant_in_returned_topk", anyReturnedTopK},
{"graph_added_relevant_post_fusion_count", graphAddedRelevant.size()},
{"graph_displaced_relevant_post_fusion_count", graphDisplacedRelevant.size()},
{"graph_added_relevant_post_fusion_doc_ids", graphAddedRelevant},
{"graph_displaced_relevant_post_fusion_doc_ids", graphDisplacedRelevant},
{"topology_added_relevant_post_fusion_count", topologyAddedRelevantPostFusion.size()},
{"topology_added_relevant_fusion_dropped_count",
topologyAddedRelevantDroppedByFusion.size()},
{"topology_added_relevant_post_fusion_doc_ids", topologyAddedRelevantPostFusion},
{"topology_added_relevant_fusion_dropped_doc_ids", topologyAddedRelevantDroppedByFusion},
{"stage_relevant_presence", stageRelevantPresence},
{"miss_stage", missStage},
{"relevant_docs", relevant},
};
}
struct DebugLogEntry {
std::string query;
int queryIndex = -1;
std::string searchType;
std::vector<std::string> relevantDocIds;
std::vector<std::string> relevantFiles;
std::vector<std::string> returnedPaths;
std::vector<std::string> returnedDocIds;
std::vector<float> returnedScores;
std::vector<int> returnedGrades;
std::vector<std::string> diagnostics;
std::uint64_t attempts = 0;
bool usedStreaming = false;
bool usedFuzzyFlag = false;
bool usedLiteralFlag = false;
bool usedFuzzyRetry = false;
bool usedLiteralTextRetry = false;
std::map<std::string, std::string> searchStats;
json extraFields;
};
struct DebugRunContext {
std::string runId;
std::string candidate;
std::string dataset;
int corpusSize = 0;
int numQueries = 0;
int topK = 0;
int traceTopN = 0;
int traceComponentTopN = 0;
bool stageTraceEnabled = false;
std::string debugFile;
};
static std::ostream* g_debugOut = nullptr;
static std::unique_ptr<std::ofstream> g_debugFile;
static std::mutex g_debugMutex;
static std::optional<DebugRunContext> g_debugRunContext;
static std::optional<double> parseDoubleLoose(const std::string& value) {
try {
return std::stod(value);
} catch (...) {
return std::nullopt;
}
}
static std::optional<double> parseDoubleStat(const std::map<std::string, std::string>& stats,
const std::string& key) {
if (auto it = stats.find(key); it != stats.end()) {
return parseDoubleLoose(it->second);
}
return std::nullopt;
}
static std::optional<bool> parseBoolStat(const std::map<std::string, std::string>& stats,
const std::string& key) {
if (auto it = stats.find(key); it != stats.end()) {
std::string normalized = it->second;
std::transform(normalized.begin(), normalized.end(), normalized.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
return normalized == "1" || normalized == "true" || normalized == "yes" ||
normalized == "on";
}
return std::nullopt;
}
static std::optional<json> parseJsonStat(const std::map<std::string, std::string>& stats,
const std::string& key) {
if (auto it = stats.find(key); it != stats.end() && !it->second.empty()) {
try {
return json::parse(it->second);
} catch (...) {
}
}
return std::nullopt;
}
static double computePercentile(std::vector<double> samples, double percentile) {
if (samples.empty()) {
return 0.0;
}
percentile = std::clamp(percentile, 0.0, 1.0);
std::sort(samples.begin(), samples.end());
const double idx = percentile * static_cast<double>(samples.size() - 1);
const auto lo = static_cast<std::size_t>(std::floor(idx));
const auto hi = static_cast<std::size_t>(std::ceil(idx));
if (lo == hi) {
return samples[lo];
}
const double t = idx - static_cast<double>(lo);
return samples[lo] * (1.0 - t) + samples[hi] * t;
}
static json summarizeSamples(const std::vector<double>& samples) {
json out = {
{"count", samples.size()},
{"mean", 0.0},
{"min", 0.0},
{"p50", 0.0},
{"p95", 0.0},
{"max", 0.0},
};
if (samples.empty()) {
return out;
}
const double sum = std::accumulate(samples.begin(), samples.end(), 0.0);
out["mean"] = sum / static_cast<double>(samples.size());
out["min"] = *std::min_element(samples.begin(), samples.end());
out["p50"] = computePercentile(samples, 0.50);
out["p95"] = computePercentile(samples, 0.95);
out["max"] = *std::max_element(samples.begin(), samples.end());
return out;
}
static void ingestQueryDiagnostics(QueryDiagnosticsSummary& summary,
const std::map<std::string, std::string>& searchStats,
const json& relevantDecisionTrace, bool degraded,
bool hadResults, bool hadTopKDuplicate, int firstRelevantRank) {
summary.queryCount++;
if (hadResults) {
summary.queryWithResultsCount++;
} else {
summary.queryWithoutResultsCount++;
}
if (firstRelevantRank < 0) {
summary.queryWithoutRelevantHitCount++;
}
if (hadTopKDuplicate) {
summary.queryWithTopKDuplicateCount++;
}
if (degraded) {
summary.degradedQueryCount++;
}
if (relevantDecisionTrace.is_object()) {
const bool anyPre = relevantDecisionTrace.value("any_relevant_in_pre_fusion", false);
const bool anyPost = relevantDecisionTrace.value("any_relevant_in_post_fusion", false);
const bool anyGraphlessPost =
relevantDecisionTrace.value("any_relevant_in_graphless_post_fusion", false);
const bool anyFinalWindow =
relevantDecisionTrace.value("any_relevant_in_final_window", false);
if (anyPre) {
summary.queryWithRelevantInPreFusionCount++;
}
if (anyPost) {
summary.queryWithRelevantInPostFusionCount++;
}
if (anyGraphlessPost) {
summary.queryWithRelevantInGraphlessPostFusionCount++;
}
if (anyFinalWindow) {
summary.queryWithRelevantInFinalWindowCount++;
}
if (relevantDecisionTrace.value("graph_added_relevant_post_fusion_count", 0) > 0) {
summary.queryWithGraphAddedRelevantPostFusionCount++;
}
if (relevantDecisionTrace.value("graph_displaced_relevant_post_fusion_count", 0) > 0) {
summary.queryWithGraphDisplacedRelevantPostFusionCount++;
}
if (relevantDecisionTrace.value("topology_added_relevant_post_fusion_count", 0) > 0) {
summary.queryWithTopologyAddedRelevantPostFusionCount++;
}
if (relevantDecisionTrace.value("topology_added_relevant_fusion_dropped_count", 0) > 0) {
summary.queryWithTopologyAddedRelevantFusionDroppedCount++;
}
if (firstRelevantRank < 0) {
const std::string missStage = relevantDecisionTrace.value("miss_stage", "unknown");
if (missStage == "missing_pre_fusion") {
summary.missMissingPreFusionCount++;
} else if (missStage == "dropped_before_fusion_window") {
summary.missFusionCutoffCount++;
} else if (missStage == "dropped_during_rerank_window") {
summary.missRerankWindowDropCount++;
} else if (missStage == "dropped_before_topk") {
summary.missTopKDropCount++;
}
}
}
if (parseBoolStat(searchStats, "trace_enabled").value_or(false)) {
summary.traceEnabledQueryCount++;
}
if (parseBoolStat(searchStats, "trace_graph_rerank_applied").value_or(false)) {
summary.graphRerankAppliedQueryCount++;
}
if (auto it = searchStats.find("trace_zoom_level");
it != searchStats.end() && !it->second.empty()) {
summary.zoomLevelCounts[it->second]++;
}
bool compressedAnnEnabled =
parseBoolStat(searchStats, "compressed_ann_enabled").value_or(false);
bool compressedAnnApplied =
parseBoolStat(searchStats, "compressed_ann_applied").value_or(false);
std::optional<std::string> compressedAnnSkipReason;
if (auto it = searchStats.find("compressed_ann_skip_reason");
it != searchStats.end() && !it->second.empty()) {
compressedAnnSkipReason = it->second;
}
if (auto stageSummary = parseJsonStat(searchStats, "trace_stage_summary_json");
stageSummary && stageSummary->is_object()) {
if (auto stageIt = stageSummary->find("compressed_ann");
stageIt != stageSummary->end() && stageIt->is_object()) {
compressedAnnEnabled = stageIt->value("enabled", compressedAnnEnabled);
compressedAnnApplied = stageIt->value("contributed", compressedAnnApplied);
if (stageIt->value("skipped", false)) {
auto stageSkipReason = stageIt->value("skip_reason", std::string{});
if (!stageSkipReason.empty()) {
compressedAnnSkipReason = stageSkipReason;
}
} else if (stageIt->value("attempted", false) &&
compressedAnnSkipReason == "adaptive_vector_skip") {
compressedAnnSkipReason.reset();
}
}
}
if (compressedAnnEnabled) {
summary.compressedAnnEnabledQueryCount++;
}
if (compressedAnnApplied) {
summary.compressedAnnAppliedQueryCount++;
}
if (auto v = parseDoubleStat(searchStats, "compressed_ann_result_count")) {
summary.compressedAnnResultCountSamples.push_back(*v);
}
if (compressedAnnSkipReason.has_value() && !compressedAnnSkipReason->empty()) {
summary.compressedAnnSkipReasonCounts[*compressedAnnSkipReason]++;
}
if (auto v = parseDoubleStat(searchStats, "semantic_rescue_rate")) {
summary.semanticRescueRateSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "semantic_rescue_final_count")) {
summary.semanticRescueFinalCountSamples.push_back(*v);
if (*v > 0.0) {
summary.semanticRescueNonZeroQueryCount++;
}
}
if (auto v = parseDoubleStat(searchStats, "semantic_rescue_target")) {
summary.semanticRescueTargetSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "fusion_pre_fusion_unique_count")) {
summary.fusionPreFusionUniqueCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "fusion_post_fusion_count")) {
summary.fusionPostFusionCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "fusion_dropped_count")) {
summary.fusionDroppedCountSamples.push_back(*v);
} else if (auto v = parseDoubleStat(searchStats, "trace_fusion_dropped_count")) {
summary.fusionDroppedCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "fusion_dropped_rate")) {
summary.fusionDroppedRateSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_weak_query_routed_docs")) {
summary.topologyRoutedDocsSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_route_best_score")) {
summary.topologyRouteBestScoreSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_route_mean_accepted_score")) {
summary.topologyRouteMeanAcceptedScoreSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_route_accepted_count")) {
summary.topologyRouteAcceptedCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_seed_count")) {
summary.topologySeedCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_seed_coverage_count")) {
summary.topologySeedCoverageCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_core_candidate_coverage")) {
summary.topologyCoreCandidateCoverageSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_weak_query_added_candidates")) {
summary.topologyAddedCandidatesSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_weak_query_duplicate_candidates")) {
summary.topologyDuplicateCandidatesSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "topology_weak_query_stale_candidates")) {
summary.topologyStaleCandidatesSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "anchored_pre_fusion_count")) {
summary.anchoredPreFusionCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "anchored_fusion_dropped_count")) {
summary.anchoredFusionDroppedCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "anchored_fusion_dropped_rate")) {
summary.anchoredFusionDroppedRateSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "top_text_pre_fusion_count")) {
summary.topTextPreFusionCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "top_text_fusion_dropped_count")) {
summary.topTextFusionDroppedCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "top_text_fusion_dropped_rate")) {
summary.topTextFusionDroppedRateSamples.push_back(*v);
}
const bool hasDirectPreFusionStats = searchStats.find("vector_only_docs") != searchStats.end();
if (auto v = parseDoubleStat(searchStats, "vector_only_docs")) {
summary.vectorOnlyDocsSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "vector_only_below_threshold")) {
summary.vectorOnlyBelowThresholdSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "vector_only_above_threshold")) {
summary.vectorOnlyAboveThresholdSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "vector_only_near_miss_eligible")) {
summary.vectorOnlyNearMissEligibleSamples.push_back(*v);
}
if (parseBoolStat(searchStats, "adaptive_fusion_enabled").value_or(false)) {
summary.adaptiveFusionEnabledQueryCount++;
}
if (auto v = parseDoubleStat(searchStats, "multi_vector_generated_phrases")) {
summary.multiVectorGeneratedPhraseSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "multi_vector_raw_hit_count")) {
summary.multiVectorRawHitSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "multi_vector_added_new_count")) {
summary.multiVectorAddedNewSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "multi_vector_replaced_base_count")) {
summary.multiVectorReplacedBaseSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "subphrase_generated_count")) {
summary.subPhraseGeneratedSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "subphrase_clause_count")) {
summary.subPhraseClauseSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "subphrase_fts_hit_count")) {
summary.subPhraseFtsHitSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "subphrase_fts_added_count")) {
summary.subPhraseFtsAddedSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "aggressive_fts_clause_count")) {
summary.aggressiveFtsClauseSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "aggressive_fts_hit_count")) {
summary.aggressiveFtsHitSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "aggressive_fts_added_count")) {
summary.aggressiveFtsAddedSamples.push_back(*v);
}
for (const auto& timingName : trackedTimingKeys()) {
const auto key = timingStatKey(timingName);
if (auto v = parseDoubleStat(searchStats, key)) {
summary.timingSamplesMs[timingName].push_back(*v);
}
}
auto prefusion = searchStats.find("trace_prefusion_signal_summary_json");
if (prefusion != searchStats.end()) {
try {
auto parsed = json::parse(prefusion->second);
if (parsed.is_object()) {
if (!hasDirectPreFusionStats) {
if (auto it = parsed.find("vector_only_docs"); it != parsed.end()) {
if (it->is_number()) {
summary.vectorOnlyDocsSamples.push_back(it->get<double>());
}
}
if (auto it = parsed.find("vector_only_below_threshold"); it != parsed.end()) {
if (it->is_number()) {
summary.vectorOnlyBelowThresholdSamples.push_back(it->get<double>());
}
}
if (auto it = parsed.find("vector_only_above_threshold"); it != parsed.end()) {
if (it->is_number()) {
summary.vectorOnlyAboveThresholdSamples.push_back(it->get<double>());
}
}
if (auto it = parsed.find("vector_only_near_miss_eligible");
it != parsed.end()) {
if (it->is_number()) {
summary.vectorOnlyNearMissEligibleSamples.push_back(it->get<double>());
}
}
}
if (auto it = parsed.find("strong_vector_only_docs"); it != parsed.end()) {
if (it->is_number()) {
summary.strongVectorOnlyDocsSamples.push_back(it->get<double>());
}
}
if (auto it = parsed.find("strong_vector_only_score_eligible_docs");
it != parsed.end()) {
if (it->is_number()) {
summary.strongVectorOnlyScoreEligibleDocsSamples.push_back(
it->get<double>());
}
}
if (auto it = parsed.find("strong_vector_only_rank_eligible_docs");
it != parsed.end()) {
if (it->is_number()) {
summary.strongVectorOnlyRankEligibleDocsSamples.push_back(
it->get<double>());
}
}
}
} catch (...) {
}
}
auto graphDisplacement = searchStats.find("trace_graph_displacement_summary_json");
if (graphDisplacement != searchStats.end()) {
try {
auto parsed = json::parse(graphDisplacement->second);
if (parsed.is_object()) {
if (auto it = parsed.find("graph_added_post_fusion_count");
it != parsed.end() && it->is_number()) {
summary.graphAddedPostFusionSamples.push_back(it->get<double>());
}
if (auto it = parsed.find("graph_displaced_post_fusion_count");
it != parsed.end() && it->is_number()) {
summary.graphDisplacedPostFusionSamples.push_back(it->get<double>());
}
}
} catch (...) {
}
}
if (auto v = parseDoubleStat(searchStats, "graph_community_supported_docs")) {
summary.graphCommunitySupportedDocsSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "graph_community_edge_count")) {
summary.graphCommunityEdgeCountSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "graph_community_largest_size")) {
summary.graphCommunityLargestSizeSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "graph_community_signal_mass")) {
summary.graphCommunitySignalMassSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "graph_community_boosted_docs")) {
summary.graphCommunityBoostedDocsSamples.push_back(*v);
}
if (auto v = parseDoubleStat(searchStats, "graph_community_weight")) {
summary.graphCommunityWeightSamples.push_back(*v);
}
if (auto stageSummary = searchStats.find("trace_stage_summary_json");
stageSummary != searchStats.end()) {
try {
auto parsed = json::parse(stageSummary->second);
if (parsed.is_object()) {
for (const auto& [stageName, stageData] : parsed.items()) {
if (!stageData.is_object()) {
continue;
}
if (stageData.value("enabled", false)) {
summary.stageEnabledCount[stageName]++;
}
if (stageData.value("attempted", false)) {
summary.stageAttemptedCount[stageName]++;
}
if (stageData.value("contributed", false)) {
summary.stageContributedCount[stageName]++;
}
if (stageData.value("skipped", false)) {
summary.stageSkippedCount[stageName]++;
auto reason = stageData.value("skip_reason", std::string{});
if (!reason.empty()) {
summary.stageSkipReasons[stageName].push_back(reason);
}
}
if (auto it = stageData.find("unique_doc_count");
it != stageData.end() && it->is_number()) {
summary.stageUniqueDocCountSamples[stageName].push_back(it->get<double>());
}
}
}
} catch (...) {
}
}
if (auto stagePresence = relevantDecisionTrace.find("stage_relevant_presence");
relevantDecisionTrace.is_object() && stagePresence != relevantDecisionTrace.end() &&
stagePresence->is_object()) {
for (const auto& [stageName, stageData] : stagePresence->items()) {
if (!stageData.is_object()) {
continue;
}
if (stageData.value("any_relevant", false)) {
summary.stageRelevantPresenceCount[stageName]++;
}
if (auto it = stageData.find("relevant_doc_count");
it != stageData.end() && it->is_number()) {
summary.stageRelevantDocCountSamples[stageName].push_back(it->get<double>());
}
}
}
if (auto fusionSummary = searchStats.find("trace_fusion_source_summary_json");
fusionSummary != searchStats.end()) {
try {
auto parsed = json::parse(fusionSummary->second);
if (parsed.is_object()) {
for (const auto& [sourceName, sourceData] : parsed.items()) {
if (!sourceData.is_object()) {
continue;
}
if (auto it = sourceData.find("final_score_mass");
it != sourceData.end() && it->is_number()) {
summary.fusionSourceScoreMassSamples[sourceName].push_back(
it->get<double>());
}
if (auto it = sourceData.find("final_top_doc_count");
it != sourceData.end() && it->is_number()) {
summary.fusionSourceFinalDocSamples[sourceName].push_back(
it->get<double>());
}
}
}
} catch (...) {
}
}
if (auto tunerSummary = searchStats.find("tuner_adjustments_json");
tunerSummary != searchStats.end()) {
try {
auto parsed = json::parse(tunerSummary->second);
if (parsed.is_object()) {
if (auto decision = parsed.find("last_decision");
decision != parsed.end() && decision->is_string()) {
summary.tunerDecisionCounts[decision->get<std::string>()]++;
}
static const std::vector<std::string> kKeys = {
"ewma_latency_ms",
"ewma_kg_latency_share",
"ewma_kg_utility",
"ewma_kg_score_mass_share",
"ewma_kg_final_doc_share",
"ewma_kg_contribution_rate",
"ewma_graph_rerank_latency_ms",
"ewma_graph_rerank_skip_rate",
"ewma_graph_rerank_contribution_rate",
"ewma_fusion_dropped_rate",
"ewma_anchored_fusion_dropped_rate",
"ewma_top_text_fusion_dropped_rate",
"ewma_vector_only_share",
"ewma_semantic_rescue_rate",
};
for (const auto& key : kKeys) {
if (auto it = parsed.find(key); it != parsed.end() && it->is_number()) {
summary.tunerSignalSamples[key].push_back(it->get<double>());
}
}
}
} catch (...) {
}
}
if (auto runtimeConfig = searchStats.find("tuner_runtime_config_json");
runtimeConfig != searchStats.end()) {
try {
auto parsed = json::parse(runtimeConfig->second);
if (parsed.is_object()) {
static const std::vector<std::string> kWeightKeys = {
"text_weight", "simeon_text_weight", "vector_weight",
"entity_vector_weight", "path_tree_weight", "kg_weight",
"tag_weight", "metadata_weight",
};
for (const auto& key : kWeightKeys) {
if (auto it = parsed.find(key); it != parsed.end() && it->is_number()) {
summary.tunerSignalSamples[key].push_back(it->get<double>());
}
}
}
} catch (...) {
}
}
}
static json queryDiagnosticsToJson(const QueryDiagnosticsSummary& summary) {
const double queryCount = static_cast<double>(std::max<std::uint64_t>(summary.queryCount, 1));
json out = {
{"query_count", summary.queryCount},
{"query_with_results_count", summary.queryWithResultsCount},
{"query_without_results_count", summary.queryWithoutResultsCount},
{"query_without_relevant_hit_count", summary.queryWithoutRelevantHitCount},
{"query_with_relevant_in_pre_fusion_count", summary.queryWithRelevantInPreFusionCount},
{"query_with_relevant_in_post_fusion_count", summary.queryWithRelevantInPostFusionCount},
{"query_with_relevant_in_graphless_post_fusion_count",
summary.queryWithRelevantInGraphlessPostFusionCount},
{"query_with_relevant_in_final_window_count", summary.queryWithRelevantInFinalWindowCount},
{"query_with_graph_added_relevant_post_fusion_count",
summary.queryWithGraphAddedRelevantPostFusionCount},
{"query_with_graph_displaced_relevant_post_fusion_count",
summary.queryWithGraphDisplacedRelevantPostFusionCount},
{"query_with_topology_added_relevant_post_fusion_count",
summary.queryWithTopologyAddedRelevantPostFusionCount},
{"query_with_topology_added_relevant_fusion_dropped_count",
summary.queryWithTopologyAddedRelevantFusionDroppedCount},
{"query_with_topk_duplicate_count", summary.queryWithTopKDuplicateCount},
{"degraded_query_count", summary.degradedQueryCount},
{"trace_enabled_query_count", summary.traceEnabledQueryCount},
{"graph_rerank_applied_query_count", summary.graphRerankAppliedQueryCount},
{"compressed_ann_enabled_query_count", summary.compressedAnnEnabledQueryCount},
{"compressed_ann_applied_query_count", summary.compressedAnnAppliedQueryCount},
{"semantic_rescue_nonzero_query_count", summary.semanticRescueNonZeroQueryCount},
{"miss_missing_pre_fusion_count", summary.missMissingPreFusionCount},
{"miss_fusion_cutoff_count", summary.missFusionCutoffCount},
{"miss_rerank_window_drop_count", summary.missRerankWindowDropCount},
{"miss_topk_drop_count", summary.missTopKDropCount},
{"query_with_results_rate",
static_cast<double>(summary.queryWithResultsCount) / queryCount},
{"query_without_relevant_hit_rate",
static_cast<double>(summary.queryWithoutRelevantHitCount) / queryCount},
{"query_with_relevant_in_pre_fusion_rate",
static_cast<double>(summary.queryWithRelevantInPreFusionCount) / queryCount},
{"query_with_relevant_in_post_fusion_rate",
static_cast<double>(summary.queryWithRelevantInPostFusionCount) / queryCount},
{"query_with_relevant_in_graphless_post_fusion_rate",
static_cast<double>(summary.queryWithRelevantInGraphlessPostFusionCount) / queryCount},
{"query_with_relevant_in_final_window_rate",
static_cast<double>(summary.queryWithRelevantInFinalWindowCount) / queryCount},
{"query_with_graph_added_relevant_post_fusion_rate",
static_cast<double>(summary.queryWithGraphAddedRelevantPostFusionCount) / queryCount},
{"query_with_graph_displaced_relevant_post_fusion_rate",
static_cast<double>(summary.queryWithGraphDisplacedRelevantPostFusionCount) / queryCount},
{"query_with_topology_added_relevant_post_fusion_rate",
static_cast<double>(summary.queryWithTopologyAddedRelevantPostFusionCount) / queryCount},
{"query_with_topology_added_relevant_fusion_dropped_rate",
static_cast<double>(summary.queryWithTopologyAddedRelevantFusionDroppedCount) /
queryCount},
{"query_with_topk_duplicate_rate",
static_cast<double>(summary.queryWithTopKDuplicateCount) / queryCount},
{"degraded_query_rate", static_cast<double>(summary.degradedQueryCount) / queryCount},
{"trace_coverage", static_cast<double>(summary.traceEnabledQueryCount) / queryCount},
{"graph_rerank_apply_rate",
static_cast<double>(summary.graphRerankAppliedQueryCount) / queryCount},
{"compressed_ann_enabled_rate",
static_cast<double>(summary.compressedAnnEnabledQueryCount) / queryCount},
{"compressed_ann_apply_rate",
static_cast<double>(summary.compressedAnnAppliedQueryCount) / queryCount},
{"adaptive_fusion_enabled_query_count", summary.adaptiveFusionEnabledQueryCount},
{"adaptive_fusion_enabled_rate",
static_cast<double>(summary.adaptiveFusionEnabledQueryCount) / queryCount},
{"semantic_rescue_nonzero_rate",
static_cast<double>(summary.semanticRescueNonZeroQueryCount) / queryCount},
{"miss_missing_pre_fusion_rate",
static_cast<double>(summary.missMissingPreFusionCount) / queryCount},
{"miss_fusion_cutoff_rate",
static_cast<double>(summary.missFusionCutoffCount) / queryCount},
{"miss_rerank_window_drop_rate",
static_cast<double>(summary.missRerankWindowDropCount) / queryCount},
{"miss_topk_drop_rate", static_cast<double>(summary.missTopKDropCount) / queryCount},
{"compressed_ann_result_count", summarizeSamples(summary.compressedAnnResultCountSamples)},
{"compressed_ann_skip_reasons", summary.compressedAnnSkipReasonCounts},
{"stage_metrics", yams::bench::stageRetrievalMetricsToJson(summary.stageRetrievalMetrics)},
{"semantic_rescue_rate", summarizeSamples(summary.semanticRescueRateSamples)},
{"semantic_rescue_final_count", summarizeSamples(summary.semanticRescueFinalCountSamples)},
{"semantic_rescue_target", summarizeSamples(summary.semanticRescueTargetSamples)},
{"fusion_pre_fusion_unique_count",
summarizeSamples(summary.fusionPreFusionUniqueCountSamples)},
{"fusion_post_fusion_count", summarizeSamples(summary.fusionPostFusionCountSamples)},
{"fusion_dropped_count", summarizeSamples(summary.fusionDroppedCountSamples)},
{"fusion_dropped_rate", summarizeSamples(summary.fusionDroppedRateSamples)},
{"anchored_pre_fusion_count", summarizeSamples(summary.anchoredPreFusionCountSamples)},
{"anchored_fusion_dropped_count",
summarizeSamples(summary.anchoredFusionDroppedCountSamples)},
{"anchored_fusion_dropped_rate",
summarizeSamples(summary.anchoredFusionDroppedRateSamples)},
{"top_text_pre_fusion_count", summarizeSamples(summary.topTextPreFusionCountSamples)},
{"top_text_fusion_dropped_count",
summarizeSamples(summary.topTextFusionDroppedCountSamples)},
{"top_text_fusion_dropped_rate", summarizeSamples(summary.topTextFusionDroppedRateSamples)},
{"vector_only_docs", summarizeSamples(summary.vectorOnlyDocsSamples)},
{"vector_only_below_threshold", summarizeSamples(summary.vectorOnlyBelowThresholdSamples)},
{"vector_only_above_threshold", summarizeSamples(summary.vectorOnlyAboveThresholdSamples)},
{"vector_only_near_miss_eligible",
summarizeSamples(summary.vectorOnlyNearMissEligibleSamples)},
{"strong_vector_only_docs", summarizeSamples(summary.strongVectorOnlyDocsSamples)},
{"strong_vector_only_score_eligible_docs",
summarizeSamples(summary.strongVectorOnlyScoreEligibleDocsSamples)},
{"strong_vector_only_rank_eligible_docs",
summarizeSamples(summary.strongVectorOnlyRankEligibleDocsSamples)},
{"graph_added_post_fusion_count", summarizeSamples(summary.graphAddedPostFusionSamples)},
{"graph_displaced_post_fusion_count",
summarizeSamples(summary.graphDisplacedPostFusionSamples)},
{"topology_weak_query_routed_docs", summarizeSamples(summary.topologyRoutedDocsSamples)},
{"topology_route_best_score", summarizeSamples(summary.topologyRouteBestScoreSamples)},
{"topology_route_mean_accepted_score",
summarizeSamples(summary.topologyRouteMeanAcceptedScoreSamples)},
{"topology_route_accepted_count",
summarizeSamples(summary.topologyRouteAcceptedCountSamples)},
{"topology_seed_count", summarizeSamples(summary.topologySeedCountSamples)},
{"topology_seed_coverage_count",
summarizeSamples(summary.topologySeedCoverageCountSamples)},
{"topology_core_candidate_coverage",
summarizeSamples(summary.topologyCoreCandidateCoverageSamples)},
{"topology_weak_query_added_candidates",
summarizeSamples(summary.topologyAddedCandidatesSamples)},
{"topology_weak_query_duplicate_candidates",
summarizeSamples(summary.topologyDuplicateCandidatesSamples)},
{"topology_weak_query_stale_candidates",
summarizeSamples(summary.topologyStaleCandidatesSamples)},
{"graph_community_supported_docs",
summarizeSamples(summary.graphCommunitySupportedDocsSamples)},
{"graph_community_edge_count", summarizeSamples(summary.graphCommunityEdgeCountSamples)},
{"graph_community_largest_size",
summarizeSamples(summary.graphCommunityLargestSizeSamples)},
{"graph_community_signal_mass", summarizeSamples(summary.graphCommunitySignalMassSamples)},
{"graph_community_boosted_docs",
summarizeSamples(summary.graphCommunityBoostedDocsSamples)},
{"graph_community_weight", summarizeSamples(summary.graphCommunityWeightSamples)},
{"multi_vector_generated_phrases",
summarizeSamples(summary.multiVectorGeneratedPhraseSamples)},
{"multi_vector_raw_hit_count", summarizeSamples(summary.multiVectorRawHitSamples)},
{"multi_vector_added_new_count", summarizeSamples(summary.multiVectorAddedNewSamples)},
{"multi_vector_replaced_base_count",
summarizeSamples(summary.multiVectorReplacedBaseSamples)},
{"subphrase_generated_count", summarizeSamples(summary.subPhraseGeneratedSamples)},
{"subphrase_clause_count", summarizeSamples(summary.subPhraseClauseSamples)},
{"subphrase_fts_hit_count", summarizeSamples(summary.subPhraseFtsHitSamples)},
{"subphrase_fts_added_count", summarizeSamples(summary.subPhraseFtsAddedSamples)},
{"aggressive_fts_clause_count", summarizeSamples(summary.aggressiveFtsClauseSamples)},
{"aggressive_fts_hit_count", summarizeSamples(summary.aggressiveFtsHitSamples)},
{"aggressive_fts_added_count", summarizeSamples(summary.aggressiveFtsAddedSamples)},
};
json timings = json::object();
for (const auto& timingName : trackedTimingKeys()) {
auto it = summary.timingSamplesMs.find(timingName);
if (it != summary.timingSamplesMs.end() && !it->second.empty()) {
timings[timingName] = summarizeSamples(it->second);
}
}
out["timings_ms"] = timings;
json stageUniqueDocCounts = json::object();
for (const auto& [stageName, samples] : summary.stageUniqueDocCountSamples) {
stageUniqueDocCounts[stageName] = summarizeSamples(samples);
}
out["stage_unique_doc_counts"] = stageUniqueDocCounts;
json stageRelevantDocCounts = json::object();
for (const auto& [stageName, samples] : summary.stageRelevantDocCountSamples) {
stageRelevantDocCounts[stageName] = summarizeSamples(samples);
}
out["stage_relevant_doc_counts"] = stageRelevantDocCounts;
json stages = json::object();
for (const auto& [stageName, enabledCount] : summary.stageEnabledCount) {
const double enabled = static_cast<double>(enabledCount);
const auto attemptedIt = summary.stageAttemptedCount.find(stageName);
const auto contributedIt = summary.stageContributedCount.find(stageName);
const auto skippedIt = summary.stageSkippedCount.find(stageName);
const double attempted = attemptedIt != summary.stageAttemptedCount.end()
? static_cast<double>(attemptedIt->second)
: 0.0;
const double contributed = contributedIt != summary.stageContributedCount.end()
? static_cast<double>(contributedIt->second)
: 0.0;
const double skipped = skippedIt != summary.stageSkippedCount.end()
? static_cast<double>(skippedIt->second)
: 0.0;
const auto relevantIt = summary.stageRelevantPresenceCount.find(stageName);
const double relevantPresence = relevantIt != summary.stageRelevantPresenceCount.end()
? static_cast<double>(relevantIt->second)
: 0.0;
stages[stageName] = {
{"enabled_rate", enabled / queryCount},
{"attempt_rate", attempted / queryCount},
{"contribution_rate", contributed / queryCount},
{"relevant_presence_rate", relevantPresence / queryCount},
{"skip_rate", skipped / queryCount},
{"skip_reasons", summary.stageSkipReasons.contains(stageName)
? json(summary.stageSkipReasons.at(stageName))
: json::array()},
};
}
out["stage_contributions"] = stages;
json fusionSources = json::object();
for (const auto& [sourceName, masses] : summary.fusionSourceScoreMassSamples) {
auto finalDocIt = summary.fusionSourceFinalDocSamples.find(sourceName);
fusionSources[sourceName] = {
{"final_score_mass", summarizeSamples(masses)},
{"final_top_doc_count", finalDocIt != summary.fusionSourceFinalDocSamples.end()
? summarizeSamples(finalDocIt->second)
: json{{"count", 0},
{"mean", 0.0},
{"p50", 0.0},
{"p95", 0.0},
{"min", 0.0},
{"max", 0.0}}},
};
}
out["fusion_sources"] = fusionSources;
json tunerSignals = json::object();
for (const auto& [signalName, samples] : summary.tunerSignalSamples) {
tunerSignals[signalName] = summarizeSamples(samples);
}
out["tuner_signals"] = tunerSignals;
out["tuner_decisions"] = summary.tunerDecisionCounts;
out["zoom_level_counts"] = summary.zoomLevelCounts;
return out;
}
static void debugLogWriteJsonLine(const DebugLogEntry& e) {
if (!g_debugOut)
return;
json j;
j["query"] = e.query;
if (e.queryIndex >= 0) {
j["query_index"] = e.queryIndex;
}
j["search_type"] = e.searchType;
j["relevant_doc_ids"] = e.relevantDocIds;
j["relevant_files"] = e.relevantFiles;
j["returned_paths"] = e.returnedPaths;
j["returned_doc_ids"] = e.returnedDocIds;
j["returned_scores"] = e.returnedScores;
j["returned_grades"] = e.returnedGrades;
j["attempts"] = e.attempts;
j["used_streaming"] = e.usedStreaming;
j["used_fuzzy_flag"] = e.usedFuzzyFlag;
j["used_literal_flag"] = e.usedLiteralFlag;
j["used_fuzzy_retry"] = e.usedFuzzyRetry;
j["used_literal_retry"] = e.usedLiteralTextRetry;
j["search_stats"] = e.searchStats;
j["diag"] = e.diagnostics;
if (const char* embBackend = std::getenv("YAMS_EMBED_BACKEND"); embBackend && *embBackend) {
j["embedding_backend"] = embBackend;
} else {
j["embedding_backend"] = "daemon";
}
if (g_debugRunContext.has_value()) {
j["run_id"] = g_debugRunContext->runId;
j["candidate"] = g_debugRunContext->candidate;
j["dataset"] = g_debugRunContext->dataset;
j["corpus_size"] = g_debugRunContext->corpusSize;
j["num_queries"] = g_debugRunContext->numQueries;
j["top_k"] = g_debugRunContext->topK;
j["trace_top_n"] = g_debugRunContext->traceTopN;
j["trace_component_top_n"] = g_debugRunContext->traceComponentTopN;
j["stage_trace_enabled"] = g_debugRunContext->stageTraceEnabled;
if (!g_debugRunContext->debugFile.empty()) {
j["debug_file"] = g_debugRunContext->debugFile;
}
}
if (e.extraFields.is_object()) {
for (const auto& [k, v] : e.extraFields.items()) {
j[k] = v;
}
}
std::lock_guard<std::mutex> lock(g_debugMutex);
(*g_debugOut) << j.dump() << "\n";
g_debugOut->flush();
}
// Store final metrics globally for summary after teardown
static RetrievalMetrics g_final_metrics;
static RetrievalMetrics g_keyword_metrics; // FTS5-only metrics for component isolation
static RetrievalMetrics g_grep_metrics; // grep literal baseline for exact retrieval comparison
static QueryDiagnosticsSummary g_final_hybrid_diagnostics;
static QueryDiagnosticsSummary g_final_keyword_diagnostics;
struct EnvSetting {
std::string key;
std::optional<std::string> value;
};
class ScopedEnvOverrides {
public:
explicit ScopedEnvOverrides(const std::vector<EnvSetting>& overrides) {
previous_.reserve(overrides.size());
for (const auto& setting : overrides) {
PreviousValue pv;
pv.key = setting.key;
if (const char* existing = std::getenv(setting.key.c_str())) {
pv.value = std::string(existing);
}
previous_.push_back(pv);
if (setting.value.has_value()) {
(void)setenv(setting.key.c_str(), setting.value->c_str(), 1);
} else {
(void)unsetenv(setting.key.c_str());
}
}
}
~ScopedEnvOverrides() {
for (const auto& previous : previous_) {
if (previous.value.has_value()) {
(void)setenv(previous.key.c_str(), previous.value->c_str(), 1);
} else {
(void)unsetenv(previous.key.c_str());
}
}
}
private:
struct PreviousValue {
std::string key;
std::optional<std::string> value;
};
std::vector<PreviousValue> previous_;
};
struct OptimizationCandidate {
std::string name;
std::string description;
std::vector<EnvSetting> envOverrides;
bool enginePolicyCandidate = false;
bool diagnosticCandidate = false;
};
struct OptimizationRunResult {
OptimizationCandidate candidate;
RetrievalMetrics hybridMetrics;
RetrievalMetrics keywordMetrics;
QueryDiagnosticsSummary hybridDiagnostics;
QueryDiagnosticsSummary keywordDiagnostics;
std::string tuningState;
std::string tuningReason;
std::string runId;
std::string debugFile;
int traceTopN = 0;
int traceComponentTopN = 0;
bool stageTraceEnabled = false;
double objectiveScore = 0.0;
double hybridEvalMs = 0.0;
double keywordEvalMs = 0.0;
std::string searchEngine =
yams::vector::vectorSearchEngineName(yams::vector::VectorSearchEngine::SimeonPqAdc);
std::uintmax_t vectorsDbBytes = 0;
std::uintmax_t vectorsWalBytes = 0;
std::uintmax_t persistedHnswNodes = 0;
std::uintmax_t persistedHnswMetaRows = 0;
std::uintmax_t persistedVec0Tables = 0;
std::uintmax_t persistedVec0Rows = 0;
std::uintmax_t persistedPqCodes = 0;
std::uintmax_t persistedPqMeta = 0;
bool success = false;
std::string errorMessage;
};
struct BenchCacheMetadata {
std::string dataset = "synthetic";
std::string datasetPath;
int corpusSize = 0;
int numQueries = 0;
int topK = 0;
bool useBEIR = false;
bool vectorsDisabled = false;
bool requireKgReady = false;
bool graphRerankRequested = false;
std::string searchEngine =
yams::vector::vectorSearchEngineName(yams::vector::VectorSearchEngine::SimeonPqAdc);
int expectedDocs = 0;
int expectedQueries = 0;
std::uintmax_t corpusFingerprint = 0;
std::string status = "priming";
int embeddedDocs = 0;
std::uintmax_t vectorCount = 0;
bool vectorIndexReady = false;
std::uintmax_t vectorsDbBytes = 0;
std::uintmax_t vectorsWalBytes = 0;
std::uintmax_t persistedHnswNodes = 0;
std::uintmax_t persistedHnswMetaRows = 0;
std::uintmax_t persistedVec0Tables = 0;
std::uintmax_t persistedVec0Rows = 0;
std::uintmax_t persistedPqCodes = 0;
std::uintmax_t persistedPqMeta = 0;
};
struct PersistedHnswState {
bool vectorsDbPresent = false;
std::uintmax_t vectorsDbBytes = 0;
std::uintmax_t vectorsWalBytes = 0;
std::uintmax_t nodeRows = 0;
std::uintmax_t metaRows = 0;
std::uintmax_t vec0Tables = 0;
std::uintmax_t vec0Rows = 0;
std::uintmax_t pqCodeRows = 0;
std::uintmax_t pqMetaRows = 0;
};
static std::string g_benchmark_search_engine =
yams::vector::vectorSearchEngineName(yams::vector::VectorSearchEngine::SimeonPqAdc);
static std::string g_simeonEncoderProfile;
static std::string g_simeonFragmentEncoderProfile;
static std::optional<bool> g_simeonFragmentGeometryEnabled;
static std::optional<bool> g_simeonBm25Enabled;
static std::optional<bool> g_simeonRouterEnabled;
static bool g_requireDaemonNativeGraph = false;
static PersistedHnswState g_final_vector_index_state;
static void consumeXplanConfigArguments(int& argc, char** argv) {
const auto takeValue = [](std::string_view argument,
std::string_view prefix) -> std::optional<std::string> {
if (!argument.starts_with(prefix)) {
return std::nullopt;
}
return std::string{argument.substr(prefix.size())};
};
int outputIndex = 1;
for (int inputIndex = 1; inputIndex < argc; ++inputIndex) {
const std::string_view argument{argv[inputIndex]};
if (auto value = takeValue(argument, "--yams-simeon-encoder-profile="); value.has_value()) {
g_simeonEncoderProfile = std::move(*value);
continue;
}
if (auto value = takeValue(argument, "--yams-simeon-fragment-encoder-profile=");
value.has_value()) {
g_simeonFragmentEncoderProfile = std::move(*value);
continue;
}
if (auto value = takeValue(argument, "--yams-simeon-fragment-geometry=");
value.has_value()) {
g_simeonFragmentGeometryEnabled = *value == "true" || *value == "1";
continue;
}
if (auto value = takeValue(argument, "--yams-simeon-bm25="); value.has_value()) {
g_simeonBm25Enabled = *value == "true" || *value == "1";
continue;
}
if (auto value = takeValue(argument, "--yams-simeon-router="); value.has_value()) {
g_simeonRouterEnabled = *value == "true" || *value == "1";
continue;
}
if (auto value = takeValue(argument, "--yams-require-daemon-native-graph=");
value.has_value()) {
g_requireDaemonNativeGraph = *value == "true" || *value == "1";
continue;
}
argv[outputIndex++] = argv[inputIndex];
}
argc = outputIndex;
}
static bool envTruthy(const char* value) {
if (!value) {
return false;
}
std::string normalized(value);
std::transform(normalized.begin(), normalized.end(), normalized.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
return normalized == "1" || normalized == "true" || normalized == "yes" || normalized == "on";
}
static yams::vector::VectorSearchEngine benchmarkVectorSearchEngine() {
if (const char* raw = std::getenv("YAMS_VECTOR_SEARCH_ENGINE"); raw && *raw) {
std::string normalized(raw);
std::transform(normalized.begin(), normalized.end(), normalized.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
if (auto parsed = yams::vector::parseVectorSearchEngine(normalized)) {
return *parsed;
}
spdlog::warn(
"[Bench] Invalid YAMS_VECTOR_SEARCH_ENGINE='{}'; using default {}", raw,
yams::vector::vectorSearchEngineName(yams::vector::VectorSearchEngine::SimeonPqAdc));
}
return yams::vector::VectorSearchEngine::SimeonPqAdc;
}
static std::string benchmarkEngineCacheLabel() {
const auto engine = benchmarkVectorSearchEngine();
std::string label = yams::vector::vectorSearchEngineName(engine);
return label;
}
static bool benchUseStreamingSearch() {
// Retrieval quality benchmarks measure ranking quality, not IPC chunking behavior.
// Default to unary search so streaming transport stalls do not skew IR evaluation,
// while preserving an opt-in path for transport debugging.
return envTruthy(std::getenv("YAMS_BENCH_ENABLE_STREAMING_SEARCH"));
}
static bool benchEvaluateGrepBaseline() {
const char* value = std::getenv("YAMS_BENCH_EVALUATE_GREP_BASELINE");
return value == nullptr || envTruthy(value);
}
static int parseIntEnvOrDefault(const char* key, int defaultValue, int minValue, int maxValue) {
const int clampedDefault = std::clamp(defaultValue, minValue, maxValue);
const char* raw = std::getenv(key);
if (!(raw && *raw)) {
return clampedDefault;
}
try {
return std::clamp(std::stoi(raw), minValue, maxValue);
} catch (...) {
return clampedDefault;
}
}
static std::size_t parseSizeEnvOrDefault(const char* key, std::size_t defaultValue) {
const char* raw = std::getenv(key);
if (!(raw && *raw)) {
return defaultValue;
}
try {
return static_cast<std::size_t>(std::max<long long>(0, std::stoll(raw)));
} catch (...) {
return defaultValue;
}
}
static std::size_t parseSizeEnvOrFallback(const char* key, const char* fallbackKey,
std::size_t defaultValue) {
if (const char* raw = std::getenv(key); raw && *raw) {
return parseSizeEnvOrDefault(key, defaultValue);
}
return parseSizeEnvOrDefault(fallbackKey, defaultValue);
}
static float parseFloatEnvOrDefault(const char* key, float defaultValue) {
const char* raw = std::getenv(key);
if (!(raw && *raw)) {
return defaultValue;
}
try {
return std::stof(raw);
} catch (...) {
return defaultValue;
}
}
static std::string sanitizeLabelForFilename(const std::string& value) {
std::string out;
out.reserve(value.size());
for (char c : value) {
if (std::isalnum(static_cast<unsigned char>(c)) || c == '-' || c == '_') {
out.push_back(c);
} else {
out.push_back('_');
}
}
return out;
}
static std::string makeRunId(const std::string& candidate) {
(void)candidate;
const auto now = std::chrono::system_clock::now().time_since_epoch();
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
return std::to_string(us);
}
static std::uintmax_t fileSizeOrZero(const fs::path& path) {
std::error_code ec;
const auto size = fs::file_size(path, ec);
return ec ? 0 : size;
}
static std::uintmax_t computePathFingerprint(const fs::path& path) {
std::error_code ec;
if (!fs::exists(path, ec)) {
return 0;
}
if (fs::is_regular_file(path, ec)) {
return fileSizeOrZero(path);
}
if (!fs::is_directory(path, ec)) {
return 0;
}
std::uintmax_t fingerprint = 1469598103934665603ull;
for (fs::recursive_directory_iterator it(path, ec), end; !ec && it != end; it.increment(ec)) {
const auto entryPath = it->path();
const auto relative = fs::relative(entryPath, path, ec);
const std::string relativeString = ec ? entryPath.filename().string() : relative.string();
for (unsigned char c : relativeString) {
fingerprint ^= static_cast<std::uintmax_t>(c);
fingerprint *= 1099511628211ull;
}
if (it->is_regular_file(ec)) {
fingerprint ^= fileSizeOrZero(entryPath);
fingerprint *= 1099511628211ull;
}
ec.clear();
}
return fingerprint;
}
static PersistedHnswState inspectPersistedHnswState(const fs::path& dataDir) {
PersistedHnswState state;
const fs::path vectorsDbPath = dataDir / "vectors.db";
if (!fs::exists(vectorsDbPath)) {
return state;
}
state.vectorsDbPresent = true;
std::error_code sizeEc;
state.vectorsDbBytes = fs::file_size(vectorsDbPath, sizeEc);
if (sizeEc) {
state.vectorsDbBytes = 0;
sizeEc.clear();
}
const fs::path walPath = vectorsDbPath.string() + "-wal";
if (fs::exists(walPath)) {
state.vectorsWalBytes = fs::file_size(walPath, sizeEc);
if (sizeEc) {
state.vectorsWalBytes = 0;
sizeEc.clear();
}
}
sqlite3* db = nullptr;
if (sqlite3_open_v2(vectorsDbPath.string().c_str(), &db, SQLITE_OPEN_READONLY, nullptr) !=
SQLITE_OK) {
spdlog::warn("[Bench] Failed to open persisted HNSW DB {}: {}", vectorsDbPath.string(),
db ? sqlite3_errmsg(db) : "open failed");
if (db) {
sqlite3_close(db);
}
return state;
}
sqlite3_busy_timeout(db, 5000);
auto closeDb = [&]() {
if (db) {
sqlite3_close(db);
db = nullptr;
}
};
sqlite3_stmt* stmt = nullptr;
const char* tableSql =
"SELECT name FROM sqlite_master WHERE type='table' AND "
"(name='vectors_hnsw_meta' OR name='vectors_hnsw_nodes' OR "
" name LIKE 'vectors_%_hnsw_meta' OR name LIKE 'vectors_%_hnsw_nodes' OR "
" name LIKE 'vectors_%_vec0' OR "
" name='simeon_pq_codes' OR name='simeon_pq_meta' OR "
" name LIKE 'vectors_%_simeon_pq_codes' OR name LIKE 'vectors_%_simeon_pq_meta')";
if (sqlite3_prepare_v2(db, tableSql, -1, &stmt, nullptr) != SQLITE_OK) {
spdlog::warn("[Bench] Failed to inspect persisted HNSW tables in {}: {}",
vectorsDbPath.string(), sqlite3_errmsg(db));
closeDb();
return state;
}
std::vector<std::string> tables;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const auto* text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
if (text && *text) {
tables.emplace_back(text);
}
}
sqlite3_finalize(stmt);
for (const auto& table : tables) {
std::string countTarget = table;
if (table.find("_vec0") != std::string::npos) {
// vec0 virtual tables require the module to be loaded on the inspecting connection.
// For benchmark readiness/footprint checks, count the shadow storage table directly.
countTarget += "_vectors";
}
const std::string countSql = "SELECT COUNT(*) FROM \"" + countTarget + "\"";
if (sqlite3_prepare_v2(db, countSql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
spdlog::warn("[Bench] Failed to count persisted vector table {} in {}: {}", countTarget,
vectorsDbPath.string(), sqlite3_errmsg(db));
continue;
}
if (sqlite3_step(stmt) == SQLITE_ROW) {
const auto count = static_cast<std::uintmax_t>(sqlite3_column_int64(stmt, 0));
if (table.find("_hnsw_nodes") != std::string::npos) {
state.nodeRows += count;
} else if (table.find("_hnsw_meta") != std::string::npos) {
state.metaRows += count;
} else if (table.find("_vec0") != std::string::npos) {
state.vec0Tables += 1;
state.vec0Rows += count;
} else if (table.find("simeon_pq_codes") != std::string::npos) {
state.pqCodeRows += count;
} else if (table.find("simeon_pq_meta") != std::string::npos) {
state.pqMetaRows += count;
}
}
sqlite3_finalize(stmt);
stmt = nullptr;
}
closeDb();
return state;
}
static json benchCacheMetadataToJson(const BenchCacheMetadata& metadata) {
return {
{"dataset", metadata.dataset},
{"dataset_path", metadata.datasetPath},
{"corpus_size", metadata.corpusSize},
{"num_queries", metadata.numQueries},
{"top_k", metadata.topK},
{"use_beir", metadata.useBEIR},
{"vectors_disabled", metadata.vectorsDisabled},
{"require_kg_ready", metadata.requireKgReady},
{"graph_rerank_requested", metadata.graphRerankRequested},
{"search_engine", metadata.searchEngine},
{"expected_docs", metadata.expectedDocs},
{"expected_queries", metadata.expectedQueries},
{"corpus_fingerprint", metadata.corpusFingerprint},
{"status", metadata.status},
{"embedded_docs", metadata.embeddedDocs},
{"vector_count", metadata.vectorCount},
{"vector_index_ready", metadata.vectorIndexReady},
{"vectors_db_bytes", metadata.vectorsDbBytes},
{"vectors_wal_bytes", metadata.vectorsWalBytes},
{"persisted_hnsw_nodes", metadata.persistedHnswNodes},
{"persisted_hnsw_meta_rows", metadata.persistedHnswMetaRows},
{"persisted_vec0_tables", metadata.persistedVec0Tables},
{"persisted_vec0_rows", metadata.persistedVec0Rows},
{"persisted_pq_codes", metadata.persistedPqCodes},
{"persisted_pq_meta", metadata.persistedPqMeta},
};
}
static std::uintmax_t jsonUintValue(const json& j, const char* key, std::uintmax_t fallback = 0) {
const auto it = j.find(key);
if (it == j.end() || it->is_null()) {
return fallback;
}
if (it->is_number_unsigned()) {
return it->get<std::uintmax_t>();
}
if (it->is_number_integer()) {
const auto value = it->get<std::intmax_t>();
return value >= 0 ? static_cast<std::uintmax_t>(value) : fallback;
}
if (it->is_string()) {
try {
return static_cast<std::uintmax_t>(std::stoull(it->get<std::string>()));
} catch (...) {
return fallback;
}
}
return fallback;
}
static std::optional<BenchCacheMetadata> parseBenchCacheMetadata(const json& j) {
if (!j.is_object()) {
return std::nullopt;
}
BenchCacheMetadata metadata;
metadata.dataset = j.value("dataset", "synthetic");
metadata.datasetPath = j.value("dataset_path", "");
metadata.corpusSize = j.value("corpus_size", 0);
metadata.numQueries = j.value("num_queries", 0);
metadata.topK = j.value("top_k", 0);
metadata.useBEIR = j.value("use_beir", false);
metadata.vectorsDisabled = j.value("vectors_disabled", false);
metadata.requireKgReady = j.value("require_kg_ready", false);
metadata.graphRerankRequested = j.value("graph_rerank_requested", false);
metadata.searchEngine =
j.value("search_engine", std::string(yams::vector::vectorSearchEngineName(
yams::vector::VectorSearchEngine::SimeonPqAdc)));
metadata.expectedDocs = j.value("expected_docs", 0);
metadata.expectedQueries = j.value("expected_queries", 0);
metadata.corpusFingerprint = jsonUintValue(j, "corpus_fingerprint");
metadata.status = j.value("status", std::string("priming"));
metadata.embeddedDocs = j.value("embedded_docs", 0);
metadata.vectorCount = jsonUintValue(j, "vector_count");
metadata.vectorIndexReady = j.value("vector_index_ready", false);
metadata.vectorsDbBytes = jsonUintValue(j, "vectors_db_bytes");
metadata.vectorsWalBytes = jsonUintValue(j, "vectors_wal_bytes");
metadata.persistedHnswNodes = jsonUintValue(j, "persisted_hnsw_nodes");
metadata.persistedHnswMetaRows = jsonUintValue(j, "persisted_hnsw_meta_rows");
metadata.persistedVec0Tables = jsonUintValue(j, "persisted_vec0_tables");
metadata.persistedVec0Rows = jsonUintValue(j, "persisted_vec0_rows");
metadata.persistedPqCodes = jsonUintValue(j, "persisted_pq_codes");
metadata.persistedPqMeta = jsonUintValue(j, "persisted_pq_meta");
return metadata;
}
static std::string canonicalPathOrEmpty(const fs::path& path) {
if (path.empty()) {
return {};
}
std::error_code ec;
const auto canonical = fs::weakly_canonical(path, ec);
if (!ec) {
return canonical.string();
}
return path.lexically_normal().string();
}
static fs::path benchCacheMetadataPath(const fs::path& cacheDir) {
return cacheDir / "retrieval_bench_cache.json";
}
static Result<BenchCacheMetadata> readBenchCacheMetadata(const fs::path& cacheDir) {
const auto metadataPath = benchCacheMetadataPath(cacheDir);
std::error_code ec;
if (!fs::exists(metadataPath, ec)) {
return Error{ErrorCode::NotFound, "Cache metadata not found: " + metadataPath.string()};
}
std::ifstream in(metadataPath);
if (!in) {
return Error{ErrorCode::IOError, "Failed to open cache metadata: " + metadataPath.string()};
}
json j;
try {
in >> j;
} catch (const std::exception& e) {
return Error{ErrorCode::InvalidArgument,
"Failed to parse cache metadata: " + std::string(e.what())};
}
auto parsed = parseBenchCacheMetadata(j);
if (!parsed) {
return Error{ErrorCode::InvalidArgument,
"Cache metadata schema invalid: " + metadataPath.string()};
}
return *parsed;
}
static Result<void> writeBenchCacheMetadata(const fs::path& cacheDir,
const BenchCacheMetadata& metadata) {
std::error_code ec;
fs::create_directories(cacheDir, ec);
if (ec) {
return Error{ErrorCode::IOError,
"Failed to create cache dir: " + cacheDir.string() + ": " + ec.message()};
}
const auto metadataPath = benchCacheMetadataPath(cacheDir);
std::ofstream out(metadataPath);
if (!out) {
return Error{ErrorCode::IOError,
"Failed to write cache metadata: " + metadataPath.string()};
}
out << benchCacheMetadataToJson(metadata).dump(2) << "\n";
return Result<void>{};
}
static bool benchCacheMatches(const BenchCacheMetadata& expected, const BenchCacheMetadata& actual,
std::string* mismatchReason = nullptr) {
auto mismatch = [&](std::string reason) {
if (mismatchReason) {
*mismatchReason = std::move(reason);
}
return false;
};
if (expected.dataset != actual.dataset)
return mismatch("dataset mismatch");
if (expected.datasetPath != actual.datasetPath)
return mismatch("dataset path mismatch");
if (expected.corpusSize != actual.corpusSize)
return mismatch("corpus size mismatch");
if (expected.numQueries != actual.numQueries)
return mismatch("query count mismatch");
if (expected.topK != actual.topK)
return mismatch("top-k mismatch");
if (expected.useBEIR != actual.useBEIR)
return mismatch("beir flag mismatch");
if (expected.vectorsDisabled != actual.vectorsDisabled)
return mismatch("vectors disabled mismatch");
if (expected.requireKgReady != actual.requireKgReady)
return mismatch("kg requirement mismatch");
if (expected.graphRerankRequested != actual.graphRerankRequested)
return mismatch("graph rerank mismatch");
if (expected.searchEngine != actual.searchEngine)
return mismatch("search engine mismatch");
if (expected.expectedDocs != actual.expectedDocs)
return mismatch("expected docs mismatch");
if (expected.expectedQueries != actual.expectedQueries)
return mismatch("expected queries mismatch");
if (expected.corpusFingerprint != 0 && actual.corpusFingerprint != 0 &&
expected.corpusFingerprint != actual.corpusFingerprint) {
return mismatch("corpus fingerprint mismatch");
}
if (actual.status != "primed") {
return mismatch("cache status not reusable");
}
return true;
}
static BenchCacheMetadata
preferStrongerBenchCacheMetadata(BenchCacheMetadata preferred,
const std::optional<BenchCacheMetadata>& candidate) {
if (!candidate) {
return preferred;
}
const auto& c = *candidate;
if (preferred.datasetPath.empty())
preferred.datasetPath = c.datasetPath;
preferred.corpusFingerprint = std::max(preferred.corpusFingerprint, c.corpusFingerprint);
preferred.expectedDocs = std::max(preferred.expectedDocs, c.expectedDocs);
preferred.expectedQueries = std::max(preferred.expectedQueries, c.expectedQueries);
preferred.embeddedDocs = std::max(preferred.embeddedDocs, c.embeddedDocs);
preferred.vectorCount = std::max(preferred.vectorCount, c.vectorCount);
preferred.vectorIndexReady = preferred.vectorIndexReady || c.vectorIndexReady;
preferred.vectorsDbBytes = std::max(preferred.vectorsDbBytes, c.vectorsDbBytes);
preferred.vectorsWalBytes = std::max(preferred.vectorsWalBytes, c.vectorsWalBytes);
preferred.persistedHnswNodes = std::max(preferred.persistedHnswNodes, c.persistedHnswNodes);
preferred.persistedHnswMetaRows =
std::max(preferred.persistedHnswMetaRows, c.persistedHnswMetaRows);
preferred.persistedVec0Tables = std::max(preferred.persistedVec0Tables, c.persistedVec0Tables);
preferred.persistedVec0Rows = std::max(preferred.persistedVec0Rows, c.persistedVec0Rows);
preferred.persistedPqCodes = std::max(preferred.persistedPqCodes, c.persistedPqCodes);
preferred.persistedPqMeta = std::max(preferred.persistedPqMeta, c.persistedPqMeta);
if (preferred.status != "primed" && c.status == "primed") {
preferred.status = c.status;
}
return preferred;
}
static BenchCacheMetadata currentBenchCacheMetadata(BenchCacheMetadata metadata,
const yams::daemon::StatusResponse& status,
const fs::path& dataDir,
bool validatedIndexReusable) {
auto getCount = [&](std::string_view key) -> std::uintmax_t {
auto it = status.requestCounts.find(std::string(key));
return it == status.requestCounts.end() ? 0 : it->second;
};
const auto persistedHnsw = inspectPersistedHnswState(dataDir);
metadata.vectorIndexReady = validatedIndexReusable;
metadata.vectorsDbBytes = persistedHnsw.vectorsDbBytes;
metadata.vectorsWalBytes = persistedHnsw.vectorsWalBytes;
metadata.persistedHnswNodes = persistedHnsw.nodeRows;
metadata.persistedHnswMetaRows = persistedHnsw.metaRows;
metadata.persistedVec0Tables = persistedHnsw.vec0Tables;
metadata.persistedVec0Rows = persistedHnsw.vec0Rows;
metadata.persistedPqCodes = persistedHnsw.pqCodeRows;
metadata.persistedPqMeta = persistedHnsw.pqMetaRows;
metadata.embeddedDocs = static_cast<int>(getCount("documents_embedded"));
metadata.vectorCount = getCount("vector_count");
const bool queueDrained = getCount("embed_svc_queued") == 0 && getCount("embed_in_flight") == 0;
const bool fullCoverage =
metadata.embeddedDocs >= metadata.expectedDocs && metadata.expectedDocs > 0;
const bool cacheIndexReady = metadata.vectorsDisabled || metadata.vectorIndexReady;
metadata.status = (queueDrained && fullCoverage && cacheIndexReady) ? "primed" : "partial";
return metadata;
}
static fs::path makeCandidateDebugPath(const fs::path& base, const std::string& candidate,
const std::string& runId) {
const auto safeCandidate = sanitizeLabelForFilename(candidate);
const auto stem = base.stem().string();
const auto ext = base.extension().string();
const auto suffix = "_" + safeCandidate + "_" + runId;
if (!stem.empty()) {
return base.parent_path() / (stem + suffix + ext);
}
return base.parent_path() / (base.filename().string() + suffix);
}
static bool hasOverrideKey(const std::vector<EnvSetting>& settings, const std::string& key) {
return std::any_of(settings.begin(), settings.end(),
[&](const EnvSetting& setting) { return setting.key == key; });
}
static std::vector<OptimizationCandidate> defaultOptimizationCandidates() {
return {
{"auto_baseline",
"Auto tuner baseline with graph rerank enabled",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_DISABLE_SEARCH_REBUILDS", "0"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", std::nullopt},
{"YAMS_CANDIDATE_MULTIPLIER", std::nullopt},
},
true},
{"mixed_precision_profile",
"MIXED precision preset with lexical and vector guardrails",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
}},
{"mixed_precision_zoom_map",
"MIXED_PRECISION with map-level navigation bias",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ZOOM_LEVEL", "MAP"},
}},
{"mixed_precision_zoom_neighborhood",
"MIXED_PRECISION with neighborhood navigation bias",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ZOOM_LEVEL", "NEIGHBORHOOD"},
}},
{"mixed_precision_zoom_street",
"MIXED_PRECISION with street-level precision bias",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ZOOM_LEVEL", "STREET"},
}},
{"mixed_precision_semantic_recall_v1",
"MIXED_PRECISION + looser vector gate + extra semantic rescue",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
}},
{"mixed_precision_semantic_recall_lexical14_v1",
"Semantic recall v1 + stronger lexical floor/tiebreak guardrails",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
}},
{"mixed_default",
"Code/mixed tuned state with benchmark defaults",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
}},
{"mixed_precision_lexical_floor",
"MIXED defaults + lexical floor to preserve top text hits",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "8"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.12"},
}},
{"mixed_precision_lexical_floor_strong",
"MIXED defaults + stronger lexical floor",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "12"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.20"},
}},
{"mixed_precision_lexical_floor_strong_tiebreak",
"MIXED stronger lexical floor with lexical tie-break",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "12"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.20"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
}},
{"small_code_precision",
"Code-heavy state with stronger lexical/entity bias",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "SMALL_CODE"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
}},
{"mixed_recall_push",
"MIXED state with larger candidate pool and no vector skip",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_CANDIDATE_MULTIPLIER", "2.0"},
}},
{"mixed_baseline",
"MIXED state baseline",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
}},
{"mixed_precision_guardrails",
"MIXED + weighted reciprocal with vector-only precision guardrails",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "10"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.93"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.70"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.07"},
}},
{"mixed_precision_mrr_recovery_rrf",
"MIXED weighted reciprocal with softer vector-only guardrails",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.91"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.82"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
}},
{"mixed_precision_rrf_neighbor_t92_p80_k14",
"MIXED weighted reciprocal near-neighbor: stricter threshold, lower RRF k",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "14"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.80"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
}},
{"mixed_precision_rrf_neighbor_t92_p78_k16",
"MIXED weighted reciprocal near-neighbor: stricter threshold and penalty",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.78"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
}},
{"mixed_precision_rrf_neighbor_t90_p84_k18",
"MIXED weighted reciprocal near-neighbor: looser threshold, higher RRF k",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "18"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.90"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.84"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
}},
{"mixed_precision_rrf_rerank10",
"MIXED weighted reciprocal with broader rerank window",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.91"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.82"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "10"},
}},
{"mixed_ablation_disable_vector_gate",
"Ablation: disable vector-only threshold/penalty",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.00"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "1.00"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
}},
{"mixed_ablation_disable_intent_adaptive",
"Ablation: disable query intent weighting",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.91"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.82"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
{"YAMS_SEARCH_ENABLE_INTENT_ADAPTIVE", "0"},
}},
{"mixed_ablation_disable_graph_rerank",
"Ablation: disable graph reranking",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "0"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.91"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.82"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
}},
{"mixed_ablation_disable_reranker",
"Ablation: disable cross-encoder reranking stage",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "16"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.91"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.82"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.05"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
{"YAMS_SEARCH_ENABLE_RERANKING", "0"},
}},
{"scientific_precision_guardrails",
"SCIENTIFIC state with strict vector-only thresholding",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "SCIENTIFIC"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "0"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_RRF_K", "10"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.94"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.68"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.08"},
},
true},
// ── SCIENTIFIC retrieval candidates ────────────────────────────
// Purpose: optimize pre-fusion recall and vector-text balance for
// scientific/benchmark corpora (SciFact, TREC-COVID, NFCorpus).
{"scientific_ablation_graph_off",
"SCIENTIFIC auto baseline with graph rerank disabled",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "0"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_ablation_no_semantic_rescue",
"SCIENTIFIC auto baseline with semantic rescue disabled",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "0"},
},
true},
{"scientific_semantic_recall_v1",
"SCIENTIFIC auto + extra semantic rescue + looser vector gate",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.82"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "4"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.55"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_vector_fanout_2x",
"SCIENTIFIC auto + 2x vector fanout (vectorMaxResults 150->300)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_CANDIDATE_MULTIPLIER", "2.0"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_rrf_k6",
"SCIENTIFIC auto + tighter RRF k=6 (stronger top-rank preference)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_RRF_K", "6"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_rrf_k24",
"SCIENTIFIC auto + looser RRF k=24 (smoother cross-component fusion)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_RRF_K", "24"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
// ── Aggressive recall-push candidates (corpus-state-aware) ────────
{"scientific_recall_aggressive_v1",
"SCI scientific auto + recall push: vec200 sim0.10 rescue6 strong_vec0.60",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_SIMILARITY_THRESHOLD", "0.10"},
{"YAMS_SEARCH_VECTOR_MAX_RESULTS", "200"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "6"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.50"},
{"YAMS_SEARCH_ENABLE_STRONG_VECTOR_ONLY_RELIEF", "1"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_MIN_SCORE", "0.60"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_TOPRANK", "6"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_PENALTY", "0.94"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.82"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.90"},
{"YAMS_SEARCH_WEAK_QUERY_VECTOR_FANOUT_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_recall_max_v1",
"SCI max recall: vec250 sim0.05 rescue8 rerank20 strong_vec0.55 fanout3.5",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_SIMILARITY_THRESHOLD", "0.05"},
{"YAMS_SEARCH_VECTOR_MAX_RESULTS", "250"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "8"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.45"},
{"YAMS_SEARCH_ENABLE_STRONG_VECTOR_ONLY_RELIEF", "1"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_MIN_SCORE", "0.55"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_TOPRANK", "8"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_PENALTY", "0.95"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.80"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.92"},
{"YAMS_SEARCH_WEAK_QUERY_VECTOR_FANOUT_MULTIPLIER", "3.5"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_recall_vec300",
"SCI max pool: vec300 sim0.05 rescue10 rerank25",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_SIMILARITY_THRESHOLD", "0.05"},
{"YAMS_SEARCH_VECTOR_MAX_RESULTS", "300"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "10"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.40"},
{"YAMS_SEARCH_ENABLE_STRONG_VECTOR_ONLY_RELIEF", "1"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_MIN_SCORE", "0.50"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_TOPRANK", "10"},
{"YAMS_SEARCH_STRONG_VECTOR_ONLY_PENALTY", "0.95"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.78"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.94"},
{"YAMS_SEARCH_WEAK_QUERY_VECTOR_FANOUT_MULTIPLIER", "4.0"},
{"YAMS_SEARCH_RERANK_TOPK", "25"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
// ── Retrieval-lane candidates (enable disabled lanes for recall) ──
{"scientific_entity_vec_on",
"SCI scientific auto + entity vector retrieval enabled (GLiNER concepts)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENTITY_VECTOR_WEIGHT", "0.15"},
{"YAMS_SEARCH_ENTITY_VECTOR_MAX_RESULTS", "80"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_concept_boost_on",
"SCI scientific auto + concept boosting enabled (mined concepts)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.12"},
{"YAMS_SEARCH_CONCEPT_MIN_CONFIDENCE", "0.35"},
{"YAMS_SEARCH_CONCEPT_MAX_COUNT", "8"},
{"YAMS_SEARCH_CONCEPT_MAX_BOOST", "0.28"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_entity_concept_combined",
"SCI entity_vec + concept_boost + rescue=4 (multi-lane recall)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENTITY_VECTOR_WEIGHT", "0.12"},
{"YAMS_SEARCH_ENTITY_VECTOR_MAX_RESULTS", "60"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.10"},
{"YAMS_SEARCH_CONCEPT_MIN_CONFIDENCE", "0.35"},
{"YAMS_SEARCH_CONCEPT_MAX_COUNT", "6"},
{"YAMS_SEARCH_CONCEPT_MAX_BOOST", "0.22"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "4"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_rrf_k8",
"SCI scientific auto + RRF k=8 (tight top-rank focus)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_RRF_K", "8"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_subphrase_aggressive",
"SCI + aggressive sub-phrase expansion + rescue=4",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENABLE_SUB_PHRASE_EXPANSION", "1"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION_MIN_HITS", "2"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION_PENALTY", "0.60"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "4"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_combined_v1",
"entity_vec + concept_boost + rrf_k6 + rescue=4 + subphrase aggressive",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_ENTITY_VECTOR_WEIGHT", "0.12"},
{"YAMS_SEARCH_ENTITY_VECTOR_MAX_RESULTS", "60"},
{"YAMS_SEARCH_CONCEPT_BOOST_WEIGHT", "0.10"},
{"YAMS_SEARCH_CONCEPT_MIN_CONFIDENCE", "0.35"},
{"YAMS_SEARCH_CONCEPT_MAX_COUNT", "6"},
{"YAMS_SEARCH_CONCEPT_MAX_BOOST", "0.22"},
{"YAMS_SEARCH_RRF_K", "6"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "4"},
{"YAMS_SEARCH_ENABLE_SUB_PHRASE_EXPANSION", "1"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION_MIN_HITS", "2"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION_PENALTY", "0.60"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_text_heavy",
"SCI text weight 0.55 + simeon 0.15 + vector 0.20 (lexical-first)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_TEXT_WEIGHT", "0.55"},
{"YAMS_SEARCH_SIMEON_TEXT_WEIGHT", "0.15"},
{"YAMS_SEARCH_VECTOR_WEIGHT", "0.20"},
{"YAMS_SEARCH_RRF_K", "6"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_strategy_router",
"SCI + simeon EntropyRouter (BM25/Keyphrase/LeadField per-query strategy)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SIMEON_STRATEGY_ROUTER_ENABLED", "1"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"scientific_strategy_router_rrf6",
"SCI EntropyRouter + RRF k=6 + rescue=4 + subphrase aggressive",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_TUNING_OVERRIDE", std::nullopt},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SIMEON_STRATEGY_ROUTER_ENABLED", "1"},
{"YAMS_SEARCH_RRF_K", "6"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "4"},
{"YAMS_SEARCH_ENABLE_SUB_PHRASE_EXPANSION", "1"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION_MIN_HITS", "2"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION_PENALTY", "0.60"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
},
true},
{"mixed_graph_off",
"MIXED state with graph rerank disabled",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "0"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
}},
// ── Tier-1 diagnostic candidates ──────────────────────────────
// Purpose: determine if the 14 both-miss queries are recoverable
// by expanding the candidate pool and/or the evaluation window.
{"diag_winner_3x_candidates",
"Winner config + 3x candidate multiplier (vector pool 150->450)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
},
false,
true},
{"diag_winner_topk20",
"Winner config + topK=20 (recall@20 diagnostic)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_BENCH_TOPK", "20"},
},
false,
true},
{"diag_winner_topk50",
"Winner config + topK=50 (recall@50 diagnostic)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_BENCH_TOPK", "50"},
},
false,
true},
{"diag_winner_3x_topk50",
"Winner + 3x candidates + topK=50 (maximum retrieval diagnostic)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_BENCH_TOPK", "50"},
},
false,
true},
// ── Tier-2 cross-encoder reranker candidates ──────────────────
// Strategy: expand pool (3x) to get ~50 candidates, then use the
// bge-reranker-large cross-encoder to rescore and promote relevant
// documents that the bi-encoder ranked at positions 11-49 into
// the top-10. Tier-1 diagnostics showed 7 of 14 both-miss
// queries have relevant docs at ranks 11-49 — reranking should
// recover these.
// Current benchmark evidence: blend-60 beats blend-70 on both q20 and q300,
// while graph rerank / semantic rescue stay effectively inactive on SciFact.
// Treat rerank_3x_blend60_top50 as the engine-policy baseline; heavier recall probes
// below remain diagnostics unless they win on both quality and latency.
{"rerank_3x_replace_top50",
"3x pool + cross-encoder rerank top-50, replace scores (max reranker impact)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-50 candidates
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "1"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend60_top50",
"Current q300 winner: 3x pool + cross-encoder rerank top-50, blend 60/40 with fusion "
"scores",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-50, blend scores
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
},
true,
false},
{"rerank_4x_blend60_top50",
"Pre-fusion recall probe: winner + larger candidate multiplier (4x), rerank window stays "
"at top-50",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "4.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
},
false,
true},
{"rerank_3x_blend60_top50_fuse100",
"Pre-fusion recall probe: winner + moderately wider fusion window (fusion limit 100)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_FUSION_CANDIDATE_LIMIT", "100"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
},
false,
true},
{"rerank_3x_blend60_top50_lexical16",
"Pre-fusion recall probe: winner + milder lexical floor (top-16 / +0.24)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "16"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.24"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
},
false,
true},
{"rerank_3x_blend60_top50_fuse200",
"Pre-fusion recall probe: winner + wider fusion window (fusion limit 200), rerank window "
"stays at top-50",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_FUSION_CANDIDATE_LIMIT", "200"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend60_top50_lexical20",
"Pre-fusion recall probe: winner + stronger lexical floor (top-20 / +0.30)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "20"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.30"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"kg_budget_5ms",
"KG tradeoff probe: keep winner policy but tighten graph scoring budget to 5ms",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_GRAPH_BUDGET_MS", "5"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_INCLUDE_COMPONENT_TIMING", "1"},
},
false,
true},
{"kg_topn_12",
"KG tradeoff probe: keep winner policy but limit graph rerank window to top-12",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_GRAPH_RERANK_TOPN", "12"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_INCLUDE_COMPONENT_TIMING", "1"},
},
false,
true},
{"kg_weight_002_topn12",
"KG tradeoff probe: keep KG enabled with lighter weight 0.02 and top-12 rerank window",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_KG_WEIGHT", "0.02"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_GRAPH_RERANK_TOPN", "12"},
{"YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "0.12"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_INCLUDE_COMPONENT_TIMING", "1"},
},
false,
true},
{"rerank_3x_blend40_top50",
"3x pool + cross-encoder rerank top-50, blend 40/60 (conservative)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-50, conservative blend
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.40"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_replace_top50_snippet512",
"3x pool + cross-encoder rerank top-50, replace scores, 512-char snippets",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank top-50, larger snippets for more context
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "1"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "512"},
}},
// --- Faster rerank candidates (top-20) for quicker iteration ---
{"rerank_3x_replace_top20",
"3x pool + cross-encoder rerank top-20, replace scores",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "1"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend40_top20",
"3x pool + cross-encoder rerank top-20, blend 40/60 (conservative)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.40"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend60_top20",
"3x pool + cross-encoder rerank top-20, blend 60/40",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
// Adaptive blend: scale reranker weight by max-score confidence
{"rerank_3x_adaptive80_top20",
"3x pool + cross-encoder rerank top-20, adaptive blend (base 0.80, floor 0.10)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.80"},
{"YAMS_SEARCH_RERANK_ADAPTIVE_BLEND", "1"},
{"YAMS_SEARCH_RERANK_ADAPTIVE_BLEND_FLOOR", "0.10"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_adaptive60_top20",
"3x pool + cross-encoder rerank top-20, adaptive blend (base 0.60, floor 0.05)",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.60"},
{"YAMS_SEARCH_RERANK_ADAPTIVE_BLEND", "1"},
{"YAMS_SEARCH_RERANK_ADAPTIVE_BLEND_FLOOR", "0.05"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend70_top20",
"3x pool + cross-encoder rerank top-20, blend 70/30 with fusion scores",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-20, stronger blend
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.70"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend80_top20",
"3x pool + cross-encoder rerank top-20, blend 80/20 with fusion scores",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-20, aggressive blend
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "20"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.80"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
{"rerank_3x_blend70_top50",
"3x pool + cross-encoder rerank top-50, blend 70/30 with fusion scores",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-50, strong blend
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.70"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
}},
// Wide fusion window: pass many more fused results through the reranker
{"rerank_3x_blend70_top200_fuse200",
"3x pool + cross-encoder rerank top-200, blend 70/30, fusion window 200",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
// Cross-encoder reranking: rerank the top-200, strong blend
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "200"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.70"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
// Wider fusion window: keep 200 fused results (vs default 50)
{"YAMS_SEARCH_FUSION_CANDIDATE_LIMIT", "200"},
}},
// ── Tier 3: query expansion before rerank ───────────────────────────
{"rerank_3x_blend70_top50_multivec",
"3x pool + rerank top-50, blend 70/30, multi-vector sub-phrase search",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.70"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_MULTI_VECTOR_QUERY", "1"},
{"YAMS_SEARCH_MULTI_VECTOR_MAX_PHRASES", "3"},
{"YAMS_SEARCH_MULTI_VECTOR_SCORE_DECAY", "0.85"},
}},
{"rerank_3x_blend70_top50_subphrase_fts",
"3x pool + rerank top-50, blend 70/30, sub-phrase FTS expansion",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.70"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION", "1"},
{"YAMS_SEARCH_SUB_PHRASE_MIN_HITS", "5"},
{"YAMS_SEARCH_SUB_PHRASE_PENALTY", "0.70"},
}},
{"rerank_3x_blend70_top50_multivec_subphrase",
"3x pool + rerank top-50, blend 70/30, multi-vector + sub-phrase FTS",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.70"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_MULTI_VECTOR_QUERY", "1"},
{"YAMS_SEARCH_MULTI_VECTOR_MAX_PHRASES", "3"},
{"YAMS_SEARCH_MULTI_VECTOR_SCORE_DECAY", "0.85"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION", "1"},
{"YAMS_SEARCH_SUB_PHRASE_MIN_HITS", "5"},
{"YAMS_SEARCH_SUB_PHRASE_PENALTY", "0.70"},
}},
{"rerank_3x_blend50_top50_multivec_subphrase",
"3x pool + rerank top-50, blend 50/50, multi-vector + sub-phrase FTS",
{
{"YAMS_ENABLE_ENV_OVERRIDES", "1"},
{"YAMS_BENCH_FORCE_TUNING_OVERRIDE", std::nullopt},
{"YAMS_TUNING_OVERRIDE", "MIXED_PRECISION"},
{"YAMS_SEARCH_ENABLE_GRAPH_RERANK", "1"},
{"YAMS_SEARCH_VECTOR_ONLY_THRESHOLD", "0.92"},
{"YAMS_SEARCH_VECTOR_ONLY_PENALTY", "0.65"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_SLOTS", "2"},
{"YAMS_SEARCH_SEMANTIC_RESCUE_MIN_VECTOR_SCORE", "0.30"},
{"YAMS_SEARCH_ENABLE_ADAPTIVE_FALLBACK", "0"},
{"YAMS_SEARCH_LEXICAL_FLOOR_TOPN", "14"},
{"YAMS_SEARCH_LEXICAL_FLOOR_BOOST", "0.22"},
{"YAMS_SEARCH_ENABLE_LEXICAL_TIEBREAK", "1"},
{"YAMS_SEARCH_LEXICAL_TIEBREAK_EPS", "0.010"},
{"YAMS_CANDIDATE_MULTIPLIER", "3.0"},
{"YAMS_SEARCH_ENABLE_RERANKING", "1"},
{"YAMS_SEARCH_RERANK_TOPK", "50"},
{"YAMS_SEARCH_RERANK_REPLACE_SCORES", "0"},
{"YAMS_SEARCH_RERANK_WEIGHT", "0.50"},
{"YAMS_SEARCH_RERANK_SCORE_GAP_THRESHOLD", "0.0"},
{"YAMS_SEARCH_RERANK_SNIPPET_MAX_CHARS", "256"},
{"YAMS_SEARCH_MULTI_VECTOR_QUERY", "1"},
{"YAMS_SEARCH_MULTI_VECTOR_MAX_PHRASES", "3"},
{"YAMS_SEARCH_MULTI_VECTOR_SCORE_DECAY", "0.85"},
{"YAMS_SEARCH_SUB_PHRASE_EXPANSION", "1"},
{"YAMS_SEARCH_SUB_PHRASE_MIN_HITS", "5"},
{"YAMS_SEARCH_SUB_PHRASE_PENALTY", "0.70"},
}},
};
}
static std::set<std::string> parseCandidateFilter(const char* raw) {
std::set<std::string> selected;
if (!raw || !*raw) {
return selected;
}
std::string value(raw);
std::stringstream ss(value);
std::string token;
while (std::getline(ss, token, ',')) {
auto trim = [](std::string& s) {
const auto first = s.find_first_not_of(" \t\n\r");
if (first == std::string::npos) {
s.clear();
return;
}
const auto last = s.find_last_not_of(" \t\n\r");
s = s.substr(first, last - first + 1);
};
trim(token);
if (!token.empty()) {
selected.insert(token);
}
}
return selected;
}
enum class OptimizationProfile {
EnginePolicy,
Diagnostics,
All,
};
static OptimizationProfile parseOptimizationProfile(const char* raw) {
if (!raw || !*raw) {
return OptimizationProfile::EnginePolicy;
}
std::string value(raw);
std::transform(value.begin(), value.end(), value.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
if (value == "diagnostic" || value == "diagnostics" || value == "probe" || value == "probes") {
return OptimizationProfile::Diagnostics;
}
if (value == "all") {
return OptimizationProfile::All;
}
return OptimizationProfile::EnginePolicy;
}
static const char* optimizationProfileName(OptimizationProfile profile) {
switch (profile) {
case OptimizationProfile::EnginePolicy:
return "engine-policy";
case OptimizationProfile::Diagnostics:
return "diagnostics";
case OptimizationProfile::All:
return "all";
}
return "engine-policy";
}
static double computeHybridRegressionPenalty(const RetrievalMetrics& hybrid,
const RetrievalMetrics& keyword) {
const double hybridMrrLoss = std::max(0.0, keyword.mrr - hybrid.mrr);
return std::min(0.12, hybridMrrLoss * 2.0);
}
static double computeDuplicatePenalty(const RetrievalMetrics& hybrid) {
return std::min(0.08, std::max(0.0, hybrid.duplicateRateAtK) * 0.30);
}
static double computeLatencyPenalty(double avgHybridQueryMs) {
// Keep latency meaningful in the 3-7s/query range seen in real SciFact runs.
// The previous cap saturated far too early and made materially slower candidates
// look effectively free once they crossed ~800ms/query.
return std::clamp(std::max(0.0, avgHybridQueryMs) / 25000.0, 0.0, 0.25);
}
static double computePrecisionFailurePenalty(const QueryDiagnosticsSummary& summary) {
const double queryCount = static_cast<double>(std::max<std::uint64_t>(summary.queryCount, 1));
const double noRelevantHitRate =
static_cast<double>(summary.queryWithoutRelevantHitCount) / queryCount;
const double missPreFusionRate =
static_cast<double>(summary.missMissingPreFusionCount) / queryCount;
const double fusionCutoffRate = static_cast<double>(summary.missFusionCutoffCount) / queryCount;
const double rerankDropRate =
static_cast<double>(summary.missRerankWindowDropCount) / queryCount;
const double topKDropRate = static_cast<double>(summary.missTopKDropCount) / queryCount;
return std::min(0.25, missPreFusionRate * 0.25 + noRelevantHitRate * 0.10 +
fusionCutoffRate * 0.04 + rerankDropRate * 0.05 +
topKDropRate * 0.03);
}
static std::string summarizeTimingTradeoffs(const json& hybridDiag) {
if (!hybridDiag.is_object()) {
return "timings=unavailable";
}
const auto timingsIt = hybridDiag.find("timings_ms");
if (timingsIt == hybridDiag.end() || !timingsIt->is_object()) {
return "timings=unavailable";
}
const json& timings = *timingsIt;
std::vector<std::pair<std::string, double>> ranked;
ranked.reserve(timings.size());
for (const auto& [name, stats] : timings.items()) {
if (!stats.is_object()) {
continue;
}
auto meanIt = stats.find("mean");
if (meanIt == stats.end() || !meanIt->is_number()) {
continue;
}
ranked.emplace_back(name, meanIt->get<double>());
}
if (ranked.empty()) {
return "timings=unavailable";
}
std::sort(ranked.begin(), ranked.end(),
[](const auto& a, const auto& b) { return a.second > b.second; });
std::ostringstream oss;
oss << std::fixed << std::setprecision(1);
const size_t limit = std::min<size_t>(3, ranked.size());
for (size_t i = 0; i < limit; ++i) {
if (i > 0) {
oss << " ";
}
oss << ranked[i].first << '=' << ranked[i].second << "ms";
}
return oss.str();
}
static std::string summarizeStageTradeoffs(const json& hybridDiag) {
if (!hybridDiag.is_object()) {
return "stages=unavailable";
}
const auto stagesIt = hybridDiag.find("stage_contributions");
if (stagesIt == hybridDiag.end() || !stagesIt->is_object()) {
return "stages=unavailable";
}
const json& stages = *stagesIt;
std::vector<std::string> parts;
for (const auto& [name, stats] : stages.items()) {
if (!stats.is_object()) {
continue;
}
const double contributionRate = stats.value("contribution_rate", 0.0);
const double skipRate = stats.value("skip_rate", 0.0);
if (contributionRate <= 0.0 && skipRate <= 0.0) {
continue;
}
std::ostringstream oss;
oss << name << ":contrib=" << std::fixed << std::setprecision(2) << contributionRate
<< ",skip=" << skipRate;
parts.push_back(oss.str());
}
if (parts.empty()) {
return "stages=unavailable";
}
std::sort(parts.begin(), parts.end());
if (parts.size() > 3) {
parts.resize(3);
}
std::ostringstream out;
for (size_t i = 0; i < parts.size(); ++i) {
if (i > 0) {
out << " ";
}
out << parts[i];
}
return out.str();
}
static std::string summarizeStageMetricGaps(const json& hybridDiag) {
if (!hybridDiag.is_object()) {
return "stage_metrics=unavailable";
}
const auto metricsIt = hybridDiag.find("stage_metrics");
if (metricsIt == hybridDiag.end() || !metricsIt->is_object() || metricsIt->empty()) {
return "stage_metrics=unavailable";
}
static const std::vector<std::string> kStageOrder = {
"pre_fusion", "graphless_post_fusion", "post_fusion", "post_graph", "final",
};
std::vector<std::string> parts;
for (const auto& stage : kStageOrder) {
auto stageIt = metricsIt->find(stage);
if (stageIt == metricsIt->end() || !stageIt->is_object()) {
continue;
}
const double mrr = stageIt->value("mrr", 0.0);
const double recall = stageIt->value("recall_at_k", 0.0);
const double ndcg = stageIt->value("ndcg_at_k", 0.0);
const double mrrDelta = stageIt->value("mrr_delta_vs_final", 0.0);
const double ndcgDelta = stageIt->value("ndcg_delta_vs_final", 0.0);
std::ostringstream oss;
oss << stage << ":mrr=" << std::fixed << std::setprecision(3) << mrr
<< "(d=" << std::showpos << mrrDelta << std::noshowpos << ")"
<< ",rec=" << recall << ",ndcg=" << ndcg << "(d=" << std::showpos << ndcgDelta
<< std::noshowpos << ")";
parts.push_back(oss.str());
}
if (parts.empty()) {
return "stage_metrics=unavailable";
}
std::ostringstream out;
for (size_t i = 0; i < parts.size(); ++i) {
if (i > 0) {
out << " ";
}
out << parts[i];
}
return out.str();
}
static double computeOptimizationObjective(const RetrievalMetrics& hybrid,
const RetrievalMetrics& keyword,
const QueryDiagnosticsSummary& hybridDiagnostics,
double avgHybridQueryMs) {
// Precision-first objective for machine-first navigation: keep top-K correctness high while
// still rewarding rank quality and recall. Miss-stage penalties keep the loop focused on the
// actual places where relevant documents are lost.
const double quality = 0.32 * hybrid.mrr + 0.24 * hybrid.ndcgAtK + 0.24 * hybrid.precisionAtK +
0.12 * hybrid.recallAtK + 0.08 * hybrid.map;
const double hybridGain = std::max(0.0, hybrid.mrr - keyword.mrr);
const double regressionPenalty = computeHybridRegressionPenalty(hybrid, keyword);
const double duplicatePenalty = computeDuplicatePenalty(hybrid);
const double latencyPenalty = computeLatencyPenalty(avgHybridQueryMs);
const double precisionFailurePenalty = computePrecisionFailurePenalty(hybridDiagnostics);
return quality + 0.10 * hybridGain - regressionPenalty - duplicatePenalty - latencyPenalty -
precisionFailurePenalty;
}
static void appendOptimizationResultJson(const fs::path& outputFile,
const OptimizationRunResult& result) {
std::ofstream out(outputFile, std::ios::out | std::ios::app);
if (!out.is_open()) {
spdlog::warn("[OptLoop] Failed to open results file: {}", outputFile.string());
return;
}
json j;
j["candidate"] = result.candidate.name;
j["description"] = result.candidate.description;
j["success"] = result.success;
j["objective"] = result.objectiveScore;
j["hybrid_eval_ms"] = result.hybridEvalMs;
j["keyword_eval_ms"] = result.keywordEvalMs;
j["search_engine"] = result.searchEngine;
if (const char* embBackend = std::getenv("YAMS_EMBED_BACKEND"); embBackend && *embBackend) {
j["embedding_backend"] = embBackend;
} else {
j["embedding_backend"] = "daemon";
}
j["vectors_db_bytes"] = result.vectorsDbBytes;
j["vectors_wal_bytes"] = result.vectorsWalBytes;
j["persisted_hnsw_nodes"] = result.persistedHnswNodes;
j["persisted_hnsw_meta_rows"] = result.persistedHnswMetaRows;
j["persisted_vec0_tables"] = result.persistedVec0Tables;
j["persisted_vec0_rows"] = result.persistedVec0Rows;
j["persisted_pq_codes"] = result.persistedPqCodes;
j["persisted_pq_meta"] = result.persistedPqMeta;
j["tuning_state"] = result.tuningState;
j["tuning_reason"] = result.tuningReason;
j["error"] = result.errorMessage;
j["run_id"] = result.runId;
j["debug_file"] = result.debugFile;
j["trace_top_n"] = result.traceTopN;
j["trace_component_top_n"] = result.traceComponentTopN;
j["stage_trace_enabled"] = result.stageTraceEnabled;
j["hybrid_keyword_mrr_delta"] = result.hybridMetrics.mrr - result.keywordMetrics.mrr;
const double objectiveRegressionPenalty =
computeHybridRegressionPenalty(result.hybridMetrics, result.keywordMetrics);
const double objectiveDuplicatePenalty = computeDuplicatePenalty(result.hybridMetrics);
const double objectivePrecisionFailurePenalty =
computePrecisionFailurePenalty(result.hybridDiagnostics);
j["objective_penalties"] = {
{"hybrid_regression", objectiveRegressionPenalty},
{"duplicate_rate", objectiveDuplicatePenalty},
{"precision_failures", objectivePrecisionFailurePenalty},
};
j["hybrid"] = {
{"mrr", result.hybridMetrics.mrr},
{"recall_at_k", result.hybridMetrics.recallAtK},
{"precision_at_k", result.hybridMetrics.precisionAtK},
{"ndcg_at_k", result.hybridMetrics.ndcgAtK},
{"map", result.hybridMetrics.map},
{"duplicate_rate_at_k", result.hybridMetrics.duplicateRateAtK},
{"num_queries", result.hybridMetrics.numQueries},
};
j["keyword"] = {
{"mrr", result.keywordMetrics.mrr},
{"recall_at_k", result.keywordMetrics.recallAtK},
{"precision_at_k", result.keywordMetrics.precisionAtK},
{"ndcg_at_k", result.keywordMetrics.ndcgAtK},
{"map", result.keywordMetrics.map},
{"duplicate_rate_at_k", result.keywordMetrics.duplicateRateAtK},
{"num_queries", result.keywordMetrics.numQueries},
};
{
auto sampleMean = [](const std::vector<double>& v) -> double {
if (v.empty())
return 0.0;
double sum = 0.0;
for (double x : v)
sum += x;
return sum / static_cast<double>(v.size());
};
auto meanSignal = [&](const std::string& key) -> double {
auto it = result.hybridDiagnostics.tunerSignalSamples.find(key);
return it == result.hybridDiagnostics.tunerSignalSamples.end() ? 0.0
: sampleMean(it->second);
};
auto meanScoreMass = [&](const std::string& src) -> double {
auto it = result.hybridDiagnostics.fusionSourceScoreMassSamples.find(src);
return it == result.hybridDiagnostics.fusionSourceScoreMassSamples.end()
? 0.0
: sampleMean(it->second);
};
const double denseMass = meanScoreMass("vector") + meanScoreMass("compressed_ann") +
meanScoreMass("graph_vector") + meanScoreMass("entity_vector");
const double lexicalMass =
meanScoreMass("text") + meanScoreMass("graph_text") + meanScoreMass("path_tree");
const double otherMass = meanScoreMass("kg") + meanScoreMass("tag") +
meanScoreMass("metadata") + meanScoreMass("symbol");
const double totalMass = denseMass + lexicalMass + otherMass;
const double denseContrib = totalMass > 0.0 ? denseMass / totalMass : 0.0;
const double bm25Contrib = totalMass > 0.0 ? lexicalMass / totalMass : 0.0;
j["fusion_alpha"] = meanSignal("vector_weight");
j["text_weight"] = meanSignal("text_weight");
j["dense_contrib"] = denseContrib;
j["bm25_contrib"] = bm25Contrib;
j["other_contrib"] = totalMass > 0.0 ? otherMass / totalMass : 0.0;
j["ngram_range_used"] = "3-5";
j["idf_weighted"] = false;
}
j["hybrid_debug_summary"] = queryDiagnosticsToJson(result.hybridDiagnostics);
j["keyword_debug_summary"] = queryDiagnosticsToJson(result.keywordDiagnostics);
json env = json::object();
for (const auto& setting : result.candidate.envOverrides) {
if (setting.value.has_value()) {
env[setting.key] = *setting.value;
} else {
env[setting.key] = nullptr;
}
}
j["env_overrides"] = env;
out << j.dump() << "\n";
}
static std::chrono::milliseconds defaultBenchQueryTimeout(const std::string& searchType) {
if (searchType == "hybrid") {
// Hybrid benchmark runs exercise graph rerank, ONNX reranking, and stage tracing.
// The default 20s request timeout is too short for cold-ish benchmark slices and
// causes partial JSONL output because timed-out queries are skipped entirely.
return std::chrono::milliseconds{120000};
}
return std::chrono::milliseconds{20000};
}
static std::chrono::milliseconds configuredBenchQueryTimeout(const std::string& searchType) {
if (const char* env = std::getenv("YAMS_BENCH_QUERY_TIMEOUT_MS")) {
return std::chrono::milliseconds{
static_cast<std::chrono::milliseconds::rep>(std::stoll(env))};
}
return defaultBenchQueryTimeout(searchType);
}
static void ingestStageRetrievalMetrics(QueryDiagnosticsSummary& summary,
const std::map<std::string, std::string>& searchStats,
const TestQuery& tq, int k) {
static const std::vector<std::pair<std::string, std::string>> kStageDocIdStats = {
{"pre_fusion", "trace_pre_fusion_doc_ids"},
{"graphless_post_fusion", "trace_graphless_post_fusion_doc_ids"},
{"post_fusion", "trace_post_fusion_doc_ids"},
{"post_graph", "trace_post_graph_doc_ids"},
{"final", "trace_final_doc_ids"},
};
for (const auto& [stage, statKey] : kStageDocIdStats) {
auto it = searchStats.find(statKey);
if (it == searchStats.end() || it->second.empty()) {
continue;
}
auto rankedDocIds = splitTabList(it->second, static_cast<size_t>(std::max(0, k)));
yams::bench::addStageMetricSample(summary.stageRetrievalMetrics[stage], rankedDocIds, tq,
k);
}
}
RetrievalMetrics evaluateQueries(yams::daemon::DaemonClient& client, const fs::path& corpusDir,
const std::vector<TestQuery>& queries, int k,
const std::string& searchType = "hybrid",
QueryDiagnosticsSummary* diagnostics = nullptr,
bool emitDebug = true,
std::vector<double>* latencySamplesMs = nullptr,
std::vector<TestQuery>* failedQueries = nullptr) {
RetrievalMetrics metrics;
metrics.numQueries = static_cast<int>(queries.size());
double totalMRR = 0.0, totalRecall = 0.0, totalPrecision = 0.0, totalNDCG = 0.0, totalMAP = 0.0;
std::uint64_t totalAttempts = 0;
std::uint64_t streamingCount = 0;
std::uint64_t fuzzyRetryCount = 0;
std::uint64_t literalRetryCount = 0;
std::uint64_t duplicateTopKCount = 0;
std::uint64_t totalTopKCount = 0;
for (std::size_t queryIndex = 0; queryIndex < queries.size(); ++queryIndex) {
const auto& tq = queries[queryIndex];
yams::cli::search_runner::DaemonSearchOptions opts;
opts.query = tq.query;
opts.searchType = searchType;
opts.limit = static_cast<std::size_t>(k);
const auto queryTimeout = configuredBenchQueryTimeout(searchType);
opts.timeout = queryTimeout;
opts.symbolRank = true;
opts.allowFuzzyRetry = false;
opts.allowLiteralTextRetry = false;
const bool benchDiagEnabled = []() -> bool {
if (const char* env = std::getenv("YAMS_BENCH_DIAG"); env && std::string(env) == "1") {
return true;
}
return false;
}();
const bool benchVerbose = []() -> bool {
if (const char* env = std::getenv("YAMS_BENCH_VERBOSE"); env) {
std::string value(env);
std::transform(value.begin(), value.end(), value.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
return value == "1" || value == "true" || value == "yes" || value == "on";
}
return false;
}();
if (benchVerbose) {
spdlog::debug("Executing search query: '{}'", tq.query);
}
// Wait at least as long as the query timeout, plus a small margin.
// Using a shorter run_sync deadline can leave in-flight requests behind,
// which can cascade into timeouts/backpressure across subsequent queries.
auto waitBudget = std::chrono::duration_cast<std::chrono::milliseconds>(opts.timeout) +
std::chrono::seconds(10);
if (waitBudget < std::chrono::seconds(10)) {
waitBudget = std::chrono::seconds(10);
}
auto run = benchRunSync(
yams::cli::search_runner::daemon_search(client, opts, benchUseStreamingSearch()),
waitBudget);
if (!run) {
spdlog::warn("Search failed for query '{}': {}", tq.query, run.error().message);
if (failedQueries) {
failedQueries->push_back(tq);
}
DebugLogEntry failedEntry;
failedEntry.query = tq.query;
failedEntry.queryIndex = static_cast<int>(queryIndex);
failedEntry.searchType = searchType;
failedEntry.attempts = 0;
failedEntry.usedStreaming = false;
failedEntry.usedFuzzyFlag = false;
failedEntry.usedLiteralFlag = false;
failedEntry.usedFuzzyRetry = false;
failedEntry.usedLiteralTextRetry = false;
failedEntry.relevantDocIds.assign(tq.relevantDocIds.begin(), tq.relevantDocIds.end());
failedEntry.relevantFiles.assign(tq.relevantFiles.begin(), tq.relevantFiles.end());
failedEntry.diagnostics.push_back("search_error=" + run.error().message);
failedEntry.diagnostics.push_back("searchType=" + opts.searchType);
failedEntry.diagnostics.push_back("limit=" + std::to_string(opts.limit));
failedEntry.diagnostics.push_back(
"timeout_ms=" +
std::to_string(
std::chrono::duration_cast<std::chrono::milliseconds>(opts.timeout).count()));
const json relevantDecisionTrace = buildRelevantDecisionTrace(
failedEntry.relevantDocIds, failedEntry.returnedDocIds, failedEntry.searchStats);
failedEntry.extraFields["relevant_decision_trace"] = relevantDecisionTrace;
if (emitDebug) {
debugLogWriteJsonLine(failedEntry);
}
if (diagnostics) {
ingestQueryDiagnostics(*diagnostics, failedEntry.searchStats, relevantDecisionTrace,
true, false, false, -1);
}
continue;
}
totalAttempts += run.value().attempts;
if (run.value().usedStreaming)
streamingCount++;
if (run.value().usedFuzzyRetry)
fuzzyRetryCount++;
if (run.value().usedLiteralTextRetry)
literalRetryCount++;
const auto& results = run.value().response.results;
if (latencySamplesMs) {
const auto latencyIt = run.value().response.searchStats.find("latency_ms");
if (latencyIt != run.value().response.searchStats.end()) {
try {
const double latencyMs = std::stod(latencyIt->second);
if (std::isfinite(latencyMs) && latencyMs >= 0.0) {
latencySamplesMs->push_back(latencyMs);
}
} catch (const std::exception& e) {
if (benchVerbose) {
spdlog::debug("Ignoring malformed benchmark latency '{}': {}",
latencyIt->second, e.what());
}
}
}
}
if (benchVerbose) {
spdlog::debug("Search returned {} results for query '{}' (attempts={}, streaming={}, "
"fuzzy_retry={}, literal_retry={})",
results.size(), tq.query, run.value().attempts, run.value().usedStreaming,
run.value().usedFuzzyRetry, run.value().usedLiteralTextRetry);
}
// Detailed result logging for debugging retrieval quality
if (benchDiagEnabled) {
spdlog::debug(" [{}] Expected relevant: {} docs", searchType,
tq.relevantDocIds.size());
for (size_t i = 0; i < std::min((size_t)5, results.size()); ++i) {
const std::string filename = fs::path(results[i].path).filename().string();
const std::string docId = yams::bench::canonicalResultDocId(tq, filename);
const bool relevant = yams::bench::isRelevantDocForQuery(tq, docId);
spdlog::debug(" [{}] Result {}: path='{}' docId='{}' score={:.4f} {}", searchType,
i, results[i].path, docId, results[i].score,
relevant ? "RELEVANT" : "");
}
}
DebugLogEntry debugEntry;
debugEntry.query = tq.query;
debugEntry.queryIndex = static_cast<int>(queryIndex);
debugEntry.searchType = searchType;
debugEntry.attempts = run.value().attempts;
debugEntry.usedStreaming = run.value().usedStreaming;
debugEntry.usedFuzzyFlag = false;
debugEntry.usedLiteralFlag = false;
debugEntry.usedFuzzyRetry = run.value().usedFuzzyRetry;
debugEntry.usedLiteralTextRetry = run.value().usedLiteralTextRetry;
debugEntry.searchStats = run.value().response.searchStats;
debugEntry.relevantDocIds.assign(tq.relevantDocIds.begin(), tq.relevantDocIds.end());
debugEntry.relevantFiles.assign(tq.relevantFiles.begin(), tq.relevantFiles.end());
if (benchDiagEnabled) {
debugEntry.diagnostics.push_back("searchType=" + opts.searchType);
debugEntry.diagnostics.push_back(std::string("symbolRank=") +
(opts.symbolRank ? "true" : "false"));
debugEntry.diagnostics.push_back("limit=" + std::to_string(opts.limit));
debugEntry.diagnostics.push_back(
"timeout_ms=" +
std::to_string(
std::chrono::duration_cast<std::chrono::milliseconds>(opts.timeout).count()));
}
for (size_t i = 0; i < std::min((size_t)k, results.size()); ++i) {
debugEntry.returnedPaths.push_back(results[i].path);
debugEntry.returnedScores.push_back(static_cast<float>(results[i].score));
const std::string filename = fs::path(results[i].path).filename().string();
debugEntry.returnedDocIds.push_back(yams::bench::canonicalResultDocId(tq, filename));
totalTopKCount++;
}
const auto scoreSample = yams::bench::scoreRankedDocIds(tq, debugEntry.returnedDocIds, k);
debugEntry.returnedGrades = scoreSample.retrievedGrades;
for (const auto& docId : scoreSample.duplicateDocIds) {
duplicateTopKCount++;
debugEntry.diagnostics.push_back("duplicate_topk_doc=" + docId);
}
const json relevantDecisionTrace = buildRelevantDecisionTrace(
debugEntry.relevantDocIds, debugEntry.returnedDocIds, debugEntry.searchStats);
debugEntry.extraFields["relevant_decision_trace"] = relevantDecisionTrace;
debugEntry.extraFields["query_metrics"] = {
{"mrr", scoreSample.reciprocalRank},
{"recall_at_k", scoreSample.recallAtK},
{"precision_at_k", scoreSample.precisionAtK},
{"ndcg_at_k", scoreSample.ndcgAtK},
{"map", scoreSample.averagePrecision},
{"first_relevant_rank", scoreSample.firstRelevantRank},
};
if (benchDiagEnabled && results.empty() && tq.useDocIds && !tq.relevantDocIds.empty()) {
// Opt-in diagnostic: show a snippet of the relevant BEIR doc file(s).
std::size_t printed = 0;
for (const auto& docId : tq.relevantDocIds) {
if (printed >= 2)
break;
const fs::path p = corpusDir / (docId + ".txt");
if (!fs::exists(p)) {
debugEntry.diagnostics.push_back("relevant_doc_missing=" + p.string());
continue;
}
std::ifstream in(p);
if (!in.is_open()) {
debugEntry.diagnostics.push_back("relevant_doc_open_failed=" + p.string());
continue;
}
std::string snippet;
snippet.resize(240);
in.read(snippet.data(), static_cast<std::streamsize>(snippet.size()));
snippet.resize(static_cast<std::size_t>(in.gcount()));
for (auto& c : snippet) {
if (c == '\n' || c == '\r' || c == '\t')
c = ' ';
}
debugEntry.diagnostics.push_back("relevant_doc_snippet[" + docId + "]=" + snippet);
++printed;
}
}
// Opt-in diagnostic: run a few "shadow" queries for failing cases.
// This does not affect scoring; it only emits diagnostic entries.
if (emitDebug && benchDiagEnabled && results.empty()) {
// 1) Try a shorter query with a few salient tokens to test whether the full
// sentence query is failing due to strict AND semantics / tokenization.
std::istringstream iss(tq.query);
std::string token;
std::vector<std::string> picked;
picked.reserve(3);
while (iss >> token && picked.size() < 3) {
// Strip trailing punctuation for the diagnostic query.
while (!token.empty() && std::ispunct(static_cast<unsigned char>(token.back()))) {
token.pop_back();
}
if (token.size() < 4)
continue;
picked.push_back(token);
}
if (!picked.empty()) {
std::string diagQuery;
for (size_t i = 0; i < picked.size(); ++i) {
if (i)
diagQuery += ' ';
diagQuery += picked[i];
}
yams::cli::search_runner::DaemonSearchOptions shadow;
shadow.query = diagQuery;
shadow.searchType = opts.searchType;
shadow.limit = opts.limit;
shadow.timeout = opts.timeout;
shadow.symbolRank = opts.symbolRank;
shadow.allowFuzzyRetry = false;
shadow.allowLiteralTextRetry = false;
DebugLogEntry shadowEntry;
shadowEntry.query = "__diag_shadow_query__";
shadowEntry.queryIndex = static_cast<int>(queryIndex);
shadowEntry.searchType = searchType;
shadowEntry.relevantDocIds.assign(tq.relevantDocIds.begin(),
tq.relevantDocIds.end());
shadowEntry.diagnostics.push_back("original_query=" + tq.query);
shadowEntry.diagnostics.push_back("shadow_query=" + diagQuery);
auto shadowRun = benchRunSync(
yams::cli::search_runner::daemon_search(client, shadow,
benchUseStreamingSearch()),
std::chrono::duration_cast<std::chrono::milliseconds>(shadow.timeout) +
std::chrono::seconds(10));
if (shadowRun) {
shadowEntry.attempts = shadowRun.value().attempts;
shadowEntry.usedStreaming = shadowRun.value().usedStreaming;
shadowEntry.usedFuzzyRetry = shadowRun.value().usedFuzzyRetry;
shadowEntry.usedLiteralTextRetry = shadowRun.value().usedLiteralTextRetry;
shadowEntry.returnedDocIds.push_back(
"result_count=" +
std::to_string(shadowRun.value().response.results.size()));
for (size_t i = 0;
i < std::min<size_t>(5, shadowRun.value().response.results.size()); ++i) {
shadowEntry.returnedPaths.push_back(
shadowRun.value().response.results[i].path);
}
} else {
shadowEntry.returnedDocIds.push_back("shadow_error=" +
shadowRun.error().message);
}
debugLogWriteJsonLine(shadowEntry);
}
}
if (emitDebug) {
debugLogWriteJsonLine(debugEntry);
}
if (diagnostics) {
ingestQueryDiagnostics(*diagnostics, run.value().response.searchStats,
relevantDecisionTrace, false, !results.empty(),
scoreSample.hadDuplicateInTopK, scoreSample.firstRelevantRank);
ingestStageRetrievalMetrics(*diagnostics, run.value().response.searchStats, tq, k);
}
totalMRR += scoreSample.reciprocalRank;
totalRecall += scoreSample.recallAtK;
totalPrecision += scoreSample.precisionAtK;
totalMAP += scoreSample.averagePrecision;
totalNDCG += scoreSample.ndcgAtK;
}
if (metrics.numQueries > 0) {
metrics.mrr = totalMRR / metrics.numQueries;
metrics.recallAtK = totalRecall / metrics.numQueries;
metrics.precisionAtK = totalPrecision / metrics.numQueries;
metrics.ndcgAtK = totalNDCG / metrics.numQueries;
metrics.map = totalMAP / metrics.numQueries;
if (totalTopKCount > 0) {
metrics.duplicateRateAtK =
static_cast<double>(duplicateTopKCount) / static_cast<double>(totalTopKCount);
}
spdlog::info("Search execution stats: queries={} total_attempts={} avg_attempts={:.2f} "
"streaming={} fuzzy_retries={} literal_retries={} duplicate_rate@k={:.4f}",
metrics.numQueries, totalAttempts,
static_cast<double>(totalAttempts) / metrics.numQueries, streamingCount,
fuzzyRetryCount, literalRetryCount, metrics.duplicateRateAtK);
}
return metrics;
}
RetrievalMetrics evaluateGrepQueries(yams::daemon::DaemonClient& client,
const std::vector<TestQuery>& queries, int k) {
RetrievalMetrics metrics;
metrics.numQueries = static_cast<int>(queries.size());
double totalMRR = 0.0;
double totalRecall = 0.0;
double totalPrecision = 0.0;
double totalNDCG = 0.0;
double totalMAP = 0.0;
std::uint64_t totalTopKCount = 0;
std::uint64_t duplicateTopKCount = 0;
for (const auto& tq : queries) {
yams::daemon::GrepRequest req;
req.pattern = tq.query;
req.literalText = true;
req.pathsOnly = true;
req.maxMatches = 1;
req.useSession = false;
const auto queryTimeout = configuredBenchQueryTimeout("grep");
auto waitBudget = queryTimeout + std::chrono::seconds(10);
if (waitBudget < std::chrono::seconds(10)) {
waitBudget = std::chrono::seconds(10);
}
auto run = benchRunSync(client.grep(req), waitBudget);
if (!run) {
spdlog::warn("Grep failed for query '{}': {}", tq.query, run.error().message);
continue;
}
std::vector<std::string> rankedDocIds;
rankedDocIds.reserve(std::min<std::size_t>(static_cast<std::size_t>(std::max(0, k)),
run.value().pathsOnly.size()));
for (size_t i = 0; i < std::min<std::size_t>(static_cast<std::size_t>(std::max(0, k)),
run.value().pathsOnly.size());
++i) {
const std::string filename = fs::path(run.value().pathsOnly[i]).filename().string();
rankedDocIds.push_back(yams::bench::canonicalResultDocId(tq, filename));
totalTopKCount++;
}
const auto scoreSample = yams::bench::scoreRankedDocIds(tq, rankedDocIds, k);
duplicateTopKCount += scoreSample.duplicateDocIds.size();
totalMRR += scoreSample.reciprocalRank;
totalRecall += scoreSample.recallAtK;
totalPrecision += scoreSample.precisionAtK;
totalMAP += scoreSample.averagePrecision;
totalNDCG += scoreSample.ndcgAtK;
}
if (metrics.numQueries > 0) {
const double queryCount = static_cast<double>(metrics.numQueries);
metrics.mrr = totalMRR / queryCount;
metrics.recallAtK = totalRecall / queryCount;
metrics.precisionAtK = totalPrecision / queryCount;
metrics.ndcgAtK = totalNDCG / queryCount;
metrics.map = totalMAP / queryCount;
if (totalTopKCount > 0) {
metrics.duplicateRateAtK =
static_cast<double>(duplicateTopKCount) / static_cast<double>(totalTopKCount);
}
}
return metrics;
}
struct BenchFixture {
struct SetupTimingMetrics {
bool coldIngestPerformed = false;
int64_t admissionMs = 0;
int64_t storageReadyMs = 0;
int64_t pipelineDrainMs = 0;
int64_t searchabilityReadyMs = 0;
int64_t enrichmentReadyMs = 0;
bool vectorIndexPrepared = false;
bool vectorIndexPersisted = false;
bool vectorIndexReusableBefore = false;
bool vectorIndexReusableAfter = false;
bool vectorQueryReadyAfter = false;
int64_t vectorIndexPrepareMs = 0;
int64_t vectorIndexPersistMs = 0;
int64_t vectorIndexReusableProbeMs = 0;
std::uint64_t vectorIndexReusableProbeCount = 0;
int64_t setupTotalMs = 0;
};
std::unique_ptr<DaemonHarness> harness;
std::unique_ptr<ScopedEnvOverrides> scopedEnv;
std::unique_ptr<ScopedEnvOverrides> pluginScopedEnv;
std::unique_ptr<yams::daemon::DaemonClient> client;
std::unique_ptr<CorpusGenerator> corpus;
std::unique_ptr<BEIRCorpusLoader> beirCorpus;
fs::path benchCorpusDir;
fs::path warmDataDirPath;
std::optional<BenchCacheMetadata> warmCacheMetadata;
std::vector<TestQuery> queries;
int corpusSize = 50, numQueries = 10, topK = 10;
bool useBEIR = false;
SyntheticCorpusMode syntheticCorpusMode = SyntheticCorpusMode::Generic;
bool warmDataDir = false; // True when reusing a pre-ingested data directory
SetupTimingMetrics setupTimings;
std::string datasetName = "synthetic";
std::string beirDatasetName; // Name of BEIR dataset (scifact, cqadupstack, etc.)
bool useSyntheticCommunityCorpus() const {
return syntheticCorpusMode == SyntheticCorpusMode::CommunityGraph;
}
std::string datasetDisplayName() const {
if (useBEIR) {
return beirDatasetName == "local-manifest" ? std::string("local manifest")
: beirDatasetName + " BEIR";
}
if (syntheticCorpusMode == SyntheticCorpusMode::CommunityGraph) {
return "synthetic-community";
}
if (syntheticCorpusMode == SyntheticCorpusMode::HardLexical) {
return "synthetic-hard";
}
return datasetName;
}
bool benchmarkSemanticNeighborSeedingEnabled() const {
const char* raw = std::getenv("YAMS_BENCH_SEED_SEMANTIC_NEIGHBORS");
if (!(raw && *raw)) {
return false;
}
std::string value(raw);
std::transform(value.begin(), value.end(), value.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return value == "1" || value == "true" || value == "yes" || value == "on";
}
void seedSyntheticCommunityEdges() {
if (!useSyntheticCommunityCorpus()) {
return;
}
auto* daemon = harness ? harness->daemon() : nullptr;
auto* serviceManager = daemon ? daemon->getServiceManager() : nullptr;
auto metadataRepo = serviceManager ? serviceManager->getMetadataRepo() : nullptr;
auto kgStore = metadataRepo ? metadataRepo->getKnowledgeGraphStore() : nullptr;
if (!metadataRepo || !kgStore) {
throw std::runtime_error(
"Synthetic community corpus requires metadata and KG stores after ingest");
}
const std::array<std::string, 3> docNames = {
"community_target.txt", "community_partner.txt", "community_rival.txt"};
std::vector<std::int64_t> nodeIds;
nodeIds.reserve(docNames.size());
for (const auto& docName : docNames) {
const auto docPath = (benchCorpusDir / docName).string();
auto docResult = metadataRepo->findDocumentByExactPath(docPath);
if (!docResult) {
throw std::runtime_error("Failed to resolve synthetic community document " +
docPath + ": " + docResult.error().message);
}
if (!docResult.value().has_value()) {
throw std::runtime_error("Synthetic community document missing from metadata: " +
docPath);
}
const auto& doc = *docResult.value();
auto nodeIdResult = kgStore->ensureDocumentNode(doc.sha256Hash, doc.fileName);
if (!nodeIdResult) {
throw std::runtime_error("Failed to ensure synthetic community KG node: " +
nodeIdResult.error().message);
}
nodeIds.push_back(nodeIdResult.value());
}
std::vector<metadata::KGEdge> edges;
metadata::KGEdge forward;
forward.srcNodeId = nodeIds[0];
forward.dstNodeId = nodeIds[1];
forward.relation = "semantic_neighbor";
forward.weight = 1.0f;
edges.push_back(forward);
metadata::KGEdge reverse;
reverse.srcNodeId = nodeIds[1];
reverse.dstNodeId = nodeIds[0];
reverse.relation = "semantic_neighbor";
reverse.weight = 1.0f;
edges.push_back(reverse);
auto addEdgesResult = kgStore->addEdgesUnique(edges);
if (!addEdgesResult) {
throw std::runtime_error("Failed to seed synthetic community KG edges: " +
addEdgesResult.error().message);
}
spdlog::info("Seeded synthetic community KG edges for {} documents", docNames.size());
}
bool seedBenchmarkSemanticNeighbors() {
if (!benchmarkSemanticNeighborSeedingEnabled()) {
return false;
}
auto* daemon = harness ? harness->daemon() : nullptr;
auto* serviceManager = daemon ? daemon->getServiceManager() : nullptr;
auto metadataRepo = serviceManager ? serviceManager->getMetadataRepo() : nullptr;
auto kgStore = metadataRepo ? metadataRepo->getKnowledgeGraphStore() : nullptr;
auto vectorDb = serviceManager ? serviceManager->getVectorDatabase() : nullptr;
if (!metadataRepo || !kgStore) {
throw std::runtime_error("Semantic benchmark seeding requires metadata and KG stores");
}
auto parseSizeEnv = [](const char* primary, const char* fallback,
std::size_t defaultValue) {
for (const char* key : {primary, fallback}) {
if (!key) {
continue;
}
if (const char* raw = std::getenv(key); raw && *raw) {
try {
return static_cast<std::size_t>(std::max(1, std::stoi(raw)));
} catch (...) {
}
}
}
return defaultValue;
};
auto parseFloatEnv = [](const char* primary, const char* fallback, float defaultValue) {
for (const char* key : {primary, fallback}) {
if (!key) {
continue;
}
if (const char* raw = std::getenv(key); raw && *raw) {
try {
return std::clamp(std::stof(raw), 0.0f, 1.0f);
} catch (...) {
}
}
}
return defaultValue;
};
auto parseBoolEnv = [](const char* key, bool defaultValue) {
if (!(key && *key)) {
return defaultValue;
}
if (const char* raw = std::getenv(key); raw && *raw) {
std::string value(raw);
std::transform(value.begin(), value.end(), value.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return value == "1" || value == "true" || value == "yes" || value == "on";
}
return defaultValue;
};
std::string topologySource = "vector";
if (const char* raw = std::getenv("YAMS_BENCH_TOPOLOGY_SOURCE"); raw && *raw) {
topologySource = raw;
std::transform(topologySource.begin(), topologySource.end(), topologySource.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
}
if (topologySource == "lexical" || topologySource == "bm25") {
topologySource = "fts5";
}
if (topologySource == "graph") {
topologySource = "kg";
}
if (topologySource == "title" || topologySource == "heading") {
topologySource = "header";
}
if (topologySource == "segment-keyphrase" || topologySource == "segmentkeyphrase") {
topologySource = "segment_keyphrase";
}
if (topologySource != "vector" && topologySource != "fts5" &&
topologySource != "keyphrase" && topologySource != "segment_keyphrase" &&
topologySource != "kg" && topologySource != "gliner" && topologySource != "header" &&
topologySource != "theme") {
throw std::runtime_error("YAMS_BENCH_TOPOLOGY_SOURCE must be vector, fts5, "
"keyphrase, segment_keyphrase, kg, gliner, header, or theme");
}
if (topologySource == "vector" && !vectorDb) {
throw std::runtime_error("Vector topology-source seeding requires vector store");
}
const std::size_t semanticTopK =
parseSizeEnv("YAMS_BENCH_SEED_SEMANTIC_TOPK", "YAMS_GRAPH_SEMANTIC_TOPK", 6);
const float semanticThreshold = parseFloatEnv("YAMS_BENCH_SEED_SEMANTIC_THRESHOLD",
"YAMS_GRAPH_SEMANTIC_THRESHOLD", 0.30f);
const float semanticWeightFloor =
parseFloatEnv("YAMS_BENCH_SEED_SEMANTIC_WEIGHT_FLOOR", nullptr, 0.10f);
const bool seedQrelCommunities = parseBoolEnv("YAMS_BENCH_SEED_QREL_COMMUNITIES", false) &&
useBEIR && static_cast<bool>(beirCorpus);
const std::size_t qrelTopK = parseSizeEnv("YAMS_BENCH_SEED_QREL_TOPK", nullptr, 4);
const std::size_t kgFeatureLimit =
parseSizeEnv("YAMS_BENCH_SEED_KG_FEATURE_LIMIT", nullptr, 512);
const std::size_t keyphraseFeatureLimit =
parseSizeEnv("YAMS_BENCH_KEYPHRASE_FEATURE_LIMIT", nullptr, 16);
const std::size_t keyphraseMaxDocumentFrequency =
parseSizeEnv("YAMS_BENCH_KEYPHRASE_MAX_DF", nullptr, 64);
const std::size_t segmentTokenBudget =
parseSizeEnv("YAMS_BENCH_SEGMENT_TOKENS", nullptr, 192);
const std::size_t segmentTokenOverlap =
parseSizeEnv("YAMS_BENCH_SEGMENT_OVERLAP", nullptr, 32);
const std::size_t segmentFeatureLimit =
parseSizeEnv("YAMS_BENCH_SEGMENT_FEATURE_LIMIT", nullptr, 12);
const std::size_t segmentMaxDocumentFrequency =
parseSizeEnv("YAMS_BENCH_SEGMENT_MAX_DF", nullptr, keyphraseMaxDocumentFrequency);
const std::size_t segmentMaxEdgesPerFeature =
parseSizeEnv("YAMS_BENCH_SEGMENT_FEATURE_EDGE_BUDGET", nullptr, 64);
const std::size_t topologyMaxComponentDocs =
parseSizeEnv("YAMS_BENCH_TOPOLOGY_MAX_COMPONENT_DOCS", nullptr, 64);
auto validateAndLogTopologyCertificate =
[&](const yams::bench::BenchmarkTopologyConstructionCertificate& cert) {
auto checkedCert = cert;
checkedCert.gates.maxComponentDocs = topologyMaxComponentDocs;
const auto validation =
yams::bench::validateTopologyConstructionCertificate(checkedCert);
if (g_debugOut) {
DebugLogEntry certificateEntry;
certificateEntry.searchType = "benchmark_setup";
certificateEntry.extraFields = {
{"event", "topology_construction_certificate"},
{"topology_source", topologySource},
{"certificate", yams::bench::topologyConstructionCertificateToJson(
checkedCert, validation)},
};
debugLogWriteJsonLine(certificateEntry);
}
if (!validation.ok) {
const std::string firstError =
validation.errors.empty()
? "unknown topology construction certificate error"
: validation.errors.front();
throw std::runtime_error(
"Benchmark topology construction certificate failed: " + firstError);
}
};
std::vector<std::string> documentPaths;
if (useBEIR && beirCorpus) {
documentPaths = beirCorpus->getDocumentPaths();
} else if (corpus) {
documentPaths.reserve(corpus->createdFiles.size());
for (const auto& filename : corpus->createdFiles) {
documentPaths.push_back((benchCorpusDir / filename).string());
}
}
if (documentPaths.empty()) {
throw std::runtime_error("Semantic benchmark seeding found no document paths");
}
struct DocSeedInfo {
std::string hash;
std::string benchmarkDocId;
std::string text;
std::string headerText;
std::string themeText;
std::vector<float> embedding;
std::int64_t documentId = 0;
std::int64_t nodeId = 0;
};
std::vector<DocSeedInfo> docs;
docs.reserve(documentPaths.size());
yams::crypto::SHA256Hasher contentHasher;
std::size_t warmPathRebases = 0;
auto trimCopy = [](std::string value) {
const auto first = std::find_if_not(
value.begin(), value.end(), [](unsigned char ch) { return std::isspace(ch) != 0; });
const auto last = std::find_if_not(value.rbegin(), value.rend(), [](unsigned char ch) {
return std::isspace(ch) != 0;
}).base();
if (first >= last) {
return std::string{};
}
return std::string(first, last);
};
auto deriveHeaderText = [&](std::string_view benchmarkDocId, std::string_view body,
std::string_view fallbackName) {
if (useBEIR && beirCorpus && !benchmarkDocId.empty()) {
if (auto it = beirCorpus->dataset.documents.find(std::string(benchmarkDocId));
it != beirCorpus->dataset.documents.end()) {
auto title = trimCopy(it->second.title);
if (!title.empty()) {
return title;
}
}
}
std::istringstream lines{std::string(body)};
std::string line;
while (std::getline(lines, line)) {
line = trimCopy(line);
if (line.empty()) {
continue;
}
while (!line.empty() && line.front() == '#') {
line.erase(line.begin());
}
line = trimCopy(line);
if (!line.empty()) {
return line;
}
}
return trimCopy(std::string(fallbackName));
};
for (const auto& docPath : documentPaths) {
auto docResult = metadataRepo->findDocumentByExactPath(docPath);
if (!docResult) {
throw std::runtime_error("Failed to resolve benchmark document " + docPath + ": " +
docResult.error().message);
}
auto resolvedDoc = std::move(docResult.value());
if (!resolvedDoc.has_value() && warmDataDir) {
const auto contentHash = contentHasher.hashFile(docPath);
auto hashResult = metadataRepo->getDocumentByHash(contentHash);
if (!hashResult) {
throw std::runtime_error("Failed to resolve warm-cache benchmark document " +
docPath +
" by content hash: " + hashResult.error().message);
}
resolvedDoc = std::move(hashResult.value());
if (resolvedDoc.has_value()) {
++warmPathRebases;
}
}
if (!resolvedDoc.has_value()) {
throw std::runtime_error("Benchmark document missing from metadata: " + docPath);
}
const auto& doc = *resolvedDoc;
std::vector<float> embedding;
if (topologySource == "vector") {
const auto vectors = vectorDb->getVectorsByDocument(doc.sha256Hash);
if (vectors.empty()) {
continue;
}
const auto documentLevel = std::find_if(
vectors.begin(), vectors.end(), [](const yams::vector::VectorRecord& record) {
return record.level == yams::vector::EmbeddingLevel::DOCUMENT &&
!record.embedding.empty();
});
const auto chosen =
(documentLevel != vectors.end() && !documentLevel->embedding.empty())
? documentLevel
: std::find_if(vectors.begin(), vectors.end(),
[](const yams::vector::VectorRecord& record) {
return !record.embedding.empty();
});
if (chosen == vectors.end() || chosen->embedding.empty()) {
continue;
}
embedding = chosen->embedding;
}
std::string text;
std::string headerText;
std::string themeText;
if (topologySource == "fts5" || topologySource == "keyphrase" ||
topologySource == "segment_keyphrase" || topologySource == "header" ||
topologySource == "theme") {
auto contentResult = metadataRepo->getContent(doc.id);
if (contentResult && contentResult.value().has_value()) {
text = contentResult.value()->contentText;
}
if (text.empty()) {
std::ifstream in(docPath, std::ios::binary);
if (in) {
std::ostringstream buffer;
buffer << in.rdbuf();
text = buffer.str();
}
}
if (text.empty()) {
continue;
}
headerText =
deriveHeaderText(fs::path(docPath).stem().string(), text, doc.fileName);
themeText = headerText;
const std::size_t snippetSize = std::min<std::size_t>(text.size(), 512);
if (snippetSize > 0) {
if (!themeText.empty()) {
themeText.push_back('\n');
}
themeText.append(text.data(), snippetSize);
}
if (topologySource == "header" && headerText.empty()) {
continue;
}
if (topologySource == "theme" && themeText.empty()) {
continue;
}
}
auto nodeIdResult = kgStore->ensureDocumentNode(doc.sha256Hash, doc.fileName);
if (!nodeIdResult) {
throw std::runtime_error("Failed to ensure benchmark semantic KG node: " +
nodeIdResult.error().message);
}
docs.push_back({doc.sha256Hash, fs::path(docPath).stem().string(), text, headerText,
themeText, embedding, doc.id, nodeIdResult.value()});
}
if (warmPathRebases > 0) {
spdlog::info("Resolved {} cloned warm-cache documents by stable content hash",
warmPathRebases);
}
if (docs.size() < 2) {
spdlog::warn("Skipping {} topology-source benchmark seeding: only {} usable documents",
topologySource, docs.size());
return false;
}
if ((topologySource == "kg" || topologySource == "gliner") && useBEIR && beirCorpus &&
!beirCorpus->dataset.kgEntities.empty()) {
std::unordered_map<std::string, const DocSeedInfo*> docByBenchmarkId;
docByBenchmarkId.reserve(docs.size());
for (const auto& doc : docs) {
if (!doc.benchmarkDocId.empty()) {
docByBenchmarkId.emplace(doc.benchmarkDocId, &doc);
}
}
std::vector<metadata::DocEntity> docEntities;
std::vector<metadata::KGEdge> manifestEdges;
std::size_t manifestEntitiesSeeded = 0;
for (const auto& entity : beirCorpus->dataset.kgEntities) {
const auto docIt = docByBenchmarkId.find(entity.docId);
if (docIt == docByBenchmarkId.end()) {
continue;
}
const auto* doc = docIt->second;
metadata::KGNode entityNode;
entityNode.nodeKey = "bench:entity:" + entity.entityKey;
entityNode.label = entity.label.empty() ? entity.entityKey : entity.label;
entityNode.type = entity.type.empty() ? "benchmark_entity" : entity.type;
entityNode.properties = json{
{"source", "benchmark_manifest"},
{"doc_id", entity.docId},
{"entity_key",
entity.entityKey}}.dump();
auto entityNodeResult = kgStore->upsertNode(entityNode);
if (!entityNodeResult) {
throw std::runtime_error(
"Failed to seed benchmark KG entity node for topology source: " +
entityNodeResult.error().message);
}
const float weight = std::clamp(entity.weight, 0.05F, 1.0F);
metadata::DocEntity docEntity;
docEntity.documentId = doc->documentId;
docEntity.entityText = entity.label.empty() ? entity.entityKey : entity.label;
docEntity.nodeId = entityNodeResult.value();
docEntity.confidence = weight;
docEntity.extractor =
entity.extractor.empty() ? "benchmark_manifest" : entity.extractor;
docEntities.push_back(docEntity);
metadata::KGEdge edge;
edge.srcNodeId = entityNodeResult.value();
edge.dstNodeId = doc->nodeId;
edge.relation = entity.relation.empty() || entity.relation == "semantic_neighbor"
? "manifest_entity_of"
: entity.relation;
edge.weight = weight;
edge.properties = json{{"source", "benchmark_manifest"},
{"doc_id", entity.docId},
{"entity_key", entity.entityKey}}
.dump();
manifestEdges.push_back(edge);
++manifestEntitiesSeeded;
}
if (!docEntities.empty()) {
auto addDocEntitiesResult = kgStore->addDocEntities(docEntities);
if (!addDocEntitiesResult) {
throw std::runtime_error(
"Failed to seed benchmark KG doc entities for topology source: " +
addDocEntitiesResult.error().message);
}
}
if (!manifestEdges.empty()) {
auto addEdgesResult = kgStore->addEdgesUnique(manifestEdges);
if (!addEdgesResult) {
throw std::runtime_error(
"Failed to seed benchmark KG relation edges for topology source: " +
addEdgesResult.error().message);
}
}
spdlog::info("Seeded {} manifest KG entity annotations and {} relation edges for "
"topology-source graph features",
manifestEntitiesSeeded, manifestEdges.size());
}
std::unordered_map<std::string, std::unordered_map<std::string, float>> neighborScores;
neighborScores.reserve(docs.size());
if (topologySource == "vector") {
yams::vector::VectorSearchParams params;
params.k = semanticTopK + 4;
params.similarity_threshold = semanticThreshold;
for (const auto& doc : docs) {
const auto neighbors = vectorDb->searchSimilar(doc.embedding, params);
auto& scores = neighborScores[doc.hash];
for (const auto& rec : neighbors) {
if (rec.level != yams::vector::EmbeddingLevel::DOCUMENT) {
continue;
}
if (rec.document_hash.empty() || rec.document_hash == doc.hash) {
continue;
}
if (rec.relevance_score < semanticThreshold) {
continue;
}
auto [it, inserted] = scores.emplace(rec.document_hash, rec.relevance_score);
if (!inserted) {
it->second = std::max(it->second, rec.relevance_score);
}
if (scores.size() >= semanticTopK) {
break;
}
}
}
} else if (topologySource == "keyphrase" || topologySource == "segment_keyphrase") {
std::vector<yams::bench::KeyphraseTopologyDocument> keyphraseDocs;
keyphraseDocs.reserve(docs.size());
for (const auto& doc : docs) {
keyphraseDocs.push_back({.documentHash = doc.hash, .text = doc.text});
}
yams::bench::BenchmarkTopologyConstructionCertificate certificate;
std::vector<yams::bench::LexicalTopologyNeighbor> keyphraseNeighbors;
if (topologySource == "segment_keyphrase") {
keyphraseNeighbors = yams::bench::buildSegmentKeyphraseTopologyNeighbors(
keyphraseDocs, semanticTopK, semanticThreshold, segmentTokenBudget,
segmentTokenOverlap, segmentFeatureLimit, segmentMaxDocumentFrequency,
topologyMaxComponentDocs, segmentMaxEdgesPerFeature, true, &certificate);
} else {
keyphraseNeighbors = yams::bench::buildKeyphraseTopologyNeighbors(
keyphraseDocs, semanticTopK, semanticThreshold, keyphraseFeatureLimit,
keyphraseMaxDocumentFrequency, true, &certificate);
}
validateAndLogTopologyCertificate(certificate);
for (const auto& neighbor : keyphraseNeighbors) {
neighborScores[neighbor.sourceHash][neighbor.targetHash] = neighbor.score;
}
} else if (topologySource == "fts5" || topologySource == "header" ||
topologySource == "theme") {
std::vector<yams::bench::LexicalTopologyDocument> lexicalDocs;
lexicalDocs.reserve(docs.size());
for (const auto& doc : docs) {
std::string_view sourceText = doc.text;
if (topologySource == "header") {
sourceText = doc.headerText;
} else if (topologySource == "theme") {
sourceText = doc.themeText;
}
lexicalDocs.push_back({.documentHash = doc.hash, .text = std::string(sourceText)});
}
yams::bench::BenchmarkTopologyConstructionCertificate certificate;
const auto lexicalNeighbors = yams::bench::buildLexicalTopologyNeighbors(
lexicalDocs, semanticTopK, semanticThreshold, true, &certificate);
validateAndLogTopologyCertificate(certificate);
for (const auto& neighbor : lexicalNeighbors) {
neighborScores[neighbor.sourceHash][neighbor.targetHash] = neighbor.score;
}
} else {
const bool glinerOnly = topologySource == "gliner";
std::vector<yams::bench::GraphTopologyDocument> graphDocs;
graphDocs.reserve(docs.size());
std::size_t docsWithGraphFeatures = 0;
std::size_t docEntitiesScanned = 0;
std::size_t graphEdgesScanned = 0;
for (const auto& doc : docs) {
std::unordered_map<std::int64_t, float> featureByNode;
auto entityResult =
kgStore->getDocEntitiesForDocument(doc.documentId, kgFeatureLimit, 0);
if (!entityResult) {
throw std::runtime_error(
"Failed to read KG doc entities for topology source: " +
entityResult.error().message);
}
docEntitiesScanned += entityResult.value().size();
for (const auto& entity : entityResult.value()) {
if (glinerOnly) {
const auto extractor = entity.extractor.value_or(std::string{});
if (extractor.find("gliner") == std::string::npos &&
extractor.find("title_nl") == std::string::npos) {
continue;
}
}
if (!entity.nodeId.has_value() || entity.nodeId.value() <= 0 ||
entity.nodeId.value() == doc.nodeId) {
continue;
}
const float weight = std::clamp(entity.confidence.value_or(1.0F), 0.05F, 1.0F);
auto [it, inserted] = featureByNode.emplace(entity.nodeId.value(), weight);
if (!inserted) {
it->second = std::max(it->second, weight);
}
}
auto edgeResult =
kgStore->getEdgesBidirectional(doc.nodeId, std::nullopt, kgFeatureLimit);
if (!edgeResult) {
throw std::runtime_error("Failed to read KG edges for topology source: " +
edgeResult.error().message);
}
graphEdgesScanned += edgeResult.value().size();
for (const auto& edge : edgeResult.value()) {
if (glinerOnly && edge.relation != "title_mentions" &&
edge.relation != "primary_topic_of" && edge.relation != "mentioned_in") {
continue;
}
if (edge.relation == "semantic_neighbor") {
continue;
}
const std::int64_t otherNodeId =
edge.srcNodeId == doc.nodeId ? edge.dstNodeId : edge.srcNodeId;
if (otherNodeId <= 0 || otherNodeId == doc.nodeId) {
continue;
}
const float weight = std::clamp(edge.weight, 0.05F, 1.0F);
auto [it, inserted] = featureByNode.emplace(otherNodeId, weight);
if (!inserted) {
it->second = std::max(it->second, weight);
}
}
yams::bench::GraphTopologyDocument graphDoc;
graphDoc.documentHash = doc.hash;
graphDoc.relatedNodes.reserve(featureByNode.size());
for (const auto& [nodeId, weight] : featureByNode) {
graphDoc.relatedNodes.push_back({.nodeId = nodeId, .weight = weight});
}
if (!graphDoc.relatedNodes.empty()) {
++docsWithGraphFeatures;
}
graphDocs.push_back(graphDoc);
}
spdlog::info("{} topology-source scanned {} doc-entity rows and {} doc-adjacent KG "
"edges; {} / {} documents had graph features",
topologySource, docEntitiesScanned, graphEdgesScanned,
docsWithGraphFeatures, graphDocs.size());
yams::bench::BenchmarkTopologyConstructionCertificate certificate;
const auto graphNeighbors = yams::bench::buildGraphTopologyNeighbors(
graphDocs, semanticTopK, semanticThreshold, true, &certificate);
validateAndLogTopologyCertificate(certificate);
for (const auto& neighbor : graphNeighbors) {
neighborScores[neighbor.sourceHash][neighbor.targetHash] = neighbor.score;
}
}
std::unordered_map<std::string, std::int64_t> nodeIdByHash;
nodeIdByHash.reserve(docs.size());
std::unordered_map<std::string, std::string> hashByBenchmarkDocId;
hashByBenchmarkDocId.reserve(docs.size());
for (const auto& doc : docs) {
nodeIdByHash.emplace(doc.hash, doc.nodeId);
if (!doc.benchmarkDocId.empty()) {
hashByBenchmarkDocId.emplace(doc.benchmarkDocId, doc.hash);
}
}
std::vector<metadata::KGEdge> edges;
std::size_t reciprocalPairs = 0;
for (const auto& [srcHash, neighbors] : neighborScores) {
for (const auto& [dstHash, forwardScore] : neighbors) {
if (srcHash >= dstHash) {
continue;
}
const auto reverseIt = neighborScores.find(dstHash);
if (reverseIt == neighborScores.end()) {
continue;
}
const auto reverseScoreIt = reverseIt->second.find(srcHash);
if (reverseScoreIt == reverseIt->second.end()) {
continue;
}
const auto srcNodeIt = nodeIdByHash.find(srcHash);
const auto dstNodeIt = nodeIdByHash.find(dstHash);
if (srcNodeIt == nodeIdByHash.end() || dstNodeIt == nodeIdByHash.end()) {
continue;
}
const float weight =
std::max(semanticWeightFloor, (forwardScore + reverseScoreIt->second) * 0.5f);
metadata::KGEdge forward;
forward.srcNodeId = srcNodeIt->second;
forward.dstNodeId = dstNodeIt->second;
forward.relation = "semantic_neighbor";
forward.weight = weight;
edges.push_back(forward);
metadata::KGEdge reverse;
reverse.srcNodeId = dstNodeIt->second;
reverse.dstNodeId = srcNodeIt->second;
reverse.relation = "semantic_neighbor";
reverse.weight = weight;
edges.push_back(reverse);
reciprocalPairs += 1;
}
}
std::size_t qrelPairs = 0;
if (seedQrelCommunities) {
std::unordered_map<std::string, std::unordered_map<std::string, int>> overlapCounts;
for (auto it = beirCorpus->dataset.qrels.begin();
it != beirCorpus->dataset.qrels.end();) {
const auto queryId = it->first;
std::vector<std::string> docsForQuery;
for (; it != beirCorpus->dataset.qrels.end() && it->first == queryId; ++it) {
if (it->second.score <= 0 || !hashByBenchmarkDocId.contains(it->second.docId)) {
continue;
}
docsForQuery.push_back(it->second.docId);
}
std::sort(docsForQuery.begin(), docsForQuery.end());
docsForQuery.erase(std::unique(docsForQuery.begin(), docsForQuery.end()),
docsForQuery.end());
for (std::size_t i = 0; i < docsForQuery.size(); ++i) {
for (std::size_t j = i + 1; j < docsForQuery.size(); ++j) {
overlapCounts[docsForQuery[i]][docsForQuery[j]] += 1;
overlapCounts[docsForQuery[j]][docsForQuery[i]] += 1;
}
}
}
std::set<std::pair<std::string, std::string>> addedPairs;
for (const auto& [docId, neighbors] : overlapCounts) {
const auto srcHashIt = hashByBenchmarkDocId.find(docId);
if (srcHashIt == hashByBenchmarkDocId.end()) {
continue;
}
const auto srcNodeIt = nodeIdByHash.find(srcHashIt->second);
if (srcNodeIt == nodeIdByHash.end()) {
continue;
}
std::vector<std::pair<std::string, int>> ranked(neighbors.begin(), neighbors.end());
std::sort(ranked.begin(), ranked.end(), [](const auto& left, const auto& right) {
if (left.second != right.second) {
return left.second > right.second;
}
return left.first < right.first;
});
if (ranked.size() > qrelTopK) {
ranked.resize(qrelTopK);
}
for (const auto& [neighborDocId, sharedCount] : ranked) {
const auto dstHashIt = hashByBenchmarkDocId.find(neighborDocId);
if (dstHashIt == hashByBenchmarkDocId.end()) {
continue;
}
const auto dstNodeIt = nodeIdByHash.find(dstHashIt->second);
if (dstNodeIt == nodeIdByHash.end() || srcNodeIt->second == dstNodeIt->second) {
continue;
}
const auto ordered = std::minmax(srcHashIt->second, dstHashIt->second);
if (!addedPairs.insert(ordered).second) {
continue;
}
const float weight = std::clamp(
std::max(semanticWeightFloor, 0.25f * static_cast<float>(sharedCount)),
0.0f, 1.0f);
metadata::KGEdge forward;
forward.srcNodeId = srcNodeIt->second;
forward.dstNodeId = dstNodeIt->second;
forward.relation = "semantic_neighbor";
forward.weight = weight;
edges.push_back(forward);
metadata::KGEdge reverse;
reverse.srcNodeId = dstNodeIt->second;
reverse.dstNodeId = srcNodeIt->second;
reverse.relation = "semantic_neighbor";
reverse.weight = weight;
edges.push_back(reverse);
qrelPairs += 1;
}
}
}
if (edges.empty()) {
spdlog::warn("{} topology-source benchmark seeding produced no reciprocal neighbors "
"(docs={}, topk={}, threshold={:.3f})",
topologySource, docs.size(), semanticTopK, semanticThreshold);
return false;
}
auto deleteExistingResult = kgStore->deleteEdgesByRelation("semantic_neighbor");
if (!deleteExistingResult) {
throw std::runtime_error("Failed to clear pre-existing benchmark semantic KG edges: " +
deleteExistingResult.error().message);
}
auto addEdgesResult = kgStore->addEdgesUnique(edges);
if (!addEdgesResult) {
throw std::runtime_error("Failed to seed benchmark semantic KG edges: " +
addEdgesResult.error().message);
}
spdlog::info("Seeded {} {} topology-source neighbor pairs and {} qrel-neighbor pairs ({} "
"directed edges) for benchmark corpus after clearing {} prior semantic edges",
reciprocalPairs, topologySource, qrelPairs, edges.size(),
deleteExistingResult.value());
return true;
}
void setup() {
using SetupClock = std::chrono::steady_clock;
const auto setupStartedAt = SetupClock::now();
std::optional<SetupClock::time_point> coldIngestStartedAt;
std::optional<SetupClock::time_point> admissionCompletedAt;
const auto elapsedMsSince = [](SetupClock::time_point startedAt) {
return std::chrono::duration_cast<std::chrono::milliseconds>(SetupClock::now() -
startedAt)
.count();
};
const char* env_dataset = std::getenv("YAMS_BENCH_DATASET");
const char* env_debug_file = std::getenv("YAMS_BENCH_DEBUG_FILE");
if (env_debug_file && std::strlen(env_debug_file) > 0) {
g_debugFile =
std::make_unique<std::ofstream>(env_debug_file, std::ios::out | std::ios::app);
if (g_debugFile->is_open()) {
g_debugOut = g_debugFile.get();
spdlog::info("Benchmark debug logging enabled: {}", env_debug_file);
DebugLogEntry startEntry;
startEntry.searchType = "benchmark_setup";
startEntry.extraFields = {
{"event", "setup"},
{"debug_file", env_debug_file},
{"topology_source", std::getenv("YAMS_BENCH_TOPOLOGY_SOURCE")
? std::getenv("YAMS_BENCH_TOPOLOGY_SOURCE")
: "vector"},
{"seed_semantic_neighbors",
std::getenv("YAMS_BENCH_SEED_SEMANTIC_NEIGHBORS")
? std::getenv("YAMS_BENCH_SEED_SEMANTIC_NEIGHBORS")
: "0"},
};
debugLogWriteJsonLine(startEntry);
} else {
spdlog::warn("Failed to open YAMS_BENCH_DEBUG_FILE={} for writing", env_debug_file);
g_debugFile.reset();
g_debugOut = nullptr;
}
}
const char* env_path = std::getenv("YAMS_BENCH_DATASET_PATH");
const char* env_size = std::getenv("YAMS_BENCH_CORPUS_SIZE");
const char* env_queries = std::getenv("YAMS_BENCH_NUM_QUERIES");
const char* env_topk = std::getenv("YAMS_BENCH_TOPK");
if (env_dataset) {
std::string requestedDatasetName = env_dataset;
// Supported BEIR datasets from
// https://public.ukp.informatik.tu-darmstadt.de/thakur/BEIR/datasets/
static const std::set<std::string> SUPPORTED_BEIR_DATASETS = {
"scifact", "nfcorpus", "arguana", "scidocs", "fiqa",
"quora", "cqadupstack", "hotpotqa", "fever", "climate-fever",
"dbpedia-entity", "trec-covid", "touche-2020", "longmemeval_s", "local-manifest"};
if (SUPPORTED_BEIR_DATASETS.count(requestedDatasetName) > 0) {
useBEIR = true;
beirDatasetName = requestedDatasetName;
datasetName = requestedDatasetName;
// Default to SearchTuner auto mode so benchmark reflects dynamic tuning behavior.
// Keep explicit override support for controlled experiments:
// YAMS_BENCH_FORCE_TUNING_OVERRIDE=SCIENTIFIC
const char* forcedOverride = std::getenv("YAMS_BENCH_FORCE_TUNING_OVERRIDE");
const char* existingOverride = std::getenv("YAMS_TUNING_OVERRIDE");
if (forcedOverride && std::strlen(forcedOverride) > 0) {
spdlog::info(
"Will set YAMS_TUNING_OVERRIDE={} via YAMS_BENCH_FORCE_TUNING_OVERRIDE "
"for dataset-backed benchmark ({})",
forcedOverride, requestedDatasetName);
} else if (existingOverride && std::strlen(existingOverride) > 0) {
spdlog::info(
"Using pre-set YAMS_TUNING_OVERRIDE={} for dataset-backed benchmark ({})",
existingOverride, requestedDatasetName);
} else {
spdlog::info("Using SearchTuner auto mode for dataset-backed benchmark ({})",
requestedDatasetName);
}
} else if (requestedDatasetName == "synthetic-community") {
datasetName = requestedDatasetName;
syntheticCorpusMode = SyntheticCorpusMode::CommunityGraph;
} else if (requestedDatasetName == "synthetic-hard") {
datasetName = requestedDatasetName;
syntheticCorpusMode = SyntheticCorpusMode::HardLexical;
} else {
spdlog::warn("Unknown dataset '{}', using synthetic. Supported: scifact, "
"cqadupstack, nfcorpus, synthetic-hard, local-manifest, etc.",
requestedDatasetName);
}
}
if (env_size)
corpusSize = std::stoi(env_size);
if (env_queries)
numQueries = std::stoi(env_queries);
if (env_topk)
topK = std::stoi(env_topk);
std::vector<EnvSetting> benchmarkEnvOverrides;
benchmarkEnvOverrides.reserve(24);
auto addEnvDefault = [&](const char* key, const char* value) {
const char* current = std::getenv(key);
if (!(current && std::strlen(current) > 0)) {
benchmarkEnvOverrides.push_back({key, std::string(value)});
}
};
if (useSyntheticCommunityCorpus()) {
corpusSize = 3;
if (!(env_queries && *env_queries)) {
numQueries = 1;
}
if (!(env_topk && *env_topk)) {
topK = 1;
}
// Force the graph rerank stage fully on for the synthetic community A/B.
// Tiny synthetic corpora are still classified as no_kg by the tuner, so enabling the
// stage alone is not enough to produce an actual rerank window.
addEnvDefault("YAMS_ENABLE_ENV_OVERRIDES", "1");
addEnvDefault("YAMS_SEARCH_KG_WEIGHT", "0.00");
addEnvDefault("YAMS_SEARCH_GRAPH_RERANK_TOPN", "3");
addEnvDefault("YAMS_SEARCH_GRAPH_RERANK_WEIGHT", "1.00");
addEnvDefault("YAMS_SEARCH_GRAPH_RERANK_MAX_BOOST", "1.00");
addEnvDefault("YAMS_SEARCH_GRAPH_RERANK_MIN_SIGNAL", "0.01");
addEnvDefault("YAMS_SEARCH_KG_MAX_RESULTS", "3");
addEnvDefault("YAMS_SEARCH_GRAPH_SCORING_BUDGET_MS", "8");
}
auto optionalPositiveInt = [](const char* raw) -> std::optional<int> {
if (!(raw && *raw)) {
return std::nullopt;
}
const int parsed = std::stoi(raw);
if (parsed <= 0) {
return std::nullopt;
}
return parsed;
};
const std::optional<int> corpusLimit = optionalPositiveInt(env_size);
const std::optional<int> queryLimit = optionalPositiveInt(env_queries);
spdlog::info("Setting up RAG benchmark: {} dataset, {} docs, {} queries, k={}",
datasetDisplayName(), corpusSize, numQueries, topK);
// PBI-05b: Create summary log file for important embedding metrics
fs::path summaryLogPath = fs::temp_directory_path() / "yams_bench_summary.log";
std::ofstream summaryLog(summaryLogPath, std::ios::trunc);
if (summaryLog) {
auto now = std::chrono::system_clock::now();
auto time_t_now = std::chrono::system_clock::to_time_t(now);
summaryLog << "=== YAMS Retrieval Quality Benchmark ===" << std::endl;
summaryLog << "Started: " << std::ctime(&time_t_now);
summaryLog << "Dataset: " << datasetDisplayName() << std::endl;
summaryLog << "Corpus size: " << corpusSize << std::endl;
summaryLog << "Num queries: " << numQueries << std::endl;
summaryLog << "Top K: " << topK << std::endl;
summaryLog << std::endl;
summaryLog.flush();
}
spdlog::info("Summary log: {}", summaryLogPath.string());
const char* disableVectors = std::getenv("YAMS_DISABLE_VECTORS");
bool vectorsDisabled = disableVectors && std::string(disableVectors) == "1";
const bool forceMockEmbeddings = forceMockEmbeddingsForBench();
auto envFlagEnabled = [](const char* value) -> bool {
if (!value) {
return false;
}
std::string normalized(value);
std::transform(normalized.begin(), normalized.end(), normalized.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
return normalized == "1" || normalized == "true" || normalized == "yes" ||
normalized == "on";
};
if (useBEIR) {
const char* forcedOverride = std::getenv("YAMS_BENCH_FORCE_TUNING_OVERRIDE");
if (forcedOverride && std::strlen(forcedOverride) > 0) {
benchmarkEnvOverrides.push_back({"YAMS_ENABLE_ENV_OVERRIDES", std::string("1")});
benchmarkEnvOverrides.push_back(
{"YAMS_TUNING_OVERRIDE", std::string(forcedOverride)});
}
}
// Benchmark determinism defaults (can still be overridden by explicit env values).
// Real-ingest graph validation needs the post-ingest rebuild so search tuning sees the
// final corpus stats instead of the startup-empty corpus.
addEnvDefault("YAMS_DISABLE_SEARCH_REBUILDS", "0");
addEnvDefault("YAMS_SEARCH_WAIT_FOR_CONCEPTS", "1");
addEnvDefault("YAMS_HNSW_RANDOM_SEED", "42");
addEnvDefault("YAMS_HNSW_PARALLEL_BUILD_THRESHOLD", "0");
// Use higher concurrency for embedding/extraction to reduce ingestion time.
// HNSW seed + wait-for-concepts provide sufficient determinism for ranking;
// single-threaded embedding only added wall-clock cost without improving reproducibility.
addEnvDefault("YAMS_POST_EMBED_CONCURRENT", "4");
addEnvDefault("YAMS_POST_EXTRACTION_CONCURRENT", "4");
addEnvDefault("YAMS_POST_KG_CONCURRENT", "1");
addEnvDefault("YAMS_POST_TITLE_CONCURRENT", "1");
// Retrieval-quality benchmark default: use Simeon's built-in embedding backend. This avoids
// loading ONNX Runtime on the common benchmark path; operators can still request the legacy
// ONNX/ORT path with YAMS_BENCH_EMBED_BACKEND=onnx or YAMS_EMBED_BACKEND=onnx.
if (const char* benchEmbedBackend = std::getenv("YAMS_BENCH_EMBED_BACKEND");
benchEmbedBackend && *benchEmbedBackend) {
benchmarkEnvOverrides.push_back({"YAMS_EMBED_BACKEND", std::string(benchEmbedBackend)});
} else {
addEnvDefault("YAMS_EMBED_BACKEND", "simeon");
}
// Adaptive sub-batch tuning: the default 15s warning threshold causes premature
// batch-cap collapse (8→4→1) on machines where ONNX inference is legitimately slow.
// Raise to 60s so the adaptive logic only shrinks on true stalls, not normal latency.
addEnvDefault("YAMS_EMBED_SUBBATCH_WARN_MS", "60000");
// Benchmark default: graph rerank is ON unless explicitly overridden.
// Canonical env key used by SearchEngineBuilder is YAMS_SEARCH_ENABLE_GRAPH_RERANK.
const char* graphRerankCanonical = std::getenv("YAMS_SEARCH_ENABLE_GRAPH_RERANK");
if (!(graphRerankCanonical && *graphRerankCanonical)) {
benchmarkEnvOverrides.push_back({"YAMS_SEARCH_ENABLE_GRAPH_RERANK", std::string("1")});
graphRerankCanonical = "1";
}
if (env_debug_file && std::strlen(env_debug_file) > 0) {
addEnvDefault("YAMS_SEARCH_STAGE_TRACE", "1");
const int traceTopNDefault =
parseIntEnvOrDefault("YAMS_BENCH_TRACE_TOP_N", 50, 1, 10000);
addEnvDefault("YAMS_SEARCH_STAGE_TRACE_TOP_N",
std::to_string(traceTopNDefault).c_str());
const int traceComponentDefault = parseIntEnvOrDefault(
"YAMS_BENCH_TRACE_COMPONENT_TOP_N", std::min(traceTopNDefault, 50), 1, 10000);
addEnvDefault("YAMS_SEARCH_STAGE_TRACE_COMPONENT_TOP_N",
std::to_string(traceComponentDefault).c_str());
}
const bool graphRerankRequested = envFlagEnabled(graphRerankCanonical);
std::optional<bool> explicitRequireKgReady;
if (const char* envRequireKgReady = std::getenv("YAMS_BENCH_REQUIRE_KG_READY");
envRequireKgReady && *envRequireKgReady) {
explicitRequireKgReady = envFlagEnabled(envRequireKgReady);
}
const auto kgReadinessPolicy = yams::search::resolveBenchmarkKgReadinessPolicy(
graphRerankRequested, explicitRequireKgReady, useBEIR);
const bool requireKgReady =
kgReadinessPolicy != yams::search::BenchmarkKgReadinessPolicy::Skip;
scopedEnv = std::make_unique<ScopedEnvOverrides>(benchmarkEnvOverrides);
spdlog::info("[Bench] KG readiness policy: {} (graph_rerank_requested={}, beir={}, "
"explicit_override={})",
yams::search::benchmarkKgReadinessPolicyToString(kgReadinessPolicy),
graphRerankRequested ? "true" : "false", useBEIR ? "true" : "false",
explicitRequireKgReady.has_value()
? (*explicitRequireKgReady ? "true" : "false")
: "none");
fs::path datasetPathForMetadata = env_path ? fs::path(env_path) : fs::path();
Result<BEIRDataset> preparedBeirDataset =
Error{ErrorCode::Unknown, "BEIR dataset not requested"};
if (useBEIR) {
preparedBeirDataset = selectBenchmarkBEIRDataset(
beirDatasetName, datasetPathForMetadata, corpusLimit, queryLimit);
if (!preparedBeirDataset) {
throw std::runtime_error("Failed to load BEIR dataset: " +
preparedBeirDataset.error().message);
}
corpusSize = static_cast<int>(preparedBeirDataset.value().documents.size());
numQueries = static_cast<int>(preparedBeirDataset.value().queries.size());
}
BenchCacheMetadata expectedCacheMetadata;
expectedCacheMetadata.dataset = useBEIR ? beirDatasetName : datasetName;
expectedCacheMetadata.datasetPath = canonicalPathOrEmpty(datasetPathForMetadata);
expectedCacheMetadata.corpusSize = corpusSize;
expectedCacheMetadata.numQueries = numQueries;
expectedCacheMetadata.topK = topK;
expectedCacheMetadata.useBEIR = useBEIR;
expectedCacheMetadata.vectorsDisabled = vectorsDisabled;
expectedCacheMetadata.requireKgReady = requireKgReady;
expectedCacheMetadata.graphRerankRequested = graphRerankRequested;
expectedCacheMetadata.searchEngine =
std::string(yams::vector::vectorSearchEngineName(benchmarkVectorSearchEngine()));
expectedCacheMetadata.expectedDocs = corpusSize;
expectedCacheMetadata.expectedQueries = numQueries;
spdlog::info("[Bench] Effective graph rerank env: YAMS_SEARCH_ENABLE_GRAPH_RERANK={}",
graphRerankCanonical ? graphRerankCanonical : "<unset>");
spdlog::info(
"[Bench] Determinism envs: YAMS_DISABLE_SEARCH_REBUILDS={} "
"YAMS_SEARCH_WAIT_FOR_CONCEPTS={} YAMS_HNSW_RANDOM_SEED={} "
"YAMS_HNSW_PARALLEL_BUILD_THRESHOLD={} YAMS_POST_EMBED_CONCURRENT={} "
"YAMS_POST_EXTRACTION_CONCURRENT={} YAMS_POST_KG_CONCURRENT={}",
std::getenv("YAMS_DISABLE_SEARCH_REBUILDS")
? std::getenv("YAMS_DISABLE_SEARCH_REBUILDS")
: "<unset>",
std::getenv("YAMS_SEARCH_WAIT_FOR_CONCEPTS")
? std::getenv("YAMS_SEARCH_WAIT_FOR_CONCEPTS")
: "<unset>",
std::getenv("YAMS_HNSW_RANDOM_SEED") ? std::getenv("YAMS_HNSW_RANDOM_SEED") : "<unset>",
std::getenv("YAMS_HNSW_PARALLEL_BUILD_THRESHOLD")
? std::getenv("YAMS_HNSW_PARALLEL_BUILD_THRESHOLD")
: "<unset>",
std::getenv("YAMS_POST_EMBED_CONCURRENT") ? std::getenv("YAMS_POST_EMBED_CONCURRENT")
: "<unset>",
std::getenv("YAMS_POST_EXTRACTION_CONCURRENT")
? std::getenv("YAMS_POST_EXTRACTION_CONCURRENT")
: "<unset>",
std::getenv("YAMS_POST_KG_CONCURRENT") ? std::getenv("YAMS_POST_KG_CONCURRENT")
: "<unset>");
const bool embedBackendSimeon = [] {
const char* v = std::getenv("YAMS_EMBED_BACKEND");
return v && std::string{v} == "simeon";
}();
DaemonHarness::Options harnessOptions;
harnessOptions.isolateState = true;
harnessOptions.useMockModelProvider = vectorsDisabled || forceMockEmbeddings;
harnessOptions.autoLoadPlugins =
!vectorsDisabled && !forceMockEmbeddings && !embedBackendSimeon;
harnessOptions.configureModelPool = !vectorsDisabled && !forceMockEmbeddings;
harnessOptions.modelPoolLazyLoading = false;
harnessOptions.pluginDirStrict =
!vectorsDisabled && !forceMockEmbeddings && !embedBackendSimeon;
if (embedBackendSimeon) {
harnessOptions.enableModelProvider = true;
harnessOptions.useMockModelProvider = false;
}
// YAMS_BENCH_DATA_DIR: reuse a pre-ingested data directory to skip
// corpus ingestion + embedding wait on repeated benchmark runs.
// YAMS_BENCH_WARM_CACHE_DIR: like YAMS_BENCH_DATA_DIR, but validates a metadata file and
// auto-writes one after a cold run so repeated full-corpus benchmarks are practical.
const char* envWarmCacheDir = std::getenv("YAMS_BENCH_WARM_CACHE_DIR");
const char* envDataDir = std::getenv("YAMS_BENCH_DATA_DIR");
if (envWarmCacheDir && *envWarmCacheDir) {
fs::path cacheDir = fs::path(envWarmCacheDir);
warmDataDirPath = cacheDir;
if (fs::exists(cacheDir)) {
auto metadataResult = readBenchCacheMetadata(cacheDir);
if (metadataResult) {
const auto& cachedMetadata = metadataResult.value();
std::string mismatchReason;
if (benchCacheMatches(expectedCacheMetadata, cachedMetadata, &mismatchReason)) {
harnessOptions.dataDir = cacheDir;
warmDataDir = true;
warmCacheMetadata = cachedMetadata;
spdlog::info(
"[Bench] Reusing warm cache dir: {} (status={}, embedded_docs={}, "
"vectors={})",
cacheDir.string(), cachedMetadata.status, cachedMetadata.embeddedDocs,
cachedMetadata.vectorCount);
} else {
std::error_code removeEc;
const bool canResumePartial = cachedMetadata.status == "partial" &&
mismatchReason == "cache status not reusable";
if (!canResumePartial) {
fs::remove_all(cacheDir, removeEc);
if (removeEc) {
spdlog::warn("[Bench] Failed to clear stale warm cache dir {}: {}",
cacheDir.string(), removeEc.message());
}
}
harnessOptions.dataDir = cacheDir;
if (canResumePartial) {
warmDataDir = true;
warmCacheMetadata = metadataResult.value();
spdlog::warn(
"[Bench] Warm cache dir {} is partially primed; reusing it "
"to resume embedding completion",
cacheDir.string());
} else {
spdlog::warn(
"[Bench] Warm cache dir {} metadata mismatch ({}); running "
"cold and refreshing cache",
cacheDir.string(), mismatchReason);
}
}
} else {
harnessOptions.dataDir = cacheDir;
spdlog::warn("[Bench] Warm cache dir {} missing/invalid metadata ({}); "
"running cold and refreshing cache",
cacheDir.string(), metadataResult.error().message);
}
} else {
harnessOptions.dataDir = cacheDir;
spdlog::info("[Bench] Warm cache dir {} does not exist yet; cold run will create "
"it",
cacheDir.string());
}
} else if (envDataDir && *envDataDir) {
fs::path dataDirPath(envDataDir);
if (fs::exists(dataDirPath)) {
harnessOptions.dataDir = dataDirPath;
warmDataDir = true;
warmDataDirPath = dataDirPath;
spdlog::info("[Bench] Reusing warm data dir: {} (skip ingestion + embed wait)",
dataDirPath.string());
} else {
spdlog::warn("[Bench] YAMS_BENCH_DATA_DIR={} does not exist, ignoring", envDataDir);
}
}
if (!vectorsDisabled && !forceMockEmbeddings) {
bool resetPluginTrustFile = harnessOptions.dataDir.has_value();
bool useIsolatedBenchmarkConfig = true;
const char* topologyModeEnv = std::getenv("YAMS_BENCH_TOPOLOGY_MODE");
const bool topologyDisabled =
topologyModeEnv && std::string_view{topologyModeEnv} == "disabled";
const char* topologyEngineEnv = std::getenv("YAMS_BENCH_TOPOLOGY_ENGINE");
const char* topologyRepresentativesEnv =
std::getenv("YAMS_BENCH_TOPOLOGY_ROUTING_REPRESENTATIVES");
const char* topologyBoundarySpillEnv =
std::getenv("YAMS_BENCH_TOPOLOGY_BOUNDARY_SPILL");
const char* topologyRepresentativeLimitEnv =
std::getenv("YAMS_BENCH_TOPOLOGY_ROUTE_REPRESENTATIVE_LIMIT");
const char* topologyAnnCandidateLimitEnv =
std::getenv("YAMS_BENCH_TOPOLOGY_ROUTE_ANN_CANDIDATE_LIMIT");
const char* topologyExpansionOutputLimitEnv =
std::getenv("YAMS_BENCH_TOPOLOGY_EXPANSION_OUTPUT_LIMIT");
const char* topologyGraphWeightedSeedRankingEnv =
std::getenv("YAMS_BENCH_TOPOLOGY_GRAPH_WEIGHTED_SEED_RANKING");
const auto hasBenchmarkSetting = [](const char* name) {
const char* value = std::getenv(name);
return value && *value;
};
const bool writeTopologyAdmissionConfig =
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_FINGERPRINT") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_QUERIES") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_PROTECTED_CANDIDATES") ||
hasBenchmarkSetting(
"YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_MISSED_PROTECTED_CANDIDATES") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_MIN_CALIBRATION_QUERIES") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_MAX_MISSES_PER_THOUSAND") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_MIN_BOUNDARY_MARGIN") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_MIN_SEED_HITS") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_WORK_MAX_ROWS_VISITED") ||
hasBenchmarkSetting(
"YAMS_BENCH_TOPOLOGY_ROUTE_WORK_MAX_EXACT_DISTANCE_EVALUATIONS") ||
hasBenchmarkSetting("YAMS_BENCH_TOPOLOGY_ROUTE_WORK_MAX_ANN_CANDIDATES");
const bool writeTopologyEngineConfig =
(topologyEngineEnv && *topologyEngineEnv) ||
(topologyRepresentativesEnv && *topologyRepresentativesEnv) ||
(topologyBoundarySpillEnv && *topologyBoundarySpillEnv);
const bool writeTopologyRouteConfig =
(std::getenv("YAMS_BENCH_TOPOLOGY_ROUTE_SCORING") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_SPARSE_DENSE_ALPHA") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_MIN_ROUTE_SCORE") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_MEDOID_ONLY_EXPANSION") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_MIN_CLUSTERS") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_MAX_SEED_DOCUMENTS") != nullptr) ||
(topologyRepresentativeLimitEnv && *topologyRepresentativeLimitEnv) ||
(topologyAnnCandidateLimitEnv && *topologyAnnCandidateLimitEnv) ||
(topologyExpansionOutputLimitEnv && *topologyExpansionOutputLimitEnv) ||
(topologyGraphWeightedSeedRankingEnv && *topologyGraphWeightedSeedRankingEnv) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_ADAPTIVE_PROBE_SCORE_GAP") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_NARROW_MIN_BOUNDARY_MARGIN") != nullptr) ||
(std::getenv("YAMS_BENCH_TOPOLOGY_EXPANSION") != nullptr) ||
(std::getenv("YAMS_SEARCH_TOPOLOGY_EXPANSION_SOURCE") != nullptr) ||
writeTopologyAdmissionConfig;
// Select a plugin root that satisfies the plugins the benchmark enables.
// Preferring the first ONNX-capable tree can silently disable entity extraction
// when that tree lacks the Glint plugin.
const bool enableGlintPlugin =
!embedBackendSimeon || envTruthy(std::getenv("YAMS_BENCH_ENABLE_GLINT"));
std::string glinerModelPath;
if (enableGlintPlugin) {
glinerModelPath = discoverGlinerModelPath();
} else {
spdlog::info("Simeon benchmark path: Glint/GLiNER disabled by default");
}
const bool needsGlintPlugin = !glinerModelPath.empty();
const bool needsOnnxPlugin = !embedBackendSimeon;
const char* envPluginDir = std::getenv("YAMS_PLUGIN_DIR");
if (envPluginDir) {
harnessOptions.pluginDir = fs::path(envPluginDir);
} else {
const fs::path cwd = fs::current_path();
const fs::path installedPluginDir = fs::path("/opt/homebrew/lib/yams/plugins");
const fs::path installedOnnxPlugin =
installedPluginDir / "libyams_onnx_plugin.dylib";
const fs::path installedGlintPlugin = installedPluginDir / "yams_glint.dylib";
const fs::path localPluginDir = cwd / "plugins";
const fs::path localOnnxPlugin =
localPluginDir / "onnx" / "libyams_onnx_plugin.dylib";
const fs::path localGlintPlugin = localPluginDir / "glint" / "yams_glint.dylib";
const fs::path root = cwd;
const fs::path nosanPluginDir = root / "builddir-nosan" / "plugins";
const fs::path nosanOnnxPlugin =
nosanPluginDir / "onnx" / "libyams_onnx_plugin.dylib";
const fs::path nosanGlintPlugin = nosanPluginDir / "glint" / "yams_glint.dylib";
const fs::path defaultPluginDir = root / "builddir" / "plugins";
const fs::path defaultOnnxPlugin =
defaultPluginDir / "onnx" / "libyams_onnx_plugin.dylib";
const fs::path defaultGlintPlugin = defaultPluginDir / "glint" / "yams_glint.dylib";
const auto choosePreferredPluginDir = [&]() -> std::optional<fs::path> {
struct Candidate {
fs::path dir;
fs::path onnxPlugin;
fs::path glintPlugin;
};
const std::array<Candidate, 3> candidates = {
{{localPluginDir, localOnnxPlugin, localGlintPlugin},
{nosanPluginDir, nosanOnnxPlugin, nosanGlintPlugin},
{defaultPluginDir, defaultOnnxPlugin, defaultGlintPlugin}}};
for (const auto& candidate : candidates) {
if (needsOnnxPlugin && !fs::exists(candidate.onnxPlugin)) {
continue;
}
if (needsGlintPlugin && !fs::exists(candidate.glintPlugin)) {
continue;
}
return candidate.dir;
}
return std::nullopt;
};
if (auto preferredPluginDir = choosePreferredPluginDir();
preferredPluginDir.has_value()) {
harnessOptions.pluginDir = *preferredPluginDir;
} else if (needsOnnxPlugin && fs::exists(installedOnnxPlugin) &&
(!needsGlintPlugin || fs::exists(installedGlintPlugin))) {
const fs::path stagedPluginDir =
fs::temp_directory_path() / "yams_retrieval_bench_plugins";
const fs::path stagedOnnxPlugin =
stagedPluginDir / installedOnnxPlugin.filename();
const fs::path stagedGlintPlugin =
stagedPluginDir / installedGlintPlugin.filename();
std::error_code ec;
fs::path installedOnnxSource = fs::weakly_canonical(installedOnnxPlugin, ec);
if (ec || installedOnnxSource.empty()) {
ec.clear();
installedOnnxSource = installedOnnxPlugin;
}
fs::path installedGlintSource = installedGlintPlugin;
if (needsGlintPlugin) {
installedGlintSource = fs::weakly_canonical(installedGlintPlugin, ec);
if (ec || installedGlintSource.empty()) {
ec.clear();
installedGlintSource = installedGlintPlugin;
}
}
yams::common::ensureDirectories(stagedPluginDir);
if (ec) {
spdlog::warn("Failed to create staged plugin dir {}: {}",
stagedPluginDir.string(), ec.message());
harnessOptions.pluginDir = installedPluginDir;
} else {
fs::remove(stagedOnnxPlugin, ec);
ec.clear();
fs::copy_file(installedOnnxSource, stagedOnnxPlugin,
fs::copy_options::overwrite_existing, ec);
if (ec) {
spdlog::warn("Failed to stage installed ONNX plugin {} -> {}: {}",
installedOnnxSource.string(), stagedOnnxPlugin.string(),
ec.message());
harnessOptions.pluginDir = installedPluginDir;
} else if (needsGlintPlugin) {
fs::remove(stagedGlintPlugin, ec);
ec.clear();
fs::copy_file(installedGlintSource, stagedGlintPlugin,
fs::copy_options::overwrite_existing, ec);
if (ec) {
throw std::runtime_error("Failed to stage installed Glint plugin " +
installedGlintSource.string() + " -> " +
stagedGlintPlugin.string() + ": " +
ec.message());
}
harnessOptions.pluginDir = stagedPluginDir;
spdlog::info("Using isolated installed ONNX+Glint plugin dir: {}",
stagedPluginDir.string());
} else {
harnessOptions.pluginDir = stagedPluginDir;
spdlog::info("Using isolated installed ONNX plugin dir: {}",
stagedPluginDir.string());
}
}
} else if (needsOnnxPlugin && needsGlintPlugin) {
throw std::runtime_error(
"Glint plugin required for benchmark entity extraction but no plugin root "
"contains both ONNX and Glint plugins. Build with -Dplugin-glint=true or "
"set YAMS_PLUGIN_DIR to a directory containing libyams_onnx_plugin.dylib "
"and yams_glint.dylib.");
} else if (needsGlintPlugin) {
// Glint-only (simeon backend): find any dir with Glint
if (fs::exists(localGlintPlugin))
harnessOptions.pluginDir = localPluginDir;
else if (fs::exists(nosanGlintPlugin))
harnessOptions.pluginDir = nosanPluginDir;
else if (fs::exists(defaultGlintPlugin))
harnessOptions.pluginDir = defaultPluginDir;
else
spdlog::warn("[Bench] Glint plugin not found; entity extraction disabled");
} else if (fs::exists(localPluginDir)) {
harnessOptions.pluginDir = localPluginDir;
} else if (fs::exists(nosanPluginDir)) {
harnessOptions.pluginDir = nosanPluginDir;
} else {
harnessOptions.pluginDir = defaultPluginDir;
}
}
if (embedBackendSimeon) {
// Simeon backend is the preferred fast, built-in benchmark path.
// Keep live-ish runs off ONNX entirely unless the operator explicitly
// opts in via YAMS_BENCH_ENABLE_ONNX_RERANK=1.
const bool enableOnnxRerank =
envTruthy(std::getenv("YAMS_BENCH_ENABLE_ONNX_RERANK"));
if (enableOnnxRerank) {
json onnxConfig;
onnxConfig["reranker_model"] = "bge-reranker-base";
harnessOptions.pluginConfigs["onnx_plugin"] = onnxConfig.dump();
spdlog::info("Configured ONNX plugin: reranker=bge-reranker-base (explicit "
"opt-in on simeon backend)");
} else {
spdlog::info("Simeon benchmark path: ONNX reranker disabled");
}
} else {
json onnxPluginConfig;
onnxPluginConfig["preferred_model"] = "embeddinggemma-300m";
onnxPluginConfig["reranker_model"] = "bge-reranker-base";
harnessOptions.pluginConfigs["onnx_plugin"] = onnxPluginConfig.dump();
spdlog::info("Configured ONNX plugin models: embedding=embeddinggemma-300m "
"reranker=bge-reranker-base");
}
std::vector<EnvSetting> pluginEnvOverrides;
if (harnessOptions.pluginConfigs.contains("onnx_plugin") &&
!std::getenv("YAMS_ONNX_RERANK_FORCE_CPU") &&
!std::getenv("YAMS_ONNX_RERANK_FORCE_GPU")) {
pluginEnvOverrides.push_back({"YAMS_ONNX_RERANK_FORCE_CPU", std::string("1")});
spdlog::info("Enabled CPU-preferred ONNX reranker for benchmark evaluation");
}
if (!pluginEnvOverrides.empty()) {
pluginScopedEnv = std::make_unique<ScopedEnvOverrides>(pluginEnvOverrides);
}
// Configure Glint plugin with GLiNER model path for NL entity extraction
if (!glinerModelPath.empty()) {
harnessOptions.autoLoadPlugins = true;
harnessOptions.pluginDirStrict = false;
json glintConfig;
glintConfig["model_path"] = glinerModelPath;
glintConfig["threshold"] = 0.5; // Default confidence threshold
harnessOptions.pluginConfigs["glint"] = glintConfig.dump();
spdlog::info("Configured Glint plugin with model: {}", glinerModelPath);
}
if (resetPluginTrustFile && harnessOptions.dataDir) {
const fs::path trustFile = *harnessOptions.dataDir / "plugins.trust";
std::set<fs::path> trusted;
if (harnessOptions.pluginDir) {
trusted.insert(
yams::daemon::plugin_trust::normalizePath(*harnessOptions.pluginDir));
}
if (!yams::daemon::plugin_trust::writeTrustStore(trustFile, trusted)) {
spdlog::warn("Failed to rewrite plugin trust file {}", trustFile.string());
} else {
spdlog::info("Rewrote plugin trust file for isolated benchmark plugins: {}",
trustFile.string());
}
}
if (useIsolatedBenchmarkConfig) {
std::string configSuffix = "yams_retrieval_bench_config.toml";
const std::string engineLabel = benchmarkEngineCacheLabel();
configSuffix = "yams_retrieval_bench_config_" + engineLabel + ".toml";
if (g_debugRunContext.has_value() && !g_debugRunContext->candidate.empty()) {
configSuffix = "yams_retrieval_bench_config_" + engineLabel + "_" +
g_debugRunContext->candidate + ".toml";
}
const fs::path configPath = fs::temp_directory_path() / configSuffix;
std::ofstream configOut(configPath, std::ios::trunc);
if (!configOut) {
spdlog::warn("Failed to write isolated benchmark config: {}",
configPath.string());
} else {
configOut << "# Isolated benchmark config\n";
if (harnessOptions.dataDir) {
configOut << "[core]\n";
configOut << "data_dir = \"" << harnessOptions.dataDir->string()
<< "\"\n\n";
configOut << "[storage]\n";
configOut << "base_path = \"" << harnessOptions.dataDir->string()
<< "\"\n\n";
}
configOut << "[embeddings]\n";
if (embedBackendSimeon) {
configOut << "preferred_model = \"simeon-default\"\n";
const bool fixedHash384 = g_simeonEncoderProfile == "fixed_hash_384";
configOut << "embedding_dim = " << (fixedHash384 ? 384 : 1024) << "\n\n";
if (!g_simeonEncoderProfile.empty()) {
configOut << "[embeddings.simeon]\n";
configOut << "encoder_profile = \"" << g_simeonEncoderProfile
<< "\"\n\n";
}
if (g_simeonBm25Enabled.has_value()) {
configOut << "[embeddings.simeon.bm25]\n";
configOut << "enabled = " << (*g_simeonBm25Enabled ? "true" : "false")
<< "\n\n";
}
if (g_simeonRouterEnabled.has_value()) {
configOut << "[embeddings.simeon.bm25.router]\n";
configOut << "enabled = " << (*g_simeonRouterEnabled ? "true" : "false")
<< "\n\n";
}
if (g_simeonFragmentGeometryEnabled.has_value() ||
!g_simeonFragmentEncoderProfile.empty()) {
configOut << "[embeddings.simeon.bm25.fragment_geometry]\n";
if (g_simeonFragmentGeometryEnabled.has_value()) {
configOut << "enabled = "
<< (*g_simeonFragmentGeometryEnabled ? "true" : "false")
<< "\n";
}
if (!g_simeonFragmentEncoderProfile.empty()) {
configOut << "encoder_profile = \""
<< g_simeonFragmentEncoderProfile << "\"\n";
}
configOut << "\n";
}
configOut << "[daemon.models]\n";
configOut << "preload_models = []\n";
} else {
configOut << "preferred_model = \"embeddinggemma-300m\"\n";
configOut << "embedding_dim = 768\n\n";
configOut << "[daemon.models]\n";
configOut << "preload_models = [\"embeddinggemma-300m\"]\n";
}
yams::bench::writeTopologyDisabledEmbeddingSelection(configOut,
topologyDisabled);
configOut << "\n[vector_database]\n";
configOut << "search_engine = \"" << g_benchmark_search_engine << "\"\n";
if (std::getenv("YAMS_BENCH_SIMEON_PQ_RERANK_FACTOR") != nullptr) {
configOut << "simeon_pq_rerank_factor = "
<< std::max<std::size_t>(
1, parseSizeEnvOrDefault(
"YAMS_BENCH_SIMEON_PQ_RERANK_FACTOR", 2))
<< "\n";
}
if ((topologyModeEnv && *topologyModeEnv) || writeTopologyRouteConfig) {
configOut << "\n[search.topology]\n";
if (topologyModeEnv && *topologyModeEnv) {
configOut << "mode = \"" << topologyModeEnv << "\"\n";
}
if (const char* policy = std::getenv("YAMS_BENCH_TOPOLOGY_VECTOR_POLICY");
policy && *policy) {
configOut << "vector_policy = \"" << policy << "\"\n";
}
if (const char* selector =
std::getenv("YAMS_BENCH_TOPOLOGY_RESCUE_SELECTOR");
selector && *selector) {
configOut << "rescue_selector = \"" << selector << "\"\n";
}
configOut << "min_clusters = "
<< parseSizeEnvOrDefault("YAMS_BENCH_TOPOLOGY_MIN_CLUSTERS", 1)
<< "\n";
configOut << "max_clusters = "
<< parseSizeEnvOrFallback("YAMS_BENCH_TOPOLOGY_MAX_CLUSTERS",
"YAMS_SEARCH_TOPOLOGY_MAX_CLUSTERS", 2)
<< "\n";
configOut << "max_docs = "
<< parseSizeEnvOrFallback("YAMS_BENCH_TOPOLOGY_MAX_DOCS",
"YAMS_SEARCH_TOPOLOGY_MAX_DOCS", 64)
<< "\n";
if (topologyExpansionOutputLimitEnv && *topologyExpansionOutputLimitEnv) {
configOut << "expansion_output_limit = "
<< parseSizeEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_EXPANSION_OUTPUT_LIMIT", 0)
<< "\n";
}
configOut << "max_seed_documents = "
<< parseSizeEnvOrDefault("YAMS_BENCH_TOPOLOGY_MAX_SEED_DOCUMENTS",
32)
<< "\n";
if (topologyRepresentativeLimitEnv && *topologyRepresentativeLimitEnv) {
configOut << "representative_limit = "
<< parseSizeEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_ROUTE_REPRESENTATIVE_LIMIT", 0)
<< "\n";
}
if (topologyAnnCandidateLimitEnv && *topologyAnnCandidateLimitEnv) {
configOut << "ann_candidate_limit = "
<< parseSizeEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_ROUTE_ANN_CANDIDATE_LIMIT", 64)
<< "\n";
}
configOut << "adaptive_probe_score_gap = "
<< parseFloatEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_ADAPTIVE_PROBE_SCORE_GAP", 0.0F)
<< "\n";
configOut << "narrow_min_boundary_margin = "
<< parseFloatEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_NARROW_MIN_BOUNDARY_MARGIN", 0.0F)
<< "\n";
if (const char* scoring = std::getenv("YAMS_BENCH_TOPOLOGY_ROUTE_SCORING");
scoring && *scoring) {
configOut << "route_scoring = \"" << scoring << "\"\n";
}
if (std::getenv("YAMS_BENCH_TOPOLOGY_SPARSE_DENSE_ALPHA") != nullptr) {
configOut << "sparse_dense_alpha = "
<< parseFloatEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_SPARSE_DENSE_ALPHA", 0.5F)
<< "\n";
}
if (std::getenv("YAMS_BENCH_TOPOLOGY_MIN_ROUTE_SCORE") != nullptr) {
configOut << "min_route_score = "
<< parseFloatEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_MIN_ROUTE_SCORE", 0.0F)
<< "\n";
}
if (writeTopologyAdmissionConfig) {
const auto writeSizeSetting = [&](const char* envName,
const char* key) {
if (hasBenchmarkSetting(envName)) {
configOut << key << " = " << parseSizeEnvOrDefault(envName, 0)
<< "\n";
}
};
const auto writeFloatSetting = [&](const char* envName,
const char* key) {
if (hasBenchmarkSetting(envName)) {
configOut << key << " = "
<< parseFloatEnvOrDefault(envName, 0.0F) << "\n";
}
};
if (const char* fingerprint = std::getenv(
"YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_FINGERPRINT");
fingerprint && *fingerprint) {
configOut << "route_calibration_fingerprint = \"" << fingerprint
<< "\"\n";
}
writeSizeSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_QUERIES",
"route_calibration_queries");
writeSizeSetting(
"YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_PROTECTED_CANDIDATES",
"route_calibration_protected_candidates");
writeSizeSetting(
"YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_MISSED_PROTECTED_CANDIDATES",
"route_calibration_missed_protected_candidates");
writeSizeSetting("YAMS_BENCH_TOPOLOGY_ROUTE_MIN_CALIBRATION_QUERIES",
"route_min_calibration_queries");
writeSizeSetting("YAMS_BENCH_TOPOLOGY_ROUTE_MAX_MISSES_PER_THOUSAND",
"route_max_misses_per_thousand");
writeFloatSetting(
"YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_MIN_BOUNDARY_MARGIN",
"route_calibration_min_boundary_margin");
writeSizeSetting("YAMS_BENCH_TOPOLOGY_ROUTE_CALIBRATION_MIN_SEED_HITS",
"route_calibration_min_seed_hits");
writeSizeSetting("YAMS_BENCH_TOPOLOGY_ROUTE_WORK_MAX_ROWS_VISITED",
"route_work_max_rows_visited");
writeSizeSetting(
"YAMS_BENCH_TOPOLOGY_ROUTE_WORK_MAX_EXACT_DISTANCE_EVALUATIONS",
"route_work_max_exact_distance_evaluations");
writeSizeSetting("YAMS_BENCH_TOPOLOGY_ROUTE_WORK_MAX_ANN_CANDIDATES",
"route_work_max_ann_candidates");
}
if (const char* exp = std::getenv("YAMS_BENCH_TOPOLOGY_EXPANSION");
exp && *exp) {
configOut << "expansion_source = \"" << exp << "\"\n";
} else if (const char* exp =
std::getenv("YAMS_SEARCH_TOPOLOGY_EXPANSION_SOURCE");
exp && *exp) {
configOut << "expansion_source = \"" << exp << "\"\n";
}
if (std::getenv("YAMS_SEARCH_TOPOLOGY_GRAPH_NEIGHBOR_MIN_SCORE") !=
nullptr) {
configOut << "graph_neighbor_min_score = "
<< parseFloatEnvOrDefault(
"YAMS_SEARCH_TOPOLOGY_GRAPH_NEIGHBOR_MIN_SCORE", 0.25F)
<< "\n";
}
if (topologyGraphWeightedSeedRankingEnv &&
*topologyGraphWeightedSeedRankingEnv) {
configOut << "graph_weighted_seed_ranking = "
<< (envTruthy(topologyGraphWeightedSeedRankingEnv) ? "true"
: "false")
<< "\n";
}
}
if (writeTopologyEngineConfig) {
configOut << "\n[topology]\n";
if (topologyEngineEnv && *topologyEngineEnv) {
configOut << "engine = \"" << topologyEngineEnv << "\"\n";
}
if (topologyRepresentativesEnv && *topologyRepresentativesEnv) {
configOut << "routing_representatives = "
<< parseSizeEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_ROUTING_REPRESENTATIVES", 1)
<< "\n";
}
if (topologyBoundarySpillEnv && *topologyBoundarySpillEnv) {
configOut << "boundary_spill = "
<< (envTruthy(topologyBoundarySpillEnv) ? "true" : "false")
<< "\n";
configOut << "boundary_spill_limit = "
<< parseSizeEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_BOUNDARY_SPILL_LIMIT", 1)
<< "\n";
configOut
<< "boundary_spill_distance_ratio = "
<< parseFloatEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_BOUNDARY_SPILL_DISTANCE_RATIO", 1.05F)
<< "\n";
configOut
<< "boundary_spill_residual_penalty = "
<< parseFloatEnvOrDefault(
"YAMS_BENCH_TOPOLOGY_BOUNDARY_SPILL_RESIDUAL_PENALTY", 1.0F)
<< "\n";
}
}
configOut.close();
harnessOptions.configPath = configPath;
spdlog::info("Using isolated benchmark config: {}", configPath.string());
}
}
} else {
spdlog::info("Using mock model provider (YAMS_DISABLE_VECTORS=1)");
}
harness = std::make_unique<DaemonHarness>(harnessOptions);
std::chrono::milliseconds daemonReadyTimeout{30000};
if (const char* env = std::getenv("YAMS_BENCH_DAEMON_READY_TIMEOUT_MS")) {
daemonReadyTimeout = std::chrono::milliseconds{
static_cast<std::chrono::milliseconds::rep>(std::stoll(env))};
}
if (!harness->start(daemonReadyTimeout))
throw std::runtime_error("Failed to start daemon");
ensureBenchmarkEmbeddingsReady(harness.get(), vectorsDisabled, forceMockEmbeddings,
embedBackendSimeon);
if (useBEIR) {
const BEIRDataset& dataset = preparedBeirDataset.value();
fs::path corpusDir = harness->rootDir() / "corpus";
beirCorpus = std::make_unique<BEIRCorpusLoader>(dataset, corpusDir);
beirCorpus->writeDocumentsAsFiles();
benchCorpusDir = corpusDir;
corpusSize = static_cast<int>(dataset.documents.size());
numQueries = static_cast<int>(dataset.queries.size());
expectedCacheMetadata.expectedDocs = corpusSize;
expectedCacheMetadata.expectedQueries = numQueries;
expectedCacheMetadata.corpusFingerprint = computePathFingerprint(benchCorpusDir);
} else {
benchCorpusDir = harness->rootDir() / "corpus";
corpus = std::make_unique<CorpusGenerator>(benchCorpusDir, syntheticCorpusMode);
corpus->generateDocuments(corpusSize);
corpusSize = static_cast<int>(corpus->createdFiles.size());
expectedCacheMetadata.expectedDocs = corpusSize;
expectedCacheMetadata.corpusFingerprint = computePathFingerprint(benchCorpusDir);
}
yams::daemon::ClientConfig clientCfg;
// Prefer proxy socket for long-running benchmark connections; it skips
// maxConnectionLifetime enforcement (main socket forces close at ~300s).
{
// Proxy socket is derived from daemon socket stem + ".proxy.sock".
fs::path daemonSock = harness->socketPath();
auto base = daemonSock.stem().string();
if (base.empty())
base = daemonSock.filename().string();
if (base.empty())
base = "yams-daemon";
fs::path proxySock = daemonSock.parent_path() / (base + ".proxy.sock");
if (fs::exists(proxySock)) {
clientCfg.socketPath = proxySock;
spdlog::info("Using proxy socket for benchmark client: {}", proxySock.string());
} else {
clientCfg.socketPath = harness->socketPath();
spdlog::info("Proxy socket not found; using main socket: {}",
clientCfg.socketPath.string());
}
}
clientCfg.connectTimeout = 5s;
const auto benchmarkRequestTimeout =
std::max(std::chrono::duration_cast<std::chrono::milliseconds>(300s),
configuredBenchQueryTimeout("hybrid"));
clientCfg.requestTimeout = benchmarkRequestTimeout;
clientCfg.autoStart = false;
auto isEofLikeError = [](const yams::Error& error) {
return error.message.find("[ipc:eof]") != std::string::npos ||
error.message.find("End of file") != std::string::npos ||
error.message.find("Connection closed") != std::string::npos;
};
auto connectClientWithProbe = [&](const char* reason) {
if (reason && *reason) {
spdlog::info("[Bench] Reconnecting benchmark client ({})", reason);
}
client = std::make_unique<yams::daemon::DaemonClient>(clientCfg);
// Override header/body timeouts to handle slow reranker queries.
// Default headerTimeout=30s is too short when cross-encoder reranking
// takes 20-60s before any response header is sent.
client->setHeaderTimeout(benchmarkRequestTimeout);
client->setBodyTimeout(benchmarkRequestTimeout);
auto connectResult = benchRunSync(client->connect(), 5s);
if (!connectResult) {
throw std::runtime_error("Failed to connect: " + connectResult.error().message);
}
// Probe the exact selected socket path before ingesting to catch startup races.
constexpr int kStatusProbeAttempts = 8;
for (int attempt = 1; attempt <= kStatusProbeAttempts; ++attempt) {
auto statusProbe = benchRunSync(client->status(true), 5s);
if (statusProbe) {
if (attempt > 1) {
spdlog::info("[Bench] Client status probe succeeded after {} attempts",
attempt);
}
return;
}
if (attempt == kStatusProbeAttempts) {
throw std::runtime_error("Client status probe failed: " +
statusProbe.error().message);
}
const bool eofLike = isEofLikeError(statusProbe.error());
const auto backoff = std::chrono::milliseconds(125 * attempt);
spdlog::warn("[Bench] Client status probe attempt {}/{} failed ({}{}), retrying in "
"{}ms",
attempt, kStatusProbeAttempts, statusProbe.error().message,
eofLike ? ", eof-like" : "", backoff.count());
if (eofLike) {
// Drop any potentially stale pooled transport before retrying.
client.reset();
yams::daemon::AsioConnectionPool::shutdown_all(std::chrono::milliseconds(250));
auto reconnectWait = std::chrono::milliseconds(80);
std::this_thread::sleep_for(reconnectWait);
client = std::make_unique<yams::daemon::DaemonClient>(clientCfg);
client->setHeaderTimeout(std::chrono::milliseconds(300000));
client->setBodyTimeout(std::chrono::milliseconds(300000));
auto reconnectResult = benchRunSync(client->connect(), 5s);
if (!reconnectResult) {
throw std::runtime_error("Failed to reconnect after probe EOF: " +
reconnectResult.error().message);
}
}
std::this_thread::sleep_for(backoff);
}
};
connectClientWithProbe("initial setup");
const bool usingExternalBenchDataDir = harnessOptions.dataDir.has_value();
const fs::path effectiveDataDir =
harnessOptions.dataDir.has_value() ? *harnessOptions.dataDir : harness->dataDir();
auto initialStatusResult = benchRunSync(client->status(true), 5s);
const auto getInitialCount = [&](const std::string& key) -> uint64_t {
if (!initialStatusResult) {
return 0;
}
auto it = initialStatusResult.value().requestCounts.find(key);
return (it == initialStatusResult.value().requestCounts.end()) ? 0ULL : it->second;
};
const bool warmCacheMetadataReusable =
warmCacheMetadata.has_value() &&
(warmCacheMetadata->status == "primed" || warmCacheMetadata->status == "partial");
const uint64_t initialIndexedDocCount = [&]() -> uint64_t {
if (warmCacheMetadataReusable) {
return static_cast<uint64_t>(warmCacheMetadata->expectedDocs);
}
if (!initialStatusResult) {
return 0;
}
auto itIndexed = initialStatusResult.value().requestCounts.find("documents_indexed");
if (itIndexed != initialStatusResult.value().requestCounts.end()) {
return itIndexed->second;
}
auto itTotal = initialStatusResult.value().requestCounts.find("documents_total");
return (itTotal == initialStatusResult.value().requestCounts.end()) ? 0ULL
: itTotal->second;
}();
const uint64_t initialDocsEmbedded =
warmCacheMetadataReusable ? static_cast<uint64_t>(warmCacheMetadata->embeddedDocs)
: getInitialCount("documents_embedded");
const uint64_t initialVectorCount =
warmCacheMetadataReusable ? static_cast<uint64_t>(warmCacheMetadata->vectorCount)
: getInitialCount("vector_count");
const uint64_t initialEmbedQueued =
warmCacheMetadataReusable ? 0 : getInitialCount("embed_svc_queued");
const uint64_t initialEmbedInFlight =
warmCacheMetadataReusable ? 0 : getInitialCount("embed_in_flight");
const PersistedHnswState initialPersistedHnsw = inspectPersistedHnswState(effectiveDataDir);
bool initialBackendIndexReusable = false;
if (auto* daemon = harness ? harness->daemon() : nullptr) {
if (auto* serviceManager = daemon->getServiceManager()) {
if (auto vectorDb = serviceManager->getVectorDatabase();
vectorDb && vectorDb->isInitialized()) {
const auto probeStart = std::chrono::steady_clock::now();
initialBackendIndexReusable = vectorDb->hasReusablePersistedSearchIndex();
setupTimings.vectorIndexReusableProbeMs +=
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - probeStart)
.count();
++setupTimings.vectorIndexReusableProbeCount;
}
}
}
const bool cacheHasIndexedCorpus =
usingExternalBenchDataDir &&
initialIndexedDocCount >= static_cast<uint64_t>(corpusSize);
const bool cacheHasFullEmbeddings =
usingExternalBenchDataDir && !vectorsDisabled &&
initialDocsEmbedded >= static_cast<uint64_t>(corpusSize) && initialEmbedQueued == 0 &&
initialEmbedInFlight == 0;
const bool cacheHasReusableVectorIndex =
vectorsDisabled || (usingExternalBenchDataDir &&
yams::bench::benchmarkSearchIndexReusable(
benchmarkVectorSearchEngine(), initialBackendIndexReusable));
if (usingExternalBenchDataDir) {
spdlog::info("[Bench] External data dir status: indexed_docs={} embedded_docs={} "
"vector_count={} embed_queue={} embed_in_flight={} vector_index_ready={} "
"persisted_hnsw_nodes={} persisted_hnsw_meta={}{}",
initialIndexedDocCount, initialDocsEmbedded, initialVectorCount,
initialEmbedQueued, initialEmbedInFlight,
(cacheHasReusableVectorIndex ? "true" : "false"),
initialPersistedHnsw.nodeRows, initialPersistedHnsw.metaRows,
warmCacheMetadataReusable ? " (trusted metadata)" : "");
}
if (!(cacheHasFullEmbeddings && cacheHasReusableVectorIndex)) {
if (cacheHasIndexedCorpus) {
spdlog::info("[Bench] Reusing indexed corpus from external data dir; skipping "
"directory ingest");
}
if (!cacheHasIndexedCorpus) {
// Use directory ingestion for faster bulk add via IndexingService
fs::path corpusDir = useBEIR ? beirCorpus->corpusDir : corpus->corpusDir;
spdlog::info("Ingesting {} documents from {}...", corpusSize, corpusDir.string());
setupTimings.coldIngestPerformed = true;
coldIngestStartedAt = SetupClock::now();
yams::daemon::AddDocumentRequest addReq;
addReq.path = corpusDir.string();
addReq.recursive = true;
addReq.noEmbeddings = false;
addReq.includePatterns = {"*.txt"};
Result<yams::daemon::AddDocumentResponse> addResult =
Error{ErrorCode::Unknown, "ingest not attempted"};
constexpr int kIngestAttempts = 2;
for (int ingestAttempt = 1; ingestAttempt <= kIngestAttempts; ++ingestAttempt) {
if (!client) {
connectClientWithProbe("directory ingest attempt");
if (!client) {
throw std::runtime_error(
"Benchmark client unavailable before directory ingest attempt");
}
}
addResult = benchRunSync(client->streamingAddDocument(addReq), 120s);
if (addResult) {
break;
}
const bool eofLike = isEofLikeError(addResult.error());
if (!(eofLike && ingestAttempt < kIngestAttempts)) {
break;
}
spdlog::warn(
"[Bench] Directory ingest attempt {}/{} failed with eof-like transport "
"error ({}). Retrying once with a fresh client.",
ingestAttempt, kIngestAttempts, addResult.error().message);
client.reset();
yams::daemon::AsioConnectionPool::shutdown_all(std::chrono::milliseconds(250));
std::this_thread::sleep_for(std::chrono::milliseconds(120));
connectClientWithProbe("ingest retry after eof");
}
if (!addResult) {
throw std::runtime_error("Failed to ingest directory: " +
addResult.error().message);
}
admissionCompletedAt = SetupClock::now();
setupTimings.admissionMs = elapsedMsSince(*coldIngestStartedAt);
spdlog::info("Directory ingestion request accepted: {}", addResult.value().message);
// Wait for directory ingestion to complete by monitoring document count
// Use progress-based timeout: only timeout if no progress for N seconds
// This is more robust than a hard deadline because slow ingestion won't fail,
// but true hangs will still be detected.
auto progressTimeoutSec = std::chrono::seconds(
300); // 5 minutes without progress = stalled (embedding/model load)
if (const char* env = std::getenv("YAMS_BENCH_PROGRESS_TIMEOUT")) {
progressTimeoutSec = std::chrono::seconds(std::stoi(env));
}
double ingestMinFraction = 1.0;
if (const char* env = std::getenv("YAMS_BENCH_INGEST_MIN_FRACTION")) {
ingestMinFraction = std::clamp(std::stod(env), 0.0, 1.0);
}
const auto ingestTargetDocs = static_cast<uint64_t>(
std::ceil(static_cast<double>(corpusSize) * ingestMinFraction));
spdlog::info("Waiting for ingestion to complete (expecting {} documents, "
"progress timeout {}s)...",
corpusSize, progressTimeoutSec.count());
auto lastProgressTime = std::chrono::steady_clock::now();
auto ingestHeartbeatAt = lastProgressTime + std::chrono::seconds(5);
uint64_t lastDocCount = 0;
uint64_t lastIndexedDocCount = 0;
uint64_t lastContentExtracted = 0;
uint64_t lastPostProcessed = 0;
uint64_t lastEmbedQueued = 0;
uint64_t lastEmbedInFlight = 0;
uint64_t lastVectorCount = 0;
uint32_t lastDepth = 0;
int stableChecks = 0;
// Helper to get metric from requestCounts with presence flag
auto getMetric = [](const auto& counts,
const std::string& key) -> std::pair<uint64_t, bool> {
auto it = counts.find(key);
if (it == counts.end())
return {0, false};
return {it->second, true};
};
uint64_t lastKgInFlight = 0, lastSymbolInFlight = 0, lastEntityInFlight = 0;
uint64_t lastExtractionInFlight = 0;
auto ingestionLooksCompleteFromLastObserved = [&]() -> bool {
const bool targetReached = (lastIndexedDocCount >= ingestTargetDocs) ||
(lastDocCount >= ingestTargetDocs);
const bool allQueuesDrained =
(lastDepth == 0 && lastExtractionInFlight == 0 && lastKgInFlight == 0 &&
lastSymbolInFlight == 0 && lastEntityInFlight == 0 &&
lastEmbedQueued == 0 && lastEmbedInFlight == 0);
const bool extractionOrPostDone = (lastContentExtracted >= ingestTargetDocs) ||
(lastPostProcessed >= ingestTargetDocs);
return targetReached && allQueuesDrained && extractionOrPostDone;
};
while (true) {
auto now = std::chrono::steady_clock::now();
auto timeSinceProgress =
std::chrono::duration_cast<std::chrono::seconds>(now - lastProgressTime);
if (now >= ingestHeartbeatAt) {
ingestHeartbeatAt = now + std::chrono::seconds(5);
spdlog::info("Ingest wait heartbeat: since_progress={}s last_total={} "
"last_indexed={} last_queue={} "
"last_processed={}",
timeSinceProgress.count(), lastDocCount, lastIndexedDocCount,
lastDepth, lastPostProcessed);
}
// Check for stall (no progress for progressTimeoutSec)
if (timeSinceProgress > progressTimeoutSec) {
if (ingestionLooksCompleteFromLastObserved()) {
spdlog::warn(
"Ingestion progress timeout reached, but last observed metrics "
"already indicate completion; accepting completion.");
break;
}
// Status polls may intermittently fail even when work is done; perform one
// final verification poll before classifying as stalled.
auto finalVerify = benchRunSync(client->status(true), 10s);
if (finalVerify) {
const auto& counts = finalVerify.value().requestCounts;
auto get = [&](const std::string& key) -> uint64_t {
auto it = counts.find(key);
return (it == counts.end()) ? 0ULL : it->second;
};
const uint64_t docsTotal = get("documents_total");
const uint64_t docsIndexed = get("documents_indexed");
const uint64_t extracted = get("documents_content_extracted");
const uint64_t postQueued = get("post_ingest_queued");
const uint64_t postInFlight = get("post_ingest_inflight");
const uint64_t postProcessed = get("post_ingest_processed");
const uint64_t extractionInFlight = get("extraction_inflight");
const uint64_t kgInFlight = get("kg_inflight");
const uint64_t symbolInFlight = get("symbol_inflight");
const uint64_t entityInFlight = get("entity_inflight");
const uint64_t embedQueued = get("embed_svc_queued");
const uint64_t embedInFlight = get("embed_in_flight");
const bool targetReached = (docsIndexed >= ingestTargetDocs) ||
(docsTotal >= ingestTargetDocs);
const bool allQueuesDrained =
(postQueued == 0 && postInFlight == 0 && extractionInFlight == 0 &&
kgInFlight == 0 && symbolInFlight == 0 && entityInFlight == 0 &&
embedQueued == 0 && embedInFlight == 0);
const bool extractionOrPostDone = (extracted >= ingestTargetDocs) ||
(postProcessed >= ingestTargetDocs);
if (targetReached && allQueuesDrained && extractionOrPostDone) {
spdlog::warn(
"Ingestion progress timeout reached but final verification "
"shows completion (docs_total={}, docs_indexed={}, "
"extracted={}, post_processed={}); accepting completion.",
docsTotal, docsIndexed, extracted, postProcessed);
break;
}
}
spdlog::error(
"Ingestion stalled - no progress for {}s (docs: total={} indexed={} "
"target={} "
"queue={}, inflight: extract={} kg={} symbol={} entity={} extracted={} "
"processed={} embed_queue={} embed_in_flight={} vectors={})",
timeSinceProgress.count(), lastDocCount, lastIndexedDocCount,
corpusSize, lastDepth, lastExtractionInFlight, lastKgInFlight,
lastSymbolInFlight, lastEntityInFlight, lastContentExtracted,
lastPostProcessed, lastEmbedQueued, lastEmbedInFlight, lastVectorCount);
throw std::runtime_error(
"Ingestion stalled - benchmark results would be invalid. "
"Set YAMS_BENCH_PROGRESS_TIMEOUT=300 for slower systems. "
"For faster ingestion: YAMS_POST_EMBED_CONCURRENT=12 "
"YAMS_POST_EXTRACTION_CONCURRENT=12 YAMS_DB_POOL_MAX=48");
}
auto statusResult = benchRunSync(client->status(true), 5s);
if (statusResult) {
const auto& counts = statusResult.value().requestCounts;
uint32_t depth = statusResult.value().postIngestQueueDepth;
auto [docCount, docCountPresent] = getMetric(counts, "documents_total");
auto [indexedCount, indexedPresent] =
getMetric(counts, "documents_indexed");
auto [contentExtracted, extractedPresent] =
getMetric(counts, "documents_content_extracted");
auto [postQueued, postQueuedPresent] =
getMetric(counts, "post_ingest_queued");
auto [postInflight, postInflightPresent] =
getMetric(counts, "post_ingest_inflight");
auto [postProcessed, postProcessedPresent] =
getMetric(counts, "post_ingest_processed");
auto [embedQueued, embedQueuedPresent] =
getMetric(counts, "embed_svc_queued");
auto [embedInFlight, embedInFlightPresent] =
getMetric(counts, "embed_in_flight");
auto [vectorCount, vectorPresent] = getMetric(counts, "vector_count");
uint64_t queuedTotal = std::max<uint64_t>(depth, postQueued);
// Check all processing stage in-flight counters
auto [extractionInFlight, extractionPresent] =
getMetric(counts, "extraction_inflight");
auto [kgInFlight, kgPresent] = getMetric(counts, "kg_inflight");
auto [symbolInFlight, symbolPresent] = getMetric(counts, "symbol_inflight");
auto [entityInFlight, entityPresent] = getMetric(counts, "entity_inflight");
// Total in-flight across all stages (matches
// PostIngestQueue::totalInFlight())
uint64_t totalInFlight =
extractionInFlight + kgInFlight + symbolInFlight + entityInFlight;
bool statusChanged =
(queuedTotal != lastDepth || docCount != lastDocCount ||
indexedCount != lastIndexedDocCount ||
contentExtracted != lastContentExtracted ||
postProcessed != lastPostProcessed || kgInFlight != lastKgInFlight ||
symbolInFlight != lastSymbolInFlight ||
entityInFlight != lastEntityInFlight ||
extractionInFlight != lastExtractionInFlight ||
embedQueued != lastEmbedQueued || embedInFlight != lastEmbedInFlight ||
vectorCount != lastVectorCount);
if (statusChanged) {
bool vectorDbReady = statusResult.value().vectorDbReady;
if (auto it = statusResult.value().readinessStates.find("vector_db");
it != statusResult.value().readinessStates.end()) {
vectorDbReady = it->second;
}
spdlog::debug(
"Documents: total={} indexed={} / {} | queue={} inflight={} | "
"extracted={} "
"processed={} | extract={} kg={} symbol={} entity={} (total={}) | "
"embed_queue={} embed_in_flight={} vectors={} (ready={})",
docCount, indexedCount, corpusSize, queuedTotal, postInflight,
contentExtracted, postProcessed, extractionInFlight, kgInFlight,
symbolInFlight, entityInFlight, totalInFlight, embedQueued,
embedInFlight, vectorCount, (vectorDbReady ? "true" : "false"));
lastDepth = static_cast<uint32_t>(queuedTotal);
lastDocCount = docCount;
lastIndexedDocCount = indexedCount;
lastContentExtracted = contentExtracted;
lastPostProcessed = postProcessed;
lastEmbedQueued = embedQueued;
lastEmbedInFlight = embedInFlight;
lastVectorCount = vectorCount;
lastKgInFlight = kgInFlight;
lastSymbolInFlight = symbolInFlight;
lastEntityInFlight = entityInFlight;
lastExtractionInFlight = extractionInFlight;
stableChecks = 0;
lastProgressTime = now; // Reset progress timer on any change
} else {
stableChecks++;
}
// Complete when ALL stages are idle:
// - post_ingest_queued == 0 AND post_ingest_inflight == 0 (queue empty)
// - totalInFlight == 0 (all stages: extraction, KG, symbol, entity)
// - indexedCount >= corpusSize (or stable for 5+ seconds after reaching
// target)
bool allStagesDrained =
(queuedTotal == 0 && postInflight == 0 && totalInFlight == 0);
bool extractedReady =
extractedPresent
? (contentExtracted >= static_cast<uint64_t>(corpusSize))
: true;
bool processedReady =
postProcessedPresent
? (postProcessed >= static_cast<uint64_t>(corpusSize))
: true;
// `documents_indexed` is a search/FTS visibility counter and can lag or
// remain stale under sanitizer/slow asynchronous rebuild runs even after
// the directory ingest and post-ingest pipeline have accepted and processed
// the whole corpus. For benchmark setup, do not block forever on that
// secondary visibility counter once the canonical document total reached
// the requested corpus and extraction/post-processing has completed.
const bool corpusStored = docCount >= static_cast<uint64_t>(corpusSize);
bool indexedReady =
indexedPresent ? (indexedCount >= static_cast<uint64_t>(corpusSize) ||
(corpusStored && (extractedReady || processedReady)))
: corpusStored;
bool stableAfterDrain = (stableChecks >= 6);
if (allStagesDrained && indexedReady &&
(extractedReady || processedReady || stableAfterDrain)) {
spdlog::info(
"Ingestion complete: total={} indexed={} (target={}), all stages "
"drained (extracted={}, processed={})",
docCount, indexedCount, corpusSize, contentExtracted,
postProcessed);
break;
}
} else {
if (now >= ingestHeartbeatAt - std::chrono::seconds(5)) {
spdlog::warn("Status polling failed during ingest wait: {}",
statusResult.error().message);
}
}
std::this_thread::sleep_for(500ms);
}
setupTimings.storageReadyMs = elapsedMsSince(*coldIngestStartedAt);
setupTimings.pipelineDrainMs =
admissionCompletedAt.has_value() ? elapsedMsSince(*admissionCompletedAt) : 0;
} else if (!vectorsDisabled) {
yams::daemon::RepairRequest repairReq;
repairReq.repairEmbeddings = true;
repairReq.embeddingModel = "embeddinggemma-300m";
repairReq.foreground = true;
repairReq.maxRetries = 3;
spdlog::info("[Bench] Requesting embedding repair to resume warm-cache priming...");
auto repairResult = benchRunSync(client->callRepair(repairReq), 300s);
if (!repairResult) {
spdlog::warn("[Bench] Embedding repair request failed: {}",
repairResult.error().message);
} else {
spdlog::info("[Bench] Embedding repair queued: success={} ops={} succeeded={} "
"failed={} skipped={}",
repairResult.value().success, repairResult.value().totalOperations,
repairResult.value().totalSucceeded,
repairResult.value().totalFailed,
repairResult.value().totalSkipped);
}
}
// Wait for embedding provider to become available
spdlog::info("Waiting for embedding provider to become available...");
auto deadline = std::chrono::steady_clock::now() + 30s;
bool embeddingReady = false;
while (std::chrono::steady_clock::now() < deadline) {
auto statusResult = benchRunSync(client->status(true), 5s);
if (statusResult && statusResult.value().embeddingAvailable) {
spdlog::info("Embedding provider is available (backend: {}, model: {})",
statusResult.value().embeddingBackend,
statusResult.value().embeddingModel);
embeddingReady = true;
break;
}
std::this_thread::sleep_for(500ms);
}
if (!embeddingReady) {
spdlog::warn("Embedding provider did not become available within 30s");
}
// Wait for embeddings to be generated by checking document-level embedding progress
// (documents_embedded) and queue drain. We still track vector_count for row-level
// visibility, but vector_count is not a document counter.
bool vectorsEnabled = !vectorsDisabled;
if (vectorsEnabled && !embeddingReady) {
vectorsEnabled = false;
spdlog::warn("Disabling vector wait for this benchmark run: embedding provider is "
"unavailable; proceeding with keyword-dominant evaluation");
if (summaryLog) {
summaryLog << "Embedding provider unavailable after 30s; skipping vector wait"
<< std::endl;
summaryLog.flush();
}
}
if (vectorsEnabled) {
spdlog::info("Waiting for embeddings to be generated (target: {} docs)...",
corpusSize);
auto embedHeartbeatAt = std::chrono::steady_clock::now() + std::chrono::seconds(5);
// Log to summary file
if (summaryLog) {
summaryLog << "=== Embedding Generation ===" << std::endl;
summaryLog << "Target: " << corpusSize << " documents" << std::endl;
}
auto embedProgressTimeoutSec = std::chrono::seconds(600);
if (const char* env = std::getenv("YAMS_BENCH_EMBED_PROGRESS_TIMEOUT")) {
embedProgressTimeoutSec = std::chrono::seconds(std::stoi(env));
}
auto embedMaxWaitSec = std::chrono::seconds(7200); // 2h hard cap (configurable)
if (const char* env = std::getenv("YAMS_BENCH_EMBED_MAX_WAIT")) {
embedMaxWaitSec = std::chrono::seconds(std::stoi(env));
}
struct EmbedWaitSnapshot {
uint64_t vectorCount = 0;
uint64_t docsEmbedded = 0;
uint64_t preparedDocs = 0;
uint64_t preparedChunks = 0;
uint64_t queueDepth = 0;
uint64_t inFlight = 0;
uint64_t dropped = 0;
uint64_t inferActive = 0;
uint64_t inferOldestMs = 0;
uint64_t inferStarted = 0;
uint64_t inferCompleted = 0;
uint64_t inferWarnCount = 0;
bool hasQueueMetrics = false;
bool vectorDbReady = false;
bool queueDrained() const { return queueDepth == 0 && inFlight == 0; }
bool inferLikelyActive(std::chrono::seconds timeout) const {
return inferActive > 0 &&
inferOldestMs < static_cast<uint64_t>(timeout.count()) * 1000ull;
}
double coverageFor(int totalDocs) const {
return totalDocs > 0 ? (docsEmbedded * 100.0 / totalDocs) : 0.0;
}
double avgChunksPerDoc() const {
return preparedDocs > 0 ? static_cast<double>(preparedChunks) /
static_cast<double>(preparedDocs)
: 0.0;
}
};
auto progressSignalChanged = [](const EmbedWaitSnapshot& lhs,
const EmbedWaitSnapshot& rhs) {
return lhs.vectorCount != rhs.vectorCount ||
lhs.docsEmbedded != rhs.docsEmbedded ||
lhs.preparedDocs != rhs.preparedDocs ||
lhs.preparedChunks != rhs.preparedChunks ||
lhs.queueDepth != rhs.queueDepth || lhs.inFlight != rhs.inFlight ||
lhs.dropped != rhs.dropped || lhs.inferActive != rhs.inferActive ||
lhs.inferStarted != rhs.inferStarted ||
lhs.inferCompleted != rhs.inferCompleted ||
lhs.inferWarnCount != rhs.inferWarnCount;
};
auto getRequestCount = [](const auto& status, std::string_view key) {
auto it = status.requestCounts.find(std::string(key));
return (it == status.requestCounts.end()) ? 0ULL : it->second;
};
auto collectEmbedSnapshot = [&](const auto& status) {
EmbedWaitSnapshot snapshot;
snapshot.vectorDbReady = status.vectorDbReady;
if (auto it = status.readinessStates.find("vector_db");
it != status.readinessStates.end()) {
snapshot.vectorDbReady = it->second;
}
snapshot.vectorCount = getRequestCount(status, "vector_count");
snapshot.docsEmbedded = getRequestCount(status, "documents_embedded");
snapshot.preparedDocs =
getRequestCount(status, "bus_embed_prepared_docs_queued");
snapshot.preparedChunks =
getRequestCount(status, "bus_embed_prepared_chunks_queued");
snapshot.queueDepth = getRequestCount(status, "embed_svc_queued");
snapshot.inFlight = getRequestCount(status, "embed_in_flight");
snapshot.dropped = getRequestCount(status, "bus_embed_dropped");
snapshot.inferActive = getRequestCount(status, "embed_infer_active");
snapshot.inferOldestMs = getRequestCount(status, "embed_infer_oldest_ms");
snapshot.inferStarted = getRequestCount(status, "embed_infer_started");
snapshot.inferCompleted = getRequestCount(status, "embed_infer_completed");
snapshot.inferWarnCount = getRequestCount(status, "embed_infer_warn_count");
snapshot.hasQueueMetrics = status.requestCounts.contains("embed_svc_queued") ||
status.requestCounts.contains("embed_in_flight");
return snapshot;
};
EmbedWaitSnapshot observedSnapshot;
EmbedWaitSnapshot lastProgressSnapshot;
bool haveObservedSnapshot = false;
bool haveProgressSnapshot = false;
int stableCount = 0;
bool embeddingDrainSatisfied = false;
auto embedStartTime = std::chrono::steady_clock::now();
auto lastEmbedProgressTime = embedStartTime;
// Phase 1: Wait for embedding queue to drain and embedded documents to reach
// target. Uses progress-based stall detection (like ingestion wait) to avoid
// failing while work is still actively progressing on large corpora/slow
// accelerators.
while (true) {
auto now = std::chrono::steady_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::seconds>(now - embedStartTime);
auto sinceProgress = std::chrono::duration_cast<std::chrono::seconds>(
now - lastEmbedProgressTime);
if (embedMaxWaitSec.count() > 0 && elapsed > embedMaxWaitSec) {
throw std::runtime_error(
"Embedding wait exceeded hard limit (" +
std::to_string(embedMaxWaitSec.count()) +
"s) before benchmark queries (embed_svc_queued=" +
std::to_string(observedSnapshot.queueDepth) +
", embed_in_flight=" + std::to_string(observedSnapshot.inFlight) +
", docs_embedded=" + std::to_string(observedSnapshot.docsEmbedded) +
", vectors=" + std::to_string(observedSnapshot.vectorCount) +
", dropped=" + std::to_string(observedSnapshot.dropped) +
"). Increase YAMS_BENCH_EMBED_MAX_WAIT or tune embedding concurrency.");
}
const bool inferLikelyActive =
observedSnapshot.inferLikelyActive(embedProgressTimeoutSec);
if (sinceProgress > embedProgressTimeoutSec && !inferLikelyActive) {
throw std::runtime_error(
"Embedding wait stalled for " +
std::to_string(embedProgressTimeoutSec.count()) +
"s before benchmark queries (embed_svc_queued=" +
std::to_string(observedSnapshot.queueDepth) +
", embed_in_flight=" + std::to_string(observedSnapshot.inFlight) +
", docs_embedded=" + std::to_string(observedSnapshot.docsEmbedded) +
", vectors=" + std::to_string(observedSnapshot.vectorCount) +
", dropped=" + std::to_string(observedSnapshot.dropped) +
"). Increase timeout/concurrency or investigate model/provider "
"stalls.");
}
if (now >= embedHeartbeatAt) {
embedHeartbeatAt = now + std::chrono::seconds(5);
spdlog::info("Embed wait heartbeat: elapsed={}s since_progress={}s "
"last_docs_embedded={} last_vectors={} queue={} in_flight={} "
"infer_active={} infer_oldest_ms={} infer_started={} "
"infer_completed={}",
elapsed.count(), sinceProgress.count(),
observedSnapshot.docsEmbedded, observedSnapshot.vectorCount,
observedSnapshot.queueDepth, observedSnapshot.inFlight,
observedSnapshot.inferActive, observedSnapshot.inferOldestMs,
observedSnapshot.inferStarted,
observedSnapshot.inferCompleted);
}
auto statusResult = benchRunSync(client->status(true), 5s);
if (statusResult) {
const auto snapshot = collectEmbedSnapshot(statusResult.value());
const bool metricsChanged =
!haveObservedSnapshot ||
progressSignalChanged(snapshot, observedSnapshot);
observedSnapshot = snapshot;
haveObservedSnapshot = true;
if (metricsChanged) {
lastEmbedProgressTime = now;
stableCount = 0;
} else {
stableCount++;
}
if (!haveProgressSnapshot ||
observedSnapshot.vectorCount != lastProgressSnapshot.vectorCount ||
observedSnapshot.docsEmbedded != lastProgressSnapshot.docsEmbedded) {
const double docCoverage = observedSnapshot.coverageFor(corpusSize);
const double preparedAvgChunksPerDoc =
observedSnapshot.avgChunksPerDoc();
spdlog::info(
"Embedding progress: docs={} / {} ({:.1f}%) vectors={} "
"prepared_docs={} prepared_chunks={} avg_chunks_per_doc={:.2f} "
"| queue={} in_flight={} dropped={}",
observedSnapshot.docsEmbedded, corpusSize, docCoverage,
observedSnapshot.vectorCount, observedSnapshot.preparedDocs,
observedSnapshot.preparedChunks, preparedAvgChunksPerDoc,
observedSnapshot.queueDepth, observedSnapshot.inFlight,
observedSnapshot.dropped);
// Log progress to summary file
if (summaryLog) {
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - embedStartTime)
.count();
summaryLog << "[" << elapsed
<< "ms] DocsEmbedded: " << observedSnapshot.docsEmbedded
<< " / " << corpusSize << " (" << std::fixed
<< std::setprecision(1) << docCoverage << "%)"
<< " | vectors=" << observedSnapshot.vectorCount
<< " | prepared_docs=" << observedSnapshot.preparedDocs
<< " prepared_chunks=" << observedSnapshot.preparedChunks
<< " avg_chunks_per_doc=" << std::fixed
<< std::setprecision(2) << preparedAvgChunksPerDoc
<< " | queue=" << observedSnapshot.queueDepth
<< " in_flight=" << observedSnapshot.inFlight
<< " dropped=" << observedSnapshot.dropped << std::endl;
summaryLog.flush();
}
lastProgressSnapshot = observedSnapshot;
haveProgressSnapshot = true;
}
// Success condition: embedded docs >= corpusSize AND queue drained.
// vector_count tracks rows (chunks + doc records), not documents.
if (observedSnapshot.hasQueueMetrics &&
observedSnapshot.docsEmbedded >= static_cast<uint64_t>(corpusSize) &&
observedSnapshot.queueDrained()) {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - embedStartTime)
.count();
spdlog::info(
"Full embedding coverage achieved: {} embedded docs for {} "
"target docs (queue drained, vector_db_ready={})",
observedSnapshot.docsEmbedded, corpusSize,
(observedSnapshot.vectorDbReady ? "true" : "false"));
if (summaryLog) {
summaryLog << "\n*** SUCCESS: Full coverage in " << elapsed
<< "ms ***" << std::endl;
summaryLog
<< "Final embedded docs: " << observedSnapshot.docsEmbedded
<< std::endl;
summaryLog << "Final vectors: " << observedSnapshot.vectorCount
<< std::endl;
summaryLog << "Total dropped: " << observedSnapshot.dropped
<< std::endl;
summaryLog.flush();
}
embeddingDrainSatisfied = true;
break;
}
// If very stable (20s) with queue drained, we're done even if < corpusSize
// This handles cases where some docs have no content to embed
// IMPORTANT: Require minimum 90% coverage to prevent premature exit from
// transient queue drain (e.g., between embedding batches)
const double coverage = observedSnapshot.coverageFor(corpusSize);
constexpr double MIN_COVERAGE_THRESHOLD = 90.0;
if (observedSnapshot.hasQueueMetrics && stableCount >= 40 &&
observedSnapshot.queueDrained() && observedSnapshot.docsEmbedded > 0 &&
coverage >= MIN_COVERAGE_THRESHOLD) {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - embedStartTime)
.count();
spdlog::info(
"Embedding generation complete (queue drained, stable): {} "
"embedded docs ({:.1f}% coverage, vector_db_ready={})",
observedSnapshot.docsEmbedded, coverage,
(observedSnapshot.vectorDbReady ? "true" : "false"));
if (summaryLog) {
summaryLog << "\n*** Complete (queue drained) in " << elapsed
<< "ms ***" << std::endl;
summaryLog
<< "Final embedded docs: " << observedSnapshot.docsEmbedded
<< " (" << coverage << "%)" << std::endl;
summaryLog << "Final vectors: " << observedSnapshot.vectorCount
<< std::endl;
summaryLog.flush();
}
embeddingDrainSatisfied = true;
break;
}
if (observedSnapshot.hasQueueMetrics && stableCount >= 40 &&
observedSnapshot.queueDrained() && observedSnapshot.docsEmbedded == 0) {
throw std::runtime_error(
"Embedding failed before benchmark queries (queue "
"drained, no documents "
"embedded, dropped=" +
std::to_string(observedSnapshot.dropped) +
"). Check embedding provider/model availability.");
}
if (observedSnapshot.hasQueueMetrics && observedSnapshot.queueDrained() &&
observedSnapshot.docsEmbedded == 0 &&
elapsed > std::chrono::seconds(60)) {
throw std::runtime_error(
"Embedding appears unavailable for this candidate (queue drained, "
"no "
"documents embedded after " +
std::to_string(elapsed.count()) +
"s, dropped=" + std::to_string(observedSnapshot.dropped) +
"). Aborting candidate to keep optimization loop progressing.");
}
// If stable but queue NOT drained, warn about potential issues
if (observedSnapshot.hasQueueMetrics && stableCount >= 20 &&
!observedSnapshot.queueDrained() &&
!observedSnapshot.inferLikelyActive(embedProgressTimeoutSec) &&
observedSnapshot.docsEmbedded > 0) {
spdlog::warn("Embedding stalled at {:.1f}% but queue not drained "
"(queue={}, in_flight={}). Continuing to wait...",
coverage, observedSnapshot.queueDepth,
observedSnapshot.inFlight);
// Don't break - keep waiting for queue to drain
}
}
std::this_thread::sleep_for(500ms);
}
if (auto* daemon = harness->daemon()) {
if (auto* serviceManager = daemon->getServiceManager()) {
auto vectorDb = serviceManager->getVectorDatabase();
auto metadataRepo = serviceManager->getMetadataRepo();
if (vectorDb && metadataRepo) {
auto embeddedHashes = vectorDb->getEmbeddedDocumentHashes();
if (embeddedHashes.size() > observedSnapshot.docsEmbedded) {
std::vector<std::string> reconciledHashes;
reconciledHashes.reserve(embeddedHashes.size());
for (const auto& hash : embeddedHashes) {
reconciledHashes.push_back(hash);
}
auto reconcileResult =
metadataRepo->batchUpdateDocumentEmbeddingStatusByHashes(
reconciledHashes, true,
serviceManager->getEmbeddingModelName());
if (!reconcileResult) {
spdlog::warn("Failed to reconcile embedded-doc status from "
"vector rows: {}",
reconcileResult.error().message);
} else {
spdlog::info("Reconciled embedded-doc status from vector rows: "
"{} -> {}",
observedSnapshot.docsEmbedded,
reconciledHashes.size());
observedSnapshot.docsEmbedded = reconciledHashes.size();
lastProgressSnapshot.docsEmbedded = reconciledHashes.size();
}
}
}
}
}
// Final status check
auto finalStatus = benchRunSync(client->status(true), 5s);
if (finalStatus) {
uint64_t finalVectorCount = 0;
auto it = finalStatus.value().requestCounts.find("vector_count");
if (it != finalStatus.value().requestCounts.end()) {
finalVectorCount = it->second;
}
uint64_t finalDocsEmbedded = 0;
auto itDocsEmbedded =
finalStatus.value().requestCounts.find("documents_embedded");
if (itDocsEmbedded != finalStatus.value().requestCounts.end()) {
finalDocsEmbedded = itDocsEmbedded->second;
}
uint64_t finalEmbedQueued = 0;
auto itQ = finalStatus.value().requestCounts.find("embed_svc_queued");
if (itQ != finalStatus.value().requestCounts.end()) {
finalEmbedQueued = itQ->second;
}
uint64_t finalEmbedInFlight = 0;
auto itInFlight = finalStatus.value().requestCounts.find("embed_in_flight");
if (itInFlight != finalStatus.value().requestCounts.end()) {
finalEmbedInFlight = itInFlight->second;
}
double finalCoverage =
corpusSize > 0 ? (finalDocsEmbedded * 100.0 / corpusSize) : 0;
bool vectorDbReady = finalStatus.value().vectorDbReady;
if (auto it = finalStatus.value().readinessStates.find("vector_db");
it != finalStatus.value().readinessStates.end()) {
vectorDbReady = it->second;
}
spdlog::info("Vector DB: ready={} dim={}, docs_embedded={} vectors={} "
"({:.1f}% doc coverage)",
(vectorDbReady ? "true" : "false"),
finalStatus.value().vectorDbDim, finalDocsEmbedded,
finalVectorCount, finalCoverage);
if (!embeddingDrainSatisfied) {
const bool queueDrained =
(finalEmbedQueued == 0 && finalEmbedInFlight == 0);
if (!queueDrained) {
throw std::runtime_error(
"Embedding drain not reached before benchmark queries "
"(embed_svc_queued=" +
std::to_string(finalEmbedQueued) +
", embed_in_flight=" + std::to_string(finalEmbedInFlight) +
", docs_embedded=" + std::to_string(finalDocsEmbedded) +
", vectors=" + std::to_string(finalVectorCount) +
"). Increase timeout/concurrency or reduce corpus size to obtain "
"valid "
"results.");
}
// Queue may only be fully drained on the final status check.
embeddingDrainSatisfied = true;
}
if (finalDocsEmbedded == 0) {
spdlog::warn("No embedded documents present after embedding wait");
} else if (finalCoverage < 90.0) {
spdlog::error("WARNING: Low document embedding coverage ({:.1f}%) will "
"degrade retrieval "
"quality!",
finalCoverage);
spdlog::error(
"Consider reducing corpus size or increasing embed channel capacity.");
}
if (!vectorDbReady) {
spdlog::warn("Vector DB not ready yet; waiting briefly before queries...");
const auto guardDeadline = std::chrono::steady_clock::now() + 30s;
while (std::chrono::steady_clock::now() < guardDeadline) {
auto st = benchRunSync(client->status(true), 5s);
if (st) {
bool ready = st.value().vectorDbReady;
if (auto it = st.value().readinessStates.find("vector_db");
it != st.value().readinessStates.end()) {
ready = it->second;
}
if (ready) {
spdlog::info("Vector DB is now ready after guard wait");
break;
}
}
std::this_thread::sleep_for(500ms);
}
}
} else {
spdlog::warn("Final status check failed after embedding wait: {}",
finalStatus.error().message);
if (!embeddingDrainSatisfied) {
throw std::runtime_error("Final status check failed after embedding wait; "
"cannot verify embedding drain. "
"Benchmark results would be unreliable.");
}
}
} else {
spdlog::info("Vectors disabled - skipping embedding generation wait");
}
} else {
spdlog::info("[Bench] Warm data dir: skipping ingestion + embedding wait (usable "
"vector index already present)");
} // end if (!warmDataDir) / else
bool benchmarkVectorIndexReusableAfter = vectorsDisabled;
auto ensureVectorIndexReady = [&]() -> bool {
if (vectorsDisabled) {
return true;
}
const fs::path vectorIndexDataDir =
harnessOptions.dataDir.has_value() ? *harnessOptions.dataDir : harness->dataDir();
auto* daemon = harness ? harness->daemon() : nullptr;
auto* serviceManager = daemon ? daemon->getServiceManager() : nullptr;
auto vectorDb = serviceManager ? serviceManager->getVectorDatabase() : nullptr;
if (!vectorDb || !vectorDb->isInitialized()) {
spdlog::warn("[Bench] Cannot ensure vector index readiness: vector DB unavailable");
return false;
}
const auto probeBackendReusable = [&]() {
const auto probeStart = std::chrono::steady_clock::now();
const bool reusable = vectorDb->hasReusablePersistedSearchIndex();
setupTimings.vectorIndexReusableProbeMs +=
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - probeStart)
.count();
++setupTimings.vectorIndexReusableProbeCount;
return reusable;
};
auto persisted = vectorIndexDataDir.empty()
? PersistedHnswState{}
: inspectPersistedHnswState(vectorIndexDataDir);
const auto benchmarkEngine = benchmarkVectorSearchEngine();
const bool backendReusableBefore = probeBackendReusable();
setupTimings.vectorIndexReusableBefore =
yams::bench::benchmarkSearchIndexReusable(benchmarkEngine, backendReusableBefore);
const auto updateVectorIndexReadiness = [&](bool ready) {
if (!daemon) {
return;
}
daemon->state_.readiness.vectorIndexReady.store(ready, std::memory_order_relaxed);
daemon->state_.readiness.vectorIndexProgress.store(
ready ? 100
: (daemon->state_.readiness.vectorDbReady.load(std::memory_order_relaxed)
? 50
: 0),
std::memory_order_relaxed);
};
const auto vectorRows = vectorDb->getVectorCount();
if (vectorRows == 0) {
spdlog::warn("[Bench] Cannot ensure vector index readiness: vector DB is empty");
return false;
}
const bool indexlessExact =
benchmarkEngine == yams::vector::VectorSearchEngine::ExactScan;
bool preparedThisRun = false;
if (!indexlessExact && !setupTimings.vectorIndexReusableBefore) {
const char* modeLabel = warmDataDirPath.empty() ? "cold-run" : "warm-cache";
spdlog::info("[Bench] Finalizing {} vector index (vectors={} persisted_nodes={} "
"persisted_meta={})",
modeLabel, vectorRows, persisted.nodeRows, persisted.metaRows);
const auto start = std::chrono::steady_clock::now();
const bool prepared = vectorDb->prepareSearchIndex();
const auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start)
.count();
setupTimings.vectorIndexPrepared = prepared;
setupTimings.vectorIndexPrepareMs = elapsedMs;
if (!prepared) {
spdlog::warn("[Bench] Vector index finalize failed after {} ms: {}", elapsedMs,
vectorDb->getLastError());
return false;
}
preparedThisRun = true;
const auto persistStart = std::chrono::steady_clock::now();
const bool saved = vectorDb->persistIndex();
setupTimings.vectorIndexPersistMs =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - persistStart)
.count();
setupTimings.vectorIndexPersisted = saved;
if (!saved) {
spdlog::warn("[Bench] Vector index persist failed after {} ms: {}",
setupTimings.vectorIndexPersistMs, vectorDb->getLastError());
return false;
}
persisted = vectorIndexDataDir.empty()
? PersistedHnswState{}
: inspectPersistedHnswState(vectorIndexDataDir);
const bool backendReusableAfterPersist = probeBackendReusable();
if (yams::bench::benchmarkSearchIndexReusable(benchmarkEngine,
backendReusableAfterPersist)) {
spdlog::info("[Bench] Vector index finalized in {} ms "
"(persisted_nodes={} persisted_meta={})",
elapsedMs, persisted.nodeRows, persisted.metaRows);
} else if (benchmarkEngine == yams::vector::VectorSearchEngine::SimeonPqAdc) {
spdlog::info("[Bench] Vector index finalized in {} ms for {} "
"(persisted PQ rows not required for this cold-run process)",
elapsedMs, yams::vector::vectorSearchEngineName(benchmarkEngine));
} else if (benchmarkEngine == yams::vector::VectorSearchEngine::Vec0L2) {
spdlog::info("[Bench] Vec0 index finalized in {} ms and is query-ready for "
"this process (restart persistence unavailable)",
elapsedMs);
} else {
spdlog::info("[Bench] Exact-scan engine query-ready after {} ms; no persisted "
"search index is required",
elapsedMs);
}
}
bool reusable =
yams::bench::benchmarkSearchIndexReusable(benchmarkEngine, probeBackendReusable());
bool ready = yams::bench::benchmarkSearchIndexQueryReady(benchmarkEngine, reusable,
preparedThisRun);
benchmarkVectorIndexReusableAfter = reusable;
setupTimings.vectorIndexReusableAfter = reusable;
setupTimings.vectorQueryReadyAfter = ready;
updateVectorIndexReadiness(ready);
int readyTimeoutSec = 60;
if (const char* env = std::getenv("YAMS_BENCH_VECTOR_INDEX_READY_TIMEOUT")) {
readyTimeoutSec = std::max(0, std::stoi(env));
}
const auto readyDeadline =
std::chrono::steady_clock::now() + std::chrono::seconds(readyTimeoutSec);
while (!ready && std::chrono::steady_clock::now() < readyDeadline) {
if (!vectorIndexDataDir.empty()) {
persisted = inspectPersistedHnswState(vectorIndexDataDir);
reusable = yams::bench::benchmarkSearchIndexReusable(benchmarkEngine,
probeBackendReusable());
}
ready = yams::bench::benchmarkSearchIndexQueryReady(benchmarkEngine, reusable,
preparedThisRun);
if (!ready) {
std::this_thread::sleep_for(500ms);
}
}
benchmarkVectorIndexReusableAfter = reusable;
setupTimings.vectorIndexReusableAfter = reusable;
setupTimings.vectorQueryReadyAfter = ready;
updateVectorIndexReadiness(ready);
return ready;
};
if (!ensureVectorIndexReady()) {
throw std::runtime_error("Vector index readiness not reached before benchmark queries; "
"benchmark would mix brute-force fallback with ANN timing.");
}
if (!warmDataDirPath.empty()) {
auto finalCacheMetadata =
warmCacheMetadata.has_value()
? preferStrongerBenchCacheMetadata(expectedCacheMetadata, warmCacheMetadata)
: expectedCacheMetadata;
auto finalStatusForCache = benchRunSync(client->status(true), 5s);
if (finalStatusForCache) {
finalCacheMetadata =
currentBenchCacheMetadata(finalCacheMetadata, finalStatusForCache.value(),
warmDataDirPath, benchmarkVectorIndexReusableAfter);
}
finalCacheMetadata =
preferStrongerBenchCacheMetadata(finalCacheMetadata, warmCacheMetadata);
if (!expectedCacheMetadata.datasetPath.empty() &&
finalCacheMetadata.datasetPath.empty()) {
finalCacheMetadata.datasetPath = expectedCacheMetadata.datasetPath;
}
const auto metadataWrite = writeBenchCacheMetadata(warmDataDirPath, finalCacheMetadata);
if (!metadataWrite) {
spdlog::warn("[Bench] Failed to write warm cache metadata for {}: {}",
warmDataDirPath.string(), metadataWrite.error().message);
} else {
spdlog::info(
"[Bench] Warm cache metadata written to {} (status={}, embedded_docs={}, "
"vectors={})",
(warmDataDirPath / "retrieval_bench_cache.json").string(),
finalCacheMetadata.status, finalCacheMetadata.embeddedDocs,
finalCacheMetadata.vectorCount);
}
}
// Wait for search engine to be ready (critical for hybrid search!)
// Without this, all hybrid searches fall back to keyword-only
spdlog::info("Waiting for hybrid/vector search readiness...");
const auto searchEngineDeadline = std::chrono::steady_clock::now() + 60s;
bool searchEngineReady = false;
while (std::chrono::steady_clock::now() < searchEngineDeadline) {
auto statusCheck = benchRunSync(client->status(true), 5s);
if (statusCheck) {
const auto& readiness = statusCheck.value().readinessStates;
bool hybridReady = false;
if (auto it = readiness.find("search_engine_hybrid_usable");
it != readiness.end()) {
hybridReady = it->second;
} else {
const bool lexicalReady = [&]() {
if (auto it = readiness.find("search_engine_lexical");
it != readiness.end()) {
return it->second;
}
if (auto it = readiness.find("search_engine"); it != readiness.end()) {
return it->second;
}
return false;
}();
const bool vectorReady = [&]() {
if (auto it = readiness.find("search_engine_vector_usable");
it != readiness.end()) {
return it->second;
}
if (auto it = readiness.find("vector_db_ready"); it != readiness.end()) {
return it->second;
}
if (auto it = readiness.find("vector_db"); it != readiness.end()) {
return it->second;
}
return statusCheck.value().vectorDbReady;
}();
hybridReady = lexicalReady && vectorReady;
}
if (hybridReady) {
searchEngineReady = true;
spdlog::info("Hybrid search is ready (lexical + vector usable)");
break;
}
}
std::this_thread::sleep_for(500ms);
}
if (!searchEngineReady) {
spdlog::error(
"Hybrid/vector search not ready after 60s - hybrid searches will fall back to "
"keyword-only!");
spdlog::error("This is likely due to vector publication not completing.");
}
// Wait for Simeon lexical enhancement and concept mining to complete.
// The async build thread can still be running after the search engine reports
// ready, and concept mining can take additional wall-clock time.
if (!vectorsDisabled) {
const bool waitForConcepts =
std::getenv("YAMS_SEARCH_WAIT_FOR_CONCEPTS") &&
std::string(std::getenv("YAMS_SEARCH_WAIT_FOR_CONCEPTS")) != "0";
if (waitForConcepts) {
const auto lexicalReadyDeadline = std::chrono::steady_clock::now() + 120s;
bool lexicalReady = false;
spdlog::info("Waiting for Simeon lexical enhancement readiness...");
while (std::chrono::steady_clock::now() < lexicalReadyDeadline) {
auto statusCheck = benchRunSync(client->status(true), 5s);
if (statusCheck) {
const auto& rc = statusCheck.value().requestCounts;
const auto get = [&](const std::string& key) -> uint64_t {
auto it = rc.find(key);
return (it == rc.end()) ? 0ULL : it->second;
};
const bool configured =
get("status_search_engine_lexical_enhancement_configured") > 0;
const bool ready =
get("status_search_engine_lexical_enhancement_ready") > 0;
const bool building =
get("status_search_engine_lexical_enhancement_building") > 0;
const uint64_t docCount =
get("status_search_engine_lexical_enhancement_doc_count");
const uint64_t conceptCount =
get("status_search_engine_lexical_enhancement_concept_count");
const bool conceptMiningEnabled =
get("status_search_engine_lexical_enhancement_concept_mining_enabled") >
0;
if (!configured) {
spdlog::info("Simeon lexical enhancement not configured; skipping "
"lexical readiness wait");
lexicalReady = true;
break;
}
if (ready && !building && docCount >= static_cast<uint64_t>(corpusSize)) {
if (conceptMiningEnabled && corpusSize >= 100 && conceptCount == 0) {
spdlog::info("Simeon lexical ready (docs={}) but concept mining "
"still pending; waiting...",
docCount);
} else {
spdlog::info("Simeon lexical enhancement ready: configured={} "
"ready={} building={} doc_count={} concept_count={} "
"concept_mining_enabled={}",
configured, ready, building, docCount, conceptCount,
conceptMiningEnabled);
lexicalReady = true;
break;
}
} else {
spdlog::info("Simeon lexical enhancement not yet ready: "
"configured={} ready={} building={} doc_count={} "
"concept_count={}",
configured, ready, building, docCount, conceptCount);
}
}
std::this_thread::sleep_for(500ms);
}
if (!lexicalReady) {
spdlog::error("Simeon lexical enhancement not ready after 120s");
}
}
}
if (coldIngestStartedAt.has_value()) {
setupTimings.searchabilityReadyMs = elapsedMsSince(*coldIngestStartedAt);
}
auto effectiveKgReadinessPolicy = kgReadinessPolicy;
if (kgReadinessPolicy != yams::search::BenchmarkKgReadinessPolicy::Skip) {
auto statusForKgPolicy = benchRunSync(client->status(true), 5s);
if (statusForKgPolicy) {
bool tunedGraphRerank = graphRerankRequested;
if (auto it =
statusForKgPolicy.value().searchTuningParams.find("enable_graph_rerank");
it != statusForKgPolicy.value().searchTuningParams.end()) {
tunedGraphRerank = it->second > 0.5f;
}
effectiveKgReadinessPolicy = yams::search::refineBenchmarkKgReadinessPolicy(
kgReadinessPolicy, explicitRequireKgReady, tunedGraphRerank);
if (effectiveKgReadinessPolicy != kgReadinessPolicy) {
spdlog::info("[Bench] Refined KG readiness policy to {} after search tuning "
"(state='{}', enable_graph_rerank={})",
yams::search::benchmarkKgReadinessPolicyToString(
effectiveKgReadinessPolicy),
statusForKgPolicy.value().searchTuningState,
tunedGraphRerank ? "true" : "false");
}
} else {
spdlog::warn("[Bench] Unable to inspect tuned graph rerank before KG wait: {}",
statusForKgPolicy.error().message);
}
}
if (effectiveKgReadinessPolicy != yams::search::BenchmarkKgReadinessPolicy::Skip) {
int kgReadyTimeoutSec = 180;
if (const char* env = std::getenv("YAMS_BENCH_KG_READY_TIMEOUT")) {
kgReadyTimeoutSec = std::max(0, std::stoi(env));
}
spdlog::info("Waiting for KG readiness before query evaluation (timeout={}s)...",
kgReadyTimeoutSec);
const auto kgDeadline =
std::chrono::steady_clock::now() + std::chrono::seconds(kgReadyTimeoutSec);
int stickyInflightGraceSec = 20;
if (const char* env = std::getenv("YAMS_BENCH_KG_STICKY_INFLIGHT_GRACE_SEC")) {
stickyInflightGraceSec = std::max(0, std::stoi(env));
}
const auto stickyInflightGrace = std::chrono::seconds(stickyInflightGraceSec);
int stableReadyChecks = 0;
bool kgReady = false;
bool acceptedStickyInflight = false;
bool acceptedWarmReuseIdle = false;
bool lastHasKg = false;
uint32_t lastQueueDepth = 0;
uint64_t lastPostQueued = 0;
uint64_t lastPostInflight = 0;
uint64_t lastKgInflight = 0;
uint64_t lastKgConsumed = 0;
uint64_t lastSymbolInflight = 0;
uint64_t lastEntityInflight = 0;
uint64_t lastTitleInflight = 0;
uint64_t lastTitleQueueDepth = 0;
uint64_t lastExtractionInflight = 0;
bool stickyInflightActive = false;
uint64_t stickyInflightValue = 0;
auto stickyInflightSince = std::chrono::steady_clock::time_point{};
while (std::chrono::steady_clock::now() < kgDeadline) {
const auto now = std::chrono::steady_clock::now();
auto statusCheck = benchRunSync(client->status(true), 5s);
auto statsCheck =
benchRunSync(client->getStats(yams::daemon::GetStatsRequest{}), 10s);
bool queuesDrained = false;
if (statusCheck) {
const auto& st = statusCheck.value();
const auto getCount = [&st](const std::string& key) -> uint64_t {
auto it = st.requestCounts.find(key);
return (it == st.requestCounts.end()) ? 0ULL : it->second;
};
lastQueueDepth = st.postIngestQueueDepth;
lastPostQueued = getCount("post_ingest_queued");
lastPostInflight = getCount("post_ingest_inflight");
lastExtractionInflight = getCount("extraction_inflight");
lastKgInflight = getCount("kg_inflight");
lastKgConsumed = getCount("kg_consumed");
lastSymbolInflight = getCount("symbol_inflight");
lastEntityInflight = getCount("entity_inflight");
lastTitleInflight = getCount("title_inflight");
lastTitleQueueDepth = getCount("title_queue_depth");
queuesDrained =
(lastQueueDepth == 0 && lastPostQueued == 0 && lastPostInflight == 0 &&
lastExtractionInflight == 0 && lastKgInflight == 0 &&
lastSymbolInflight == 0 && lastEntityInflight == 0 &&
lastTitleInflight == 0 && lastTitleQueueDepth == 0);
}
bool hasKg = false;
uint64_t docEntitiesInserted = 0;
if (statsCheck) {
const auto& stats = statsCheck.value();
if (auto it = stats.additionalStats.find("corpus_stats");
it != stats.additionalStats.end() && !it->second.empty()) {
try {
auto corpusStats = json::parse(it->second);
if (corpusStats.contains("classification") &&
corpusStats["classification"].is_object()) {
hasKg = corpusStats["classification"].value("has_kg", false);
}
} catch (const json::exception&) {
}
}
if (auto it = stats.additionalStats.find("kg_write_doc_entities_inserted");
it != stats.additionalStats.end() && !it->second.empty()) {
docEntitiesInserted = static_cast<uint64_t>(std::stoull(it->second));
}
}
lastHasKg = hasKg;
const bool kgSignalReady =
hasKg || (lastKgConsumed > 0) || (docEntitiesInserted > 0);
const bool queueIdle = (lastQueueDepth == 0 && lastPostQueued == 0);
const bool stageInflightIdle =
(lastExtractionInflight == 0 && lastKgInflight == 0 &&
lastSymbolInflight == 0 && lastEntityInflight == 0 && lastTitleInflight == 0 &&
lastTitleQueueDepth == 0);
bool stickyInflightReady = false;
if (kgSignalReady && queueIdle && stageInflightIdle && lastPostInflight > 0) {
if (!stickyInflightActive || stickyInflightValue != lastPostInflight) {
stickyInflightActive = true;
stickyInflightValue = lastPostInflight;
stickyInflightSince = now;
} else if (now - stickyInflightSince >= stickyInflightGrace) {
stickyInflightReady = true;
}
} else {
stickyInflightActive = false;
stickyInflightValue = 0;
}
const bool reusedWarmCacheWithoutIngest =
usingExternalBenchDataDir && cacheHasIndexedCorpus && cacheHasFullEmbeddings &&
cacheHasReusableVectorIndex;
const bool warmReuseIdleReady =
reusedWarmCacheWithoutIngest && queuesDrained && lastPostInflight == 0;
if (yams::search::benchmarkKgReadinessSatisfied(effectiveKgReadinessPolicy,
queuesDrained, kgSignalReady)) {
stableReadyChecks++;
if (stableReadyChecks >= 4) {
kgReady = true;
break;
}
} else if (warmReuseIdleReady) {
kgReady = true;
acceptedWarmReuseIdle = true;
break;
} else if (stickyInflightReady) {
kgReady = true;
acceptedStickyInflight = true;
break;
} else {
stableReadyChecks = 0;
}
std::this_thread::sleep_for(500ms);
}
if (!kgReady) {
throw std::runtime_error(
"KG not ready before benchmark queries (has_kg=" +
std::string(lastHasKg ? "true" : "false") + ", policy=" +
std::string(yams::search::benchmarkKgReadinessPolicyToString(
effectiveKgReadinessPolicy)) +
", kg_consumed=" + std::to_string(lastKgConsumed) +
", post_ingest_queue_depth=" + std::to_string(lastQueueDepth) +
", post_ingest_queued=" + std::to_string(lastPostQueued) +
", post_ingest_inflight=" + std::to_string(lastPostInflight) +
", extraction_inflight=" + std::to_string(lastExtractionInflight) +
", kg_inflight=" + std::to_string(lastKgInflight) +
", symbol_inflight=" + std::to_string(lastSymbolInflight) +
", entity_inflight=" + std::to_string(lastEntityInflight) +
", title_inflight=" + std::to_string(lastTitleInflight) +
", title_queue_depth=" + std::to_string(lastTitleQueueDepth) +
"). Increase YAMS_BENCH_KG_READY_TIMEOUT or reduce ingestion load.");
}
if (effectiveKgReadinessPolicy ==
yams::search::BenchmarkKgReadinessPolicy::AcceptDrainedWithoutSignal &&
!lastHasKg && lastKgConsumed == 0) {
spdlog::warn(
"KG readiness satisfied with drained queues under relaxed synthetic policy; "
"no explicit KG signal was observed. Graph signals may be weak.");
} else if (!lastHasKg) {
if (acceptedWarmReuseIdle) {
spdlog::warn(
"KG readiness accepted for reused warm cache with drained queues and no "
"active KG work, but corpus_stats.has_kg=false and kg_consumed={} in this "
"process. Graph signals may still be weak.",
lastKgConsumed);
} else {
spdlog::warn(
"KG readiness satisfied via kg_consumed={}, but corpus_stats.has_kg=false "
"(low symbol_density). Graph signals may still be weak.",
lastKgConsumed);
}
} else if (acceptedStickyInflight) {
spdlog::warn(
"KG readiness accepted with sticky post_ingest_inflight={} after {}s grace "
"(queues drained + stage inflight idle + corpus_stats.has_kg=true).",
lastPostInflight, stickyInflightGraceSec);
} else if (acceptedWarmReuseIdle) {
spdlog::info(
"KG readiness accepted for reused warm cache with drained queues and no "
"active KG work");
} else {
spdlog::info("KG readiness satisfied (queues drained + corpus_stats.has_kg=true)");
}
} else if (requireKgReady) {
spdlog::info(
"Skipping KG readiness wait because the effective tuned search policy disables "
"graph rerank.");
}
yams::search::BenchmarkDaemonGraphState daemonGraphState;
bool daemonGraphReady = false;
bool daemonGraphCanonicalized = false;
std::size_t daemonGraphCanonicalEdgesGenerated = 0;
std::string daemonGraphCanonicalTopologySnapshot;
std::string daemonGraphCanonicalTopologyFingerprint;
if (g_requireDaemonNativeGraph) {
auto graphState =
waitForDaemonNativeGraph(*client, static_cast<std::uint64_t>(corpusSize));
if (!graphState) {
throw std::runtime_error(graphState.error().message);
}
daemonGraphState = std::move(graphState.value());
auto* daemon = harness ? harness->daemon() : nullptr;
auto* serviceManager = daemon ? daemon->getServiceManager() : nullptr;
if (!serviceManager) {
throw std::runtime_error(
"Daemon-native graph canonicalization requires ServiceManager");
}
auto semanticRebuild = serviceManager->rebuildSemanticNeighborGraph(
"benchmark_daemon_native_graph_canonicalization");
if (!semanticRebuild) {
throw std::runtime_error("Failed to canonicalize daemon semantic graph: " +
semanticRebuild.error().message);
}
daemonGraphCanonicalEdgesGenerated = semanticRebuild.value();
auto canonicalGraphState =
waitForDaemonNativeGraph(*client, static_cast<std::uint64_t>(corpusSize));
if (!canonicalGraphState) {
throw std::runtime_error(canonicalGraphState.error().message);
}
daemonGraphState = std::move(canonicalGraphState.value());
std::string topologyAlgorithm = "connected";
if (const char* raw = std::getenv("YAMS_BENCH_TOPOLOGY_ENGINE"); raw && *raw) {
topologyAlgorithm = raw;
}
auto topologyRebuild =
rebuildCanonicalDaemonTopology(*serviceManager, topologyAlgorithm);
if (!topologyRebuild) {
throw std::runtime_error("Failed to canonicalize daemon topology artifacts: " +
topologyRebuild.error().message);
}
daemonGraphCanonicalTopologySnapshot = topologyRebuild.value().snapshotId;
auto topologyFingerprint = loadTopologyRoutingConstructionFingerprint(
*serviceManager, daemonGraphCanonicalTopologySnapshot);
if (!topologyFingerprint) {
throw std::runtime_error(
"Failed to fingerprint canonical daemon topology artifacts: " +
topologyFingerprint.error().message);
}
daemonGraphCanonicalTopologyFingerprint = std::move(topologyFingerprint.value());
daemonGraphCanonicalized = true;
daemonGraphReady = true;
}
if (coldIngestStartedAt.has_value()) {
setupTimings.enrichmentReadyMs = elapsedMsSince(*coldIngestStartedAt);
}
// Verify document count using status metrics (avoids degraded search false negatives)
uint64_t indexedDocCount = 0;
auto statusResult = benchRunSync(client->status(true), 5s);
if (warmCacheMetadata && warmCacheMetadata->status == "primed") {
indexedDocCount = static_cast<uint64_t>(warmCacheMetadata->expectedDocs);
} else if (statusResult) {
if (auto it = statusResult.value().requestCounts.find("documents_indexed");
it != statusResult.value().requestCounts.end()) {
indexedDocCount = it->second;
} else if (auto it = statusResult.value().requestCounts.find("documents_total");
it != statusResult.value().requestCounts.end()) {
indexedDocCount = it->second;
}
}
if (indexedDocCount == 0) {
yams::daemon::SearchRequest testReq;
testReq.query = "test";
testReq.searchType = "hybrid";
testReq.limit = 1000;
const auto queryTimeout = configuredBenchQueryTimeout("hybrid");
testReq.timeout = queryTimeout;
auto waitBudget = queryTimeout + std::chrono::seconds(10);
if (waitBudget < std::chrono::seconds(10)) {
waitBudget = std::chrono::seconds(10);
}
auto testSearch =
[&]() -> boost::asio::awaitable<Result<yams::daemon::SearchResponse>> {
if (benchUseStreamingSearch()) {
co_return co_await client->search(testReq);
}
co_return co_await client->unarySearch(testReq);
};
auto testResult = benchRunSync(testSearch(), waitBudget);
indexedDocCount = testResult ? testResult.value().results.size() : 0;
}
spdlog::info("Verified indexed documents: {} (expected: {})", indexedDocCount, corpusSize);
if (indexedDocCount == 0) {
spdlog::error("NO DOCUMENTS IN INDEX! Ingestion failed completely.");
throw std::runtime_error("No documents indexed - benchmark cannot proceed");
}
seedSyntheticCommunityEdges();
const bool reuseSeededTopologyInputs =
warmDataDir && envTruthy(std::getenv("YAMS_BENCH_REUSE_SEEDED_TOPOLOGY_INPUTS"));
const bool seededBenchmarkTopology =
reuseSeededTopologyInputs || seedBenchmarkSemanticNeighbors();
if (reuseSeededTopologyInputs) {
spdlog::info("Reusing immutable semantic-neighbor topology inputs from warm cache");
}
if (benchmarkSemanticNeighborSeedingEnabled()) {
if (!seededBenchmarkTopology) {
throw std::runtime_error(
"Benchmark topology source seeding did not produce semantic_neighbor edges");
}
auto* daemon = harness ? harness->daemon() : nullptr;
auto* serviceManager = daemon ? daemon->getServiceManager() : nullptr;
if (!serviceManager) {
throw std::runtime_error("Topology source benchmark requires ServiceManager");
}
std::string topologyEngine = "connected";
if (const char* raw = std::getenv("YAMS_BENCH_TOPOLOGY_ENGINE"); raw && *raw) {
topologyEngine = raw;
}
auto& topologyManager = serviceManager->getTopologyManager();
const auto rebuildDeadline = std::chrono::steady_clock::now() + 60s;
std::optional<yams::daemon::TopologyManager::RebuildStats> rebuildStats;
do {
if (topologyManager.isRebuildInProgress()) {
std::this_thread::sleep_for(50ms);
continue;
}
auto attempt = topologyManager.rebuildArtifacts("benchmark_topology_source_seed",
false, {}, topologyEngine);
if (!attempt) {
throw std::runtime_error("Failed to rebuild topology after benchmark source "
"seeding: " +
attempt.error().message);
}
if (!attempt.value().skipped) {
rebuildStats = std::move(attempt.value());
break;
}
std::this_thread::sleep_for(50ms);
} while (std::chrono::steady_clock::now() < rebuildDeadline);
if (!rebuildStats.has_value()) {
throw std::runtime_error(
"Timed out waiting to publish benchmark topology snapshot");
}
if (!rebuildStats->stored) {
throw std::runtime_error(
"Topology source benchmark rebuild did not publish a stored snapshot");
}
spdlog::info("Rebuilt topology after source seeding: source={} clusters={} "
"memberships={} snapshot={}",
std::getenv("YAMS_BENCH_TOPOLOGY_SOURCE")
? std::getenv("YAMS_BENCH_TOPOLOGY_SOURCE")
: "vector",
rebuildStats->clustersBuilt, rebuildStats->membershipsBuilt,
rebuildStats->snapshotId);
auto exportResult = exportTopologyClusters(*serviceManager, rebuildStats->snapshotId);
if (!exportResult) {
throw std::runtime_error("Failed to export topology cluster composition: " +
exportResult.error().message);
}
}
// Post-ingest status/stats snapshot + sanity searches.
// Goal: distinguish "no docs" vs "docs but query returns empty".
{
// Log StatusResponse (it already powers our ingestion waits).
auto statusRes = benchRunSync(client->status(true), 5s);
if (statusRes) {
const auto& st = statusRes.value();
uint64_t documentsTotal = 0;
uint64_t documentsEmbedded = 0;
uint64_t vectorCount = 0;
uint64_t preparedDocsQueued = 0;
uint64_t preparedChunksQueued = 0;
uint64_t titleInflight = 0;
uint64_t titleQueueDepth = 0;
uint64_t titleQueued = 0;
uint64_t titleDropped = 0;
uint64_t titleConsumed = 0;
if (auto it = st.requestCounts.find("documents_total");
it != st.requestCounts.end()) {
documentsTotal = it->second;
}
if (auto it = st.requestCounts.find("documents_embedded");
it != st.requestCounts.end()) {
documentsEmbedded = it->second;
}
if (auto it = st.requestCounts.find("vector_count"); it != st.requestCounts.end()) {
vectorCount = it->second;
}
if (auto it = st.requestCounts.find("bus_embed_prepared_docs_queued");
it != st.requestCounts.end()) {
preparedDocsQueued = it->second;
}
if (auto it = st.requestCounts.find("bus_embed_prepared_chunks_queued");
it != st.requestCounts.end()) {
preparedChunksQueued = it->second;
}
if (auto it = st.requestCounts.find("title_inflight");
it != st.requestCounts.end()) {
titleInflight = it->second;
}
if (auto it = st.requestCounts.find("title_queue_depth");
it != st.requestCounts.end()) {
titleQueueDepth = it->second;
}
if (auto it = st.requestCounts.find("title_queued"); it != st.requestCounts.end()) {
titleQueued = it->second;
}
if (auto it = st.requestCounts.find("title_dropped");
it != st.requestCounts.end()) {
titleDropped = it->second;
}
if (auto it = st.requestCounts.find("title_consumed");
it != st.requestCounts.end()) {
titleConsumed = it->second;
}
// Log search tuning state (epic yams-7ez4)
if (!st.searchTuningState.empty()) {
spdlog::info("Search tuning state: {} ({})", st.searchTuningState,
st.searchTuningReason);
spdlog::info("Search tuning params:");
for (const auto& [k, v] : st.searchTuningParams) {
spdlog::info(" {}: {:.4f}", k, v);
}
}
DebugLogEntry statusEntry;
statusEntry.query = "__post_ingest_status__";
statusEntry.returnedPaths.push_back("documents_total=" +
std::to_string(documentsTotal));
statusEntry.returnedPaths.push_back("documents_embedded=" +
std::to_string(documentsEmbedded));
statusEntry.returnedPaths.push_back("vector_count=" + std::to_string(vectorCount));
statusEntry.returnedPaths.push_back("bus_embed_prepared_docs_queued=" +
std::to_string(preparedDocsQueued));
statusEntry.returnedPaths.push_back("bus_embed_prepared_chunks_queued=" +
std::to_string(preparedChunksQueued));
statusEntry.returnedPaths.push_back("title_inflight=" +
std::to_string(titleInflight));
statusEntry.returnedPaths.push_back("title_queue_depth=" +
std::to_string(titleQueueDepth));
statusEntry.returnedPaths.push_back("title_queued=" + std::to_string(titleQueued));
statusEntry.returnedPaths.push_back("title_dropped=" +
std::to_string(titleDropped));
statusEntry.returnedPaths.push_back("title_consumed=" +
std::to_string(titleConsumed));
statusEntry.returnedPaths.push_back("post_ingest_queue_depth=" +
std::to_string(st.postIngestQueueDepth));
statusEntry.returnedPaths.push_back(std::string("embedding_available=") +
(st.embeddingAvailable ? "true" : "false"));
bool vectorDbReady = st.vectorDbReady;
if (auto it = st.readinessStates.find("vector_db");
it != st.readinessStates.end()) {
vectorDbReady = it->second;
}
statusEntry.returnedPaths.push_back(std::string("vector_db_ready=") +
(vectorDbReady ? "true" : "false"));
statusEntry.returnedPaths.push_back("vector_db_dim=" +
std::to_string(st.vectorDbDim));
statusEntry.returnedPaths.push_back("embedding_backend=" + st.embeddingBackend);
statusEntry.returnedPaths.push_back("embedding_model=" + st.embeddingModel);
// Search tuning state (epic yams-7ez4)
statusEntry.returnedPaths.push_back("search_tuning_state=" + st.searchTuningState);
statusEntry.returnedPaths.push_back("search_tuning_reason=" +
st.searchTuningReason);
double tunedKgWeight = 0.0;
bool tunedGraphRerank = graphRerankRequested;
if (auto it = st.searchTuningParams.find("kg_weight");
it != st.searchTuningParams.end()) {
tunedKgWeight = static_cast<double>(it->second);
}
if (auto it = st.searchTuningParams.find("enable_graph_rerank");
it != st.searchTuningParams.end()) {
tunedGraphRerank = it->second > 0.5;
}
spdlog::info("[Bench] Effective graph rerank: env={} tuned={} kg_weight={:.4f}",
graphRerankRequested ? "on" : "off", tunedGraphRerank ? "on" : "off",
tunedKgWeight);
for (const auto& [k, v] : st.searchTuningParams) {
statusEntry.returnedPaths.push_back("tuning_" + k + "=" + std::to_string(v));
}
debugLogWriteJsonLine(statusEntry);
} else {
spdlog::warn("Status failed (post-ingest): {}", statusRes.error().message);
}
// Log GetStatsResponse (extra counters);
// we also emit structured JSON (additional_stats) for easier parsing.
yams::daemon::GetStatsRequest statsReq;
auto statsRes = benchRunSync(client->getStats(statsReq), 10s);
if (statsRes) {
const auto& st = statsRes.value();
spdlog::info("GetStats: totalDocuments={} indexedDocuments={} vectorIndexSize={} "
"additionalStats.size={}",
st.totalDocuments, st.indexedDocuments, st.vectorIndexSize,
st.additionalStats.size());
DebugLogEntry statsEntry;
statsEntry.query = "__post_ingest_stats__";
statsEntry.returnedPaths.push_back("totalDocuments=" +
std::to_string(st.totalDocuments));
statsEntry.returnedPaths.push_back("indexedDocuments=" +
std::to_string(st.indexedDocuments));
statsEntry.returnedPaths.push_back("vectorIndexSize=" +
std::to_string(st.vectorIndexSize));
const auto appendIfPresent = [&](std::string_view key) {
auto it = st.additionalStats.find(std::string(key));
if (it != st.additionalStats.end()) {
statsEntry.returnedPaths.push_back(std::string(key) + "=" + it->second);
}
};
appendIfPresent("kg_doc_entities_total");
appendIfPresent("post_title_nl_docs_processed");
appendIfPresent("post_title_nl_docs_with_entities");
appendIfPresent("post_title_nl_entities_extracted");
appendIfPresent("post_deferred_doc_entities_queued");
appendIfPresent("post_deferred_doc_entity_queue_failures");
appendIfPresent("kg_write_doc_entities_inserted");
appendIfPresent("kg_write_deferred_doc_entities_skipped");
statsEntry.extraFields = {
{"additional_stats", st.additionalStats},
{"total_documents", st.totalDocuments},
{"indexed_documents", st.indexedDocuments},
{"vector_index_size", st.vectorIndexSize},
};
for (const auto& [k, v] : st.additionalStats) {
statsEntry.returnedPaths.push_back(k + "=" + v);
}
debugLogWriteJsonLine(statsEntry);
} else {
spdlog::warn("GetStats failed: {}", statsRes.error().message);
}
auto doSanitySearch = [&](std::string label, std::string query, std::string searchType,
bool symbolRank) {
yams::cli::search_runner::DaemonSearchOptions opts;
opts.query = std::move(query);
opts.searchType = std::move(searchType);
opts.limit = 25;
const auto queryTimeout = configuredBenchQueryTimeout(opts.searchType);
opts.timeout = queryTimeout;
opts.symbolRank = symbolRank;
opts.allowFuzzyRetry = false;
opts.allowLiteralTextRetry = false;
DebugLogEntry sanityEntry;
sanityEntry.query = std::move(label);
auto waitBudget =
std::chrono::duration_cast<std::chrono::milliseconds>(opts.timeout) +
std::chrono::seconds(10);
if (waitBudget < std::chrono::seconds(10)) {
waitBudget = std::chrono::seconds(10);
}
auto run = benchRunSync(yams::cli::search_runner::daemon_search(
*client, opts, benchUseStreamingSearch()),
waitBudget);
if (!run) {
sanityEntry.returnedPaths.push_back("error=" + run.error().message);
debugLogWriteJsonLine(sanityEntry);
return;
}
sanityEntry.attempts = run.value().attempts;
sanityEntry.usedStreaming = run.value().usedStreaming;
sanityEntry.usedFuzzyRetry = run.value().usedFuzzyRetry;
sanityEntry.usedLiteralTextRetry = run.value().usedLiteralTextRetry;
const auto& results = run.value().response.results;
for (size_t i = 0; i < std::min<size_t>(results.size(), 10); ++i) {
sanityEntry.returnedPaths.push_back(results[i].path);
}
sanityEntry.returnedDocIds.push_back("result_count=" +
std::to_string(results.size()));
debugLogWriteJsonLine(sanityEntry);
};
// Keyword search should return something if FTS is populated.
doSanitySearch("__sanity_keyword_the__", "the", "keyword", false);
// Hybrid search without symbol rank to avoid symbol-only decisions.
doSanitySearch("__sanity_hybrid_the__", "the", "hybrid", false);
// If BEIR corpus is used, easily-searchable token is doc id.
if (useBEIR && beirCorpus && !beirCorpus->dataset.documents.empty()) {
const auto& firstDocId = beirCorpus->dataset.documents.begin()->first;
doSanitySearch("__sanity_keyword_docid__", firstDocId, "keyword", false);
}
}
if (useBEIR) {
queries = beirCorpus->generateTestQueries();
} else {
queries = corpus->generateQueries(numQueries);
}
spdlog::info("Generated {} test queries", queries.size());
setupTimings.setupTotalMs = elapsedMsSince(setupStartedAt);
if (g_debugOut) {
DebugLogEntry timingEntry;
timingEntry.searchType = "benchmark_setup";
timingEntry.extraFields = {
{"event", "benchmark_setup_metrics"},
{"ingestion",
{{"cold_performed", setupTimings.coldIngestPerformed},
{"admission_ms", setupTimings.admissionMs},
{"storage_ready_ms", setupTimings.storageReadyMs},
{"pipeline_drain_ms", setupTimings.pipelineDrainMs},
{"searchability_ready_ms", setupTimings.searchabilityReadyMs},
{"enrichment_ready_ms", setupTimings.enrichmentReadyMs},
{"measurement_n", setupTimings.coldIngestPerformed ? 1 : 0}}},
{"vector_index",
{{"prepared", setupTimings.vectorIndexPrepared},
{"persisted", setupTimings.vectorIndexPersisted},
{"reusable_before", setupTimings.vectorIndexReusableBefore},
{"reusable_after", setupTimings.vectorIndexReusableAfter},
{"query_ready_after", setupTimings.vectorQueryReadyAfter},
{"prepare_ms", setupTimings.vectorIndexPrepareMs},
{"persist_ms", setupTimings.vectorIndexPersistMs},
{"reusable_probe_ms", setupTimings.vectorIndexReusableProbeMs},
{"reusable_probe_count", setupTimings.vectorIndexReusableProbeCount}}},
{"setup_total_ms", setupTimings.setupTotalMs},
{"dataset", datasetName},
{"corpus_size", corpusSize},
{"daemon_graph",
{{"required", g_requireDaemonNativeGraph},
{"ready", daemonGraphReady},
{"source", "post_ingest_queue_embedding_service"},
{"canonicalized", daemonGraphCanonicalized},
{"canonical_edges_generated", daemonGraphCanonicalEdgesGenerated},
{"canonical_topology_snapshot", daemonGraphCanonicalTopologySnapshot},
{"canonical_topology_fingerprint", daemonGraphCanonicalTopologyFingerprint},
{"semantic_documents_processed", daemonGraphState.semanticDocumentsProcessed},
{"semantic_edges_created", daemonGraphState.semanticEdgesCreated},
{"semantic_update_errors", daemonGraphState.semanticUpdateErrors},
{"topology_document_nodes", daemonGraphState.topologyDocumentNodes},
{"topology_semantic_edges", daemonGraphState.topologySemanticEdges},
{"topology_documents_with_neighbors",
daemonGraphState.topologyDocumentsWithNeighbors},
{"topology_isolated_documents", daemonGraphState.topologyIsolatedDocuments},
{"post_ingest_queued", daemonGraphState.postIngestQueued},
{"post_ingest_in_flight", daemonGraphState.postIngestInFlight},
{"embedding_queued", daemonGraphState.embeddingQueued},
{"embedding_in_flight", daemonGraphState.embeddingInFlight},
{"write_queued", daemonGraphState.writeQueued},
{"write_in_flight", daemonGraphState.writeInFlight}}},
};
debugLogWriteJsonLine(timingEntry);
}
}
void teardown() {
client.reset();
harness.reset();
corpus.reset();
g_debugRunContext.reset();
g_debugOut = nullptr;
g_debugFile.reset();
}
};
static std::unique_ptr<BenchFixture> g_fixture;
void SetupFixture() {
if (!g_fixture) {
g_fixture = std::make_unique<BenchFixture>();
g_fixture->setup();
}
}
void CleanupFixture() {
if (g_fixture) {
g_fixture->teardown();
g_fixture.reset();
}
}
static OptimizationRunResult runOptimizationCandidate(const OptimizationCandidate& candidate,
const std::optional<fs::path>& outputFile) {
OptimizationRunResult result;
result.candidate = candidate;
result.runId = makeRunId(candidate.name);
std::vector<EnvSetting> candidateOverrides = candidate.envOverrides;
const char* debugBaseEnv = std::getenv("YAMS_BENCH_DEBUG_FILE");
if (debugBaseEnv && std::strlen(debugBaseEnv) > 0) {
const fs::path basePath(debugBaseEnv);
const fs::path candidateDebugPath =
makeCandidateDebugPath(basePath, candidate.name, result.runId);
result.debugFile = candidateDebugPath.string();
candidateOverrides.push_back({"YAMS_BENCH_DEBUG_FILE", result.debugFile});
const bool hasExplicitTrace = hasOverrideKey(candidateOverrides, "YAMS_SEARCH_STAGE_TRACE");
if (!hasExplicitTrace && std::getenv("YAMS_SEARCH_STAGE_TRACE") == nullptr) {
candidateOverrides.push_back({"YAMS_SEARCH_STAGE_TRACE", "1"});
result.stageTraceEnabled = true;
} else {
result.stageTraceEnabled = envTruthy(std::getenv("YAMS_SEARCH_STAGE_TRACE"));
}
const int traceTopNDefault = parseIntEnvOrDefault("YAMS_BENCH_TRACE_TOP_N", 50, 1, 10000);
const int traceComponentDefault = parseIntEnvOrDefault(
"YAMS_BENCH_TRACE_COMPONENT_TOP_N", std::min(traceTopNDefault, 50), 1, 10000);
const bool hasExplicitTraceTop =
hasOverrideKey(candidateOverrides, "YAMS_SEARCH_STAGE_TRACE_TOP_N");
if (!hasExplicitTraceTop && std::getenv("YAMS_SEARCH_STAGE_TRACE_TOP_N") == nullptr) {
candidateOverrides.push_back(
{"YAMS_SEARCH_STAGE_TRACE_TOP_N", std::to_string(traceTopNDefault)});
}
const bool hasExplicitComponentTop =
hasOverrideKey(candidateOverrides, "YAMS_SEARCH_STAGE_TRACE_COMPONENT_TOP_N");
if (!hasExplicitComponentTop &&
std::getenv("YAMS_SEARCH_STAGE_TRACE_COMPONENT_TOP_N") == nullptr) {
candidateOverrides.push_back(
{"YAMS_SEARCH_STAGE_TRACE_COMPONENT_TOP_N", std::to_string(traceComponentDefault)});
}
} else {
result.stageTraceEnabled = envTruthy(std::getenv("YAMS_SEARCH_STAGE_TRACE"));
}
ScopedEnvOverrides scopedEnv(candidateOverrides);
result.traceTopN = parseIntEnvOrDefault("YAMS_SEARCH_STAGE_TRACE_TOP_N", 0, 0, 10000);
result.traceComponentTopN =
parseIntEnvOrDefault("YAMS_SEARCH_STAGE_TRACE_COMPONENT_TOP_N", 0, 0, 10000);
g_debugRunContext = DebugRunContext{
.runId = result.runId,
.candidate = result.candidate.name,
.dataset = "",
.corpusSize = 0,
.numQueries = 0,
.topK = 0,
.traceTopN = result.traceTopN,
.traceComponentTopN = result.traceComponentTopN,
.stageTraceEnabled = envTruthy(std::getenv("YAMS_SEARCH_STAGE_TRACE")),
.debugFile = result.debugFile,
};
CleanupFixture();
try {
SetupFixture();
if (!g_fixture || !g_fixture->client) {
throw std::runtime_error("Benchmark fixture did not initialize a daemon client");
}
auto status = benchRunSync(g_fixture->client->status(true), 5s);
if (status) {
result.tuningState = status.value().searchTuningState;
result.tuningReason = status.value().searchTuningReason;
}
result.searchEngine =
std::string(yams::vector::vectorSearchEngineName(benchmarkVectorSearchEngine()));
if (g_fixture && g_fixture->harness) {
const auto persisted = inspectPersistedHnswState(g_fixture->harness->dataDir());
result.vectorsDbBytes = persisted.vectorsDbBytes;
result.vectorsWalBytes = persisted.vectorsWalBytes;
result.persistedHnswNodes = persisted.nodeRows;
result.persistedHnswMetaRows = persisted.metaRows;
result.persistedVec0Tables = persisted.vec0Tables;
result.persistedVec0Rows = persisted.vec0Rows;
result.persistedPqCodes = persisted.pqCodeRows;
result.persistedPqMeta = persisted.pqMetaRows;
}
g_debugRunContext->dataset =
g_fixture->useBEIR ? g_fixture->beirDatasetName : g_fixture->datasetName;
g_debugRunContext->corpusSize = g_fixture->corpusSize;
g_debugRunContext->numQueries = static_cast<int>(g_fixture->queries.size());
g_debugRunContext->topK = g_fixture->topK;
g_debugRunContext->traceTopN =
parseIntEnvOrDefault("YAMS_SEARCH_STAGE_TRACE_TOP_N", result.traceTopN, 0, 10000);
g_debugRunContext->traceComponentTopN = parseIntEnvOrDefault(
"YAMS_SEARCH_STAGE_TRACE_COMPONENT_TOP_N", result.traceComponentTopN, 0, 10000);
g_debugRunContext->stageTraceEnabled = envTruthy(std::getenv("YAMS_SEARCH_STAGE_TRACE"));
result.traceTopN = g_debugRunContext->traceTopN;
result.traceComponentTopN = g_debugRunContext->traceComponentTopN;
result.stageTraceEnabled = g_debugRunContext->stageTraceEnabled;
const auto hybridStart = std::chrono::steady_clock::now();
result.hybridMetrics =
evaluateQueries(*g_fixture->client, g_fixture->benchCorpusDir, g_fixture->queries,
g_fixture->topK, "hybrid", &result.hybridDiagnostics);
const auto hybridEnd = std::chrono::steady_clock::now();
result.hybridEvalMs =
std::chrono::duration<double, std::milli>(hybridEnd - hybridStart).count();
const auto keywordStart = std::chrono::steady_clock::now();
result.keywordMetrics =
evaluateQueries(*g_fixture->client, g_fixture->benchCorpusDir, g_fixture->queries,
g_fixture->topK, "keyword", &result.keywordDiagnostics);
const auto keywordEnd = std::chrono::steady_clock::now();
result.keywordEvalMs =
std::chrono::duration<double, std::milli>(keywordEnd - keywordStart).count();
if (result.hybridMetrics.numQueries <= 0) {
throw std::runtime_error("No benchmark queries generated for optimization candidate");
}
const double avgHybridQueryMs =
result.hybridEvalMs / std::max(1, result.hybridMetrics.numQueries);
result.objectiveScore =
computeOptimizationObjective(result.hybridMetrics, result.keywordMetrics,
result.hybridDiagnostics, avgHybridQueryMs);
result.success = true;
} catch (const std::exception& e) {
result.success = false;
result.errorMessage = e.what();
}
g_debugRunContext.reset();
CleanupFixture();
if (outputFile.has_value()) {
appendOptimizationResultJson(*outputFile, result);
}
return result;
}
static int runOptimizationLoop() {
std::vector<OptimizationCandidate> candidates = defaultOptimizationCandidates();
const auto optProfile = parseOptimizationProfile(std::getenv("YAMS_BENCH_OPT_PROFILE"));
const bool hasExplicitCandidateFilter =
std::getenv("YAMS_BENCH_OPT_CANDIDATE") &&
std::strlen(std::getenv("YAMS_BENCH_OPT_CANDIDATE")) > 0;
if (!hasExplicitCandidateFilter) {
std::vector<OptimizationCandidate> filteredByProfile;
filteredByProfile.reserve(candidates.size());
for (const auto& candidate : candidates) {
const bool keep =
optProfile == OptimizationProfile::All ||
(optProfile == OptimizationProfile::EnginePolicy &&
candidate.enginePolicyCandidate) ||
(optProfile == OptimizationProfile::Diagnostics && candidate.diagnosticCandidate);
if (keep) {
filteredByProfile.push_back(candidate);
}
}
if (!filteredByProfile.empty()) {
spdlog::info("[OptLoop] No candidate filter set; using optimization profile '{}' with "
"{} candidates",
optimizationProfileName(optProfile), filteredByProfile.size());
candidates = std::move(filteredByProfile);
}
}
const auto selectedCandidates = parseCandidateFilter(std::getenv("YAMS_BENCH_OPT_CANDIDATE"));
if (!selectedCandidates.empty()) {
std::vector<OptimizationCandidate> filtered;
filtered.reserve(candidates.size());
for (const auto& candidate : candidates) {
if (selectedCandidates.count(candidate.name) > 0) {
filtered.push_back(candidate);
}
}
candidates = std::move(filtered);
if (candidates.empty()) {
std::cerr << "No optimization candidates matched YAMS_BENCH_OPT_CANDIDATE='"
<< std::getenv("YAMS_BENCH_OPT_CANDIDATE") << "'\n";
return 2;
}
}
bool pruneKnownBadCandidates = true;
if (const char* pruneEnv = std::getenv("YAMS_BENCH_OPT_PRUNE_KNOWN_BAD"); pruneEnv) {
pruneKnownBadCandidates = envTruthy(pruneEnv);
}
if (pruneKnownBadCandidates && selectedCandidates.empty()) {
static const std::unordered_set<std::string> kKnownBadCandidates = {
"mixed_precision_rrf_neighbor_t92_p80_k14",
"mixed_precision_rrf_neighbor_t92_p78_k16",
"mixed_precision_rrf_neighbor_t90_p84_k18",
"mixed_ablation_disable_graph_rerank",
};
const auto beforeCount = candidates.size();
candidates.erase(std::remove_if(candidates.begin(), candidates.end(),
[](const OptimizationCandidate& candidate) {
return kKnownBadCandidates.count(candidate.name) > 0;
}),
candidates.end());
const auto removed = beforeCount - candidates.size();
if (removed > 0) {
spdlog::info("[OptLoop] Pruned {} known low-value candidates (set "
"YAMS_BENCH_OPT_PRUNE_KNOWN_BAD=0 to disable)",
removed);
}
}
if (const char* maxCandidatesEnv = std::getenv("YAMS_BENCH_OPT_MAX_CANDIDATES")) {
try {
const auto parsed = std::max(1, std::stoi(maxCandidatesEnv));
if (static_cast<std::size_t>(parsed) < candidates.size()) {
candidates.resize(static_cast<std::size_t>(parsed));
}
} catch (...) {
spdlog::warn("[OptLoop] Invalid YAMS_BENCH_OPT_MAX_CANDIDATES='{}', using default {}",
maxCandidatesEnv, candidates.size());
}
}
std::optional<fs::path> outputFile;
if (const char* outputEnv = std::getenv("YAMS_BENCH_OPT_RESULTS_FILE");
outputEnv && std::strlen(outputEnv) > 0) {
outputFile = fs::path(outputEnv);
const bool appendMode = envTruthy(std::getenv("YAMS_BENCH_OPT_APPEND_RESULTS"));
std::ofstream probe(*outputFile, appendMode ? (std::ios::out | std::ios::app)
: (std::ios::out | std::ios::trunc));
if (!probe.is_open()) {
spdlog::warn("[OptLoop] Could not create optimization results file: {}",
outputFile->string());
outputFile.reset();
} else {
spdlog::info("[OptLoop] Writing optimization results to {} ({})", outputFile->string(),
appendMode ? "append" : "truncate");
}
}
std::cout << "\n" << std::string(78, '=') << "\n";
std::cout << " RETRIEVAL OPTIMIZATION LOOP (code/mixed first)\n";
std::cout << std::string(78, '=') << "\n";
std::cout << "Profile: " << optimizationProfileName(optProfile)
<< (hasExplicitCandidateFilter ? " (explicit candidate filter)" : "") << "\n";
std::vector<OptimizationRunResult> allResults;
allResults.reserve(candidates.size());
for (std::size_t i = 0; i < candidates.size(); ++i) {
const auto& candidate = candidates[i];
spdlog::info("[OptLoop] Candidate {}/{}: {} - {}", i + 1, candidates.size(), candidate.name,
candidate.description);
auto result = runOptimizationCandidate(candidate, outputFile);
allResults.push_back(result);
if (!result.success) {
std::cout << "\n [" << (i + 1) << "/" << candidates.size() << "] " << candidate.name
<< " -> FAILED: " << result.errorMessage << "\n";
continue;
}
const double avgMs = result.hybridEvalMs / std::max(1, result.hybridMetrics.numQueries);
const double mrrDelta = result.hybridMetrics.mrr - result.keywordMetrics.mrr;
std::cout << "\n [" << (i + 1) << "/" << candidates.size() << "] " << candidate.name
<< "\n";
std::cout << " objective=" << std::fixed << std::setprecision(4) << result.objectiveScore
<< " hybrid_mrr=" << result.hybridMetrics.mrr
<< " keyword_mrr=" << result.keywordMetrics.mrr << " mrr_delta=" << std::showpos
<< std::setprecision(4) << mrrDelta << std::noshowpos
<< " dup@k=" << std::setprecision(4) << result.hybridMetrics.duplicateRateAtK
<< " avg_hybrid_ms=" << std::setprecision(1) << avgMs << "\n";
const auto hybridDiag = queryDiagnosticsToJson(result.hybridDiagnostics);
std::cout << " trace_cov=" << std::setprecision(3)
<< hybridDiag["trace_coverage"].get<double>() << " sem_rescue_mean="
<< hybridDiag["semantic_rescue_rate"]["mean"].get<double>()
<< " ca_apply_rate=" << hybridDiag["compressed_ann_apply_rate"].get<double>()
<< " vec_only_below_mean="
<< hybridDiag["vector_only_below_threshold"]["mean"].get<double>()
<< " no_relevant_hit_rate="
<< hybridDiag["query_without_relevant_hit_rate"].get<double>()
<< " graph_apply_rate=" << hybridDiag["graph_rerank_apply_rate"].get<double>()
<< " miss_pre_fusion_rate="
<< hybridDiag["miss_missing_pre_fusion_rate"].get<double>() << "\n";
std::cout << " timing_tradeoffs=" << summarizeTimingTradeoffs(hybridDiag) << "\n";
std::cout << " ca_skip_reasons=" << hybridDiag["compressed_ann_skip_reasons"].dump()
<< "\n";
std::cout << " stage_tradeoffs=" << summarizeStageTradeoffs(hybridDiag) << "\n";
std::cout << " stage_quality=" << summarizeStageMetricGaps(hybridDiag) << "\n";
if (result.traceTopN > 0 || result.traceComponentTopN > 0) {
std::cout << " trace_top_n=" << result.traceTopN
<< " trace_component_top_n=" << result.traceComponentTopN << "\n";
}
std::cout << " tuning_state="
<< (result.tuningState.empty() ? "<unknown>" : result.tuningState) << "\n";
if (!result.debugFile.empty()) {
std::cout << " debug_file=" << result.debugFile << "\n";
}
}
std::vector<OptimizationRunResult> successful;
for (const auto& result : allResults) {
if (result.success) {
successful.push_back(result);
}
}
if (successful.empty()) {
std::cout << "\nNo successful optimization candidates completed.\n";
return 2;
}
std::sort(successful.begin(), successful.end(),
[](const OptimizationRunResult& a, const OptimizationRunResult& b) {
return a.objectiveScore > b.objectiveScore;
});
const auto& best = successful.front();
g_final_metrics = best.hybridMetrics;
g_keyword_metrics = best.keywordMetrics;
std::cout << "\n" << std::string(78, '-') << "\n";
std::cout << "Top candidates by objective\n";
std::cout << std::string(78, '-') << "\n";
for (std::size_t i = 0; i < successful.size(); ++i) {
const auto& result = successful[i];
const double avgMs = result.hybridEvalMs / std::max(1, result.hybridMetrics.numQueries);
const double mrrDelta = result.hybridMetrics.mrr - result.keywordMetrics.mrr;
std::cout << " " << (i + 1) << ". " << result.candidate.name
<< " objective=" << std::fixed << std::setprecision(4) << result.objectiveScore
<< " mrr=" << result.hybridMetrics.mrr
<< " ndcg=" << result.hybridMetrics.ndcgAtK << " mrr_delta=" << std::showpos
<< std::setprecision(4) << mrrDelta << std::noshowpos
<< " dup@k=" << std::setprecision(4) << result.hybridMetrics.duplicateRateAtK
<< " avg_ms=" << std::setprecision(1) << avgMs << "\n";
}
std::cout << "\nBest candidate: " << best.candidate.name << "\n";
std::cout << " " << best.candidate.description << "\n";
std::ostringstream envLine;
for (const auto& setting : best.candidate.envOverrides) {
if (setting.value.has_value()) {
envLine << setting.key << "=" << *setting.value << " ";
}
}
std::cout << " Recommended env overrides: " << envLine.str() << "\n";
if (outputFile.has_value()) {
std::cout << " Saved per-run JSONL to: " << outputFile->string() << "\n";
}
const char* datasetEnv = std::getenv("YAMS_BENCH_DATASET");
if (!(datasetEnv && std::strlen(datasetEnv) > 0)) {
std::cout << " Next: validate this winner on a harder dataset, e.g. "
<< "YAMS_BENCH_DATASET=synthetic-hard or YAMS_BENCH_DATASET=scifact ...\n";
}
std::cout << std::string(78, '=') << "\n";
return 0;
}
void BM_RetrievalQuality(benchmark::State& state) {
SetupFixture();
auto& fixture = *g_fixture;
RetrievalMetrics metrics;
for (auto _ : state) {
std::vector<double> warmupLatencyMs;
std::vector<TestQuery> failedWarmupQueries;
evaluateQueries(*fixture.client, fixture.benchCorpusDir, fixture.queries, fixture.topK,
"hybrid", nullptr, false, &warmupLatencyMs, &failedWarmupQueries);
const auto retriedWarmupQueries = failedWarmupQueries.size();
if (!failedWarmupQueries.empty()) {
std::vector<TestQuery> retryFailures;
evaluateQueries(*fixture.client, fixture.benchCorpusDir, failedWarmupQueries,
fixture.topK, "hybrid", nullptr, false, &warmupLatencyMs,
&retryFailures);
failedWarmupQueries = std::move(retryFailures);
}
if (g_debugOut) {
DebugLogEntry warmupEntry;
warmupEntry.searchType = "benchmark_warmup";
warmupEntry.extraFields = {
{"event", "query_warmup_summary"},
{"query_count", fixture.queries.size()},
{"completed_queries", warmupLatencyMs.size()},
{"first_query_latency_ms", warmupLatencyMs.empty() ? 0.0 : warmupLatencyMs.front()},
{"retried_queries", retriedWarmupQueries},
{"retry_failed_queries", failedWarmupQueries.size()},
};
debugLogWriteJsonLine(warmupEntry);
}
g_final_hybrid_diagnostics = QueryDiagnosticsSummary{};
metrics = evaluateQueries(*fixture.client, fixture.benchCorpusDir, fixture.queries,
fixture.topK, "hybrid", &g_final_hybrid_diagnostics);
benchmark::DoNotOptimize(metrics);
}
// Store metrics globally for post-teardown summary
g_final_metrics = metrics;
g_benchmark_search_engine =
std::string(yams::vector::vectorSearchEngineName(benchmarkVectorSearchEngine()));
if (fixture.harness) {
g_final_vector_index_state = inspectPersistedHnswState(fixture.harness->dataDir());
}
state.counters["MRR"] = metrics.mrr;
state.counters["Recall@K"] = metrics.recallAtK;
state.counters["Precision@K"] = metrics.precisionAtK;
state.counters["nDCG@K"] = metrics.ndcgAtK;
state.counters["MAP"] = metrics.map;
state.counters["num_queries"] = metrics.numQueries;
// Also evaluate keyword-only (FTS5) for component isolation
// This helps diagnose whether low MRR is from FTS5 or vector search
spdlog::info("=== Evaluating KEYWORD-ONLY (FTS5) for component isolation ===");
g_final_keyword_diagnostics = QueryDiagnosticsSummary{};
g_keyword_metrics = evaluateQueries(*fixture.client, fixture.benchCorpusDir, fixture.queries,
fixture.topK, "keyword", &g_final_keyword_diagnostics);
if (g_debugOut) {
DebugLogEntry summaryEntry;
summaryEntry.searchType = "benchmark_summary";
summaryEntry.extraFields = {
{"event", "hybrid_summary"},
{"hybrid_metrics",
{{"mrr", metrics.mrr},
{"recall_at_k", metrics.recallAtK},
{"precision_at_k", metrics.precisionAtK},
{"ndcg_at_k", metrics.ndcgAtK},
{"map", metrics.map}}},
{"hybrid_diag_summary", queryDiagnosticsToJson(g_final_hybrid_diagnostics)},
{"keyword_metrics",
{{"mrr", g_keyword_metrics.mrr},
{"recall_at_k", g_keyword_metrics.recallAtK},
{"precision_at_k", g_keyword_metrics.precisionAtK},
{"ndcg_at_k", g_keyword_metrics.ndcgAtK},
{"map", g_keyword_metrics.map}}},
{"keyword_diag_summary", queryDiagnosticsToJson(g_final_keyword_diagnostics)},
};
debugLogWriteJsonLine(summaryEntry);
}
state.counters["MRR_keyword"] = g_keyword_metrics.mrr;
state.counters["Recall_keyword"] = g_keyword_metrics.recallAtK;
if (benchEvaluateGrepBaseline()) {
spdlog::info("=== Evaluating GREP literal baseline for exact-match comparison ===");
g_grep_metrics = evaluateGrepQueries(*fixture.client, fixture.queries, fixture.topK);
state.counters["MRR_grep"] = g_grep_metrics.mrr;
state.counters["Recall_grep"] = g_grep_metrics.recallAtK;
} else {
spdlog::info("=== Skipping GREP literal baseline for this benchmark plan ===");
}
if (g_debugOut) {
const auto peakRssMb = yams::bench::processPeakRssMb();
DebugLogEntry resourceEntry;
resourceEntry.searchType = "benchmark_summary";
resourceEntry.extraFields = {
{"event", "process_resource_metrics"},
{"process",
{{"peak_rss_observed", peakRssMb.has_value()},
{"peak_rss_mb", peakRssMb.value_or(0.0)}}},
};
debugLogWriteJsonLine(resourceEntry);
}
}
// Retrieval quality is a long-running, end-to-end evaluation.
// Force a single iteration to avoid repeated full-corpus evaluations.
BENCHMARK(BM_RetrievalQuality)->Iterations(1);
int main(int argc, char** argv) {
consumeXplanConfigArguments(argc, argv);
if (envTruthy(std::getenv("YAMS_BENCH_OPT_LOOP"))) {
return runOptimizationLoop();
}
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
CleanupFixture();
// Re-print summary after all teardown logs
// This ensures results are visible even when daemon teardown is verbose
std::cout << "\n" << std::string(70, '=') << "\n";
std::cout << " RETRIEVAL QUALITY BENCHMARK RESULTS\n";
std::cout << std::string(70, '=') << "\n";
std::cout << std::fixed << std::setprecision(4);
// Hybrid search results
std::cout << "\n --- HYBRID SEARCH (text + vector) ---\n";
std::cout << " Search engine: " << std::setw(10)
<< g_benchmark_search_engine << "\n";
std::cout << " MRR (Mean Reciprocal Rank): " << std::setw(10) << g_final_metrics.mrr
<< "\n";
std::cout << " Recall@K: " << std::setw(10) << g_final_metrics.recallAtK
<< "\n";
std::cout << " Precision@K: " << std::setw(10)
<< g_final_metrics.precisionAtK << "\n";
std::cout << " nDCG@K (Normalized DCG): " << std::setw(10) << g_final_metrics.ndcgAtK
<< "\n";
std::cout << " MAP (Mean Average Precision): " << std::setw(10) << g_final_metrics.map
<< "\n";
const auto hybridDiag = queryDiagnosticsToJson(g_final_hybrid_diagnostics);
std::cout << " Stage quality gaps: " << summarizeStageMetricGaps(hybridDiag)
<< "\n";
std::cout << " vectors.db bytes: " << std::setw(10)
<< g_final_vector_index_state.vectorsDbBytes << "\n";
std::cout << " vectors.db-wal bytes: " << std::setw(10)
<< g_final_vector_index_state.vectorsWalBytes << "\n";
std::cout << " persisted_hnsw_nodes: " << std::setw(10)
<< g_final_vector_index_state.nodeRows << "\n";
std::cout << " persisted_hnsw_meta_rows: " << std::setw(10)
<< g_final_vector_index_state.metaRows << "\n";
std::cout << " persisted_vec0_tables: " << std::setw(10)
<< g_final_vector_index_state.vec0Tables << "\n";
std::cout << " persisted_vec0_rows: " << std::setw(10)
<< g_final_vector_index_state.vec0Rows << "\n";
std::cout << " persisted_simeon_pq_codes: " << std::setw(10)
<< g_final_vector_index_state.pqCodeRows << "\n";
std::cout << " persisted_simeon_pq_meta: " << std::setw(10)
<< g_final_vector_index_state.pqMetaRows << "\n";
// Keyword-only search results (FTS5 isolation)
std::cout << "\n --- KEYWORD SEARCH (FTS5 only) ---\n";
std::cout << " MRR (Mean Reciprocal Rank): " << std::setw(10) << g_keyword_metrics.mrr
<< "\n";
std::cout << " Recall@K: " << std::setw(10)
<< g_keyword_metrics.recallAtK << "\n";
std::cout << " Precision@K: " << std::setw(10)
<< g_keyword_metrics.precisionAtK << "\n";
std::cout << " nDCG@K (Normalized DCG): " << std::setw(10) << g_keyword_metrics.ndcgAtK
<< "\n";
std::cout << " MAP (Mean Average Precision): " << std::setw(10) << g_keyword_metrics.map
<< "\n";
// Grep baseline results
std::cout << "\n --- GREP BASELINE (literal exact match) ---\n";
std::cout << " MRR (Mean Reciprocal Rank): " << std::setw(10) << g_grep_metrics.mrr
<< "\n";
std::cout << " Recall@K: " << std::setw(10) << g_grep_metrics.recallAtK
<< "\n";
std::cout << " Precision@K: " << std::setw(10)
<< g_grep_metrics.precisionAtK << "\n";
std::cout << " nDCG@K (Normalized DCG): " << std::setw(10) << g_grep_metrics.ndcgAtK
<< "\n";
std::cout << " MAP (Mean Average Precision): " << std::setw(10) << g_grep_metrics.map
<< "\n";
// Component comparison summary
std::cout << "\n --- COMPONENT COMPARISON ---\n";
std::cout << " Number of queries evaluated: " << std::setw(10) << g_final_metrics.numQueries
<< "\n";
auto describeDelta = [](double delta, std::string_view positive, std::string_view negative) {
constexpr double kTieEpsilon = 1e-9;
if (std::abs(delta) <= kTieEpsilon) {
return std::string(" (tied)");
}
return std::string(delta > 0 ? positive : negative);
};
double keywordMrrDelta = g_final_metrics.mrr - g_keyword_metrics.mrr;
double grepMrrDelta = g_final_metrics.mrr - g_grep_metrics.mrr;
std::cout << " MRR delta (hybrid - keyword): " << std::setw(10) << keywordMrrDelta
<< describeDelta(keywordMrrDelta, " (hybrid better)", " (keyword better)") << "\n";
std::cout << " MRR delta (hybrid - grep): " << std::setw(10) << grepMrrDelta
<< describeDelta(grepMrrDelta, " (hybrid better)", " (grep better)") << "\n";
std::cout << std::string(70, '=') << "\n";
return 0;
}