Production had no EMBED_PROVIDER, so every knowledge_chunk carried a null embedding and a question only matched documents that shared its words. A person asking about a family emergency got nothing from a document titled "shift cover and cancellation". Ollama rather than Voyage: internal/knowledge/embed.go calls it "the default worth reaching for" — real semantics, no credential, no per-token cost, and no tenant text leaving the cluster. Voyage needs an API key nobody has issued. Bounded deliberately. The API pods share this node, so an unbounded model server is a way to evict them; the memory limit means the kubelet kills the embedder and nothing else. The 1Gi request is also what keeps it off the second node, which has 1.2Gi allocatable and could not hold it. Applied in three stages so nothing was pointed at an embedder that had not been proven: deploy and pull the model, run reembed with the settings passed as exec environment — 34 chunks in 11s, which proves connectivity without touching live config — and only then patch krow-config and restart. Rolling back is removing four keys and restarting. Verified after: 55/55 on verify-deploy, and a question with no literal keyword overlap with the corpus returned the relevant policy documents. This file is the record of what was applied. It was applied by hand, which is the same gap the README already admits for migrations — there is no deploy pipeline, so a manifest in the repository is a description of the cluster rather than the thing that produces it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJvibeSc1JYXjatankqM1g
infrastructure
Deployment and local-environment definitions.
Empty in Phase 1, on purpose. The Phase 1 scope is the Go module, the
database connection and the initial migration, run against a PostgreSQL 18.6
instance that already exists on the developer's machine. Nothing here is needed
to get make migrate-up && make run working.
What lands here in later phases, once each is actually approved:
| File | Phase | Contents |
|---|---|---|
docker-compose.dev.yml |
2 | PostgreSQL + pgvector, so the dev database stops being a machine-local install |
docker-compose.dev.yml (extended) |
later | Redis, MinIO — each only when the phase that needs it starts |
Dockerfile.api |
later | Multi-stage build for go-api |
Dockerfile.owliver |
later | The Python service |
otel-collector.yaml |
later | OpenTelemetry collector config |
NATS is deliberately absent from that table: it is not part of the target architecture, and nothing here should reintroduce it.
Adding any of these before its phase would be speculative, so the directory holds only this note for now.