Skip to content

release: v0.7.0 - correctness, error envelope, and release automation - #121

Merged
fvadicamo merged 94 commits into
mainfrom
develop
Jul 18, 2026
Merged

release: v0.7.0 - correctness, error envelope, and release automation#121
fvadicamo merged 94 commits into
mainfrom
develop

Conversation

@fvadicamo

@fvadicamo fvadicamo commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What

Promotes the accumulated develop work to main as v0.7.0 (81 commits since v0.6.0). Highlights:

New endpoints

  • GET /api/v1/documents/{id}/chunks — inspect a document's chunks
  • DELETE /api/v1/index-versions/{version} (admin) — reclaim superseded index versions; refuses to delete the live one (DEBT-032, ERR-INDEX-001 / 409)

Error contract

  • REQ-010 error envelope now sits at the JSON document root on every error path (DEBT-033/034)

Correctness & hardening

  • top_k bounded 1..100 on /query + /learn/query (BUG-026)
  • namespace binding on DELETE /documents/{id} and the chunk endpoints
  • every Qdrant chunk path routed through the VectorStoreProvider Protocol (BUG-023, ADR-0026)
  • startup fails cleanly without a traceback (BUG-025); empty VEKTRA_LLM_PROVIDER rejected; sparse provider registered under its configured name (BUG-024); check_provider_registration wired at startup (ARCH-057)
  • runtime __version__ aligned to 0.7.0 (fixes /health + OpenAPI version reporting)

Config

  • removed VEKTRA_PARENT_CHILD_LEVELS (DEBT-027) and VEKTRA_RERANK_TOP_K (DEBT-013) — both were dead/unwired, no runtime behavior change; added VEKTRA_RERANK_FETCH_K

CI / infra

  • publish ghcr.io/vektralabs/vektra:{version} + :{version}-ocr on tag push (INFRA-007)
  • suite-execution guard + env-isolation guard, hermetic tests (DEBT-029/030/031); integration matrix over pgvector and qdrant
  • Qdrant healthcheck fixed; CMD_TARGET=migrate honored

Why

Post-Phase-2 correctness and operability release: closes the storage-correctness family (chunks belong to the vector store, ADR-0026), unifies the REQ-010 error envelope, and lands the GHCR publish pipeline so tagged builds ship images automatically. Ships two new admin/inspection endpoints alongside.

Testing

  • make lint (ruff + ruff format + mypy 77 files + import-linter 8/8 contracts) and make test (800 passed, 3 skipped, 52 integration deselected) green on develop
  • CI green on the release-prep PR chore(release): finalize v0.7.0 #120: Lint and type check, CI gate, Integration tests + NFR gates (pgvector + qdrant matrix)

Checklist

  • CHANGELOG [0.7.0] - 2026-07-18 complete; versions bumped across the 8 components + runtime __version__ constants
  • No breaking changes for existing integrations (removed config vars were dead; Moodle plugin already parses both root and nested error envelope)
  • Bot review addressed on chore(release): finalize v0.7.0 #120 (CodeRabbit Major finding fixed + resolved; Gemini no feedback)
  • Merge approval from the operator — signed tag v0.7.0 follows after merge and triggers publish.yml (GHCR images)

Excluded from this release: PR #99 (TECH-005 textbook eval, ground truth pending review) — orthogonal eval material.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added batch ingestion/deletion, granular pipeline endpoints, and expanded conversation + reindex management, including index-version cleanup.
    • Added reranking candidate fetch configuration and bounded query limits.
    • Published versioned container images and added a release-image Docker Compose example.
  • Bug Fixes
    • Standardized API error responses to a root-level error object.
    • Fixed startup validation/exit behavior and improved vector-store chunk lifecycle, reindex correctness, and retention cleanup.
    • Strengthened namespace-bound access controls and index-version deletion safeguards.
  • Documentation
    • Updated API/config/reindex/provider guidance and Quick Start for release-image usage.
  • Tests/CI
    • Expanded unit/integration CI coverage and added integration tests for chunk lifecycle and reindexing.

fvadicamo and others added 30 commits July 13, 2026 10:03
Add .github/workflows/publish.yml: on v* tag push, build and push
ghcr.io/vektralabs/vektra:{version} and :{version}-ocr with GHA build
cache and OCI version/revision labels, using the built-in GITHUB_TOKEN
(no new secrets). No latest tag. The manual tagging flow is unchanged.

