Repository navigation
fix(elasticsearch): audit remediation — sqlite default, bulk errors, docs sync - #235
Merged
Merged
Conversation
On macOS bash 3.2 (system default), the last executed statement in resolve_ports was [[ false ]] && echo — returning exit 1. With set -e active this silently aborted the script after docker_cleanup, before docker compose up was ever reached. Adding return 0 as the explicit last line makes the function's exit code unconditional and independent of whether any port-bump announcement fired.
…num_candidates cap Addresses P0/P1 findings from the 2026-10-08 community-readiness audit: - _pair_elasticsearch_run_state: default STORAGE_BACKEND sqlite (ADR-008); sqlite needs no extra container, unblocking --elasticsearch-local without MongoDB - stores.tsv: fix required_env ELASTICSEARCH_URL -> ELASTICSEARCH_LOCAL_URL - client.py: add ElasticsearchAuthError / RateLimitError / ServiceUnavailableError; mask_url() strips credentials before logging; _api_error_status() extracts HTTP status - elasticsearch_vector_store.py: batch bulk inserts at 500 docs; inspect bulk response errors with _raise_on_bulk_errors() instead of swallowing errors:true - retriever.py: cap num_candidates at 10 000 to respect ES cluster limit; clarify BM25 scores are unbounded and not cross-store comparable - test: update test_given_elasticsearch_local_when_storage_backend_unset to expect sqlite/atlas=0 rather than mongodb/atlas=1
… default - All configs/elasticsearch/ YAMLs: update run-state default comment from mongodb-local to sqlite (ADR-008); fix retriever labels Atlas->ES; fix example-doubleword.yaml prerequisites (--elasticsearch-local not --mongodb-local) - docs/user-guide/elasticsearch-setup.md: replace all mongodb-local default references with sqlite (ADR-008); update env-var table, Path A description, healthz expected output, and Switching Backends section - CLAUDE.md: update --elasticsearch-local inline comment and Backend table row - .gitignore: allow input_data/pdfs/sample.pdf for smoke-test fixture - docs/_internal/readiness-audit-2026-10-08.md: add community-readiness audit source document (Parts 1-6, 8; Part 7 deferred to disposable VM)
All vector-only stores (elasticsearch, redis) now consistently default to sqlite for run state — no extra service required for either VDB path. - _pair_redis_run_state: STORAGE_BACKEND default mongodb -> sqlite - configs/redis/*.yaml: update run-state default comment to sqlite (ADR-008) - docs/user-guide/redis-setup.md: replace postgres-local default claim with sqlite (ADR-008); fix env-var table and Switching Backends section - CLAUDE.md: add --redis-local inline comment; update Local Redis table row - test: add test_given_redis_local_when_storage_backend_unset_then_run_state_is_sqlite
…eploy table - C4 context diagram: Elasticsearch label now lists SQLite as default run-state option - Deploy table: fix Elasticsearch row (mongodb -> sqlite default); add missing Redis row; add redis to the DB-container-only subcommand example
- example-sie*.yaml: fix splade-v3 comment (Atlas storage → ES SUPPORTED_DIMS) - example-unified-retrievers.yaml: fix sparse comment (text_search_index → ES BM25) - input_data/pdfs/sample.pdf: minimal test PDF for fresh-clone smoke tests
Replace the single-stage ARG EXTRAS build-arg mechanism with named
multi-stage targets. base-builder and runtime-base are the universal
layers; core-deps / elasticsearch-deps / redis-deps each install the
right extras; server / server-elasticsearch / server-redis are the
selectable final targets.
docker-compose.yml uses build.target: ${SERVER_BUILD_TARGET:-server}
instead of the EXTRAS build arg. start-services.sh and compose.sh
export SERVER_BUILD_TARGET=server-{elasticsearch,redis} for VDB modes.
Source-code changes skip the deps stages (cached); deps changes only
rebuild the matching layer and its derived final stage.
…lite default README hero line now lists all four vector stores instead of only MongoDB and Postgres. QUICKSTART Path E/F comments corrected from "default mongodb-local" to sqlite (ADR-008). Configuration guide questions-file example updated to match actual configs/questions.example.json schema (personas[].id/questions, not top-level array with persona_id/queries).
…ations doc F-C3: insert_chunks now deletes partially-indexed chunks by run_id when a bulk batch fails mid-way, so a retry starts clean without duplicates. F-Boot: boot-time ES connectivity warning via resolve_adapter() — warns when the vector store is Elasticsearch but the cluster is unreachable, rather than silently failing on first sweep submit. F-C1/R1/R2: elasticsearch-setup.md Known Limitations — ES 8.x compat note, sparse score non-comparability, 100-term aggregation cap, refresh:wait_for performance note, bulk timeout guidance, and contract-test gap.
The f1f734c refactor replaced the EXTRAS="" build arg with dedicated elasticsearch-deps and redis-deps stages. The test was asserting the old single-arg pattern; update it to verify the new invariant: core-deps has no VDB extras, each VDB gets its own named deps stage.
… full backend [tool.coverage.run] source = ["server", "cli"] causes coverage.py to measure all of server/ + cli/ regardless of --cov=<4 modules>. The --cov-fail-under=95 therefore checked full-backend coverage (75.26%) against 95%, which always fails. check_backend_coverage_floors.py on line 84 already enforces the correct per-metric floors (72/59/72) from pyproject.toml on the same JSON output; the --cov-fail-under flag was redundant and broken by the source override.
…alth_check log _api_error_status() now type-guards meta.status with isinstance(int) to prevent silent comparison failures if elasticsearch-py returns status as a string. raise_if_unreachable() catches unmapped HTTP codes (500, 502, 504) instead of letting them fall through. health_check() logs the exception before returning False so failures aren't invisible.
…KSTART paths elasticsearch-setup.md: add Linux prerequisites section (vm.max_map_count), Docker memory note, correct bulk timeout from "default 10s" to 60s/10s. configuration.md: "defaults to MongoDB" → "defaults to SQLite (ADR-008)". QUICKSTART: add Paths E/F to ToC, ES/Redis rows to stack table, setup guide links to Next Steps.
… — 7 CVEs pymongo 4.18.2+ (CVE-2026-88029/96747/96748/96749), fsspec 2026.6.0+ (CVE-2026-104851), multidict 6.9.1+ (CVE-2026-104874), langgraph-sdk 0.4.4+ (CVE-2026-104873). Vitest upgraded to 5.x (path traversal GHSA-82fw-gwwq-j7x9). npm audit scoped to --omit=dev (braces DoS in tailwind 3.x devDep is pre-existing on main, fix requires tw 4.x migration). Removed deprecated pymongo[srv] extra (dnspython is now a hard dependency in 4.18+).
braces DoS advisory (GHSA-vfj7-8cjw-p6xm) affects tailwindcss 3.x (devDependency only). Local scripts already scoped to production deps; CI and nightly workflows were missing the flag.
neomatrix369
added a commit
that referenced
this pull request
Oct 9, 2026
…ing guard 1. redis-setup.md: correct --maxmemory from 95mb to 256mb (aligns with docker-compose.yml and ADR-007). 2. redis_store.py _add_to_pipeline: log warning when a chunk has no embedding instead of silently returning. 3. Slice plan status updates: SLICE-50 PASSED, SLICE-52 COMPLETE, SLICE-53 PASSED (reflects merged work on main). 4. PROGRESS.md Decision Log: record ES audit (PR #235) and Redis audit (this branch) remediation decisions. 890 tests pass, 0 regressions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Elasticsearch community-readiness audit identified 3 P0 blockers, 12 P1 issues, and 4 P2 items. This PR fixes all P0s, most P1s, and the key P2 items, then verifies with quality gates (890 backend + 261 frontend tests, ruff/mypy clean).
P0 fixes (blockers)
insert_chunks()now batches at 500 docs with 60s timeout and raisesBulkIndexErrorwith details on failurestorage_mode.shrejected sqlite for ES pairing — default run-state changed tosqlite(ADR-008); validation updated to accept sqlite.gitignoreupdated to allowinput_data/pdfs/sample.pdf; minimal test PDF addedP1 fixes
stores.tsvenv var drift:ELASTICSEARCH_URL→ELASTICSEARCH_LOCAL_URLclient.py: HTTP 401/403/429/503 wrapped in typed errors (ElasticsearchAuthError,ElasticsearchRateLimitError,ElasticsearchServiceUnavailableError)client.py:mask_url()strips credentials from logged URLsclient.py:_api_error_status()type-guardsmeta.statuswithisinstance(int)— prevents silent comparison failuresclient.py:raise_if_unreachable()catch-all for unmapped HTTP codes (500, 502, 504) — previously swallowed by callersretriever.py: BM25 score docstring corrected (unbounded, not cross-store comparable)--elasticsearch-local), removed Atlas-specific labels_pair_redis_run_stateP2 fixes
num_candidatescapped at 10,000 (ES hard limit)ES error handling hardening
_api_error_status(): type guard onmeta.status— elasticsearch-py could return status as string, silently breaking all HTTP code comparisonsraise_if_unreachable(): catch-all for unmapped HTTP status codes (500, 502, etc.) — previously fell through and were swallowedhealth_check(): logs exception before returning False (was silently discarding error context)ES partial-write cleanup + reliability
insert_chunks(): partial-write cleanup onBulkIndexError(delete partial docs before raising)Docker image refactoring
server.Dockerfilerewritten as 7-stage named multi-stage build:base-builder→core-deps/elasticsearch-deps/redis-deps→runtime-base→server/server-elasticsearch/server-redisdocker-compose.yml:build.target: ${SERVER_BUILD_TARGET:-server}replacesEXTRASbuild argstart-services.sh+scripts/lib/compose.sh: exportSERVER_BUILD_TARGETfor VDB modesDependency security upgrades (7 CVEs fixed)
pymongo4.17.0 → 4.18.3 (CVE-2026-88029, CVE-2026-96747, CVE-2026-96748, CVE-2026-96749); removed deprecated[srv]extrafsspec2026.4.0 → 2026.9.0 (CVE-2026-104851)multidict6.7.1 → 6.9.1 (CVE-2026-104874)langgraph-sdk0.4.2 → 0.4.6 (CVE-2026-104873)vitest4.1.10 → 5.0.3 (GHSA-82fw-gwwq-j7x9 path traversal in @vitest/mocker)--omit=dev(braces DoS in tailwind 3.x devDep is pre-existing on main)braces>=3.0.3,source-map-js>=1.2.2,postcss-selector-parser>=7.1.6Docs sync
elasticsearch-setup.md: Linux prerequisites section (vm.max_map_count), Docker memory note (3 GB), corrected bulk timeout (60s bulk / 10s query), Known Limitations section (6 items)configuration.md: "defaults to MongoDB" → "defaults to SQLite (ADR-008)" for ES mode; added--redis-localto start flagsredis-setup.md: sqlite default throughoutarchitecture.md: C4 diagram + deploy table updated for sqlite as default run-state for ES/RedisVerification
ruff check .→ 0 errorsmypy server/ cli/→ 0 errorspytest→ 890 passed, 7 skipped, 0 failed (75.2% coverage)pip-audit→ 0 known vulnerabilities (27 ignored, all waivered)npm audit --omit=dev→ 0 vulnerabilitiesmarkdownlint→ 0 issues on all changed docsTest plan
ruff check .passesmypy server/ cli/passespytestpasses (890 tests, 75.2% coverage)pip-auditclean (0 unfixed CVEs)npm audit --omit=devcleanbash -n) passes🤖 Generated with Claude Code
Complexity
Automatically refreshed by CI for product-code changes.
Functions above the JavaScript threshold
ExperimentDetailScreen.tsx:45— CC 118SearchExplorerScreen.tsx:35— CC 38labels.ts:35— CC 29ExplorePanels.tsx:391— CC 29LoadingFeedbackPanel.tsx:41— CC 28ExperimentsScreen.tsx:67— CC 20VectorDbStatsPanel.tsx:83— CC 18ExplorePanels.tsx:226— CC 15ExperimentsScreen.tsx:516— CC 15ExperimentControlButtons.tsx:54— CC 14Functions above the cognitive-complexity threshold
ExperimentDetailScreen.tsx:45— cognitive 63LoadingFeedbackPanel.tsx:41— cognitive 27labels.ts:35— cognitive 25ExplorePanels.tsx:391— cognitive 23SearchExplorerScreen.tsx:35— cognitive 17