Addresses both Phase-4 security findings on the GGUF download curl
fallbacks (crates/ruvllm-cli/src/commands/download.rs):
- MED (CWE-214): the Authorization: Bearer header was passed as a curl
-H argument, leaving HF_TOKEN world-readable via ps / /proc/<pid>/cmdline
for the curl process lifetime. Both call sites (download_via_curl and
list_files_via_curl) now pass the header through a curl config fed on
stdin (--config -), built by curl_auth_config() which escapes quotes,
backslashes, and CR/LF so a hostile token value cannot inject extra
config directives. Behavior when HF_TOKEN is unset is unchanged (no
config, no --config flag).
- LOW: remote-controlled file names from the HF tree/siblings listing
were joined into the cache path unchecked. validate_remote_file_name()
rejects empty names and any non-Normal component (absolute, .., .,
prefixes) before the join, and ensure_under_cache_dir() verifies the
canonicalized parent still resolves under the model cache dir after
create_dir_all.
Tests: 5 new unit tests (hostile-name rejection incl. "../x", "/abs",
"a/../../x"; containment check; curl config content + escaping);
all 31 pass, clippy and fmt clean. Manually verified `ruvllm download
hf-internal-testing/tiny-random-gpt2 --quantization none` end-to-end and
that --config-on-stdin delivers the Authorization header.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012Jib2gQyJpqCoo2xYAbb4X
GGUF weight downloads failed two ways (deferred in 946275a61, blocks WP9 #841):
1. get_files_to_download() pushed an unexpanded glob ("*Q4_K_M.gguf") that was
sent to HF as a literal filename -> 404. Now the repo's actual file list is
fetched (hf-hub ApiRepo::info(), with a curl fallback against
GET /api/models/<id>/tree/<rev> in the same HF_TOKEN-honoring idiom as the
307-redirect fix) and the quant pattern is matched against real filenames.
Multi-part GGUF (…-q4_k_m-00001-of-00003.gguf) is handled — all parts are
downloaded in order — because the flagship `qwen` alias (Qwen2.5-14B) only
ships Q4_K_M as a 3-part split; failing on multi-part would leave the
primary model unusable. Matching is case-insensitive and accepts per-preset
spelling variants (f16/fp16). Aux files (tokenizer.json etc.) are filtered
by the listing, so GGUF-only repos no longer fail on files they don't have.
2. The `phi` alias maps to microsoft/Phi-4-mini-instruct (safetensors-only),
yet the default q4k quant forced the GGUF path. The registry gains an
optional gguf_repo twin (bartowski GGUF repos for phi/mistral/llama; all
verified live against the HF tree API) and resolve_weights_repo() routes
quantized requests there. chat/serve use the same resolution so the cache
key matches download's. Repos with no GGUF files and no twin now fail
early with the repo's actual file inventory and an actionable hint,
instead of a 404 on a glob.
ADR-259's "Honest gap" is updated: the 307 redirect was fixed 2026-06-18
(946275a61, PR #590); this closes the remaining GGUF gap.
Tests: 11 new unit tests (tree-JSON fixture parsing, multi-part glob
expansion + ordering, uppercase/lowercase naming, fp16 variant, no-GGUF and
missing-quant error listings, aux filtering, alias-routing decisions).
Verified live: `download microsoft/Phi-4-mini-instruct` routes to the twin
and fetches the real 2.5GB Q4_K_M; `download microsoft/phi-2` fails early
listing available files.
Refs #846, #841, ADR-259.
Co-Authored-By: claude-flow <ruv@ruv.net>
The terminate-after cap added in #822 (10 minutes) was sized for the
regular shards and killed legitimately long tests on the first sharded
run of main: ruvector-mincut subpolynomial tests and
ruvector-nervous-system pattern_separation_collision_rate all TIMEOUT
at exactly 600s in run 31714159600, failing ml-research-heavy and
core-and-rest-heavy. Historical successful runs of those shards take
up to ~75 minutes with individual tests exceeding 10 minutes by design.
Scope a slow-timeout override to the 13 packages of the two heavy
shards: 300s SLOW reporting period, killed after 18 periods (90 min) —
still bounding a genuine hang at 1.5h instead of the 4h job budget.
Co-Authored-By: claude-flow <ruv@ruv.net>
Doc corrections (merge gate for PR #824):
- State the actual threat model everywhere: receipts detect post-issuance
mutation of a receipt/result pair; they do NOT protect against a
dishonest query engine and do NOT prove write-chain membership. Leaves
commit to COPIES of WriteReceipt fields and verification never consults
the write gate, so a mutated ingestion history leaves already-issued
receipts verifying. Named future work: bind leaves to MerkleGate's MMR
membership proofs (HashChainGate::verify_receipt needs the live chain;
no offline membership proof exists).
- Soften "verifiable offline without trusting the query engine" to match
reality (unsigned, engine-chosen leaves).
- Relabel the 2x/2.1x benchmark comparison: PerResultReceipt proof size
is defined as genesis-anchored replay O(idx); a head-anchored verifier
needs only the O(k-idx) suffix, so the durable claim is asymptotic
O(log k) vs O(k), not the constant. Reframe 200/200 tamper detection
as a SHA-256 regression check, not an empirical rate (incl. ADR-304
Rejection Criteria).
- Reword ADR-304 Evidence line citing
index_state_root_changes_receipts_across_reingestion (that test
compares roots only; it builds no receipt).
- Applications table: legal/medical row no longer marketed as
chain-of-custody.
Code fixes:
- verify_full now fails closed on empty result sets (was vacuously true);
documented + tested for all variants.
- RetrievalIndex::search uses total_cmp instead of
partial_cmp().unwrap() (NaN no longer panics a public API).
- gate_variant is bound into each result leaf so a NullGate receipt
(all-zero commitment) is distinguishable from a gated one; tested.
Tests: 14 passed (was 12). Clippy -D warnings and fmt clean.
Co-Authored-By: claude-flow <ruv@ruv.net>
Review (measured, with rebuilt crate) found the PoC's headline claim does not
hold: EntropyScaledEf computes ef_actual=122-124 for every query — no per-query
adaptivity — and FixedEf(124) reproduces its recall to four decimal places on
all three query sets. The reported +1.6-3.9pp recall gain was entirely the
2.5x larger ef budget, not entropy. Entropy separation between easy and hard
queries is negative at every usable temperature (softmin entropy over
retrieved-neighbour distances tracks local density, wrong sign for beam
control); T=0.1 is effectively infinite temperature on this data.
Fixes applied:
- graph.rs: add FlatGraph::is_empty() (clippy len_without_is_empty CI blocker),
use it in find_entry
- benchmark.rs: move ground_truth() out of the timed closure (it was ~41% of
reported time, hiding a real ~50% search-only latency regression); add
FixedEf(124, matched) control rows so the adaptive claim is falsifiable
- lib.rs: recall_at_k denominator is now min(k, |ground_truth|) only — no
longer shrinks with |results|, which rewarded early termination
- search.rs: fix doc/code mismatch (scale uses ln(|results|), docs said ln(k));
document measured outcomes on both entropy variants
- tests: graph_is_symmetric_on_uniform now asserts the reciprocity fraction it
computes; renamed entropy_threshold_exits_early_on_easy_query and
entropy_scaled_ef_expands_for_hard_queries to match what they actually test
- ADR-303: status now 'Closed — negative result'; removed 'recommended' and
'validated in the PoC benchmark' for Strategy B and the false 'same nominal
ef budget' claim; documented the matched-budget equivalence and wrong-sign
finding; marked the multi-layer-HNSW rescue as untested conjecture
- research README + gist: results regenerated with honest search-only timing
(FixedEf(50) ~33us vs EntropyScaledEf ~50us) and matched-budget comparison
cargo test / clippy -D warnings / fmt --check all pass.
Co-Authored-By: claude-flow <ruv@ruv.net>
The `core-and-rest` catch-all shard was not sharding. Its `packages:` value
is a YAML folded scalar (`>-`) that contained `#`-prefixed lines *inside*
the scalar. Those are content, not YAML comments: folding joins the whole
block onto one line, and when `run:` expands `${{ matrix.packages }}` the
shell treats the first `#` as the start of a comment and truncates the rest
of the command.
The effective command was therefore:
cargo nextest run --no-fail-fast --workspace
0 of 162 `--exclude` flags survived. Every shard split landed in iters
230-240 was inert — the catch-all kept building and testing all 210
workspace crates, which is why it kept drifting into the job timeout no
matter how many crates were hoisted out of it. The doctest step had the
same truncation. `core-and-rest-wasm` had the same defect but its inline
comment was trailing prose with no flags after it, so all 29 `-p` flags
survived; fixed anyway so the pattern does not get copied.
Move every comment above the `packages:` key at mapping level, where YAML
strips it — the pattern the `core-platform` entry already used. The folded
scalars now contain only `--workspace`, `--exclude <crate>`, and
`-p <crate>` tokens.
Verified by parsing the workflow with PyYAML and diffing each shard's
effective package set against `cargo metadata`: 162 excludes / 50 effective
packages in the catch-all, 203 of 210 crates covered, no crate built twice.
Also add `.config/nextest.toml` with a 10-minute per-test kill switch.
`ruvector-delta-index::tests::test_insert_and_search` hangs indefinitely in
DeltaHnsw insert/search rather than failing, and with no timeout it consumed
3h52m of the 240-minute `core-platform` budget. Hold that crate out of CI
until it is fixed (#825).
Co-Authored-By: claude-flow <ruv@ruv.net>
Full methodology, raw benchmark output, memory/performance math,
practical and long-horizon applications, and falsification criteria
for the 2026-08-13 retrieval-receipts nightly run.
Documents the hypothesis, evidence, alternatives considered, and
rejection criteria for promoting retrieval receipts beyond the
experimental crate, including the disclosed Merkle padding
malleability limitation.
Extends ruvector-proof-gate's write-side integrity to the read path:
retrieval receipts bind each query result to the WriteReceipt produced
at ingestion, closing the write->read provenance loop for RAG audits.
Three variants (NoReceipt / PerResultReceipt / MerkleReceipt) measured
against a proof-gate-backed brute-force index. 12 unit tests cover
honest verification and four independent tamper kinds per variant.
Implements Shannon entropy of the candidate-heap distance distribution as
a live beam-width gate for ANN graph traversal — a novel application of
EDEN's entropy-based branching (ICML 2026) to HNSW-style search.
Three variants (FixedEf baseline, EntropyThresholdBeam, EntropyScaledEf)
benchmarked on 16D clustered synthetic data (N=2000, k=10, ef=50).
EntropyScaledEf achieves +1.6–3.9 pp recall@10 vs FixedEf at equal ef.
- 15 unit tests, all pass
- Zero external dependencies
- Real benchmark numbers, no mocks or placeholder values
- ADR-303 and research README included
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_018DMsyZzgWJ1pWw3svjfAAG
The phase-G ablation showed escalation firing on 100% of queries on
concentrated workloads while moving recall@10 only +0.7pp at 2.5x
latency — tight boundary margins there are precision-bound, which wider
traversal cannot fix and the VectorDB f32 verification tier now resolves
(-7pp -> +1.4pp vs the f32 index). Balanced therefore matches
MaxCompression's single-pass traversal (keeping its larger rescore
pool); Quality retains escalation as the safety net for deployments
with no higher-precision tier above the index.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk
With Turbo4 quantization active, VectorDB::search now over-fetches 2k
candidates from the quantized index and re-ranks them against the stored
f32 vectors before truncating to k — nearly free, since result
enrichment fetches those vectors anyway.
Ablation justification (20k x 768-D clustered corpus, 200 queries):
4-bit rescoring pins recall@10 at ~0.88 in concentrated neighborhoods
regardless of oversampling (candidates all present; tail ranks are
precision-bound, so wider traversal cannot help). With verification:
config recall@10 P50 us payload
f32 HNSW 0.947 1708 3072 B/vec
t4 maxcomp+verify 0.961 1664 392 B/vec (7.8x)
cascade mc+verify 0.962 1202 496 B/vec (6.2x, 30% faster)
The cascade+verify configuration beats the f32 baseline on recall,
latency, and memory simultaneously.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk
First ablation run (20k x 768-D clustered, 200 queries) showed the
precision-bound regime: Turbo4 recall@1 BEATS f32 (0.995 vs 0.945) and
MaxCompression is 1.6x faster than f32 at 7.8x compression, but
recall@10 pins at ~0.88 regardless of oversampling — with mult=8 the
true neighbors are already in the candidate pool; 4-bit rescoring cannot
order ranks 5-10 inside tightly concentrated clusters, so widening ef
(escalation) cannot help. That is exactly the case the ADR-297 §2
FP16/FP32 verification tier exists for: the new configs fetch 2k from
the quantized index and re-rank those ids against original f32 vectors.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk
One deterministic clustered corpus, identical HNSW parameters, five
configurations: f32 baseline, Turbo4 direct under MaxCompression/
Balanced/Quality policies, and the RaBitQ1 cascade. Reports recall@1,
recall@10 vs brute-force ground truth, build time, P50/P95 latency,
payload bytes/vector, and adaptive escalation rate — the measurement
plane for the ADR-297 ablation gate.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk
- VectorDB now persists a collection-level VectorProvenance record
(codec, codec_version, rotation_seed, dim, metric) in the vector store
itself when Turbo4 is active, and validates it on every reopen: a
mismatched rotation seed, dimension, metric, or codec version refuses
to open instead of silently serving wrong results. Tested: record
written and readable; tampered seed rejects reopen.
- ann_benchmark and memory_benchmark accept "turbo4" so the existing
harness measures the applied 4-bit path alongside none/scalar/binary.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk
The ~5 bits/dim active search plane from ADR-297 §2, wired end to end:
- SearchQuantization { Turbo4Direct, RaBitQ1 } on QuantizationConfig::Turbo4.
In cascade mode node data is [bits1 || turbo4] with the 1-bit plane FIRST
(traversal touches only the short cache-friendly prefix); the HNSW walk
scores pure AND+POPCNT bit-plane kernels against the query, graph
construction still scores Turbo4 sections (build quality paid once,
traversal bandwidth every query), and candidates rescore on the shared
Turbo4 plane. One rotation per query serves both representations.
- bits1: flat query-blob form + slice-based scorer callable inside
Distance<u8>::eval (no allocation per candidate).
- New SIMD f32xnibble rescore kernel (pshufb levels -> cvtepi8/cvtdq2ps ->
fmadd, sequential byte order so the f32 query needs no scrambling), with
FMA runtime detection and a tolerance-gated scalar oracle test; rescore()
now dispatches through it. Level grid rounding is ~1% of code error, so
the rescore tier remains the highest-fidelity scorer.
- Cascade tests: recall within 5pp of direct mode on clustered data,
serialization roundtrip in cascade mode (search_quant tag persisted).
- Recall-vs-f32 gate widened 2pp -> 3pp: ADR target 0.5pp + measured
hnsw_rs graph-construction nondeterminism across independent builds.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk
- bits1 module: RaBitQ-style sign codes over the SAME Turbo4 rotation
(one rotation pass, two codes; deterministic). Blob = word-padded sign
bits + alpha + c (per-vector MSE-optimal 1-bit scale, c = mean|z|).
Query int8 is decomposed into 8 bit-planes so candidate scoring is pure
AND+POPCNT (9 passes over D/64 words, ~4x less memory traffic than the
nibble kernel — the win when traversal is bandwidth-bound at scale).
Oracle test proves the popcount path equals the naive sign-sum; cascade
test (1-bit top-40 -> Turbo4 rescore -> top-10) gates recall on the
Gaussian worst case.
- Turbo4Codec::encode_dual: both planes from one rotation, byte-identical
to the single encoders (tested).
- AVX2 helpers now carry #[target_feature(enable = "avx2")] explicitly.
Measured kernel throughput (criterion, this hardware): asymmetric
int8xnibble 24.5 Gelem/s at 1536-D (62.6 ns/vector) vs the previous
widen-sequence kernel at 1.19 Gelem/s (1.29 us/vector) — the old inline
helpers without the target-feature attribute compiled to catastrophic
codegen; the bench keeps the old shape as a permanent baseline.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01XFWB9PKwsZYk5FbjBRY6mk