Commit graph

87 commits

Author SHA1 Message Date
trvon
2cff3982c6
fix(vector): bump sqlite-vec-cpp for safe error formatting
0fec31c: sqlite3_mprintf error paths used %zu, which SQLite parses as a
string conversion and crashed on invalid vec0 dimensions or corrupt HNSW
persistence; also corrects a RaBitQ test expectation.
2026-09-22 18:58:23 -06:00
trvon
2824cb8a44
perf(vector): use AVX2 on x86 through runtime CPU dispatch
Bump simeon to 38a0b39 (active_simd_tier() checks CPUID; pq.cpp kernels
follow it) and sqlite-vec-cpp to d4ce0cc (target-attribute AVX2+FMA float
distance kernels behind a CPUID check).

x86 builds now compile simeon's arch/avx2.cpp alone with -mavx2 -mfma and
define SIMEON_HAS_AVX2; every other TU keeps the baseline ISA, so generic
x86-64 binaries stay portable while AVX2 hosts use SIMD for encoding, PQ
training, and sqlite-vec distances (3-4x per distance call at 384d on a
Zen 2 host). Full unit suite on Linux x86 (clang, Debug): no new failures.
2026-09-22 18:21:08 -06:00
trvon
cddb9e7283
perf(vector): score Simeon PQ candidates with batched ADC scans
Bump simeon to c846635:
- fix(tokenizer): locale-independent character classes
- perf(pq): batched/gathered inner-product scans, bit-identical
- perf(projection): Achlioptas apply visits only non-zero sketch buckets
  (5.6x on short texts at 4096->384, bit-identical)

The PQ search scan now calls inner_product_batch/_gather instead of one
pimpl call per code. Scores are bit-identical, so ranking and tie-breaks
are unchanged (1.6-2.0x lower ADC scan time in simeon's pq_query_bench).
2026-09-22 17:22:44 -06:00
Trevon
0effb84a5c
perf(vector): harden portable backends (#66)
* perf(vector): update portable backends

Keep generic release binaries on baseline ISA until runtime CPU dispatch can guard AVX and FMA paths.

Signed-off-by: trvon <git@trevon.dev>

* test(vector): isolate backend measurements

Signed-off-by: trvon <git@trevon.dev>

---------

Signed-off-by: trvon <git@trevon.dev>
2026-08-23 23:12:39 -04:00
trvon
db7366509d
build(deps): update Simeon concept mining
Point the submodule at the reviewed, published optimization so clean CI clones can resolve it.
2026-08-07 21:13:20 -04:00
trvon
67b1f894c1
perf(search): optimize concept mining warmup 2026-08-05 20:53:19 -04:00
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
trvon
4e566f6387
fix: harden buffer and parser contracts
Validate Simeon buffer boundaries and replace ZYP reverse pointer arithmetic with bounded indexing. Keep release SIMD kernels unchecked while asserting contracts in debug builds.
2026-07-29 19:00:10 -04:00
trvon
3a5f1b8ebc
chore(deps): update Simeon dimension cleanup 2026-07-29 15:26:18 -04:00
trvon
58c7813315
chore(deps): update owned library docs 2026-07-29 13:13:38 -04:00
Trevon
3f37e8f564
Sync experimental into main: Search retrieval improvements (#60)
* fix(graph): handle qualified C++ symbols

Signed-off-by: trvon <me@trevon.dev>

* refactor(vector)!: remove dead transition APIs

Split Simeon vector and retrieval linkage so consumers inherit only the runtime surface they use.

BREAKING CHANGE: remove unused async/model/config helpers and the undefined vector-backend factory from public headers.

Signed-off-by: trvon <me@trevon.dev>

* fix(vector): harden PQ snapshot lifecycle

Validate and atomically install persisted generations, revalidate after races, and fall back to exact search when a snapshot is stale. Add the exact-scan reference lane and distinguish observed work counters from unavailable backend metrics.

Signed-off-by: trvon <me@trevon.dev>

* feat(topology): expose route coordinates

Persist chart distortion and local-dimension evidence, retain pre-scalarization route axes, and emit detailed trace rows without treating unavailable vector work as zero.

Signed-off-by: trvon <me@trevon.dev>

* feat(xplan): add vector decision gates

Track binary and corpus identity, preserve missing-work semantics, and add repeated PQ routing, crossover, and rerank plans with quality and cost summaries.

Signed-off-by: trvon <me@trevon.dev>

* feat(topology): formalize coordinate routing

Separate chart geometry from route-risk admission and prove candidate-stage recall and strict-focus boundaries. Record the measured atlas limitations and literature basis for the next construction experiment.

Signed-off-by: trvon <me@trevon.dev>

* fix(search): serialize SymSpell readers

SQLite-backed lookups reuse mutable prepared statements, so shared-reader locking is unsafe. Advance the owned SymSpell revision for batched delete insertion and cover concurrent root lookups under TSAN.

Signed-off-by: trvon <me@trevon.dev>

* fix(vector): make mutations atomic

Preserve stored vectors on replacement and commit failures, reject cross-thread writes during explicit transactions, and restore exact reranking for quantized-primary PQ rows.

* fix(search)!: surface SymSpell write errors

Propagate persistent dictionary failures through metadata ingestion, roll back failed batches, and make clear remove stored terms.

BREAKING CHANGE: SymSpellSearch mutations now return Result values.

* feat(topology): formalize candidate expansion

* feat(vector): add coordinate-aware embeddings

* feat(topology): preserve protected relation cover

* feat(search): add graph candidate rescue

* feat(daemon): expose retrieval hydration telemetry

* feat(xplan): add rescue and hydration gates

* refactor(content): dedupe media handlers

Reuse shared graph presenter helpers and centralize repeated audio/video/archive buffer processing, validation, lifecycle, and stats helper logic.

* feat(lifecycle): prune stale corpus data

Keep cleanup preview-first while retention stays opt-in and long prune work no longer holds IPC responses open.

* feat(search): add topology candidate rescue

Preserve high-value routed candidates across vector backends while keeping exact rerank diagnostics explicit.

* feat(search): expose evidence paths

* docs: define mobile host contract

* formal: model bounded candidate rescue

* fix(prune): inspect extensionless signatures

* fix(prune): tolerate stale extensions

---------

Signed-off-by: trvon <me@trevon.dev>
2026-07-24 19:00:22 -04:00
Trevon
7df64b1161
perf(search): bound topology routing and harden runtime paths (#59)
* fix: address review build issues

* perf(search): bound topology routing

Cache route membership, shortlist centroids with static ANN, and route SPQ through explicit allowed-document budgets.

* test(xplan): measure routed vector work

Pin benchmark binary identity and export route, cache, and phase costs for repeated equal-budget comparisons.

* test(search): use portable jthread wrapper

* fix(daemon): serialize detached cancellation

* fix(cli): honor pinned daemon sockets

* fix(xplan): support Windows contract imports

* fix(list): apply metadata filters before paging

* docs(prompts): require memory hydration

Treat search results as candidates and hydrate selected artifacts before use. Quote argument hints for strict YAML loaders.

* test(cli): keep add on pinned daemon

* test(metadata): isolate performance timing

* fix(graph): tolerate stale snippet ranges

Source files may change before persisted symbol metadata is refreshed. Omit stale snippets instead of aborting graph exploration.

* test(daemon): await request readiness

Reuse the retrying list probe before asserting post-shutdown error quality under sanitizer load.

* ci(release): use hosted cmake

Resolve Conan CMake tool requirements from PATH so cold ARM64 caches do not depend on cmake.org. Default BUILD_DIR for failure cleanup.
2026-07-19 14:53:10 -04:00
Trevon
a3d065dd8d
feat(search): make topology-assisted retrieval the default (#57)
* fix(release): repair package repo publish

Arch repo metadata and R2 uploads need to be reproducible from CI, with retry hardening for transient Cloudflare failures.

* fix(daemon): stop shutdown log storm

Init waiter must treat ShuttingDown as terminal so daemon shutdown tests do not flood Meson logs while the daemon is stopping.

* refactor(cli): delegate serve to MCP binary

Keep yams serve UX while removing MCP server linkage from yams-cli. The standalone MCP binary owns stdio serving and exits on stdin EOF.

* refactor(cli): move daemon path helpers

Keep CLI path resolution out of YamsDaemon so later link cuts can separate CLI and daemon internals. Full yams_daemon removal still needs a socket-only daemon-client split.

* refactor(daemon): split embedded client

* perf(search): add lean-guided benchmark gates

Add Lean topology/search models, ingestion ablation docs, and focused regression tests for topology and compression threshold behavior.

Extract search observability, keep benchmark-only ablation controls, and make retrieval quality benchmarks default to Simeon while preserving explicit ONNX opt-in.

* refactor(config): move daemon policies

* refactor(daemon): extract plugin runtime

* refactor(daemon): untangle service coordinators

Untangle CLI/MCP from daemon service coordinators and the daemon static lib.

- MetadataRepository uses a daemon-neutral tree-diff callback. The
  GraphComponent wrapper moves to src/daemon/components/metadata_graph_bridge.cpp,
  owned by the daemon library.
- WriteCoordinator moves to a dedicated build-only yams_write_coordinator
  static lib. Drop ResourceGovernor coupling inside the writer loop; batch
  sizing still respects config.maxBatchSize.
- AppContext gains enqueuePostIngest callback. ServiceManager wires it to
  its own enqueuePostIngest; app services no longer call ServiceManager
  directly.
- Embedding repair uses BulkIngestLease/BeginBulkIngestCallback instead of
  concrete VectorIndexCoordinator::BulkScope. Daemon dispatchers provide a
  lease factory backed by the real coordinator.
- CLI daemon_command uses config helpers instead of YamsDaemon::getXDGRuntimeDir.
- Remove explicit dependency('yams_daemon') from src/cli and tools/yams-mcp.
- Declare missing yams_extraction/yams_ingest deps on yams_app_services so
  app services link cleanly without daemon.

Validated:
  meson compile -C build/release -j4 yams-daemon yams-cli yams-mcp-server
  ninja -C build/release -t commands tools/yams-cli/yams-cli tools/yams-mcp/yams-mcp-server | grep -c libyams_daemon.a -> 0
  yams-cli --version, yams-mcp-server init, yams serve --help smoke tests

Size drop on macOS release: yams-cli 41M -> 32M, yams-mcp-server 37M -> 22M.

* fix(cli): keep stdin add local fallback

No embedded daemon now. When yams add - buffers stdin and daemon IPC is missing, store via local app services instead of failing socket_missing.

Validated:
  meson compile -C build/debug -j4 yams-cli catch2_cli_commands
  MESON_BUILD_ROOT=/Users/trevon/work/tools/yams/build/debug build/debug/tests/catch2_cli_commands 'AddCommand - reads from piped stdin and stores content'
  MESON_BUILD_ROOT=/Users/trevon/work/tools/yams/build/debug build/debug/tests/catch2_cli_commands
  meson compile -C build/release -j4 yams-cli yams-mcp-server
  meson compile -C build/asan-api -j2 yams-cli catch2_cli_commands
  MESON_BUILD_ROOT=/Users/trevon/work/tools/yams/build/asan-api ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 build/asan-api/tests/catch2_cli_commands 'AddCommand - reads from piped stdin and stores content'
  ninja -C build/release -t commands tools/yams-cli/yams-cli tools/yams-mcp/yams-mcp-server | grep libyams_daemon.a -> no output

* feat(bench): add xplan multi-arm experiment harness

Unified plan runner, ablation axes, REPORT/ablation docs, and
KPI snapshot so optimization loops stop living in shell matrices.

* feat(formal): expand topology/search Lean contracts

Boundary models for search provenance, construction gates,
and cluster/route objectives so Lean guides correctness while
xplan ranks performance levers.

* feat(search,topology): construction purity + graph expansion path

Raise topology build defaults (min edge 0.25, max component 64) and
split oversized CC pieces so hybrid assist is quality-positive on
scifact. Add GraphNeighbors expansion with medoid-anchor fallback,
structured helpers instead of nested session logic, and BEIR-default
xplan plans. Search engine extraction (fanout/classic pipeline) rides
along as the integration surface for routing.

* feat(topology): add KMeans engine and SGC identity contracts

Register kmeans in the factory with deterministic spherical k-means
over embeddings, and enforce SGC document-identity invariants in
debug builds with matching unit coverage.

* feat(daemon): topology readiness gates and selectable reranker

Drive topologyReady from published epoch/freshness/rebuild/dirty
ingest state (not just KG drain), surface those fields in search
stats, and wire onnx|simeon|auto|none cross-reranker selection.

* chore(search): drop meta_path tuner knobs

Meta-path routing is gone; remove dead TunedParams fields and the
ConfigResolver test for [search.meta_path].

* feat(bench): add topology_purity_validate plan

Repeats=3 validation matrix for construction-purity winners vs
topo_off so MRR deltas can clear run-to-run noise.

* chore: format add_command and config include order

Mechanical clang-format / include reorder only; no behavior change.

* feat(bench): decision-grade xplan loop for search engine

Document search-engine measurement in AGENTS; harden xplan with
repeats=3 plans, quality×latency primaries, mechanism metrics from
debug.jsonl, multi-rep log promotion, and archive superseded topology
plans.

* feat(graph): denser product semantic_neighbor topK

Raise default YAMS_GRAPH_SEMANTIC_TOPK fallback from 4 to 8 so product
graphs leave fewer degree-0 docs for GraphNeighbors expansion.

* feat(search): extract topology assist and cross-rerank seams

Pull topology assist into search_topology_stage (seed merge, skip
reasons, optional vector seed probe default 0). Extract cross_rerank
compute from search_engine. Wire probe via typed config/ConfigResolver.

* feat(bench): product-path search engine ablation plans

Add topology-off component, vector-weight, and tiered-execution xplan
plans (repeats=3) and wire them into the AGENTS measurement loop table.

* fix(ci): repair pre-push fallbacks

* feat(bench): lock-free mid-run builds + multi-corpus gates

xplan skips meson rebuild when the quality binary exists (flock +
YAMS_BENCH_FORCE_BUILD override) to stop multi-arm link races. Add
graph_vector weight and nfcorpus transfer-gate plans; document in AGENTS.

* fix(daemon): keep SearchEngine alive via shared_ptr cache

getCachedEngine previously published a raw pointer that metrics polling
used through rebuild, racing destructor of SearchEngine::Impl (TSAN).
Store and return a shared_ptr snapshot so diagnostic readers pin the
engine for the duration of getConfig/health checks.

Also adds the cautious vectorWeight 0.30→0.20 multi-corpus xplan plan.

* feat(search): route vectors through cached topology

Build and reuse validated topology snapshots, rank routed members by query similarity, and narrow the vector leg to the accepted document set with explicit work diagnostics.

Remove the retired HDBSCAN engine and vendor dependency, preserve typed topology policy through search tuning, and cover the runtime/configuration contracts.

* feat(bench): consolidate search decision plans

Enforce deterministic experiment identity and declared baselines, expose routed/global vector work metrics, and register the focused benchmark contracts.

Promote the compact repeats=3 routing-budget gate, archive superseded topology mechanism screens, and add multi-corpus product calibration plans.

* feat(search): refine topology vector routing

* fix(search): propagate daemon readiness

* feat(bench): measure generalized memory health

* fix(cli): honor in-process fallbacks

* ci: harden smolvm debug builds

* perf(search): route topology through filtered ANN

* feat(bench): measure read-write pressure

* perf(metadata): index symbol lookups on read pool

* fix(daemon): isolate startup reads and maintenance

* feat(bench): replay isolated generalized corpora

* feat(search): add evidence routing pipeline

Replace the blocking smolvm pre-push path with host ASan/TSan validation, harden sanitizer-sensitive smoke tests, and add recovery cleanup for malformed SQLite WAL sidecars.

* refactor(search): unify topology evidence path

Remove classic and sidecar fusion lanes so topology augments the recall-preserving ANN and lexical candidate pool through one product path.

* refactor(bench): prune superseded search lanes

Measure the topology-plus-ANN product path with stable experiment identity and remove obsolete sidecar and tiered controls.

* docs(search): retire stale experiment notes

Keep the benchmark handoff focused on the topology-plus-ANN product lane and its active decision plans.

* refactor(search): prune dead search surfaces

Remove unused fusion, reranker, policy, and router abstractions.
Bound topology materialization and keep document trace payloads opt-in.

* fix(cli): clear build warnings

* fix(xplan): reject stale run identity

* refactor(search)!: remove legacy query stack

Replace the unused AST/ranker/post-processor surface with focused facet aggregation used by product search.

BREAKING CHANGE: removes query parser, result ranker, search filter, and SearchResults container APIs from yams_search.

* refactor(search): type value stage traces

Remove synthetic ComponentResult markers for embedding and concept stages. Preserve failure and timeout states instead of overwriting them with fake successful results.

* refactor(search): isolate benchmark env overlays

Move test-only search environment parsing behind an injectable internal adapter. Keep all existing overlay keys and tuner pin semantics while restoring SearchEngineBuilder to composition.

* refactor(search): unify topology routing options

Snapshot topology policy once at the assist boundary and pass it through routing sessions and diagnostics. Remove repeated scalar copying without changing routing behavior or metric keys.

* fix(search): unify tuner config ownership

Use one complete config-to-params overlay for runtime seeding and no-tuner policy resolution. Reseed attached tuners on setConfig so reported and executed configuration cannot diverge.

* fix(search): snapshot tuner state per query

Read tuned config, params, and state under one lock before routing. Add a TSAN correlation test so adaptive observation cannot produce a torn logical query snapshot.

* fix(search): enforce topology routing contract

Generated configs must preserve hybrid-assist shadow routing, while daemon-backed search must abstain when published topology artifacts are stale. Keep standalone validation and global ANN recall intact.

* fix(daemon): let SQLite reclaim its file

Directly resizing a live database from sampled page counts can truncate pages allocated by concurrent writers. VACUUM must remain the only file-reclamation mechanism.

* fix(metadata): tolerate missing symbol FTS

Readiness lookups can race an unavailable optional FTS migration. Retain the indexed fast path, but retry against the base table when prepare or cached-statement execution proves the capability absent.

* build(fuzz): drop removed query parser target

The optional AFL build still referenced the deleted legacy query parser API and could no longer compile.

* fix(bench): include writes in drain oracle

A zero post-ingest queue is not durable drain while coordinated writes remain queued or in flight.

* fix(daemon): vacuum padded WAL databases safely
2026-07-13 20:26:43 -04:00
trvon
d112aae8b8
perf: coalesce KG writes and document live-mirror drift 2026-07-02 09:12:23 -04:00
trvon
903e29ab55
test(metadata): add corruption fixture + suites: page smash (header
+ cell tail, not free space), torn WAL, truncation, crash snapshot,
salvage row-by-row fallback, writer promise draining, pool behavior.
Runs green on libsql and stock sqlite.
2026-07-01 20:11:03 -04:00
trvon
7e2e5be626
refactor(search): remove RM3 from the retrieval product 2026-06-28 18:31:35 -04:00
trvon
1a11b9d230
refactor(search): retire fragment-geometry; fix geom scale-mix 2026-06-28 14:04:59 -04:00
Trevon
771deebc84
fix: harden CI and metadata stability (#48)
* feat: dead code removal, profling foudnation improvements, addressing code smells in reference db implementation

* fix: test fixes and optimmizations for benchmarks

* fix: harden audit findings

   Reject invalid tokenizer ids, fix move-order hazards, bound manifest
   and audio IO, and guard numeric/process edge cases found by Fold.

* fix: route SymSpell writes through coordinator

* test: fix batch content initializers

* fix(ci): restore cross-platform builds

* fix: address Copilot review findings
2026-06-11 16:42:54 -04:00
Trevon
9cb6421593
feat: daemon stability fixes, vector search optimizations, and docs refresh (#46)
* fix(daemon): resolve sign-conversion warnings

* fix(daemon): add IO thread startup barrier

* refactor: consolidate toLowerCopy clones

* fix(daemon): add atexit handler for static host map cleanup

* fix(build): add missing include, fix daemon_helpers syntax, use atomic barrier

* feat(docs): docs cleanup, and metadata refactor updates

* fix(daemon): resolve Windows-only PostIngestQueue shutdown SIGSEGV (#45)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* feat: submodule bump, multiclient optimizations and benchmark optimizations

* feat(perf): reduced contention with update to placement of flushPathCacheBuffer()

* fix(metadata): invalidate path cache on document mutation

* fix(metadata): hydrate cached counters before first write

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:30:38 -04:00
Trevon
2d01ba314c
Assertion hardening, metadata correctness, & daemon lifecycle fixes (#41)
* fix(core): add assertions and harden daemon lifecycle

* fix(daemon): tighten shutdown lifecycle invariants

* fix(test): add PressureLimitedPoller capability-sleep shutdown test

* refactor(vector): harden backend contracts

Split the vector backend surface into narrower contracts and
move entity read paths to Result<> so callers can distinguish
backend errors from empty results.

Also fixes the TurboQuant lazy-init race, makes VectorDatabase
error state thread-safe, wires eager index preparation, and
adds regression plus memory-scaling benchmark coverage.

* fix(vector): address audit findings plus hardening

Fix the five confirmed bugs: coroutine lifetime hazard in
embedding_generator (await_with_timeout outliving captured state),
VectorSystemManager init retry latch poisoning, incremental HNSW
persistence race, vec0 registry key collisions, and simeon PMI
output_dim/config() drift.

Add invariant hardening: PostIngestQueue stage validation +
numChunks assertion, VectorSystemManager success postcondition,
VectorDatabase TurboQuant non-null assertions on all quantize/
dequantize paths, and sqlite_vec_backend Simeon PQ range and
divisibility preconditions.

Also adds regression coverage for init-retry and lock-busy paths
and a locked node snapshot helper for safe incremental HNSW
persistence.

* fix(test): add PressureLimitedPoller wake-timer shutdown tests

* chore(vector): resolve clang-tidy hygiene across queue, vdb, and sqlite-vec

Replace unprotected std::getenv calls with locked getenvCopy helpers,
add debug-level logging to previously-silent catch blocks in
PostIngestQueue, VectorDatabase, and SqliteVecBackend, wrap
PostIngestQueue timer-detach allocations in try-catch, and fix
unsigned-widening / optional-deref / unused-include hygiene.

Verified with LSP diagnostics and rebuilds of catch2_vector_submodule
and catch2_daemon_component_submodule.

* fix(daemon): harden PressureLimitedPoller inFlightCounter null check

* fix(daemon): harden PostIngestQueue wait_until deadline checks

* fix(daemon): clean up recovery sentinels regardless of salvage count

Previously the .recovered-* sentinel and .corrupt-* file cleanup
was gated on documentsSalvaged > 0, leaving quarantine
artifacts to accumulate on repeated crash/recovery cycles where
the corrupt DB had 0 salvageable docs.

Move cleanup outside the salvage-count guard so stale
quarantine artifacts are always removed after examination.

* feat(vec0): restore persisted ANN index on daemon restart

After vec0 rebuild, probe for vectors_<dim>_hnsw_meta shadow tables
and load a previously-persisted HNSW index.  When found, the ANN
index is set directly on the vec0 table, skipping the O(n log n)
rebuild that was previously paid on every daemon restart.

Removes the stub restoreVec0AnnIndexIfPresentUnlocked() in favor
of inline restoration in rebuildVec0DimUnlocked(), which has
the vec0 table already created and ready for ann_index assignment.

* fix: enable DCHECK by default and assert metadata counter consistency

* fix(services): assert document deletion ordering content-before-metadata

* fix(test): add fork-based assertion validation tests

* fix(test): expand assertion tests for POSTCONDITION, DCHECK, UNREACHABLE

* fix(ci): enable -Denable-dcheck=true in all test CI lanes

* fix(test): address assertion review findings

* refactor(daemon): isolate poller config assertion checks

* refactor(services): reduce deletion and poller complexity

* style(ci): normalize test workflow spacing

* refactor(services): extract list query helpers

* refactor(services): extract list hydration helpers

* refactor(daemon): extract metrics snapshot helpers

* refactor(daemon): extract metrics counter snapshot

* refactor(daemon): extract metrics resource snapshot

* feat(graph): add daemon-backed explore

Wire graph explore through daemon IPC, keep CLI rendering stable,
and fall back locally when daemon transport or protocol skew fails.

Also add graph context service/tests, improve graph follow-up hints,
and keep release builds working with the current JSON library.

* fix(services): prevent prune delete metadata orphans

* fix(cli): honor data-dir in graph explore

- bypass daemon explore when the CLI pins a data dir so\n  temp fixtures do not resolve against a long-lived global DB\n- guard snippet truncation and ratio math to remove Fold-\n  reported underflow and div-by-zero paths\n- clamp zero-based symbol lines before rendering graph\n  context

* fix(daemon): make lifecycle stop completion safe

* fix(daemon): gate db-open startup against shutdown

* fix(metadata): serialize FTS indexed counter updates

* test(daemon): simulate vector lock contention cross-process

* test(daemon): isolate post-ingest identity batch

* style(daemon): normalize test include order

* refactor(graph): split cli graph helpers

Keep graph command paths smaller and easier to evolve.

Lock graph explore/topology contracts into focused presenter,
dispatcher, and support tests so follow-up refactors keep the
current IPC and hot-path behavior intact.

* fix(config): harden expand_tilde and fix Windows XDG state path doubling

- expand_tilde: handle bare ~ and ~/ explicitly to avoid std::out_of_range
  on substr(2) for single-char input
- getXDGStateHome: on Windows, go up two levels from %LOCALAPPDATA%\yams\state
  to %LOCALAPPDATA% so callers' xdg/yams append doesn't double the yams segment

* fix(static-analysis): add logging to empty catch blocks and fix nosemgrep syntax

* fix(static-analysis): strip trailing text from nosemgrep comments

* fix(doctor): add logging to daemon_check empty catch blocks

* fix(db_repair): add logging to empty catch blocks

* fix(chunking): add precondition checks for rabin polynomial and windowSize

* fix(safety): add null precondition checks for Fold proved null-deref sites

* fix(daemon): widen init-failure dispatch, add null/dbz preconditions

InitializationFailedEvent races with shutdown — async init
fails after teardown begins. Widen canDispatch to accept
Ready/ShuttingDown. Add static_assert on SnapshotRing N>0.
Add YAMS_PRECONDITION null guards on hex/stages/data/bytes.

* ci(ubsan): use restricted build targets to avoid runner timeout

* fix(daemon): detach wake timers on Windows stop path to prevent SIGSEGV

* fix(config): cast parseTomlU32 to size_t for batch fields

* fix(ci): use static helper for Windows timer leak, restrict ubsan tests
2026-06-04 12:53:42 -04:00
Trevon
bfe7cd94ca
test: expand storage-readiness coverage — 48.1%→59.8% broad, 74.3% narrow (#38)
* fix(daemon): avoid socket cancel on stop

Signal active sockets with shutdown only so pending I/O wakes without entering Boost.Asio's reactor cancel path during teardown.

* fix(metadata): open read pools read-only

* ci: fix coverage report generation

* fix(metadata): tag unscoped pool holders

* test(daemon): avoid ipc teardown takeover

* ci: skip plugin coverage objects

* fix(daemon): repair completed FTS5 ghosts

* build(vector): guard unusable FAISS headers

* ci: use clang gcov for coverage

* test(daemon): stabilize arm CI flakes

* Harden search and compression numeric config

* fix(daemon): reconcile orphan vector embeddings

* fix: address vector cleanup review comments

* chore(main): release 0.16.1

* Harden search ranking divisors

* Harden snippet distance and command registration

* test(storage): add readiness coverage gate

Document the distributed sync readiness surface and add direct adapter, refcount, and GC failure-path coverage.

* test(storage): cover strict resolver fallback

* fix(search): tighten retrieval ranking

Honor component weights in default RRF, over-fetch vector chunks before document aggregation, and persist topology centroids for sparse-guided routing.

* fix(search): route weak queries through topology

* fix(search): improve rerank and weak queries

Wire provider-backed cross reranking, add direct Simeon candidates for weak lexical pools, and report stage-level retrieval metrics.

* fix(storage): honor explicit plugin names

Add readiness coverage for factory, URL backend, and compressed storage failure paths.

* fix(storage): avoid remote size listing

* fix(api): rollback failed content adds

* test(storage): cover engine readiness

* test(storage): cover compressed readiness

* fix(core): harden delete and recovery paths

Route prune and local delete fallback through DocumentService so content, metadata, vectors, and KG cleanup stay consistent.

Treat transient SQLite quick_check lock failures as ResourceBusy, refresh IPC activity on streaming writes, and preserve reranker config in tuner seeding.

* test(storage): cover URL backend readiness

* fix(api): harden content rollback

* feat(storage): add list seam, URL listing, and write-edge coverage

* feat(api): reconcile ambiguous remote manifest writes

* feat(storage): add deep compressed scan validation

* test(storage): add plugin loader error path coverage

* fix(gc): prune reference rows after collection

* test(api,storage): add health, compact, gc, and verify edge coverage

* docs: update storage-readiness coverage to 71.8%

* test(metadata): add connection pool shutdown-while-leased coverage

* test(metadata): add tree builder snapshot root stability coverage

* test(vector): add before-init and after-close operation rejection coverage

* test(metadata): add database post-close, open-failure, and cache-clear coverage

* test(integrity): add P2P wrong-hash rejection + batch matrix resolution

* docs: audit and resolve all matrix rows — 18 fully covered

* test(metadata): add failed-migration and rollback coverage

* test(storage): add getBlockSize-invalid-key, empty-verify, PUT/DELETE retry coverage

* feat(storage): add file-open and rename failure hooks + ContentStore retrieve edge coverage

* docs: add broad-surface coverage with per-subsystem breakdown

* test(integrity): add chunk validator manifest validation coverage

* test(vector): add batch insert, delete, and update operation coverage

* docs: update integrity subsystem coverage to 46.4%

* docs: consolidate coverage report — clean matrix, remove boilerplate

* docs: update coverage with complete-suite numbers — 59.8% broad, 74.3% narrow

* test(storage): add URLBackend HEAD exists with 2xx coverage

* bump submodules

* fix: address PR review — curl_slist leak, ec ordering, CAS rollback, production hooks

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-25 22:58:15 -04:00
Trevon
6d8877a6d4
feat(search): add Simeon bandit tuning (#33)
* feat(search): per-profile simeon bandit with training-free self-tuning

* fix(zyp): free parallel buffers correctly

* fix: code cleanup and simeon version bump

* fix(search): guard Simeon bandit state
2026-05-17 04:08:50 -04:00
trvon
61fc7d1e70
fix(ci): ci fixes 2026-05-15 09:35:48 -04:00
Trevon
e27d5e3e84
fix: Copilot review feedback and gitignore for artifacts (#26)
* feat: search work and moving to experimental

* WIP

* feat(search): diagnostic logging pipeline — graph build, concepts, reranker gate

- New [concepts] per-50-query log showing extracted query concepts, type
  distribution, and used_gliner flag.

- New [PIQ-entity] per-1000-dispatch + per-document completion log with
  entity type counts (e.g., 'protein=3, gene=1, chemical=2').

- New [graph_rerank-gate] one-shot log showing why enableGraphRerank
  is zeroed: shows shortQueryBudgeted, corpusWarming, bypassWarmingGate,
  lexicalReady, and post-ingest inflight.

- New [graph_rerank] per-50-query log with window size, matched
  candidates, applied count, concept count, and elapsed time.

- retrieval_quality_bench.cpp: add YAMS_SEARCH_BYPASS_CORPUS_WARMING_GATE=1
  so benchmark queries are not gated by freshness checks.

- resolve merge conflicts from experimental branch.

* fix(search): enable entity extraction for text files via GLiNER fallback

- prepareMetadataEntry: shouldDispatchEntity now also checks hasTitleExtractor()
  so plain-text files (.txt, .md) get entity extraction even when no binary
  entity provider supports their extension.

- processEntityExtractionStage: when no ExternalEntityProvider matches,
  fall back to processTitleExtractionStage which runs GLiNER on text.

- refreshStageAvailability: entity stage is now considered capable when
  hasTitleExtractor() is true, so the entity poller gets concurrency budget
  even if entityProviders_ is empty.

- kCombinedEntityTypes: add biomedical entity types (protein, gene, cell,
  disease, chemical, drug, pathway, biological_process, biomarker, anatomy,
  organism) so GLiNER extracts high-value biomedical entities instead of
  only generic NL types (person, organization, concept).

* perf(bench): add YAMS_POST_ENTITY_CONCURRENT=4 for text entity fallback throughput

* feat(search): fast token-based entity extraction for text documents

- Replace slow GLiNER-based entity extraction (~260ms/doc) with fast
  token-based concept mining (~1ms/doc) via generateFallbackQueryConcepts.
  Uses sub-phrase mining + IDF-weighted token salience — the same function
  already used for query-time concept fallback.

- Store entities with full KG scaffolding: KGNode with entity type/label,
  KGAlias for query-time resolution, DeferredEdge from entity→document,
  and DeferredDocEntity linking entity to document for getDocEntitiesForDocument.

- Add biomedical entity types to kCombinedEntityTypes in title extraction
  (protein, gene, cell, disease, chemical, drug, pathway, etc.) so GLiNER
  can output high-value biomedical entities when used.

- Add include for query_expansion.h to access generateFallbackQueryConcepts.

- bench: add YAMS_POST_ENTITY_CONCURRENT=4 for entity poller throughput.

Benchmark: 22K+ entities extracted across 5183 docs, ~41% high-value
biomedical. MRR 0.4281 (beats 0.4273 baseline by +0.2%).

* feat(diag): add firstDocEntities check to graph_rerank-gate log

- Queries kg_doc_entities for the first candidate document to verify
  whether fast entity writes were committed before queries start.
- Confirmed: firstDocEntities=0 — entities stuck in WriteCoordinator
  async queue when benchmark queries begin.

* fix(search): add periodic write-coordinator flush during entity extraction

Entity writes enqueued via writeCoordinator_ can accumulate since the
writer loop is capped at 8 batches/iteration. For 5K+ documents this
creates a backlog that outlasts the post-ingest drain wait — entities
are not committed to kg_doc_entities before benchmark queries start.

Add a periodic flush (every 128 batches, 500ms timeout) in the entity
extraction batch processor to drain the WC queue incrementally.

Diagnostic confirms firstDocEntities=0 persists — a synchronous
committed flush or batched WC enqueue is needed.

* fix(docker): add gfortran for openblas arm64 build

* fix(search): accumulate entity writes into shared WC batch, flush once

The WriteCoordinator writer loop is capped at 8 batches/iteration. With
5K+ per-doc entity writes, entities outlast the benchmark's post-ingest
drain and firstDocEntities=0 when the graph scorer runs.

- processEntityExtractionStage: add optional DeferredKGBatch* parameter.
  Text-fallback appends entity nodes/aliases/edges/doc-entities to the
  shared batch instead of creating per-doc WC batches.

- processEntityExtractionBatch: creates one DeferredKGBatch, passes it to
  all stage calls in the batch, enqueues to WC once at end.

- Single-shot WC flush: after all stages go idle (totalInFlight==0),
  calls writeCoordinator_->flush(15s) to drain remaining entity writes
  before benchmark queries start.

- DeferredKGBatch forward-declared in PostIngestQueue header.

* ci: fix free-disk-space action ref, sha didnt exist

* fix(search): revert WC accumulation, fix text fallback to per-doc writes

The shared-batch WC accumulation approach worked conceptually but:
- WC flush with totalInFlight==0 fires too early (before last batch)
- generateFallbackQueryConcepts produces empty concepts for 99% of
  document texts (designed for short queries, not abstracts)
- Only 1/5183 docs produced concepts → 1 doc worth of entities in KG

Revert to simple per-doc entity extraction. The enable=/disable=
graph reranker gate is still controlled by shortQueryBudgeted=1
which zeroes the graph reranker on the first query (intent=Code).

firstDocEntities=0 persists — entities need a different creation
strategy for document text (phrase mining too conservative).

* fix(docker): add curl retry for Zig download

* feat(search): per-profile ConceptExtractionBackend (Fallback vs GlinerWithFallback)

- search_engine_config.h: new ConceptExtractionBackend enum with Fallback
  (sub-phrase mining + IDF tokens, <1ms) and GlinerWithFallback (GLiNER
  first, fall back on empty/timeout). Default: GlinerWithFallback.

- search_tuner.h: SCIENTIFIC profile sets Fallback (GLiNER returns empty
  for 99% of short biomedical claims). Other profiles keep default.
  Wired through TunedParams.applyTo().

- search_engine.cpp: gate GLiNER concept extraction on the config backend.
  When Fallback, conceptFuture is never created and concepts come directly
  from generateFallbackQueryConcepts. Added [concept-backend] diagnostic.

- search_engine_builder.cpp: builder log now includes concept_backend
  in the override-state startup message.

- search_tuner_catch2_test.cpp: verify SCIENTIFIC profile uses Fallback.

Note: builder correctly sets Fallback but query-time workingConfig still
shows GlinerWithFallback (int=1). This is a config-sync issue between
builder-time profile application and runtime config snapshot — the
tuner or a post-override config copy may reset the field. To be fixed.

* refactor(search): extract concept resolver, per-profile backend, clean dead code

- New concept_resolver.h/cpp: extract enrichWithFallbackConcepts from the
  search engine monolith into a testable unit. Generates IDF-weighted
  token concepts via generateFallbackQueryConcepts, deduplicates, and
  appends to existing concepts.

- search_engine_config.h: new ConceptExtractionBackend enum (Fallback vs
  GlinerWithFallback). SCIENTIFIC profile sets Fallback since GLiNER
  extracts 0 concepts for 99% of short biomedical claims.

- search_tuner.h: wire conceptExtractionBackend through TunedParams,
  applyTo, seedTunedParamsFromConfig (the one-line fix that resolved
  the config-sync bug where profile Fallback was overridden at query
  policy resolution time).

- search_engine.cpp: materializeConcepts lambda restructured to always
  reach the fallback even when GLiNER future is invalid. Removed
  ~80 lines of diagnostic bloat ([concept-backend], [workingConfig-*],
  per-50 [concepts]). GLiNER gate checks config backend.

- PostIngestQueue.cpp: removed dead fast-token entity extraction
  (~150 lines of concept generation + KG scaffolding that produced
  0 entities for 99% of documents). Reverted entity-stage gating
  (entityCapable || hasTitleExtractor) and shouldDispatchEntity to
  extension-only checks. Removed DeferredKGBatch forward decl.

- gliner_query_extractor: removed unused createGlinerExtractionFunc-
  FromProvider fallback factory (~150 lines).

- ServiceManager.cpp: removed fallback call site for removed factory.

- builder log: removed concept_backend diagnostic line noise.

- search_tuner_catch2_test.cpp: verify SCIENTIFIC uses Fallback.

Net: ~400 lines removed, ~120 lines added (concept_resolver unit +
config wiring). GLiNER concept extraction savings: ~30-80ms/query
× 300 queries = 9-24s total for SCIENTIFIC profiles.

* fix: entity stage only for binaries, title stage for text

entity stage = binary providers (Ghidra/Zyp). title stage = GLiNER for all
text. No overlap — title already stores NL entities to KG.

* fix(docker): add wget for Zig, disable faiss

openblas arm64 build fails in Docker containers. YAMS_DISABLE_FAISS=1
env var skips faiss (and its openblas transitive dep). Zig download
now uses wget -c for resume on flaky ziglang.org connections.

* ci: add experimental branch to tests trigger

* ci: pin free-disk-space to v1.3.1

* feat: Simeon concept mining entity export for graph reranker

- simeon_lexical_backend.h: EntityCallback in Config. Called with
  (docId, entityText, confidence) per concept match per doc.

- simeon_lexical_backend.cpp: after mine_concepts, iterate docs
  via collect_doc_concepts + entity_callback.

- SearchEngineManager.cpp: enable concept_mining_enabled, wire
  entity_callback batch-inserting DocEntity via KG store. Fix
  kgStore capture-before-move race.

Note: simeon submodule has collect_doc_concepts in concept_mining.hpp
+ concept_mining.cpp (must commit to submodule separately).

* ci: disable faiss in warm and test jobs

* ci(bench): add faiss disable, ccache, and failure diagnostics to weekly benchmarks

* fix(metadata): retry constraint failures in executeQueryOnPool

FK race on Linux causes transient constraint failures when metadata
write races ahead of document commit. Previously treated as terminal.
Now retried with backoff like lock errors.

* fix(metadata): deduplicate batch entries before UPSERT

Duplicate (document_id, key) pairs within a single batch cause SQLite
ON CONFLICT DO UPDATE to fail with constraint violation. Dedup keeps
the last write per key.

* chore: bump simeon, add extraction readiness stats

Simeon: 8bf225e -> 6320ab6 (adapter + QPP router framework).
CorpusStats: add contentExtracted*, ftsIndexed*, titleCoverage,
languageCoverage, and KG topology richness fields.

* feat(search): integrate simeon EntropyRouter strategy lane, corpus-state tuning

- Wire EntropyRouter + Keyphrase/LeadField strategies into SimeonLexicalBackend
- Add scoreStrategyRouted(), hasStrategyRouter(), strategy_router_enabled config
- Add YAMS_SIMEON_STRATEGY_ROUTER_ENABLED env wiring
- Add applyCorpusStateAdjustments(): per-corpus-state recall push (vec max,
  rescue slots, weak-query fanout, entity vec expansion, NER damping)
- Extend CorpusStats with extraction/FTS/title/language/KG edge+alias density
- Add hasRichGraphTopology(), nerOnlyNoEdges damping to graph adjustments
- Add 14 new engine-policy benchmark candidates (retrieval lanes, RRF sweep,
  aggressive recall, strategy router)
- Weight miss_pre_fusion_rate in optimization objective (0.25x)
- Add Simeon lexical concept/doc count to IndexFreshnessSnapshot + status
- Bump simeon submodule (retrieval_strategy + corpus_adapter API)

* feat(search): add concept_count and concept_mining_enabled accessors

* feat(search): add ScientificAdapter + RM3 PRF blend

ScientificAdapter: training-free entity extraction for scientific
text via regex/suffix patterns (biomedical suffixes, ALL_CAPS symbols,
capitalized multi-word terms, measurements). Replaces TextAdapter
in strategy router build, providing entity lists for KeyphraseStrategy.

RM3: add score_with_prf blend path to scoreStrategyRouted at 0.30
weight when rm3_enabled=true. New benchmark candidate
scientific_strategy_rm3.

Strategy router + ScientificAdapter: mrr=0.4514 ndcg=0.4789 recall=0.5849

* docs: soften governance and contribution prose

Replace prescriptive language ('must', 'require', 'adjudicates') with
friendlier, more welcoming phrasing across governance docs, PR template,
security policy, and contributing guide.

* feat(extract): add language-agnostic IMRAD section detection, expand entity types

detectDocumentSections(): structural heuristics for title/abstract/body
using line-length, ALL_CAPS, numbering patterns. No word matching.
Works across all languages and scripts.

deriveTitle(): add IMRAD detection step before first-line fallback.
isHighValueGraphType(): use ScientificAdapter suffix detection (40+
biomedical suffixes) instead of hardcoded 11 types.

* feat(ingest): field-weighted FTS5, IMRAD claim segmentation, ScientificAdapter fallback

- FTS5: title tokens repeated 3x, abstract 2x, body 1x in content
  field for BM25 field weighting without schema migration
- IMRAD-aware claim segmentation: buildBodyClaimSegments splits
  each detected section independently, distributes maxSegments
- ScientificAdapter fallback: when GLiNER unavailable, inline
  entity extraction via suffix/pattern detection → direct KG write
- Add abstract field to PreparedMetadataEntry + BatchContentEntry

* refactor(daemon): extract enrichment stages to post_ingest_enrichment.cpp

Split PostIngestQueue.cpp (3145 lines) into:
- PostIngestQueue.cpp (~3084 lines): coordinator, lifecycle, queue
  management, extraction pipeline, gradient limiters
- post_ingest_enrichment.cpp (new, 701 lines): KG/symbol/entity/title
  stage processing with self-contained enrichment utilities

* fix(daemon): restore enrichment utilities to PostIngestQueue.cpp

Processing methods still in PostIngestQueue.cpp reference entity/NL
utilities (isUsefulNlEntity, buildBodyClaimSegments, etc.) that were
removed during decomposition. Restore them to anonymous namespace.

* fix: address PR #25 Copilot review feedback

- Add missing #include <unordered_map> to concept_resolver.cpp
- Batch entity writes per doc in SearchEngineManager (reduces write amp)
- Remove non-existent CorpusAdapter API claims from README
- Replace absolute paths with repo-relative in daemon-download-jobs.md
- Revert plugin-zyp default to false (noisy warnings)
- Fix grammar in extraction-repair-pipeline.md heading
- Add gitignore entries for .wrangler, .claude, .artifacts, papers

* fix: Copilot feedback - IDF passthrough, batch flush, debug gate, IMRAD comment

- Pass IDF map through enrichWithFallbackConcepts for weighted fallback
- Batch entity writes per doc with threshold flush in SearchEngineManager
- Downgrade graph_rerank-gate diagnostic to spdlog::debug
- Add TODO for entity_callback wiring during concept mining
- Fix DocumentSections comment to match language-agnostic implementation

* chore: bump simeon (ScientificAdapter v3)

* fix: resolve merge conflict markers, add missing <random> include

Remove leftover <<<<<<< / ======= / >>>>>>> from earlier merge.
Add #include <random> to ingestion_throughput_bench.cpp.

* chore: trigger CI after simeon submodule push
2026-05-08 05:29:46 -04:00
Trevon
72647bbaf7
chore: stabilize CI, faiss, metadata, docker, and simeon (#25)
- CI warm: ccache dep, continue-on-error, 60min timeout, YAMS_DISABLE_FAISS
- Faiss: YAMS_HAS_FAISS guard, Apple Clang disable, OpenMP detection
- Metadata: retry constraint failures, deduplicate batch UPSERT entries
- Docker: wget for Zig, gfortran, YAMS_DISABLE_FAISS=1
- CI config: free-disk-space v1.3.1, libomp-18-dev, experimental trigger
- Weekly benchmarks: faiss disable, ccache, diagnostics capture
- Simeon: bump to 7763a97, EntropyRouter, concept_count
- CorpusStats: extraction readiness fields
- Remove committed artifacts (.wrangler, .artifacts, dispatcher_external)
- Fix .vscode/settings.json hardcoded path

Signed-off-by: trvon <git@trevon.dev>
2026-05-07 21:07:59 -04:00
trvon
285c6f7607
Revert "Experimental Merge (#23)"
This reverts commit e21de6ff4a.
2026-05-07 20:44:33 -04:00
Trevon
e21de6ff4a
Experimental Merge (#23)
* feat: search work and moving to experimental

* WIP

* feat(search): diagnostic logging pipeline — graph build, concepts, reranker gate

- New [concepts] per-50-query log showing extracted query concepts, type
  distribution, and used_gliner flag.

- New [PIQ-entity] per-1000-dispatch + per-document completion log with
  entity type counts (e.g., 'protein=3, gene=1, chemical=2').

- New [graph_rerank-gate] one-shot log showing why enableGraphRerank
  is zeroed: shows shortQueryBudgeted, corpusWarming, bypassWarmingGate,
  lexicalReady, and post-ingest inflight.

- New [graph_rerank] per-50-query log with window size, matched
  candidates, applied count, concept count, and elapsed time.

- retrieval_quality_bench.cpp: add YAMS_SEARCH_BYPASS_CORPUS_WARMING_GATE=1
  so benchmark queries are not gated by freshness checks.

- resolve merge conflicts from experimental branch.

* fix(search): enable entity extraction for text files via GLiNER fallback

- prepareMetadataEntry: shouldDispatchEntity now also checks hasTitleExtractor()
  so plain-text files (.txt, .md) get entity extraction even when no binary
  entity provider supports their extension.

- processEntityExtractionStage: when no ExternalEntityProvider matches,
  fall back to processTitleExtractionStage which runs GLiNER on text.

- refreshStageAvailability: entity stage is now considered capable when
  hasTitleExtractor() is true, so the entity poller gets concurrency budget
  even if entityProviders_ is empty.

- kCombinedEntityTypes: add biomedical entity types (protein, gene, cell,
  disease, chemical, drug, pathway, biological_process, biomarker, anatomy,
  organism) so GLiNER extracts high-value biomedical entities instead of
  only generic NL types (person, organization, concept).

* perf(bench): add YAMS_POST_ENTITY_CONCURRENT=4 for text entity fallback throughput

* feat(search): fast token-based entity extraction for text documents

- Replace slow GLiNER-based entity extraction (~260ms/doc) with fast
  token-based concept mining (~1ms/doc) via generateFallbackQueryConcepts.
  Uses sub-phrase mining + IDF-weighted token salience — the same function
  already used for query-time concept fallback.

- Store entities with full KG scaffolding: KGNode with entity type/label,
  KGAlias for query-time resolution, DeferredEdge from entity→document,
  and DeferredDocEntity linking entity to document for getDocEntitiesForDocument.

- Add biomedical entity types to kCombinedEntityTypes in title extraction
  (protein, gene, cell, disease, chemical, drug, pathway, etc.) so GLiNER
  can output high-value biomedical entities when used.

- Add include for query_expansion.h to access generateFallbackQueryConcepts.

- bench: add YAMS_POST_ENTITY_CONCURRENT=4 for entity poller throughput.

Benchmark: 22K+ entities extracted across 5183 docs, ~41% high-value
biomedical. MRR 0.4281 (beats 0.4273 baseline by +0.2%).

* feat(diag): add firstDocEntities check to graph_rerank-gate log

- Queries kg_doc_entities for the first candidate document to verify
  whether fast entity writes were committed before queries start.
- Confirmed: firstDocEntities=0 — entities stuck in WriteCoordinator
  async queue when benchmark queries begin.

* fix(search): add periodic write-coordinator flush during entity extraction

Entity writes enqueued via writeCoordinator_ can accumulate since the
writer loop is capped at 8 batches/iteration. For 5K+ documents this
creates a backlog that outlasts the post-ingest drain wait — entities
are not committed to kg_doc_entities before benchmark queries start.

Add a periodic flush (every 128 batches, 500ms timeout) in the entity
extraction batch processor to drain the WC queue incrementally.

Diagnostic confirms firstDocEntities=0 persists — a synchronous
committed flush or batched WC enqueue is needed.

* fix(docker): add gfortran for openblas arm64 build

* fix(search): accumulate entity writes into shared WC batch, flush once

The WriteCoordinator writer loop is capped at 8 batches/iteration. With
5K+ per-doc entity writes, entities outlast the benchmark's post-ingest
drain and firstDocEntities=0 when the graph scorer runs.

- processEntityExtractionStage: add optional DeferredKGBatch* parameter.
  Text-fallback appends entity nodes/aliases/edges/doc-entities to the
  shared batch instead of creating per-doc WC batches.

- processEntityExtractionBatch: creates one DeferredKGBatch, passes it to
  all stage calls in the batch, enqueues to WC once at end.

- Single-shot WC flush: after all stages go idle (totalInFlight==0),
  calls writeCoordinator_->flush(15s) to drain remaining entity writes
  before benchmark queries start.

- DeferredKGBatch forward-declared in PostIngestQueue header.

* ci: fix free-disk-space action ref, sha didnt exist

* fix(search): revert WC accumulation, fix text fallback to per-doc writes

The shared-batch WC accumulation approach worked conceptually but:
- WC flush with totalInFlight==0 fires too early (before last batch)
- generateFallbackQueryConcepts produces empty concepts for 99% of
  document texts (designed for short queries, not abstracts)
- Only 1/5183 docs produced concepts → 1 doc worth of entities in KG

Revert to simple per-doc entity extraction. The enable=/disable=
graph reranker gate is still controlled by shortQueryBudgeted=1
which zeroes the graph reranker on the first query (intent=Code).

firstDocEntities=0 persists — entities need a different creation
strategy for document text (phrase mining too conservative).

* fix(docker): add curl retry for Zig download

* feat(search): per-profile ConceptExtractionBackend (Fallback vs GlinerWithFallback)

- search_engine_config.h: new ConceptExtractionBackend enum with Fallback
  (sub-phrase mining + IDF tokens, <1ms) and GlinerWithFallback (GLiNER
  first, fall back on empty/timeout). Default: GlinerWithFallback.

- search_tuner.h: SCIENTIFIC profile sets Fallback (GLiNER returns empty
  for 99% of short biomedical claims). Other profiles keep default.
  Wired through TunedParams.applyTo().

- search_engine.cpp: gate GLiNER concept extraction on the config backend.
  When Fallback, conceptFuture is never created and concepts come directly
  from generateFallbackQueryConcepts. Added [concept-backend] diagnostic.

- search_engine_builder.cpp: builder log now includes concept_backend
  in the override-state startup message.

- search_tuner_catch2_test.cpp: verify SCIENTIFIC profile uses Fallback.

Note: builder correctly sets Fallback but query-time workingConfig still
shows GlinerWithFallback (int=1). This is a config-sync issue between
builder-time profile application and runtime config snapshot — the
tuner or a post-override config copy may reset the field. To be fixed.

* refactor(search): extract concept resolver, per-profile backend, clean dead code

- New concept_resolver.h/cpp: extract enrichWithFallbackConcepts from the
  search engine monolith into a testable unit. Generates IDF-weighted
  token concepts via generateFallbackQueryConcepts, deduplicates, and
  appends to existing concepts.

- search_engine_config.h: new ConceptExtractionBackend enum (Fallback vs
  GlinerWithFallback). SCIENTIFIC profile sets Fallback since GLiNER
  extracts 0 concepts for 99% of short biomedical claims.

- search_tuner.h: wire conceptExtractionBackend through TunedParams,
  applyTo, seedTunedParamsFromConfig (the one-line fix that resolved
  the config-sync bug where profile Fallback was overridden at query
  policy resolution time).

- search_engine.cpp: materializeConcepts lambda restructured to always
  reach the fallback even when GLiNER future is invalid. Removed
  ~80 lines of diagnostic bloat ([concept-backend], [workingConfig-*],
  per-50 [concepts]). GLiNER gate checks config backend.

- PostIngestQueue.cpp: removed dead fast-token entity extraction
  (~150 lines of concept generation + KG scaffolding that produced
  0 entities for 99% of documents). Reverted entity-stage gating
  (entityCapable || hasTitleExtractor) and shouldDispatchEntity to
  extension-only checks. Removed DeferredKGBatch forward decl.

- gliner_query_extractor: removed unused createGlinerExtractionFunc-
  FromProvider fallback factory (~150 lines).

- ServiceManager.cpp: removed fallback call site for removed factory.

- builder log: removed concept_backend diagnostic line noise.

- search_tuner_catch2_test.cpp: verify SCIENTIFIC uses Fallback.

Net: ~400 lines removed, ~120 lines added (concept_resolver unit +
config wiring). GLiNER concept extraction savings: ~30-80ms/query
× 300 queries = 9-24s total for SCIENTIFIC profiles.

* fix: entity stage only for binaries, title stage for text

entity stage = binary providers (Ghidra/Zyp). title stage = GLiNER for all
text. No overlap — title already stores NL entities to KG.

* fix(docker): add wget for Zig, disable faiss

openblas arm64 build fails in Docker containers. YAMS_DISABLE_FAISS=1
env var skips faiss (and its openblas transitive dep). Zig download
now uses wget -c for resume on flaky ziglang.org connections.

* ci: add experimental branch to tests trigger

* ci: pin free-disk-space to v1.3.1

* feat: Simeon concept mining entity export for graph reranker

- simeon_lexical_backend.h: EntityCallback in Config. Called with
  (docId, entityText, confidence) per concept match per doc.

- simeon_lexical_backend.cpp: after mine_concepts, iterate docs
  via collect_doc_concepts + entity_callback.

- SearchEngineManager.cpp: enable concept_mining_enabled, wire
  entity_callback batch-inserting DocEntity via KG store. Fix
  kgStore capture-before-move race.

Note: simeon submodule has collect_doc_concepts in concept_mining.hpp
+ concept_mining.cpp (must commit to submodule separately).

* ci: disable faiss in warm and test jobs

* ci(bench): add faiss disable, ccache, and failure diagnostics to weekly benchmarks

* fix(metadata): retry constraint failures in executeQueryOnPool

FK race on Linux causes transient constraint failures when metadata
write races ahead of document commit. Previously treated as terminal.
Now retried with backoff like lock errors.

* fix(metadata): deduplicate batch entries before UPSERT

Duplicate (document_id, key) pairs within a single batch cause SQLite
ON CONFLICT DO UPDATE to fail with constraint violation. Dedup keeps
the last write per key.

* chore: bump simeon, add extraction readiness stats

Simeon: 8bf225e -> 6320ab6 (adapter + QPP router framework).
CorpusStats: add contentExtracted*, ftsIndexed*, titleCoverage,
languageCoverage, and KG topology richness fields.

* feat(search): integrate simeon EntropyRouter strategy lane, corpus-state tuning

- Wire EntropyRouter + Keyphrase/LeadField strategies into SimeonLexicalBackend
- Add scoreStrategyRouted(), hasStrategyRouter(), strategy_router_enabled config
- Add YAMS_SIMEON_STRATEGY_ROUTER_ENABLED env wiring
- Add applyCorpusStateAdjustments(): per-corpus-state recall push (vec max,
  rescue slots, weak-query fanout, entity vec expansion, NER damping)
- Extend CorpusStats with extraction/FTS/title/language/KG edge+alias density
- Add hasRichGraphTopology(), nerOnlyNoEdges damping to graph adjustments
- Add 14 new engine-policy benchmark candidates (retrieval lanes, RRF sweep,
  aggressive recall, strategy router)
- Weight miss_pre_fusion_rate in optimization objective (0.25x)
- Add Simeon lexical concept/doc count to IndexFreshnessSnapshot + status
- Bump simeon submodule (retrieval_strategy + corpus_adapter API)

* feat(search): add concept_count and concept_mining_enabled accessors

* feat(search): add ScientificAdapter + RM3 PRF blend

ScientificAdapter: training-free entity extraction for scientific
text via regex/suffix patterns (biomedical suffixes, ALL_CAPS symbols,
capitalized multi-word terms, measurements). Replaces TextAdapter
in strategy router build, providing entity lists for KeyphraseStrategy.

RM3: add score_with_prf blend path to scoreStrategyRouted at 0.30
weight when rm3_enabled=true. New benchmark candidate
scientific_strategy_rm3.

Strategy router + ScientificAdapter: mrr=0.4514 ndcg=0.4789 recall=0.5849
2026-05-07 20:36:10 -04:00
trvon
8fd830e9a9
feat(search): integrate simeon EntropyRouter strategy lane, corpus-state tuning
- Wire EntropyRouter + Keyphrase/LeadField strategies into SimeonLexicalBackend
- Add scoreStrategyRouted(), hasStrategyRouter(), strategy_router_enabled config
- Add YAMS_SIMEON_STRATEGY_ROUTER_ENABLED env wiring
- Add applyCorpusStateAdjustments(): per-corpus-state recall push (vec max,
  rescue slots, weak-query fanout, entity vec expansion, NER damping)
- Extend CorpusStats with extraction/FTS/title/language/KG edge+alias density
- Add hasRichGraphTopology(), nerOnlyNoEdges damping to graph adjustments
- Add 14 new engine-policy benchmark candidates (retrieval lanes, RRF sweep,
  aggressive recall, strategy router)
- Weight miss_pre_fusion_rate in optimization objective (0.25x)
- Add Simeon lexical concept/doc count to IndexFreshnessSnapshot + status
- Bump simeon submodule (retrieval_strategy + corpus_adapter API)
2026-05-07 20:14:59 -04:00
trvon
342a3f8fae
chore: bump simeon, add extraction readiness stats
Simeon: 8bf225e -> 6320ab6 (adapter + QPP router framework).
CorpusStats: add contentExtracted*, ftsIndexed*, titleCoverage,
languageCoverage, and KG topology richness fields.
2026-05-07 20:14:02 -04:00
trvon
faee34ef79
security: additional security fixes 2026-05-01 21:12:07 -04:00
trvon
ff10c70d45
tests: test fixes and simeon version bump 2026-05-01 16:05:27 -04:00
trvon
c55ce54b87
fix: ci fixes and experiment for search / cluster routing 2026-04-28 01:29:48 -04:00
trvon
36152546b0
fix: simeon bump and double lock addressed in search 2026-04-25 16:10:17 -04:00
trvon
84015b39b7
build(ci,tests): cleaning build system and updates related to ci test failures and compat 2026-04-25 14:48:44 -04:00
trvon
49b40d5471
fix(ci): ci build fixes for windows, linux, macos tests lanes 2026-04-25 12:55:02 -04:00
trvon
9b774d6073
feat: profiling improvements 2026-04-24 23:23:02 -04:00
trvon
8de19b84f0
feat: adding instrumentation and config options for build and repair system. Bumping simeon and improving topology system with experimental findings 2026-04-24 17:38:24 -04:00
trvon
2ced7a7e5c
feat: reinforcing proxy path for quick ux, adding topology tuning engine for corpus cluster usage in search, simeon memory management improvements 2026-04-23 17:33:47 -04:00
trvon
e88578a9fc
feat: adding support for phss vector search, test fixes, daemon status regression fix, ci fixes for docker builds with new third-party library 2026-04-23 11:02:18 -04:00
trvon
127bc9e9e0
fix: fixing leakage of build artifacts in release, unifying repair path, adding cache to tuning path and bumping simeon version 2026-04-23 10:20:25 -04:00
trvon
0eeed2ed41
feat: bumping simeon module and linking new fragmented strategy 2026-04-23 08:58:14 -04:00
trvon
be0feac605
feat: refactor vector engine to reduce monoliths in codebase 2026-04-22 08:36:55 -04:00
trvon
1b6f137132
fix: prune fixes for build artifacts, readiness improvements and hnsw api unification 2026-04-21 17:03:58 -04:00
trvon
801980ce11
fix: fixing onnx model logic so that memory does not hold indefinitely. Removing re-ranker logic from plugin 2026-04-21 11:49:12 -04:00
trvon
6fa8b037b0
feat: removing other graph clustering algorithms for hdbscan with sgc 2026-04-21 10:20:00 -04:00
trvon
94c8e6a9db
feat(linter): running linter on codebase 2026-04-20 16:13:30 -04:00
trvon
6cdba45660
feat: vendoring hdbscan for clustering of documents, refactor duplicate code logic in cli and daemon paths, topology instrumentation 2026-04-20 15:59:47 -04:00
trvon
3ac9bd68b8
feat: graph clustering improvements for topology system. Checkpoint before experiment with better clustering systems and simeon module bump 2026-04-20 11:31:40 -04:00
trvon
a01bd767ce
feat: bumping simeon, improving graph building, clustering, configuration tuning of said system and updating benchmark files. Additional fixes for daemon readiness and status return underload. 2026-04-20 09:31:45 -04:00
trvon
e4a8639ef6
feat: tuning topology system to work better with simeon via configuration 2026-04-19 20:10:46 -04:00