Add deploy/docker-compose.image.yml.example so hosts can point
docker-compose.yml at the published image (docker compose pull && up -d)
instead of building from source, and document the flow in
docs/getting-started/index.md and README.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
check_provider_registration hardcoded the embedding provider name to
"sentence-transformers" and was never called outside its own unit test,
so it silently stopped protecting startup once TEI mode
(VEKTRA_EMBEDDING_PROVIDER=tei) was added. Call it at the end of
_step_5_register_providers with the configured vector_store_provider and
sparse_embedding_provider, and check the "default" alias instead of the
hardcoded name so it validates whichever embedding provider is active.
Adds a regression test for a TEI-only registry (default + tei, no
sentence-transformers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The qdrant/qdrant:v1.17.0 image has no curl, so
["CMD", "curl", "--fail", "http://localhost:6333/healthz"] always failed
with "exec: curl: executable file not found in $PATH", permanently
reporting the container unhealthy in every deployment using the qdrant
profile (verified on a live stack). bash is present in the image, so
switch to a bash-only check that speaks raw HTTP over /dev/tcp and greps
the status line. Verified empirically: recreated the live container with
the new healthcheck and it flipped from unhealthy (FailingStreak 10235)
to healthy (ExitCode 0) on the first probe. Also audited the TEI
healthcheck (same curl pattern) against the pinned cpu-1.6 image: curl
is present there, so it is left unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The entrypoint's CMD_TARGET="${1:-${CMD_TARGET:-server}}" prefers the
positional arg over the env var, but the Dockerfile's CMD ["server"]
meant Docker always passed "server" as $1, so CMD_TARGET could never
win: `CMD_TARGET=migrate docker run image` silently booted a full server
instead of running the one-shot migration (this hung a production
deployment script). Remove the Dockerfile CMD - the entrypoint already
defaults CMD_TARGET to "server" when no argument is given, so
`docker run image` and `docker run image migrate` are unaffected. Fix
the comment that claimed both forms already worked.

Verified: grepped the repo for anything relying on the image's default
CMD (compose files, CI workflows, scripts, docs) - nothing does;
docker-compose.yml already sets CMD_TARGET=server as an env var for the
vektra service, so its runtime behavior is unaffected. Confirmed the
dispatch logic itself in isolation (sh, no Docker) for all four
invocation combinations, including reproducing the prior bug for
contrast. Did not perform a full image build (expensive, out of scope
per instructions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_store_honors_deterministic_ids_and_parent_linkage and
test_store_falls_back_to_random_id_on_non_uuid patched DocumentChunkOrm
and asserted on the mock's call_args_list, which tests the mock's
bookkeeping rather than the real ORM mapping and hides mapping errors.
.coderabbit.yaml's path instructions explicitly forbid mocking
SQLAlchemy ORM classes. Both tests now let store() construct real
DocumentChunkOrm instances and capture them via a session.add side
effect (_make_session() already stubs session.add as a MagicMock),
asserting on the captured instances' .id/.parent_id attributes instead.

Also annotates BUG-021 in .s2s/BACKLOG.md with a related parity gap
found in the same review: QdrantVectorStoreProvider.retrieve() filters
by namespace_id only, unlike PgvectorProvider.retrieve() which also
filters by index_version. Not fixed here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- disable credential persistence on checkout (matches the OCR build workflow)
- document the pull-based deployment via COMPOSE_FILE instead of repeating -f

Addresses review comments on PR #96.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t chunk-storage claim

The sync ingest response returns new/exists/alias, never "indexed" (that is an
async job status), and MarkdownExtractor has always handled text/markdown.

The agent instructions claimed chunk text lives in document_chunks; that table is
written only by PgvectorProvider, so in Qdrant mode it is empty for every namespace
and the Qdrant payload is the only source of chunk text. Recorded in BUG-021 as the
root cause of the reindex no-op: run_reindex reads that empty table and reports
success after writing nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- INFRA-007: publish ghcr.io/vektralabs/vektra:{version} and :{version}-ocr on v* tag push
- GHA layer cache per variant, OCI version/revision labels, GITHUB_TOKEN auth, no new secrets
- deploy/docker-compose.image.yml.example: overlay that makes the documented pull flow actually work
- docs: pull-based deployment via COMPOSE_FILE

Reviews: 2/2 addressed (persist-credentials, COMPOSE_FILE)
Tests: 699 passed; CI green
Refs: INFRA-007. Publishing starts from the next tag: v0.6.0 predates this workflow.
- wire check_provider_registration into startup (ARCH-057 step 5 was dead code); checks the embedding/default alias
- fix the Qdrant healthcheck: the image ships no curl, so the container was permanently unhealthy; bash /dev/tcp probe instead
- remove Dockerfile CMD ["server"] so CMD_TARGET=migrate actually migrates (it hung the v0.6.0 rollout script)
- stop mocking DocumentChunkOrm in pgvector tests; use the session.add intercept
- docs: sync ingest returns new/exists/alias (not "indexed"), markdown is supported, and document_chunks is EMPTY in Qdrant mode (root cause of the BUG-021 reindex no-op)

Reviews: Gemini no findings; CodeRabbit no findings
Tests: 699 passed; CI green
Refs: follow-ups from #93/#95 review + two deployment bugs found during the v0.6.0 rollout
…ress

BUG-023: in Qdrant mode document_chunks is empty (only PgvectorProvider writes it),
so reindex, stats and the chunk-listing endpoints operate on an empty table and
report success. Root cause of the reindex no-op previously noted under BUG-021.

DEBT-027: VEKTRA_PARENT_CHILD_LEVELS is validated but never consumed.

TECH-008: compare chunk-RAG against link-graph navigation on a structured markdown
wiki, with a mandatory closed-book control and link-aware expansion as the possible
practical outcome.

TECH-005: collection 1 corpus built, ingested and machine-validated; the human
spot-check remains open and is now an explicit acceptance criterion, alongside the
closed-book control as a standing requirement for every eval dataset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- BUG-023 (high): in Qdrant mode document_chunks is empty, so reindex/stats/chunk-listing operate on an empty table and report success
- DEBT-027: VEKTRA_PARENT_CHILD_LEVELS is validated but never consumed
- TECH-008: chunk-RAG vs link-graph navigation on a structured wiki, with a mandatory closed-book control
- TECH-005: collection 1 progress; human spot-check made an explicit acceptance criterion; closed-book control now required for every eval dataset

Reviews: 2/2 addressed (declined: referencing vektra-internal paths is the established convention in this file)
Docs only, no code touched
…(BUG-023)

In Qdrant mode, which is what every real deployment runs, `document_chunks` is
empty: only PgvectorProvider writes it. Every path that read chunks from
Postgres therefore worked on an empty table and reported success. They did not
fail, they lied:

- `run_reindex` re-embedded nothing and marked the job `completed` (the root
  cause of the no-op previously attributed to BUG-021)
- `GET /stats` reported `chunk_count: 0` for namespaces holding 12/105/562 chunks
- `POST /documents/{id}/chunks` wrote to the inactive store
- `GET /health` reported the index healthy without looking at the store behind it
- `DELETE /documents/{id}` returned 200 with `chunks_removed: 0`, left the points
  in Qdrant, and the deleted document went on answering queries
- retention (REQ-057) hard-deleted the document row and relied on the
  document_chunks CASCADE, leaving the content searchable and untraceable

ADR-0026 records the decision: `document_chunks` is private to the pgvector
provider, and chunk text, counts and deletion all go through the
VectorStoreProvider Protocol. The rejected alternative (a neutral table both
providers write) would have made Postgres a mandatory co-store under every
provider, which is the redundancy the pluggable-store design exists to avoid.

The Protocol grows three things, each with a real caller: `list_chunks()`,
`count_chunks()`, and an optional `index_version` on `store()` for reindex.
Reindex derives target-version chunk ids so it writes alongside the live version
instead of overwriting it in Qdrant, and remaps parent links (FEAT-017)
accordingly. A reindex over a non-empty namespace that stores nothing now fails
loudly, and `reindex_jobs.chunks_reindexed` (migration 0007) makes the work it
did observable.

The gap that let this survive was the test layer: the only Qdrant test mocked
the qdrant_client module wholesale, and the integration suite ran against
pgvector only. It now runs as a CI matrix over both providers, and
test_chunk_lifecycle.py asserts the lifecycle through the public API, including
that a deleted document is not retrievable.

Verified against the live Qdrant stack: reindex took the target version from
0 to 12 points with the source version intact, stats match the real point
counts, and deleting a document removes it from search.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-024)

Startup validation looks the sparse provider up by the name in
VEKTRA_SPARSE_EMBEDDING_PROVIDER (`fastembed-bm25`), but the app registered it
only under "default":

  Provider 'fastembed-bm25' not registered in category 'sparse_embedding'.
  Available: ['default']

The vector store registers both aliases; the sparse provider registered one. So
every stack with sparse embeddings enabled failed to start, which means hybrid
search could not be turned on at all. Introduced by b49ce23, which wired up the
check that had until then been dead code. Found while rebuilding the development
stack to verify BUG-023: the container that had been up for days survived only
because its image predated the defect.

Registering the alias is one line. Why nothing caught it is the larger half:

- `vektra-app/tests/` was executed by nothing, neither `make test` nor CI, even
  though it holds the tests for the module that wires every provider together.
  It now runs in both, via a new `test-app` job gated in the CI aggregator.
- The existing check tests could not have caught it: they hand
  check_provider_registration a mock registry that already contains the name, so
  they assert the check against a fiction. test_provider_registration.py instead
  wires the real registration step to the real check, and fails with the exact
  production error when this fix is reverted.
- Two app test files need Docker and said so in their docstrings, but carried no
  `integration` marker, so they could not be excluded from a unit run. They do now.

Verified on the live stack: with VEKTRA_SPARSE_EMBEDDING_PROVIDER=fastembed-bm25
the container starts, logs sparse_embedding_registered, and reports healthy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ment

Review follow-up on #101 (gemini, coderabbit).

The tests pinned only the three settings they assert on; everything else fell back
to defaults, which are not hermetic. Two leaks, both real:

- os.environ: importing litellm (registration does) runs load_dotenv(), pulling
  the repo .env into the process environment for the rest of the session, so
  _env_file=None was not enough.
- the .env file itself: registration builds its own sub-configs
  (QueryPipelineConfig), which resolve env_file=".env" against the working
  directory and bypass the settings passed in.

An autouse fixture now scrubs VEKTRA_* and runs from an empty cwd, so the tests
exercise the same code path on a developer machine as in CI.

Reranking is on by default and is read from that internal config, so registration
was loading a cross-encoder on every test: pinned off, since nothing here asserts
on the reranker. Test time drops from 10.8s to 1.5s and stops depending on a model
being downloadable.

Also set persist-credentials: false on the test-app checkout: the job runs
PR-authored test code and has no reason to keep the token in .git/config.

Verified: with the alias registration removed from main.py the suite still fails
(2 of 3), so the guard is intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review follow-up on #102 (gemini).

DELETE /documents/{id} never enforced namespace binding (H5): it took the
namespace straight from the query string, so an admin key bound to one namespace
could name another and have it honoured. The gap predates this PR, but it was
survivable only while the delete was a no-op against the active store. Now that
the delete actually removes the chunks, the same request is a real cross-namespace
deletion, so it is fixed here rather than filed.

The new GET /documents/{id}/chunks had the mirror-image bug: `namespace` defaulted
to the literal "default", so a namespace-bound key that omitted the parameter
collided with it and got a 403 on its own documents. Both endpoints now default the
parameter to None and resolve it from the key binding, like /stats and /search do.

The 403 now returns the ERR-AUTH-003 envelope (insufficient scope) instead of a
bare string, per the repository style guide. Note the reviewer proposed ERR-AUTH-001,
which is the missing/invalid-token code; the scope-violation code is ERR-AUTH-003.

test_api_namespace_binding.py covers both endpoints, and fails on the pre-fix code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r matrix

Branch protection requires a status check named "Integration tests + NFR gates".
Turning the integration job into a matrix renamed it to "Integration tests
(pgvector)" and "(qdrant)", so the required check would never report and every PR
would sit BLOCKED forever.

Add an aggregator job that carries the required name and fails if any provider in
the matrix failed, mirroring the ci-gate pattern already used in ci-unit.yml.
Adding a provider to the matrix now needs no change to branch protection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lias

- Register the sparse embedding provider under its configured name, not only "default": startup validation looked it up by name, so any stack with VEKTRA_SPARSE_EMBEDDING_PROVIDER set failed to boot and hybrid search could not be enabled at all
- Wire vektra-app/tests into make test and a new test-app CI job, gated in the aggregator: the suite was executed by nothing, which is why a provider-wiring defect shipped unnoticed
- Add test_provider_registration.py, which connects the real registration step to the real check (the existing tests asserted the check against a mock registry that already had the name)
- Mark the two Docker-dependent app test files as integration, as their own docstrings always claimed
- Isolate the tests from the local .env (litellm's load_dotenv leaks it into os.environ; sub-configs read the file directly)

Reviews: 3/3 addressed (Gemini 1, CodeRabbit 2)
Tests: 718 passed, lint clean, 8 import contracts kept
Verified: live stack boots with sparse enabled; guard fails on the pre-fix code
Refs: BUG-024
The review follow-up commit changes shipped behaviour (a cross-namespace deletion
becomes impossible) and had no changelog entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Route every chunk path (reindex, stats, delete, store, health, retention purge) through the VectorStoreProvider Protocol: in Qdrant mode they all read an empty Postgres table and reported success, so reindex re-embedded nothing while reporting "completed", stats reported 0 chunks, and a deleted document went on answering queries
- Record ADR-0026: document_chunks is private to the pgvector provider; the two providers stay interchangeable peers instead of Postgres becoming a mandatory co-store
- Protocol grows list_chunks(), count_chunks() and an optional index_version on store(); reindex fails loudly when it stores nothing, and reindex_jobs.chunks_reindexed (migration 0007) makes its work observable
- Run the integration suite as a CI matrix over both providers: it ran against pgvector only, which is why this class of bug survived for months
- Enforce namespace binding on DELETE and the new GET /documents/{id}/chunks (found in review): a no-op delete becoming a real one turned a dormant gap into a cross-namespace deletion

Reviews: 3/3 addressed (Gemini)
Tests: 733 passed, lint clean, integration green on pgvector and qdrant
Verified live on Qdrant: reindex 0 -> 12 points on the target version, stats match the real counts, deleted document drops out of search
Refs: BUG-023, ADR-0026, migration 0007
…ord the plan

Backlog:
- BUG-023 and BUG-024 marked completed with their PR numbers, the measured
  before/after evidence, and a pointer to the full record in vektra-internal
- DEBT-029: DEBT-025's test isolation reaches three test packages out of eight,
  and a scrub of os.environ is not sufficient anyway, because sub-configs read the
  .env file relative to the working directory. A test that passes locally and in CI
  for different reasons is worse than a missing one.
- DEBT-030: two vektra-app test files (the ARCH-057 startup sequence and the
  REQ-011 error contract) carry the integration marker but no workflow runs them,
  so they still test nothing
- DOCS-009: the reindex endpoints are undocumented, including chunks_reindexed,
  which is the field an operator needs to tell a real reindex from one that did
  nothing

Plans:
- Sprint 3 closed (all five tasks done, FEAT-018 as a recorded deferral)
- New plan 20260714-qdrant-parity: what shipped, why the ADR went the way it did,
  and the two traps found on the way (branch protection matches check names;
  litellm's load_dotenv defeats test hermeticity)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…riterion)

Review follow-up on #103 (gemini): reranking is on by default and read from an
internal config, so provider registration loads a cross-encoder on any test that
touches it. Pinning it off took the new test file from 10.8s to 1.5s and removed
its dependency on a model being downloadable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Close BUG-023 and BUG-024 with PR numbers and the measured before/after evidence; full record in vektra-internal
- File DEBT-029: DEBT-025's test isolation reaches three test packages out of eight, and scrubbing os.environ is not enough anyway (sub-configs read the .env file relative to the cwd)
- File DEBT-030: the ARCH-057 startup test and the REQ-011 error-contract test carry the integration marker but no workflow runs them
- DOCS-009: the reindex endpoints are undocumented, including chunks_reindexed
- Close the Sprint 3 plan; add 20260714-qdrant-parity recording what shipped and the two traps found on the way

Reviews: 1/1 addressed (Gemini; the model-download criterion taken, the .env rewording declined with evidence)
Docs only, no code changes
Refs: BUG-023, BUG-024, ADR-0026
…, DEBT-030)

Two structural holes in the test layer, both of which had already let a bug
through (BUG-024).

DEBT-029. The local .env reached every test package, including the three that
carried DEBT-025's scrub fixture. litellm calls dotenv.load_dotenv() at import
and finds the repo .env by walking up from its own module inside .venv/, which
lives inside the repo. The scrub cannot stop that: it runs before the test body,
while the import that re-injects the file happens inside it, because the product
imports litellm lazily. Measured: after `import litellm` in a test, a config left
at its default resolved to the developer's .env value (qdrant) instead of the
code's default (pgvector) in all four packages checked, vektra-core and
vektra-shared included. Tests were running a different code path locally than in
CI, which is the one thing a test must not do.

Two claims in the DEBT-029 entry were wrong and measuring corrected them: the
settings classes never read the .env file (no env_file in their SettingsConfigDict;
they only read os.environ), and monkeypatch.chdir does nothing, because
load_dotenv resolves the file relative to the calling module, not the cwd. The
backlog entry now records what was actually true.

The fix disarms the leak instead of undoing it: vektra_shared.testing sets
LITELLM_MODE before litellm can be imported, so litellm skips its dotenv load
outright. All eight test packages import that single fixture, and a structural
test fails if a package is added without it. Two empty tests/__init__.py files
(analytics, learn) made pytest derive the same module name for two conftests and
refused to run the suite at all; removed.

DEBT-030. vektra-app's two Docker-backed test files (the ARCH-057 startup
sequence, the REQ-011/NFR-009 error contract) were run by no workflow. Unrun, they
had rotted: both built the test container's URL with str(make_url(...)), which
masks the password as "***", so Alembic authenticated with a literal "***" and
every test errored at setup. They had never worked. Fixed, and they now run in an
app-integration CI job gated by the integration aggregator, which keeps the name
branch protection requires. 8 tests pass.

Suite: 755 passed (from 733), lint clean, 8 import contracts kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review follow-up on #104 (gemini): read_text() falls back to the system encoding,
which is not UTF-8 everywhere. Matches templates.py, which already pins it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion

- Close the local-env leak at its source: litellm's import-time load_dotenv() re-injected the repo .env into os.environ after any scrub could run, so tests ran a different code path locally than in CI. vektra_shared.testing now sets LITELLM_MODE before litellm can be imported; all eight test packages import the one shared fixture, and a structural test fails if a package is added without it
- Correct two wrong claims in the DEBT-029 entry: the settings classes never read the .env file, and chdir does nothing, because load_dotenv resolves relative to the calling module
- Remove two empty tests/__init__.py files that made pytest derive the same module name for two conftests and refuse to run the suite
- Run vektra-app's two Docker-backed test files (ARCH-057 startup, REQ-011 error contract) in a new app-integration CI job, gated by the integration aggregator
- Fix those two files, which had never worked: str(make_url(...)) masks the container password as "***", so Alembic authenticated with a literal "***" and every test errored at setup. 8 tests now pass

Reviews: 1/1 addressed (Gemini)
Tests: 755 passed (from 733), lint clean, app integration 8 passed, both providers green
Verified: every new test fails on the pre-fix code; the canary reads pgvector in all eight packages, where it used to read qdrant
Refs: DEBT-029, DEBT-030
The Qdrant-parity plan carried three explanations for why test isolation was
broken. DEBT-029 (#104) measured them and all three were wrong: the scrub fixtures
protected zero packages rather than three of eight (they run before the lazy litellm
import that re-injects the .env), sub-configs do not read the .env file at all (no
env_file in their SettingsConfigDict) and monkeypatch.chdir cannot help since
load_dotenv resolves relative to the calling module, and a root conftest.py would
not even be loaded in CI because each package declares its own pytest rootdir.

Corrected in place rather than quietly rewritten: plausible-and-wrong is the failure
mode that plan is about, and the note was not immune to it.

DEBT-031: the guard from DEBT-029 checks that every test package imports the
isolation fixture, but nothing checks that a test package is *executed*. Both
`make test` and ci-unit.yml enumerate the eight packages by hand, so a package added
tomorrow is silently unrun and no test fails. That is the exact hole BUG-024 fell
through, still open one level up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…criteria

Review follow-up on #105 (gemini), and the first one is instructive: the correction
itself carried a wrong number. Three packages had the scrub fixture (vektra-shared,
vektra-core, vektra-ingest), not two. Verified against 0a812d4.

DEBT-031's proposed approach asked for both the CI job and the make test target to
be checked, but the acceptance criteria only named CI. Both lists are hand-maintained
and can drift apart independently, so both are now criteria.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Correct the DEBT-029 diagnosis in the Qdrant-parity plan: all three explanations it gave for the broken test isolation were wrong (the scrub protected zero packages, not three of eight; sub-configs never read the .env file; a root conftest would not even load in CI). Corrected visibly, not quietly rewritten
- File DEBT-031: the DEBT-029 guard checks that every test package imports the isolation fixture, but nothing checks that a package is executed at all. make test and ci-unit.yml enumerate the eight packages by hand, so a package added tomorrow is silently unrun

Reviews: 2/2 addressed (Gemini; one of them caught a wrong number inside the correction itself)
Docs only, no code changes
Refs: DEBT-029, DEBT-030, DEBT-031, BUG-024
fvadicamo and others added 3 commits July 18, 2026 07:20
- Bump version 0.6.0 -> 0.7.0 across 8 components
- Promote CHANGELOG entries from [Unreleased] to [0.7.0] - 2026-07-18
  (new endpoints: GET /documents/{id}/chunks, DELETE /index-versions/{version};
  removed config: VEKTRA_PARENT_CHILD_LEVELS, VEKTRA_RERANK_TOP_K;
  fixes: DEBT-033/034 error envelope, BUG-023/024/025/026,
  DEBT-028/029/030/031/032, INFRA-007 GHCR publish)
- Refresh uv.lock for the version change

Prepares the develop -> main release PR for v0.7.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
CodeRabbit (PR #120, comment 3607913835) flagged three package __version__
constants left behind by the pyproject-only bump:

- vektra-app: 0.6.0 -> 0.7.0 — feeds app.state.version and the OpenAPI
  `version` field (main.py:558, 690), so /health and /openapi.json would
  otherwise report 0.6.0 for a 0.7.0 build
- vektra-analytics: 0.4.0-dev -> 0.7.0
- vektra-shared: 0.4.0-dev -> 0.7.0

Kept as manual constants (matching the v0.6.0 release); did not adopt the
importlib.metadata derivation suggestion, to keep the change minimal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
- Cut v0.7.0 from [Unreleased]: new endpoints (GET documents/{id}/chunks, DELETE index-versions/{version}), removed config (PARENT_CHILD_LEVELS, RERANK_TOP_K), REQ-010 root envelope, BUG-023/024/025/026, DEBT-028/029/030/031/032, INFRA-007 GHCR publish
- Bump 8 components + uv.lock to 0.7.0
- Align runtime __version__ constants (app/analytics/shared) to 0.7.0 (fixes /health + OpenAPI version reporting)

Reviews: 1/1 addressed (CodeRabbit Major; Gemini no feedback)
Tests: 800 passed; make lint + make test green; CI green
Refs: v0.7.0 release prep
@fvadicamo fvadicamo added documentation Improvements or additions to documentation component:shared vektra-shared component component:core vektra-core component component:index vektra-index component component:admin vektra-admin component ci CI/CD and toolchain changes component:learn vektra-learn component security Security hardening and vulnerability fixes labels Jul 18, 2026
@github-actions github-actions Bot added component:ingest vektra-ingest component infra Infrastructure, Docker, deployment labels Jul 18, 2026
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9bd9ad26-5c1a-419e-bca0-eeba93eaedc5

📥 Commits

Reviewing files that changed from the base of the PR and between 385311c and 7314d2f.

⛔ Files ignored due to path filters (1)
  • .s2s/BACKLOG.md is excluded by !.s2s/**
📒 Files selected for processing (6)
  • deploy/docker-compose.image.yml.example
  • docs/getting-started/index.md
  • scripts/reindex.sh
  • tests/integration/test_chunk_lifecycle.py
  • vektra-index/src/vektra_index/reindex.py
  • vektra-ingest/src/vektra_ingest/jobs.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • deploy/docker-compose.image.yml.example
  • vektra-ingest/src/vektra_ingest/jobs.py
  • tests/integration/test_chunk_lifecycle.py
  • scripts/reindex.sh

📝 Walkthrough

Walkthrough

Version 0.7.0 adds provider-neutral chunk lifecycle APIs, versioned reindexing and cleanup, structured error envelopes, startup validation, hermetic test coverage, provider-matrix CI, published container workflows, and expanded API/operator documentation.

Changes

Platform and indexing

Layer / File(s) Summary
Shared contracts and structured errors
vektra-shared/src/vektra_shared/..., vektra-core/src/vektra_core/...
Provider protocols, stored-chunk types, configuration, runtime error factories, root-level HTTP envelopes, and bounded query parameters are updated.
Provider-backed chunk lifecycle
vektra-index/src/vektra_index/...
Chunk storage, listing, counting, deletion, health checks, active-index filtering, and namespace enforcement use the active vector-store provider.
Reindex and retention cleanup
vektra-index/src/vektra_index/reindex.py, scripts/reindex.sh, vektra-ingest/src/vektra_ingest/jobs.py
Reindexing records actual writes, remaps parent IDs, supports target versions, exposes guarded cleanup, and removes vector content before purging database rows.
Startup and test execution
vektra-app/src/vektra_app/main.py, .github/workflows/*, vektra-shared/tests/*
Startup validation runs before container serving, shared environment isolation is registered across packages, and CI adds structural, application, package, and provider-matrix test gates.
Release and documentation
.github/workflows/publish.yml, docs/reference/*, CHANGELOG.md
Version 0.7.0 metadata, published image workflows, API/configuration references, reindex operations, and provider-specific storage guidance are documented.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: enhancement, bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the release version and the main themes: correctness fixes, error-envelope changes, and release automation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread vektra-index/tests/test_api_namespace_binding.py
Comment thread vektra-learn/tests/test_api.py
Comment thread vektra-learn/tests/test_api.py
Comment thread vektra-shared/src/vektra_shared/protocols.py
Comment thread vektra-shared/src/vektra_shared/protocols.py
Comment thread vektra-shared/src/vektra_shared/protocols.py
Comment thread vektra-shared/src/vektra_shared/protocols.py

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a major refactoring pass to achieve Qdrant vector store parity, unifies the REQ-010 error envelope to the JSON document root, and introduces a structural test execution guard to prevent unrun test suites. Key changes include routing all chunk-level operations through the VectorStoreProvider protocol (making document_chunks private to pgvector), implementing index version cleanup, bounding query top_k to prevent CPU-bound abuse, and fixing startup validation tracebacks. Since no review comments were provided, there is no feedback to evaluate on the review itself.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@fvadicamo

Copy link
Copy Markdown
Contributor Author

Resolving the 7 github-code-quality threads as won't-fix. All are false positives on idiomatic, pre-existing code that this release-promotion PR does not modify:

  • vektra-shared/src/vektra_shared/protocols.py (115, 143, 147, 163) — "Statement has no effect": these are the ... bodies of VectorStoreProvider Protocol methods (PEP 544). The ellipsis is the intended placeholder; the sibling methods using inline : ... were not flagged. Replacing with pass is churn.
  • vektra-index/tests/test_api_namespace_binding.py:58, vektra-learn/tests/test_api.py:857-858 — "Unnecessary lambda": these are FastAPI dependency_overrides providers (lambda: _make_session(), lambda: MagicMock()). The lambda is intentional — using the callable directly would change FastAPI resolution semantics.

None are introduced by v0.7.0 (which changes CHANGELOG, versions, and uv.lock). Out of scope for a version-bump promotion; not tracked as debt.

fvadicamo and others added 3 commits July 18, 2026 10:23
The "Variable count summary" claimed 59 Pydantic-validated VEKTRA_*
variables; config.py actually declares 66 distinct VEKTRA_-aliased fields
(each with a single alias, no AliasChoices). The number was already stale
before v0.7.0 — v0.6.0 shipped the same "59" against a different underlying
count — so this is chronic drift, not a v0.7.0 regression, surfaced while
auditing docs for the release.

- table row: 59 -> 66
- Total documented cascades 64 -> 71 (66 + 1 CORS_ORIGINS + 2 external
  API keys + 2 infrastructure)
- prose sentence: 59 -> 66

No config surface changed; only the descriptive count is corrected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
…review)

Gemini review on #122 correctly noted that the corrected count of 66
Pydantic-validated VEKTRA_* variables was not fully backed by table rows:
only 64 had entries. Add the two missing variables so the count matches
the documented set:

- VEKTRA_DEBUG_LOG_QUERIES -> Query pipeline table (bool, default false)
- VEKTRA_ANALYTICS_STORE_TRACES -> Observability table (bool, default
  auto: on in dev, off in prod)

Verified: all 66 code-defined VEKTRA_ aliases now have a documentation row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
- Correct the config variable count in docs/reference/configuration.md: 59 -> 66 Pydantic-validated VEKTRA_* variables; Total documented 64 -> 71
- Document the 2 previously-missing variables: VEKTRA_DEBUG_LOG_QUERIES (Query pipeline), VEKTRA_ANALYTICS_STORE_TRACES (Observability)

Reviews: 1/1 addressed (Gemini medium; incomplete tables fixed)
Docs only; make lint green; all 66 code-defined VEKTRA_ aliases now documented
Refs: v0.7.0 docs audit

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
vektra-index/src/vektra_index/api.py (1)

154-191: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Restore document existence validation before chunk writes The adapter only checks that all chunks share the same document_id; it does not prove a live SourceDocumentOrm exists for (document_id, effective_ns) before insert. Add a namespace-scoped existence check here, or this endpoint can create searchable orphan chunks that never appear in document bookkeeping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vektra-index/src/vektra_index/api.py` around lines 154 - 191, The
chunk-writing flow in the endpoint around vector_store.store must validate that
a live SourceDocumentOrm exists for (document_id, effective_ns) before
constructing or inserting chunks. Add the namespace-scoped document existence
check before the store call, and reject the request using the endpoint’s
established missing-document error behavior when no matching document exists.

Source: Path instructions

vektra-index/src/vektra_index/providers/pgvector.py (1)

80-117: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Make store() idempotent for deterministic chunk IDs. run_reindex already reuses stable target-version chunk IDs, so session.add() here will fail on a partial retry as soon as any rows from the same document/version are already present. Use an upsert or replace the target-version rows before inserting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vektra-index/src/vektra_index/providers/pgvector.py` around lines 80 - 117,
The chunk insertion logic in store() must be idempotent when deterministic IDs
already exist for the same document and target version. Update the session.add()
flow to upsert or replace conflicting target-version rows before insertion,
while preserving deterministic chunk IDs, parent linkage, and the existing
inserted_ids behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/getting-started/index.md`:
- Line 61: Update the published-image version references to v0.7.0: change the
walkthrough value in docs/getting-started/index.md lines 61-61, the standard and
OCR examples in deploy/docker-compose.image.yml.example lines 6-7 to 0.7.0 and
0.7.0-ocr, and the validation message in deploy/docker-compose.image.yml.example
line 24 to match those examples.

In `@scripts/reindex.sh`:
- Line 125: Update the success-response handling in scripts/reindex.sh,
including the paths around CLEANUP_BODY and the reindex response, to validate
that chunks_removed, chunks_reindexed, and source_index_version exist and have
their expected JSON types before indexing them. On missing or incorrectly typed
fields, fail with a clear API-contract error rather than exposing a Python
traceback or opaque shell failure; preserve normal processing for valid
responses.
- Around line 64-70: Update the positional-argument handling in the script’s
option-parsing case so only the first two positional arguments populate VERSION
and NAMESPACE. Reject any argument when POSITIONAL is already 2 by emitting an
error and exiting nonzero, rather than overwriting NAMESPACE.

In `@tests/integration/test_chunk_lifecycle.py`:
- Around line 155-164: Update the search precondition in the chunk lifecycle
test to verify that the returned search results contain the specific doomed_id
document, not merely that found["total"] is positive. Preserve the existing
query and search request, and assert against the result identifier field used by
the API before deleting the document.

In `@vektra-app/src/vektra_app/main.py`:
- Around line 546-552: Update the startup-step loop around step_fn in main.py to
catch unexpected exceptions and convert them into StartupValidationError,
including the failing step name and preserving the original exception as the
cause. Keep existing StartupValidationError propagation unchanged and ensure
failed steps do not emit startup_step_complete. This allows _serve() to handle
provider, import, and initialization failures through the structured
startup-failure path.

In `@vektra-index/src/vektra_index/reindex.py`:
- Around line 320-325: Update the reindexing flow around the vector_store.store
call to verify that len(stored) exactly matches the number of requested
chunk_embeddings. If the counts differ, fail the job instead of incrementing
chunks_reindexed or allowing status="completed"; preserve the existing
successful path for complete batches.

In `@vektra-index/tests/test_index_version_cleanup.py`:
- Around line 171-182: Update
test_deletes_a_superseded_version_and_reports_the_count to inspect the second
session.execute call and assert the Pgvector DELETE statement includes both the
"default" namespace predicate and index version 1 predicate. Keep the existing
removal-count and execute-call-count assertions.

In `@vektra-index/tests/test_qdrant_provider.py`:
- Around line 515-523: Update test_count_chunks_scopes_to_active_index_version
to inspect the count_filter passed through client.count and assert it includes
namespace_id="default" and index_version=2, while preserving the existing
exact=True assertion.

In `@vektra-ingest/src/vektra_ingest/jobs.py`:
- Around line 229-265: Refactor the cleanup flow around the session factory so
the initial expired-document query uses a short-lived session that closes before
the vector_store.delete calls begin. Perform all external deletions outside any
active database session, then open a second short-lived session to delete purged
IDs and commit; preserve the existing logging, skip behavior, and empty-result
handling.

In `@vektra-ingest/tests/test_cleanup.py`:
- Around line 59-94: Update test_cleanup_keeps_document_when_chunk_removal_fails
to retain the generated document ID from mock_result.all and assert that
vector_store.delete was awaited with that ID before verifying
session.execute.call_count and session.commit. Preserve the existing
database-row preservation assertions.

In `@vektra-shared/src/vektra_shared/config.py`:
- Around line 488-493: Update the llm_provider Field validation to strip
surrounding whitespace before applying the minimum-length check, ensuring
whitespace-only values are rejected while preserving the existing
VEKTRA_LLM_PROVIDER alias and description.

In `@vektra-shared/tests/test_config.py`:
- Around line 141-144: Restore the deprecated top_k property on RerankConfig,
returning the existing fetch_k value for backward-compatible reads. Update
test_stale_top_k_ignored to assert top_k remains accessible and maps safely to
fetch_k, while preserving support for the legacy VEKTRA_RERANK_TOP_K input.

In `@vektra-shared/tests/test_env_isolation_coverage.py`:
- Line 12: Strengthen the import validation in the test’s hermetic_env coverage
check to parse the source and require an actual import of the hermetic_env
symbol from vektra_shared.testing, rather than matching substrings that may
occur in comments or unrelated imports. Update the checks around the existing
import-validation logic while preserving the test’s intended failure behavior
when hermetic_env is absent.

In `@vektra-shared/tests/test_errors.py`:
- Around line 219-233: Update
TestDebt033Codes.test_new_codes_have_expected_prefixes to assert the exact
expected values for ERR_CONV_001, ERR_CONV_002, and ERR_CONV_003, while
retaining the existing exact assertions for the other error constants.

In `@vektra-shared/tests/test_suite_execution_coverage.py`:
- Around line 135-144: Update _suites() to collect both pytest-discoverable
filename patterns, test_*.py and *_test.py, while retaining the existing
directory and __pycache__ filtering and classification behavior.

---

Outside diff comments:
In `@vektra-index/src/vektra_index/api.py`:
- Around line 154-191: The chunk-writing flow in the endpoint around
vector_store.store must validate that a live SourceDocumentOrm exists for
(document_id, effective_ns) before constructing or inserting chunks. Add the
namespace-scoped document existence check before the store call, and reject the
request using the endpoint’s established missing-document error behavior when no
matching document exists.

In `@vektra-index/src/vektra_index/providers/pgvector.py`:
- Around line 80-117: The chunk insertion logic in store() must be idempotent
when deterministic IDs already exist for the same document and target version.
Update the session.add() flow to upsert or replace conflicting target-version
rows before insertion, while preserving deterministic chunk IDs, parent linkage,
and the existing inserted_ids behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5a112664-8930-4871-8a04-99ecc73b0182

📥 Commits

Reviewing files that changed from the base of the PR and between 3d10c8b and 385311c.

⛔ Files ignored due to path filters (6)
  • .s2s/BACKLOG.md is excluded by !.s2s/**
  • .s2s/decisions/ADR-0026-document-chunks-pgvector-internal.md is excluded by !.s2s/**
  • .s2s/plans/20260712-sprint3-rag-quality.md is excluded by !.s2s/**
  • .s2s/plans/20260714-qdrant-parity.md is excluded by !.s2s/**
  • migrations/versions/0007_reindex_chunks_counter.py is excluded by !**/migrations/**
  • uv.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (93)
  • .claude/CLAUDE.md
  • .env.example
  • .gemini/styleguide.md
  • .github/workflows/ci-unit.yml
  • .github/workflows/integration.yml
  • .github/workflows/publish.yml
  • CHANGELOG.md
  • Dockerfile
  • Makefile
  • README.md
  • deploy/docker-compose.image.yml.example
  • docker-compose.yml
  • docker/entrypoint.sh
  • docs/getting-started/index.md
  • docs/reference/api.md
  • docs/reference/configuration.md
  • docs/reference/error-codes.md
  • scripts/reindex.sh
  • tests/integration/test_chunk_lifecycle.py
  • tests/integration/test_e2e_flow.py
  • tests/nfr/test_nfr_hard.py
  • tests/nfr/test_performance.py
  • tests/test_startup.py
  • vektra-admin/pyproject.toml
  • vektra-admin/src/vektra_admin/api.py
  • vektra-admin/src/vektra_admin/quotas.py
  • vektra-admin/tests/conftest.py
  • vektra-admin/tests/test_admin_turns.py
  • vektra-admin/tests/test_integration.py
  • vektra-admin/tests/test_quotas.py
  • vektra-analytics/pyproject.toml
  • vektra-analytics/src/vektra_analytics/__init__.py
  • vektra-analytics/tests/__init__.py
  • vektra-analytics/tests/conftest.py
  • vektra-analytics/tests/test_api.py
  • vektra-app/README.md
  • vektra-app/pyproject.toml
  • vektra-app/src/vektra_app/__init__.py
  • vektra-app/src/vektra_app/main.py
  • vektra-app/tests/conftest.py
  • vektra-app/tests/test_app_integration.py
  • vektra-app/tests/test_error_codes.py
  • vektra-app/tests/test_provider_registration.py
  • vektra-core/pyproject.toml
  • vektra-core/src/vektra_core/advanced_pipeline.py
  • vektra-core/src/vektra_core/api.py
  • vektra-core/tests/conftest.py
  • vektra-core/tests/test_advanced_pipeline.py
  • vektra-core/tests/test_api.py
  • vektra-core/tests/test_env_isolation.py
  • vektra-core/tests/test_feedback_api.py
  • vektra-index/README.md
  • vektra-index/pyproject.toml
  • vektra-index/src/vektra_index/adapters.py
  • vektra-index/src/vektra_index/api.py
  • vektra-index/src/vektra_index/models.py
  • vektra-index/src/vektra_index/providers/pgvector.py
  • vektra-index/src/vektra_index/providers/qdrant.py
  • vektra-index/src/vektra_index/reindex.py
  • vektra-index/src/vektra_index/startup.py
  • vektra-index/tests/conftest.py
  • vektra-index/tests/test_api_namespace_binding.py
  • vektra-index/tests/test_index_version_cleanup.py
  • vektra-index/tests/test_pgvector_unit.py
  • vektra-index/tests/test_qdrant_provider.py
  • vektra-index/tests/test_reindex.py
  • vektra-index/tests/test_startup.py
  • vektra-ingest/pyproject.toml
  • vektra-ingest/src/vektra_ingest/jobs.py
  • vektra-ingest/tests/conftest.py
  • vektra-ingest/tests/test_api.py
  • vektra-ingest/tests/test_cleanup.py
  • vektra-ingest/tests/test_pipeline.py
  • vektra-learn/pyproject.toml
  • vektra-learn/src/vektra_learn/query.py
  • vektra-learn/tests/__init__.py
  • vektra-learn/tests/conftest.py
  • vektra-learn/tests/test_api.py
  • vektra-learn/widget/src/api-client.js
  • vektra-shared/pyproject.toml
  • vektra-shared/src/vektra_shared/__init__.py
  • vektra-shared/src/vektra_shared/config.py
  • vektra-shared/src/vektra_shared/errors.py
  • vektra-shared/src/vektra_shared/http_errors.py
  • vektra-shared/src/vektra_shared/protocols.py
  • vektra-shared/src/vektra_shared/testing.py
  • vektra-shared/src/vektra_shared/types.py
  • vektra-shared/tests/conftest.py
  • vektra-shared/tests/test_auth.py
  • vektra-shared/tests/test_config.py
  • vektra-shared/tests/test_env_isolation_coverage.py
  • vektra-shared/tests/test_errors.py
  • vektra-shared/tests/test_suite_execution_coverage.py
💤 Files with no reviewable changes (1)
  • vektra-ingest/tests/test_pipeline.py

Comment thread docs/getting-started/index.md Outdated
Comment thread scripts/reindex.sh
Comment thread scripts/reindex.sh
Comment thread tests/integration/test_chunk_lifecycle.py Outdated
Comment thread vektra-app/src/vektra_app/main.py
Comment thread vektra-shared/src/vektra_shared/config.py
Comment thread vektra-shared/tests/test_config.py
Comment thread vektra-shared/tests/test_env_isolation_coverage.py
Comment thread vektra-shared/tests/test_errors.py
Comment thread vektra-shared/tests/test_suite_execution_coverage.py
fvadicamo and others added 5 commits July 18, 2026 15:04
The getting-started walkthrough and deploy/docker-compose.image.yml.example referenced VEKTRA_VERSION=0.6.1, a tag that was never published (INFRA-007 ships its first image at 0.7.0). Point operators at the tag this release actually publishes.

Addresses CodeRabbit #121 (comment 3608554399).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
Every positional argument after the second silently replaced NAMESPACE, so 'reindex.sh --cleanup 1 tenant-a tenant-b' would delete from tenant-b. Reject a third positional argument with a clear error instead.

Addresses CodeRabbit #121 (comment 3608554401).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
A provider returning fewer ids than requested still let the job reach status=completed, so an operator could switch the active version to an incomplete index. Raise when len(stored) != len(chunk_embeddings); run_reindex's handler marks the job failed with the message.

Addresses CodeRabbit #121 (comment 3608554413).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
cleanup_soft_deleted_task held one Postgres connection open across per-document vector-store delete calls (external network I/O), risking pool exhaustion on a large backlog. Split into two short-lived sessions with the external deletions in between; behaviour (skip-empty, per-doc error skip, final log) is unchanged.

Addresses CodeRabbit #121 (comment 3608554417).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
The precondition asserted found[total] > 0, which the shared fixture text could satisfy without the target document being indexed. Assert doomed_id is in the returned results, mirroring the post-delete check.

Addresses CodeRabbit #121 (comment 3608554407).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
fvadicamo and others added 2 commits July 18, 2026 15:06
Records the nine minor CodeRabbit findings from the #121 release review that were deferred (test-strengthening plus two minor edges), and the one rejected on policy grounds (restoring removed VEKTRA_RERANK_TOP_K). The four Major items were fixed in this same PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Francesco Vadicamo <f.vadicamo@gmail.com>
- docs(deploy): published-image examples 0.6.1 -> 0.7.0 (never-published tag)
- fix(scripts): reindex.sh rejects extra positional args instead of overwriting namespace
- fix(index): reindex fails when the store writes a partial batch (no false completed)
- fix(ingest): cleanup splits into two short-lived sessions, no DB connection held across vector-store network deletes
- test(index): chunk-lifecycle asserts the doomed doc is searchable before delete
- docs(backlog): DEBT-036 tracks the 9 deferred minor findings; the RERANK_TOP_K backward-compat request is rejected on policy

Reviews: 2/2 addressed (Gemini; private _session_factory is a pre-existing module-wide pattern)
Tests: make lint + make test green (800 passed); integration change runs in CI
Refs: v0.7.0 review (#121), DEBT-036
@fvadicamo
fvadicamo merged commit 493e79c into main Jul 18, 2026
45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD and toolchain changes component:admin vektra-admin component component:core vektra-core component component:index vektra-index component component:ingest vektra-ingest component component:learn vektra-learn component component:shared vektra-shared component documentation Improvements or additions to documentation infra Infrastructure, Docker, deployment security Security hardening and vulnerability fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant