Skip to content

perf: v0.2.5 spike follow-ups — hydrate verify, streaming hash, JSONL policy, embed batching, vector polish - #93

Merged
valiantone merged 6 commits into
mainfrom
perf/v0.2.5-spike-followups
Aug 29, 2026
Merged

perf: v0.2.5 spike follow-ups — hydrate verify, streaming hash, JSONL policy, embed batching, vector polish#93
valiantone merged 6 commits into
mainfrom
perf/v0.2.5-spike-followups

Conversation

@valiantone

@valiantone valiantone commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What

Performance and correctness follow-ups from the native helper spike (#48, benched in #84), batched as the v0.2.5 release. This PR is opened as a draft and filled in ticket by ticket; each ticket's scope is implemented, tested, and checked against the unified acceptance criteria below.

Scope — tickets closed by this PR

Unified acceptance criteria (holistic, across all tickets)

Correctness — the contracts that must not move:

  1. Result parity everywhere. /v1/search responses remain byte-identical with and without the vector index (golden additive test stays green); verified hydration produces digests identical to the current double-read path on every range size; hybrid ranking order is unchanged for stores within the exactness window.
  2. No API/behavior change except the explicit JSONL inspection validation policy: per-line json.loads costs 5.5x at 100 MB #89 policy decision. Any change to FileInspection guarantees is deliberate, documented in docs/api.md, and versioned in the CHANGELOG. include_archived/TTL/archived predicates behave identically on every new code path.
  3. Dependency-free default preserved. All improvements are pure Python stdlib; chromadb stays optional ([vector] extra); zero new required dependencies or wheels.

Performance — measured against the committed spike baselines (bench/native_spike/results.json, B1/B2/B3):

  1. Hydrate/verify speedup demonstrated: single-read (+Streaming range hash for large verified ranges (constant memory) #88 streaming above threshold) ≥ the spike's ~1.16–1.26x at 100 MB on the benchmark fixtures; no regression at small range sizes.
  2. Constant memory for large ranges: verified hydration of a 100 MB range peaks at O(chunk) RSS (spike target ≈ 20 MB), not O(range).
  3. Inspection cost reduction: under the chosen JSONL inspection validation policy: per-line json.loads costs 5.5x at 100 MB #89 policy, 100 MB JSONL inspection improves materially toward the spike's scan-only baseline (319 ms vs 1740 ms), without weakening guarantees beyond the documented policy.
  4. Bundle parse speedup: embed_text batching yields a measurable parse_bundle reduction on the spike bundle trees (fixtures reusable), with hotmem-hash-v1 vectors bit-identical (or model string versioned + migration note).

Robustness:

  1. search_by_ids is parameter-limit safe for any configured oversample (chunked binds), with a regression test covering >999 ids.
  2. Staleness/fallback semantics unchanged: index staleness, graceful fallback, rebuild-marker safety (fingerprint-before-read) all keep their existing tests green; swallowed backend errors become visible warnings.

Quality gates (every commit):

  1. Full suite green on Python 3.11–3.14 plus the vector CI job; ruff check + ruff format --check clean on src/ tests/ examples/.
  2. Each ticket's own acceptance criteria (in Single-read verified hydration: drop redundant range re-read #87Vector index polish: chunked search_by_ids binds, single FTS pass, shared unpack_embedding #92) individually satisfied and cross-referenced from its closing commit message.
  3. CHANGELOG updated under [Unreleased] per ticket; docs (api.md, architecture.md) updated wherever user-visible behavior or policy changes.

Release

  • Milestone v0.2.5; version bump to 0.2.5 happens as its own commit at release time (auto-tag cuts v0.2.5 on merge to main), not incidentally in feature commits.

References


Implementation status — all five tickets landed

Ticket Commit Delivered Tests (all proven intent-purposed)
#92 864d655 900-bind chunking w/ canonical merge order; single FTS pass on both paths; shared unpack_embedding; warn-logged Chroma failures >999-id parity vs full scan; FTS call-count == 1 on accelerated + fallback
#90 fe7602e bounded per-gram lru_cache (65 536) + int.from_bytes digest conversion; hotmem-hash-v1 bit-identical golden equivalence vs verbatim pre-#90 algorithm (ASCII/unicode/random, 159 cases); cache-engagement assertion
#87 c053082 provenance.verify_bytes; hydrate hashes already-read bytes — one read per range SpyAdapter read-once assertion (proven failing on double-read code); error-surface parity via existing mismatch/truncation/missing tests
#88 ebd8ce2 read_range_chunked (optional local-adapter capability, no protocol change); streaming verify > 8 MiB threshold digest parity + path engagement across the threshold boundary (exactly 8 MiB = simple path); truncated semantics preserved
#89 9b2ded7 advisory policy: sampled-by-default, assurance declared via metadata["validation"], opt-in validation="full" (+ CLI flag); row_count untouched window-line reported in both modes; beyond-window only under full; assurance declaration; mode validation

Measured (this machine, min-of-N):

  • embed_text 9.7 KB: 6.26 ms → 1.07 ms (5.9x, cold cache) — attacks the spike's 37–78% of parse_bundle.
  • JSONL inspection 11.6 MB: full 115 ms → sampled 34 ms (3.4x; spike baseline ~5.5x at 100 MB where validation dominates).
  • Verified hydration: one read_range per range (was two) — spike B1: ~+16% at 100 MB.
  • Streaming verify: O(chunk) RSS for ranges > 8 MiB (spike B1: 20 MB vs 219 MB at 100 MB).

Decision record (#89, ratified by @valiantone 2026-08-28): inspection is advisory and never authorizes import/hydration/snapshot/provenance decisions; default validation="sampled" with declared assurance in metadata["validation"]; full validation preserved as opt-in. Documented in docs/architecture.md.

Atlas alignment: #87/#88 preserve digest + ProvenanceError semantics exactly (no new public semantics); #90 keeps hotmem-hash-v1 bit-identical (no model-version bump needed — the golden test is the compatibility proof); #92 keeps the index optional/rebuildable with zero result-semantics change; #89 implements the advisory-vs-authoritative boundary verbatim.

@valiantone valiantone added this to the v0.2.5 milestone Aug 28, 2026
@valiantone valiantone added enhancement New feature or request area:storage Storage adapter abstraction + filesystem adapters area:hydration Hydration profiles and zero-copy/reference hydration v0.2.x HotMem post-v0.2 follow-up work priority:p2 Do after evidence or dependency gates; optional portability capability labels Aug 28, 2026
@valiantone valiantone self-assigned this Aug 28, 2026
@valiantone
valiantone requested a review from alphakenz August 28, 2026 12:34
…d unpacker (#92)

- db.search_by_ids binds ids in chunks of 900 (under SQLite's legacy
  999-variable cap for any oversample); merged results carry the same
  canonical (cosine DESC, id ASC, NULL-last) order.
- search_memories fetches FTS rows once; _fetch_candidates unions them and
  _normalize_bm25 reuses them (one FTS pass on both paths).
- vector_index drops _unpack_blob for embed.unpack_embedding and logs
  swallowed Chroma delete/clear failures at warn level.
- Tests: >999-id chunking parity vs full scan; single-FTS-pass assertion on
  both accelerated and fallback paths.
@valiantone
valiantone marked this pull request as ready for review August 28, 2026 12:39
Trigram -> (bucket, sign) results are memoized in an lru_cache (65 536
entries), and md5 digests are converted via int.from_bytes instead of
hexdigest parsing. Iteration order and float accumulation are unchanged,
so hotmem-hash-v1 vectors are bit-identical — golden test compares against
the verbatim pre-#90 algorithm over ASCII, unicode, and randomized corpora.

Measured: 6.26 ms -> 1.07 ms per 9.7 KB embedding (5.9x, cold cache).
Targets the spike B3 finding that embed_text is 37-78% of parse_bundle.
hydrate_memory_detailed hashes the bytes it already read via the new
provenance.verify_bytes instead of calling verify_range, which re-read the
range through the adapter. The digest and ProvenanceError surface are
byte-for-byte identical; verify_range remains for standalone verification.

Test: SpyAdapter asserts exactly one read_range per verified hydrate
(proven to fail against the double-read implementation).
Targets spike B1: ~+16% at 100 MB (850 -> 736 ms median).
verify_range hashes ranges > STREAM_VERIFY_THRESHOLD (8 MiB) through the
new optional LocalFilesystemAdapter.read_range_chunked generator — O(chunk)
memory instead of O(range). Digest, mismatch, and truncation semantics are
identical to the single-read path; adapters without the capability and
ranges at/below the threshold are unchanged (duck-typed capability probe,
no StorageAdapter protocol change).

Test: parity + path engagement across the threshold boundary (proven
boundary: exactly 8 MiB stays single-read) via SpyAdapter.
… assurance (#89)

Inspection is advisory: it never authorizes import, hydration, snapshot,
or provenance decisions. Default validation now parses only the declared
sample window and declares the assurance level via
FileInspection.metadata['validation'] ('sampled' | 'full'); validation='full'
(inspect_file param / hotmem inspect --full-validation) keeps the pre-#89
parse-every-line behavior. row_count semantics unchanged (validation-
independent). The validation kwarg is accepted uniformly across inspectors
for dispatch; CSV/Parquet ignore it (no JSON validation applies).

Tests: window-line reporting in both modes, beyond-window behavior
(sampled None vs full reported), assurance declaration, mode validation.
Measured: 34 ms vs 115 ms per 11.6 MB JSONL (spike B2: ~5.5x at 100 MB).
@valiantone
valiantone merged commit 04cf0b6 into main Aug 29, 2026
11 checks passed
@valiantone
valiantone deleted the perf/v0.2.5-spike-followups branch August 29, 2026 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:hydration Hydration profiles and zero-copy/reference hydration area:storage Storage adapter abstraction + filesystem adapters enhancement New feature or request priority:p2 Do after evidence or dependency gates; optional portability capability v0.2.x HotMem post-v0.2 follow-up work

Projects

None yet

2 participants