homelab-codex-ws/hosts/piha/services.yaml
oskar 3d4ee3818d feat(kb-query): active embed fallback SOLARIA→PIHA (module 5 phase 4, plan §2/§5)
Last missing core piece of KB phase 4: kb-query no longer hard-fails /search
when Ollama@SOLARIA is unreachable. app/fallback.py implements the plan's
circuit-breaker exactly (30s cached health probe, 3s hard embed timeout on
SOLARIA, one-shot same-request switch to a new local ollama-piha@PIHA
container on timeout/error). sol_status in /healthz and /search now reflects
the real breaker state instead of a hardcoded "up".

New services/ollama-piha (bge-m3, OLLAMA_KEEP_ALIVE=0, arm64/no-GPU) is the
local fallback leg. Live calibration on PIHA (2026-07-27, normal load):
embed latency 4.2-5.2s, RAM peak ~983MiB against a 2.5GiB ceiling -- both
inside the plan's go-bar, so the fallback is enabled by default rather than
gated behind a flag. Calibration also surfaced and disabled (not removed) a
previously-undocumented orphaned native ollama.service on PIHA that had been
conflicting with the container's port.

The embed-model invariant (query embedding == document_chunk.model) still
enforces once at startup, since both fallback legs share one EMBED_MODEL
constant by construction; a redundant per-request DB check was deliberately
skipped and the invariant is instead proven structurally by test.

retrieval_eval.py gains --transport http (plan §2 decision 6/§9), previously
unimplemented. Verified live: HTTP transport is bit-identical to direct
transport against the same live SOLARIA (0 mismatches), and a live sol-down
simulation (kb-query's own OLLAMA_URL pointed at a dead address, no other
Ollama consumer touched) shows the PIHA fallback answering with the same
hit@3 gate outcome and dist within ~3e-4 of the SOLARIA baseline.

Zero changes to DB schema or kb_retrieval's retrieval logic -- only the
embed + health layer, per task constraints.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 22:23:53 +02:00

144 lines
4.8 KiB
YAML

host: piha
services:
ha-diag-agent:
role: ha-diagnostic-agent
deployment_model: docker-compose
exposure: local-only
offline_required: false
depends_on:
local: []
external: [homeassistant]
config:
target_url: http://localhost:8123
location_tag: "ken"
events_dir: /opt/homelab/events/piha
runtime:
config_path: /opt/homelab/config/ha-diag-agent
data_path: /var/lib/ha-diag-agent
node-agent:
role: node-stability-monitor
deployment_model: docker-compose
exposure: local-only
offline_required: true
depends_on:
local: []
external: []
runtime:
config_path: /opt/homelab/config/node-agent
data_path: /opt/homelab/state
logs_path: /opt/homelab/events
brain-watchdog:
role: control-plane-watchdog
deployment_model: docker-compose
exposure: private
offline_required: false
depends_on:
local: []
external: [control-plane]
runtime:
config_path: /opt/homelab/config/brain-watchdog
vikunja:
role: task-management
deployment_model: docker-compose
exposure: private # public via npm reverse proxy at vikunja.okit.pl
offline_required: false
depends_on:
local: []
external: [forgejo] # OIDC identity provider
ports:
- name: http
container_port: 3456
protocol: tcp
runtime:
# secrets (.env) + OIDC config (config.yml) live alongside the compose file
config_path: services/vikunja
# data is in Docker named volumes: vikunja_vikunja_db, vikunja_vikunja_files
llm-gateway:
role: llm-router # FastAPI proxy -> Ollama @ SOLARIA :11434
deployment_model: docker-compose
exposure: private # Tailscale-only bind (TAILSCALE_BIND_IP); no public ingress
offline_required: false
depends_on:
local: []
external: [ollama] # SOLARIA may be powered down -> routes 502, health stays ok
ports:
- name: http
container_port: 8080
protocol: tcp
runtime:
# .env (TAILSCALE_BIND_IP) lives alongside the compose file; stateless, no data path
config_path: services/llm-gateway
node_exporter:
role: metrics-exporter
deployment_model: docker-compose
exposure: local-only
offline_required: true
depends_on:
local: []
external: []
runtime:
# textfile collector reads /opt/homelab/state/node-exporter (module 5 phase 3 step 5,
# docs/kb/modules/05-faza3-plan.md §7.2 — kb-ingest.prom) via the existing /:/host:ro
# mount, see hosts/piha/runtime/node_exporter/docker-compose.override.yml.
data_path: /opt/homelab/state/node-exporter
kb-postgres:
role: kb-database # KB spine: Postgres 16 + pgvector (always-on)
deployment_model: docker-compose
exposure: local-only # Tailscale-accessible; no public ingress
offline_required: false
depends_on:
local: []
external: []
ports:
- name: postgres
host_port: 5433
protocol: tcp
runtime:
config_path: /opt/homelab/config/kb-postgres
# data is in Docker named volume kb_postgres_data — must land on the NVMe
# (Docker data-root on /home); see hosts/piha/runtime/kb-postgres override.
kb-query:
role: kb-search-api # module 5 phase 4: FastAPI wrapper over kb_retrieval cascade/flat query
deployment_model: docker-compose
exposure: private # LAN bind (LAN_BIND_IP); npm@PIHA vhost + OIDC is a later step
offline_required: false
depends_on:
local: [kb-postgres, ollama-piha] # ollama-piha is the fallback leg, not hard-required at boot
external: [ollama] # SOLARIA may be offline -> active fallback to ollama-piha, plan §2/§5
ports:
- name: http
container_port: 8080
host_port: 8230
protocol: tcp
runtime:
# .env (KB_DSN, LAN_BIND_IP, OLLAMA_PIHA_URL) lives alongside the compose file; stateless, no data path
config_path: services/kb-query
ollama-piha:
role: kb-embed-fallback # module 5 phase 4 plan §2 decision 2 / §5: local CPU embed
# fallback for kb-query when Ollama@SOLARIA is down/times out
deployment_model: docker-compose
exposure: private # LAN bind (LAN_BIND_IP); consumed only by kb-query@PIHA
offline_required: true # PIHA-local, never depends on SOLARIA/VPS/Forgejo at runtime
depends_on:
local: []
external: []
ports:
- name: http
container_port: 11434
host_port: 11434
protocol: tcp
runtime:
# .env (LAN_BIND_IP) lives alongside the compose file
config_path: services/ollama-piha
# bge-m3 model files persist in the Docker named volume-equivalent bind
# /opt/homelab/data/ollama-piha — see hosts/piha/runtime/ollama-piha override.