"Postgres + pgvector" is described as part of the running stack in three places. Nothing in the Python code connects to a database.
What was checked
grep -rn "psycopg" --include=*.py . -> no matches
grep -rln "postgres|POSTGRES|DSN|dbname" src -> no matches
find src/praxis/index -type f -> schema.sql only
src/praxis/index/ contains a single schema.sql and no Python. The api extra declares psycopg[binary]>=3.1 and pgvector>=0.2, and neither is imported anywhere in the source tree.
What actually serves dense retrieval is src/praxis/retrieve/dense.py, and its own docstring says so: cosine similarity as a numpy matrix-vector product, with a pure-stdlib fallback so offline mode and CI work without numpy, and corpus vectors cached to disk under PRAXIS_CACHE_DIR.
docker-compose.yml starts a db service on pgvector/pgvector:pg16 and mounts schema.sql into its init directory — but the app service has no depends_on, no connection string and no client code. The database comes up and nothing talks to it.
Where the claim appears
README.md / README.en.md — the stack line
- the organisation profile README
drobyshevdev.github.io — the Stack section, which I wrote as "pgvector keeps the dense index in the same database as the corpus, so there is no second system to keep in sync"
That last one is mine and it is the worst of the three, because it explains a design decision for a component that is not wired. I inferred it from the compose file and the extras instead of reading the retrieval path, which is the mistake this organisation's third rule exists to prevent.
Why it matters beyond tidiness
The eval numbers on the front page — recall@5 0.92, MRR 0.94 — are produced by the numpy path. Anyone reading "Postgres + pgvector" reasonably assumes they were measured on the pgvector index, on an HNSW index with vector_cosine_ops, at a scale where that choice matters. They were not. The numbers are honest about what they measured; the stack description is not honest about what produced them.
It also puts two unused dependencies into the Docker image, and generates Dependabot noise for both — which is how this surfaced.
Options
- Describe it as planned. Cheapest and immediately true: the stack lines say numpy in memory with a disk cache, and
schema.sql is named as the design for the Postgres path rather than as the path. The compose db service gets a comment saying it is there for the index that is coming.
- Wire it. Implement the psycopg-backed retriever behind the same
retrieve.base.Retriever protocol, so dense.py and a pg.py are interchangeable, and re-run the golden set on it. Then the claim becomes true and the eval numbers get a second measurement to compare against — which is the more interesting outcome, since it would show whether HNSW recall costs anything at this corpus size.
- Drop it. Remove
psycopg and pgvector from the api extra, drop the db service, keep schema.sql as a design note. Smallest surface, but forecloses the scaling story.
Option 1 is needed regardless and takes minutes; 2 or 3 is the actual decision.
Related
DrobyshevDev/DrobyshevDev.github.io — the Stack card needs the same correction, and I will send that separately rather than leave it pointing at this issue.
"Postgres + pgvector" is described as part of the running stack in three places. Nothing in the Python code connects to a database.
What was checked
src/praxis/index/contains a singleschema.sqland no Python. Theapiextra declarespsycopg[binary]>=3.1andpgvector>=0.2, and neither is imported anywhere in the source tree.What actually serves dense retrieval is
src/praxis/retrieve/dense.py, and its own docstring says so: cosine similarity as a numpy matrix-vector product, with a pure-stdlib fallback so offline mode and CI work without numpy, and corpus vectors cached to disk underPRAXIS_CACHE_DIR.docker-compose.ymlstarts adbservice onpgvector/pgvector:pg16and mountsschema.sqlinto its init directory — but theappservice has nodepends_on, no connection string and no client code. The database comes up and nothing talks to it.Where the claim appears
README.md/README.en.md— the stack linedrobyshevdev.github.io— the Stack section, which I wrote as "pgvector keeps the dense index in the same database as the corpus, so there is no second system to keep in sync"That last one is mine and it is the worst of the three, because it explains a design decision for a component that is not wired. I inferred it from the compose file and the extras instead of reading the retrieval path, which is the mistake this organisation's third rule exists to prevent.
Why it matters beyond tidiness
The eval numbers on the front page — recall@5 0.92, MRR 0.94 — are produced by the numpy path. Anyone reading "Postgres + pgvector" reasonably assumes they were measured on the pgvector index, on an HNSW index with
vector_cosine_ops, at a scale where that choice matters. They were not. The numbers are honest about what they measured; the stack description is not honest about what produced them.It also puts two unused dependencies into the Docker image, and generates Dependabot noise for both — which is how this surfaced.
Options
schema.sqlis named as the design for the Postgres path rather than as the path. The composedbservice gets a comment saying it is there for the index that is coming.retrieve.base.Retrieverprotocol, sodense.pyand apg.pyare interchangeable, and re-run the golden set on it. Then the claim becomes true and the eval numbers get a second measurement to compare against — which is the more interesting outcome, since it would show whether HNSW recall costs anything at this corpus size.psycopgandpgvectorfrom theapiextra, drop thedbservice, keepschema.sqlas a design note. Smallest surface, but forecloses the scaling story.Option 1 is needed regardless and takes minutes; 2 or 3 is the actual decision.
Related
DrobyshevDev/DrobyshevDev.github.io — the Stack card needs the same correction, and I will send that separately rather than leave it pointing at this issue.