PaveDB 0.9.5
English
PaveDB 0.9.5 is a planned patch and the first 1.0 preview. It carries security fixes, the durable SQLite compatibility baseline, and the first shared-plan quota surface.
Security
This release fixes several defects in the multi-tenant boundary. Operators running 0.9.4 or earlier should upgrade.
- Startup auth policy is enforced on every entry point.
enforce_policypreviously ran only underpavesrv, so launching throughuvicorn pave.main:appskipped the production refusal ofauth.mode=noneand the loopback coercion. - Query replay no longer re-executes a revoked shared-corpus scope. Replay
now derives the shared scope from live configuration, so turning
common_enabledoff — or re-pointing it — takes effect for stored queries. - Tenant names are validated at startup. They must match
^[a-z0-9][a-z0-9-]{0,62}$, the same rule collection names already use. Unvalidated names became directory components while authorization compared them byte-exactly, so two names differing only by case or Unicode normalization shared one data directory on case-insensitive filesystems. - A collection’s model no longer inherits an unrelated execution grant. A
caller-supplied
embed_modelcould inherit the operator’strust_remote_codeand load an arbitrary model repository. - Ingest rejects unusable chunk identifiers before it commits. A control
character in a
docidcould fail partway through a batch, leaving metadata rows without vectors and blocking instance archives. - Tenant bearer tokens must be strings. An unquoted YAML value became a
guessable literal token:
acme: yesauthenticated asTrue, and all-digit or date-shaped values behaved the same way. - Duplicate bearer tokens are refused at startup. One token configured for two tenants bound its holder to whichever appeared first, so the second tenant read and wrote the first tenant’s data.
- Batch ingest enforces the per-collection chunk quota. The cap was applied to single-document ingest only, so the batch endpoint stepped around it.
- Search
kis bounded. A single request could previously ask for an entire collection. - Unmatched routes no longer mint unbounded metrics series. Any caller could grow the shared catalog permanently by varying the request path.
- Search no longer logs matched chunk text. Document content was copied into the operator’s logs at INFO by default.
- Readiness probes no longer race each other. Concurrent probes shared one write-test filename and reported a healthy instance unready.
Upgrade note
Three startup checks are breaking changes. Each fails loudly and names the offending entry rather than degrading silently.
- Tenant names must match
^[a-z0-9][a-z0-9-]{0,62}$— the same rule collection names already use. Renaming a tenant also requires moving its data directory from<data_dir>/t_<old>to<data_dir>/t_<new>; renaming without moving it orphans that tenant’s data. - Tenant tokens must be non-empty strings. Quote any value that YAML would otherwise read as a boolean, number or date.
- Tenant tokens must be unique. Two tenants sharing one token is refused.
Two runtime limits also tighten. Search rejects k above 1000 with 422, and a
query logged before that bound existed is clamped to it on replay. Batch ingest
that would exceed max_chunks_per_collection is now refused as a whole: the
request still answers 201, with every item reporting chunk_limit_reached and
nothing indexed, matching how that endpoint already reports per-item failures.
Single-document ingest keeps returning 429.
The metrics path label for unmatched requests is now a single <unmatched>
value rather than the raw request path.
Highlights
- Preview compatibility baseline. Catalog schema v5 and collection schema v6 are the supported floor. From here, released schema changes carry append-only, transactional, data-preserving forward migrations; failed migrations roll back and newer schemas reject downgrades.
- Shared-plan quotas. Per-tenant collection limits and per-collection chunk limits are enforced at the store layer and return 429.
- Embedder options. Adds
trust_remote_code, task prefixes as vector-space identity, and a TEI-compatible remote runtime. - UI gating.
ui.enabledcontrols the OpenAPI UI, which stays off by default in production.