# Vector Desk > Audit one vector index against its recall, latency and memory budgets - does the engine accept it, does every query use it and get the rows it asks for, does it fit its memory, and does the evidence support the chosen setting - then fix it. The free check runs in the browser and uploads nothing: it reads pasted pgvector SQL, Qdrant collection and search bodies, FAISS or hnswlib code, a workload file with the vector count and the budgets, and a parameter sweep, and runs 23 deterministic checks drawn from vector index tuning practice. The paid audit rates the index configuration, the search settings, the memory and the evidence, names the operating point (a sweep row inside every budget), confirms or dismisses every flag and gives exact before/after edits per finding; the paid fix lane writes the whole fixed file(s) and a changes list tied to the flags. The page checks every quote and line against the paste, applies every edit and file back into the paste and re-runs its checks - including that every table, column, index and collection is still there, that the workload and the sweep were not rewritten and that no file was added - and calls out a reply that repeats a credential from the paste. App: https://vector-desk.skillsafe.ai/ API tutorial: https://vector-desk.skillsafe.ai/api.html ## Input - The files pasted into one box, each introduced by a `# file: ` line (`# file: db/schema.sql`, `# file: qdrant/collection.json`, `# file: index/build_index.py`, `# file: workload.yaml`, `# file: bench/sweep.csv`); dropped files or a dropped folder are joined that way automatically (vector data, index files and other files are skipped). A paste with no `# file:` line is read as one file, named by what it looks like. - The kind comes from the path: `.sql` is pgvector SQL, `.json` a Qdrant body (optionally after a `PUT /collections/` or `POST /collections//points/query` line; a `GET` collection response with `result.config` is read too), `.py` FAISS or hnswlib code, `workload.*` the workload, `.csv` / `.tsv` the sweep. - SQL is split into statements with comments ignored: `CREATE TABLE` vector, halfvec, bit and sparsevec columns, `CREATE INDEX ... USING hnsw | ivfflat (column opclass) WITH (...)` (including a cast expression), `SET [LOCAL] hnsw.ef_search | ivfflat.probes | hnsw.iterative_scan ...`, and every `SELECT ... ORDER BY column ... LIMIT n` with its WHERE. - Python is read line by line: `faiss.index_factory(d, "...")` strings (HNSW, IVF, PQ, SQ, OPQ/PCA, RFlat), the `faiss.Index*` constructors, `nprobe`, `hnsw.efSearch`, `hnsw.efConstruction`, `IndexRefineFlat`, `faiss.normalize_L2`, `index.search(q, k)`, and `hnswlib.Index` with `init_index` and `set_ef`. Integer constants assigned at the top of the file are resolved. - The workload is `key: value` lines: `vectors` (12M, 4.2 million, 250k), `dimensions`, `k`, `target_recall` (0.95 or 95%), `p99_ms`, `memory_gb` (GiB), `qps`, `normalized`, `metric`, `filter_selectivity`, `model`. - The sweep is a CSV with a header: `m`, `ef_construction`, `ef_search` (or `hnsw_ef`, `ef`), `nprobe`, `recall` or `recall@10`, `p50_ms`, `p99_ms`, `memory_gb` or `memory_mb`, `qps`. - Nothing is built, loaded or queried: every flag is a reading of the text, with the file and line it points at. The memory figure is an estimate from the parameters. The servers, the data distribution and the engine version are not visible: VX-24 says so, and the note is where you give facts ("we run pgvector 0.8.0", "the embeddings are unit length"). ## Flags the free check raises - VX-01 (high): pgvector options it refuses - HNSW m outside 2..100, ef_construction outside 4..1000 or below 2 * m, IVFFlat lists outside 1..32768, hnsw.ef_search outside 1..1000, an iterative_scan value other than off, strict_order or relaxed_order. - VX-02 (high): a pgvector index on vector columns over 2,000 dimensions (halfvec over 4,000, bit over 64,000), with the halfvec cast that fixes it. - VX-03 (high): an index whose dimensions differ from the workload's. - VX-04 (medium): pgvector IVFFlat lists more than 4x away from rows / 1000 (up to 1M rows) or sqrt(rows); FAISS IVF with fewer than 39 vectors per list. - VX-05 (medium): a FAISS flat index over a million vectors or more; full-precision HNSW over 100M vectors; a pgvector query ordering by distance on a column with no pasted HNSW or IVFFlat index (low when the row count is unknown). - VX-06 (high): PQ sub-quantizers that do not divide the dimension (after an OPQ or PCA output size). - VX-07 (high): a credential written into a file - an API key, token or password literal, a role PASSWORD, a password in a connection URL. The value is masked as *** everywhere the page shows it. - VX-08 (high): pgvector hnsw.ef_search (40 by default) below the query's LIMIT (or the workload's k when the LIMIT is a parameter): the HNSW scan returns at most ef_search rows. - VX-09 (high): a pgvector ORDER BY operator that does not match any index opclass on the column (<-> l2, <#> ip, <=> cosine, <+> l1): the query cannot use the index. - VX-10 (high): an index metric that differs from the workload's metric when the vectors are not known to be unit length (low when they are); (medium) inner product over vectors the workload says are not normalized; FAISS inner product for cosine without faiss.normalize_L2. - VX-11 (medium): pgvector ivfflat.probes unset or 1 for an IVFFlat index a query uses; FAISS IVF with nprobe unset or 1. - VX-12 (medium): a pgvector query with WHERE and ORDER BY distance on an approximate index without hnsw.iterative_scan (or ivfflat.iterative_scan). - VX-13 (medium): a Qdrant search over quantized vectors with "rescore": false, or FAISS PQ without refinement, at a target recall of 95% or more (low when the target is unknown). - VX-14 (medium): a Qdrant search with "exact": true. - VX-15 (high): the estimated resident memory of the main index over the workload's memory budget (low above 85% of it). - VX-16 (low): a million or more full-precision float32 vectors taking 8 GiB or more without quantization. - VX-17 (medium): a Qdrant collection with quantization and on-disk originals whose quantized vectors are not always_ram. - VX-18 (high): no sweep row reaches the target recall. - VX-19 (medium): the configured setting is a sweep row that misses a budget while another row meets every budget. - VX-20 (medium): recall falls by more than half a point as ef or nprobe rises at fixed build parameters. - VX-21 (high): every sweep row that reaches the recall target is over the p99 budget. - VX-22 (medium): the sweep's recall@k differs from the k the queries ask for. - VX-23 (low): no workload file, or a workload without vectors, target_recall, p99_ms or memory_gb (those checks are skipped). - VX-24 (info): context - counts, the vector count, the estimate, files that could not be read, what is outside the check. ## Free extras - Every index with its type, metric, dimensions, build and search parameters; every query with what it asks for and the index it can use; the memory estimate part by part; the sweep with the configured row and the cheapest row inside every budget; every file. - Put any audit finding (or all of them, or the fixed files) back into the paste and re-run the check; undo puts the original back. - Exports: the check as Markdown, the flags as CSV, the edited or fixed files, the changes as a unified diff for git apply, the findings or changes as CSV, the whole result as JSON. ## Paid lanes (the `task` field) - `audit`: `{task, verdict: blocked|needs_work|ready, headline, index, areas: [{area: config|search|memory|evidence, status: sound|fragile|broken, note}], operating_point: {row, m, ef_construction, ef_search, nprobe, recall, p99_ms, memory_gib, why}, findings: [{id, flags, file, line, severity, area, title, evidence, why, edits: [{before, after}]}], flag_answers: [{flag, status: confirmed|dismissed, reason}], plan, questions, summary}`. `before` is an exact slice of the file, applied in order; the operating point quotes a real sweep row inside every budget (or row null). - `fix`: `{task, verdict: fixed|partial, headline, files: [{path, content}], changes: [{file, object, flags, change, why}], verify, open: [{item, flags, reason}], questions, summary}`. `content` is the whole file; no file is added, the workload and the sweep are never returned, and every table, column, index and collection stays. - Run input: `{task, code, facts, note?, audit_handoff?, retry_note?}` - all strings; `facts` is the page's analysis as a JSON string. The audit hands its findings to the fix lane with every edit applied to `code`. - The model never invents a measurement - a recall, a latency or a memory size comes from the workload, the sweep, the estimate or the note; a parameter it picks without a sweep is a starting point to measure. - Model: gpt-terra, 10% publisher markup. A run needs a signed-in account; the reservation shown before a run is a hold, and only what the run uses is charged. ## Sources - vector-index-tuning by Seth Hobson, wshobson/agents (github.com/wshobson/agents, plugins/llm-application-dev/skills/vector-index-tuning), MIT - https://skillsafe.ai/skill/@wshobson/vector-index-tuning - The checks and the reconciliation are original to this app. pgvector, Qdrant, FAISS and hnswlib are projects of their own authors; this app is not affiliated with or endorsed by any of them.